From a0983b64a4b5e1707c44e696ea04ccd5f54867d4 Mon Sep 17 00:00:00 2001 From: baldurk Date: Wed, 6 Jul 2016 15:38:26 +0300 Subject: [PATCH] Serialise the command list/queue functions HelloWorldD3D12 uses --- renderdoc/driver/d3d12/d3d12_command_list.h | 20 +- .../driver/d3d12/d3d12_command_list_wrap.cpp | 395 ++++++++++++++++++ renderdoc/driver/d3d12/d3d12_command_queue.h | 13 +- .../driver/d3d12/d3d12_command_queue_wrap.cpp | 56 +++ renderdoc/driver/d3d12/d3d12_commands.cpp | 26 +- renderdoc/driver/d3d12/d3d12_common.cpp | 122 ++++++ renderdoc/driver/d3d12/d3d12_common.h | 82 ++-- renderdoc/driver/d3d12/d3d12_device_wrap.cpp | 4 +- renderdoc/driver/d3d12/d3d12_manager.h | 6 + 9 files changed, 679 insertions(+), 45 deletions(-) diff --git a/renderdoc/driver/d3d12/d3d12_command_list.h b/renderdoc/driver/d3d12/d3d12_command_list.h index ae26e45d6..47978fa8f 100644 --- a/renderdoc/driver/d3d12/d3d12_command_list.h +++ b/renderdoc/driver/d3d12/d3d12_command_list.h @@ -83,7 +83,6 @@ struct DummyID3D12DebugCommandList : public ID3D12DebugCommandList class WrappedID3D12GraphicsCommandList : public RefCounter12, public ID3D12GraphicsCommandList { - ID3D12GraphicsCommandList *m_pList; WrappedID3D12Device *m_pDevice; ResourceId m_ResourceID; @@ -94,6 +93,8 @@ class WrappedID3D12GraphicsCommandList : public RefCounter12GetChunkName(idx); } + D3D12ResourceManager *GetResourceManager() { return m_pDevice->GetResourceManager(); } public: ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D12GraphicsCommandList); @@ -103,7 +104,7 @@ public: Serialiser *GetSerialiser() { return m_pSerialiser; } ResourceId GetResourceID() { return m_ResourceID; } - ID3D12GraphicsCommandList *GetReal() { return m_pList; } + ID3D12GraphicsCommandList *GetReal() { return m_pReal; } WrappedID3D12Device *GetWrappedDevice() { return m_pDevice; } ////////////////////////////// // implement IUnknown @@ -117,7 +118,7 @@ public: HRESULT STDMETHODCALLTYPE GetPrivateData(REFGUID guid, UINT *pDataSize, void *pData) { - return m_pList->GetPrivateData(guid, pDataSize, pData); + return m_pReal->GetPrivateData(guid, pDataSize, pData); } HRESULT STDMETHODCALLTYPE SetPrivateData(REFGUID guid, UINT DataSize, const void *pData) @@ -125,12 +126,12 @@ public: if(guid == WKPDID_D3DDebugObjectName) m_pDevice->SetResourceName(this, (const char *)pData); - return m_pList->SetPrivateData(guid, DataSize, pData); + return m_pReal->SetPrivateData(guid, DataSize, pData); } HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(REFGUID guid, const IUnknown *pData) { - return m_pList->SetPrivateDataInterface(guid, pData); + return m_pReal->SetPrivateDataInterface(guid, pData); } HRESULT STDMETHODCALLTYPE SetName(LPCWSTR Name) @@ -138,7 +139,7 @@ public: string utf8 = StringFormat::Wide2UTF8(Name); m_pDevice->SetResourceName(this, utf8.c_str()); - return m_pList->SetName(Name); + return m_pReal->SetName(Name); } ////////////////////////////// @@ -162,7 +163,7 @@ public: ////////////////////////////// // implement ID3D12CommandList - virtual D3D12_COMMAND_LIST_TYPE STDMETHODCALLTYPE GetType() { return m_pList->GetType(); } + virtual D3D12_COMMAND_LIST_TYPE STDMETHODCALLTYPE GetType() { return m_pReal->GetType(); } ////////////////////////////// // implement ID3D12GraphicsCommandList @@ -394,3 +395,8 @@ template <> ID3D12GraphicsCommandList *Unwrap(ID3D12GraphicsCommandList *obj); template <> ID3D12CommandList *Unwrap(ID3D12CommandList *obj); + +template <> +ResourceId GetResID(ID3D12GraphicsCommandList *obj); +template <> +ResourceId GetResID(ID3D12CommandList *obj); diff --git a/renderdoc/driver/d3d12/d3d12_command_list_wrap.cpp b/renderdoc/driver/d3d12/d3d12_command_list_wrap.cpp index eaabc5ae3..e113c1a39 100644 --- a/renderdoc/driver/d3d12/d3d12_command_list_wrap.cpp +++ b/renderdoc/driver/d3d12/d3d12_command_list_wrap.cpp @@ -24,14 +24,61 @@ #include "d3d12_command_list.h" +bool WrappedID3D12GraphicsCommandList::Serialise_Close() +{ + if(m_State <= READING) + m_pReal->Close(); + + return true; +} + HRESULT WrappedID3D12GraphicsCommandList::Close() { + if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(CLOSE_LIST); + Serialise_Close(); + + m_ListRecord->AddChunk(scope.Get()); + } + + // bake m_ListRecord to somewhere else + return m_pReal->Close(); } +bool WrappedID3D12GraphicsCommandList::Serialise_Reset(ID3D12CommandAllocator *pAllocator, + ID3D12PipelineState *pInitialState) +{ + SERIALISE_ELEMENT(ResourceId, Allocator, GetResID(pAllocator)); + SERIALISE_ELEMENT(ResourceId, State, GetResID(pInitialState)); + + if(m_State <= READING) + { + pAllocator = GetResourceManager()->GetLiveAs(Allocator); + pInitialState = + State == ResourceId() ? NULL : GetResourceManager()->GetLiveAs(State); + + m_pReal->Reset(Unwrap(pAllocator), Unwrap(pInitialState)); + } + + return true; +} + HRESULT WrappedID3D12GraphicsCommandList::Reset(ID3D12CommandAllocator *pAllocator, ID3D12PipelineState *pInitialState) { + if(m_State >= WRITING) + { + // reset for new recording + m_ListRecord->DeleteChunks(); + + SCOPED_SERIALISE_CONTEXT(RESET_LIST); + Serialise_Reset(pAllocator, pInitialState); + + m_ListRecord->AddChunk(scope.Get()); + } + return m_pReal->Reset(Unwrap(pAllocator), Unwrap(pInitialState)); } @@ -48,6 +95,49 @@ void WrappedID3D12GraphicsCommandList::DrawInstanced(UINT VertexCountPerInstance StartInstanceLocation); } +bool WrappedID3D12GraphicsCommandList::Serialise_DrawIndexedInstanced(UINT IndexCountPerInstance, + UINT InstanceCount, + UINT StartIndexLocation, + INT BaseVertexLocation, + UINT StartInstanceLocation) +{ + SERIALISE_ELEMENT(UINT, idxCount, IndexCountPerInstance); + SERIALISE_ELEMENT(UINT, instCount, InstanceCount); + SERIALISE_ELEMENT(UINT, startIdx, StartIndexLocation); + SERIALISE_ELEMENT(INT, startVtx, BaseVertexLocation); + SERIALISE_ELEMENT(UINT, startInst, StartInstanceLocation); + + if(m_State <= READING) + { + m_pReal->DrawIndexedInstanced(idxCount, instCount, startIdx, startVtx, startInst); + } + + const string desc = m_pSerialiser->GetDebugStr(); + + // TODO - Serialise_DebugMessages(); + + if(m_State == READING) + { + // TODO - AddEvent(DRAW_INDEXED_INST, desc); + string name = + "DrawIndexedInstanced(" + ToStr::Get(idxCount) + ", " + ToStr::Get(instCount) + ")"; + + FetchDrawcall draw; + draw.name = name; + draw.numIndices = idxCount; + draw.numInstances = instCount; + draw.indexOffset = startIdx; + draw.baseVertex = startVtx; + draw.instanceOffset = startInst; + + draw.flags |= eDraw_Drawcall | eDraw_Instanced | eDraw_UseIBuffer; + + // TODO - AddDrawcall(draw, true); + } + + return true; +} + void WrappedID3D12GraphicsCommandList::DrawIndexedInstanced(UINT IndexCountPerInstance, UINT InstanceCount, UINT StartIndexLocation, @@ -56,6 +146,15 @@ void WrappedID3D12GraphicsCommandList::DrawIndexedInstanced(UINT IndexCountPerIn { m_pReal->DrawIndexedInstanced(IndexCountPerInstance, InstanceCount, StartIndexLocation, BaseVertexLocation, StartInstanceLocation); + + if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(DRAW_INDEXED_INST); + Serialise_DrawIndexedInstanced(IndexCountPerInstance, InstanceCount, StartIndexLocation, + BaseVertexLocation, StartInstanceLocation); + + m_ListRecord->AddChunk(scope.Get()); + } } void WrappedID3D12GraphicsCommandList::Dispatch(UINT ThreadGroupCountX, UINT ThreadGroupCountY, @@ -64,11 +163,42 @@ void WrappedID3D12GraphicsCommandList::Dispatch(UINT ThreadGroupCountX, UINT Thr m_pReal->Dispatch(ThreadGroupCountX, ThreadGroupCountY, ThreadGroupCountZ); } +bool WrappedID3D12GraphicsCommandList::Serialise_CopyBufferRegion(ID3D12Resource *pDstBuffer, + UINT64 DstOffset, + ID3D12Resource *pSrcBuffer, + UINT64 SrcOffset, UINT64 NumBytes) +{ + SERIALISE_ELEMENT(ResourceId, dst, GetResID(pDstBuffer)); + SERIALISE_ELEMENT(UINT64, dstoffs, DstOffset); + SERIALISE_ELEMENT(ResourceId, src, GetResID(pSrcBuffer)); + SERIALISE_ELEMENT(UINT64, srcoffs, SrcOffset); + SERIALISE_ELEMENT(UINT64, num, NumBytes); + + if(m_State <= READING && GetResourceManager()->HasLiveResource(dst) && + GetResourceManager()->HasLiveResource(src)) + { + pDstBuffer = GetResourceManager()->GetLiveAs(dst); + pSrcBuffer = GetResourceManager()->GetLiveAs(src); + + m_pReal->CopyBufferRegion(Unwrap(pDstBuffer), dstoffs, Unwrap(pSrcBuffer), srcoffs, num); + } + + return true; +} + void WrappedID3D12GraphicsCommandList::CopyBufferRegion(ID3D12Resource *pDstBuffer, UINT64 DstOffset, ID3D12Resource *pSrcBuffer, UINT64 SrcOffset, UINT64 NumBytes) { m_pReal->CopyBufferRegion(pDstBuffer, DstOffset, pSrcBuffer, SrcOffset, NumBytes); + + if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(COPY_BUFFER); + Serialise_CopyBufferRegion(pDstBuffer, DstOffset, pSrcBuffer, SrcOffset, NumBytes); + + m_ListRecord->AddChunk(scope.Get()); + } } void WrappedID3D12GraphicsCommandList::CopyTextureRegion(const D3D12_TEXTURE_COPY_LOCATION *pDst, @@ -102,20 +232,89 @@ void WrappedID3D12GraphicsCommandList::ResolveSubresource(ID3D12Resource *pDstRe m_pReal->ResolveSubresource(pDstResource, DstSubresource, pSrcResource, SrcSubresource, Format); } +bool WrappedID3D12GraphicsCommandList::Serialise_IASetPrimitiveTopology( + D3D12_PRIMITIVE_TOPOLOGY PrimitiveTopology) +{ + SERIALISE_ELEMENT(D3D12_PRIMITIVE_TOPOLOGY, topo, PrimitiveTopology); + + if(m_State <= READING) + { + m_pReal->IASetPrimitiveTopology(topo); + } + + return true; +} + void WrappedID3D12GraphicsCommandList::IASetPrimitiveTopology(D3D12_PRIMITIVE_TOPOLOGY PrimitiveTopology) { m_pReal->IASetPrimitiveTopology(PrimitiveTopology); + + if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(SET_TOPOLOGY); + Serialise_IASetPrimitiveTopology(PrimitiveTopology); + + m_ListRecord->AddChunk(scope.Get()); + } +} + +bool WrappedID3D12GraphicsCommandList::Serialise_RSSetViewports(UINT NumViewports, + const D3D12_VIEWPORT *pViewports) +{ + SERIALISE_ELEMENT(UINT, num, NumViewports); + SERIALISE_ELEMENT_ARR(D3D12_VIEWPORT, views, pViewports, num); + + if(m_State <= READING) + { + m_pReal->RSSetViewports(num, views); + } + + SAFE_DELETE_ARRAY(views); + + return true; } void WrappedID3D12GraphicsCommandList::RSSetViewports(UINT NumViewports, const D3D12_VIEWPORT *pViewports) { m_pReal->RSSetViewports(NumViewports, pViewports); + + if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(SET_VIEWPORTS); + Serialise_RSSetViewports(NumViewports, pViewports); + + m_ListRecord->AddChunk(scope.Get()); + } +} + +bool WrappedID3D12GraphicsCommandList::Serialise_RSSetScissorRects(UINT NumRects, + const D3D12_RECT *pRects) +{ + SERIALISE_ELEMENT(UINT, num, NumRects); + SERIALISE_ELEMENT_ARR(D3D12_RECT, rects, pRects, num); + + if(m_State <= READING) + { + m_pReal->RSSetScissorRects(num, rects); + } + + SAFE_DELETE_ARRAY(rects); + + return true; } void WrappedID3D12GraphicsCommandList::RSSetScissorRects(UINT NumRects, const D3D12_RECT *pRects) { m_pReal->RSSetScissorRects(NumRects, pRects); + + if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(SET_SCISSORS); + Serialise_RSSetScissorRects(NumRects, pRects); + + m_ListRecord->AddChunk(scope.Get()); + } } void WrappedID3D12GraphicsCommandList::OMSetBlendFactor(const FLOAT BlendFactor[4]) @@ -128,9 +327,44 @@ void WrappedID3D12GraphicsCommandList::OMSetStencilRef(UINT StencilRef) m_pReal->OMSetStencilRef(StencilRef); } +bool WrappedID3D12GraphicsCommandList::Serialise_SetPipelineState(ID3D12PipelineState *pPipelineState) +{ + SERIALISE_ELEMENT(ResourceId, pipe, GetResID(pPipelineState)); + + if(m_State <= READING) + { + pPipelineState = GetResourceManager()->GetLiveAs(pipe); + m_pReal->SetPipelineState(Unwrap(pPipelineState)); + } + + return true; +} + void WrappedID3D12GraphicsCommandList::SetPipelineState(ID3D12PipelineState *pPipelineState) { m_pReal->SetPipelineState(Unwrap(pPipelineState)); + + if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(SET_PIPE); + Serialise_SetPipelineState(pPipelineState); + + m_ListRecord->AddChunk(scope.Get()); + } +} + +bool WrappedID3D12GraphicsCommandList::Serialise_ResourceBarrier(UINT NumBarriers, + const D3D12_RESOURCE_BARRIER *pBarriers) +{ + SERIALISE_ELEMENT(UINT, num, NumBarriers); + SERIALISE_ELEMENT_ARR(D3D12_RESOURCE_BARRIER, barriers, pBarriers, num); + + if(m_State <= READING) + { + m_pReal->ResourceBarrier(num, barriers); + } + + return true; } void WrappedID3D12GraphicsCommandList::ResourceBarrier(UINT NumBarriers, @@ -151,6 +385,14 @@ void WrappedID3D12GraphicsCommandList::ResourceBarrier(UINT NumBarriers, m_pReal->ResourceBarrier(NumBarriers, barriers); SAFE_DELETE_ARRAY(barriers); + + if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(RESOURCE_BARRIER); + Serialise_ResourceBarrier(NumBarriers, pBarriers); + + m_ListRecord->AddChunk(scope.Get()); + } } void WrappedID3D12GraphicsCommandList::ExecuteBundle(ID3D12GraphicsCommandList *pCommandList) @@ -169,9 +411,31 @@ void WrappedID3D12GraphicsCommandList::SetComputeRootSignature(ID3D12RootSignatu m_pReal->SetComputeRootSignature(pRootSignature); } +bool WrappedID3D12GraphicsCommandList::Serialise_SetGraphicsRootSignature( + ID3D12RootSignature *pRootSignature) +{ + SERIALISE_ELEMENT(ResourceId, sig, GetResID(pRootSignature)); + + if(m_State <= READING) + { + pRootSignature = GetResourceManager()->GetLiveAs(sig); + m_pReal->SetGraphicsRootSignature(Unwrap(pRootSignature)); + } + + return true; +} + void WrappedID3D12GraphicsCommandList::SetGraphicsRootSignature(ID3D12RootSignature *pRootSignature) { m_pReal->SetGraphicsRootSignature(pRootSignature); + + if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(SET_ROOT_SIG); + Serialise_SetGraphicsRootSignature(pRootSignature); + + m_ListRecord->AddChunk(scope.Get()); + } } void WrappedID3D12GraphicsCommandList::SetComputeRootDescriptorTable( @@ -224,10 +488,32 @@ void WrappedID3D12GraphicsCommandList::SetComputeRootConstantBufferView( m_pReal->SetComputeRootConstantBufferView(RootParameterIndex, BufferLocation); } +bool WrappedID3D12GraphicsCommandList::Serialise_SetGraphicsRootConstantBufferView( + UINT RootParameterIndex, D3D12_GPU_VIRTUAL_ADDRESS BufferLocation) +{ + SERIALISE_ELEMENT(UINT, idx, RootParameterIndex); + // TODO wrap and serialise buffer location as heap ID + idx + + if(m_State <= READING) + { + m_pReal->SetGraphicsRootConstantBufferView(idx, BufferLocation); + } + + return true; +} + void WrappedID3D12GraphicsCommandList::SetGraphicsRootConstantBufferView( UINT RootParameterIndex, D3D12_GPU_VIRTUAL_ADDRESS BufferLocation) { m_pReal->SetGraphicsRootConstantBufferView(RootParameterIndex, BufferLocation); + + if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(SET_GFX_ROOT_CBV); + Serialise_SetGraphicsRootConstantBufferView(RootParameterIndex, BufferLocation); + + m_ListRecord->AddChunk(scope.Get()); + } } void WrappedID3D12GraphicsCommandList::SetComputeRootShaderResourceView( @@ -254,15 +540,64 @@ void WrappedID3D12GraphicsCommandList::SetGraphicsRootUnorderedAccessView( m_pReal->SetGraphicsRootUnorderedAccessView(RootParameterIndex, BufferLocation); } +bool WrappedID3D12GraphicsCommandList::Serialise_IASetIndexBuffer(const D3D12_INDEX_BUFFER_VIEW *pView) +{ + SERIALISE_ELEMENT(bool, HasView, pView != NULL); + SERIALISE_ELEMENT_OPT(D3D12_INDEX_BUFFER_VIEW, view, *pView, HasView); + + if(m_State <= READING) + { + if(HasView) + m_pReal->IASetIndexBuffer(&view); + else + m_pReal->IASetIndexBuffer(NULL); + } + + return true; +} + void WrappedID3D12GraphicsCommandList::IASetIndexBuffer(const D3D12_INDEX_BUFFER_VIEW *pView) { m_pReal->IASetIndexBuffer(pView); + + if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(SET_IBUFFER); + Serialise_IASetIndexBuffer(pView); + + m_ListRecord->AddChunk(scope.Get()); + } +} + +bool WrappedID3D12GraphicsCommandList::Serialise_IASetVertexBuffers( + UINT StartSlot, UINT NumViews, const D3D12_VERTEX_BUFFER_VIEW *pViews) +{ + SERIALISE_ELEMENT(UINT, start, StartSlot); + SERIALISE_ELEMENT(UINT, num, NumViews); + SERIALISE_ELEMENT_ARR(D3D12_VERTEX_BUFFER_VIEW, views, pViews, num); + + if(m_State <= READING) + { + m_pReal->IASetVertexBuffers(start, num, views); + } + + SAFE_DELETE_ARRAY(views); + + return true; } void WrappedID3D12GraphicsCommandList::IASetVertexBuffers(UINT StartSlot, UINT NumViews, const D3D12_VERTEX_BUFFER_VIEW *pViews) { m_pReal->IASetVertexBuffers(StartSlot, NumViews, pViews); + + if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(SET_VBUFFERS); + Serialise_IASetVertexBuffers(StartSlot, NumViews, pViews); + + m_ListRecord->AddChunk(scope.Get()); + } } void WrappedID3D12GraphicsCommandList::SOSetTargets(UINT StartSlot, UINT NumViews, @@ -271,12 +606,38 @@ void WrappedID3D12GraphicsCommandList::SOSetTargets(UINT StartSlot, UINT NumView m_pReal->SOSetTargets(StartSlot, NumViews, pViews); } +bool WrappedID3D12GraphicsCommandList::Serialise_OMSetRenderTargets( + UINT NumRenderTargetDescriptors, const D3D12_CPU_DESCRIPTOR_HANDLE *pRenderTargetDescriptors, + BOOL RTsSingleHandleToDescriptorRange, const D3D12_CPU_DESCRIPTOR_HANDLE *pDepthStencilDescriptor) +{ + SERIALISE_ELEMENT(UINT, num, NumRenderTargetDescriptors); + SERIALISE_ELEMENT(bool, singlehandle, RTsSingleHandleToDescriptorRange != FALSE); + + // TODO unwrap and serialise handles as heaps + idxs + + if(m_State <= READING) + { + m_pReal->OMSetRenderTargets(num, NULL, singlehandle ? TRUE : FALSE, NULL); + } + + return true; +} + void WrappedID3D12GraphicsCommandList::OMSetRenderTargets( UINT NumRenderTargetDescriptors, const D3D12_CPU_DESCRIPTOR_HANDLE *pRenderTargetDescriptors, BOOL RTsSingleHandleToDescriptorRange, const D3D12_CPU_DESCRIPTOR_HANDLE *pDepthStencilDescriptor) { m_pReal->OMSetRenderTargets(NumRenderTargetDescriptors, pRenderTargetDescriptors, RTsSingleHandleToDescriptorRange, pDepthStencilDescriptor); + + if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(SET_RTVS); + Serialise_OMSetRenderTargets(NumRenderTargetDescriptors, pRenderTargetDescriptors, + RTsSingleHandleToDescriptorRange, pDepthStencilDescriptor); + + m_ListRecord->AddChunk(scope.Get()); + } } void WrappedID3D12GraphicsCommandList::ClearDepthStencilView( @@ -286,11 +647,45 @@ void WrappedID3D12GraphicsCommandList::ClearDepthStencilView( m_pReal->ClearDepthStencilView(DepthStencilView, ClearFlags, Depth, Stencil, NumRects, pRects); } +bool WrappedID3D12GraphicsCommandList::Serialise_ClearRenderTargetView( + D3D12_CPU_DESCRIPTOR_HANDLE RenderTargetView, const FLOAT ColorRGBA[4], UINT NumRects, + const D3D12_RECT *pRects) +{ + // TODO unwrap and serialise handle as heap + idx + + float Color[4] = {0}; + + if(m_State >= WRITING) + memcpy(Color, ColorRGBA, sizeof(float) * 4); + + m_pSerialiser->SerialisePODArray<4>("ColorRGBA", Color); + + SERIALISE_ELEMENT(UINT, num, NumRects); + SERIALISE_ELEMENT_ARR(D3D12_RECT, rects, pRects, num); + + if(m_State <= READING) + { + m_pReal->ClearRenderTargetView(RenderTargetView, Color, num, rects); + } + + SAFE_DELETE_ARRAY(rects); + + return true; +} + void WrappedID3D12GraphicsCommandList::ClearRenderTargetView( D3D12_CPU_DESCRIPTOR_HANDLE RenderTargetView, const FLOAT ColorRGBA[4], UINT NumRects, const D3D12_RECT *pRects) { m_pReal->ClearRenderTargetView(RenderTargetView, ColorRGBA, NumRects, pRects); + + if(m_State >= WRITING) + { + SCOPED_SERIALISE_CONTEXT(CLEAR_RTV); + Serialise_ClearRenderTargetView(RenderTargetView, ColorRGBA, NumRects, pRects); + + m_ListRecord->AddChunk(scope.Get()); + } } void WrappedID3D12GraphicsCommandList::ClearUnorderedAccessViewUint( diff --git a/renderdoc/driver/d3d12/d3d12_command_queue.h b/renderdoc/driver/d3d12/d3d12_command_queue.h index d47149cc2..58ad15dc4 100644 --- a/renderdoc/driver/d3d12/d3d12_command_queue.h +++ b/renderdoc/driver/d3d12/d3d12_command_queue.h @@ -70,7 +70,6 @@ class WrappedID3D12CommandQueue : public ID3D12CommandQueue, public RefCounter12, public ID3DDevice { - ID3D12CommandQueue *m_pQueue; WrappedID3D12Device *m_pDevice; ResourceId m_ResourceID; @@ -81,6 +80,8 @@ class WrappedID3D12CommandQueue : public ID3D12CommandQueue, DummyID3D12DebugCommandQueue m_DummyDebug; + const char *GetChunkName(uint32_t idx) { return m_pDevice->GetChunkName(idx); } + D3D12ResourceManager *GetResourceManager() { return m_pDevice->GetResourceManager(); } public: ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D12CommandQueue); @@ -90,7 +91,7 @@ public: Serialiser *GetSerialiser() { return m_pSerialiser; } ResourceId GetResourceID() { return m_ResourceID; } - ID3D12CommandQueue *GetReal() { return m_pQueue; } + ID3D12CommandQueue *GetReal() { return m_pReal; } WrappedID3D12Device *GetWrappedDevice() { return m_pDevice; } // interface for DXGI virtual IUnknown *GetRealIUnknown() { return GetReal(); } @@ -135,7 +136,7 @@ public: HRESULT STDMETHODCALLTYPE GetPrivateData(REFGUID guid, UINT *pDataSize, void *pData) { - return m_pQueue->GetPrivateData(guid, pDataSize, pData); + return m_pReal->GetPrivateData(guid, pDataSize, pData); } HRESULT STDMETHODCALLTYPE SetPrivateData(REFGUID guid, UINT DataSize, const void *pData) @@ -143,12 +144,12 @@ public: if(guid == WKPDID_D3DDebugObjectName) m_pDevice->SetResourceName(this, (const char *)pData); - return m_pQueue->SetPrivateData(guid, DataSize, pData); + return m_pReal->SetPrivateData(guid, DataSize, pData); } HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(REFGUID guid, const IUnknown *pData) { - return m_pQueue->SetPrivateDataInterface(guid, pData); + return m_pReal->SetPrivateDataInterface(guid, pData); } HRESULT STDMETHODCALLTYPE SetName(LPCWSTR Name) @@ -156,7 +157,7 @@ public: string utf8 = StringFormat::Wide2UTF8(Name); m_pDevice->SetResourceName(this, utf8.c_str()); - return m_pQueue->SetName(Name); + return m_pReal->SetName(Name); } ////////////////////////////// diff --git a/renderdoc/driver/d3d12/d3d12_command_queue_wrap.cpp b/renderdoc/driver/d3d12/d3d12_command_queue_wrap.cpp index 49e008799..b0e617dcc 100644 --- a/renderdoc/driver/d3d12/d3d12_command_queue_wrap.cpp +++ b/renderdoc/driver/d3d12/d3d12_command_queue_wrap.cpp @@ -47,6 +47,31 @@ void STDMETHODCALLTYPE WrappedID3D12CommandQueue::CopyTileMappings( pSrcRegionStartCoordinate, pRegionSize, Flags); } +bool WrappedID3D12CommandQueue::Serialise_ExecuteCommandLists(UINT NumCommandLists, + ID3D12CommandList *const *ppCommandLists) +{ + SERIALISE_ELEMENT(UINT, num, NumCommandLists); + + std::vector ids; + ids.reserve(num); + for(UINT i = 0; i < num; i++) + ids.push_back(GetResID(ppCommandLists[i])); + + m_pSerialiser->Serialise("ppCommandLists", ids); + + if(m_State <= EXECUTING) + { + 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]); + } + + return true; +} + void STDMETHODCALLTYPE WrappedID3D12CommandQueue::ExecuteCommandLists( UINT NumCommandLists, ID3D12CommandList *const *ppCommandLists) { @@ -57,6 +82,14 @@ void STDMETHODCALLTYPE WrappedID3D12CommandQueue::ExecuteCommandLists( m_pReal->ExecuteCommandLists(NumCommandLists, unwrapped); SAFE_DELETE_ARRAY(unwrapped); + + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(EXECUTE_CMD_LISTS); + Serialise_ExecuteCommandLists(NumCommandLists, ppCommandLists); + + m_QueueRecord->AddChunk(scope.Get()); + } } void STDMETHODCALLTYPE WrappedID3D12CommandQueue::SetMarker(UINT Metadata, const void *pData, @@ -76,8 +109,31 @@ void STDMETHODCALLTYPE WrappedID3D12CommandQueue::EndEvent() m_pReal->EndEvent(); } +bool WrappedID3D12CommandQueue::Serialise_Signal(ID3D12Fence *pFence, UINT64 Value) +{ + SERIALISE_ELEMENT(ResourceId, Fence, GetResID(pFence)); + SERIALISE_ELEMENT(UINT64, val, Value); + + if(m_State <= EXECUTING) + { + pFence = GetResourceManager()->GetLiveAs(Fence); + + m_pReal->Signal(Unwrap(pFence), val); + } + + return true; +} + HRESULT STDMETHODCALLTYPE WrappedID3D12CommandQueue::Signal(ID3D12Fence *pFence, UINT64 Value) { + if(m_State == WRITING_CAPFRAME) + { + SCOPED_SERIALISE_CONTEXT(SIGNAL); + Serialise_Signal(pFence, Value); + + m_QueueRecord->AddChunk(scope.Get()); + } + return m_pReal->Signal(pFence, Value); } diff --git a/renderdoc/driver/d3d12/d3d12_commands.cpp b/renderdoc/driver/d3d12/d3d12_commands.cpp index 0763edc35..22c1950a0 100644 --- a/renderdoc/driver/d3d12/d3d12_commands.cpp +++ b/renderdoc/driver/d3d12/d3d12_commands.cpp @@ -46,6 +46,24 @@ ID3D12CommandList *Unwrap(ID3D12CommandList *obj) return ((WrappedID3D12GraphicsCommandList *)obj)->GetReal(); } +template <> +ResourceId GetResID(ID3D12GraphicsCommandList *obj) +{ + if(obj == NULL) + return ResourceId(); + + return ((WrappedID3D12GraphicsCommandList *)obj)->GetResourceID(); +} + +template <> +ResourceId GetResID(ID3D12CommandList *obj) +{ + if(obj == NULL) + return ResourceId(); + + return ((WrappedID3D12GraphicsCommandList *)obj)->GetResourceID(); +} + template <> ID3D12CommandQueue *Unwrap(ID3D12CommandQueue *obj) { @@ -82,13 +100,13 @@ ULONG STDMETHODCALLTYPE DummyID3D12DebugCommandList::Release() WrappedID3D12CommandQueue::WrappedID3D12CommandQueue(ID3D12CommandQueue *real, WrappedID3D12Device *device, Serialiser *serialiser) - : RefCounter12(real), m_pDevice(device), m_pQueue(real) + : RefCounter12(real), m_pDevice(device) { if(RenderDoc::Inst().GetCrashHandler()) RenderDoc::Inst().GetCrashHandler()->RegisterMemoryRegion(this, sizeof(WrappedID3D12CommandQueue)); - m_pQueue->QueryInterface(__uuidof(ID3D12DebugCommandQueue), (void **)&m_DummyDebug.m_pReal); + m_pReal->QueryInterface(__uuidof(ID3D12DebugCommandQueue), (void **)&m_DummyDebug.m_pReal); if(RenderDoc::Inst().IsReplayApp()) { @@ -172,13 +190,13 @@ HRESULT STDMETHODCALLTYPE WrappedID3D12CommandQueue::QueryInterface(REFIID riid, WrappedID3D12GraphicsCommandList::WrappedID3D12GraphicsCommandList(ID3D12GraphicsCommandList *real, WrappedID3D12Device *device, Serialiser *serialiser) - : RefCounter12(real), m_pDevice(device), m_pList(real) + : RefCounter12(real), m_pDevice(device) { if(RenderDoc::Inst().GetCrashHandler()) RenderDoc::Inst().GetCrashHandler()->RegisterMemoryRegion( this, sizeof(WrappedID3D12GraphicsCommandList)); - m_pList->QueryInterface(__uuidof(ID3D12DebugCommandList), (void **)&m_DummyDebug.m_pReal); + m_pReal->QueryInterface(__uuidof(ID3D12DebugCommandList), (void **)&m_DummyDebug.m_pReal); if(RenderDoc::Inst().IsReplayApp()) { diff --git a/renderdoc/driver/d3d12/d3d12_common.cpp b/renderdoc/driver/d3d12/d3d12_common.cpp index 53d2c3edc..c7028b2f0 100644 --- a/renderdoc/driver/d3d12/d3d12_common.cpp +++ b/renderdoc/driver/d3d12/d3d12_common.cpp @@ -330,6 +330,69 @@ void Serialiser::Serialise(const char *name, D3D12_COMPUTE_PIPELINE_STATE_DESC & } } +template <> +void Serialiser::Serialise(const char *name, D3D12_VERTEX_BUFFER_VIEW &el) +{ + ScopedContext scope(this, name, "D3D12_VERTEX_BUFFER_VIEW", 0, true); + + // TODO serialise gpu virtual address as heap ID and idx + Serialise("SizeInBytes", el.SizeInBytes); + Serialise("StrideInBytes", el.StrideInBytes); +} + +template <> +void Serialiser::Serialise(const char *name, D3D12_INDEX_BUFFER_VIEW &el) +{ + ScopedContext scope(this, name, "D3D12_INDEX_BUFFER_VIEW", 0, true); + + // TODO serialise gpu virtual address as heap ID and idx + Serialise("SizeInBytes", el.SizeInBytes); + Serialise("Format", el.Format); +} + +template <> +void Serialiser::Serialise(const char *name, D3D12_RESOURCE_BARRIER &el) +{ + ScopedContext scope(this, name, "D3D12_RESOURCE_BARRIER", 0, true); + + Serialise("Type", el.Type); + Serialise("Flags", el.Flags); + + switch(el.Type) + { + case D3D12_RESOURCE_BARRIER_TYPE_TRANSITION: + Serialise("Transition.pResource", el.Transition.pResource); + Serialise("Transition.Subresource", el.Transition.Subresource); + Serialise("Transition.StateBefore", el.Transition.StateBefore); + Serialise("Transition.StateAfter", el.Transition.StateAfter); + break; + case D3D12_RESOURCE_BARRIER_TYPE_ALIASING: + Serialise("Aliasing.pResourceBefore", el.Aliasing.pResourceBefore); + Serialise("Aliasing.pResourceAfter", el.Aliasing.pResourceAfter); + break; + case D3D12_RESOURCE_BARRIER_TYPE_UAV: Serialise("UAV.pResource", el.UAV.pResource); break; + } +} + +string ToStrHelper::Get(const D3D12_VIEWPORT &el) +{ + return StringFormat::Fmt("Viewport<%.0fx%.0f+%.0f+%.0f z=%f->%f>", el.Width, el.Height, + el.TopLeftX, el.TopLeftY, el.MinDepth, el.MaxDepth); +} + +string ToStrHelper::Get(const D3D12_RESOURCE_BARRIER_TYPE &el) +{ + switch(el) + { + TOSTR_CASE_STRINGIZE(D3D12_RESOURCE_BARRIER_TYPE_TRANSITION) + TOSTR_CASE_STRINGIZE(D3D12_RESOURCE_BARRIER_TYPE_ALIASING) + TOSTR_CASE_STRINGIZE(D3D12_RESOURCE_BARRIER_TYPE_UAV) + default: break; + } + + return StringFormat::Fmt("D3D12_RESOURCE_BARRIER_TYPE<%d>", el); +} + string ToStrHelper::Get(const D3D12_BLEND &el) { switch(el) @@ -568,6 +631,65 @@ string ToStrHelper::Get(const D3D12_TEXTURE_LAYOUT return StringFormat::Fmt("D3D12_TEXTURE_LAYOUT<%d>", el); } +string ToStrHelper::Get(const D3D12_RESOURCE_BARRIER_FLAGS &el) +{ + string ret; + + if(el & D3D12_RESOURCE_BARRIER_FLAG_BEGIN_ONLY) + ret += " | D3D12_RESOURCE_BARRIER_FLAG_BEGIN_ONLY"; + if(el & D3D12_RESOURCE_BARRIER_FLAG_END_ONLY) + ret += " | D3D12_RESOURCE_BARRIER_FLAG_END_ONLY"; + + if(!ret.empty()) + ret = ret.substr(3); + + return ret; +} + +string ToStrHelper::Get(const D3D12_RESOURCE_STATES &el) +{ + string ret; + + if(el == D3D12_RESOURCE_STATE_COMMON) + return "COMMON/PRESENT"; + + if(el == D3D12_RESOURCE_STATE_GENERIC_READ) + return "GENERIC_READ"; + + if(el & D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER) + ret += " | VB & CB"; + if(el & D3D12_RESOURCE_STATE_INDEX_BUFFER) + ret += " | IB"; + if(el & D3D12_RESOURCE_STATE_RENDER_TARGET) + ret += " | RTV"; + if(el & D3D12_RESOURCE_STATE_UNORDERED_ACCESS) + ret += " | UAV"; + if(el & D3D12_RESOURCE_STATE_DEPTH_WRITE) + ret += " | DSV Write"; + if(el & D3D12_RESOURCE_STATE_DEPTH_READ) + ret += " | DSV Read"; + if(el & D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE) + ret += " | SRV (Non-Pixel)"; + if(el & D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE) + ret += " | SRV (Pixel)"; + if(el & D3D12_RESOURCE_STATE_STREAM_OUT) + ret += " | Stream Out"; + if(el & D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT) + ret += " | Indirect"; + if(el & D3D12_RESOURCE_STATE_COPY_DEST) + ret += " | Copy (Dst)"; + if(el & D3D12_RESOURCE_STATE_COPY_SOURCE) + ret += " | Copy (Src)"; + if(el & D3D12_RESOURCE_STATE_RESOLVE_DEST) + ret += " | Resolve (Dst)"; + if(el & D3D12_RESOURCE_STATE_RESOLVE_SOURCE) + ret += " | Resolve (Src)"; + if(el & D3D12_RESOURCE_STATE_PREDICATION) + ret += " | Predication"; + + return ret; +} + string ToStrHelper::Get(const D3D12_PIPELINE_STATE_FLAGS &el) { string ret; diff --git a/renderdoc/driver/d3d12/d3d12_common.h b/renderdoc/driver/d3d12/d3d12_common.h index 092ffbe89..aca2a59cc 100644 --- a/renderdoc/driver/d3d12/d3d12_common.h +++ b/renderdoc/driver/d3d12/d3d12_common.h @@ -118,35 +118,65 @@ template <> void Serialiser::Serialise(const char *name, D3D12_GRAPHICS_PIPELINE_STATE_DESC &el); template <> void Serialiser::Serialise(const char *name, D3D12_COMPUTE_PIPELINE_STATE_DESC &el); +template <> +void Serialiser::Serialise(const char *name, D3D12_INDEX_BUFFER_VIEW &el); +template <> +void Serialiser::Serialise(const char *name, D3D12_VERTEX_BUFFER_VIEW &el); +template <> +void Serialiser::Serialise(const char *name, D3D12_RESOURCE_BARRIER &el); #pragma region Chunks -#define D3D12_CHUNKS \ - D3D12_CHUNK_MACRO(DEVICE_INIT = FIRST_CHUNK_ID, "ID3D12Device::Initialisation") \ - D3D12_CHUNK_MACRO(SET_RESOURCE_NAME, "ID3D12Object::SetName") \ - D3D12_CHUNK_MACRO(RELEASE_RESOURCE, "IUnknown::Release") \ - D3D12_CHUNK_MACRO(CREATE_SWAP_BUFFER, "IDXGISwapChain::GetBuffer") \ - \ - D3D12_CHUNK_MACRO(CAPTURE_SCOPE, "Capture") \ - \ - D3D12_CHUNK_MACRO(PUSH_EVENT, "BeginEvent") \ - D3D12_CHUNK_MACRO(SET_MARKER, "SetMarker") \ - D3D12_CHUNK_MACRO(POP_EVENT, "EndEvent") \ - \ - D3D12_CHUNK_MACRO(DEBUG_MESSAGES, "DebugMessageList") \ - \ - D3D12_CHUNK_MACRO(CONTEXT_CAPTURE_HEADER, "ContextBegin") \ - D3D12_CHUNK_MACRO(CONTEXT_CAPTURE_FOOTER, "ContextEnd") \ - \ - D3D12_CHUNK_MACRO(SET_SHADER_DEBUG_PATH, "SetShaderDebugPath") \ - \ - D3D12_CHUNK_MACRO(CREATE_COMMAND_QUEUE, "WrappedID3D12Device::CreateCommandQueue") \ - D3D12_CHUNK_MACRO(CREATE_COMMAND_ALLOCATOR, "WrappedID3D12Device::CreateCommandAllocator") \ - D3D12_CHUNK_MACRO(CREATE_COMMAND_LIST, "WrappedID3D12Device::CreateCommandList") \ - \ - D3D12_CHUNK_MACRO(CREATE_GRAPHICS_PIPE, "WrappedID3D12Device::CreateGraphicsPipeline") \ - D3D12_CHUNK_MACRO(CREATE_COMPUTE_PIPE, "WrappedID3D12Device::CreateComputePipeline") \ - \ +#define D3D12_CHUNKS \ + D3D12_CHUNK_MACRO(DEVICE_INIT = FIRST_CHUNK_ID, "ID3D12Device::Initialisation") \ + D3D12_CHUNK_MACRO(SET_RESOURCE_NAME, "ID3D12Object::SetName") \ + D3D12_CHUNK_MACRO(RELEASE_RESOURCE, "IUnknown::Release") \ + D3D12_CHUNK_MACRO(CREATE_SWAP_BUFFER, "IDXGISwapChain::GetBuffer") \ + \ + D3D12_CHUNK_MACRO(CAPTURE_SCOPE, "Capture") \ + \ + D3D12_CHUNK_MACRO(PUSH_EVENT, "BeginEvent") \ + D3D12_CHUNK_MACRO(SET_MARKER, "SetMarker") \ + D3D12_CHUNK_MACRO(POP_EVENT, "EndEvent") \ + \ + D3D12_CHUNK_MACRO(DEBUG_MESSAGES, "DebugMessageList") \ + \ + D3D12_CHUNK_MACRO(CONTEXT_CAPTURE_HEADER, "ContextBegin") \ + D3D12_CHUNK_MACRO(CONTEXT_CAPTURE_FOOTER, "ContextEnd") \ + \ + D3D12_CHUNK_MACRO(SET_SHADER_DEBUG_PATH, "SetShaderDebugPath") \ + \ + D3D12_CHUNK_MACRO(CREATE_COMMAND_QUEUE, "ID3D12Device::CreateCommandQueue") \ + D3D12_CHUNK_MACRO(CREATE_COMMAND_ALLOCATOR, "ID3D12Device::CreateCommandAllocator") \ + D3D12_CHUNK_MACRO(CREATE_COMMAND_LIST, "ID3D12Device::CreateCommandList") \ + \ + D3D12_CHUNK_MACRO(CREATE_GRAPHICS_PIPE, "ID3D12Device::CreateGraphicsPipeline") \ + D3D12_CHUNK_MACRO(CREATE_COMPUTE_PIPE, "ID3D12Device::CreateComputePipeline") \ + \ + D3D12_CHUNK_MACRO(CLOSE_LIST, "ID3D12GraphicsCommandList::Close") \ + D3D12_CHUNK_MACRO(RESET_LIST, "ID3D12GraphicsCommandList::Reset") \ + \ + D3D12_CHUNK_MACRO(RESOURCE_BARRIER, "ID3D12GraphicsCommandList::ResourceBarrier") \ + \ + D3D12_CHUNK_MACRO(DRAW_INDEXED_INST, "ID3D12GraphicsCommandList::DrawIndexedInstanced") \ + D3D12_CHUNK_MACRO(COPY_BUFFER, "ID3D12GraphicsCommandList::CopyBufferRegion") \ + \ + D3D12_CHUNK_MACRO(CLEAR_RTV, "ID3D12GraphicsCommandList::ClearRenderTargetView") \ + \ + D3D12_CHUNK_MACRO(SET_TOPOLOGY, "ID3D12GraphicsCommandList::IASetPrimitiveTopology") \ + D3D12_CHUNK_MACRO(SET_IBUFFER, "ID3D12GraphicsCommandList::IASetIndexBuffer") \ + D3D12_CHUNK_MACRO(SET_VBUFFERS, "ID3D12GraphicsCommandList::IASetVertexBuffers") \ + D3D12_CHUNK_MACRO(SET_VIEWPORTS, "ID3D12GraphicsCommandList::RSSetViewports") \ + D3D12_CHUNK_MACRO(SET_SCISSORS, "ID3D12GraphicsCommandList::RSSetScissors") \ + D3D12_CHUNK_MACRO(SET_PIPE, "ID3D12GraphicsCommandList::SetPipelineState") \ + D3D12_CHUNK_MACRO(SET_RTVS, "ID3D12GraphicsCommandList::OMSetRenderTargets") \ + D3D12_CHUNK_MACRO(SET_ROOT_SIG, "ID3D12GraphicsCommandList::SetRootSignature") \ + D3D12_CHUNK_MACRO(SET_GFX_ROOT_CBV, \ + "ID3D12GraphicsCommandList::SetGraphicsRootConstantBufferView") \ + \ + D3D12_CHUNK_MACRO(EXECUTE_CMD_LISTS, "ID3D12GraphicsCommandQueue::ExecuteCommandLists") \ + D3D12_CHUNK_MACRO(SIGNAL, "ID3D12GraphicsCommandQueue::Signal") \ + \ D3D12_CHUNK_MACRO(NUM_D3D12_CHUNKS, "") enum D3D12ChunkType diff --git a/renderdoc/driver/d3d12/d3d12_device_wrap.cpp b/renderdoc/driver/d3d12/d3d12_device_wrap.cpp index 324556c6e..3e5762ce1 100644 --- a/renderdoc/driver/d3d12/d3d12_device_wrap.cpp +++ b/renderdoc/driver/d3d12/d3d12_device_wrap.cpp @@ -162,8 +162,8 @@ bool WrappedID3D12Device::Serialise_CreateCommandList(UINT nodeMask, D3D12_COMMA if(m_State == READING) { - pCommandAllocator = (ID3D12CommandAllocator *)GetResourceManager()->GetLiveResource(Allocator); - pInitialState = (ID3D12PipelineState *)GetResourceManager()->GetLiveResource(State); + pCommandAllocator = GetResourceManager()->GetLiveAs(Allocator); + pInitialState = GetResourceManager()->GetLiveAs(State); ID3D12GraphicsCommandList *ret = NULL; HRESULT hr = m_pDevice->CreateCommandList(Mask, ListType, pCommandAllocator, pInitialState, diff --git a/renderdoc/driver/d3d12/d3d12_manager.h b/renderdoc/driver/d3d12/d3d12_manager.h index c2b3fe2a6..729233f1e 100644 --- a/renderdoc/driver/d3d12/d3d12_manager.h +++ b/renderdoc/driver/d3d12/d3d12_manager.h @@ -234,6 +234,12 @@ public: { } + template + T *GetLiveAs(ResourceId id) + { + return (T *)GetLiveResource(id); + } + private: bool SerialisableResource(ResourceId id, D3D12ResourceRecord *record); ResourceId GetID(ID3D12DeviceChild *res);