Add verification of TLAS build inputs

This commit is contained in:
baldurk
2024-11-21 17:50:56 +00:00
parent 9e65af1a8c
commit 081345fccf
4 changed files with 148 additions and 14 deletions
@@ -847,7 +847,7 @@ bool WrappedID3D12GraphicsCommandList::PatchAccStructBlasAddress(
resBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
resBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
resBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
resBarrier.Transition.pResource = patchRaytracing->m_patchedInstanceBuffer->Resource();
resBarrier.Transition.pResource = patchRaytracing->patchedInstanceBuffer->Resource();
resBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
resBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;
resBarriers.push_back(resBarrier);
@@ -866,7 +866,7 @@ bool WrappedID3D12GraphicsCommandList::PatchAccStructBlasAddress(
// unroll the instances list into a flat array (which will then get patched below in-place)
D3D12GpuBuffer *tempBuffer = rtManager->UnrollBLASInstancesList(
unwrappedList, accStructInput.Inputs, addressPairResAddress, addressCount,
patchRaytracing->m_patchedInstanceBuffer);
patchRaytracing->patchedInstanceBuffer);
accStructInput.Inputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY;
@@ -880,9 +880,20 @@ bool WrappedID3D12GraphicsCommandList::PatchAccStructBlasAddress(
}
else
{
unwrappedList->CopyBufferRegion(patchRaytracing->m_patchedInstanceBuffer->Resource(),
patchRaytracing->m_patchedInstanceBuffer->Offset(),
unwrappedList->CopyBufferRegion(patchRaytracing->patchedInstanceBuffer->Resource(),
patchRaytracing->patchedInstanceBuffer->Offset(),
instanceResource, instanceResOffset, totalInstancesSize);
if(D3D12_Debug_RTAuditing())
{
GetResourceManager()->GetGPUBufferAllocator().Alloc(
D3D12GpuBufferHeapType::ReadBackHeap, D3D12GpuBufferHeapMemoryFlag::Default,
totalInstancesSize, 256, &patchRaytracing->unpatchedInstanceBufferReadback);
unwrappedList->CopyBufferRegion(patchRaytracing->unpatchedInstanceBufferReadback->Resource(),
patchRaytracing->unpatchedInstanceBufferReadback->Offset(),
instanceResource, instanceResOffset, totalInstancesSize);
}
}
D3D12AccStructPatchInfo patchInfo = rtManager->GetAccStructPatchInfo();
@@ -894,7 +905,7 @@ bool WrappedID3D12GraphicsCommandList::PatchAccStructBlasAddress(
resBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
resBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
resBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
resBarrier.Transition.pResource = patchRaytracing->m_patchedInstanceBuffer->Resource();
resBarrier.Transition.pResource = patchRaytracing->patchedInstanceBuffer->Resource();
resBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
resBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
resBarriers.push_back(resBarrier);
@@ -928,7 +939,7 @@ bool WrappedID3D12GraphicsCommandList::PatchAccStructBlasAddress(
D3D12_RESOURCE_BARRIER resBarrier;
resBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV;
resBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
resBarrier.UAV.pResource = patchRaytracing->m_patchedInstanceBuffer->Resource();
resBarrier.UAV.pResource = patchRaytracing->patchedInstanceBuffer->Resource();
unwrappedList->ResourceBarrier(1, &resBarrier);
}
@@ -940,14 +951,15 @@ bool WrappedID3D12GraphicsCommandList::PatchAccStructBlasAddress(
(UINT)D3D12PatchTLASBuildParam::RootAddressPairSrv, addressPairResAddress);
unwrappedList->SetComputeRootUnorderedAccessView(
(UINT)D3D12PatchTLASBuildParam::RootPatchedAddressUav,
patchRaytracing->m_patchedInstanceBuffer->Address());
patchRaytracing->patchedInstanceBuffer->Address());
unwrappedList->Dispatch(accStructInput.Inputs.NumDescs, 1, 1);
{
D3D12_RESOURCE_BARRIER resBarrier;
resBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV;
resBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
resBarrier.UAV.pResource = patchRaytracing->m_patchedInstanceBuffer->Resource();
resBarrier.UAV.pResource = patchRaytracing->patchedInstanceBuffer->Resource();
unwrappedList->ResourceBarrier(1, &resBarrier);
}
@@ -956,7 +968,7 @@ bool WrappedID3D12GraphicsCommandList::PatchAccStructBlasAddress(
resBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
resBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
resBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
resBarrier.Transition.pResource = patchRaytracing->m_patchedInstanceBuffer->Resource();
resBarrier.Transition.pResource = patchRaytracing->patchedInstanceBuffer->Resource();
resBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
resBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
unwrappedList->ResourceBarrier(1, &resBarrier);
@@ -993,6 +1005,22 @@ bool WrappedID3D12GraphicsCommandList::Serialise_BuildRaytracingAccelerationStru
BakedCmdListInfo::PatchRaytracing &patchInfo =
bakedCmdInfo.m_patchRaytracingInfo[bakedCmdInfo.curEventID];
D3D12AccelerationStructure *accStructAtDstOffset = NULL;
if(D3D12_Debug_RTAuditing())
{
ResourceId destASBId;
D3D12BufferOffset destASBOffset;
WrappedID3D12Resource::GetResIDFromAddr(AccStructDesc.DestAccelerationStructureData,
destASBId, destASBOffset);
WrappedID3D12Resource *destASB =
GetResourceManager()->GetCurrentAs<WrappedID3D12Resource>(destASBId);
RDCASSERT(destASB->GetAccStructIfExist(destASBOffset, &accStructAtDstOffset));
}
if(IsActiveReplaying(m_State))
{
if(m_Cmd->InRerecordRange(m_Cmd->m_LastCmdListID))
@@ -1004,9 +1032,15 @@ bool WrappedID3D12GraphicsCommandList::Serialise_BuildRaytracingAccelerationStru
{
patchInfo.m_patched = false;
PatchAccStructBlasAddress(AccStructDesc, Unwrap4(list), &patchInfo);
// the destination AS *will* be present by definition, but we only fetch it and store it
// here for auditing so the pointer may be NULL.
patchInfo.destinationAS =
accStructAtDstOffset ? accStructAtDstOffset->GetResourceID() : ResourceId();
if(patchInfo.m_patched)
{
AccStructDesc.Inputs.InstanceDescs = patchInfo.m_patchedInstanceBuffer->Address();
AccStructDesc.Inputs.InstanceDescs = patchInfo.patchedInstanceBuffer->Address();
}
else
{
@@ -1017,6 +1051,13 @@ bool WrappedID3D12GraphicsCommandList::Serialise_BuildRaytracingAccelerationStru
// Switch back to previous state
bakedCmdInfo.state.ApplyState(m_pDevice, list);
}
else if(AccStructDesc.Inputs.Type == D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL)
{
// the destination AS *will* be present by definition, but we only fetch it and store it
// here for auditing so the pointer may be NULL.
patchInfo.destinationAS =
accStructAtDstOffset ? accStructAtDstOffset->GetResourceID() : ResourceId();
}
if(!D3D12_Debug_RTAuditing())
{
@@ -1039,13 +1080,18 @@ bool WrappedID3D12GraphicsCommandList::Serialise_BuildRaytracingAccelerationStru
if(GetResourceManager()->GetGPUBufferAllocator().Alloc(
D3D12GpuBufferHeapType::DefaultHeapWithUav, D3D12GpuBufferHeapMemoryFlag::Default,
totalInstancesSize, D3D12_RAYTRACING_INSTANCE_DESCS_BYTE_ALIGNMENT,
&patchInfo.m_patchedInstanceBuffer))
&patchInfo.patchedInstanceBuffer))
{
PatchAccStructBlasAddress(AccStructDesc, Unwrap4(pCommandList), &patchInfo);
// the destination AS *will* be present by definition, but we only fetch it and store it
// here for auditing so the pointer may be NULL.
patchInfo.destinationAS =
accStructAtDstOffset ? accStructAtDstOffset->GetResourceID() : ResourceId();
if(patchInfo.m_patched)
{
AccStructDesc.Inputs.InstanceDescs = patchInfo.m_patchedInstanceBuffer->Address();
AccStructDesc.Inputs.InstanceDescs = patchInfo.patchedInstanceBuffer->Address();
}
// Switch back to previous state
@@ -28,6 +28,7 @@
#include "d3d12_resources.h"
RDOC_EXTERN_CONFIG(bool, D3D12_Debug_SingleSubmitFlushing);
RDOC_EXTERN_CONFIG(bool, D3D12_Debug_RTAuditing);
template <typename SerialiserType>
bool WrappedID3D12CommandQueue::Serialise_UpdateTileMappings(
@@ -491,11 +492,93 @@ bool WrappedID3D12CommandQueue::Serialise_ExecuteCommandLists(SerialiserType &se
ID3D12CommandList *list = Unwrap(ppCommandLists[i]);
real->ExecuteCommandLists(1, &list);
if(D3D12_Debug_SingleSubmitFlushing())
if(D3D12_Debug_SingleSubmitFlushing() || D3D12_Debug_RTAuditing())
m_pDevice->GPUSync();
BakedCmdListInfo &info = m_Cmd.m_BakedCmdListInfo[cmd];
if(D3D12_Debug_RTAuditing())
{
for(auto it = info.m_patchRaytracingInfo.begin(); it != info.m_patchRaytracingInfo.end();
++it)
{
if(!it->second.unpatchedInstanceBufferReadback)
{
if(it->second.destinationAS != ResourceId())
{
D3D12AccelerationStructure *as =
(D3D12AccelerationStructure *)GetResourceManager()->GetLiveResource(
it->second.destinationAS);
as->seenReplayBuild = true;
}
continue;
}
const D3D12_RAYTRACING_INSTANCE_DESC *instances =
(const D3D12_RAYTRACING_INSTANCE_DESC *)
it->second.unpatchedInstanceBufferReadback->Map();
ResourceId id = it->second.destinationAS;
RDCLOG("Verifying TLAS build of %s at relative %u in %s", ToStr(id).c_str(), it->first,
ToStr(cmd).c_str());
for(UINT desc = 0; desc < it->second.numDescs; desc++)
{
// silently ignore NULL BLASs
if(instances[desc].AccelerationStructure == 0)
continue;
ResourceId blasId;
UINT64 blasOffs;
m_pDevice->GetResIDFromOrigAddr(instances[desc].AccelerationStructure, blasId,
blasOffs);
WrappedID3D12Resource *blas =
GetResourceManager()->GetLiveAs<WrappedID3D12Resource>(blasId);
D3D12AccelerationStructure *blasCheck = NULL;
rdcstr invalid;
if(blasId == ResourceId() || blas == NULL)
invalid = StringFormat::Fmt("Address references non-existant buffer");
else if(!blas->GetAccStructIfExist(blasOffs, &blasCheck))
invalid = StringFormat::Fmt("No valid AS known at buffer location");
else if(blasCheck->Type() == D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL)
invalid = StringFormat::Fmt("TLAS referenced by TLAS");
if(!invalid.empty())
{
RDCERR("%s[%u]: %s", ToStr(id).c_str(), desc, invalid.c_str());
continue;
}
if(id < GetResourceManager()->GetOriginalID(blasCheck->GetResourceID()))
{
RDCERR("%s[%u]: BLAS referenced by TLAS is newer than TLAS", ToStr(id).c_str(), desc);
continue;
}
if(!blasCheck->seenReplayBuild)
{
RDCERR("%s[%u]: BLAS referenced by TLAS has not been built yet on replay",
ToStr(id).c_str(), desc);
continue;
}
RDCLOG("%s[%u]: valid BLAS referenced at %llx (%llx on replay)", ToStr(id).c_str(),
desc, instances[desc].AccelerationStructure,
blas->GetGPUVirtualAddress() + blasOffs);
RDCASSERTEQUAL(blasCheck->GetVirtualAddress(), blas->GetGPUVirtualAddress() + blasOffs);
}
it->second.unpatchedInstanceBufferReadback->Unmap();
SAFE_RELEASE(it->second.unpatchedInstanceBufferReadback);
}
}
if(!info.executeEvents.empty())
{
// ensure all GPU work has finished for readback of arguments
+4 -1
View File
@@ -205,7 +205,10 @@ struct BakedCmdListInfo
struct PatchRaytracing
{
bool m_patched = false;
D3D12GpuBuffer *m_patchedInstanceBuffer;
uint32_t numDescs = 0;
D3D12GpuBuffer *patchedInstanceBuffer = NULL;
D3D12GpuBuffer *unpatchedInstanceBufferReadback = NULL;
ResourceId destinationAS;
};
rdcflatmap<uint32_t, PatchRaytracing> m_patchRaytracingInfo;
+2
View File
@@ -1684,6 +1684,8 @@ public:
ASBuildData *buildData = NULL;
// only valid on replay - for auditing
bool seenReplayBuild = false;
private:
WrappedID3D12Resource *m_asbWrappedResource;
D3D12BufferOffset m_asbWrappedResourceBufferOffset;