From 32ca05bb2bd2fb97e21c7dc3eae4d1b962fe2681 Mon Sep 17 00:00:00 2001 From: baldurk Date: Thu, 28 Jul 2016 17:06:50 +0700 Subject: [PATCH] Factor out command record/partial replay into common place * Both command lists and command queues need to be able to access this data so we expose it in a common place. * This gets command stepping partially working. --- renderdoc/driver/d3d12/d3d12_command_list.h | 8 +- .../driver/d3d12/d3d12_command_list_wrap.cpp | 576 +++++++++++++++++- renderdoc/driver/d3d12/d3d12_command_queue.h | 173 +----- .../driver/d3d12/d3d12_command_queue_wrap.cpp | 240 +++++++- renderdoc/driver/d3d12/d3d12_commands.cpp | 405 +++++++----- renderdoc/driver/d3d12/d3d12_commands.h | 258 ++++++++ renderdoc/driver/d3d12/d3d12_common.h | 19 +- renderdoc/driver/d3d12/d3d12_replay.cpp | 10 +- .../driver/d3d12/renderdoc_d3d12.vcxproj | 1 + .../d3d12/renderdoc_d3d12.vcxproj.filters | 3 + 10 files changed, 1331 insertions(+), 362 deletions(-) create mode 100644 renderdoc/driver/d3d12/d3d12_commands.h diff --git a/renderdoc/driver/d3d12/d3d12_command_list.h b/renderdoc/driver/d3d12/d3d12_command_list.h index f234df095..3b5e70ffd 100644 --- a/renderdoc/driver/d3d12/d3d12_command_list.h +++ b/renderdoc/driver/d3d12/d3d12_command_list.h @@ -25,6 +25,7 @@ #pragma once #include "common/wrapped_pool.h" +#include "d3d12_commands.h" #include "d3d12_common.h" #include "d3d12_device.h" #include "d3d12_resources.h" @@ -85,6 +86,9 @@ class WrappedID3D12GraphicsCommandList : public RefCounter12GetChunkName(idx); } D3D12ResourceManager *GetResourceManager() { return m_pDevice->GetResourceManager(); } public: @@ -119,6 +120,7 @@ public: D3D12ResourceRecord *GetResourceRecord() { return m_ListRecord; } ID3D12GraphicsCommandList *GetList(ResourceId id); + void SetCommandData(D3D12CommandData *cmd) { m_Cmd = cmd; } void SetInitParams(REFIID riid, UINT nodeMask, D3D12_COMMAND_LIST_TYPE type) { m_Init.riid = riid; diff --git a/renderdoc/driver/d3d12/d3d12_command_list_wrap.cpp b/renderdoc/driver/d3d12/d3d12_command_list_wrap.cpp index 0e694f743..ada248a1e 100644 --- a/renderdoc/driver/d3d12/d3d12_command_list_wrap.cpp +++ b/renderdoc/driver/d3d12/d3d12_command_list_wrap.cpp @@ -23,6 +23,7 @@ ******************************************************************************/ #include "d3d12_command_list.h" +#include "d3d12_command_queue.h" ID3D12GraphicsCommandList *WrappedID3D12GraphicsCommandList::GetList(ResourceId id) { @@ -33,8 +34,68 @@ bool WrappedID3D12GraphicsCommandList::Serialise_Close() { SERIALISE_ELEMENT(ResourceId, CommandList, GetResourceID()); - if(m_State <= READING) - GetList(CommandList)->Close(); + ResourceId bakedCmdId; + + if(m_State >= WRITING) + { + D3D12ResourceRecord *record = GetResourceManager()->GetResourceRecord(CommandList); + RDCASSERT(record->bakedCommands); + if(record->bakedCommands) + bakedCmdId = record->bakedCommands->GetResourceID(); + } + + SERIALISE_ELEMENT(ResourceId, bakeId, bakedCmdId); + + if(m_State < WRITING) + m_Cmd->m_LastCmdListID = CommandList; + + if(m_State == EXECUTING) + { + if(m_Cmd->ShouldRerecordCmd(CommandList)) + { + ID3D12GraphicsCommandList *list = m_Cmd->RerecordCmdList(CommandList); +#ifdef VERBOSE_PARTIAL_REPLAY + RDCDEBUG("Ending partial command buffer for %llu baked to %llu", CommandList, bakeId); +#endif + + list->Close(); + + // erase the non-baked reference to this command list so that we don't have + // duplicates when it comes time to clean up. See below in in Reset() + m_Cmd->m_RerecordCmds.erase(CommandList); + + if(m_Cmd->m_Partial[D3D12CommandData::Primary].partialParent == CommandList) + m_Cmd->m_Partial[D3D12CommandData::Primary].partialParent = ResourceId(); + } + + m_Cmd->m_BakedCmdListInfo[CommandList].curEventID = 0; + } + else if(m_State == READING) + { + ID3D12GraphicsCommandList *list = GetList(CommandList); + + GetResourceManager()->RemoveReplacement(CommandList); + + list->Close(); + + if(m_State == READING && !m_Cmd->m_BakedCmdListInfo[CommandList].curEvents.empty()) + { + FetchDrawcall draw; + draw.name = "API Calls"; + draw.flags |= eDraw_SetMarker; + + m_Cmd->AddDrawcall(draw, true); + + m_Cmd->m_BakedCmdListInfo[CommandList].curEventID++; + } + + { + if(m_Cmd->GetDrawcallStack().size() > 1) + m_Cmd->GetDrawcallStack().pop_back(); + } + + m_Cmd->m_BakedCmdListInfo[bakeId].BakeFrom(m_Cmd->m_BakedCmdListInfo[CommandList]); + } return true; } @@ -68,21 +129,128 @@ bool WrappedID3D12GraphicsCommandList::Serialise_Reset(ID3D12CommandAllocator *p SERIALISE_ELEMENT(ResourceId, Allocator, GetResID(pAllocator)); SERIALISE_ELEMENT(ResourceId, State, GetResID(pInitialState)); - if(m_State <= READING) + ResourceId bakedCmdId; + + if(m_State >= WRITING) + { + D3D12ResourceRecord *record = GetResourceManager()->GetResourceRecord(CommandList); + RDCASSERT(record->bakedCommands); + if(record->bakedCommands) + bakedCmdId = record->bakedCommands->GetResourceID(); + } + + SERIALISE_ELEMENT(ResourceId, bakeId, bakedCmdId); + + if(m_State < WRITING) + m_Cmd->m_LastCmdListID = CommandList; + + if(m_State == EXECUTING) + { + const uint32_t length = m_Cmd->m_BakedCmdListInfo[bakeId].eventCount; + + bool partial = false; + int partialType = D3D12CommandData::ePartialNum; + + // check for partial execution of this command buffer + for(int p = 0; p < D3D12CommandData::ePartialNum; p++) + { + const vector &baseEvents = m_Cmd->m_Partial[p].cmdListExecs[bakeId]; + + for(auto it = baseEvents.begin(); it != baseEvents.end(); ++it) + { + if(*it <= m_Cmd->m_LastEventID && m_Cmd->m_LastEventID < (*it + length)) + { +#ifdef VERBOSE_PARTIAL_REPLAY + RDCDEBUG("vkBegin - partial detected %u < %u < %u, %llu -> %llu", *it, + m_Cmd->m_LastEventID, *it + length, CommandList, bakeId); +#endif + + m_Cmd->m_Partial[p].partialParent = CommandList; + m_Cmd->m_Partial[p].baseEvent = *it; + + partial = true; + partialType = p; + } + } + } + + D3D12NOTIMP("m_DrawcallCallback"); + // const bool recordAllCmds = false; // m_DrawcallCallback && + // m_DrawcallCallback->RecordAllCmds() + + if(partial) // || recordAllCmds + { + pAllocator = GetResourceManager()->GetLiveAs(Allocator); + pInitialState = + State == ResourceId() ? NULL : GetResourceManager()->GetLiveAs(State); + + // pull all re-recorded commands from our own device and command pool for easier cleanup + if(!partial) + pAllocator = Unwrap(m_pDevice->GetAlloc()); + + ID3D12GraphicsCommandList *list = NULL; + HRESULT hr = m_pDevice->CreateCommandList(nodeMask, type, pAllocator, pInitialState, riid, + (void **)&list); + + if(FAILED(hr)) + RDCERR("Failed on resource serialise-creation, hr: 0x%08x", hr); + + if(partial) + { + m_Cmd->m_Partial[partialType].resultPartialCmdList = list; + } + else + { + // we store under both baked and non baked ID. + // The baked ID is the 'real' entry, the non baked is simply so it + // can be found in the subsequent serialised commands that ref the + // non-baked ID. The baked ID is referenced by the submit itself. + // + // In vkEndCommandBuffer we erase the non-baked reference, and since + // we know you can only be recording a command buffer once at a time + // (even if it's baked to several command buffers in the frame) + // there's no issue with clashes here. + m_Cmd->m_RerecordCmds[bakeId] = list; + m_Cmd->m_RerecordCmds[CommandList] = list; + } + } + + m_Cmd->m_BakedCmdListInfo[CommandList].curEventID = 0; + } + else if(m_State == READING) { pAllocator = GetResourceManager()->GetLiveAs(Allocator); pInitialState = State == ResourceId() ? NULL : GetResourceManager()->GetLiveAs(State); - if(m_State == READING && !GetResourceManager()->HasLiveResource(CommandList)) + if(!GetResourceManager()->HasLiveResource(bakeId)) { ID3D12GraphicsCommandList *list = NULL; m_pDevice->CreateCommandList(nodeMask, type, pAllocator, pInitialState, riid, (void **)&list); - GetResourceManager()->AddLiveResource(CommandList, list); + GetResourceManager()->AddLiveResource(bakeId, list); + + // whenever a vkCmd command-building chunk asks for the command buffer, it + // will get our baked version. + GetResourceManager()->ReplaceResource(CommandList, bakeId); } else + { GetList(CommandList)->Reset(Unwrap(pAllocator), Unwrap(pInitialState)); + } + + { + D3D12DrawcallTreeNode *draw = new D3D12DrawcallTreeNode; + m_Cmd->m_BakedCmdListInfo[CommandList].draw = draw; + + // On list execute we increment all child events/drawcalls by + // m_RootEventID and insert them into the tree. + m_Cmd->m_BakedCmdListInfo[CommandList].curEventID = 0; + m_Cmd->m_BakedCmdListInfo[CommandList].eventCount = 0; + m_Cmd->m_BakedCmdListInfo[CommandList].drawCount = 0; + + m_Cmd->m_BakedCmdListInfo[CommandList].drawStack.push_back(draw); + } } return true; @@ -151,18 +319,43 @@ bool WrappedID3D12GraphicsCommandList::Serialise_DrawIndexedInstanced(UINT Index SERIALISE_ELEMENT(INT, startVtx, BaseVertexLocation); SERIALISE_ELEMENT(UINT, startInst, StartInstanceLocation); - if(m_State <= READING) + if(m_State < WRITING) + m_Cmd->m_LastCmdListID = CommandList; + + D3D12NOTIMP("Serialise_DebugMessages"); + + if(m_State == EXECUTING) + { + if(m_Cmd->ShouldRerecordCmd(CommandList) && m_Cmd->InRerecordRange(CommandList)) + { + ID3D12GraphicsCommandList *list = m_Cmd->RerecordCmdList(CommandList); + + Unwrap(list)->DrawIndexedInstanced(idxCount, instCount, startIdx, startVtx, startInst); + + D3D12NOTIMP("Drawcall callbacks"); + /* + uint32_t eventID = HandlePreCallback(commandBuffer); + + ObjDisp(commandBuffer) + ->CmdDrawIndexed(Unwrap(commandBuffer), idxCount, instCount, firstIdx, vtxOffs, + firstInst); + + if(eventID && m_DrawcallCallback->PostDraw(eventID, commandBuffer)) + { + ObjDisp(commandBuffer) + ->CmdDrawIndexed(Unwrap(commandBuffer), idxCount, instCount, firstIdx, vtxOffs, + firstInst); + m_DrawcallCallback->PostRedraw(eventID, commandBuffer); + }*/ + } + } + else if(m_State == READING) { GetList(CommandList)->DrawIndexedInstanced(idxCount, instCount, startIdx, startVtx, startInst); - } - const string desc = m_pSerialiser->GetDebugStr(); + const string desc = m_pSerialiser->GetDebugStr(); - // TODO - Serialise_DebugMessages(); - - if(m_State == READING) - { - AddEvent(DRAW_INDEXED_INST, desc); + m_Cmd->AddEvent(DRAW_INDEXED_INST, desc); string name = "DrawIndexedInstanced(" + ToStr::Get(idxCount) + ", " + ToStr::Get(instCount) + ")"; @@ -176,7 +369,7 @@ bool WrappedID3D12GraphicsCommandList::Serialise_DrawIndexedInstanced(UINT Index draw.flags |= eDraw_Drawcall | eDraw_Instanced | eDraw_UseIBuffer; - AddDrawcall(draw, true); + m_Cmd->AddDrawcall(draw, true); } return true; @@ -219,13 +412,58 @@ bool WrappedID3D12GraphicsCommandList::Serialise_CopyBufferRegion(ID3D12Resource SERIALISE_ELEMENT(UINT64, srcoffs, SrcOffset); SERIALISE_ELEMENT(UINT64, num, NumBytes); - if(m_State <= READING && GetResourceManager()->HasLiveResource(dst) && - GetResourceManager()->HasLiveResource(src)) + if(m_State < WRITING) + m_Cmd->m_LastCmdListID = CommandList; + + if(m_State == EXECUTING) { pDstBuffer = GetResourceManager()->GetLiveAs(dst); pSrcBuffer = GetResourceManager()->GetLiveAs(src); - GetList(CommandList)->CopyBufferRegion(Unwrap(pDstBuffer), dstoffs, Unwrap(pSrcBuffer), srcoffs, num); + if(m_Cmd->ShouldRerecordCmd(CommandList) && m_Cmd->InRerecordRange(CommandList)) + { + ID3D12GraphicsCommandList *list = m_Cmd->RerecordCmdList(CommandList); + Unwrap(list)->CopyBufferRegion(Unwrap(pDstBuffer), dstoffs, Unwrap(pSrcBuffer), srcoffs, num); + } + } + else if(m_State == READING) + { + ID3D12GraphicsCommandList *list = GetList(CommandList); + pDstBuffer = GetResourceManager()->GetLiveAs(dst); + pSrcBuffer = GetResourceManager()->GetLiveAs(src); + + list->CopyBufferRegion(Unwrap(pDstBuffer), dstoffs, Unwrap(pSrcBuffer), srcoffs, num); + + const string desc = m_pSerialiser->GetDebugStr(); + + { + m_Cmd->AddEvent(COPY_BUFFER, desc); + string name = "CopyBufferRegion(" + ToStr::Get(src) + "," + ToStr::Get(dst) + ")"; + + FetchDrawcall draw; + draw.name = name; + draw.flags |= eDraw_Copy; + + draw.copySource = src; + draw.copyDestination = dst; + + m_Cmd->AddDrawcall(draw, true); + + D3D12DrawcallTreeNode &drawNode = m_Cmd->GetDrawcallStack().back()->children.back(); + + if(src == dst) + { + drawNode.resourceUsage.push_back( + std::make_pair(GetResID(pSrcBuffer), EventUsage(drawNode.draw.eventID, eUsage_Copy))); + } + else + { + drawNode.resourceUsage.push_back(std::make_pair( + GetResID(pSrcBuffer), EventUsage(drawNode.draw.eventID, eUsage_CopySrc))); + drawNode.resourceUsage.push_back(std::make_pair( + GetResID(pDstBuffer), EventUsage(drawNode.draw.eventID, eUsage_CopyDst))); + } + } } return true; @@ -292,8 +530,22 @@ bool WrappedID3D12GraphicsCommandList::Serialise_IASetPrimitiveTopology( SERIALISE_ELEMENT(ResourceId, CommandList, GetResourceID()); SERIALISE_ELEMENT(D3D12_PRIMITIVE_TOPOLOGY, topo, PrimitiveTopology); - if(m_State <= READING) + if(m_State < WRITING) + m_Cmd->m_LastCmdListID = CommandList; + + if(m_State == EXECUTING) { + if(m_Cmd->ShouldRerecordCmd(CommandList) && m_Cmd->InRerecordRange(CommandList)) + { + Unwrap(m_Cmd->RerecordCmdList(CommandList))->IASetPrimitiveTopology(topo); + + // m_RenderState.topo = topo; + } + } + else if(m_State == READING) + { + m_Cmd->m_BakedCmdListInfo[CommandList].state.topo = topo; + GetList(CommandList)->IASetPrimitiveTopology(topo); } @@ -320,7 +572,24 @@ bool WrappedID3D12GraphicsCommandList::Serialise_RSSetViewports(UINT NumViewport SERIALISE_ELEMENT(UINT, num, NumViewports); SERIALISE_ELEMENT_ARR(D3D12_VIEWPORT, views, pViewports, num); - if(m_State <= READING) + if(m_State < WRITING) + m_Cmd->m_LastCmdListID = CommandList; + + if(m_State == EXECUTING) + { + if(m_Cmd->ShouldRerecordCmd(CommandList) && m_Cmd->InRerecordRange(CommandList)) + { + Unwrap(m_Cmd->RerecordCmdList(CommandList))->RSSetViewports(num, views); + + /* + if(m_RenderState.views.size() < first + count) + m_RenderState.views.resize(first + count); + + for(uint32_t i = 0; i < count; i++) + m_RenderState.views[first + i] = views[i];*/ + } + } + else if(m_State == READING) { GetList(CommandList)->RSSetViewports(num, views); } @@ -351,7 +620,24 @@ bool WrappedID3D12GraphicsCommandList::Serialise_RSSetScissorRects(UINT NumRects SERIALISE_ELEMENT(UINT, num, NumRects); SERIALISE_ELEMENT_ARR(D3D12_RECT, rects, pRects, num); - if(m_State <= READING) + if(m_State < WRITING) + m_Cmd->m_LastCmdListID = CommandList; + + if(m_State == EXECUTING) + { + if(m_Cmd->ShouldRerecordCmd(CommandList) && m_Cmd->InRerecordRange(CommandList)) + { + Unwrap(m_Cmd->RerecordCmdList(CommandList))->RSSetScissorRects(num, rects); + + /* + if(m_RenderState.scissors.size() < first + count) + m_RenderState.scissors.resize(first + count); + + for(uint32_t i = 0; i < count; i++) + m_RenderState.scissors[first + i] = scissors[i];*/ + } + } + else if(m_State == READING) { GetList(CommandList)->RSSetScissorRects(num, rects); } @@ -389,7 +675,20 @@ bool WrappedID3D12GraphicsCommandList::Serialise_SetPipelineState(ID3D12Pipeline SERIALISE_ELEMENT(ResourceId, CommandList, GetResourceID()); SERIALISE_ELEMENT(ResourceId, pipe, GetResID(pPipelineState)); - if(m_State <= READING) + if(m_State < WRITING) + m_Cmd->m_LastCmdListID = CommandList; + + if(m_State == EXECUTING) + { + if(m_Cmd->ShouldRerecordCmd(CommandList) && m_Cmd->InRerecordRange(CommandList)) + { + pPipelineState = GetResourceManager()->GetLiveAs(pipe); + Unwrap(m_Cmd->RerecordCmdList(CommandList))->SetPipelineState(Unwrap(pPipelineState)); + + // m_RenderState.pipe = ; + } + } + else if(m_State == READING) { pPipelineState = GetResourceManager()->GetLiveAs(pipe); GetList(CommandList)->SetPipelineState(Unwrap(pPipelineState)); @@ -419,11 +718,94 @@ bool WrappedID3D12GraphicsCommandList::Serialise_ResourceBarrier(UINT NumBarrier SERIALISE_ELEMENT(UINT, num, NumBarriers); SERIALISE_ELEMENT_ARR(D3D12_RESOURCE_BARRIER, barriers, pBarriers, num); + if(m_State < WRITING) + m_Cmd->m_LastCmdListID = CommandList; + if(m_State <= READING) { // TODO filter out any barriers for NULL resources GetList(CommandList)->ResourceBarrier(num, barriers); } + if(m_State == EXECUTING) + { + if(m_Cmd->ShouldRerecordCmd(CommandList) && m_Cmd->InRerecordRange(CommandList)) + { + ID3D12GraphicsCommandList *list = m_Cmd->RerecordCmdList(CommandList); + Unwrap(list)->ResourceBarrier(num, barriers); + + ResourceId cmd = GetResID(list); + + // need to re-wrap the barriers + for(UINT i = 0; i < num; i++) + { + D3D12_RESOURCE_BARRIER b = barriers[i]; + + switch(b.Type) + { + case D3D12_RESOURCE_BARRIER_TYPE_TRANSITION: + { + b.Transition.pResource = + (ID3D12Resource *)GetResourceManager()->GetWrapper(b.Transition.pResource); + break; + } + case D3D12_RESOURCE_BARRIER_TYPE_ALIASING: + { + b.Aliasing.pResourceBefore = + (ID3D12Resource *)GetResourceManager()->GetWrapper(b.Aliasing.pResourceBefore); + b.Aliasing.pResourceAfter = + (ID3D12Resource *)GetResourceManager()->GetWrapper(b.Aliasing.pResourceAfter); + break; + } + case D3D12_RESOURCE_BARRIER_TYPE_UAV: + { + b.UAV.pResource = (ID3D12Resource *)GetResourceManager()->GetWrapper(b.UAV.pResource); + break; + } + } + + m_Cmd->m_BakedCmdListInfo[cmd].barriers.push_back(b); + } + } + } + else if(m_State == READING) + { + ID3D12GraphicsCommandList *list = GetList(CommandList); + + list->ResourceBarrier(num, barriers); + + ResourceId cmd = GetResID(list); + + // need to re-wrap the barriers + for(UINT i = 0; i < num; i++) + { + D3D12_RESOURCE_BARRIER b = barriers[i]; + + switch(b.Type) + { + case D3D12_RESOURCE_BARRIER_TYPE_TRANSITION: + { + b.Transition.pResource = + (ID3D12Resource *)GetResourceManager()->GetWrapper(b.Transition.pResource); + break; + } + case D3D12_RESOURCE_BARRIER_TYPE_ALIASING: + { + b.Aliasing.pResourceBefore = + (ID3D12Resource *)GetResourceManager()->GetWrapper(b.Aliasing.pResourceBefore); + b.Aliasing.pResourceAfter = + (ID3D12Resource *)GetResourceManager()->GetWrapper(b.Aliasing.pResourceAfter); + break; + } + case D3D12_RESOURCE_BARRIER_TYPE_UAV: + { + b.UAV.pResource = (ID3D12Resource *)GetResourceManager()->GetWrapper(b.UAV.pResource); + break; + } + } + + m_Cmd->m_BakedCmdListInfo[cmd].barriers.push_back(b); + } + } return true; } @@ -487,9 +869,21 @@ bool WrappedID3D12GraphicsCommandList::Serialise_SetGraphicsRootSignature( SERIALISE_ELEMENT(ResourceId, CommandList, GetResourceID()); SERIALISE_ELEMENT(ResourceId, sig, GetResID(pRootSignature)); - if(m_State <= READING) + if(m_State < WRITING) + m_Cmd->m_LastCmdListID = CommandList; + + if(m_State == EXECUTING) + { + if(m_Cmd->ShouldRerecordCmd(CommandList) && m_Cmd->InRerecordRange(CommandList)) + { + pRootSignature = GetResourceManager()->GetLiveAs(sig); + Unwrap(m_Cmd->RerecordCmdList(CommandList))->SetGraphicsRootSignature(Unwrap(pRootSignature)); + } + } + else if(m_State == READING) { pRootSignature = GetResourceManager()->GetLiveAs(sig); + GetList(CommandList)->SetGraphicsRootSignature(Unwrap(pRootSignature)); } @@ -574,7 +968,20 @@ bool WrappedID3D12GraphicsCommandList::Serialise_SetGraphicsRootConstantBufferVi SERIALISE_ELEMENT(ResourceId, buffer, id); SERIALISE_ELEMENT(UINT64, byteOffset, offs); - if(m_State <= READING) + if(m_State < WRITING) + m_Cmd->m_LastCmdListID = CommandList; + + if(m_State == EXECUTING) + { + if(m_Cmd->ShouldRerecordCmd(CommandList) && m_Cmd->InRerecordRange(CommandList)) + { + WrappedID3D12Resource *pRes = GetResourceManager()->GetLiveAs(buffer); + + Unwrap(m_Cmd->RerecordCmdList(CommandList)) + ->SetGraphicsRootConstantBufferView(idx, pRes->GetGPUVirtualAddress() + byteOffset); + } + } + else if(m_State == READING) { WrappedID3D12Resource *pRes = GetResourceManager()->GetLiveAs(buffer); @@ -634,12 +1041,54 @@ bool WrappedID3D12GraphicsCommandList::Serialise_IASetIndexBuffer(const D3D12_IN SERIALISE_ELEMENT(bool, HasView, pView != NULL); SERIALISE_ELEMENT_OPT(D3D12_INDEX_BUFFER_VIEW, view, *pView, HasView); - if(m_State <= READING) + if(m_State < WRITING) + m_Cmd->m_LastCmdListID = CommandList; + + if(m_State == EXECUTING) { + if(m_Cmd->ShouldRerecordCmd(CommandList) && m_Cmd->InRerecordRange(CommandList)) + { + ID3D12GraphicsCommandList *list = m_Cmd->RerecordCmdList(CommandList); + + if(HasView) + { + Unwrap(list)->IASetIndexBuffer(&view); + + // WrappedID3D12Resource::GetResIDFromAddr(view.BufferLocation, m_RenderState.ibuffer.buf, + // m_RenderState.ibuffer.offs); + // m_RenderState.ibuffer.bytewidth = (view.Format == DXGI_FORMAT_R32_UINT ? 4 : 2); + } + else + { + Unwrap(list)->IASetIndexBuffer(NULL); + + // m_RenderState.ibuffer.buf = ResourceId(); + // m_RenderState.ibuffer.offs = 0; + // m_RenderState.ibuffer.bytewidth = 2; + } + } + } + else if(m_State == READING) + { + ID3D12GraphicsCommandList *list = GetList(CommandList); + if(HasView) - GetList(CommandList)->IASetIndexBuffer(&view); + { + list->IASetIndexBuffer(&view); + + UINT64 dummy = 0; + WrappedID3D12Resource::GetResIDFromAddr( + view.BufferLocation, m_Cmd->m_BakedCmdListInfo[CommandList].state.ibuffer, dummy); + m_Cmd->m_BakedCmdListInfo[CommandList].state.idxWidth = + (view.Format == DXGI_FORMAT_R32_UINT ? 4 : 2); + } else - GetList(CommandList)->IASetIndexBuffer(NULL); + { + list->IASetIndexBuffer(NULL); + + m_Cmd->m_BakedCmdListInfo[CommandList].state.ibuffer = ResourceId(); + m_Cmd->m_BakedCmdListInfo[CommandList].state.idxWidth = 2; + } } return true; @@ -674,7 +1123,19 @@ bool WrappedID3D12GraphicsCommandList::Serialise_IASetVertexBuffers( SERIALISE_ELEMENT(UINT, num, NumViews); SERIALISE_ELEMENT_ARR(D3D12_VERTEX_BUFFER_VIEW, views, pViews, num); - if(m_State <= READING) + if(m_State < WRITING) + m_Cmd->m_LastCmdListID = CommandList; + + if(m_State == EXECUTING) + { + if(m_Cmd->ShouldRerecordCmd(CommandList) && m_Cmd->InRerecordRange(CommandList)) + { + Unwrap(m_Cmd->RerecordCmdList(CommandList))->IASetVertexBuffers(start, num, views); + + // m_RenderState.vbuffers = ; + } + } + else if(m_State == READING) { GetList(CommandList)->IASetVertexBuffers(start, num, views); } @@ -720,6 +1181,9 @@ bool WrappedID3D12GraphicsCommandList::Serialise_OMSetRenderTargets( SERIALISE_ELEMENT(UINT, num, NumRenderTargetDescriptors); SERIALISE_ELEMENT(bool, singlehandle, RTsSingleHandleToDescriptorRange != FALSE); + if(m_State < WRITING) + m_Cmd->m_LastCmdListID = CommandList; + UINT numHandles = singlehandle ? 1U : num; std::vector rts; @@ -739,7 +1203,25 @@ bool WrappedID3D12GraphicsCommandList::Serialise_OMSetRenderTargets( ? ToPortableHandle(*pDepthStencilDescriptor) : PortableHandle(0)); - if(m_State <= READING) + if(m_State == EXECUTING) + { + if(m_Cmd->ShouldRerecordCmd(CommandList) && m_Cmd->InRerecordRange(CommandList)) + { + D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = FromPortableHandle(GetResourceManager(), dsv); + + D3D12_CPU_DESCRIPTOR_HANDLE *rtHandles = new D3D12_CPU_DESCRIPTOR_HANDLE[numHandles]; + + for(UINT i = 0; i < numHandles; i++) + rtHandles[i] = FromPortableHandle(GetResourceManager(), rts[i]); + + Unwrap(m_Cmd->RerecordCmdList(CommandList)) + ->OMSetRenderTargets(num, rtHandles, singlehandle ? TRUE : FALSE, + dsv.heap != ResourceId() ? &dsvHandle : NULL); + + SAFE_DELETE_ARRAY(rtHandles); + } + } + else if(m_State == READING) { D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = FromPortableHandle(GetResourceManager(), dsv); @@ -751,6 +1233,8 @@ bool WrappedID3D12GraphicsCommandList::Serialise_OMSetRenderTargets( GetList(CommandList) ->OMSetRenderTargets(num, rtHandles, singlehandle ? TRUE : FALSE, dsv.heap != ResourceId() ? &dsvHandle : NULL); + + SAFE_DELETE_ARRAY(rtHandles); } return true; @@ -811,6 +1295,9 @@ bool WrappedID3D12GraphicsCommandList::Serialise_ClearRenderTargetView( SERIALISE_ELEMENT(ResourceId, CommandList, GetResourceID()); SERIALISE_ELEMENT(PortableHandle, rtv, ToPortableHandle(RenderTargetView)); + if(m_State < WRITING) + m_Cmd->m_LastCmdListID = CommandList; + float Color[4] = {0}; if(m_State >= WRITING) @@ -821,11 +1308,42 @@ bool WrappedID3D12GraphicsCommandList::Serialise_ClearRenderTargetView( SERIALISE_ELEMENT(UINT, num, NumRects); SERIALISE_ELEMENT_ARR(D3D12_RECT, rects, pRects, num); - if(m_State <= READING) + if(m_State == EXECUTING) + { + RenderTargetView = FromPortableHandle(GetResourceManager(), rtv); + + if(m_Cmd->ShouldRerecordCmd(CommandList) && m_Cmd->InRerecordRange(CommandList)) + { + Unwrap(m_Cmd->RerecordCmdList(CommandList)) + ->ClearRenderTargetView(RenderTargetView, Color, num, rects); + } + } + else if(m_State == READING) { RenderTargetView = FromPortableHandle(GetResourceManager(), rtv); GetList(CommandList)->ClearRenderTargetView(RenderTargetView, Color, num, rects); + + const string desc = m_pSerialiser->GetDebugStr(); + + { + m_Cmd->AddEvent(CLEAR_RTV, desc); + string name = "ClearRenderTargetView(" + ToStr::Get(Color[0]) + "," + ToStr::Get(Color[1]) + + "," + ToStr::Get(Color[2]) + "," + ToStr::Get(Color[3]) + ")"; + + FetchDrawcall draw; + draw.name = name; + draw.flags |= eDraw_Clear | eDraw_ClearColour; + + m_Cmd->AddDrawcall(draw, true); + + D3D12NOTIMP("Getting image for RTV to mark usage"); + + // D3D12DrawcallTreeNode &drawNode = m_Cmd->GetDrawcallStack().back()->children.back(); + + // drawNode.resourceUsage.push_back( + // std::make_pair(GetResID(image), EventUsage(drawNode.draw.eventID, eUsage_Clear))); + } } SAFE_DELETE_ARRAY(rects); diff --git a/renderdoc/driver/d3d12/d3d12_command_queue.h b/renderdoc/driver/d3d12/d3d12_command_queue.h index cad589aad..da193fa7e 100644 --- a/renderdoc/driver/d3d12/d3d12_command_queue.h +++ b/renderdoc/driver/d3d12/d3d12_command_queue.h @@ -26,6 +26,7 @@ #include #include "common/wrapped_pool.h" +#include "d3d12_commands.h" #include "d3d12_common.h" #include "d3d12_device.h" #include "d3d12_resources.h" @@ -67,44 +68,14 @@ 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 { + friend class WrappedID3D12GraphicsCommandList; + WrappedID3D12Device *m_pDevice; WrappedID3D12GraphicsCommandList *m_ReplayList; @@ -119,136 +90,11 @@ 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; + // command recording/replay data shared between queues and lists + D3D12CommandData m_Cmd; ResourceId m_BackbufferID; - 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(ResourceId cmdid); - ID3D12GraphicsCommandList *RerecordCmdList(ResourceId cmdid); - void ProcessChunk(uint64_t offset, D3D12ChunkType context); const char *GetChunkName(uint32_t idx) { return m_pDevice->GetChunkName(idx); } @@ -267,17 +113,16 @@ public: D3D12ResourceRecord *GetResourceRecord() { return m_QueueRecord; } WrappedID3D12Device *GetWrappedDevice() { return m_pDevice; } const vector &GetCmdLists() { return m_CmdListRecords; } - D3D12DrawcallTreeNode &GetParentDrawcall() { return m_ParentDrawcall; } + D3D12DrawcallTreeNode &GetParentDrawcall() { return m_Cmd.m_ParentDrawcall; } FetchAPIEvent GetEvent(uint32_t eventID); - uint32_t GetMaxEID() { return m_Events.back().eventID; } + uint32_t GetMaxEID() { return m_Cmd.m_Events.back().eventID; } ResourceId GetBackbufferResourceID() { return m_BackbufferID; } 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); + D3D12CommandData *GetCommandData() { return &m_Cmd; } + vector GetUsage(ResourceId id) { return m_Cmd.m_ResourceUses[id]; } // 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 ef4e9c128..16631b863 100644 --- a/renderdoc/driver/d3d12/d3d12_command_queue_wrap.cpp +++ b/renderdoc/driver/d3d12/d3d12_command_queue_wrap.cpp @@ -50,29 +50,243 @@ void STDMETHODCALLTYPE WrappedID3D12CommandQueue::CopyTileMappings( bool WrappedID3D12CommandQueue::Serialise_ExecuteCommandLists(UINT NumCommandLists, ID3D12CommandList *const *ppCommandLists) { - SERIALISE_ELEMENT(UINT, num, NumCommandLists); + SERIALISE_ELEMENT(UINT, numCmds, NumCommandLists); - std::vector ids; + vector cmdIds; + ID3D12CommandList **cmds = m_State >= WRITING ? NULL : new ID3D12CommandList *[numCmds]; if(m_State >= WRITING) { - ids.reserve(num); - for(UINT i = 0; i < num; i++) - ids.push_back(GetResID(ppCommandLists[i])); + for(UINT i = 0; i < numCmds; i++) + { + D3D12ResourceRecord *record = GetRecord(ppCommandLists[i]); + RDCASSERT(record->bakedCommands); + if(record->bakedCommands) + cmdIds.push_back(record->bakedCommands->GetResourceID()); + } } - m_pSerialiser->Serialise("ppCommandLists", ids); + m_pSerialiser->Serialise("ppCommandLists", cmdIds); - if(m_State <= EXECUTING) + if(m_State < WRITING) { - std::vector unwrappedLists; - unwrappedLists.reserve(num); - for(UINT i = 0; i < num; i++) - unwrappedLists.push_back(Unwrap(GetResourceManager()->GetLiveAs(ids[i]))); - - m_pReal->ExecuteCommandLists(num, &unwrappedLists[0]); + for(UINT i = 0; i < numCmds; i++) + { + cmds[i] = cmdIds[i] != ResourceId() + ? Unwrap(GetResourceManager()->GetLiveAs(cmdIds[i])) + : NULL; + } } + const string desc = m_pSerialiser->GetDebugStr(); + + D3D12NOTIMP("Serialise_DebugMessages"); + + if(m_State == READING) + { + m_pReal->ExecuteCommandLists(numCmds, cmds); + + for(uint32_t i = 0; i < numCmds; i++) + { + ResourceId cmd = GetResourceManager()->GetLiveID(cmdIds[i]); + m_pDevice->ApplyBarriers(m_Cmd.m_BakedCmdListInfo[cmd].barriers); + } + + m_Cmd.AddEvent(EXECUTE_CMD_LISTS, desc); + + // we're adding multiple events, need to increment ourselves + m_Cmd.m_RootEventID++; + + string basename = "ExecuteCommandLists(" + ToStr::Get(numCmds) + ")"; + + for(uint32_t c = 0; c < numCmds; c++) + { + string name = StringFormat::Fmt("=> %s[%u]: ID3D12CommandList(%s)", basename.c_str(), c, + ToStr::Get(cmdIds[c]).c_str()); + + // add a fake marker + FetchDrawcall draw; + draw.name = name; + draw.flags |= eDraw_SetMarker; + m_Cmd.AddEvent(SET_MARKER, name); + m_Cmd.AddDrawcall(draw, true); + m_Cmd.m_RootEventID++; + + BakedCmdListInfo &cmdBufInfo = m_Cmd.m_BakedCmdListInfo[cmdIds[c]]; + + // insert the baked command buffer in-line into this list of notes, assigning new event and + // drawIDs + m_Cmd.InsertDrawsAndRefreshIDs(cmdBufInfo.draw->children); + + for(size_t e = 0; e < cmdBufInfo.draw->executedCmds.size(); e++) + { + vector &submits = + m_Cmd.m_Partial[D3D12CommandData::Secondary].cmdListExecs[cmdBufInfo.draw->executedCmds[e]]; + + for(size_t s = 0; s < submits.size(); s++) + submits[s] += m_Cmd.m_RootEventID; + } + + D3D12NOTIMP("Debug Messages"); + /* + for(size_t i = 0; i < cmdBufInfo.debugMessages.size(); i++) + { + m_DebugMessages.push_back(cmdBufInfo.debugMessages[i]); + m_DebugMessages.back().eventID += m_RootEventID; + } + */ + + // only primary command buffers can be submitted + m_Cmd.m_Partial[D3D12CommandData::Primary].cmdListExecs[cmdIds[c]].push_back( + m_Cmd.m_RootEventID); + + m_Cmd.m_RootEventID += cmdBufInfo.eventCount; + m_Cmd.m_RootDrawcallID += cmdBufInfo.drawCount; + + name = StringFormat::Fmt("=> %s[%u]: Close(%s)", basename.c_str(), c, + ToStr::Get(cmdIds[c]).c_str()); + draw.name = name; + m_Cmd.AddEvent(SET_MARKER, name); + m_Cmd.AddDrawcall(draw, true); + m_Cmd.m_RootEventID++; + } + + // account for the outer loop thinking we've added one event and incrementing, + // since we've done all the handling ourselves this will be off by one. + m_Cmd.m_RootEventID--; + } + else if(m_State == EXECUTING) + { + // account for the queue submit event + m_Cmd.m_RootEventID++; + + uint32_t startEID = m_Cmd.m_RootEventID; + + // advance m_CurEventID to match the events added when reading + for(uint32_t c = 0; c < numCmds; c++) + { + // 2 extra for the virtual labels around the command buffer + m_Cmd.m_RootEventID += 2 + m_Cmd.m_BakedCmdListInfo[cmdIds[c]].eventCount; + m_Cmd.m_RootDrawcallID += 2 + m_Cmd.m_BakedCmdListInfo[cmdIds[c]].drawCount; + } + + // same accounting for the outer loop as above + m_Cmd.m_RootEventID--; + + D3D12NOTIMP("m_DrawcallCallback"); + + if(numCmds == 0) + { + // do nothing, don't bother with the logic below + } + else if(m_Cmd.m_LastEventID <= startEID) + { +#ifdef VERBOSE_PARTIAL_REPLAY + RDCDEBUG("Queue Submit no replay %u == %u", m_Cmd.m_LastEventID, startEID); +#endif + } + /* + else if(m_DrawcallCallback && m_DrawcallCallback->RecordAllCmds()) + { +#ifdef VERBOSE_PARTIAL_REPLAY + RDCDEBUG("Queue Submit re-recording from %u", m_RootEventID); +#endif + + vector rerecordedCmds; + + for(uint32_t c = 0; c < numCmds; c++) + { + ID3D12CommandList *cmd = RerecordCmdBuf(cmdIds[c]); + ResourceId rerecord = GetResID(cmd); +#ifdef VERBOSE_PARTIAL_REPLAY + RDCDEBUG("Queue Submit fully re-recorded replay of %llu, using %llu", cmdIds[c], rerecord); +#endif + rerecordedCmds.push_back(Unwrap(cmd)); + + m_pDevice->ApplyBarriers(m_BakedCmdBufferInfo[rerecord].imgbarriers); + } + + m_pReal->ExecuteCommandLists((UINT)rerecordedCmds.size(), &rerecordedCmds[0]); + } + */ + else if(m_Cmd.m_LastEventID > startEID && m_Cmd.m_LastEventID < m_Cmd.m_RootEventID) + { +#ifdef VERBOSE_PARTIAL_REPLAY + RDCDEBUG("Queue Submit partial replay %u < %u", m_Cmd.m_LastEventID, m_Cmd.m_RootEventID); +#endif + + uint32_t eid = startEID; + + vector trimmedCmdIds; + vector trimmedCmds; + + for(uint32_t c = 0; c < numCmds; c++) + { + // account for the virtual vkBeginCommandBuffer label at the start of the events here + // so it matches up to baseEvent + eid++; + + uint32_t end = eid + m_Cmd.m_BakedCmdListInfo[cmdIds[c]].eventCount; + + if(eid == m_Cmd.m_Partial[D3D12CommandData::Primary].baseEvent) + { + ID3D12GraphicsCommandList *list = + m_Cmd.RerecordCmdList(cmdIds[c], D3D12CommandData::Primary); + ResourceId partial = GetResID(list); +#ifdef VERBOSE_PARTIAL_REPLAY + RDCDEBUG("Queue Submit partial replay of %llu at %u, using %llu", cmdIds[c], eid, partial); +#endif + trimmedCmdIds.push_back(partial); + trimmedCmds.push_back(Unwrap(list)); + } + else if(m_Cmd.m_LastEventID >= end) + { +#ifdef VERBOSE_PARTIAL_REPLAY + RDCDEBUG("Queue Submit full replay %llu", cmdIds[c]); +#endif + trimmedCmdIds.push_back(cmdIds[c]); + trimmedCmds.push_back(Unwrap(GetResourceManager()->GetLiveAs(cmdIds[c]))); + } + else + { +#ifdef VERBOSE_PARTIAL_REPLAY + RDCDEBUG("Queue not submitting %llu", cmdIds[c]); +#endif + } + + // 1 extra to account for the virtual end command buffer label (begin is accounted for + // above) + eid += 1 + m_Cmd.m_BakedCmdListInfo[cmdIds[c]].eventCount; + } + + RDCASSERT(trimmedCmds.size() > 0); + + m_pReal->ExecuteCommandLists((UINT)trimmedCmds.size(), &trimmedCmds[0]); + + for(uint32_t i = 0; i < trimmedCmdIds.size(); i++) + { + ResourceId cmd = trimmedCmdIds[i]; + m_pDevice->ApplyBarriers(m_Cmd.m_BakedCmdListInfo[cmd].barriers); + } + } + else + { +#ifdef VERBOSE_PARTIAL_REPLAY + RDCDEBUG("Queue Submit full replay %u >= %u", m_Cmd.m_LastEventID, m_Cmd.m_RootEventID); +#endif + + m_pReal->ExecuteCommandLists(numCmds, cmds); + + for(uint32_t i = 0; i < numCmds; i++) + { + ResourceId cmd = GetResourceManager()->GetLiveID(cmdIds[i]); + m_pDevice->ApplyBarriers(m_Cmd.m_BakedCmdListInfo[cmd].barriers); + } + } + } + + SAFE_DELETE_ARRAY(cmds); + return true; } diff --git a/renderdoc/driver/d3d12/d3d12_commands.cpp b/renderdoc/driver/d3d12/d3d12_commands.cpp index 2fb6b874c..df78a4194 100644 --- a/renderdoc/driver/d3d12/d3d12_commands.cpp +++ b/renderdoc/driver/d3d12/d3d12_commands.cpp @@ -150,6 +150,8 @@ WrappedID3D12CommandQueue::WrappedID3D12CommandQueue(ID3D12CommandQueue *real, m_pSerialiser = serialiser; m_ReplayList = new WrappedID3D12GraphicsCommandList(NULL, m_pDevice, m_pSerialiser, state); + + m_ReplayList->SetCommandData(&m_Cmd); } else { @@ -165,19 +167,7 @@ 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); + m_Cmd.m_pSerialiser = m_pSerialiser; if(!RenderDoc::Inst().IsReplayApp()) { @@ -247,20 +237,19 @@ void WrappedID3D12CommandQueue::ClearAfterCapture() FetchAPIEvent WrappedID3D12CommandQueue::GetEvent(uint32_t eventID) { - for(size_t i = m_Events.size() - 1; i > 0; i--) + for(size_t i = m_Cmd.m_Events.size() - 1; i > 0; i--) { - if(m_Events[i].eventID <= eventID) - return m_Events[i]; + if(m_Cmd.m_Events[i].eventID <= eventID) + return m_Cmd.m_Events[i]; } - return m_Events[0]; + return m_Cmd.m_Events[0]; } void WrappedID3D12CommandQueue::ProcessChunk(uint64_t offset, D3D12ChunkType chunk) { - m_CurChunkOffset = offset; - - m_AddedDrawcall = false; + m_Cmd.m_CurChunkOffset = offset; + m_Cmd.m_AddedDrawcall = false; switch(chunk) { @@ -316,7 +305,7 @@ void WrappedID3D12CommandQueue::ProcessChunk(uint64_t offset, D3D12ChunkType chu if(m_State == READING) { - AddEvent(CONTEXT_CAPTURE_FOOTER, "Present()"); + m_Cmd.AddEvent(CONTEXT_CAPTURE_FOOTER, "Present()"); FetchDrawcall draw; draw.name = "Present()"; @@ -324,7 +313,7 @@ void WrappedID3D12CommandQueue::ProcessChunk(uint64_t offset, D3D12ChunkType chu draw.copyDestination = bbid; - AddDrawcall(draw, true); + m_Cmd.AddDrawcall(draw, true); } break; } @@ -351,11 +340,11 @@ void WrappedID3D12CommandQueue::ProcessChunk(uint64_t offset, D3D12ChunkType chu } else if(m_State == READING) { - if(!m_AddedDrawcall) - AddEvent(chunk, m_pSerialiser->GetDebugStr()); + if(!m_Cmd.m_AddedDrawcall) + m_Cmd.AddEvent(chunk, m_pSerialiser->GetDebugStr()); } - m_AddedDrawcall = false; + m_Cmd.m_AddedDrawcall = false; } void WrappedID3D12CommandQueue::ReplayLog(LogState readType, uint32_t startEventID, @@ -373,12 +362,12 @@ void WrappedID3D12CommandQueue::ReplayLog(LogState readType, uint32_t startEvent m_pSerialiser->PopContext(header); - m_RootEvents.clear(); + m_Cmd.m_RootEvents.clear(); if(m_State == EXECUTING) { FetchAPIEvent ev = GetEvent(startEventID); - m_RootEventID = ev.eventID; + m_Cmd.m_RootEventID = ev.eventID; // if not partial, we need to be sure to replay // past the command buffer records, so can't @@ -386,20 +375,20 @@ void WrappedID3D12CommandQueue::ReplayLog(LogState readType, uint32_t startEvent if(partial) m_pSerialiser->SetOffset(ev.fileOffset); - m_FirstEventID = startEventID; - m_LastEventID = endEventID; + m_Cmd.m_FirstEventID = startEventID; + m_Cmd.m_LastEventID = endEventID; } else if(m_State == READING) { - m_RootEventID = 1; - m_RootDrawcallID = 1; - m_FirstEventID = 0; - m_LastEventID = ~0U; + m_Cmd.m_RootEventID = 1; + m_Cmd.m_RootDrawcallID = 1; + m_Cmd.m_FirstEventID = 0; + m_Cmd.m_LastEventID = ~0U; } for(;;) { - if(m_State == EXECUTING && m_RootEventID > endEventID) + if(m_State == EXECUTING && m_Cmd.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 @@ -410,7 +399,7 @@ void WrappedID3D12CommandQueue::ReplayLog(LogState readType, uint32_t startEvent D3D12ChunkType context = (D3D12ChunkType)m_pSerialiser->PushContext(NULL, NULL, 1, false); - m_LastCmdListID = ResourceId(); + m_Cmd.m_LastCmdListID = ResourceId(); ProcessChunk(offset, context); @@ -430,16 +419,16 @@ void WrappedID3D12CommandQueue::ReplayLog(LogState readType, uint32_t startEvent // 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) + if(m_Cmd.m_LastCmdListID == ResourceId() || startEventID > 1) { - m_RootEventID++; + m_Cmd.m_RootEventID++; if(startEventID > 1) - m_pSerialiser->SetOffset(GetEvent(m_RootEventID).fileOffset); + m_pSerialiser->SetOffset(GetEvent(m_Cmd.m_RootEventID).fileOffset); } else { - m_BakedCmdListInfo[m_LastCmdListID].curEventID++; + m_Cmd.m_BakedCmdListInfo[m_Cmd.m_LastCmdListID].curEventID++; } } @@ -456,119 +445,20 @@ void WrappedID3D12CommandQueue::ReplayLog(LogState readType, uint32_t startEvent } }; - std::sort(m_Events.begin(), m_Events.end(), SortEID()); + std::sort(m_Cmd.m_Events.begin(), m_Cmd.m_Events.end(), SortEID()); } - SAFE_RELEASE(m_PartialReplayData.resultPartialCmdList); + for(int p = 0; p < D3D12CommandData::ePartialNum; p++) + SAFE_RELEASE(m_Cmd.m_Partial[p].resultPartialCmdList); - for(auto it = m_RerecordCmds.begin(); it != m_RerecordCmds.end(); ++it) + for(auto it = m_Cmd.m_RerecordCmds.begin(); it != m_Cmd.m_RerecordCmds.end(); ++it) SAFE_RELEASE(it->second); - m_RerecordCmds.clear(); + m_Cmd.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, @@ -601,6 +491,7 @@ WrappedID3D12GraphicsCommandList::WrappedID3D12GraphicsCommandList(ID3D12Graphic RDCEraseEl(m_Init); m_ListRecord = NULL; + m_Cmd = NULL; if(!RenderDoc::Inst().IsReplayApp()) { @@ -615,6 +506,10 @@ WrappedID3D12GraphicsCommandList::WrappedID3D12GraphicsCommandList(ID3D12Graphic // this is set up in the implicit Reset() right after creation m_ListRecord->bakedCommands = NULL; } + else + { + m_Cmd = m_pDevice->GetQueue()->GetCommandData(); + } m_pDevice->SoftRef(); } @@ -671,12 +566,228 @@ HRESULT STDMETHODCALLTYPE WrappedID3D12GraphicsCommandList::QueryInterface(REFII return RefCounter12::QueryInterface(riid, ppvObject); } -void WrappedID3D12GraphicsCommandList::AddDrawcall(const FetchDrawcall &d, bool hasEvents) +D3D12CommandData::D3D12CommandData() { - m_pDevice->GetQueue()->AddDrawcall(d, hasEvents); + m_RootEventID = 1; + m_RootDrawcallID = 1; + m_FirstEventID = 0; + m_LastEventID = ~0U; + + m_RootDrawcallStack.push_back(&m_ParentDrawcall); } -void WrappedID3D12GraphicsCommandList::AddEvent(D3D12ChunkType type, string description) +bool D3D12CommandData::ShouldRerecordCmd(ResourceId cmdid) { - m_pDevice->GetQueue()->AddEvent(type, description); + if(m_Partial[Primary].outsideCmdList != NULL) + return true; + + D3D12NOTIMP("m_DrawcallCallback"); + /* + if(m_DrawcallCallback && m_DrawcallCallback->RecordAllCmds()) + return true; + */ + + return cmdid == m_Partial[Primary].partialParent || cmdid == m_Partial[Secondary].partialParent; +} + +bool D3D12CommandData::InRerecordRange(ResourceId cmdid) +{ + if(m_Partial[Primary].outsideCmdList != NULL) + return true; + + D3D12NOTIMP("m_DrawcallCallback"); + /* + if(m_DrawcallCallback && m_DrawcallCallback->RecordAllCmds()) + return true; + */ + + for(int p = 0; p < ePartialNum; p++) + { + if(cmdid == m_Partial[p].partialParent) + { + return m_BakedCmdListInfo[m_Partial[p].partialParent].curEventID <= + m_LastEventID - m_Partial[p].baseEvent; + } + } + + return false; +} + +ID3D12GraphicsCommandList *D3D12CommandData::RerecordCmdList(ResourceId cmdid, + PartialReplayIndex partialType) +{ + if(m_Partial[Primary].outsideCmdList != NULL) + return m_Partial[Primary].outsideCmdList; + + D3D12NOTIMP("m_DrawcallCallback"); + /* + if(m_DrawcallCallback && m_DrawcallCallback->RecordAllCmds()) + { + auto it = m_RerecordCmds.find(cmdid); + + RDCASSERT(it != m_RerecordCmds.end()); + + return it->second; + } + */ + + if(partialType != ePartialNum) + return m_Partial[partialType].resultPartialCmdList; + + for(int p = 0; p < ePartialNum; p++) + if(cmdid == m_Partial[p].partialParent) + return m_Partial[p].resultPartialCmdList; + + RDCERR("Calling re-record for invalid command list id"); + + return NULL; +} + +void D3D12CommandData::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(); +} + +void D3D12CommandData::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 D3D12CommandData::InsertDrawsAndRefreshIDs(vector &cmdBufNodes) +{ + // assign new drawcall IDs + for(size_t i = 0; i < cmdBufNodes.size(); i++) + { + if(cmdBufNodes[i].draw.flags & eDraw_PopMarker) + { + RDCASSERT(GetDrawcallStack().size() > 1); + if(GetDrawcallStack().size() > 1) + GetDrawcallStack().pop_back(); + + // Skip - pop marker draws aren't processed otherwise, we just apply them to the drawcall + // stack. + continue; + } + + D3D12DrawcallTreeNode n = cmdBufNodes[i]; + n.draw.eventID += m_RootEventID; + n.draw.drawcallID += m_RootDrawcallID; + + for(int32_t e = 0; e < n.draw.events.count; e++) + { + n.draw.events[e].eventID += m_RootEventID; + m_Events.push_back(n.draw.events[e]); + } + + DrawcallUse use(m_Events.back().fileOffset, n.draw.eventID); + + // insert in sorted location + auto drawit = std::lower_bound(m_DrawcallUses.begin(), m_DrawcallUses.end(), use); + m_DrawcallUses.insert(drawit, use); + + RDCASSERT(n.children.empty()); + + for(auto it = n.resourceUsage.begin(); it != n.resourceUsage.end(); ++it) + { + EventUsage u = it->second; + u.eventID += m_RootEventID; + m_ResourceUses[it->first].push_back(u); + } + + GetDrawcallStack().back()->children.push_back(n); + + // if this is a push marker too, step down the drawcall stack + if(cmdBufNodes[i].draw.flags & eDraw_PushMarker) + GetDrawcallStack().push_back(&GetDrawcallStack().back()->children.back()); + } } diff --git a/renderdoc/driver/d3d12/d3d12_commands.h b/renderdoc/driver/d3d12/d3d12_commands.h new file mode 100644 index 000000000..2e4bf5f31 --- /dev/null +++ b/renderdoc/driver/d3d12/d3d12_commands.h @@ -0,0 +1,258 @@ +/****************************************************************************** + * 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 "common/common.h" +#include "api/replay/renderdoc_replay.h" +#include "d3d12_common.h" + +struct D3D12DrawcallTreeNode +{ + D3D12DrawcallTreeNode() {} + explicit D3D12DrawcallTreeNode(const FetchDrawcall &d) : draw(d) {} + FetchDrawcall draw; + vector children; + + vector > resourceUsage; + + vector executedCmds; + + D3D12DrawcallTreeNode &operator=(const FetchDrawcall &d) + { + *this = D3D12DrawcallTreeNode(d); + return *this; + } + + void InsertAndUpdateIDs(const D3D12DrawcallTreeNode &child, uint32_t baseEventID, + uint32_t baseDrawID) + { + for(size_t i = 0; i < child.resourceUsage.size(); i++) + { + resourceUsage.push_back(child.resourceUsage[i]); + resourceUsage.back().second.eventID += baseEventID; + } + + for(size_t i = 0; i < child.children.size(); i++) + { + children.push_back(child.children[i]); + children.back().draw.eventID += baseEventID; + children.back().draw.drawcallID += baseDrawID; + + for(int32_t e = 0; e < children.back().draw.events.count; e++) + children.back().draw.events[e].eventID += baseEventID; + } + } + + 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; + } +}; + +struct BakedCmdListInfo +{ + void BakeFrom(BakedCmdListInfo &parent) + { + draw = parent.draw; + curEvents = parent.curEvents; + debugMessages = parent.debugMessages; + eventCount = parent.curEventID; + drawCount = parent.drawCount; + + curEventID = 0; + + parent.draw = NULL; + parent.curEventID = 0; + parent.eventCount = 0; + parent.drawCount = 0; + parent.curEvents.clear(); + parent.debugMessages.clear(); + } + + vector curEvents; + vector debugMessages; + std::list drawStack; + + vector > resourceUsage; + + struct CmdListState + { + ResourceId pipeline; + + D3D12_PRIMITIVE_TOPOLOGY topo; + + 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 +}; + +struct D3D12CommandData +{ + D3D12CommandData(); + + Serialiser *m_pSerialiser; + + ResourceId m_LastCmdListID; + + map m_BakedCmdListInfo; + + enum PartialReplayIndex + { + Primary, + Secondary, + ePartialNum + }; + + struct PartialReplayData + { + PartialReplayData() { Reset(); } + void Reset() + { + resultPartialCmdList = NULL; + outsideCmdList = NULL; + partialParent = ResourceId(); + baseEvent = 0; + } + + // 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. + 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_Partial[ePartialNum]; + + void InsertDrawsAndRefreshIDs(vector &cmdBufNodes); + + // 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; + + map m_RerecordCmds; + + bool m_AddedDrawcall; + + vector m_RootEvents, m_Events; + + uint64_t m_CurChunkOffset; + + uint32_t m_RootEventID, m_RootDrawcallID; + uint32_t m_FirstEventID, m_LastEventID; + + map > m_ResourceUses; + + D3D12DrawcallTreeNode m_ParentDrawcall; + + std::list m_RootDrawcallStack; + + std::list &GetDrawcallStack() + { + if(m_LastCmdListID != ResourceId()) + return m_BakedCmdListInfo[m_LastCmdListID].drawStack; + + return m_RootDrawcallStack; + } + + bool ShouldRerecordCmd(ResourceId cmdid); + bool InRerecordRange(ResourceId cmdid); + ID3D12GraphicsCommandList *RerecordCmdList(ResourceId cmdid, + PartialReplayIndex partialType = ePartialNum); + + void AddDrawcall(const FetchDrawcall &d, bool hasEvents); + void AddEvent(D3D12ChunkType type, string description); +}; diff --git a/renderdoc/driver/d3d12/d3d12_common.h b/renderdoc/driver/d3d12/d3d12_common.h index 53d21fe26..1b27b7afd 100644 --- a/renderdoc/driver/d3d12/d3d12_common.h +++ b/renderdoc/driver/d3d12/d3d12_common.h @@ -35,7 +35,24 @@ // similar to RDCUNIMPLEMENTED but for things that are hit often so we don't want to fire the // debugbreak. -#define D3D12NOTIMP(...) RDCDEBUG("D3D12 not implemented - " __VA_ARGS__) +#define D3D12NOTIMP(...) \ + { \ + static bool CONCAT(ignore, __LINE__) = false; \ + if(!CONCAT(ignore, __LINE__)) \ + { \ + RDCDEBUG("D3D12 not implemented - " __VA_ARGS__); \ + CONCAT(ignore, __LINE__) = true; \ + } \ + } + +// uncomment this to cause every internal ExecuteCommandLists to immediately call +// FlushLists(), and to only submit one command list at once to narrow +// down the cause of device lost errors +//#define SINGLE_FLUSH_VALIDATE + +// uncomment this to get verbose debugging about when/where/why partial command +// buffer replay is happening +#define VERBOSE_PARTIAL_REPLAY UINT GetNumSubresources(const D3D12_RESOURCE_DESC *desc); diff --git a/renderdoc/driver/d3d12/d3d12_replay.cpp b/renderdoc/driver/d3d12/d3d12_replay.cpp index 5feffe988..b29c07285 100644 --- a/renderdoc/driver/d3d12/d3d12_replay.cpp +++ b/renderdoc/driver/d3d12/d3d12_replay.cpp @@ -229,6 +229,11 @@ ResourceId D3D12Replay::GetLiveID(ResourceId id) return m_pDevice->GetResourceManager()->GetLiveID(id); } +vector D3D12Replay::GetUsage(ResourceId id) +{ + return m_pDevice->GetQueue()->GetUsage(id); +} + void D3D12Replay::RenderCheckerboard(Vec3f light, Vec3f dark) { m_pDevice->GetDebugManager()->RenderCheckerboard(light, dark); @@ -326,11 +331,6 @@ ShaderReflection *D3D12Replay::GetShader(ResourceId shader, string entryPoint) return NULL; } -vector D3D12Replay::GetUsage(ResourceId id) -{ - return vector(); -} - vector D3D12Replay::GetDebugMessages() { return vector(); diff --git a/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj b/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj index 4901215a5..21f15cbdb 100644 --- a/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj +++ b/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj @@ -197,6 +197,7 @@ + diff --git a/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj.filters b/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj.filters index 799d571b5..66b7cfb55 100644 --- a/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj.filters +++ b/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj.filters @@ -51,6 +51,9 @@ Replay + + Core IFaces +