From 6254393bdf87f1635061deb2f04418a62997e73c Mon Sep 17 00:00:00 2001 From: Amit Prakash Date: Wed, 27 Jul 2022 17:55:41 -0400 Subject: [PATCH] Add serialisation & replay of Acceleration structure build calls * Add patching of BLAS address in TLAS * Add a compute shader to patch the BLAS address * Adds a pipeline, and root signature for patching the BLAS --- renderdoc/api/replay/replay_enums.h | 10 + renderdoc/data/hlsl/hlsl_cbuffers.h | 28 ++ renderdoc/data/hlsl/raytracing.hlsl | 60 +++++ renderdoc/data/renderdoc.rc | 1 + renderdoc/data/resource.h | 1 + renderdoc/driver/d3d12/d3d12_command_list.h | 4 + .../driver/d3d12/d3d12_command_list4_wrap.cpp | 245 +++++++++++++++++- renderdoc/driver/d3d12/d3d12_commands.h | 19 +- renderdoc/driver/d3d12/d3d12_device.cpp | 112 ++++++++ renderdoc/driver/d3d12/d3d12_device.h | 6 + renderdoc/driver/d3d12/d3d12_manager.cpp | 90 +++++++ renderdoc/driver/d3d12/d3d12_manager.h | 20 ++ renderdoc/renderdoc.vcxproj | 1 + renderdoc/renderdoc.vcxproj.filters | 1 + 14 files changed, 592 insertions(+), 6 deletions(-) create mode 100644 renderdoc/data/hlsl/raytracing.hlsl diff --git a/renderdoc/api/replay/replay_enums.h b/renderdoc/api/replay/replay_enums.h index f2dcab1a4..8be5d1004 100644 --- a/renderdoc/api/replay/replay_enums.h +++ b/renderdoc/api/replay/replay_enums.h @@ -4715,6 +4715,14 @@ actions. The action marks the beginning or end of a render pass. See :data:`BeginPass` and :data:`EndPass`. +.. data:: DispatchRay + + This action issues a number of rays. + +.. data:: BuildAccStruct + + This action builds the acceleration structure. + .. data:: Indexed The action uses an index buffer. @@ -4772,6 +4780,8 @@ enum class ActionFlags : uint32_t Resolve = 0x0800, GenMips = 0x1000, PassBoundary = 0x2000, + DispatchRay = 0x4000, + BuildAccStruct = 0x8000, // flags Indexed = 0x010000, diff --git a/renderdoc/data/hlsl/hlsl_cbuffers.h b/renderdoc/data/hlsl/hlsl_cbuffers.h index 33cbd8a97..c20eb71af 100644 --- a/renderdoc/data/hlsl/hlsl_cbuffers.h +++ b/renderdoc/data/hlsl/hlsl_cbuffers.h @@ -190,6 +190,34 @@ cbuffer DebugMathOperation REG(b0) int mathOp; }; +cbuffer AccStructPatchInfo REG(b0) +{ + uint addressCount; +}; + +#if defined(SHADER_MODEL_MIN_6_0_REQUIRED) || defined(__cplusplus) +typedef uint64_t GPUAddress; + +struct BlasAddressRange +{ + GPUAddress start; + GPUAddress end; +}; + +struct BlasAddressPair +{ + BlasAddressRange oldAddress; + BlasAddressRange newAddress; +}; + +// This corresponds to D3D12_RAYTRACING_INSTANCE_DESC structure +struct InstanceDesc +{ + uint64_t padding[7]; + GPUAddress blasAddress; +}; +#endif + cbuffer DebugSampleOperation REG(b0) { float4 debugSampleUV; diff --git a/renderdoc/data/hlsl/raytracing.hlsl b/renderdoc/data/hlsl/raytracing.hlsl new file mode 100644 index 000000000..56e695da6 --- /dev/null +++ b/renderdoc/data/hlsl/raytracing.hlsl @@ -0,0 +1,60 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2022 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#ifndef SHADER_MODEL_MIN_6_0_REQUIRED +#define SHADER_MODEL_MIN_6_0_REQUIRED +#endif +#include "hlsl_cbuffers.h" + +RWStructuredBuffer instanceDescs : register(u0, space0); +StructuredBuffer oldNewAddressesPair : register(t0, space0); + +bool InRange(BlasAddressRange addressRange, GPUAddress address) +{ + if(addressRange.start <= address && address <= addressRange.end) + { + return true; + } + + return false; +} + +// Each SV_GroupId corresponds to each of the BLAS (instance) in TLAS +[numthreads(1, 1, 1)] void RENDERDOC_PatchAccStructAddressCS(uint3 dispatchGroup + : SV_GroupId) { + GPUAddress instanceBlasAddress = instanceDescs[dispatchGroup.x].blasAddress; + + for(uint i = 0; i < addressCount; i++) + { + if(InRange(oldNewAddressesPair[i].oldAddress, instanceBlasAddress)) + { + uint64_t offset = instanceBlasAddress - oldNewAddressesPair[i].oldAddress.start; + instanceDescs[dispatchGroup.x].blasAddress = oldNewAddressesPair[i].newAddress.start + offset; + return; + } + } + + // This might cause device hang but at least we won't access incorrect addresses + instanceDescs[dispatchGroup.x].blasAddress = 0; +} diff --git a/renderdoc/data/renderdoc.rc b/renderdoc/data/renderdoc.rc index be64d63bb..07623bdff 100644 --- a/renderdoc/data/renderdoc.rc +++ b/renderdoc/data/renderdoc.rc @@ -117,6 +117,7 @@ RESOURCE_fixedcol_hlsl TYPE_EMBED "hlsl/fixedcol.hlsl" RESOURCE_shaderdebug_hlsl TYPE_EMBED "hlsl/shaderdebug.hlsl" RESOURCE_d3d12_pixelhistory_hlsl TYPE_EMBED "hlsl/d3d12_pixelhistory.hlsl" RESOURCE_depth_copy_hlsl TYPE_EMBED "hlsl/depth_copy.hlsl" +RESOURCE_raytracing_hlsl TYPE_EMBED "hlsl/raytracing.hlsl" #ifdef RENDERDOC_BAKED_DXC_SHADERS diff --git a/renderdoc/data/resource.h b/renderdoc/data/resource.h index 4988b6466..95f4417ab 100644 --- a/renderdoc/data/resource.h +++ b/renderdoc/data/resource.h @@ -20,6 +20,7 @@ #define RESOURCE_shaderdebug_hlsl 118 #define RESOURCE_d3d12_pixelhistory_hlsl 119 #define RESOURCE_depth_copy_hlsl 120 +#define RESOURCE_raytracing_hlsl 121 #define RESOURCE_fixedcol_0_dxbc 113 #define RESOURCE_fixedcol_1_dxbc 114 diff --git a/renderdoc/driver/d3d12/d3d12_command_list.h b/renderdoc/driver/d3d12/d3d12_command_list.h index 3e5914fa2..7f5e53ed4 100644 --- a/renderdoc/driver/d3d12/d3d12_command_list.h +++ b/renderdoc/driver/d3d12/d3d12_command_list.h @@ -568,6 +568,10 @@ public: const void *pExecutionParametersData, _In_ SIZE_T ExecutionParametersDataSizeInBytes); + bool PatchAccStructBlasAddress(const D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC *accStructInput, + ID3D12GraphicsCommandList4 *dxrCmd, + BakedCmdListInfo::PatchRaytracing *patchRaytracing); + IMPLEMENT_FUNCTION_SERIALISED( virtual void STDMETHODCALLTYPE, BuildRaytracingAccelerationStructure, _In_ const D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC *pDesc, diff --git a/renderdoc/driver/d3d12/d3d12_command_list4_wrap.cpp b/renderdoc/driver/d3d12/d3d12_command_list4_wrap.cpp index 843be3b45..ea2465789 100644 --- a/renderdoc/driver/d3d12/d3d12_command_list4_wrap.cpp +++ b/renderdoc/driver/d3d12/d3d12_command_list4_wrap.cpp @@ -25,6 +25,8 @@ #include "d3d12_command_list.h" #include "d3d12_debug.h" +#include "data/hlsl/hlsl_cbuffers.h" + static rdcstr ToHumanStr(const D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE &el) { BEGIN_ENUM_STRINGISE(D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE); @@ -725,6 +727,168 @@ void WrappedID3D12GraphicsCommandList::ExecuteMetaCommand( RDCERR("ExecuteMetaCommand called but no meta commands reported!"); } +bool WrappedID3D12GraphicsCommandList::PatchAccStructBlasAddress( + const D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC *accStructInput, + ID3D12GraphicsCommandList4 *dxrCmd, BakedCmdListInfo::PatchRaytracing *patchRaytracing) +{ + if(accStructInput->Inputs.Type == D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL) + { + // Here, we are uploading the old BLAS addresses, and comparing the BLAS + // addresses in the TLAS and patching it with the corresponding new address. + + D3D12RaytracingResourceAndUtilHandler *rtHandler = + GetResourceManager()->GetRaytracingResourceAndUtilHandler(); + + // Create a resource for patched instance desc; we don't + // need a resource of same size but of same number of instances in the TLAS with uav + uint64_t totalInstancesSize = + accStructInput->Inputs.NumDescs * sizeof(D3D12_RAYTRACING_INSTANCE_DESC); + + totalInstancesSize = + AlignUp(totalInstancesSize, D3D12_RAYTRACING_INSTANCE_DESCS_BYTE_ALIGNMENT); + + ResourceId instanceResourceId = + WrappedID3D12Resource::GetResIDFromAddr(accStructInput->Inputs.InstanceDescs); + + ID3D12Resource *instanceResource = + GetResourceManager()->GetCurrentAs(instanceResourceId)->GetReal(); + D3D12_GPU_VIRTUAL_ADDRESS instanceGpuAddress = instanceResource->GetGPUVirtualAddress(); + uint64_t instanceResOffset = accStructInput->Inputs.InstanceDescs - instanceGpuAddress; + + D3D12_RESOURCE_STATES instanceResState = + m_pDevice->GetSubresourceStates(instanceResourceId)[0].ToStates(); + + bool needInitialTransition = false; + if(!(instanceResState & D3D12_RESOURCE_STATE_COPY_SOURCE)) + { + needInitialTransition = true; + } + + { + rdcarray resBarriers; + + if(needInitialTransition) + { + D3D12_RESOURCE_BARRIER resBarrier; + 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 = instanceResource; + resBarrier.Transition.StateBefore = instanceResState; + resBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE; + resBarriers.push_back(resBarrier); + } + + { + D3D12_RESOURCE_BARRIER resBarrier; + 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.StateBefore = D3D12_RESOURCE_STATE_UNORDERED_ACCESS; + resBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST; + resBarriers.push_back(resBarrier); + } + + dxrCmd->ResourceBarrier((UINT)resBarriers.size(), resBarriers.data()); + } + + dxrCmd->CopyBufferRegion(patchRaytracing->m_patchedInstanceBuffer.Resource(), + patchRaytracing->m_patchedInstanceBuffer.Offset(), instanceResource, + instanceResOffset, totalInstancesSize); + + D3D12AccStructPatchInfo patchInfo = rtHandler->GetAccStructPatchInfo(); + + { + rdcarray resBarriers; + { + D3D12_RESOURCE_BARRIER resBarrier; + 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.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST; + resBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_UNORDERED_ACCESS; + resBarriers.push_back(resBarrier); + } + + if(needInitialTransition) + { + D3D12_RESOURCE_BARRIER resBarrier; + 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 = instanceResource; + resBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_SOURCE; + resBarrier.Transition.StateAfter = instanceResState; + resBarriers.push_back(resBarrier); + } + + dxrCmd->ResourceBarrier((UINT)resBarriers.size(), resBarriers.data()); + } + + RDCCOMPILE_ASSERT(sizeof(D3D12_RAYTRACING_INSTANCE_DESC) == sizeof(InstanceDesc), + "Mismatch between the hlsl, and cpp size of instance desc"); + + if(!patchInfo.m_pipeline || !patchInfo.m_rootSignature) + { + RDCERR("Pipeline or root signature for patching the TLAS not available"); + return false; + } + + { + 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(); + dxrCmd->ResourceBarrier(1, &resBarrier); + } + + ID3D12Resource *addressPairRes = m_pDevice->GetBLASAddressBufferResource(); + D3D12_GPU_VIRTUAL_ADDRESS addressPairResAddress = addressPairRes->GetGPUVirtualAddress(); + + // TODO: Update to gather the right count. + uint64_t addressCount = 0; + + dxrCmd->SetPipelineState(patchInfo.m_pipeline); + dxrCmd->SetComputeRootSignature(patchInfo.m_rootSignature); + dxrCmd->SetComputeRoot32BitConstant( + (UINT)D3D12PatchAccStructRootParamIndices::RootConstantBuffer, (UINT)addressCount, 0); + dxrCmd->SetComputeRootShaderResourceView( + (UINT)D3D12PatchAccStructRootParamIndices::RootAddressPairSrv, addressPairResAddress); + dxrCmd->SetComputeRootUnorderedAccessView( + (UINT)D3D12PatchAccStructRootParamIndices::RootPatchedAddressUav, + patchRaytracing->m_patchedInstanceBuffer.Address()); + dxrCmd->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(); + dxrCmd->ResourceBarrier(1, &resBarrier); + } + + { + D3D12_RESOURCE_BARRIER resBarrier; + 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.StateBefore = D3D12_RESOURCE_STATE_UNORDERED_ACCESS; + resBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; + dxrCmd->ResourceBarrier(1, &resBarrier); + } + + patchRaytracing->m_patched = true; + + return true; + } + + RDCDEBUG("Not a TLAS - Invalid call"); + return true; +} + template bool WrappedID3D12GraphicsCommandList::Serialise_BuildRaytracingAccelerationStructure( SerialiserType &ser, _In_ const D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC *pDesc, @@ -732,8 +896,85 @@ bool WrappedID3D12GraphicsCommandList::Serialise_BuildRaytracingAccelerationStru _In_reads_opt_(NumPostbuildInfoDescs) const D3D12_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_DESC *pPostbuildInfoDescs) { - // TODO AMD - return false; + ID3D12GraphicsCommandList4 *pCommandList = this; + SERIALISE_ELEMENT(pCommandList); + SERIALISE_ELEMENT_LOCAL(AccStructDesc, *pDesc).TypedAs("AccStructDesc"_lit).Important(); + SERIALISE_ELEMENT(NumPostbuildInfoDescs); + SERIALISE_ELEMENT_ARRAY(pPostbuildInfoDescs, NumPostbuildInfoDescs); + + ID3D12GraphicsCommandList4 *dxrCmd = Unwrap4(pCommandList); + + if(IsReplayingAndReading()) + { + m_Cmd->m_LastCmdListID = GetResourceManager()->GetOriginalID(GetResID(pCommandList)); + BakedCmdListInfo &bakedCmdInfo = m_Cmd->m_BakedCmdListInfo[m_Cmd->m_LastCmdListID]; + BakedCmdListInfo::PatchRaytracing &patchInfo = + bakedCmdInfo.m_patchRaytracingInfo[bakedCmdInfo.curEventID]; + + if(IsActiveReplaying(m_State)) + { + if(m_Cmd->InRerecordRange(m_Cmd->m_LastCmdListID)) + { + if(AccStructDesc.Inputs.Type == D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL) + { + patchInfo.m_patched = false; + PatchAccStructBlasAddress(&AccStructDesc, dxrCmd, &patchInfo); + if(patchInfo.m_patched) + { + AccStructDesc.Inputs.InstanceDescs = patchInfo.m_patchedInstanceBuffer.Address(); + } + else + { + RDCERR("TLAS Buffer isn't patched"); + return false; + } + } + + // AMD TODO: Find out do we need pre callback before build Acc struct call + dxrCmd->BuildRaytracingAccelerationStructure(&AccStructDesc, NumPostbuildInfoDescs, + pPostbuildInfoDescs); + } + } + else + { + if(AccStructDesc.Inputs.Type == D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL) + { + uint64_t totalInstancesSize = + (uint64_t)(AccStructDesc.Inputs.NumDescs * sizeof(D3D12_RAYTRACING_INSTANCE_DESC)); + + totalInstancesSize = + AlignUp(totalInstancesSize, D3D12_RAYTRACING_INSTANCE_DESCS_BYTE_ALIGNMENT); + + if(D3D12GpuBufferAllocator::Inst()->Alloc( + D3D12GpuBufferHeapType::DefaultHeapWithUav, D3D12GpuBufferHeapMemoryFlag::Default, + totalInstancesSize, D3D12_RAYTRACING_INSTANCE_DESCS_BYTE_ALIGNMENT, + patchInfo.m_patchedInstanceBuffer)) + { + PatchAccStructBlasAddress(&AccStructDesc, dxrCmd, &patchInfo); + + if(patchInfo.m_patched) + { + AccStructDesc.Inputs.InstanceDescs = patchInfo.m_patchedInstanceBuffer.Address(); + } + + // Switch back to previous state + bakedCmdInfo.state.ApplyState(m_pDevice, (ID3D12GraphicsCommandListX *)pCommandList); + } + } + + dxrCmd->BuildRaytracingAccelerationStructure(&AccStructDesc, NumPostbuildInfoDescs, + pPostbuildInfoDescs); + + m_Cmd->AddEvent(); + + ActionDescription actionDesc; + actionDesc.flags |= ActionFlags::BuildAccStruct; + m_Cmd->AddAction(actionDesc); + } + } + + SERIALISE_CHECK_READ_ERRORS(); + return true; } void WrappedID3D12GraphicsCommandList::BuildRaytracingAccelerationStructure( diff --git a/renderdoc/driver/d3d12/d3d12_commands.h b/renderdoc/driver/d3d12/d3d12_commands.h index 2beccfef6..ccd15c6f8 100644 --- a/renderdoc/driver/d3d12/d3d12_commands.h +++ b/renderdoc/driver/d3d12/d3d12_commands.h @@ -26,6 +26,8 @@ #include "common/common.h" #include "d3d12_common.h" +#include "d3d12_device.h" +#include "d3d12_resources.h" #include "d3d12_state.h" struct D3D12ActionTreeNode @@ -39,7 +41,7 @@ struct D3D12ActionTreeNode D3D12RenderState *state = NULL; - rdcarray > resourceUsage; + rdcarray> resourceUsage; rdcarray executedCmds; @@ -172,6 +174,7 @@ struct D3D12ActionCallback }; class WrappedID3D12CommandSignature; +struct AccStructPatchInfo; struct BakedCmdListInfo { @@ -197,7 +200,15 @@ struct BakedCmdListInfo rdcarray debugMessages; rdcarray actionStack; - rdcarray > resourceUsage; + rdcarray> resourceUsage; + + struct PatchRaytracing + { + bool m_patched = false; + D3D12GpuBuffer m_patchedInstanceBuffer; + }; + + rdcflatmap m_patchRaytracingInfo; ResourceId allocator; D3D12_COMMAND_LIST_TYPE type; @@ -279,7 +290,7 @@ struct D3D12CommandData // However, a single baked command list can be executed multiple times - so we have to have a // list of base events // Map from bakeID -> vector - std::map > cmdListExecs; + std::map> cmdListExecs; // This is just the baked ID of the parent command list that's partially replayed // If we are in the middle of a partial replay - allows fast checking in all CmdList chunks, @@ -352,7 +363,7 @@ struct D3D12CommandData double m_TimeFrequency = 1.0f; SDFile *m_StructuredFile; - std::map > m_ResourceUses; + std::map> m_ResourceUses; D3D12ActionTreeNode m_ParentAction; diff --git a/renderdoc/driver/d3d12/d3d12_device.cpp b/renderdoc/driver/d3d12/d3d12_device.cpp index 310dfcd52..35cd87a5e 100644 --- a/renderdoc/driver/d3d12/d3d12_device.cpp +++ b/renderdoc/driver/d3d12/d3d12_device.cpp @@ -26,6 +26,7 @@ #include #include "core/core.h" #include "core/settings.h" +#include "data/hlsl/hlsl_cbuffers.h" #include "driver/dxgi/dxgi_common.h" #include "driver/dxgi/dxgi_wrapped.h" #include "driver/ihv/amd/amd_rgp.h" @@ -863,6 +864,9 @@ WrappedID3D12Device::~WrappedID3D12Device() SAFE_RELEASE(it->second); } + SAFE_RELEASE(m_blasAddressBufferResource); + SAFE_RELEASE(m_blasAddressBufferUploadResource); + m_Replay->DestroyResources(); DestroyInternalResources(); @@ -1530,6 +1534,10 @@ void WrappedID3D12Device::ApplyInitialContents() GetResourceManager()->ApplyInitialContents(); + // Upload all buffer addresses as all of the referenced buffer resources would have been + // created and addresses had been tracked + UploadBLASBufferAddresses(); + // close the final list if(initStateCurList) { @@ -3068,6 +3076,109 @@ bool WrappedID3D12Device::DiscardFrameCapture(DeviceOwnedWindow devWnd) return true; } +void WrappedID3D12Device::UploadBLASBufferAddresses() +{ + if(m_addressBufferUploaded) + return; + + rdcarray blasAddressPair; + D3D12ResourceManager *resManager = GetResourceManager(); + + for(size_t i = 0; i < m_OrigGPUAddresses.addresses.size(); i++) + { + GPUAddressRange addressRange = m_OrigGPUAddresses.addresses[i]; + ResourceId resId = addressRange.id; + if(resManager->HasLiveResource(resId)) + { + WrappedID3D12Resource *wrappedRes = (WrappedID3D12Resource *)resManager->GetLiveResource(resId); + if(wrappedRes->IsAccelerationStructureResource()) + { + BlasAddressPair addressPair; + addressPair.oldAddress.start = addressRange.start; + addressPair.oldAddress.end = addressRange.realEnd; + + addressPair.newAddress.start = wrappedRes->GetGPUVirtualAddress(); + addressPair.newAddress.end = addressPair.newAddress.start + wrappedRes->GetDesc().Width; + blasAddressPair.push_back(addressPair); + } + } + } + + uint64_t requiredSize = blasAddressPair.size() * sizeof(BlasAddressPair); + + D3D12_RESOURCE_DESC addressBufferResDesc; + addressBufferResDesc.Alignment = 0; + addressBufferResDesc.DepthOrArraySize = 1; + addressBufferResDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + addressBufferResDesc.Flags = D3D12_RESOURCE_FLAG_NONE; + addressBufferResDesc.Format = DXGI_FORMAT_UNKNOWN; + addressBufferResDesc.Height = 1; + addressBufferResDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + addressBufferResDesc.MipLevels = 1; + addressBufferResDesc.SampleDesc.Count = 1; + addressBufferResDesc.SampleDesc.Quality = 0; + addressBufferResDesc.Width = requiredSize; + + D3D12_HEAP_PROPERTIES heapProps; + heapProps.Type = D3D12_HEAP_TYPE_UPLOAD; + heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; + heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; + heapProps.CreationNodeMask = 1; + heapProps.VisibleNodeMask = 1; + + HRESULT hr = CreateCommittedResource( + &heapProps, D3D12_HEAP_FLAG_NONE, &addressBufferResDesc, D3D12_RESOURCE_STATE_GENERIC_READ, + NULL, __uuidof(ID3D12Resource), (void **)&m_blasAddressBufferUploadResource); + + if(!SUCCEEDED(hr)) + { + RDCERR("Unable to create upload buffer for BLAS address"); + } + else + { + D3D12_RANGE readRange = {0, 0}; + void *ptr = NULL; + HRESULT result = m_blasAddressBufferUploadResource->Map(0, &readRange, &ptr); + + if(!SUCCEEDED(result)) + { + RDCERR("Unable to map the resource for uploading old addresses"); + } + else + { + memcpy((byte *)ptr, blasAddressPair.data(), (size_t)requiredSize); + m_blasAddressBufferUploadResource->Unmap(0, NULL); + } + } + + heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; + hr = CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &addressBufferResDesc, + D3D12_RESOURCE_STATE_COPY_DEST, NULL, __uuidof(ID3D12Resource), + (void **)&m_blasAddressBufferResource); + + if(!SUCCEEDED(hr)) + { + RDCERR("Unable to create upload buffer for BLAS address"); + } + else + { + ID3D12GraphicsCommandList *initList = GetInitialStateList(); + initList->CopyBufferRegion(m_blasAddressBufferResource, 0, m_blasAddressBufferUploadResource, 0, + requiredSize); + + D3D12_RESOURCE_BARRIER resBarrier; + resBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + resBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; + resBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST; + resBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_GENERIC_READ; + resBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + resBarrier.Transition.pResource = m_blasAddressBufferResource; + initList->ResourceBarrier(1, &resBarrier); + } + + m_addressBufferUploaded = true; +} + void WrappedID3D12Device::ReleaseResource(ID3D12DeviceChild *res) { ResourceId id = GetResID(res); @@ -3920,6 +4031,7 @@ void WrappedID3D12Device::CreateInternalResources() m_Replay->CreateResources(); WrappedID3D12Shader::InternalResources(false); + GetResourceManager()->GetRaytracingResourceAndUtilHandler()->InitInternalResources(); } void WrappedID3D12Device::DestroyInternalResources() diff --git a/renderdoc/driver/d3d12/d3d12_device.h b/renderdoc/driver/d3d12/d3d12_device.h index 0f4e9471a..ca59d51bd 100644 --- a/renderdoc/driver/d3d12/d3d12_device.h +++ b/renderdoc/driver/d3d12/d3d12_device.h @@ -1233,6 +1233,12 @@ public: m_SparseHeaps.insert(heap); } + void UploadBLASBufferAddresses(); + ID3D12Resource *GetBLASAddressBufferResource() const { return m_blasAddressBufferResource; } + ID3D12Resource *m_blasAddressBufferResource = NULL; + ID3D12Resource *m_blasAddressBufferUploadResource = NULL; + bool m_addressBufferUploaded = false; + void ReleaseResource(ID3D12DeviceChild *pResource); // helper function that takes an expanded descriptor, but downcasts it to the regular descriptor diff --git a/renderdoc/driver/d3d12/d3d12_manager.cpp b/renderdoc/driver/d3d12/d3d12_manager.cpp index 7cb09e7c5..c9eb6827a 100644 --- a/renderdoc/driver/d3d12/d3d12_manager.cpp +++ b/renderdoc/driver/d3d12/d3d12_manager.cpp @@ -24,11 +24,13 @@ #include "d3d12_manager.h" #include +#include "driver/dx/official/d3dcompiler.h" #include "driver/dxgi/dxgi_common.h" #include "d3d12_command_list.h" #include "d3d12_command_queue.h" #include "d3d12_device.h" #include "d3d12_resources.h" +#include "d3d12_shader_cache.h" void D3D12Descriptor::Init(const D3D12_SAMPLER_DESC2 *pDesc) { @@ -753,6 +755,94 @@ void D3D12RaytracingResourceAndUtilHandler::SyncGpuForRtWork() WaitForSingleObject(m_gpuSyncHandle, 10000); } +void D3D12RaytracingResourceAndUtilHandler::InitInternalResources() +{ + if(IsReplayMode(m_wrappedDevice->GetState())) + { + InitReplayBlasPatchingResources(); + } +} + +void D3D12RaytracingResourceAndUtilHandler::InitReplayBlasPatchingResources() +{ + // Root Signature + rdcarray rootParameters; + rootParameters.reserve((uint16_t)D3D12PatchAccStructRootParamIndices::Count); + + { + D3D12_ROOT_PARAMETER1 rootParam; + rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; + rootParam.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + rootParam.Constants.ShaderRegister = 0; + rootParam.Constants.RegisterSpace = 0; + rootParam.Constants.Num32BitValues = 1; + rootParameters.push_back(rootParam); + } + + { + D3D12_ROOT_PARAMETER1 rootParam; + rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_SRV; + rootParam.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + rootParam.Descriptor.ShaderRegister = 0; + rootParam.Descriptor.RegisterSpace = 0; + rootParam.Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE; + rootParameters.push_back(rootParam); + } + + { + D3D12_ROOT_PARAMETER1 rootParam; + rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_UAV; + rootParam.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + rootParam.Descriptor.ShaderRegister = 0; + rootParam.Descriptor.RegisterSpace = 0; + rootParam.Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE; + rootParameters.push_back(rootParam); + } + + D3D12ShaderCache *shaderCache = m_wrappedDevice->GetShaderCache(); + + if(shaderCache != NULL) + { + ID3DBlob *rootSig = shaderCache->MakeRootSig(rootParameters, D3D12_ROOT_SIGNATURE_FLAG_NONE); + + if(rootSig) + { + HRESULT result = m_wrappedDevice->GetReal()->CreateRootSignature( + 0, rootSig->GetBufferPointer(), rootSig->GetBufferSize(), __uuidof(ID3D12RootSignature), + (void **)&m_accStructPatchInfo.m_rootSignature); + + if(!SUCCEEDED(result)) + RDCERR("Unable to create root signature for patching the BLAS"); + + // PipelineState + ID3DBlob *shader = NULL; + rdcstr hlsl = GetEmbeddedResource(raytracing_hlsl); + shaderCache->GetShaderBlob(hlsl.c_str(), "RENDERDOC_PatchAccStructAddressCS", + D3DCOMPILE_WARNINGS_ARE_ERRORS, {}, "cs_6_0", &shader); + + if(shader) + { + D3D12_COMPUTE_PIPELINE_STATE_DESC pipeline; + pipeline.Flags = D3D12_PIPELINE_STATE_FLAG_NONE; + pipeline.NodeMask = 0; + pipeline.CS = {(void *)shader->GetBufferPointer(), shader->GetBufferSize()}; + pipeline.CachedPSO = {NULL, 0}; + pipeline.pRootSignature = m_accStructPatchInfo.m_rootSignature; + + result = m_wrappedDevice->GetReal()->CreateComputePipelineState( + &pipeline, __uuidof(ID3D12PipelineState), (void **)&m_accStructPatchInfo.m_pipeline); + + if(!SUCCEEDED(result)) + RDCERR("Unable to create pipeline for patching the BLAS"); + } + } + } + else + { + RDCERR("Shadercache not available"); + } +} + D3D12GpuBufferAllocator *D3D12GpuBufferAllocator::m_bufferAllocator = NULL; bool D3D12GpuBufferAllocator::CopyBufferRegion(WrappedID3D12GraphicsCommandList *wrappedCmd, diff --git a/renderdoc/driver/d3d12/d3d12_manager.h b/renderdoc/driver/d3d12/d3d12_manager.h index aa4027029..76c2a3415 100644 --- a/renderdoc/driver/d3d12/d3d12_manager.h +++ b/renderdoc/driver/d3d12/d3d12_manager.h @@ -1020,6 +1020,21 @@ private: uint64_t m_totalAllocatedMemoryInUse; }; +enum class D3D12PatchAccStructRootParamIndices +{ + RootConstantBuffer, + RootAddressPairSrv, + RootPatchedAddressUav, + Count +}; + +struct D3D12AccStructPatchInfo +{ + D3D12AccStructPatchInfo() : m_rootSignature(NULL), m_pipeline(NULL) {} + ID3D12RootSignature *m_rootSignature; + ID3D12PipelineState *m_pipeline; +}; + class D3D12RaytracingResourceAndUtilHandler { public: @@ -1029,6 +1044,7 @@ public: ID3D12CommandAllocator *GetCmdAlloc() const { return m_cmdAlloc; } ID3D12CommandQueue *GetCmdQueue() const { return m_cmdQueue; } ID3D12Fence *GetFence() const { return m_gpuFence; } + D3D12AccStructPatchInfo GetAccStructPatchInfo() const { return m_accStructPatchInfo; } void SyncGpuForRtWork(); ~D3D12RaytracingResourceAndUtilHandler() @@ -1039,7 +1055,10 @@ public: SAFE_RELEASE(m_gpuFence); } + void InitInternalResources(); + private: + void InitReplayBlasPatchingResources(); WrappedID3D12Device *m_wrappedDevice; ID3D12GraphicsCommandListX *m_cmdList; @@ -1048,6 +1067,7 @@ private: ID3D12Fence *m_gpuFence; HANDLE m_gpuSyncHandle; UINT64 m_gpuSyncCounter; + D3D12AccStructPatchInfo m_accStructPatchInfo; }; struct D3D12ResourceManagerConfiguration diff --git a/renderdoc/renderdoc.vcxproj b/renderdoc/renderdoc.vcxproj index 65709359d..c5beeee10 100644 --- a/renderdoc/renderdoc.vcxproj +++ b/renderdoc/renderdoc.vcxproj @@ -732,6 +732,7 @@ + diff --git a/renderdoc/renderdoc.vcxproj.filters b/renderdoc/renderdoc.vcxproj.filters index b29a17b0b..fda737b05 100644 --- a/renderdoc/renderdoc.vcxproj.filters +++ b/renderdoc/renderdoc.vcxproj.filters @@ -1137,6 +1137,7 @@ Resources\glsl + Resources\hlsl