diff --git a/renderdoc/driver/d3d12/d3d12_command_list.h b/renderdoc/driver/d3d12/d3d12_command_list.h index 3a9417080..3e5914fa2 100644 --- a/renderdoc/driver/d3d12/d3d12_command_list.h +++ b/renderdoc/driver/d3d12/d3d12_command_list.h @@ -191,6 +191,8 @@ private: static rdcstr GetChunkName(uint32_t idx); D3D12ResourceManager *GetResourceManager() { return m_pDevice->GetResourceManager(); } + + rdcarray> m_accStructPostBuildQueueFunc; public: ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D12GraphicsCommandList); @@ -237,6 +239,24 @@ public: bool ValidateRootGPUVA(D3D12_GPU_VIRTUAL_ADDRESS buffer); + void EnqueueAccStructPostBuild(const std::function &postBldExec) + { + m_accStructPostBuildQueueFunc.push_back(postBldExec); + } + + bool ExecuteAccStructPostBuilds() + { + bool success = true; + + for(std::function &func : m_accStructPostBuildQueueFunc) + { + success &= func(); + } + + m_accStructPostBuildQueueFunc.clear(); + return success; + } + ////////////////////////////// // implement IUnknown ULONG STDMETHODCALLTYPE AddRef() { return m_RefCounter.SoftRef(m_pDevice); } diff --git a/renderdoc/driver/d3d12/d3d12_command_list4_wrap.cpp b/renderdoc/driver/d3d12/d3d12_command_list4_wrap.cpp index 6b24f9a56..843be3b45 100644 --- a/renderdoc/driver/d3d12/d3d12_command_list4_wrap.cpp +++ b/renderdoc/driver/d3d12/d3d12_command_list4_wrap.cpp @@ -742,8 +742,88 @@ void WrappedID3D12GraphicsCommandList::BuildRaytracingAccelerationStructure( _In_reads_opt_(NumPostbuildInfoDescs) const D3D12_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_DESC *pPostbuildInfoDescs) { - // TODO AMD - RDCERR("BuildRaytracingAccelerationStructure called but raytracing is not supported!"); + SERIALISE_TIME_CALL(m_pList4->BuildRaytracingAccelerationStructure(pDesc, NumPostbuildInfoDescs, + pPostbuildInfoDescs)); + + if(IsCaptureMode(m_State)) + { + // Acceleration structure (AS) are created on buffer created with Acceleration structure init + // state which helps them differentiate between non-Acceleration structure buffers (non-ASB). + + // AS creation at recording can happen at any offset, given offset + its size is less than the + // resource size. It can also be recorded for overwriting on same or another command list, + // invalidating occupying previous acceleration structure(s) in order of command list execution. + // It can also be updated but there are many update constraints around it. + + CACHE_THREAD_SERIALISER(); + SCOPED_SERIALISE_CHUNK(D3D12Chunk::List_BuildRaytracingAccelerationStructure); + + D3D12ResourceManager *resManager = m_pDevice->GetResourceManager(); + ResourceId asbWrappedResourceId; + D3D12BufferOffset asbWrappedResourceBufferOffset; + + WrappedID3D12Resource::GetResIDFromAddr(pDesc->DestAccelerationStructureData, + asbWrappedResourceId, asbWrappedResourceBufferOffset); + + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO preBldInfo; + m_pDevice->GetRaytracingAccelerationStructurePrebuildInfo(&pDesc->Inputs, &preBldInfo); + + auto PostBldExecute = [resManager, asbWrappedResourceId, asbWrappedResourceBufferOffset, + preBldInfo]() -> bool { + bool success = false; + D3D12AccelerationStructure *accStructAtOffset = NULL; + + WrappedID3D12Resource *asbWrappedResource = + resManager->GetCurrentAs(asbWrappedResourceId); + + // See if acc already exist at the given offset + bool accStructExistAtOffset = asbWrappedResource->GetAccStructIfExist( + asbWrappedResourceBufferOffset, &accStructAtOffset); + + bool createAccStruct = false; + + if(accStructExistAtOffset) + { + if(accStructAtOffset && accStructAtOffset->Size() != preBldInfo.ResultDataMaxSizeInBytes) + { + asbWrappedResource->DeleteAccStructAtOffset(asbWrappedResourceBufferOffset); + createAccStruct = true; + } + } + else + { + createAccStruct = true; + } + + if(createAccStruct) + { + // CreateAccStruct also deletes any previous overlapping ASs on the ASB + if(asbWrappedResource->CreateAccStruct(asbWrappedResourceBufferOffset, preBldInfo, + &accStructAtOffset)) + { + success = true; + D3D12ResourceRecord *record = + resManager->AddResourceRecord(accStructAtOffset->GetResourceID()); + record->type = Resource_AccelerationStructure; + record->Length = 0; + accStructAtOffset->SetResourceRecord(record); + resManager->MarkDirtyResource(accStructAtOffset->GetResourceID()); + + record->AddParent( + resManager->GetResourceRecord(accStructAtOffset->GetBackingBufferResourceId())); + } + else + { + RDCERR("Unable to create acceleration structure"); + success = false; + } + } + + return success; + }; + + EnqueueAccStructPostBuild(PostBldExecute); + } } template diff --git a/renderdoc/driver/d3d12/d3d12_command_queue_wrap.cpp b/renderdoc/driver/d3d12/d3d12_command_queue_wrap.cpp index 6e5dfe548..1e8faba9e 100644 --- a/renderdoc/driver/d3d12/d3d12_command_queue_wrap.cpp +++ b/renderdoc/driver/d3d12/d3d12_command_queue_wrap.cpp @@ -738,6 +738,17 @@ void WrappedID3D12CommandQueue::ExecuteCommandListsInternal(UINT NumCommandLists if(!SkipRealExecute) { SERIALISE_TIME_CALL(m_pReal->ExecuteCommandLists(NumCommandLists, unwrapped)); + + for(UINT i = 0; i < NumCommandLists; i++) + { + WrappedID3D12GraphicsCommandList *wrapped = + (WrappedID3D12GraphicsCommandList *)(ppCommandLists[i]); + + if(!wrapped->ExecuteAccStructPostBuilds()) + { + RDCERR("Unable to execute post build for acc struct"); + } + } } if(IsCaptureMode(m_State)) diff --git a/renderdoc/driver/d3d12/d3d12_device.h b/renderdoc/driver/d3d12/d3d12_device.h index f722bcdc5..0f4e9471a 100644 --- a/renderdoc/driver/d3d12/d3d12_device.h +++ b/renderdoc/driver/d3d12/d3d12_device.h @@ -848,6 +848,15 @@ public: WriteSerialiser &GetThreadSerialiser(); ID3D12Device *GetReal() { return m_pDevice; } + ID3D12Device1 *GetReal1() const { return m_pDevice1; } + ID3D12Device2 *GetReal2() const { return m_pDevice2; } + ID3D12Device3 *GetReal3() const { return m_pDevice3; } + ID3D12Device4 *GetReal4() const { return m_pDevice4; } + ID3D12Device5 *GetReal5() const { return m_pDevice5; } + ID3D12Device6 *GetReal6() const { return m_pDevice6; } + ID3D12Device7 *GetReal7() const { return m_pDevice7; } + ID3D12Device8 *GetReal8() const { return m_pDevice8; } + ID3D12Device9 *GetReal9() const { return m_pDevice9; } static rdcstr GetChunkName(uint32_t idx); D3D12ResourceManager *GetResourceManager() { return m_ResourceManager; } D3D12ShaderCache *GetShaderCache() { return m_ShaderCache; } diff --git a/renderdoc/driver/d3d12/d3d12_resources.cpp b/renderdoc/driver/d3d12/d3d12_resources.cpp index 8716998f6..5d706784d 100644 --- a/renderdoc/driver/d3d12/d3d12_resources.cpp +++ b/renderdoc/driver/d3d12/d3d12_resources.cpp @@ -232,6 +232,47 @@ WriteSerialiser &WrappedID3D12Resource::GetThreadSerialiser() return m_pDevice->GetThreadSerialiser(); } +size_t WrappedID3D12Resource::DeleteOverlappingAccStructsInRangeAtOffset(D3D12BufferOffset bufferOffset) +{ + SCOPED_LOCK(m_accStructResourcesCS); + + if(!m_accelerationStructMap.empty()) + { + rdcarray toBeDeleted; + uint64_t accStructAtOffsetSize = m_accelerationStructMap[bufferOffset]->Size(); + + for(const rdcpair &accStructAtOffset : + m_accelerationStructMap) + { + if(accStructAtOffset.first == bufferOffset) + { + continue; + } + + if(accStructAtOffset.first < bufferOffset && + (accStructAtOffset.first + accStructAtOffset.second->Size()) > bufferOffset) + { + toBeDeleted.push_back(accStructAtOffset.first); + } + + if(accStructAtOffset.first > bufferOffset && + (bufferOffset + accStructAtOffsetSize) > accStructAtOffset.first) + { + toBeDeleted.push_back(accStructAtOffset.first); + } + } + + for(D3D12BufferOffset deleting : toBeDeleted) + { + DeleteAccStructAtOffset(deleting); + } + + return toBeDeleted.size(); + } + + return 0; +} + HRESULT STDMETHODCALLTYPE WrappedID3D12Resource::Map(UINT Subresource, const D3D12_RANGE *pReadRange, void **ppData) { @@ -320,8 +361,8 @@ D3D12AccelerationStructure::D3D12AccelerationStructure( D3D12BufferOffset bufferOffset, const D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO &preBldInfo) : WrappedDeviceChild12(NULL, wrappedDevice), - m_bufferRes(bufferRes), - m_bufferOffset(bufferOffset), + m_asbWrappedResource(bufferRes), + m_asbWrappedResourceBufferOffset(bufferOffset), m_preBldInfo(preBldInfo) { } @@ -330,6 +371,72 @@ D3D12AccelerationStructure::~D3D12AccelerationStructure() { Shutdown(); } + +bool WrappedID3D12Resource::CreateAccStruct( + D3D12BufferOffset bufferOffset, + const D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO &preBldInfo, + D3D12AccelerationStructure **accStruct) +{ + SCOPED_LOCK(m_accStructResourcesCS); + if(m_accelerationStructMap.find(bufferOffset) == m_accelerationStructMap.end()) + { + m_accelerationStructMap[bufferOffset] = + new D3D12AccelerationStructure(m_pDevice, this, bufferOffset, preBldInfo); + + if(accStruct) + { + *accStruct = m_accelerationStructMap[bufferOffset]; + + if(IsCaptureMode(m_pDevice->GetState())) + { + size_t deletedAccStructCount = DeleteOverlappingAccStructsInRangeAtOffset(bufferOffset); + RDCDEBUG("Acc structure created after deleting %u overlapping acc structure(s)", + deletedAccStructCount); + deletedAccStructCount; + } + } + + return true; + } + + return false; +} + +bool WrappedID3D12Resource::GetAccStructIfExist(D3D12BufferOffset bufferOffset, + D3D12AccelerationStructure **accStruct) +{ + SCOPED_LOCK(m_accStructResourcesCS); + bool found = false; + + if(m_accelerationStructMap.find(bufferOffset) != m_accelerationStructMap.end()) + { + found = true; + if(accStruct) + { + *accStruct = m_accelerationStructMap[bufferOffset]; + } + } + + return found; +} + +bool WrappedID3D12Resource::DeleteAccStructAtOffset(D3D12BufferOffset bufferOffset) +{ + SCOPED_LOCK(m_accStructResourcesCS); + D3D12AccelerationStructure *accStruct = NULL; + if(GetAccStructIfExist(bufferOffset, &accStruct)) + { + if(m_accelerationStructMap[bufferOffset]->Release() == 0) + { + m_accelerationStructMap.erase(bufferOffset); + } + + return true; + } + + return false; +} + void WrappedID3D12Resource::RefBuffers(D3D12ResourceManager *rm) { // only buffers go into m_Addresses diff --git a/renderdoc/driver/d3d12/d3d12_resources.h b/renderdoc/driver/d3d12/d3d12_resources.h index 2174beeaa..25305ac64 100644 --- a/renderdoc/driver/d3d12/d3d12_resources.h +++ b/renderdoc/driver/d3d12/d3d12_resources.h @@ -928,15 +928,20 @@ public: virtual ~WrappedID3D12QueryHeap() { Shutdown(); } }; +class D3D12AccelerationStructure; + class WrappedID3D12Resource : public WrappedDeviceChild12 { static GPUAddressRangeTracker m_Addresses; WriteSerialiser &GetThreadSerialiser(); + size_t DeleteOverlappingAccStructsInRangeAtOffset(D3D12BufferOffset bufferOffset); WrappedID3D12Heap *m_Heap = NULL; + Threading::CriticalSection m_accStructResourcesCS; + rdcflatmap m_accelerationStructMap; bool m_isAccelerationStructureResource = false; public: @@ -963,6 +968,15 @@ public: return this->GetResourceID(); } + bool CreateAccStruct(D3D12BufferOffset bufferOffset, + const D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO &preBldInfo, + D3D12AccelerationStructure **accStruct); + + bool GetAccStructIfExist(D3D12BufferOffset bufferOffset, + D3D12AccelerationStructure **accStruct = NULL); + + bool DeleteAccStructAtOffset(D3D12BufferOffset bufferOffset); + bool IsAccelerationStructureResource() const { return m_isAccelerationStructureResource; } void MarkAsAccelerationStructureResource() { m_isAccelerationStructureResource = true; } @@ -1281,9 +1295,12 @@ public: ~D3D12AccelerationStructure(); + uint64_t Size() const { return m_preBldInfo.ResultDataMaxSizeInBytes; } + ResourceId GetBackingBufferResourceId() const { return m_asbWrappedResource->GetResourceID(); } + private: - WrappedID3D12Resource *m_bufferRes; - D3D12BufferOffset m_bufferOffset; + WrappedID3D12Resource *m_asbWrappedResource; + D3D12BufferOffset m_asbWrappedResourceBufferOffset; D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO m_preBldInfo; };