diff --git a/renderdoc/driver/d3d12/d3d12_command_list.h b/renderdoc/driver/d3d12/d3d12_command_list.h index 3a5f2d7ec..94ed293ef 100644 --- a/renderdoc/driver/d3d12/d3d12_command_list.h +++ b/renderdoc/driver/d3d12/d3d12_command_list.h @@ -93,6 +93,13 @@ class WrappedID3D12GraphicsCommandList : public RefCounter12GetChunkName(idx); } D3D12ResourceManager *GetResourceManager() { return m_pDevice->GetResourceManager(); } public: @@ -106,8 +113,16 @@ public: ResourceId GetResourceID() { return m_ResourceID; } ID3D12GraphicsCommandList *GetReal() { return m_pReal; } WrappedID3D12Device *GetWrappedDevice() { return m_pDevice; } + D3D12ResourceRecord *GetResourceRecord() { return m_ListRecord; } ID3D12GraphicsCommandList *GetList(ResourceId id); + void SetInitParams(REFIID riid, UINT nodeMask, D3D12_COMMAND_LIST_TYPE type) + { + m_Init.riid = riid; + m_Init.nodeMask = nodeMask; + m_Init.type = type; + } + ////////////////////////////// // implement IUnknown @@ -402,3 +417,8 @@ template <> ResourceId GetResID(ID3D12GraphicsCommandList *obj); template <> ResourceId GetResID(ID3D12CommandList *obj); + +template <> +D3D12ResourceRecord *GetRecord(ID3D12GraphicsCommandList *obj); +template <> +D3D12ResourceRecord *GetRecord(ID3D12CommandList *obj); \ No newline at end of file diff --git a/renderdoc/driver/d3d12/d3d12_command_list_wrap.cpp b/renderdoc/driver/d3d12/d3d12_command_list_wrap.cpp index 17874c7a0..17553d7b6 100644 --- a/renderdoc/driver/d3d12/d3d12_command_list_wrap.cpp +++ b/renderdoc/driver/d3d12/d3d12_command_list_wrap.cpp @@ -43,10 +43,14 @@ HRESULT WrappedID3D12GraphicsCommandList::Close() { if(m_State >= WRITING) { - SCOPED_SERIALISE_CONTEXT(CLOSE_LIST); - Serialise_Close(); + { + SCOPED_SERIALISE_CONTEXT(CLOSE_LIST); + Serialise_Close(); - m_ListRecord->AddChunk(scope.Get()); + m_ListRecord->AddChunk(scope.Get()); + } + + m_ListRecord->Bake(); } // bake m_ListRecord to somewhere else @@ -57,6 +61,11 @@ HRESULT WrappedID3D12GraphicsCommandList::Close() bool WrappedID3D12GraphicsCommandList::Serialise_Reset(ID3D12CommandAllocator *pAllocator, ID3D12PipelineState *pInitialState) { + // parameters to create the list with if needed + SERIALISE_ELEMENT(IID, riid, m_Init.riid); + SERIALISE_ELEMENT(UINT, nodeMask, m_Init.nodeMask); + SERIALISE_ELEMENT(D3D12_COMMAND_LIST_TYPE, type, m_Init.type); + SERIALISE_ELEMENT(ResourceId, CommandList, GetResourceID()); SERIALISE_ELEMENT(ResourceId, Allocator, GetResID(pAllocator)); SERIALISE_ELEMENT(ResourceId, State, GetResID(pInitialState)); @@ -67,6 +76,12 @@ bool WrappedID3D12GraphicsCommandList::Serialise_Reset(ID3D12CommandAllocator *p pInitialState = State == ResourceId() ? NULL : GetResourceManager()->GetLiveAs(State); + if(m_State == READING && !GetResourceManager()->HasLiveResource(CommandList)) + { + ID3D12GraphicsCommandList *list = NULL; + m_pDevice->CreateCommandList(nodeMask, type, pAllocator, pInitialState, riid, (void **)&list); + } + GetList(CommandList)->Reset(Unwrap(pAllocator), Unwrap(pInitialState)); } @@ -84,10 +99,21 @@ HRESULT WrappedID3D12GraphicsCommandList::Reset(ID3D12CommandAllocator *pAllocat // free parents m_ListRecord->FreeParents(GetResourceManager()); - SCOPED_SERIALISE_CONTEXT(RESET_LIST); - Serialise_Reset(pAllocator, pInitialState); + // free any baked commands + if(m_ListRecord->bakedCommands) + m_ListRecord->bakedCommands->Delete(GetResourceManager()); - m_ListRecord->AddChunk(scope.Get()); + m_ListRecord->bakedCommands = + GetResourceManager()->AddResourceRecord(ResourceIDGen::GetNewUniqueID()); + m_ListRecord->bakedCommands->SpecialResource = true; + m_ListRecord->bakedCommands->cmdInfo = new CmdListRecordingInfo(); + + { + SCOPED_SERIALISE_CONTEXT(RESET_LIST); + Serialise_Reset(pAllocator, pInitialState); + + m_ListRecord->AddChunk(scope.Get()); + } // add allocator and initial state (if there is one) as parents m_ListRecord->AddParent(GetRecord(pAllocator)); @@ -216,6 +242,8 @@ void WrappedID3D12GraphicsCommandList::CopyBufferRegion(ID3D12Resource *pDstBuff Serialise_CopyBufferRegion(pDstBuffer, DstOffset, pSrcBuffer, SrcOffset, NumBytes); m_ListRecord->AddChunk(scope.Get()); + m_ListRecord->MarkResourceFrameReferenced(GetResID(pDstBuffer), eFrameRef_Write); + m_ListRecord->MarkResourceFrameReferenced(GetResID(pSrcBuffer), eFrameRef_Read); } } @@ -379,6 +407,7 @@ void WrappedID3D12GraphicsCommandList::SetPipelineState(ID3D12PipelineState *pPi Serialise_SetPipelineState(pPipelineState); m_ListRecord->AddChunk(scope.Get()); + m_ListRecord->MarkResourceFrameReferenced(GetResID(pPipelineState), eFrameRef_Read); } } @@ -422,6 +451,9 @@ void WrappedID3D12GraphicsCommandList::ResourceBarrier(UINT NumBarriers, Serialise_ResourceBarrier(NumBarriers, pBarriers); m_ListRecord->AddChunk(scope.Get()); + + m_ListRecord->cmdInfo->barriers.insert(m_ListRecord->cmdInfo->barriers.end(), pBarriers, + pBarriers + NumBarriers); } } @@ -467,6 +499,7 @@ void WrappedID3D12GraphicsCommandList::SetGraphicsRootSignature(ID3D12RootSignat Serialise_SetGraphicsRootSignature(pRootSignature); m_ListRecord->AddChunk(scope.Get()); + m_ListRecord->MarkResourceFrameReferenced(GetResID(pRootSignature), eFrameRef_Read); } } @@ -548,6 +581,7 @@ void WrappedID3D12GraphicsCommandList::SetGraphicsRootConstantBufferView( Serialise_SetGraphicsRootConstantBufferView(RootParameterIndex, BufferLocation); m_ListRecord->AddChunk(scope.Get()); + m_ListRecord->MarkResourceFrameReferenced(GetResID(BufferLocation), eFrameRef_Read); } } @@ -612,6 +646,8 @@ void WrappedID3D12GraphicsCommandList::IASetIndexBuffer(const D3D12_INDEX_BUFFER Serialise_IASetIndexBuffer(pView); m_ListRecord->AddChunk(scope.Get()); + if(pView) + m_ListRecord->MarkResourceFrameReferenced(GetResID(pView->BufferLocation), eFrameRef_Read); } } @@ -654,6 +690,8 @@ void WrappedID3D12GraphicsCommandList::IASetVertexBuffers(UINT StartSlot, UINT N Serialise_IASetVertexBuffers(StartSlot, NumViews, pViews); m_ListRecord->AddChunk(scope.Get()); + for(UINT i = 0; i < NumViews; i++) + m_ListRecord->MarkResourceFrameReferenced(GetResID(pViews[i].BufferLocation), eFrameRef_Read); } } @@ -742,6 +780,19 @@ void WrappedID3D12GraphicsCommandList::OMSetRenderTargets( RTsSingleHandleToDescriptorRange, pDepthStencilDescriptor); m_ListRecord->AddChunk(scope.Get()); + for(UINT i = 0; i < numHandles; i++) + { + D3D12Descriptor *desc = GetWrapped(pRenderTargetDescriptors[i]); + m_ListRecord->MarkResourceFrameReferenced(desc->nonsamp.heap->GetResourceID(), eFrameRef_Read); + m_ListRecord->MarkResourceFrameReferenced(GetResID(desc->nonsamp.resource), eFrameRef_Read); + } + + if(pDepthStencilDescriptor) + { + D3D12Descriptor *desc = GetWrapped(*pDepthStencilDescriptor); + m_ListRecord->MarkResourceFrameReferenced(desc->nonsamp.heap->GetResourceID(), eFrameRef_Read); + m_ListRecord->MarkResourceFrameReferenced(GetResID(desc->nonsamp.resource), eFrameRef_Read); + } } } @@ -794,6 +845,12 @@ void WrappedID3D12GraphicsCommandList::ClearRenderTargetView( Serialise_ClearRenderTargetView(RenderTargetView, ColorRGBA, NumRects, pRects); m_ListRecord->AddChunk(scope.Get()); + + { + D3D12Descriptor *desc = GetWrapped(RenderTargetView); + m_ListRecord->MarkResourceFrameReferenced(desc->nonsamp.heap->GetResourceID(), eFrameRef_Read); + m_ListRecord->MarkResourceFrameReferenced(GetResID(desc->nonsamp.resource), eFrameRef_Read); + } } } diff --git a/renderdoc/driver/d3d12/d3d12_command_queue.h b/renderdoc/driver/d3d12/d3d12_command_queue.h index 31f20c51d..2c13adb4b 100644 --- a/renderdoc/driver/d3d12/d3d12_command_queue.h +++ b/renderdoc/driver/d3d12/d3d12_command_queue.h @@ -80,10 +80,13 @@ class WrappedID3D12CommandQueue : public ID3D12CommandQueue, DummyID3D12DebugCommandQueue m_DummyDebug; + vector m_CmdListRecords; + const char *GetChunkName(uint32_t idx) { return m_pDevice->GetChunkName(idx); } D3D12ResourceManager *GetResourceManager() { return m_pDevice->GetResourceManager(); } public: - ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D12CommandQueue); + static const int AllocPoolCount = 16; + ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D12CommandQueue, AllocPoolCount); WrappedID3D12CommandQueue(ID3D12CommandQueue *real, WrappedID3D12Device *device, Serialiser *serialiser, LogState &state); @@ -92,8 +95,11 @@ public: Serialiser *GetSerialiser() { return m_pSerialiser; } ResourceId GetResourceID() { return m_ResourceID; } ID3D12CommandQueue *GetReal() { return m_pReal; } - D3D12ResourceRecord *GetRecord() { return m_QueueRecord; } + D3D12ResourceRecord *GetResourceRecord() { return m_QueueRecord; } WrappedID3D12Device *GetWrappedDevice() { return m_pDevice; } + const vector &GetCmdLists() { return m_CmdListRecords; } + void ClearAfterCapture(); + // 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 8e5d8204d..b23e88d60 100644 --- a/renderdoc/driver/d3d12/d3d12_command_queue_wrap.cpp +++ b/renderdoc/driver/d3d12/d3d12_command_queue_wrap.cpp @@ -83,12 +83,84 @@ void STDMETHODCALLTYPE WrappedID3D12CommandQueue::ExecuteCommandLists( SAFE_DELETE_ARRAY(unwrapped); - if(m_State == WRITING_CAPFRAME) - { - SCOPED_SERIALISE_CONTEXT(EXECUTE_CMD_LISTS); - Serialise_ExecuteCommandLists(NumCommandLists, ppCommandLists); + bool capframe = false; + set refdIDs; - m_QueueRecord->AddChunk(scope.Get()); + for(UINT i = 0; i < NumCommandLists; i++) + { + D3D12ResourceRecord *record = GetRecord(ppCommandLists[i]); + + // TODO apply barriers from command list to current resource state tracking + + // need to lock the whole section of code, not just the check on + // m_State, as we also need to make sure we don't check the state, + // start marking dirty resources then while we're doing so the + // state becomes capframe. + // the next sections where we mark resources referenced and add + // the submit chunk to the frame record don't have to be protected. + // Only the decision of whether we're inframe or not, and marking + // dirty. + { + SCOPED_LOCK(m_pDevice->GetCapTransitionLock()); + if(m_State == WRITING_CAPFRAME) + { + for(auto it = record->bakedCommands->cmdInfo->dirtied.begin(); + it != record->bakedCommands->cmdInfo->dirtied.end(); ++it) + GetResourceManager()->MarkPendingDirty(*it); + + capframe = true; + } + else + { + for(auto it = record->bakedCommands->cmdInfo->dirtied.begin(); + it != record->bakedCommands->cmdInfo->dirtied.end(); ++it) + GetResourceManager()->MarkDirtyResource(*it); + } + } + + if(capframe) + { + // pull in frame refs from this baked command buffer + record->bakedCommands->AddResourceReferences(GetResourceManager()); + record->bakedCommands->AddReferencedIDs(refdIDs); + + // ref the parent command buffer by itself, this will pull in the cmd buffer pool + GetResourceManager()->MarkResourceFrameReferenced(record->GetResourceID(), eFrameRef_Read); + + // reference all executed bundles as well + for(size_t b = 0; b < record->bakedCommands->cmdInfo->bundles.size(); b++) + { + record->bakedCommands->cmdInfo->bundles[b]->bakedCommands->AddResourceReferences( + GetResourceManager()); + record->bakedCommands->cmdInfo->bundles[b]->bakedCommands->AddReferencedIDs(refdIDs); + GetResourceManager()->MarkResourceFrameReferenced( + record->bakedCommands->cmdInfo->bundles[b]->GetResourceID(), eFrameRef_Read); + + record->bakedCommands->cmdInfo->bundles[b]->bakedCommands->AddRef(); + } + + { + m_CmdListRecords.push_back(record->bakedCommands); + for(size_t sub = 0; sub < record->bakedCommands->cmdInfo->bundles.size(); sub++) + m_CmdListRecords.push_back(record->bakedCommands->cmdInfo->bundles[sub]->bakedCommands); + } + + record->bakedCommands->AddRef(); + } + + record->cmdInfo->dirtied.clear(); + } + + if(capframe) + { + // flush coherent maps + for(UINT i = 0; i < NumCommandLists; i++) + { + SCOPED_SERIALISE_CONTEXT(EXECUTE_CMD_LISTS); + Serialise_ExecuteCommandLists(1, ppCommandLists + i); + + m_QueueRecord->AddChunk(scope.Get()); + } } } diff --git a/renderdoc/driver/d3d12/d3d12_commands.cpp b/renderdoc/driver/d3d12/d3d12_commands.cpp index f50b2ff19..5e424e50f 100644 --- a/renderdoc/driver/d3d12/d3d12_commands.cpp +++ b/renderdoc/driver/d3d12/d3d12_commands.cpp @@ -64,6 +64,24 @@ ResourceId GetResID(ID3D12CommandList *obj) return ((WrappedID3D12GraphicsCommandList *)obj)->GetResourceID(); } +template <> +D3D12ResourceRecord *GetRecord(ID3D12GraphicsCommandList *obj) +{ + if(obj == NULL) + return NULL; + + return ((WrappedID3D12GraphicsCommandList *)obj)->GetResourceRecord(); +} + +template <> +D3D12ResourceRecord *GetRecord(ID3D12CommandList *obj) +{ + if(obj == NULL) + return NULL; + + return ((WrappedID3D12GraphicsCommandList *)obj)->GetResourceRecord(); +} + template <> ID3D12CommandQueue *Unwrap(ID3D12CommandQueue *obj) { @@ -88,7 +106,7 @@ D3D12ResourceRecord *GetRecord(ID3D12CommandQueue *obj) if(obj == NULL) return NULL; - return ((WrappedID3D12CommandQueue *)obj)->GetRecord(); + return ((WrappedID3D12CommandQueue *)obj)->GetResourceRecord(); } ULONG STDMETHODCALLTYPE DummyID3D12DebugCommandQueue::AddRef() @@ -150,7 +168,6 @@ WrappedID3D12CommandQueue::WrappedID3D12CommandQueue(ID3D12CommandQueue *real, m_QueueRecord->DataInSerialiser = false; m_QueueRecord->SpecialResource = true; m_QueueRecord->Length = 0; - m_QueueRecord->ignoreSerialise = true; } m_pDevice->SoftRef(); @@ -201,6 +218,15 @@ HRESULT STDMETHODCALLTYPE WrappedID3D12CommandQueue::QueryInterface(REFIID riid, return RefCounter12::QueryInterface(riid, ppvObject); } +void WrappedID3D12CommandQueue::ClearAfterCapture() +{ + // delete cmd buffers now - had to keep them alive until after serialiser flush. + for(size_t i = 0; i < m_CmdListRecords.size(); i++) + m_CmdListRecords[i]->Delete(GetResourceManager()); + + m_CmdListRecords.clear(); +} + WrappedID3D12GraphicsCommandList::WrappedID3D12GraphicsCommandList(ID3D12GraphicsCommandList *real, WrappedID3D12Device *device, Serialiser *serialiser, @@ -237,7 +263,11 @@ WrappedID3D12GraphicsCommandList::WrappedID3D12GraphicsCommandList(ID3D12Graphic m_ListRecord->DataInSerialiser = false; m_ListRecord->SpecialResource = true; m_ListRecord->Length = 0; - m_ListRecord->ignoreSerialise = true; + + m_ListRecord->cmdInfo = new CmdListRecordingInfo(); + + // this is set up in the implicit Reset() right after creation + m_ListRecord->bakedCommands = NULL; } m_pDevice->SoftRef(); diff --git a/renderdoc/driver/d3d12/d3d12_common.cpp b/renderdoc/driver/d3d12/d3d12_common.cpp index 436de2baa..f7b2897cd 100644 --- a/renderdoc/driver/d3d12/d3d12_common.cpp +++ b/renderdoc/driver/d3d12/d3d12_common.cpp @@ -28,6 +28,19 @@ #include "d3d12_manager.h" #include "d3d12_resources.h" +enum D3D12ResourceBarrierSubresource +{ + D3D12AllSubresources = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES +}; + +string ToStrHelper::Get(const D3D12ResourceBarrierSubresource &el) +{ + if(el == D3D12AllSubresources) + return "All Subresources"; + + return ToStr::Get(uint32_t(el)); +} + // we know the object will be a non-dispatchable object type #define SerialiseObject(type, name, obj) \ { \ @@ -398,7 +411,11 @@ void Serialiser::Serialise(const char *name, D3D12_RESOURCE_BARRIER &el) case D3D12_RESOURCE_BARRIER_TYPE_TRANSITION: { SerialiseObject(ID3D12Resource, "Transition.pResource", el.Transition.pResource); - Serialise("Transition.Subresource", el.Transition.Subresource); + // cast to a special enum so we print 'all subresources' nicely + RDCCOMPILE_ASSERT(sizeof(D3D12ResourceBarrierSubresource) == sizeof(UINT), + "Enum isn't uint sized"); + Serialise("Transition.Subresource", + (D3D12ResourceBarrierSubresource &)el.Transition.Subresource); Serialise("Transition.StateBefore", el.Transition.StateBefore); Serialise("Transition.StateAfter", el.Transition.StateAfter); break; diff --git a/renderdoc/driver/d3d12/d3d12_device.cpp b/renderdoc/driver/d3d12/d3d12_device.cpp index e4102bfc4..20193daa8 100644 --- a/renderdoc/driver/d3d12/d3d12_device.cpp +++ b/renderdoc/driver/d3d12/d3d12_device.cpp @@ -217,6 +217,7 @@ WrappedID3D12Device::WrappedID3D12Device(ID3D12Device *realDevice, D3D12InitPara m_DeviceRecord = NULL; m_Queue = NULL; + m_LastSwap = NULL; if(!RenderDoc::Inst().IsReplayApp()) { @@ -227,8 +228,8 @@ WrappedID3D12Device::WrappedID3D12Device(ID3D12Device *realDevice, D3D12InitPara m_FrameCaptureRecord = GetResourceManager()->AddResourceRecord(ResourceIDGen::GetNewUniqueID()); m_FrameCaptureRecord->DataInSerialiser = false; - m_FrameCaptureRecord->Length = 0; m_FrameCaptureRecord->SpecialResource = true; + m_FrameCaptureRecord->Length = 0; RenderDoc::Inst().AddDeviceFrameCapturer((ID3D12Device *)this, this); } @@ -573,7 +574,10 @@ IUnknown *WrappedID3D12Device::WrapSwapchainBuffer(WrappedIDXGISwapChain3 *swap, D3D12NOTIMP("Creating RTV for rendering to back buffer"); // m_pDevice->CreateRenderTargetView(Unwrap(pRes), &rtvDesc, rtv); - m_SwapChains[swap] = rtv; + m_SwapChains[swap].rtvs[buffer] = rtv; + + // start at -1 so that we know we've never presented before + m_SwapChains[swap].lastPresentedBuffer = -1; } if(swap) @@ -603,6 +607,20 @@ HRESULT WrappedID3D12Device::Present(WrappedIDXGISwapChain3 *swap, UINT SyncInte swap->GetDesc(&swapdesc); bool activeWindow = RenderDoc::Inst().IsActiveWindow((ID3D12Device *)this, swapdesc.OutputWindow); + m_LastSwap = swap; + + if(swapdesc.SwapEffect == DXGI_SWAP_EFFECT_DISCARD) + { + // discard always presents from 0 + m_SwapChains[swap].lastPresentedBuffer = 0; + } + else + { + // other modes use each buffer in turn + m_SwapChains[swap].lastPresentedBuffer++; + m_SwapChains[swap].lastPresentedBuffer %= swapdesc.BufferCount; + } + if(m_State == WRITING_IDLE) { m_FrameTimes.push_back(m_FrameTimer.GetMilliseconds()); @@ -765,11 +783,11 @@ bool WrappedID3D12Device::Serialise_BeginCaptureFrame(bool applyInitialState) return true; } - // TODO save initial resources + // TODO save initial resource states if(applyInitialState) { - // apply initial resources + // apply initial resource states } return true; @@ -842,7 +860,6 @@ void WrappedID3D12Device::StartFrameCapture(void *dev, void *wnd) GetResourceManager()->ClearReferencedResources(); GetResourceManager()->MarkResourceFrameReferenced(m_ResourceID, eFrameRef_Read); - GetResourceManager()->MarkResourceFrameReferenced(GetResID(m_Queue), eFrameRef_Read); // need to do all this atomically so that no other commands // will check to see if they need to markdirty or markpendingdirty @@ -876,6 +893,7 @@ bool WrappedID3D12Device::EndFrameCapture(void *dev, void *wnd) return true; WrappedIDXGISwapChain3 *swap = NULL; + SwapPresentInfo swapInfo = {}; if(wnd) { @@ -887,6 +905,7 @@ bool WrappedID3D12Device::EndFrameCapture(void *dev, void *wnd) if(swapDesc.OutputWindow == wnd) { swap = it->first; + swapInfo = it->second; break; } } @@ -900,11 +919,17 @@ bool WrappedID3D12Device::EndFrameCapture(void *dev, void *wnd) RDCLOG("Finished capture, Frame %u", m_FrameCounter); - // TODO either get the swapchain associated with this window, or the last swapchain - // to be presented. - // Get the last buffer presented on that swapchain as backbuffer ID3D12Resource *backbuffer = NULL; + if(swap == NULL) + { + swap = m_LastSwap; + swapInfo = m_SwapChains[swap]; + } + + if(swap != NULL) + backbuffer = (ID3D12Resource *)swap->GetBackbuffers()[swapInfo.lastPresentedBuffer]; + // transition back to IDLE atomically { SCOPED_LOCK(m_CapTransitionLock); @@ -912,7 +937,7 @@ bool WrappedID3D12Device::EndFrameCapture(void *dev, void *wnd) m_State = WRITING_IDLE; - // TOD wait for idle + // TODO wait for idle // TODO free coherent map capture ref-data } @@ -980,31 +1005,26 @@ bool WrappedID3D12Device::EndFrameCapture(void *dev, void *wnd) // in capframe (the transition is thread-protected) so nothing will be // pushed to the vector + map recordlist; + { + const vector &cmdListRecords = m_Queue->GetCmdLists(); + RDCDEBUG("Flushing %u command buffer records to file serialiser", - (uint32_t)m_CmdListRecords.size()); + (uint32_t)cmdListRecords.size()); - map recordlist; - - // ensure all command buffer records within the frame evne if recorded before, but - // otherwise order must be preserved (vs. queue submits and desc set updates) - for(size_t i = 0; i < m_CmdListRecords.size(); i++) + for(size_t i = 0; i < cmdListRecords.size(); i++) { - /* - SCOPED_SERIALISE_CONTEXT(BEGIN_CMD_LIST); - Serialise_BeginCmdList(m_CmdListRecords[i]->GetResourceID()); - Chunk *beginCmdList = scope.Get(); - - */ - - m_CmdListRecords[i]->Insert(recordlist); + cmdListRecords[i]->Insert(recordlist); RDCDEBUG("Adding %u chunks to file serialiser from command buffer %llu", - (uint32_t)recordlist.size(), m_CmdListRecords[i]->GetResourceID()); + (uint32_t)recordlist.size(), cmdListRecords[i]->GetResourceID()); } - GetRecord(m_Queue)->Insert(recordlist); + m_Queue->GetResourceRecord()->Insert(recordlist); + } + { m_FrameCaptureRecord->Insert(recordlist); RDCDEBUG("Flushing %u chunks to file serialiser from context record", @@ -1025,11 +1045,7 @@ bool WrappedID3D12Device::EndFrameCapture(void *dev, void *wnd) m_State = WRITING_IDLE; - // delete cmd buffers now - had to keep them alive until after serialiser flush. - for(size_t i = 0; i < m_CmdListRecords.size(); i++) - m_CmdListRecords[i]->Delete(GetResourceManager()); - - m_CmdListRecords.clear(); + m_Queue->ClearAfterCapture(); GetResourceManager()->MarkUnwrittenResources(); diff --git a/renderdoc/driver/d3d12/d3d12_device.h b/renderdoc/driver/d3d12/d3d12_device.h index 92bd13097..f9b53d818 100644 --- a/renderdoc/driver/d3d12/d3d12_device.h +++ b/renderdoc/driver/d3d12/d3d12_device.h @@ -210,12 +210,14 @@ struct DummyID3D12DebugDevice : public ID3D12DebugDevice virtual HRESULT STDMETHODCALLTYPE ReportLiveDeviceObjects(D3D12_RLDO_FLAGS Flags) { return S_OK; } }; +class WrappedID3D12CommandQueue; + class WrappedID3D12Device : public IFrameCapturer, public ID3DDevice, public ID3D12Device { private: ID3D12Device *m_pDevice; - ID3D12CommandQueue *m_Queue; + WrappedID3D12CommandQueue *m_Queue; D3D12ResourceManager *m_ResourceManager; DummyID3D12InfoQueue m_DummyInfoQueue; @@ -251,19 +253,19 @@ private: D3D12ResourceRecord *m_FrameCaptureRecord; Chunk *m_HeaderChunk; - // we record the command buffer records so we can insert them - // individually, that means even if they were recorded locklessly - // in parallel, on replay they are disjoint and it makes things - // much easier to process (we will enforce/display ordering - // by queue submit order anyway, so it's OK to lose the record - // order). - Threading::CriticalSection m_CmdListRecordsLock; - vector m_CmdListRecords; - ResourceId m_ResourceID; D3D12ResourceRecord *m_DeviceRecord; - map m_SwapChains; + struct SwapPresentInfo + { + D3D12_CPU_DESCRIPTOR_HANDLE rtvs[8]; + + int32_t lastPresentedBuffer; + }; + + map m_SwapChains; + + WrappedIDXGISwapChain3 *m_LastSwap; UINT m_DescriptorIncrements[D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES]; @@ -291,6 +293,7 @@ public: D3D12ResourceManager *GetResourceManager() { return m_ResourceManager; } 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); diff --git a/renderdoc/driver/d3d12/d3d12_device_wrap.cpp b/renderdoc/driver/d3d12/d3d12_device_wrap.cpp index 78f6a62ed..8a48ed914 100644 --- a/renderdoc/driver/d3d12/d3d12_device_wrap.cpp +++ b/renderdoc/driver/d3d12/d3d12_device_wrap.cpp @@ -85,7 +85,7 @@ HRESULT WrappedID3D12Device::CreateCommandQueue(const D3D12_COMMAND_QUEUE_DESC * if(m_Queue != NULL) RDCERR("Don't support multiple queues yet!"); - m_Queue = (ID3D12CommandQueue *)wrapped; + m_Queue = wrapped; *ppCommandQueue = (ID3D12CommandQueue *)wrapped; } @@ -219,18 +219,9 @@ HRESULT WrappedID3D12Device::CreateCommandList(UINT nodeMask, D3D12_COMMAND_LIST if(m_State >= WRITING) { - SCOPED_SERIALISE_CONTEXT(CREATE_COMMAND_LIST); - Serialise_CreateCommandList(nodeMask, type, pCommandAllocator, pInitialState, riid, - (void **)&wrapped); - - D3D12ResourceRecord *record = wrapped->GetResourceRecord(); - - // we can add these parents - if the list is reset later, it will free all of its parents - record->AddParent(GetRecord(pCommandAllocator)); - if(pInitialState) - record->AddParent(GetRecord(pInitialState)); - - record->AddChunk(scope.Get()); + // we just serialise out command allocator creation as a reset, since it's equivalent. + wrapped->SetInitParams(riid, nodeMask, type); + wrapped->Reset(pCommandAllocator, pInitialState); } *ppCommandList = (ID3D12GraphicsCommandList *)wrapped; @@ -297,6 +288,8 @@ HRESULT WrappedID3D12Device::CreateGraphicsPipelineState(const D3D12_GRAPHICS_PI record->Length = 0; wrapped->SetResourceRecord(record); + record->AddParent(GetRecord(pDesc->pRootSignature)); + record->AddChunk(scope.Get()); } @@ -361,6 +354,8 @@ HRESULT WrappedID3D12Device::CreateComputePipelineState(const D3D12_COMPUTE_PIPE record->Length = 0; wrapped->SetResourceRecord(record); + record->AddParent(GetRecord(pDesc->pRootSignature)); + record->AddChunk(scope.Get()); } diff --git a/renderdoc/driver/d3d12/d3d12_manager.cpp b/renderdoc/driver/d3d12/d3d12_manager.cpp index 7ed0f5148..2f5b76a13 100644 --- a/renderdoc/driver/d3d12/d3d12_manager.cpp +++ b/renderdoc/driver/d3d12/d3d12_manager.cpp @@ -129,16 +129,16 @@ D3D12_CPU_DESCRIPTOR_HANDLE FromPortableHandle(D3D12ResourceManager *manager, Po string ToStrHelper::Get(const PortableHandle &el) { - return StringFormat::Fmt("D3D12_CPU_DESCRIPTOR_HANDLE %s[%u]", ToStr::Get(el.heap).c_str(), + if(el.heap == ResourceId()) + return "NULL"; + + return StringFormat::Fmt("D3D12_CPU_DESCRIPTOR_HANDLE(%s, %u)", ToStr::Get(el.heap).c_str(), el.index); } bool D3D12ResourceManager::SerialisableResource(ResourceId id, D3D12ResourceRecord *record) { - if(id == m_Device->GetResourceID()) - return true; - - if(record->ignoreSerialise) + if(record->SpecialResource) return false; return true; diff --git a/renderdoc/driver/d3d12/d3d12_manager.h b/renderdoc/driver/d3d12/d3d12_manager.h index b6d2efcd8..6e1162671 100644 --- a/renderdoc/driver/d3d12/d3d12_manager.h +++ b/renderdoc/driver/d3d12/d3d12_manager.h @@ -197,6 +197,19 @@ class D3D12ResourceManager; PortableHandle ToPortableHandle(D3D12_CPU_DESCRIPTOR_HANDLE handle); D3D12_CPU_DESCRIPTOR_HANDLE FromPortableHandle(D3D12ResourceManager *manager, PortableHandle handle); +struct D3D12ResourceRecord; + +struct CmdListRecordingInfo +{ + vector barriers; + + // a list of all resources dirtied by this command buffer + set dirtied; + + // bundles executed + vector bundles; +}; + struct D3D12ResourceRecord : public ResourceRecord { enum @@ -204,8 +217,19 @@ struct D3D12ResourceRecord : public ResourceRecord NullResource = NULL }; - D3D12ResourceRecord(ResourceId id) : ResourceRecord(id, true) { ignoreSerialise = false; } + D3D12ResourceRecord(ResourceId id) : ResourceRecord(id, true), cmdInfo(NULL), bakedCommands(NULL) + { + } ~D3D12ResourceRecord() {} + void Bake() + { + RDCASSERT(cmdInfo); + SwapChunks(bakedCommands); + cmdInfo->barriers.swap(bakedCommands->cmdInfo->barriers); + cmdInfo->dirtied.swap(bakedCommands->cmdInfo->dirtied); + cmdInfo->bundles.swap(bakedCommands->cmdInfo->bundles); + } + void Insert(map &recordlist) { bool dataWritten = DataWritten; @@ -224,7 +248,8 @@ struct D3D12ResourceRecord : public ResourceRecord recordlist.insert(m_Chunks.begin(), m_Chunks.end()); } - bool ignoreSerialise; + D3D12ResourceRecord *bakedCommands; + CmdListRecordingInfo *cmdInfo; }; class D3D12ResourceManager