Set up a patching function to unwrap shader records during capture

This commit is contained in:
baldurk
2024-04-30 18:28:33 +01:00
parent db44d06d41
commit c26c4b11d0
10 changed files with 238 additions and 13 deletions
@@ -176,6 +176,14 @@ private:
D3D12ResourceRecord *m_ListRecord;
D3D12ResourceRecord *m_CreationRecord;
// for ray dispatching we need to patch the tables on the GPU which requires pushing & popping
// compute pipeline and root signature, so we track it here during capture
D3D12RenderState m_CaptureComputeState;
// the ray dispatches which have happened on this list, this keeps a reference on the buffers until
// the list is reset, and each time the list is submitted the queue takes an additional reference
rdcarray<PatchedRayDispatch::Resources> m_RayDispatches;
CaptureState &m_State;
WrappedID3D12DebugCommandList m_WrappedDebug;
@@ -226,6 +234,8 @@ public:
ID3D12Resource *pArgumentBuffer,
UINT64 ArgumentBufferOffset, uint32_t argumentsReplayed);
void AddRayDispatches(rdcarray<PatchedRayDispatch::Resources> &dispatches);
void SetAMDMarkerInterface(IAmdExtD3DCommandListMarker *marker) { m_AMDMarkers = marker; }
void SetCommandData(D3D12CommandData *cmd) { m_Cmd = cmd; }
void SetInitParams(REFIID riid, UINT nodeMask, D3D12_COMMAND_LIST_TYPE type)
@@ -929,6 +929,9 @@ bool WrappedID3D12GraphicsCommandList::Serialise_BuildRaytracingAccelerationStru
RDCERR("TLAS Buffer isn't patched");
return false;
}
// Switch back to previous state
bakedCmdInfo.state.ApplyState(m_pDevice, (ID3D12GraphicsCommandListX *)pCommandList);
}
dxrCmd->BuildRaytracingAccelerationStructure(&AccStructDesc, NumPostbuildInfoDescs,
@@ -1202,6 +1205,8 @@ void WrappedID3D12GraphicsCommandList::SetPipelineState1(_In_ ID3D12StateObject
m_ListRecord->AddChunk(scope.Get(m_ListRecord->cmdInfo->alloc));
m_ListRecord->MarkResourceFrameReferenced(GetResID(pStateObject), eFrameRef_Read);
m_CaptureComputeState.stateobj = GetResID(pStateObject);
}
}
@@ -1271,7 +1276,20 @@ bool WrappedID3D12GraphicsCommandList::Serialise_DispatchRays(SerialiserType &se
void WrappedID3D12GraphicsCommandList::DispatchRays(_In_ const D3D12_DISPATCH_RAYS_DESC *pDesc)
{
SERIALISE_TIME_CALL(m_pList4->DispatchRays(pDesc));
// this call will copy the specified buffers containing shader records and patch them. We get a
// reference to the lookup buffer used as well as a reference to the scratch buffer containing the
// patched shader records.
PatchedRayDispatch patchedDispatch =
GetResourceManager()->GetRaytracingResourceAndUtilHandler()->PatchRayDispatch(m_pList4, *pDesc);
// restore state that would have been mutated by the patching process
m_pList4->SetComputeRootSignature(Unwrap(GetResourceManager()->GetCurrentAs<ID3D12RootSignature>(
m_CaptureComputeState.compute.rootsig)));
m_pList4->SetPipelineState1(
Unwrap(GetResourceManager()->GetCurrentAs<ID3D12StateObject>(m_CaptureComputeState.stateobj)));
m_CaptureComputeState.ApplyComputeRootElementsUnwrapped(m_pList);
SERIALISE_TIME_CALL(m_pList4->DispatchRays(&patchedDispatch.desc));
if(IsCaptureMode(m_State))
{
@@ -1296,6 +1314,10 @@ void WrappedID3D12GraphicsCommandList::DispatchRays(_In_ const D3D12_DISPATCH_RA
if(pDesc->HitGroupTable.SizeInBytes > 0)
m_ListRecord->MarkResourceFrameReferenced(
WrappedID3D12Resource::GetResIDFromAddr(pDesc->HitGroupTable.StartAddress), eFrameRef_Read);
// during capture track the ray dispatches so the memory can be freed dynamically. On replay we
// free all the memory at the end of each replay
m_RayDispatches.push_back(patchedDispatch.resources);
}
}
@@ -386,6 +386,18 @@ HRESULT WrappedID3D12GraphicsCommandList::ResetInternal(ID3D12CommandAllocator *
m_ListRecord->DeleteChunks();
m_ListRecord->ContainsExecuteIndirect = false;
// release the 'persistent' reference on all these buffers immediately. If this list was never
// submitted, this immediately frees the buffer. If it was submitted those submissions will be
// holding references until their fences are appropriately signalled.
for(PatchedRayDispatch::Resources &r : m_RayDispatches)
{
r.lookupBuffer->Release();
r.patchScratchBuffer->Release();
}
m_RayDispatches.clear();
m_CaptureComputeState.m_ResourceManager = GetResourceManager();
// free any baked commands.
if(m_ListRecord->bakedCommands)
m_ListRecord->bakedCommands->Delete(GetResourceManager());
@@ -1651,6 +1663,7 @@ void WrappedID3D12GraphicsCommandList::SetComputeRootSignature(ID3D12RootSignatu
// store this so we can look up how many descriptors a given slot references, etc
m_CurCompRootSig = GetWrapped(pRootSignature);
m_CaptureComputeState.compute.rootsig = GetResID(pRootSignature);
}
}
@@ -1722,6 +1735,14 @@ void WrappedID3D12GraphicsCommandList::SetComputeRootDescriptorTable(
m_ListRecord->MarkResourceFrameReferenced(GetWrapped(BaseDescriptor)->GetHeapResourceId(),
eFrameRef_Read);
{
m_CaptureComputeState.compute.sigelems.resize_for_index(RootParameterIndex);
m_CaptureComputeState.compute.sigelems[RootParameterIndex] =
D3D12RenderState::SignatureElement(eRootTable,
GetWrapped(BaseDescriptor)->GetHeapResourceId(),
(UINT64)GetWrapped(BaseDescriptor)->GetHeapIndex());
}
rdcarray<D3D12_DESCRIPTOR_RANGE1> &ranges =
GetWrapped(m_CurCompRootSig)->sig.Parameters[RootParameterIndex].ranges;
@@ -1826,6 +1847,12 @@ void WrappedID3D12GraphicsCommandList::SetComputeRoot32BitConstant(UINT RootPara
Serialise_SetComputeRoot32BitConstant(ser, RootParameterIndex, SrcData, DestOffsetIn32BitValues);
m_ListRecord->AddChunk(scope.Get(m_ListRecord->cmdInfo->alloc));
{
m_CaptureComputeState.compute.sigelems.resize_for_index(RootParameterIndex);
m_CaptureComputeState.compute.sigelems[RootParameterIndex].SetConstant(
DestOffsetIn32BitValues, SrcData);
}
}
}
@@ -1909,6 +1936,12 @@ void WrappedID3D12GraphicsCommandList::SetComputeRoot32BitConstants(UINT RootPar
DestOffsetIn32BitValues);
m_ListRecord->AddChunk(scope.Get(m_ListRecord->cmdInfo->alloc));
{
m_CaptureComputeState.compute.sigelems.resize_for_index(RootParameterIndex);
m_CaptureComputeState.compute.sigelems[RootParameterIndex].SetConstants(
Num32BitValuesToSet, pValidSrcData, DestOffsetIn32BitValues);
}
}
}
@@ -1988,6 +2021,12 @@ void WrappedID3D12GraphicsCommandList::SetComputeRootConstantBufferView(
m_ListRecord->AddChunk(scope.Get(m_ListRecord->cmdInfo->alloc));
m_ListRecord->MarkResourceFrameReferenced(id, eFrameRef_Read);
{
m_CaptureComputeState.compute.sigelems.resize_for_index(RootParameterIndex);
m_CaptureComputeState.compute.sigelems[RootParameterIndex] =
D3D12RenderState::SignatureElement(eRootCBV, id, offs);
}
}
}
@@ -2067,6 +2106,12 @@ void WrappedID3D12GraphicsCommandList::SetComputeRootShaderResourceView(
m_ListRecord->AddChunk(scope.Get(m_ListRecord->cmdInfo->alloc));
m_ListRecord->MarkResourceFrameReferenced(id, eFrameRef_Read);
{
m_CaptureComputeState.compute.sigelems.resize_for_index(RootParameterIndex);
m_CaptureComputeState.compute.sigelems[RootParameterIndex] =
D3D12RenderState::SignatureElement(eRootSRV, id, offs);
}
}
}
@@ -2146,6 +2191,12 @@ void WrappedID3D12GraphicsCommandList::SetComputeRootUnorderedAccessView(
m_ListRecord->AddChunk(scope.Get(m_ListRecord->cmdInfo->alloc));
m_ListRecord->MarkResourceFrameReferenced(id, eFrameRef_Read);
{
m_CaptureComputeState.compute.sigelems.resize_for_index(RootParameterIndex);
m_CaptureComputeState.compute.sigelems[RootParameterIndex] =
D3D12RenderState::SignatureElement(eRootUAV, id, offs);
}
}
}
@@ -171,6 +171,11 @@ class WrappedID3D12CommandQueue : public ID3D12CommandQueue,
CaptureState &m_State;
// tracking ray dispatches that are pending during capture, to free them once the execution is finished
ID3D12Fence *m_RayFence = NULL;
UINT64 m_RayFenceValue = 1;
rdcarray<PatchedRayDispatch::Resources> m_RayDispatchesPending;
bool m_MarkedActive = false;
WrappedID3D12DebugCommandQueue m_WrappedDebug;
@@ -226,6 +231,8 @@ public:
return m_SparseBindResources.find(id) != m_SparseBindResources.end();
}
void CheckAndFreeRayDispatches();
RDResult ReplayLog(CaptureState readType, uint32_t startEventID, uint32_t endEventID, bool partial);
void SetFrameReader(StreamReader *reader) { m_FrameReader = reader; }
D3D12CommandData *GetCommandData() { return &m_Cmd; }
@@ -753,6 +753,8 @@ void WrappedID3D12CommandQueue::ExecuteCommandListsInternal(UINT NumCommandLists
if(IsCaptureMode(m_State))
{
rdcarray<PatchedRayDispatch::Resources> rayDispatches;
if(!InFrameCaptureBoundary)
m_pDevice->GetCapTransitionLock().ReadLock();
@@ -772,6 +774,8 @@ void WrappedID3D12CommandQueue::ExecuteCommandListsInternal(UINT NumCommandLists
m_pDevice->ApplyBarriers(record->bakedCommands->cmdInfo->barriers);
wrapped->AddRayDispatches(rayDispatches);
// 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
@@ -882,6 +886,27 @@ void WrappedID3D12CommandQueue::ExecuteCommandListsInternal(UINT NumCommandLists
record->cmdInfo->dirtied.clear();
}
if(!rayDispatches.empty())
{
// if we don't have a fence for this queue tracking, create it now
if(!m_RayFence)
{
// create this unwrapped so that it doesn't get recorded into captures
m_pDevice->GetReal()->CreateFence(0, D3D12_FENCE_FLAG_NONE, __uuidof(ID3D12Fence),
(void **)&m_RayFence);
m_RayFence->SetName(L"Queue Ray Fence");
}
for(PatchedRayDispatch::Resources &ray : rayDispatches)
ray.fenceValue = m_RayFenceValue;
m_RayDispatchesPending.append(rayDispatches);
HRESULT hr = m_pReal->Signal(m_RayFence, m_RayFenceValue++);
m_pDevice->CheckHRESULT(hr);
RDCASSERTEQUAL(hr, S_OK);
}
if(capframe)
{
rdcarray<MapState> maps = m_pDevice->GetMaps();
+32
View File
@@ -525,6 +525,8 @@ WrappedID3D12CommandQueue::~WrappedID3D12CommandQueue()
{
SAFE_DELETE(m_FrameReader);
SAFE_RELEASE(m_RayFence);
if(m_CreationRecord)
m_CreationRecord->Delete(m_pDevice->GetResourceManager());
@@ -629,6 +631,25 @@ HRESULT STDMETHODCALLTYPE WrappedID3D12CommandQueue::QueryInterface(REFIID riid,
return RefCounter12::QueryInterface("ID3D12CommandQueue", riid, ppvObject);
}
void WrappedID3D12CommandQueue::CheckAndFreeRayDispatches()
{
UINT64 signalled = 0;
if(m_RayFence)
signalled = m_RayFence->GetCompletedValue();
for(PatchedRayDispatch::Resources &ray : m_RayDispatchesPending)
{
if(signalled >= ray.fenceValue)
{
SAFE_RELEASE(ray.patchScratchBuffer);
SAFE_RELEASE(ray.lookupBuffer);
}
}
m_RayDispatchesPending.removeIf(
[](const PatchedRayDispatch::Resources &ray) { return ray.lookupBuffer == NULL; });
}
void WrappedID3D12CommandQueue::ClearAfterCapture()
{
// delete cmd buffers now - had to keep them alive until after serialiser flush.
@@ -1407,6 +1428,17 @@ WriteSerialiser &WrappedID3D12GraphicsCommandList::GetThreadSerialiser()
return m_pDevice->GetThreadSerialiser();
}
void WrappedID3D12GraphicsCommandList::AddRayDispatches(rdcarray<PatchedRayDispatch::Resources> &dispatches)
{
dispatches.reserve(dispatches.size() + m_RayDispatches.size());
for(const PatchedRayDispatch::Resources &r : m_RayDispatches)
{
dispatches.push_back(r);
r.lookupBuffer->AddRef();
r.patchScratchBuffer->AddRef();
}
}
rdcstr WrappedID3D12GraphicsCommandList::GetChunkName(uint32_t idx)
{
if((SystemChunk)idx < SystemChunk::FirstDriverChunk)
+6
View File
@@ -779,6 +779,12 @@ void D3D12RaytracingResourceAndUtilHandler::ResizeSerialisationBuffer(UINT64 siz
}
}
PatchedRayDispatch D3D12RaytracingResourceAndUtilHandler::PatchRayDispatch(
ID3D12GraphicsCommandList4 *unwrappedCmd, const D3D12_DISPATCH_RAYS_DESC &desc)
{
return {};
}
void D3D12RaytracingResourceAndUtilHandler::InitReplayBlasPatchingResources()
{
// Root Signature
+26
View File
@@ -1045,6 +1045,29 @@ struct D3D12AccStructPatchInfo
ID3D12PipelineState *m_pipeline;
};
struct PatchedRayDispatch
{
struct Resources
{
// the lookup buffer
D3D12GpuBuffer *lookupBuffer;
// the scratch buffer used for patching's fence.
D3D12GpuBuffer *patchScratchBuffer;
// for convenience, when these resources are referenced in a queue they get a fence value to
// indicate when they're safe to release. This values are unset when returned from patching or
// referenced in the list and is set in each queue's copy of the references.
UINT64 fenceValue = 0;
};
Resources resources;
// the patched dispatch descriptor
D3D12_DISPATCH_RAYS_DESC desc = {};
};
struct D3D12ShaderExportDatabase;
class D3D12RaytracingResourceAndUtilHandler
{
public:
@@ -1074,6 +1097,9 @@ public:
void RegisterExportDatabase(D3D12ShaderExportDatabase *db);
void UnregisterExportDatabase(D3D12ShaderExportDatabase *db);
PatchedRayDispatch PatchRayDispatch(ID3D12GraphicsCommandList4 *unwrappedCmd,
const D3D12_DISPATCH_RAYS_DESC &desc);
void ResizeSerialisationBuffer(UINT64 size);
// buffer in UAV state for emitting AS queries to, CPU accessible/mappable
+41 -5
View File
@@ -347,7 +347,7 @@ void D3D12RenderState::ApplyState(WrappedID3D12Device *dev, ID3D12GraphicsComman
}
}
void D3D12RenderState::ApplyDescriptorHeaps(ID3D12GraphicsCommandListX *cmd) const
void D3D12RenderState::ApplyDescriptorHeaps(ID3D12GraphicsCommandList *cmd) const
{
rdcarray<ID3D12DescriptorHeap *> descHeaps;
descHeaps.resize(heaps.size());
@@ -359,7 +359,7 @@ void D3D12RenderState::ApplyDescriptorHeaps(ID3D12GraphicsCommandListX *cmd) con
cmd->SetDescriptorHeaps((UINT)descHeaps.size(), &descHeaps[0]);
}
void D3D12RenderState::ApplyComputeRootElements(ID3D12GraphicsCommandListX *cmd) const
void D3D12RenderState::ApplyComputeRootElements(ID3D12GraphicsCommandList *cmd) const
{
for(size_t i = 0; i < compute.sigelems.size(); i++)
{
@@ -367,7 +367,7 @@ void D3D12RenderState::ApplyComputeRootElements(ID3D12GraphicsCommandListX *cmd)
// and is probably just from stale bindings that aren't going to be used
if(compute.sigelems[i].type != eRootTable || heaps.contains(compute.sigelems[i].id))
{
compute.sigelems[i].SetToCompute(GetResourceManager(), cmd, (UINT)i);
compute.sigelems[i].SetToCompute(GetResourceManager(), cmd, (UINT)i, false);
}
else
{
@@ -377,7 +377,7 @@ void D3D12RenderState::ApplyComputeRootElements(ID3D12GraphicsCommandListX *cmd)
}
}
void D3D12RenderState::ApplyGraphicsRootElements(ID3D12GraphicsCommandListX *cmd) const
void D3D12RenderState::ApplyGraphicsRootElements(ID3D12GraphicsCommandList *cmd) const
{
for(size_t i = 0; i < graphics.sigelems.size(); i++)
{
@@ -385,7 +385,43 @@ void D3D12RenderState::ApplyGraphicsRootElements(ID3D12GraphicsCommandListX *cmd
// and is probably just from stale bindings that aren't going to be used
if(graphics.sigelems[i].type != eRootTable || heaps.contains(graphics.sigelems[i].id))
{
graphics.sigelems[i].SetToGraphics(GetResourceManager(), cmd, (UINT)i);
graphics.sigelems[i].SetToGraphics(GetResourceManager(), cmd, (UINT)i, false);
}
else
{
RDCDEBUG("Skipping setting possibly stale graphics root table referring to heap %s",
ToStr(graphics.sigelems[i].id).c_str());
}
}
}
void D3D12RenderState::ApplyComputeRootElementsUnwrapped(ID3D12GraphicsCommandList *cmd) const
{
for(size_t i = 0; i < compute.sigelems.size(); i++)
{
// just don't set tables that aren't in the descriptor heaps, since it's invalid and can crash
// and is probably just from stale bindings that aren't going to be used
if(compute.sigelems[i].type != eRootTable || heaps.contains(compute.sigelems[i].id))
{
compute.sigelems[i].SetToCompute(GetResourceManager(), cmd, (UINT)i, true);
}
else
{
RDCDEBUG("Skipping setting possibly stale compute root table referring to heap %s",
ToStr(compute.sigelems[i].id).c_str());
}
}
}
void D3D12RenderState::ApplyGraphicsRootElementsUnwrapped(ID3D12GraphicsCommandList *cmd) const
{
for(size_t i = 0; i < graphics.sigelems.size(); i++)
{
// just don't set tables that aren't in the descriptor heaps, since it's invalid and can crash
// and is probably just from stale bindings that aren't going to be used
if(graphics.sigelems[i].type != eRootTable || heaps.contains(graphics.sigelems[i].id))
{
graphics.sigelems[i].SetToGraphics(GetResourceManager(), cmd, (UINT)i, true);
}
else
{
+17 -7
View File
@@ -47,9 +47,11 @@ struct D3D12RenderState
D3D12RenderState &operator=(const D3D12RenderState &o) = default;
void ApplyState(WrappedID3D12Device *dev, ID3D12GraphicsCommandListX *list) const;
void ApplyDescriptorHeaps(ID3D12GraphicsCommandListX *list) const;
void ApplyComputeRootElements(ID3D12GraphicsCommandListX *cmd) const;
void ApplyGraphicsRootElements(ID3D12GraphicsCommandListX *cmd) const;
void ApplyDescriptorHeaps(ID3D12GraphicsCommandList *list) const;
void ApplyComputeRootElements(ID3D12GraphicsCommandList *cmd) const;
void ApplyGraphicsRootElements(ID3D12GraphicsCommandList *cmd) const;
void ApplyComputeRootElementsUnwrapped(ID3D12GraphicsCommandList *cmd) const;
void ApplyGraphicsRootElementsUnwrapped(ID3D12GraphicsCommandList *cmd) const;
rdcarray<D3D12_VIEWPORT> views;
rdcarray<D3D12_RECT> scissors;
@@ -93,7 +95,8 @@ struct D3D12RenderState
memcpy(&constants[offs], vals, numVals * sizeof(UINT));
}
void SetToGraphics(D3D12ResourceManager *rm, ID3D12GraphicsCommandList *cmd, UINT slot) const
void SetToGraphics(D3D12ResourceManager *rm, ID3D12GraphicsCommandList *cmd, UINT slot,
bool unwrapped) const
{
if(type == eRootConst)
{
@@ -104,7 +107,10 @@ struct D3D12RenderState
D3D12_GPU_DESCRIPTOR_HANDLE handle =
rm->GetCurrentAs<ID3D12DescriptorHeap>(id)->GetGPUDescriptorHandleForHeapStart();
handle.ptr += sizeof(D3D12Descriptor) * offset;
cmd->SetGraphicsRootDescriptorTable(slot, handle);
if(unwrapped)
cmd->SetGraphicsRootDescriptorTable(slot, Unwrap(handle));
else
cmd->SetGraphicsRootDescriptorTable(slot, handle);
}
else if(type == eRootCBV)
{
@@ -123,7 +129,8 @@ struct D3D12RenderState
}
}
void SetToCompute(D3D12ResourceManager *rm, ID3D12GraphicsCommandList *cmd, UINT slot) const
void SetToCompute(D3D12ResourceManager *rm, ID3D12GraphicsCommandList *cmd, UINT slot,
bool unwrapped) const
{
if(type == eRootConst)
{
@@ -134,7 +141,10 @@ struct D3D12RenderState
D3D12_GPU_DESCRIPTOR_HANDLE handle =
rm->GetCurrentAs<ID3D12DescriptorHeap>(id)->GetGPUDescriptorHandleForHeapStart();
handle.ptr += sizeof(D3D12Descriptor) * offset;
cmd->SetComputeRootDescriptorTable(slot, handle);
if(unwrapped)
cmd->SetComputeRootDescriptorTable(slot, Unwrap(handle));
else
cmd->SetComputeRootDescriptorTable(slot, handle);
}
else if(type == eRootCBV)
{