diff --git a/renderdoc/driver/d3d12/d3d12_command_list.h b/renderdoc/driver/d3d12/d3d12_command_list.h index 94ed293ef..bb87e5e48 100644 --- a/renderdoc/driver/d3d12/d3d12_command_list.h +++ b/renderdoc/driver/d3d12/d3d12_command_list.h @@ -100,6 +100,9 @@ class WrappedID3D12GraphicsCommandList : public RefCounter12GetChunkName(idx); } D3D12ResourceManager *GetResourceManager() { return m_pDevice->GetResourceManager(); } public: diff --git a/renderdoc/driver/d3d12/d3d12_command_list_wrap.cpp b/renderdoc/driver/d3d12/d3d12_command_list_wrap.cpp index e07625f7b..904ec6768 100644 --- a/renderdoc/driver/d3d12/d3d12_command_list_wrap.cpp +++ b/renderdoc/driver/d3d12/d3d12_command_list_wrap.cpp @@ -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()); diff --git a/renderdoc/driver/d3d12/d3d12_command_queue.h b/renderdoc/driver/d3d12/d3d12_command_queue.h index 2c13adb4b..153296be9 100644 --- a/renderdoc/driver/d3d12/d3d12_command_queue.h +++ b/renderdoc/driver/d3d12/d3d12_command_queue.h @@ -24,6 +24,7 @@ #pragma once +#include #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 children; + + vector > resourceUsage; + + D3D12DrawcallTreeNode &operator=(const FetchDrawcall &d) + { + *this = D3D12DrawcallTreeNode(d); + return *this; + } + + vector Bake() + { + vector 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, public ID3DDevice { WrappedID3D12Device *m_pDevice; + WrappedID3D12GraphicsCommandList *m_ReplayList; + ResourceId m_ResourceID; D3D12ResourceRecord *m_QueueRecord; @@ -82,6 +119,136 @@ class WrappedID3D12CommandQueue : public ID3D12CommandQueue, vector m_CmdListRecords; + vector 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 &cmdBufNodes, uint32_t baseEventID, + uint32_t baseDrawID); + + struct BakedCmdListInfo + { + vector curEvents; + vector debugMessages; + std::list drawStack; + + vector > resourceUsage; + + struct CmdListState + { + ResourceId pipeline; + + uint32_t idxWidth; + ResourceId ibuffer; + vector vbuffers; + + ResourceId rts[8]; + ResourceId dsv; + } state; + + vector 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 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 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 + map > 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 m_RerecordCmds; + + std::list m_DrawcallStack; + + std::list &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 &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); } diff --git a/renderdoc/driver/d3d12/d3d12_command_queue_wrap.cpp b/renderdoc/driver/d3d12/d3d12_command_queue_wrap.cpp index 208bc5041..32f1a80ed 100644 --- a/renderdoc/driver/d3d12/d3d12_command_queue_wrap.cpp +++ b/renderdoc/driver/d3d12/d3d12_command_queue_wrap.cpp @@ -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 diff --git a/renderdoc/driver/d3d12/d3d12_commands.cpp b/renderdoc/driver/d3d12/d3d12_commands.cpp index e875685bc..0bd1b6dbe 100644 --- a/renderdoc/driver/d3d12/d3d12_commands.cpp +++ b/renderdoc/driver/d3d12/d3d12_commands.cpp @@ -22,6 +22,7 @@ * THE SOFTWARE. ******************************************************************************/ +#include #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 &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 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 &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); +} diff --git a/renderdoc/driver/d3d12/d3d12_common.h b/renderdoc/driver/d3d12/d3d12_common.h index 1f5f1f98e..53d21fe26 100644 --- a/renderdoc/driver/d3d12/d3d12_common.h +++ b/renderdoc/driver/d3d12/d3d12_common.h @@ -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 diff --git a/renderdoc/driver/d3d12/d3d12_debug.cpp b/renderdoc/driver/d3d12/d3d12_debug.cpp new file mode 100644 index 000000000..ee3dccc2a --- /dev/null +++ b/renderdoc/driver/d3d12/d3d12_debug.cpp @@ -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); + } +} diff --git a/renderdoc/driver/d3d12/d3d12_debug.h b/renderdoc/driver/d3d12/d3d12_debug.h new file mode 100644 index 000000000..2af556f50 --- /dev/null +++ b/renderdoc/driver/d3d12/d3d12_debug.h @@ -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 m_OutputWindows; + + WrappedID3D12Device *m_WrappedDevice; + ID3D12Device *m_Device; + + IDXGIFactory *m_pFactory; + + D3D12ResourceManager *m_ResourceManager; +}; diff --git a/renderdoc/driver/d3d12/d3d12_device.cpp b/renderdoc/driver/d3d12/d3d12_device.cpp index b45ee58f2..26070eb26 100644 --- a/renderdoc/driver/d3d12/d3d12_device.cpp +++ b/renderdoc/driver/d3d12/d3d12_device.cpp @@ -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 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"); +} diff --git a/renderdoc/driver/d3d12/d3d12_device.h b/renderdoc/driver/d3d12/d3d12_device.h index c84c0e666..5d9a9dd90 100644 --- a/renderdoc/driver/d3d12/d3d12_device.h +++ b/renderdoc/driver/d3d12/d3d12_device.h @@ -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 m_RefCounter; RefCounter12 m_SoftRefCounter; @@ -241,6 +250,7 @@ private: uint32_t m_FrameCounter; vector m_CapturedFrames; FetchFrameRecord m_FrameRecord; + vector m_Drawcalls; PerformanceTimer m_FrameTimer; vector 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); } diff --git a/renderdoc/driver/d3d12/d3d12_manager.h b/renderdoc/driver/d3d12/d3d12_manager.h index c3d9332fd..7bcac743c 100644 --- a/renderdoc/driver/d3d12/d3d12_manager.h +++ b/renderdoc/driver/d3d12/d3d12_manager.h @@ -297,6 +297,8 @@ public: void SerialiseResourceStates(vector &barriers, map &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); diff --git a/renderdoc/driver/d3d12/d3d12_replay.cpp b/renderdoc/driver/d3d12/d3d12_replay.cpp new file mode 100644 index 000000000..c68808daf --- /dev/null +++ b/renderdoc/driver/d3d12/d3d12_replay.cpp @@ -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 D3D12Replay::GetUsage(ResourceId id) +{ + return vector(); +} + +vector D3D12Replay::GetDebugMessages() +{ + return vector(); +} + +APIProperties D3D12Replay::GetAPIProperties() +{ + APIProperties ret; + + ret.pipelineType = ePipelineState_D3D11; + ret.degraded = false; + + return ret; +} + +vector D3D12Replay::GetBuffers() +{ + vector ret; + + return ret; +} + +FetchBuffer D3D12Replay::GetBuffer(ResourceId id) +{ + FetchBuffer ret; + ret.ID = ResourceId(); + + return ret; +} + +vector D3D12Replay::GetTextures() +{ + vector 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 D3D12Replay::GetPassEvents(uint32_t eventID) +{ + vector 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 &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 &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 &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 D3D12Replay::EnumerateCounters() +{ + return vector(); +} + +void D3D12Replay::DescribeCounter(uint32_t counterID, CounterDescription &desc) +{ + desc = CounterDescription(); +} + +vector D3D12Replay::FetchCounters(const vector &counters) +{ + return vector(); +} + +void D3D12Replay::RenderMesh(uint32_t eventID, const vector &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 &outvars, const vector &data) +{ + return; +} + +vector D3D12Replay::PixelHistory(vector events, ResourceId target, + uint32_t x, uint32_t y, uint32_t slice, + uint32_t mip, uint32_t sampleIdx, + FormatComponentType typeHint) +{ + return vector(); +} + +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 &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); diff --git a/renderdoc/driver/d3d12/d3d12_replay.h b/renderdoc/driver/d3d12/d3d12_replay.h new file mode 100644 index 000000000..d667ff0d7 --- /dev/null +++ b/renderdoc/driver/d3d12/d3d12_replay.h @@ -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 GetBuffers(); + FetchBuffer GetBuffer(ResourceId id); + + vector GetTextures(); + FetchTexture GetTexture(ResourceId id); + + vector GetDebugMessages(); + + ShaderReflection *GetShader(ResourceId shader, string entryPoint); + + vector 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 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 &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 &histogram); + + MeshFormat GetPostVSBuffers(uint32_t eventID, uint32_t instID, MeshDataStage stage); + + void GetBufferData(ResourceId buff, uint64_t offset, uint64_t len, vector &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 EnumerateCounters(); + void DescribeCounter(uint32_t counterID, CounterDescription &desc); + vector FetchCounters(const vector &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 &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 &outvars, const vector &data); + + vector PixelHistory(vector 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 &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 m_ProxyResources; + + WrappedID3D12Device *m_pDevice; +}; diff --git a/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj b/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj index f912e1678..4901215a5 100644 --- a/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj +++ b/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj @@ -188,20 +188,24 @@ + + + + diff --git a/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj.filters b/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj.filters index c1679ce07..799d571b5 100644 --- a/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj.filters +++ b/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj.filters @@ -16,6 +16,9 @@ {b66407e3-297a-4a8d-bdae-09468c64ca18} + + {97a405db-4782-4c62-b6c1-ca6a398c6a60} + @@ -42,6 +45,12 @@ Core IFaces + + Replay + + + Replay + @@ -71,5 +80,11 @@ Core IFaces + + Replay + + + Replay + \ No newline at end of file diff --git a/renderdoc/driver/vulkan/vk_core.cpp b/renderdoc/driver/vulkan/vk_core.cpp index b11b10b93..5f6478592 100644 --- a/renderdoc/driver/vulkan/vk_core.cpp +++ b/renderdoc/driver/vulkan/vk_core.cpp @@ -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); diff --git a/renderdoc/driver/vulkan/vk_core.h b/renderdoc/driver/vulkan/vk_core.h index 61bfe8d41..355187b97 100644 --- a/renderdoc/driver/vulkan/vk_core.h +++ b/renderdoc/driver/vulkan/vk_core.h @@ -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 diff --git a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp index 571636081..c5e713058 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp @@ -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)