mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-08-27 08:56:44 +00:00
Add mostly stubbed D3D12 replay interface, and 2 core chunk replay loops
This commit is contained in:
@@ -100,6 +100,9 @@ class WrappedID3D12GraphicsCommandList : public RefCounter12<ID3D12GraphicsComma
|
||||
D3D12_COMMAND_LIST_TYPE type;
|
||||
} m_Init;
|
||||
|
||||
void AddDrawcall(const FetchDrawcall &d, bool hasEvents);
|
||||
void AddEvent(D3D12ChunkType type, string description);
|
||||
|
||||
const char *GetChunkName(uint32_t idx) { return m_pDevice->GetChunkName(idx); }
|
||||
D3D12ResourceManager *GetResourceManager() { return m_pDevice->GetResourceManager(); }
|
||||
public:
|
||||
|
||||
@@ -162,7 +162,7 @@ bool WrappedID3D12GraphicsCommandList::Serialise_DrawIndexedInstanced(UINT Index
|
||||
|
||||
if(m_State == READING)
|
||||
{
|
||||
// TODO - AddEvent(DRAW_INDEXED_INST, desc);
|
||||
AddEvent(DRAW_INDEXED_INST, desc);
|
||||
string name =
|
||||
"DrawIndexedInstanced(" + ToStr::Get(idxCount) + ", " + ToStr::Get(instCount) + ")";
|
||||
|
||||
@@ -176,7 +176,7 @@ bool WrappedID3D12GraphicsCommandList::Serialise_DrawIndexedInstanced(UINT Index
|
||||
|
||||
draw.flags |= eDraw_Drawcall | eDraw_Instanced | eDraw_UseIBuffer;
|
||||
|
||||
// TODO - AddDrawcall(draw, true);
|
||||
AddDrawcall(draw, true);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -496,7 +496,7 @@ void WrappedID3D12GraphicsCommandList::SetGraphicsRootSignature(ID3D12RootSignat
|
||||
|
||||
if(m_State >= WRITING)
|
||||
{
|
||||
SCOPED_SERIALISE_CONTEXT(SET_ROOT_SIG);
|
||||
SCOPED_SERIALISE_CONTEXT(SET_GFX_ROOT_SIG);
|
||||
Serialise_SetGraphicsRootSignature(pRootSignature);
|
||||
|
||||
m_ListRecord->AddChunk(scope.Get());
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include "common/wrapped_pool.h"
|
||||
#include "d3d12_common.h"
|
||||
#include "d3d12_device.h"
|
||||
@@ -66,12 +67,48 @@ struct DummyID3D12DebugCommandQueue : public ID3D12DebugCommandQueue
|
||||
}
|
||||
};
|
||||
|
||||
struct D3D12DrawcallTreeNode
|
||||
{
|
||||
D3D12DrawcallTreeNode() {}
|
||||
explicit D3D12DrawcallTreeNode(const FetchDrawcall &d) : draw(d) {}
|
||||
FetchDrawcall draw;
|
||||
vector<D3D12DrawcallTreeNode> children;
|
||||
|
||||
vector<pair<ResourceId, EventUsage> > resourceUsage;
|
||||
|
||||
D3D12DrawcallTreeNode &operator=(const FetchDrawcall &d)
|
||||
{
|
||||
*this = D3D12DrawcallTreeNode(d);
|
||||
return *this;
|
||||
}
|
||||
|
||||
vector<FetchDrawcall> Bake()
|
||||
{
|
||||
vector<FetchDrawcall> ret;
|
||||
if(children.empty())
|
||||
return ret;
|
||||
|
||||
ret.resize(children.size());
|
||||
for(size_t i = 0; i < children.size(); i++)
|
||||
{
|
||||
ret[i] = children[i].draw;
|
||||
ret[i].children = children[i].Bake();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
class WrappedID3D12GraphicsCommandList;
|
||||
|
||||
class WrappedID3D12CommandQueue : public ID3D12CommandQueue,
|
||||
public RefCounter12<ID3D12CommandQueue>,
|
||||
public ID3DDevice
|
||||
{
|
||||
WrappedID3D12Device *m_pDevice;
|
||||
|
||||
WrappedID3D12GraphicsCommandList *m_ReplayList;
|
||||
|
||||
ResourceId m_ResourceID;
|
||||
D3D12ResourceRecord *m_QueueRecord;
|
||||
|
||||
@@ -82,6 +119,136 @@ class WrappedID3D12CommandQueue : public ID3D12CommandQueue,
|
||||
|
||||
vector<D3D12ResourceRecord *> m_CmdListRecords;
|
||||
|
||||
vector<FetchAPIEvent> m_RootEvents, m_Events;
|
||||
bool m_AddedDrawcall;
|
||||
|
||||
uint64_t m_CurChunkOffset;
|
||||
uint32_t m_RootEventID, m_RootDrawcallID;
|
||||
uint32_t m_FirstEventID, m_LastEventID;
|
||||
|
||||
D3D12DrawcallTreeNode m_ParentDrawcall;
|
||||
|
||||
void InsertDrawsAndRefreshIDs(vector<D3D12DrawcallTreeNode> &cmdBufNodes, uint32_t baseEventID,
|
||||
uint32_t baseDrawID);
|
||||
|
||||
struct BakedCmdListInfo
|
||||
{
|
||||
vector<FetchAPIEvent> curEvents;
|
||||
vector<DebugMessage> debugMessages;
|
||||
std::list<D3D12DrawcallTreeNode *> drawStack;
|
||||
|
||||
vector<pair<ResourceId, EventUsage> > resourceUsage;
|
||||
|
||||
struct CmdListState
|
||||
{
|
||||
ResourceId pipeline;
|
||||
|
||||
uint32_t idxWidth;
|
||||
ResourceId ibuffer;
|
||||
vector<ResourceId> vbuffers;
|
||||
|
||||
ResourceId rts[8];
|
||||
ResourceId dsv;
|
||||
} state;
|
||||
|
||||
vector<D3D12_RESOURCE_BARRIER> barriers;
|
||||
|
||||
D3D12DrawcallTreeNode *draw; // the root draw to copy from when submitting
|
||||
uint32_t eventCount; // how many events are in this cmd list, for quick skipping
|
||||
uint32_t curEventID; // current event ID while reading or executing
|
||||
uint32_t drawCount; // similar to above
|
||||
};
|
||||
map<ResourceId, BakedCmdListInfo> m_BakedCmdListInfo;
|
||||
|
||||
// on replay, the current command list for the last chunk we
|
||||
// handled.
|
||||
ResourceId m_LastCmdListID;
|
||||
int m_CmdListsInProgress;
|
||||
|
||||
// this is a list of uint64_t file offset -> uint32_t EIDs of where each
|
||||
// drawcall is used. E.g. the drawcall at offset 873954 is EID 50. If a
|
||||
// command list is executed more than once, there may be more than
|
||||
// one entry here - the drawcall will be aliased among several EIDs, with
|
||||
// the first one being the 'primary'
|
||||
struct DrawcallUse
|
||||
{
|
||||
DrawcallUse(uint64_t offs, uint32_t eid) : fileOffset(offs), eventID(eid) {}
|
||||
uint64_t fileOffset;
|
||||
uint32_t eventID;
|
||||
bool operator<(const DrawcallUse &o) const
|
||||
{
|
||||
if(fileOffset != o.fileOffset)
|
||||
return fileOffset < o.fileOffset;
|
||||
return eventID < o.eventID;
|
||||
}
|
||||
};
|
||||
vector<DrawcallUse> m_DrawcallUses;
|
||||
|
||||
struct PartialReplayData
|
||||
{
|
||||
// if we're doing a partial replay, by definition only one command
|
||||
// list will be partial at any one time. While replaying through
|
||||
// the command list chunks, the partial command list will be
|
||||
// created as a temporary new command list and when it comes to
|
||||
// the queue that should execute it, it can execute this instead.
|
||||
ID3D12CommandAllocator *resultPartialCmdAllocator;
|
||||
ID3D12GraphicsCommandList *resultPartialCmdList;
|
||||
|
||||
// if we're replaying just a single draw or a particular command
|
||||
// list subsection of command events, we don't go through the
|
||||
// whole original command lists to set up the partial replay,
|
||||
// so we just set this command list
|
||||
ID3D12GraphicsCommandList *outsideCmdList;
|
||||
|
||||
// this records where in the frame a command list was executed,
|
||||
// so that we know if our replay range ends in one of these ranges
|
||||
// we need to construct a partial command list for future
|
||||
// replaying. Note that we always have the complete command list
|
||||
// around - it's the bakeID itself.
|
||||
// Since we only ever record a bakeID once the key is unique - note
|
||||
// that the same command list could be reset multiple times
|
||||
// a frame, so the parent command list ID (the one recorded in
|
||||
// CmdList chunks) is NOT unique.
|
||||
// However, a single baked command list can be executed multiple
|
||||
// times - so we have to have a list of base events
|
||||
// Map from bakeID -> vector<baseEventID>
|
||||
map<ResourceId, vector<uint32_t> > cmdListExecs;
|
||||
|
||||
// This is just the ResourceId of the original parent command list
|
||||
// and it's baked id.
|
||||
// If we are in the middle of a partial replay - allows fast checking
|
||||
// in all CmdList chunks, with the iteration through the above list
|
||||
// only in Reset.
|
||||
// partialParent gets reset to ResourceId() in the Close so that
|
||||
// other baked command lists from the same parent don't pick it up
|
||||
// Also reset each overall replay
|
||||
ResourceId partialParent;
|
||||
|
||||
// If a partial replay is detected, this records the base of the
|
||||
// range. This both allows easily and uniquely identifying it in the
|
||||
// executecmdlists, but also allows the recording to 'rebase' the
|
||||
// last event ID by subtracting this, to know how far to record
|
||||
uint32_t baseEvent;
|
||||
} m_PartialReplayData;
|
||||
|
||||
map<ResourceId, ID3D12GraphicsCommandList *> m_RerecordCmds;
|
||||
|
||||
std::list<D3D12DrawcallTreeNode *> m_DrawcallStack;
|
||||
|
||||
std::list<D3D12DrawcallTreeNode *> &GetDrawcallStack()
|
||||
{
|
||||
if(m_LastCmdListID != ResourceId())
|
||||
return m_BakedCmdListInfo[m_LastCmdListID].drawStack;
|
||||
|
||||
return m_DrawcallStack;
|
||||
}
|
||||
|
||||
bool ShouldRerecordCmd(ResourceId cmdid);
|
||||
bool InRerecordRange();
|
||||
ID3D12GraphicsCommandList *RerecordCmdList(ResourceId cmdid);
|
||||
|
||||
void ProcessChunk(uint64_t offset, D3D12ChunkType context);
|
||||
|
||||
const char *GetChunkName(uint32_t idx) { return m_pDevice->GetChunkName(idx); }
|
||||
D3D12ResourceManager *GetResourceManager() { return m_pDevice->GetResourceManager(); }
|
||||
public:
|
||||
@@ -98,8 +265,16 @@ public:
|
||||
D3D12ResourceRecord *GetResourceRecord() { return m_QueueRecord; }
|
||||
WrappedID3D12Device *GetWrappedDevice() { return m_pDevice; }
|
||||
const vector<D3D12ResourceRecord *> &GetCmdLists() { return m_CmdListRecords; }
|
||||
D3D12DrawcallTreeNode &GetParentDrawcall() { return m_ParentDrawcall; }
|
||||
FetchAPIEvent GetEvent(uint32_t eventID);
|
||||
uint32_t GetMaxEID() { return m_Events.back().eventID; }
|
||||
void ClearAfterCapture();
|
||||
|
||||
void AddDrawcall(const FetchDrawcall &d, bool hasEvents);
|
||||
void AddEvent(D3D12ChunkType type, string description);
|
||||
|
||||
void ReplayLog(LogState readType, uint32_t startEventID, uint32_t endEventID, bool partial);
|
||||
|
||||
// interface for DXGI
|
||||
virtual IUnknown *GetRealIUnknown() { return GetReal(); }
|
||||
virtual IID GetBackbufferUUID() { return __uuidof(ID3D12Resource); }
|
||||
|
||||
@@ -90,8 +90,6 @@ void STDMETHODCALLTYPE WrappedID3D12CommandQueue::ExecuteCommandLists(
|
||||
{
|
||||
D3D12ResourceRecord *record = GetRecord(ppCommandLists[i]);
|
||||
|
||||
// TODO apply barriers from command list to current resource state tracking
|
||||
|
||||
m_pDevice->ApplyBarriers(record->bakedCommands->cmdInfo->barriers);
|
||||
|
||||
// need to lock the whole section of code, not just the check on
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#include <algorithm>
|
||||
#include "d3d12_command_list.h"
|
||||
#include "d3d12_command_queue.h"
|
||||
|
||||
@@ -147,6 +148,8 @@ WrappedID3D12CommandQueue::WrappedID3D12CommandQueue(ID3D12CommandQueue *real,
|
||||
if(RenderDoc::Inst().IsReplayApp())
|
||||
{
|
||||
m_pSerialiser = serialiser;
|
||||
|
||||
m_ReplayList = new WrappedID3D12GraphicsCommandList(NULL, m_pDevice, m_pSerialiser, state);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -162,6 +165,20 @@ WrappedID3D12CommandQueue::WrappedID3D12CommandQueue(ID3D12CommandQueue *real,
|
||||
|
||||
m_QueueRecord = NULL;
|
||||
|
||||
m_RootEventID = 1;
|
||||
m_RootDrawcallID = 1;
|
||||
m_FirstEventID = 0;
|
||||
m_LastEventID = ~0U;
|
||||
|
||||
m_LastCmdListID = ResourceId();
|
||||
|
||||
m_PartialReplayData.resultPartialCmdList = NULL;
|
||||
m_PartialReplayData.outsideCmdList = NULL;
|
||||
m_PartialReplayData.partialParent = ResourceId();
|
||||
m_PartialReplayData.baseEvent = 0;
|
||||
|
||||
m_DrawcallStack.push_back(&m_ParentDrawcall);
|
||||
|
||||
if(!RenderDoc::Inst().IsReplayApp())
|
||||
{
|
||||
m_QueueRecord = m_pDevice->GetResourceManager()->AddResourceRecord(m_ResourceID);
|
||||
@@ -228,6 +245,325 @@ void WrappedID3D12CommandQueue::ClearAfterCapture()
|
||||
m_CmdListRecords.clear();
|
||||
}
|
||||
|
||||
FetchAPIEvent WrappedID3D12CommandQueue::GetEvent(uint32_t eventID)
|
||||
{
|
||||
for(size_t i = m_Events.size() - 1; i > 0; i--)
|
||||
{
|
||||
if(m_Events[i].eventID <= eventID)
|
||||
return m_Events[i];
|
||||
}
|
||||
|
||||
return m_Events[0];
|
||||
}
|
||||
|
||||
void WrappedID3D12CommandQueue::ProcessChunk(uint64_t offset, D3D12ChunkType chunk)
|
||||
{
|
||||
m_CurChunkOffset = offset;
|
||||
|
||||
m_AddedDrawcall = false;
|
||||
|
||||
switch(chunk)
|
||||
{
|
||||
case CLOSE_LIST: m_ReplayList->Close(); break;
|
||||
case RESET_LIST: m_ReplayList->Serialise_Reset(NULL, NULL); break;
|
||||
|
||||
case RESOURCE_BARRIER: m_ReplayList->Serialise_ResourceBarrier(0, NULL); break;
|
||||
|
||||
case DRAW_INDEXED_INST: m_ReplayList->Serialise_DrawIndexedInstanced(0, 0, 0, 0, 0); break;
|
||||
case COPY_BUFFER: m_ReplayList->Serialise_CopyBufferRegion(NULL, 0, NULL, 0, 0); break;
|
||||
|
||||
case CLEAR_RTV:
|
||||
m_ReplayList->Serialise_ClearRenderTargetView(D3D12_CPU_DESCRIPTOR_HANDLE(), (FLOAT *)NULL, 0,
|
||||
NULL);
|
||||
break;
|
||||
|
||||
case SET_TOPOLOGY:
|
||||
m_ReplayList->Serialise_IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_UNDEFINED);
|
||||
break;
|
||||
case SET_IBUFFER: m_ReplayList->Serialise_IASetIndexBuffer(NULL); break;
|
||||
case SET_VBUFFERS: m_ReplayList->Serialise_IASetVertexBuffers(0, 0, NULL); break;
|
||||
case SET_VIEWPORTS: m_ReplayList->Serialise_RSSetViewports(0, NULL); break;
|
||||
case SET_SCISSORS: m_ReplayList->Serialise_RSSetScissorRects(0, NULL); break;
|
||||
case SET_PIPE: m_ReplayList->Serialise_SetPipelineState(NULL); break;
|
||||
case SET_RTVS: m_ReplayList->Serialise_OMSetRenderTargets(0, NULL, FALSE, NULL); break;
|
||||
case SET_GFX_ROOT_SIG: m_ReplayList->Serialise_SetGraphicsRootSignature(NULL); break;
|
||||
case SET_GFX_ROOT_CBV:
|
||||
m_ReplayList->Serialise_SetGraphicsRootConstantBufferView(0, D3D12_GPU_VIRTUAL_ADDRESS());
|
||||
break;
|
||||
|
||||
case EXECUTE_CMD_LISTS: Serialise_ExecuteCommandLists(0, NULL); break;
|
||||
case SIGNAL: Serialise_Signal(NULL, 0); break;
|
||||
case CONTEXT_CAPTURE_FOOTER:
|
||||
{
|
||||
SERIALISE_ELEMENT(ResourceId, bbid, ResourceId());
|
||||
|
||||
bool HasCallstack = false;
|
||||
m_pSerialiser->Serialise("HasCallstack", HasCallstack);
|
||||
|
||||
if(HasCallstack)
|
||||
{
|
||||
size_t numLevels = 0;
|
||||
uint64_t *stack = NULL;
|
||||
|
||||
m_pSerialiser->SerialisePODArray("callstack", stack, numLevels);
|
||||
|
||||
m_pSerialiser->SetCallstack(stack, numLevels);
|
||||
|
||||
SAFE_DELETE_ARRAY(stack);
|
||||
}
|
||||
|
||||
if(m_State == READING)
|
||||
{
|
||||
AddEvent(CONTEXT_CAPTURE_FOOTER, "Present()");
|
||||
|
||||
FetchDrawcall draw;
|
||||
draw.name = "Present()";
|
||||
draw.flags |= eDraw_Present;
|
||||
|
||||
draw.copyDestination = bbid;
|
||||
|
||||
AddDrawcall(draw, true);
|
||||
}
|
||||
}
|
||||
default:
|
||||
// ignore system chunks
|
||||
if(chunk == INITIAL_CONTENTS)
|
||||
GetResourceManager()->Serialise_InitialState(ResourceId(), NULL);
|
||||
else if(chunk < FIRST_CHUNK_ID)
|
||||
m_pSerialiser->SkipCurrentChunk();
|
||||
else
|
||||
RDCERR("Unexpected non-device chunk %d at offset %llu", chunk, offset);
|
||||
break;
|
||||
}
|
||||
|
||||
m_pSerialiser->PopContext(chunk);
|
||||
|
||||
if(m_State == READING && chunk == SET_MARKER)
|
||||
{
|
||||
// no push/pop necessary
|
||||
}
|
||||
else if(m_State == READING && (chunk == PUSH_EVENT || chunk == POP_EVENT))
|
||||
{
|
||||
// don't add these events - they will be handled when inserted in-line into queue submit
|
||||
}
|
||||
else if(m_State == READING)
|
||||
{
|
||||
if(!m_AddedDrawcall)
|
||||
AddEvent(chunk, m_pSerialiser->GetDebugStr());
|
||||
}
|
||||
|
||||
m_AddedDrawcall = false;
|
||||
}
|
||||
|
||||
void WrappedID3D12CommandQueue::ReplayLog(LogState readType, uint32_t startEventID,
|
||||
uint32_t endEventID, bool partial)
|
||||
{
|
||||
m_State = readType;
|
||||
|
||||
D3D12ChunkType header = (D3D12ChunkType)m_pSerialiser->PushContext(NULL, NULL, 1, false);
|
||||
RDCASSERTEQUAL(header, CONTEXT_CAPTURE_HEADER);
|
||||
|
||||
m_pDevice->Serialise_BeginCaptureFrame(!partial);
|
||||
|
||||
m_pDevice->GPUSync();
|
||||
|
||||
m_pSerialiser->PopContext(header);
|
||||
|
||||
m_RootEvents.clear();
|
||||
|
||||
if(m_State == EXECUTING)
|
||||
{
|
||||
FetchAPIEvent ev = GetEvent(startEventID);
|
||||
m_RootEventID = ev.eventID;
|
||||
|
||||
// if not partial, we need to be sure to replay
|
||||
// past the command buffer records, so can't
|
||||
// skip to the file offset of the first event
|
||||
if(partial)
|
||||
m_pSerialiser->SetOffset(ev.fileOffset);
|
||||
|
||||
m_FirstEventID = startEventID;
|
||||
m_LastEventID = endEventID;
|
||||
}
|
||||
else if(m_State == READING)
|
||||
{
|
||||
m_RootEventID = 1;
|
||||
m_RootDrawcallID = 1;
|
||||
m_FirstEventID = 0;
|
||||
m_LastEventID = ~0U;
|
||||
}
|
||||
|
||||
for(;;)
|
||||
{
|
||||
if(m_State == EXECUTING && m_RootEventID > endEventID)
|
||||
{
|
||||
// we can just break out if we've done all the events desired.
|
||||
// note that the command buffer events aren't 'real' and we just blaze through them
|
||||
break;
|
||||
}
|
||||
|
||||
uint64_t offset = m_pSerialiser->GetOffset();
|
||||
|
||||
D3D12ChunkType context = (D3D12ChunkType)m_pSerialiser->PushContext(NULL, NULL, 1, false);
|
||||
|
||||
m_LastCmdListID = ResourceId();
|
||||
|
||||
ProcessChunk(offset, context);
|
||||
|
||||
RenderDoc::Inst().SetProgress(FileInitialRead, float(offset) / float(m_pSerialiser->GetSize()));
|
||||
|
||||
// for now just abort after capture scope. Really we'd need to support multiple frames
|
||||
// but for now this will do.
|
||||
if(context == CONTEXT_CAPTURE_FOOTER)
|
||||
break;
|
||||
|
||||
// break out if we were only executing one event
|
||||
if(m_State == EXECUTING && startEventID == endEventID)
|
||||
break;
|
||||
|
||||
// increment root event ID either if we didn't just replay a cmd
|
||||
// buffer event, OR if we are doing a frame sub-section replay,
|
||||
// in which case it's up to the calling code to make sure we only
|
||||
// replay inside a command buffer (if we crossed command buffer
|
||||
// boundaries, the event IDs would no longer match up).
|
||||
if(m_LastCmdListID == ResourceId() || startEventID > 1)
|
||||
{
|
||||
m_RootEventID++;
|
||||
|
||||
if(startEventID > 1)
|
||||
m_pSerialiser->SetOffset(GetEvent(m_RootEventID).fileOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_BakedCmdListInfo[m_LastCmdListID].curEventID++;
|
||||
}
|
||||
}
|
||||
|
||||
m_pDevice->GPUSync();
|
||||
|
||||
if(m_State == READING)
|
||||
{
|
||||
struct SortEID
|
||||
{
|
||||
bool operator()(const FetchAPIEvent &a, const FetchAPIEvent &b)
|
||||
{
|
||||
return a.eventID < b.eventID;
|
||||
}
|
||||
};
|
||||
|
||||
std::sort(m_Events.begin(), m_Events.end(), SortEID());
|
||||
}
|
||||
|
||||
SAFE_RELEASE(m_PartialReplayData.resultPartialCmdList);
|
||||
|
||||
for(auto it = m_RerecordCmds.begin(); it != m_RerecordCmds.end(); ++it)
|
||||
SAFE_RELEASE(it->second);
|
||||
|
||||
m_RerecordCmds.clear();
|
||||
|
||||
m_State = READING;
|
||||
}
|
||||
|
||||
void WrappedID3D12CommandQueue::AddDrawcall(const FetchDrawcall &d, bool hasEvents)
|
||||
{
|
||||
m_AddedDrawcall = true;
|
||||
|
||||
FetchDrawcall draw = d;
|
||||
draw.eventID = m_LastCmdListID != ResourceId() ? m_BakedCmdListInfo[m_LastCmdListID].curEventID
|
||||
: m_RootEventID;
|
||||
draw.drawcallID = m_LastCmdListID != ResourceId() ? m_BakedCmdListInfo[m_LastCmdListID].drawCount
|
||||
: m_RootDrawcallID;
|
||||
|
||||
for(int i = 0; i < 8; i++)
|
||||
draw.outputs[i] = ResourceId();
|
||||
|
||||
draw.depthOut = ResourceId();
|
||||
|
||||
draw.indexByteWidth = 0;
|
||||
draw.topology = eTopology_Unknown;
|
||||
|
||||
if(m_LastCmdListID != ResourceId())
|
||||
{
|
||||
// TODO fill from m_BakedCmdListInfo[m_LastCmdListID].state
|
||||
}
|
||||
|
||||
if(m_LastCmdListID != ResourceId())
|
||||
m_BakedCmdListInfo[m_LastCmdListID].drawCount++;
|
||||
else
|
||||
m_RootDrawcallID++;
|
||||
|
||||
if(hasEvents)
|
||||
{
|
||||
vector<FetchAPIEvent> &srcEvents = m_LastCmdListID != ResourceId()
|
||||
? m_BakedCmdListInfo[m_LastCmdListID].curEvents
|
||||
: m_RootEvents;
|
||||
|
||||
draw.events = srcEvents;
|
||||
srcEvents.clear();
|
||||
}
|
||||
|
||||
// should have at least the root drawcall here, push this drawcall
|
||||
// onto the back's children list.
|
||||
if(!GetDrawcallStack().empty())
|
||||
{
|
||||
D3D12DrawcallTreeNode node(draw);
|
||||
|
||||
node.resourceUsage.swap(m_BakedCmdListInfo[m_LastCmdListID].resourceUsage);
|
||||
|
||||
// TODO add usage
|
||||
|
||||
node.children.insert(node.children.begin(), draw.children.elems,
|
||||
draw.children.elems + draw.children.count);
|
||||
GetDrawcallStack().back()->children.push_back(node);
|
||||
}
|
||||
else
|
||||
RDCERR("Somehow lost drawcall stack!");
|
||||
}
|
||||
|
||||
void WrappedID3D12CommandQueue::AddEvent(D3D12ChunkType type, string description)
|
||||
{
|
||||
FetchAPIEvent apievent;
|
||||
|
||||
apievent.context = ResourceId();
|
||||
apievent.fileOffset = m_CurChunkOffset;
|
||||
apievent.eventID = m_LastCmdListID != ResourceId() ? m_BakedCmdListInfo[m_LastCmdListID].curEventID
|
||||
: m_RootEventID;
|
||||
|
||||
apievent.eventDesc = description;
|
||||
|
||||
Callstack::Stackwalk *stack = m_pSerialiser->GetLastCallstack();
|
||||
if(stack)
|
||||
{
|
||||
create_array(apievent.callstack, stack->NumLevels());
|
||||
memcpy(apievent.callstack.elems, stack->GetAddrs(), sizeof(uint64_t) * stack->NumLevels());
|
||||
}
|
||||
|
||||
// TODO have real m_EventMessages
|
||||
vector<DebugMessage> m_EventMessages;
|
||||
|
||||
for(size_t i = 0; i < m_EventMessages.size(); i++)
|
||||
m_EventMessages[i].eventID = apievent.eventID;
|
||||
|
||||
if(m_LastCmdListID != ResourceId())
|
||||
{
|
||||
m_BakedCmdListInfo[m_LastCmdListID].curEvents.push_back(apievent);
|
||||
|
||||
vector<DebugMessage> &msgs = m_BakedCmdListInfo[m_LastCmdListID].debugMessages;
|
||||
|
||||
msgs.insert(msgs.end(), m_EventMessages.begin(), m_EventMessages.end());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_RootEvents.push_back(apievent);
|
||||
m_Events.push_back(apievent);
|
||||
|
||||
// TODO m_DebugMessages.insert(m_DebugMessages.end(), m_EventMessages.begin(),
|
||||
// m_EventMessages.end());
|
||||
}
|
||||
|
||||
m_EventMessages.clear();
|
||||
}
|
||||
|
||||
WrappedID3D12GraphicsCommandList::WrappedID3D12GraphicsCommandList(ID3D12GraphicsCommandList *real,
|
||||
WrappedID3D12Device *device,
|
||||
Serialiser *serialiser,
|
||||
@@ -238,7 +574,8 @@ WrappedID3D12GraphicsCommandList::WrappedID3D12GraphicsCommandList(ID3D12Graphic
|
||||
RenderDoc::Inst().GetCrashHandler()->RegisterMemoryRegion(
|
||||
this, sizeof(WrappedID3D12GraphicsCommandList));
|
||||
|
||||
m_pReal->QueryInterface(__uuidof(ID3D12DebugCommandList), (void **)&m_DummyDebug.m_pReal);
|
||||
if(m_pReal)
|
||||
m_pReal->QueryInterface(__uuidof(ID3D12DebugCommandList), (void **)&m_DummyDebug.m_pReal);
|
||||
|
||||
if(RenderDoc::Inst().IsReplayApp())
|
||||
{
|
||||
@@ -326,3 +663,13 @@ HRESULT STDMETHODCALLTYPE WrappedID3D12GraphicsCommandList::QueryInterface(REFII
|
||||
|
||||
return RefCounter12::QueryInterface(riid, ppvObject);
|
||||
}
|
||||
|
||||
void WrappedID3D12GraphicsCommandList::AddDrawcall(const FetchDrawcall &d, bool hasEvents)
|
||||
{
|
||||
m_pDevice->GetQueue()->AddDrawcall(d, hasEvents);
|
||||
}
|
||||
|
||||
void WrappedID3D12GraphicsCommandList::AddEvent(D3D12ChunkType type, string description)
|
||||
{
|
||||
m_pDevice->GetQueue()->AddEvent(type, description);
|
||||
}
|
||||
|
||||
@@ -151,62 +151,62 @@ void Serialiser::Serialise(const char *name, D3D12Descriptor &el);
|
||||
|
||||
#pragma region Chunks
|
||||
|
||||
#define D3D12_CHUNKS \
|
||||
D3D12_CHUNK_MACRO(DEVICE_INIT = FIRST_CHUNK_ID, "ID3D12Device::Initialisation") \
|
||||
D3D12_CHUNK_MACRO(SET_RESOURCE_NAME, "ID3D12Object::SetName") \
|
||||
D3D12_CHUNK_MACRO(RELEASE_RESOURCE, "IUnknown::Release") \
|
||||
D3D12_CHUNK_MACRO(CREATE_SWAP_BUFFER, "IDXGISwapChain::GetBuffer") \
|
||||
\
|
||||
D3D12_CHUNK_MACRO(CAPTURE_SCOPE, "Capture") \
|
||||
\
|
||||
D3D12_CHUNK_MACRO(PUSH_EVENT, "BeginEvent") \
|
||||
D3D12_CHUNK_MACRO(SET_MARKER, "SetMarker") \
|
||||
D3D12_CHUNK_MACRO(POP_EVENT, "EndEvent") \
|
||||
\
|
||||
D3D12_CHUNK_MACRO(DEBUG_MESSAGES, "DebugMessageList") \
|
||||
\
|
||||
D3D12_CHUNK_MACRO(CONTEXT_CAPTURE_HEADER, "ContextBegin") \
|
||||
D3D12_CHUNK_MACRO(CONTEXT_CAPTURE_FOOTER, "ContextEnd") \
|
||||
\
|
||||
D3D12_CHUNK_MACRO(SET_SHADER_DEBUG_PATH, "SetShaderDebugPath") \
|
||||
\
|
||||
D3D12_CHUNK_MACRO(CREATE_COMMAND_QUEUE, "ID3D12Device::CreateCommandQueue") \
|
||||
D3D12_CHUNK_MACRO(CREATE_COMMAND_ALLOCATOR, "ID3D12Device::CreateCommandAllocator") \
|
||||
D3D12_CHUNK_MACRO(CREATE_COMMAND_LIST, "ID3D12Device::CreateCommandList") \
|
||||
\
|
||||
D3D12_CHUNK_MACRO(CREATE_GRAPHICS_PIPE, "ID3D12Device::CreateGraphicsPipeline") \
|
||||
D3D12_CHUNK_MACRO(CREATE_COMPUTE_PIPE, "ID3D12Device::CreateComputePipeline") \
|
||||
D3D12_CHUNK_MACRO(CREATE_DESCRIPTOR_HEAP, "ID3D12Device::CreateDescriptorHeap") \
|
||||
D3D12_CHUNK_MACRO(CREATE_ROOT_SIG, "ID3D12Device::CreateRootSignature") \
|
||||
\
|
||||
D3D12_CHUNK_MACRO(CREATE_COMMITTED_RESOURCE, "ID3D12Device::CreateCommittedResource") \
|
||||
\
|
||||
D3D12_CHUNK_MACRO(CREATE_FENCE, "ID3D12Device::CreateFence") \
|
||||
\
|
||||
D3D12_CHUNK_MACRO(CLOSE_LIST, "ID3D12GraphicsCommandList::Close") \
|
||||
D3D12_CHUNK_MACRO(RESET_LIST, "ID3D12GraphicsCommandList::Reset") \
|
||||
\
|
||||
D3D12_CHUNK_MACRO(RESOURCE_BARRIER, "ID3D12GraphicsCommandList::ResourceBarrier") \
|
||||
\
|
||||
D3D12_CHUNK_MACRO(DRAW_INDEXED_INST, "ID3D12GraphicsCommandList::DrawIndexedInstanced") \
|
||||
D3D12_CHUNK_MACRO(COPY_BUFFER, "ID3D12GraphicsCommandList::CopyBufferRegion") \
|
||||
\
|
||||
D3D12_CHUNK_MACRO(CLEAR_RTV, "ID3D12GraphicsCommandList::ClearRenderTargetView") \
|
||||
\
|
||||
D3D12_CHUNK_MACRO(SET_TOPOLOGY, "ID3D12GraphicsCommandList::IASetPrimitiveTopology") \
|
||||
D3D12_CHUNK_MACRO(SET_IBUFFER, "ID3D12GraphicsCommandList::IASetIndexBuffer") \
|
||||
D3D12_CHUNK_MACRO(SET_VBUFFERS, "ID3D12GraphicsCommandList::IASetVertexBuffers") \
|
||||
D3D12_CHUNK_MACRO(SET_VIEWPORTS, "ID3D12GraphicsCommandList::RSSetViewports") \
|
||||
D3D12_CHUNK_MACRO(SET_SCISSORS, "ID3D12GraphicsCommandList::RSSetScissors") \
|
||||
D3D12_CHUNK_MACRO(SET_PIPE, "ID3D12GraphicsCommandList::SetPipelineState") \
|
||||
D3D12_CHUNK_MACRO(SET_RTVS, "ID3D12GraphicsCommandList::OMSetRenderTargets") \
|
||||
D3D12_CHUNK_MACRO(SET_ROOT_SIG, "ID3D12GraphicsCommandList::SetRootSignature") \
|
||||
D3D12_CHUNK_MACRO(SET_GFX_ROOT_CBV, \
|
||||
"ID3D12GraphicsCommandList::SetGraphicsRootConstantBufferView") \
|
||||
\
|
||||
D3D12_CHUNK_MACRO(EXECUTE_CMD_LISTS, "ID3D12GraphicsCommandQueue::ExecuteCommandLists") \
|
||||
D3D12_CHUNK_MACRO(SIGNAL, "ID3D12GraphicsCommandQueue::Signal") \
|
||||
\
|
||||
#define D3D12_CHUNKS \
|
||||
D3D12_CHUNK_MACRO(DEVICE_INIT = FIRST_CHUNK_ID, "ID3D12Device::Initialisation") \
|
||||
D3D12_CHUNK_MACRO(SET_RESOURCE_NAME, "ID3D12Object::SetName") \
|
||||
D3D12_CHUNK_MACRO(RELEASE_RESOURCE, "IUnknown::Release") \
|
||||
D3D12_CHUNK_MACRO(CREATE_SWAP_BUFFER, "IDXGISwapChain::GetBuffer") \
|
||||
\
|
||||
D3D12_CHUNK_MACRO(CAPTURE_SCOPE, "Capture") \
|
||||
\
|
||||
D3D12_CHUNK_MACRO(PUSH_EVENT, "BeginEvent") \
|
||||
D3D12_CHUNK_MACRO(SET_MARKER, "SetMarker") \
|
||||
D3D12_CHUNK_MACRO(POP_EVENT, "EndEvent") \
|
||||
\
|
||||
D3D12_CHUNK_MACRO(DEBUG_MESSAGES, "DebugMessageList") \
|
||||
\
|
||||
D3D12_CHUNK_MACRO(CONTEXT_CAPTURE_HEADER, "ContextBegin") \
|
||||
D3D12_CHUNK_MACRO(CONTEXT_CAPTURE_FOOTER, "ContextEnd") \
|
||||
\
|
||||
D3D12_CHUNK_MACRO(SET_SHADER_DEBUG_PATH, "SetShaderDebugPath") \
|
||||
\
|
||||
D3D12_CHUNK_MACRO(CREATE_COMMAND_QUEUE, "ID3D12Device::CreateCommandQueue") \
|
||||
D3D12_CHUNK_MACRO(CREATE_COMMAND_ALLOCATOR, "ID3D12Device::CreateCommandAllocator") \
|
||||
D3D12_CHUNK_MACRO(CREATE_COMMAND_LIST, "ID3D12Device::CreateCommandList") \
|
||||
\
|
||||
D3D12_CHUNK_MACRO(CREATE_GRAPHICS_PIPE, "ID3D12Device::CreateGraphicsPipeline") \
|
||||
D3D12_CHUNK_MACRO(CREATE_COMPUTE_PIPE, "ID3D12Device::CreateComputePipeline") \
|
||||
D3D12_CHUNK_MACRO(CREATE_DESCRIPTOR_HEAP, "ID3D12Device::CreateDescriptorHeap") \
|
||||
D3D12_CHUNK_MACRO(CREATE_ROOT_SIG, "ID3D12Device::CreateRootSignature") \
|
||||
\
|
||||
D3D12_CHUNK_MACRO(CREATE_COMMITTED_RESOURCE, "ID3D12Device::CreateCommittedResource") \
|
||||
\
|
||||
D3D12_CHUNK_MACRO(CREATE_FENCE, "ID3D12Device::CreateFence") \
|
||||
\
|
||||
D3D12_CHUNK_MACRO(CLOSE_LIST, "ID3D12GraphicsCommandList::Close") \
|
||||
D3D12_CHUNK_MACRO(RESET_LIST, "ID3D12GraphicsCommandList::Reset") \
|
||||
\
|
||||
D3D12_CHUNK_MACRO(RESOURCE_BARRIER, "ID3D12GraphicsCommandList::ResourceBarrier") \
|
||||
\
|
||||
D3D12_CHUNK_MACRO(DRAW_INDEXED_INST, "ID3D12GraphicsCommandList::DrawIndexedInstanced") \
|
||||
D3D12_CHUNK_MACRO(COPY_BUFFER, "ID3D12GraphicsCommandList::CopyBufferRegion") \
|
||||
\
|
||||
D3D12_CHUNK_MACRO(CLEAR_RTV, "ID3D12GraphicsCommandList::ClearRenderTargetView") \
|
||||
\
|
||||
D3D12_CHUNK_MACRO(SET_TOPOLOGY, "ID3D12GraphicsCommandList::IASetPrimitiveTopology") \
|
||||
D3D12_CHUNK_MACRO(SET_IBUFFER, "ID3D12GraphicsCommandList::IASetIndexBuffer") \
|
||||
D3D12_CHUNK_MACRO(SET_VBUFFERS, "ID3D12GraphicsCommandList::IASetVertexBuffers") \
|
||||
D3D12_CHUNK_MACRO(SET_VIEWPORTS, "ID3D12GraphicsCommandList::RSSetViewports") \
|
||||
D3D12_CHUNK_MACRO(SET_SCISSORS, "ID3D12GraphicsCommandList::RSSetScissors") \
|
||||
D3D12_CHUNK_MACRO(SET_PIPE, "ID3D12GraphicsCommandList::SetPipelineState") \
|
||||
D3D12_CHUNK_MACRO(SET_RTVS, "ID3D12GraphicsCommandList::OMSetRenderTargets") \
|
||||
D3D12_CHUNK_MACRO(SET_GFX_ROOT_SIG, "ID3D12GraphicsCommandList::SetGraphicsRootSignature") \
|
||||
D3D12_CHUNK_MACRO(SET_GFX_ROOT_CBV, \
|
||||
"ID3D12GraphicsCommandList::SetGraphicsRootConstantBufferView") \
|
||||
\
|
||||
D3D12_CHUNK_MACRO(EXECUTE_CMD_LISTS, "ID3D12GraphicsCommandQueue::ExecuteCommandLists") \
|
||||
D3D12_CHUNK_MACRO(SIGNAL, "ID3D12GraphicsCommandQueue::Signal") \
|
||||
\
|
||||
D3D12_CHUNK_MACRO(NUM_D3D12_CHUNKS, "")
|
||||
|
||||
enum D3D12ChunkType
|
||||
|
||||
@@ -0,0 +1,381 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2016 Baldur Karlsson
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#include "d3d12_debug.h"
|
||||
#include "d3d12_command_queue.h"
|
||||
#include "d3d12_device.h"
|
||||
|
||||
D3D12DebugManager::D3D12DebugManager(WrappedID3D12Device *wrapper)
|
||||
{
|
||||
if(RenderDoc::Inst().GetCrashHandler())
|
||||
RenderDoc::Inst().GetCrashHandler()->RegisterMemoryRegion(this, sizeof(D3D12DebugManager));
|
||||
|
||||
m_Device = wrapper->GetReal();
|
||||
m_ResourceManager = wrapper->GetResourceManager();
|
||||
|
||||
m_OutputWindowID = 1;
|
||||
|
||||
m_WrappedDevice = wrapper;
|
||||
m_WrappedDevice->InternalRef();
|
||||
|
||||
RenderDoc::Inst().SetProgress(DebugManagerInit, 0.0f);
|
||||
|
||||
m_pFactory = NULL;
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
IDXGIDevice *pDXGIDevice;
|
||||
hr = m_WrappedDevice->QueryInterface(__uuidof(IDXGIDevice), (void **)&pDXGIDevice);
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
RDCERR("Couldn't get DXGI device from D3D device");
|
||||
}
|
||||
else
|
||||
{
|
||||
IDXGIAdapter *pDXGIAdapter;
|
||||
hr = pDXGIDevice->GetParent(__uuidof(IDXGIAdapter), (void **)&pDXGIAdapter);
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
RDCERR("Couldn't get DXGI adapter from DXGI device");
|
||||
SAFE_RELEASE(pDXGIDevice);
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = pDXGIAdapter->GetParent(__uuidof(IDXGIFactory), (void **)&m_pFactory);
|
||||
|
||||
SAFE_RELEASE(pDXGIDevice);
|
||||
SAFE_RELEASE(pDXGIAdapter);
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
RDCERR("Couldn't get DXGI factory from DXGI adapter");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
D3D12_DESCRIPTOR_HEAP_DESC desc;
|
||||
desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
|
||||
desc.NodeMask = 1;
|
||||
desc.NumDescriptors = 1024;
|
||||
desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
|
||||
|
||||
hr = m_WrappedDevice->CreateDescriptorHeap(&desc, __uuidof(ID3D12DescriptorHeap),
|
||||
(void **)&rtvHeap);
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
RDCERR("Couldn't create RTV descriptor heap!");
|
||||
}
|
||||
|
||||
desc.NumDescriptors = 16;
|
||||
desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV;
|
||||
|
||||
hr = m_WrappedDevice->CreateDescriptorHeap(&desc, __uuidof(ID3D12DescriptorHeap),
|
||||
(void **)&dsvHeap);
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
RDCERR("Couldn't create DSV descriptor heap!");
|
||||
}
|
||||
|
||||
RenderDoc::Inst().SetProgress(DebugManagerInit, 1.0f);
|
||||
}
|
||||
|
||||
D3D12DebugManager::~D3D12DebugManager()
|
||||
{
|
||||
SAFE_RELEASE(m_pFactory);
|
||||
|
||||
m_WrappedDevice->InternalRelease();
|
||||
|
||||
if(RenderDoc::Inst().GetCrashHandler())
|
||||
RenderDoc::Inst().GetCrashHandler()->UnregisterMemoryRegion(this);
|
||||
}
|
||||
|
||||
void D3D12DebugManager::OutputWindow::MakeDSV()
|
||||
{
|
||||
SAFE_RELEASE(depth);
|
||||
|
||||
D3D12_RESOURCE_DESC texDesc = bb->GetDesc();
|
||||
|
||||
texDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
|
||||
texDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
|
||||
|
||||
D3D12_HEAP_PROPERTIES heapProps;
|
||||
heapProps.Type = D3D12_HEAP_TYPE_DEFAULT;
|
||||
heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||
heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
||||
heapProps.CreationNodeMask = 1;
|
||||
heapProps.VisibleNodeMask = 1;
|
||||
|
||||
HRESULT hr = dev->CreateCommittedResource(
|
||||
&heapProps, D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES, &texDesc,
|
||||
D3D12_RESOURCE_STATE_DEPTH_WRITE | D3D12_RESOURCE_STATE_DEPTH_READ, NULL,
|
||||
__uuidof(ID3D12Resource), (void **)&depth);
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
RDCERR("Failed to create DSV texture for main output, HRESULT: 0x%08x", hr);
|
||||
return;
|
||||
}
|
||||
|
||||
dev->CreateDepthStencilView(depth, NULL, dsv);
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
RDCERR("Failed to create DSV for main output, HRESULT: 0x%08x", hr);
|
||||
SAFE_RELEASE(swap);
|
||||
SAFE_RELEASE(depth);
|
||||
SAFE_RELEASE(bb);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t D3D12DebugManager::MakeOutputWindow(void *w, bool depth)
|
||||
{
|
||||
OutputWindow outw;
|
||||
outw.wnd = (HWND)w;
|
||||
outw.dev = m_WrappedDevice;
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC swapDesc;
|
||||
RDCEraseEl(swapDesc);
|
||||
|
||||
RECT rect;
|
||||
GetClientRect(outw.wnd, &rect);
|
||||
|
||||
swapDesc.BufferCount = 2;
|
||||
swapDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
|
||||
outw.width = swapDesc.BufferDesc.Width = rect.right - rect.left;
|
||||
outw.height = swapDesc.BufferDesc.Height = rect.bottom - rect.top;
|
||||
swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
swapDesc.SampleDesc.Count = depth ? 4 : 1;
|
||||
swapDesc.SampleDesc.Quality = 0;
|
||||
swapDesc.OutputWindow = outw.wnd;
|
||||
swapDesc.Windowed = TRUE;
|
||||
swapDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
|
||||
swapDesc.Flags = 0;
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
hr = m_pFactory->CreateSwapChain(m_WrappedDevice->GetQueue()->GetReal(), &swapDesc, &outw.swap);
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
RDCERR("Failed to create swap chain for HWND, HRESULT: 0x%08x", hr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
outw.swap->GetBuffer(0, __uuidof(ID3D12Resource), (void **)&outw.bb);
|
||||
|
||||
outw.rtv = rtvHeap->GetCPUDescriptorHandleForHeapStart();
|
||||
outw.rtv.ptr += m_OutputWindowID *
|
||||
m_WrappedDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
|
||||
|
||||
outw.dsv = dsvHeap->GetCPUDescriptorHandleForHeapStart();
|
||||
outw.dsv.ptr += m_OutputWindowID *
|
||||
m_WrappedDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV);
|
||||
|
||||
m_WrappedDevice->CreateRenderTargetView(outw.bb, NULL, outw.rtv);
|
||||
|
||||
outw.depth = NULL;
|
||||
if(depth)
|
||||
outw.MakeDSV();
|
||||
|
||||
uint64_t id = m_OutputWindowID++;
|
||||
m_OutputWindows[id] = outw;
|
||||
return id;
|
||||
}
|
||||
|
||||
void D3D12DebugManager::DestroyOutputWindow(uint64_t id)
|
||||
{
|
||||
auto it = m_OutputWindows.find(id);
|
||||
if(id == 0 || it == m_OutputWindows.end())
|
||||
return;
|
||||
|
||||
OutputWindow &outw = it->second;
|
||||
|
||||
SAFE_RELEASE(outw.swap);
|
||||
SAFE_RELEASE(outw.bb);
|
||||
SAFE_RELEASE(outw.depth);
|
||||
|
||||
m_OutputWindows.erase(it);
|
||||
}
|
||||
|
||||
bool D3D12DebugManager::CheckResizeOutputWindow(uint64_t id)
|
||||
{
|
||||
if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end())
|
||||
return false;
|
||||
|
||||
OutputWindow &outw = m_OutputWindows[id];
|
||||
|
||||
if(outw.wnd == NULL || outw.swap == NULL)
|
||||
return false;
|
||||
|
||||
RECT rect;
|
||||
GetClientRect(outw.wnd, &rect);
|
||||
long w = rect.right - rect.left;
|
||||
long h = rect.bottom - rect.top;
|
||||
|
||||
if(w != outw.width || h != outw.height)
|
||||
{
|
||||
outw.width = w;
|
||||
outw.height = h;
|
||||
|
||||
m_WrappedDevice->GPUSync();
|
||||
|
||||
if(outw.width > 0 && outw.height > 0)
|
||||
{
|
||||
SAFE_RELEASE(outw.bb);
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC desc;
|
||||
outw.swap->GetDesc(&desc);
|
||||
|
||||
HRESULT hr = outw.swap->ResizeBuffers(desc.BufferCount, outw.width, outw.height,
|
||||
desc.BufferDesc.Format, desc.Flags);
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
RDCERR("Failed to resize swap chain, HRESULT: 0x%08x", hr);
|
||||
return true;
|
||||
}
|
||||
|
||||
outw.swap->GetBuffer(0, __uuidof(ID3D12Resource), (void **)&outw.bb);
|
||||
|
||||
m_WrappedDevice->CreateRenderTargetView(outw.bb, NULL, outw.rtv);
|
||||
if(outw.depth)
|
||||
outw.MakeDSV();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void D3D12DebugManager::GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h)
|
||||
{
|
||||
if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end())
|
||||
return;
|
||||
|
||||
w = m_OutputWindows[id].width;
|
||||
h = m_OutputWindows[id].height;
|
||||
}
|
||||
|
||||
void D3D12DebugManager::ClearOutputWindowColour(uint64_t id, float col[4])
|
||||
{
|
||||
if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end())
|
||||
return;
|
||||
|
||||
m_WrappedDevice->GetList()->Reset(m_WrappedDevice->GetAlloc(), NULL);
|
||||
|
||||
m_WrappedDevice->GetList()->ClearRenderTargetView(Unwrap(m_OutputWindows[id].rtv), col, 0, NULL);
|
||||
|
||||
m_WrappedDevice->GetList()->Close();
|
||||
|
||||
ID3D12CommandList *list = (ID3D12CommandList *)m_WrappedDevice->GetList();
|
||||
m_WrappedDevice->GetQueue()->GetReal()->ExecuteCommandLists(1, &list);
|
||||
}
|
||||
|
||||
void D3D12DebugManager::ClearOutputWindowDepth(uint64_t id, float depth, uint8_t stencil)
|
||||
{
|
||||
if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end())
|
||||
return;
|
||||
|
||||
m_WrappedDevice->GetList()->Reset(m_WrappedDevice->GetAlloc(), NULL);
|
||||
|
||||
m_WrappedDevice->GetList()->ClearDepthStencilView(
|
||||
Unwrap(m_OutputWindows[id].dsv), D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, depth,
|
||||
stencil, 0, NULL);
|
||||
|
||||
m_WrappedDevice->GetList()->Close();
|
||||
|
||||
ID3D12CommandList *list = (ID3D12CommandList *)m_WrappedDevice->GetList();
|
||||
m_WrappedDevice->GetQueue()->GetReal()->ExecuteCommandLists(1, &list);
|
||||
}
|
||||
|
||||
void D3D12DebugManager::BindOutputWindow(uint64_t id, bool depth)
|
||||
{
|
||||
if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end())
|
||||
return;
|
||||
|
||||
OutputWindow &outw = m_OutputWindows[id];
|
||||
|
||||
if(outw.bb == NULL)
|
||||
return;
|
||||
|
||||
m_width = (int32_t)outw.width;
|
||||
m_height = (int32_t)outw.height;
|
||||
|
||||
D3D12_RESOURCE_BARRIER barrier;
|
||||
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||
barrier.Transition.pResource = Unwrap(m_OutputWindows[id].bb);
|
||||
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
|
||||
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||
|
||||
m_WrappedDevice->GetList()->Reset(m_WrappedDevice->GetAlloc(), NULL);
|
||||
|
||||
m_WrappedDevice->GetList()->ResourceBarrier(1, &barrier);
|
||||
|
||||
m_WrappedDevice->GetList()->Close();
|
||||
|
||||
ID3D12CommandList *list = (ID3D12CommandList *)m_WrappedDevice->GetList();
|
||||
m_WrappedDevice->GetQueue()->GetReal()->ExecuteCommandLists(1, &list);
|
||||
}
|
||||
|
||||
bool D3D12DebugManager::IsOutputWindowVisible(uint64_t id)
|
||||
{
|
||||
if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end())
|
||||
return false;
|
||||
|
||||
return (IsWindowVisible(m_OutputWindows[id].wnd) == TRUE);
|
||||
}
|
||||
|
||||
void D3D12DebugManager::FlipOutputWindow(uint64_t id)
|
||||
{
|
||||
if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end())
|
||||
return;
|
||||
|
||||
if(m_OutputWindows[id].swap)
|
||||
{
|
||||
D3D12_RESOURCE_BARRIER barrier;
|
||||
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||
barrier.Transition.pResource = Unwrap(m_OutputWindows[id].bb);
|
||||
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
|
||||
|
||||
m_WrappedDevice->GetList()->Reset(m_WrappedDevice->GetAlloc(), NULL);
|
||||
|
||||
m_WrappedDevice->GetList()->ResourceBarrier(1, &barrier);
|
||||
|
||||
m_WrappedDevice->GetList()->Close();
|
||||
|
||||
ID3D12CommandList *list = (ID3D12CommandList *)m_WrappedDevice->GetList();
|
||||
m_WrappedDevice->GetQueue()->GetReal()->ExecuteCommandLists(1, &list);
|
||||
|
||||
m_OutputWindows[id].swap->Present(0, 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2016 Baldur Karlsson
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "api/replay/renderdoc_replay.h"
|
||||
#include "core/core.h"
|
||||
#include "replay/replay_driver.h"
|
||||
#include "d3d12_common.h"
|
||||
|
||||
class WrappedID3D12Device;
|
||||
class D3D12ResourceManager;
|
||||
|
||||
class D3D12DebugManager
|
||||
{
|
||||
public:
|
||||
D3D12DebugManager(WrappedID3D12Device *wrapper);
|
||||
~D3D12DebugManager();
|
||||
|
||||
uint64_t MakeOutputWindow(void *w, bool depth);
|
||||
void DestroyOutputWindow(uint64_t id);
|
||||
bool CheckResizeOutputWindow(uint64_t id);
|
||||
void GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h);
|
||||
void ClearOutputWindowColour(uint64_t id, float col[4]);
|
||||
void ClearOutputWindowDepth(uint64_t id, float depth, uint8_t stencil);
|
||||
void BindOutputWindow(uint64_t id, bool depth);
|
||||
bool IsOutputWindowVisible(uint64_t id);
|
||||
void FlipOutputWindow(uint64_t id);
|
||||
|
||||
void SetOutputDimensions(int w, int h)
|
||||
{
|
||||
m_width = w;
|
||||
m_height = h;
|
||||
}
|
||||
int GetWidth() { return m_width; }
|
||||
int GetHeight() { return m_height; }
|
||||
private:
|
||||
struct OutputWindow
|
||||
{
|
||||
HWND wnd;
|
||||
IDXGISwapChain *swap;
|
||||
ID3D12Resource *bb;
|
||||
ID3D12Resource *depth;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE rtv;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE dsv;
|
||||
|
||||
WrappedID3D12Device *dev;
|
||||
|
||||
void MakeDSV();
|
||||
|
||||
int width, height;
|
||||
};
|
||||
|
||||
ID3D12DescriptorHeap *rtvHeap;
|
||||
ID3D12DescriptorHeap *dsvHeap;
|
||||
|
||||
int m_width, m_height;
|
||||
|
||||
uint64_t m_OutputWindowID;
|
||||
map<uint64_t, OutputWindow> m_OutputWindows;
|
||||
|
||||
WrappedID3D12Device *m_WrappedDevice;
|
||||
ID3D12Device *m_Device;
|
||||
|
||||
IDXGIFactory *m_pFactory;
|
||||
|
||||
D3D12ResourceManager *m_ResourceManager;
|
||||
};
|
||||
@@ -557,6 +557,8 @@ IUnknown *WrappedID3D12Device::WrapSwapchainBuffer(WrappedIDXGISwapChain3 *swap,
|
||||
return tex;
|
||||
}
|
||||
|
||||
LazyInit();
|
||||
|
||||
ID3D12Resource *pRes = new WrappedID3D12Resource((ID3D12Resource *)realSurface, this);
|
||||
|
||||
ResourceId id = GetResID(pRes);
|
||||
@@ -803,6 +805,27 @@ HRESULT WrappedID3D12Device::Present(WrappedIDXGISwapChain3 *swap, UINT SyncInte
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void WrappedID3D12Device::Serialise_CaptureScope(uint64_t offset)
|
||||
{
|
||||
uint32_t FrameNumber = m_FrameCounter;
|
||||
m_pSerialiser->Serialise("FrameNumber", FrameNumber);
|
||||
|
||||
if(m_State >= WRITING)
|
||||
{
|
||||
GetResourceManager()->Serialise_InitialContentsNeeded();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_FrameRecord.frameInfo.fileOffset = offset;
|
||||
m_FrameRecord.frameInfo.firstEvent = 1;
|
||||
m_FrameRecord.frameInfo.frameNumber = FrameNumber;
|
||||
m_FrameRecord.frameInfo.immContextId = ResourceId();
|
||||
RDCEraseEl(m_FrameRecord.frameInfo.stats);
|
||||
|
||||
GetResourceManager()->CreateInitialContents();
|
||||
}
|
||||
}
|
||||
|
||||
bool WrappedID3D12Device::Serialise_BeginCaptureFrame(bool applyInitialState)
|
||||
{
|
||||
if(m_State < WRITING && !applyInitialState)
|
||||
@@ -828,27 +851,6 @@ bool WrappedID3D12Device::Serialise_BeginCaptureFrame(bool applyInitialState)
|
||||
return true;
|
||||
}
|
||||
|
||||
void WrappedID3D12Device::Serialise_CaptureScope(uint64_t offset)
|
||||
{
|
||||
uint32_t FrameNumber = m_FrameCounter;
|
||||
m_pSerialiser->Serialise("FrameNumber", FrameNumber);
|
||||
|
||||
if(m_State >= WRITING)
|
||||
{
|
||||
GetResourceManager()->Serialise_InitialContentsNeeded();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_FrameRecord.frameInfo.fileOffset = offset;
|
||||
m_FrameRecord.frameInfo.firstEvent = 1;
|
||||
m_FrameRecord.frameInfo.frameNumber = FrameNumber;
|
||||
m_FrameRecord.frameInfo.immContextId = ResourceId();
|
||||
RDCEraseEl(m_FrameRecord.frameInfo.stats);
|
||||
|
||||
GetResourceManager()->CreateInitialContents();
|
||||
}
|
||||
}
|
||||
|
||||
void WrappedID3D12Device::EndCaptureFrame(ID3D12Resource *presentImage)
|
||||
{
|
||||
SCOPED_SERIALISE_CONTEXT(CONTEXT_CAPTURE_FOOTER);
|
||||
@@ -972,9 +974,7 @@ bool WrappedID3D12Device::EndFrameCapture(void *dev, void *wnd)
|
||||
|
||||
m_State = WRITING_IDLE;
|
||||
|
||||
// TODO wait for idle
|
||||
|
||||
// TODO free coherent map capture ref-data
|
||||
GPUSync();
|
||||
}
|
||||
|
||||
byte *thpixels = NULL;
|
||||
@@ -1238,10 +1238,211 @@ void WrappedID3D12Device::GPUSync()
|
||||
WaitForSingleObject(m_GPUSyncHandle, 2000);
|
||||
}
|
||||
|
||||
// need to create this dummy here so that we can record D3D12.
|
||||
ReplayCreateStatus D3D12_CreateReplayDevice(const char *logfile, IReplayDriver **driver)
|
||||
void WrappedID3D12Device::SetLogFile(const char *logfile)
|
||||
{
|
||||
return eReplayCreate_APIUnsupported;
|
||||
m_pSerialiser = new Serialiser(logfile, Serialiser::READING, false);
|
||||
m_pSerialiser->SetChunkNameLookup(&GetChunkName);
|
||||
|
||||
SAFE_DELETE(m_ResourceManager);
|
||||
m_ResourceManager = new D3D12ResourceManager(m_State, m_pSerialiser, this);
|
||||
}
|
||||
|
||||
static DriverRegistration D3D12DriverRegistration(RDC_D3D12, "D3D12", &D3D12_CreateReplayDevice);
|
||||
void WrappedID3D12Device::LazyInit()
|
||||
{
|
||||
m_DebugManager = new D3D12DebugManager(this);
|
||||
}
|
||||
|
||||
const FetchDrawcall *WrappedID3D12Device::GetDrawcall(uint32_t eventID)
|
||||
{
|
||||
if(eventID >= m_Drawcalls.size())
|
||||
return NULL;
|
||||
|
||||
return m_Drawcalls[eventID];
|
||||
}
|
||||
|
||||
void WrappedID3D12Device::ProcessChunk(uint64_t offset, D3D12ChunkType context)
|
||||
{
|
||||
switch(context)
|
||||
{
|
||||
case DEVICE_INIT: { break;
|
||||
}
|
||||
|
||||
case CREATE_COMMAND_QUEUE: Serialise_CreateCommandQueue(NULL, IID(), NULL); break;
|
||||
case CREATE_COMMAND_ALLOCATOR:
|
||||
Serialise_CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID(), NULL);
|
||||
break;
|
||||
case CREATE_COMMAND_LIST:
|
||||
Serialise_CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, NULL, NULL, IID(), NULL);
|
||||
break;
|
||||
|
||||
case CREATE_GRAPHICS_PIPE: Serialise_CreateGraphicsPipelineState(NULL, IID(), NULL); break;
|
||||
case CREATE_COMPUTE_PIPE: Serialise_CreateComputePipelineState(NULL, IID(), NULL); break;
|
||||
case CREATE_DESCRIPTOR_HEAP: Serialise_CreateDescriptorHeap(NULL, IID(), NULL); break;
|
||||
case CREATE_ROOT_SIG: Serialise_CreateRootSignature(0, NULL, 0, IID(), NULL); break;
|
||||
|
||||
case CREATE_COMMITTED_RESOURCE:
|
||||
Serialise_CreateCommittedResource(NULL, D3D12_HEAP_FLAG_NONE, NULL,
|
||||
D3D12_RESOURCE_STATE_COMMON, NULL, IID(), NULL);
|
||||
break;
|
||||
|
||||
case CREATE_FENCE: Serialise_CreateFence(0, D3D12_FENCE_FLAG_NONE, IID(), NULL); break;
|
||||
|
||||
case SET_RESOURCE_NAME: Serialise_SetResourceName(0x0, ""); break;
|
||||
case SET_SHADER_DEBUG_PATH: Serialise_SetShaderDebugPath(NULL, NULL); break;
|
||||
case RELEASE_RESOURCE: Serialise_ReleaseResource(0x0); break;
|
||||
case CREATE_SWAP_BUFFER: Serialise_WrapSwapchainBuffer(NULL, NULL, 0, NULL); break;
|
||||
case CAPTURE_SCOPE: Serialise_CaptureScope(offset); break;
|
||||
default:
|
||||
// ignore system chunks
|
||||
if(context == INITIAL_CONTENTS)
|
||||
GetResourceManager()->Serialise_InitialState(ResourceId(), NULL);
|
||||
else if(context < FIRST_CHUNK_ID)
|
||||
m_pSerialiser->SkipCurrentChunk();
|
||||
else
|
||||
RDCERR("Unexpected non-device chunk %d at offset %llu", context, offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void WrappedID3D12Device::ReadLogInitialisation()
|
||||
{
|
||||
uint64_t frameOffset = 0;
|
||||
|
||||
m_pSerialiser->SetDebugText(true);
|
||||
|
||||
m_pSerialiser->Rewind();
|
||||
|
||||
int chunkIdx = 0;
|
||||
|
||||
struct chunkinfo
|
||||
{
|
||||
chunkinfo() : count(0), totalsize(0), total(0.0) {}
|
||||
int count;
|
||||
uint64_t totalsize;
|
||||
double total;
|
||||
};
|
||||
|
||||
map<D3D12ChunkType, chunkinfo> chunkInfos;
|
||||
|
||||
SCOPED_TIMER("chunk initialisation");
|
||||
|
||||
for(;;)
|
||||
{
|
||||
PerformanceTimer timer;
|
||||
|
||||
uint64_t offset = m_pSerialiser->GetOffset();
|
||||
|
||||
D3D12ChunkType context = (D3D12ChunkType)m_pSerialiser->PushContext(NULL, NULL, 1, false);
|
||||
|
||||
if(context == CAPTURE_SCOPE)
|
||||
{
|
||||
// immediately read rest of log into memory
|
||||
m_pSerialiser->SetPersistentBlock(offset);
|
||||
}
|
||||
|
||||
chunkIdx++;
|
||||
|
||||
ProcessChunk(offset, context);
|
||||
|
||||
m_pSerialiser->PopContext(context);
|
||||
|
||||
RenderDoc::Inst().SetProgress(FileInitialRead, float(offset) / float(m_pSerialiser->GetSize()));
|
||||
|
||||
if(context == CAPTURE_SCOPE)
|
||||
{
|
||||
frameOffset = offset;
|
||||
|
||||
GetResourceManager()->ApplyInitialContents();
|
||||
|
||||
m_Queue->ReplayLog(READING, 0, 0, false);
|
||||
}
|
||||
|
||||
uint64_t offset2 = m_pSerialiser->GetOffset();
|
||||
|
||||
chunkInfos[context].total += timer.GetMilliseconds();
|
||||
chunkInfos[context].totalsize += offset2 - offset;
|
||||
chunkInfos[context].count++;
|
||||
|
||||
if(context == CAPTURE_SCOPE)
|
||||
break;
|
||||
|
||||
if(m_pSerialiser->AtEnd())
|
||||
break;
|
||||
}
|
||||
|
||||
if(m_State == READING)
|
||||
{
|
||||
GetFrameRecord().drawcallList = m_Queue->GetParentDrawcall().Bake();
|
||||
|
||||
m_Queue->GetParentDrawcall().children.clear();
|
||||
|
||||
SetupDrawcallPointers(&m_Drawcalls, m_FrameRecord.frameInfo.immContextId,
|
||||
m_FrameRecord.drawcallList, NULL, NULL);
|
||||
}
|
||||
|
||||
#if !defined(RELEASE)
|
||||
for(auto it = chunkInfos.begin(); it != chunkInfos.end(); ++it)
|
||||
{
|
||||
double dcount = double(it->second.count);
|
||||
|
||||
RDCDEBUG(
|
||||
"% 5d chunks - Time: %9.3fms total/%9.3fms avg - Size: %8.3fMB total/%7.3fMB avg - %s (%u)",
|
||||
it->second.count, it->second.total, it->second.total / dcount,
|
||||
double(it->second.totalsize) / (1024.0 * 1024.0),
|
||||
double(it->second.totalsize) / (dcount * 1024.0 * 1024.0), GetChunkName(it->first),
|
||||
uint32_t(it->first));
|
||||
}
|
||||
#endif
|
||||
|
||||
m_FrameRecord.frameInfo.fileSize = m_pSerialiser->GetSize();
|
||||
m_FrameRecord.frameInfo.persistentSize = m_pSerialiser->GetSize() - frameOffset;
|
||||
m_FrameRecord.frameInfo.initDataSize = chunkInfos[(D3D12ChunkType)INITIAL_CONTENTS].totalsize;
|
||||
|
||||
RDCDEBUG("Allocating %llu persistant bytes of memory for the log.",
|
||||
m_pSerialiser->GetSize() - frameOffset);
|
||||
|
||||
m_pSerialiser->SetDebugText(false);
|
||||
}
|
||||
|
||||
void WrappedID3D12Device::ReplayLog(uint32_t startEventID, uint32_t endEventID,
|
||||
ReplayLogType replayType)
|
||||
{
|
||||
uint64_t offs = m_FrameRecord.frameInfo.fileOffset;
|
||||
|
||||
m_pSerialiser->SetOffset(offs);
|
||||
|
||||
bool partial = true;
|
||||
|
||||
if(startEventID == 0 && (replayType == eReplay_WithoutDraw || replayType == eReplay_Full))
|
||||
{
|
||||
startEventID = m_FrameRecord.frameInfo.firstEvent;
|
||||
partial = false;
|
||||
}
|
||||
|
||||
D3D12ChunkType header = (D3D12ChunkType)m_pSerialiser->PushContext(NULL, NULL, 1, false);
|
||||
|
||||
RDCASSERTEQUAL(header, CAPTURE_SCOPE);
|
||||
|
||||
m_pSerialiser->SkipCurrentChunk();
|
||||
|
||||
m_pSerialiser->PopContext(header);
|
||||
|
||||
if(!partial)
|
||||
{
|
||||
GetResourceManager()->ApplyInitialContents();
|
||||
GetResourceManager()->ReleaseInFrameResources();
|
||||
|
||||
GPUSync();
|
||||
}
|
||||
|
||||
m_State = EXECUTING;
|
||||
|
||||
if(replayType == eReplay_Full)
|
||||
m_Queue->ReplayLog(EXECUTING, startEventID, endEventID, partial);
|
||||
else if(replayType == eReplay_WithoutDraw)
|
||||
m_Queue->ReplayLog(EXECUTING, startEventID, RDCMAX(1U, endEventID) - 1, partial);
|
||||
else if(replayType == eReplay_OnlyDraw)
|
||||
m_Queue->ReplayLog(EXECUTING, endEventID, endEventID, partial);
|
||||
else
|
||||
RDCFATAL("Unexpected replay type");
|
||||
}
|
||||
|
||||
@@ -34,7 +34,9 @@
|
||||
#include "driver/dxgi/dxgi_wrapped.h"
|
||||
#include "replay/replay_driver.h"
|
||||
#include "d3d12_common.h"
|
||||
#include "d3d12_debug.h"
|
||||
#include "d3d12_manager.h"
|
||||
#include "d3d12_replay.h"
|
||||
|
||||
struct D3D12InitParams : public RDCInitParams
|
||||
{
|
||||
@@ -233,6 +235,13 @@ private:
|
||||
DummyID3D12DebugDevice m_DummyDebug;
|
||||
WrappedID3D12DebugDevice m_WrappedDebug;
|
||||
|
||||
D3D12Replay m_Replay;
|
||||
D3D12DebugManager *m_DebugManager;
|
||||
|
||||
void LazyInit();
|
||||
|
||||
void ProcessChunk(uint64_t offset, D3D12ChunkType context);
|
||||
|
||||
unsigned int m_InternalRefcount;
|
||||
RefCounter12<ID3D12Device> m_RefCounter;
|
||||
RefCounter12<ID3D12Device> m_SoftRefCounter;
|
||||
@@ -241,6 +250,7 @@ private:
|
||||
uint32_t m_FrameCounter;
|
||||
vector<FetchFrameInfo> m_CapturedFrames;
|
||||
FetchFrameRecord m_FrameRecord;
|
||||
vector<FetchDrawcall *> m_Drawcalls;
|
||||
|
||||
PerformanceTimer m_FrameTimer;
|
||||
vector<double> m_FrameTimes;
|
||||
@@ -284,7 +294,6 @@ private:
|
||||
UINT m_DescriptorIncrements[D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES];
|
||||
|
||||
void Serialise_CaptureScope(uint64_t offset);
|
||||
bool Serialise_BeginCaptureFrame(bool applyInitialState);
|
||||
void EndCaptureFrame(ID3D12Resource *presentImage);
|
||||
|
||||
public:
|
||||
@@ -305,12 +314,23 @@ public:
|
||||
ID3D12Device *GetReal() { return m_pDevice; }
|
||||
static const char *GetChunkName(uint32_t idx);
|
||||
D3D12ResourceManager *GetResourceManager() { return m_ResourceManager; }
|
||||
D3D12DebugManager *GetDebugManager() { return m_DebugManager; }
|
||||
Serialiser *GetSerialiser() { return m_pSerialiser; }
|
||||
ResourceId GetResourceID() { return m_ResourceID; }
|
||||
Threading::CriticalSection &GetCapTransitionLock() { return m_CapTransitionLock; }
|
||||
void ReleaseSwapchainResources(IDXGISwapChain *swap, IUnknown **backbuffers, int numBackbuffers);
|
||||
void FirstFrame(WrappedIDXGISwapChain3 *swap);
|
||||
FetchFrameRecord GetFrameRecord() { return m_FrameRecord; }
|
||||
const FetchDrawcall *GetDrawcall(uint32_t eventID);
|
||||
|
||||
void SetLogFile(const char *logfile);
|
||||
void SetLogVersion(uint32_t fileversion)
|
||||
{
|
||||
LazyInit();
|
||||
m_InitParams.SerialiseVersion = fileversion;
|
||||
}
|
||||
|
||||
D3D12Replay *GetReplay() { return &m_Replay; }
|
||||
WrappedID3D12CommandQueue *GetQueue() { return m_Queue; }
|
||||
ID3D12CommandAllocator *GetAlloc() { return m_Alloc; }
|
||||
ID3D12GraphicsCommandList *GetList() { return m_List; }
|
||||
@@ -320,6 +340,11 @@ public:
|
||||
void StartFrameCapture(void *dev, void *wnd);
|
||||
bool EndFrameCapture(void *dev, void *wnd);
|
||||
|
||||
bool Serialise_BeginCaptureFrame(bool applyInitialState);
|
||||
|
||||
void ReadLogInitialisation();
|
||||
void ReplayLog(uint32_t startEventID, uint32_t endEventID, ReplayLogType replayType);
|
||||
|
||||
// interface for DXGI
|
||||
virtual IUnknown *GetRealIUnknown() { return GetReal(); }
|
||||
virtual IID GetBackbufferUUID() { return __uuidof(ID3D12Resource); }
|
||||
|
||||
@@ -297,6 +297,8 @@ public:
|
||||
void SerialiseResourceStates(vector<D3D12_RESOURCE_BARRIER> &barriers,
|
||||
map<ResourceId, SubresourceStateVector> &states);
|
||||
|
||||
bool Serialise_InitialState(ResourceId resid, ID3D12DeviceChild *res);
|
||||
|
||||
private:
|
||||
bool SerialisableResource(ResourceId id, D3D12ResourceRecord *record);
|
||||
ResourceId GetID(ID3D12DeviceChild *res);
|
||||
@@ -306,7 +308,6 @@ private:
|
||||
bool Force_InitialState(ID3D12DeviceChild *res);
|
||||
bool Need_InitialStateChunk(ID3D12DeviceChild *res);
|
||||
bool Prepare_InitialState(ID3D12DeviceChild *res);
|
||||
bool Serialise_InitialState(ResourceId resid, ID3D12DeviceChild *res);
|
||||
void Create_InitialState(ResourceId id, ID3D12DeviceChild *live, bool hasData);
|
||||
void Apply_InitialState(ID3D12DeviceChild *live, InitialContentData data);
|
||||
|
||||
|
||||
@@ -0,0 +1,465 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2016 Baldur Karlsson
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#include "d3d12_replay.h"
|
||||
#include "d3d12_device.h"
|
||||
|
||||
D3D12Replay::D3D12Replay()
|
||||
{
|
||||
m_pDevice = NULL;
|
||||
m_Proxy = false;
|
||||
}
|
||||
|
||||
void D3D12Replay::Shutdown()
|
||||
{
|
||||
for(size_t i = 0; i < m_ProxyResources.size(); i++)
|
||||
m_ProxyResources[i]->Release();
|
||||
m_ProxyResources.clear();
|
||||
|
||||
m_pDevice->Release();
|
||||
}
|
||||
|
||||
FetchTexture D3D12Replay::GetTexture(ResourceId id)
|
||||
{
|
||||
FetchTexture tex;
|
||||
tex.ID = ResourceId();
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
ShaderReflection *D3D12Replay::GetShader(ResourceId shader, string entryPoint)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void D3D12Replay::FreeTargetResource(ResourceId id)
|
||||
{
|
||||
if(m_pDevice->GetResourceManager()->HasLiveResource(id))
|
||||
{
|
||||
ID3D12DeviceChild *resource = m_pDevice->GetResourceManager()->GetLiveResource(id);
|
||||
|
||||
SAFE_RELEASE(resource);
|
||||
}
|
||||
}
|
||||
|
||||
void D3D12Replay::FreeCustomShader(ResourceId id)
|
||||
{
|
||||
if(m_pDevice->GetResourceManager()->HasLiveResource(id))
|
||||
{
|
||||
ID3D12DeviceChild *resource = m_pDevice->GetResourceManager()->GetLiveResource(id);
|
||||
|
||||
SAFE_RELEASE(resource);
|
||||
}
|
||||
}
|
||||
|
||||
FetchFrameRecord D3D12Replay::GetFrameRecord()
|
||||
{
|
||||
return m_pDevice->GetFrameRecord();
|
||||
}
|
||||
|
||||
vector<EventUsage> D3D12Replay::GetUsage(ResourceId id)
|
||||
{
|
||||
return vector<EventUsage>();
|
||||
}
|
||||
|
||||
vector<DebugMessage> D3D12Replay::GetDebugMessages()
|
||||
{
|
||||
return vector<DebugMessage>();
|
||||
}
|
||||
|
||||
APIProperties D3D12Replay::GetAPIProperties()
|
||||
{
|
||||
APIProperties ret;
|
||||
|
||||
ret.pipelineType = ePipelineState_D3D11;
|
||||
ret.degraded = false;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
vector<ResourceId> D3D12Replay::GetBuffers()
|
||||
{
|
||||
vector<ResourceId> ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
FetchBuffer D3D12Replay::GetBuffer(ResourceId id)
|
||||
{
|
||||
FetchBuffer ret;
|
||||
ret.ID = ResourceId();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
vector<ResourceId> D3D12Replay::GetTextures()
|
||||
{
|
||||
vector<ResourceId> ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
D3D11PipelineState D3D12Replay::MakePipelineState()
|
||||
{
|
||||
D3D11PipelineState ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void D3D12Replay::ReadLogInitialisation()
|
||||
{
|
||||
m_pDevice->ReadLogInitialisation();
|
||||
}
|
||||
|
||||
void D3D12Replay::SetContextFilter(ResourceId id, uint32_t firstDefEv, uint32_t lastDefEv)
|
||||
{
|
||||
RDCERR("Should never hit SetContextFilter");
|
||||
}
|
||||
|
||||
void D3D12Replay::ReplayLog(uint32_t endEventID, ReplayLogType replayType)
|
||||
{
|
||||
m_pDevice->ReplayLog(0, endEventID, replayType);
|
||||
}
|
||||
|
||||
vector<uint32_t> D3D12Replay::GetPassEvents(uint32_t eventID)
|
||||
{
|
||||
vector<uint32_t> passEvents;
|
||||
|
||||
return passEvents;
|
||||
}
|
||||
|
||||
uint64_t D3D12Replay::MakeOutputWindow(void *w, bool depth)
|
||||
{
|
||||
return m_pDevice->GetDebugManager()->MakeOutputWindow(w, depth);
|
||||
}
|
||||
|
||||
void D3D12Replay::DestroyOutputWindow(uint64_t id)
|
||||
{
|
||||
m_pDevice->GetDebugManager()->DestroyOutputWindow(id);
|
||||
}
|
||||
|
||||
bool D3D12Replay::CheckResizeOutputWindow(uint64_t id)
|
||||
{
|
||||
return m_pDevice->GetDebugManager()->CheckResizeOutputWindow(id);
|
||||
}
|
||||
|
||||
void D3D12Replay::GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h)
|
||||
{
|
||||
m_pDevice->GetDebugManager()->GetOutputWindowDimensions(id, w, h);
|
||||
}
|
||||
|
||||
void D3D12Replay::ClearOutputWindowColour(uint64_t id, float col[4])
|
||||
{
|
||||
m_pDevice->GetDebugManager()->ClearOutputWindowColour(id, col);
|
||||
}
|
||||
|
||||
void D3D12Replay::ClearOutputWindowDepth(uint64_t id, float depth, uint8_t stencil)
|
||||
{
|
||||
m_pDevice->GetDebugManager()->ClearOutputWindowDepth(id, depth, stencil);
|
||||
}
|
||||
|
||||
void D3D12Replay::BindOutputWindow(uint64_t id, bool depth)
|
||||
{
|
||||
m_pDevice->GetDebugManager()->BindOutputWindow(id, depth);
|
||||
}
|
||||
|
||||
bool D3D12Replay::IsOutputWindowVisible(uint64_t id)
|
||||
{
|
||||
return m_pDevice->GetDebugManager()->IsOutputWindowVisible(id);
|
||||
}
|
||||
|
||||
void D3D12Replay::FlipOutputWindow(uint64_t id)
|
||||
{
|
||||
m_pDevice->GetDebugManager()->FlipOutputWindow(id);
|
||||
}
|
||||
|
||||
void D3D12Replay::InitPostVSBuffers(uint32_t eventID)
|
||||
{
|
||||
}
|
||||
|
||||
void D3D12Replay::InitPostVSBuffers(const vector<uint32_t> &passEvents)
|
||||
{
|
||||
}
|
||||
|
||||
ResourceId D3D12Replay::GetLiveID(ResourceId id)
|
||||
{
|
||||
return m_pDevice->GetResourceManager()->GetLiveID(id);
|
||||
}
|
||||
|
||||
bool D3D12Replay::GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample,
|
||||
FormatComponentType typeHint, float *minval, float *maxval)
|
||||
{
|
||||
*minval = 0.0f;
|
||||
*maxval = 1.0f;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool D3D12Replay::GetHistogram(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample,
|
||||
FormatComponentType typeHint, float minval, float maxval,
|
||||
bool channels[4], vector<uint32_t> &histogram)
|
||||
{
|
||||
histogram.resize(256, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
MeshFormat D3D12Replay::GetPostVSBuffers(uint32_t eventID, uint32_t instID, MeshDataStage stage)
|
||||
{
|
||||
return MeshFormat();
|
||||
}
|
||||
|
||||
void D3D12Replay::GetBufferData(ResourceId buff, uint64_t offset, uint64_t len, vector<byte> &retData)
|
||||
{
|
||||
}
|
||||
|
||||
byte *D3D12Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip,
|
||||
FormatComponentType typeHint, bool resolve, bool forceRGBA8unorm,
|
||||
float blackPoint, float whitePoint, size_t &dataSize)
|
||||
{
|
||||
dataSize = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void D3D12Replay::ReplaceResource(ResourceId from, ResourceId to)
|
||||
{
|
||||
m_pDevice->GetResourceManager()->ReplaceResource(from, to);
|
||||
}
|
||||
|
||||
void D3D12Replay::RemoveReplacement(ResourceId id)
|
||||
{
|
||||
m_pDevice->GetResourceManager()->RemoveReplacement(id);
|
||||
}
|
||||
|
||||
vector<uint32_t> D3D12Replay::EnumerateCounters()
|
||||
{
|
||||
return vector<uint32_t>();
|
||||
}
|
||||
|
||||
void D3D12Replay::DescribeCounter(uint32_t counterID, CounterDescription &desc)
|
||||
{
|
||||
desc = CounterDescription();
|
||||
}
|
||||
|
||||
vector<CounterResult> D3D12Replay::FetchCounters(const vector<uint32_t> &counters)
|
||||
{
|
||||
return vector<CounterResult>();
|
||||
}
|
||||
|
||||
void D3D12Replay::RenderMesh(uint32_t eventID, const vector<MeshFormat> &secondaryDraws,
|
||||
const MeshDisplay &cfg)
|
||||
{
|
||||
}
|
||||
|
||||
void D3D12Replay::BuildTargetShader(string source, string entry, const uint32_t compileFlags,
|
||||
ShaderStageType type, ResourceId *id, string *errors)
|
||||
{
|
||||
}
|
||||
|
||||
void D3D12Replay::BuildCustomShader(string source, string entry, const uint32_t compileFlags,
|
||||
ShaderStageType type, ResourceId *id, string *errors)
|
||||
{
|
||||
}
|
||||
|
||||
bool D3D12Replay::RenderTexture(TextureDisplay cfg)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void D3D12Replay::RenderCheckerboard(Vec3f light, Vec3f dark)
|
||||
{
|
||||
}
|
||||
|
||||
void D3D12Replay::RenderHighlightBox(float w, float h, float scale)
|
||||
{
|
||||
}
|
||||
|
||||
void D3D12Replay::FillCBufferVariables(ResourceId shader, string entryPoint, uint32_t cbufSlot,
|
||||
vector<ShaderVariable> &outvars, const vector<byte> &data)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
vector<PixelModification> D3D12Replay::PixelHistory(vector<EventUsage> events, ResourceId target,
|
||||
uint32_t x, uint32_t y, uint32_t slice,
|
||||
uint32_t mip, uint32_t sampleIdx,
|
||||
FormatComponentType typeHint)
|
||||
{
|
||||
return vector<PixelModification>();
|
||||
}
|
||||
|
||||
ShaderDebugTrace D3D12Replay::DebugVertex(uint32_t eventID, uint32_t vertid, uint32_t instid,
|
||||
uint32_t idx, uint32_t instOffset, uint32_t vertOffset)
|
||||
{
|
||||
return ShaderDebugTrace();
|
||||
}
|
||||
|
||||
ShaderDebugTrace D3D12Replay::DebugPixel(uint32_t eventID, uint32_t x, uint32_t y, uint32_t sample,
|
||||
uint32_t primitive)
|
||||
{
|
||||
return ShaderDebugTrace();
|
||||
}
|
||||
|
||||
ShaderDebugTrace D3D12Replay::DebugThread(uint32_t eventID, uint32_t groupid[3], uint32_t threadid[3])
|
||||
{
|
||||
return ShaderDebugTrace();
|
||||
}
|
||||
|
||||
uint32_t D3D12Replay::PickVertex(uint32_t eventID, const MeshDisplay &cfg, uint32_t x, uint32_t y)
|
||||
{
|
||||
return ~0U;
|
||||
}
|
||||
|
||||
void D3D12Replay::PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace,
|
||||
uint32_t mip, uint32_t sample, FormatComponentType typeHint,
|
||||
float pixel[4])
|
||||
{
|
||||
}
|
||||
|
||||
ResourceId D3D12Replay::RenderOverlay(ResourceId texid, FormatComponentType typeHint,
|
||||
TextureDisplayOverlay overlay, uint32_t eventID,
|
||||
const vector<uint32_t> &passEvents)
|
||||
{
|
||||
return ResourceId();
|
||||
}
|
||||
|
||||
ResourceId D3D12Replay::ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip,
|
||||
FormatComponentType typeHint)
|
||||
{
|
||||
return ResourceId();
|
||||
}
|
||||
|
||||
bool D3D12Replay::IsRenderOutput(ResourceId id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void D3D12Replay::InitCallstackResolver()
|
||||
{
|
||||
m_pDevice->GetSerialiser()->InitCallstackResolver();
|
||||
}
|
||||
|
||||
bool D3D12Replay::HasCallstacks()
|
||||
{
|
||||
return m_pDevice->GetSerialiser()->HasCallstacks();
|
||||
}
|
||||
|
||||
Callstack::StackResolver *D3D12Replay::GetCallstackResolver()
|
||||
{
|
||||
return m_pDevice->GetSerialiser()->GetCallstackResolver();
|
||||
}
|
||||
|
||||
ResourceId D3D12Replay::CreateProxyTexture(const FetchTexture &templateTex)
|
||||
{
|
||||
return ResourceId();
|
||||
}
|
||||
|
||||
void D3D12Replay::SetProxyTextureData(ResourceId texid, uint32_t arrayIdx, uint32_t mip, byte *data,
|
||||
size_t dataSize)
|
||||
{
|
||||
}
|
||||
|
||||
ResourceId D3D12Replay::CreateProxyBuffer(const FetchBuffer &templateBuf)
|
||||
{
|
||||
return ResourceId();
|
||||
}
|
||||
|
||||
void D3D12Replay::SetProxyBufferData(ResourceId bufid, byte *data, size_t dataSize)
|
||||
{
|
||||
}
|
||||
|
||||
extern "C" __declspec(dllexport) HRESULT
|
||||
__cdecl RENDERDOC_CreateWrappedD3D12Device(IUnknown *pAdapter,
|
||||
D3D_FEATURE_LEVEL MinimumFeatureLevel, REFIID riid,
|
||||
void **ppDevice);
|
||||
|
||||
ReplayCreateStatus D3D12_CreateReplayDevice(const char *logfile, IReplayDriver **driver)
|
||||
{
|
||||
RDCDEBUG("Creating a D3D12 replay device");
|
||||
|
||||
HMODULE lib = NULL;
|
||||
lib = LoadLibraryA("d3d12.dll");
|
||||
if(lib == NULL)
|
||||
{
|
||||
RDCERR("Failed to load d3d12.dll");
|
||||
return eReplayCreate_APIInitFailed;
|
||||
}
|
||||
|
||||
lib = LoadLibraryA("dxgi.dll");
|
||||
if(lib == NULL)
|
||||
{
|
||||
RDCERR("Failed to load dxgi.dll");
|
||||
return eReplayCreate_APIInitFailed;
|
||||
}
|
||||
|
||||
if(GetD3DCompiler() == NULL)
|
||||
{
|
||||
RDCERR("Failed to load d3dcompiler_??.dll");
|
||||
return eReplayCreate_APIInitFailed;
|
||||
}
|
||||
|
||||
ID3D12Device *device = NULL;
|
||||
|
||||
D3D12InitParams initParams;
|
||||
RDCDriver driverFileType = RDC_D3D12;
|
||||
string driverName = "D3D12";
|
||||
if(logfile)
|
||||
{
|
||||
auto status = RenderDoc::Inst().FillInitParams(logfile, driverFileType, driverName,
|
||||
(RDCInitParams *)&initParams);
|
||||
if(status != eReplayCreate_Success)
|
||||
return status;
|
||||
}
|
||||
|
||||
// initParams.SerialiseVersion is guaranteed to be valid/supported since otherwise the
|
||||
// FillInitParams (which calls D3D12InitParams::Serialise) would have failed above, so no need to
|
||||
// check it here.
|
||||
|
||||
if(initParams.MinimumFeatureLevel < D3D_FEATURE_LEVEL_11_0)
|
||||
initParams.MinimumFeatureLevel = D3D_FEATURE_LEVEL_11_0;
|
||||
|
||||
ID3D12Device *dev = NULL;
|
||||
HRESULT hr = RENDERDOC_CreateWrappedD3D12Device(NULL, initParams.MinimumFeatureLevel,
|
||||
__uuidof(ID3D12Device), (void **)&dev);
|
||||
|
||||
if(FAILED(hr))
|
||||
{
|
||||
RDCERR("Couldn't create a d3d12 device :(.");
|
||||
|
||||
return eReplayCreate_APIHardwareUnsupported;
|
||||
}
|
||||
|
||||
WrappedID3D12Device *wrappedDev = (WrappedID3D12Device *)device;
|
||||
if(logfile)
|
||||
wrappedDev->SetLogFile(logfile);
|
||||
wrappedDev->SetLogVersion(initParams.SerialiseVersion);
|
||||
|
||||
RDCLOG("Created device.");
|
||||
D3D12Replay *replay = wrappedDev->GetReplay();
|
||||
|
||||
replay->SetProxy(logfile == NULL);
|
||||
|
||||
*driver = (IReplayDriver *)replay;
|
||||
return eReplayCreate_Success;
|
||||
}
|
||||
|
||||
static DriverRegistration D3D12DriverRegistration(RDC_D3D12, "D3D12", &D3D12_CreateReplayDevice);
|
||||
@@ -0,0 +1,164 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2016 Baldur Karlsson
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "api/replay/renderdoc_replay.h"
|
||||
#include "core/core.h"
|
||||
#include "replay/replay_driver.h"
|
||||
#include "d3d12_common.h"
|
||||
|
||||
class WrappedID3D12Device;
|
||||
|
||||
class D3D12Replay : public IReplayDriver
|
||||
{
|
||||
public:
|
||||
D3D12Replay();
|
||||
|
||||
void SetProxy(bool proxy) { m_Proxy = proxy; }
|
||||
bool IsRemoteProxy() { return m_Proxy; }
|
||||
void Shutdown();
|
||||
|
||||
void SetDevice(WrappedID3D12Device *d) { m_pDevice = d; }
|
||||
APIProperties GetAPIProperties();
|
||||
|
||||
vector<ResourceId> GetBuffers();
|
||||
FetchBuffer GetBuffer(ResourceId id);
|
||||
|
||||
vector<ResourceId> GetTextures();
|
||||
FetchTexture GetTexture(ResourceId id);
|
||||
|
||||
vector<DebugMessage> GetDebugMessages();
|
||||
|
||||
ShaderReflection *GetShader(ResourceId shader, string entryPoint);
|
||||
|
||||
vector<EventUsage> GetUsage(ResourceId id);
|
||||
|
||||
FetchFrameRecord GetFrameRecord();
|
||||
|
||||
void SavePipelineState() { MakePipelineState(); }
|
||||
D3D11PipelineState GetD3D11PipelineState() { return D3D11PipelineState(); }
|
||||
GLPipelineState GetGLPipelineState() { return GLPipelineState(); }
|
||||
VulkanPipelineState GetVulkanPipelineState() { return VulkanPipelineState(); }
|
||||
void FreeTargetResource(ResourceId id);
|
||||
void FreeCustomShader(ResourceId id);
|
||||
|
||||
void ReadLogInitialisation();
|
||||
void SetContextFilter(ResourceId id, uint32_t firstDefEv, uint32_t lastDefEv);
|
||||
void ReplayLog(uint32_t endEventID, ReplayLogType replayType);
|
||||
|
||||
vector<uint32_t> GetPassEvents(uint32_t eventID);
|
||||
|
||||
uint64_t MakeOutputWindow(void *w, bool depth);
|
||||
void DestroyOutputWindow(uint64_t id);
|
||||
bool CheckResizeOutputWindow(uint64_t id);
|
||||
void GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h);
|
||||
void ClearOutputWindowColour(uint64_t id, float col[4]);
|
||||
void ClearOutputWindowDepth(uint64_t id, float depth, uint8_t stencil);
|
||||
void BindOutputWindow(uint64_t id, bool depth);
|
||||
bool IsOutputWindowVisible(uint64_t id);
|
||||
void FlipOutputWindow(uint64_t id);
|
||||
|
||||
void InitPostVSBuffers(uint32_t eventID);
|
||||
void InitPostVSBuffers(const vector<uint32_t> &passEvents);
|
||||
|
||||
ResourceId GetLiveID(ResourceId id);
|
||||
|
||||
bool GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample,
|
||||
FormatComponentType typeHint, float *minval, float *maxval);
|
||||
bool GetHistogram(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample,
|
||||
FormatComponentType typeHint, float minval, float maxval, bool channels[4],
|
||||
vector<uint32_t> &histogram);
|
||||
|
||||
MeshFormat GetPostVSBuffers(uint32_t eventID, uint32_t instID, MeshDataStage stage);
|
||||
|
||||
void GetBufferData(ResourceId buff, uint64_t offset, uint64_t len, vector<byte> &retData);
|
||||
byte *GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip,
|
||||
FormatComponentType typeHint, bool resolve, bool forceRGBA8unorm,
|
||||
float blackPoint, float whitePoint, size_t &dataSize);
|
||||
|
||||
void BuildTargetShader(string source, string entry, const uint32_t compileFlags,
|
||||
ShaderStageType type, ResourceId *id, string *errors);
|
||||
void ReplaceResource(ResourceId from, ResourceId to);
|
||||
void RemoveReplacement(ResourceId id);
|
||||
|
||||
vector<uint32_t> EnumerateCounters();
|
||||
void DescribeCounter(uint32_t counterID, CounterDescription &desc);
|
||||
vector<CounterResult> FetchCounters(const vector<uint32_t> &counters);
|
||||
|
||||
ResourceId CreateProxyTexture(const FetchTexture &templateTex);
|
||||
void SetProxyTextureData(ResourceId texid, uint32_t arrayIdx, uint32_t mip, byte *data,
|
||||
size_t dataSize);
|
||||
|
||||
ResourceId CreateProxyBuffer(const FetchBuffer &templateBuf);
|
||||
void SetProxyBufferData(ResourceId bufid, byte *data, size_t dataSize);
|
||||
|
||||
void RenderMesh(uint32_t eventID, const vector<MeshFormat> &secondaryDraws, const MeshDisplay &cfg);
|
||||
|
||||
bool RenderTexture(TextureDisplay cfg);
|
||||
|
||||
void RenderCheckerboard(Vec3f light, Vec3f dark);
|
||||
|
||||
void RenderHighlightBox(float w, float h, float scale);
|
||||
|
||||
void FillCBufferVariables(ResourceId shader, string entryPoint, uint32_t cbufSlot,
|
||||
vector<ShaderVariable> &outvars, const vector<byte> &data);
|
||||
|
||||
vector<PixelModification> PixelHistory(vector<EventUsage> events, ResourceId target, uint32_t x,
|
||||
uint32_t y, uint32_t slice, uint32_t mip,
|
||||
uint32_t sampleIdx, FormatComponentType typeHint);
|
||||
ShaderDebugTrace DebugVertex(uint32_t eventID, uint32_t vertid, uint32_t instid, uint32_t idx,
|
||||
uint32_t instOffset, uint32_t vertOffset);
|
||||
ShaderDebugTrace DebugPixel(uint32_t eventID, uint32_t x, uint32_t y, uint32_t sample,
|
||||
uint32_t primitive);
|
||||
ShaderDebugTrace DebugThread(uint32_t eventID, uint32_t groupid[3], uint32_t threadid[3]);
|
||||
void PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace, uint32_t mip,
|
||||
uint32_t sample, FormatComponentType typeHint, float pixel[4]);
|
||||
uint32_t PickVertex(uint32_t eventID, const MeshDisplay &cfg, uint32_t x, uint32_t y);
|
||||
|
||||
ResourceId RenderOverlay(ResourceId texid, FormatComponentType typeHint,
|
||||
TextureDisplayOverlay overlay, uint32_t eventID,
|
||||
const vector<uint32_t> &passEvents);
|
||||
|
||||
void BuildCustomShader(string source, string entry, const uint32_t compileFlags,
|
||||
ShaderStageType type, ResourceId *id, string *errors);
|
||||
ResourceId ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip,
|
||||
FormatComponentType typeHint);
|
||||
|
||||
bool IsRenderOutput(ResourceId id);
|
||||
|
||||
void FileChanged() {}
|
||||
void InitCallstackResolver();
|
||||
bool HasCallstacks();
|
||||
Callstack::StackResolver *GetCallstackResolver();
|
||||
|
||||
private:
|
||||
D3D11PipelineState MakePipelineState();
|
||||
|
||||
bool m_Proxy;
|
||||
|
||||
vector<ID3D12Resource *> m_ProxyResources;
|
||||
|
||||
WrappedID3D12Device *m_pDevice;
|
||||
};
|
||||
@@ -188,20 +188,24 @@
|
||||
<ClCompile Include="d3d12_command_list_wrap.cpp" />
|
||||
<ClCompile Include="d3d12_command_queue_wrap.cpp" />
|
||||
<ClCompile Include="d3d12_common.cpp" />
|
||||
<ClCompile Include="d3d12_debug.cpp" />
|
||||
<ClCompile Include="d3d12_device.cpp" />
|
||||
<ClCompile Include="d3d12_device_wrap.cpp" />
|
||||
<ClCompile Include="d3d12_hooks.cpp" />
|
||||
<ClCompile Include="d3d12_manager.cpp" />
|
||||
<ClCompile Include="d3d12_replay.cpp" />
|
||||
<ClCompile Include="d3d12_resources.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="d3d12_command_list.h" />
|
||||
<ClInclude Include="d3d12_command_queue.h" />
|
||||
<ClInclude Include="d3d12_common.h" />
|
||||
<ClInclude Include="d3d12_debug.h" />
|
||||
<ClInclude Include="d3d12_device.h" />
|
||||
<ClInclude Include="d3d12_manager.h" />
|
||||
<ClInclude Include="..\dx\official\d3d12.h" />
|
||||
<ClInclude Include="..\dx\official\d3d12sdklayers.h" />
|
||||
<ClInclude Include="d3d12_replay.h" />
|
||||
<ClInclude Include="d3d12_resources.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
<Filter Include="Wrapped">
|
||||
<UniqueIdentifier>{b66407e3-297a-4a8d-bdae-09468c64ca18}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Replay">
|
||||
<UniqueIdentifier>{97a405db-4782-4c62-b6c1-ca6a398c6a60}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\dx\official\d3d12.h">
|
||||
@@ -42,6 +45,12 @@
|
||||
<ClInclude Include="d3d12_command_queue.h">
|
||||
<Filter>Core IFaces</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="d3d12_replay.h">
|
||||
<Filter>Replay</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="d3d12_debug.h">
|
||||
<Filter>Replay</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="d3d12_common.cpp">
|
||||
@@ -71,5 +80,11 @@
|
||||
<ClCompile Include="d3d12_commands.cpp">
|
||||
<Filter>Core IFaces</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="d3d12_replay.cpp">
|
||||
<Filter>Replay</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="d3d12_debug.cpp">
|
||||
<Filter>Replay</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1532,8 +1532,6 @@ void WrappedVulkan::ContextReplayLog(LogState readType, uint32_t startEventID, u
|
||||
|
||||
m_RootEvents.clear();
|
||||
|
||||
m_CmdBuffersInProgress = 0;
|
||||
|
||||
if(m_State == EXECUTING)
|
||||
{
|
||||
FetchAPIEvent ev = GetEvent(startEventID);
|
||||
|
||||
@@ -357,7 +357,6 @@ private:
|
||||
// on replay, the current command buffer for the last chunk we
|
||||
// handled.
|
||||
ResourceId m_LastCmdBufferID;
|
||||
int m_CmdBuffersInProgress;
|
||||
|
||||
// this is a list of uint64_t file offset -> uint32_t EIDs of where each
|
||||
// drawcall is used. E.g. the drawcall at offset 873954 is EID 50. If a
|
||||
|
||||
@@ -311,7 +311,6 @@ bool WrappedVulkan::Serialise_vkBeginCommandBuffer(Serialiser *localSerialiser,
|
||||
if(m_State < WRITING)
|
||||
{
|
||||
m_LastCmdBufferID = cmdId;
|
||||
m_CmdBuffersInProgress++;
|
||||
}
|
||||
|
||||
SERIALISE_ELEMENT(ResourceId, devId, GetResID(device));
|
||||
@@ -509,7 +508,6 @@ bool WrappedVulkan::Serialise_vkEndCommandBuffer(Serialiser *localSerialiser,
|
||||
if(m_State < WRITING)
|
||||
{
|
||||
m_LastCmdBufferID = cmdid;
|
||||
m_CmdBuffersInProgress--;
|
||||
}
|
||||
|
||||
if(m_State == EXECUTING)
|
||||
|
||||
Reference in New Issue
Block a user