|
@@ -0,0 +1,212 @@
|
|
|
|
|
+#include "DX12TLAS.h"
|
|
|
|
|
+
|
|
|
|
|
+#include "DX12CommandQueue.h"
|
|
|
|
|
+
|
|
|
|
|
+Framework::DX12TLAS::DX12TLAS(
|
|
|
|
|
+ ID3D12Device5* zDevice, Framework::DX12DirectCommandQueue* zDirectQueue)
|
|
|
|
|
+ : ReferenceCounter(),
|
|
|
|
|
+ scratchBuffer(0),
|
|
|
|
|
+ resultBuffer(0),
|
|
|
|
|
+ descriptorBuffer(0),
|
|
|
|
|
+ previousResultBuffer(0),
|
|
|
|
|
+ zDevice(zDevice),
|
|
|
|
|
+ zDirectQueue(zDirectQueue),
|
|
|
|
|
+ overflowInstanceIterator(0, 0),
|
|
|
|
|
+ currentInstanceIndex(0),
|
|
|
|
|
+ mappedDescriptorBuffer(0)
|
|
|
|
|
+{}
|
|
|
|
|
+
|
|
|
|
|
+Framework::DX12TLAS::~DX12TLAS()
|
|
|
|
|
+{
|
|
|
|
|
+ if (scratchBuffer)
|
|
|
|
|
+ {
|
|
|
|
|
+ scratchBuffer->release();
|
|
|
|
|
+ }
|
|
|
|
|
+ if (resultBuffer)
|
|
|
|
|
+ {
|
|
|
|
|
+ resultBuffer->release();
|
|
|
|
|
+ }
|
|
|
|
|
+ if (descriptorBuffer)
|
|
|
|
|
+ {
|
|
|
|
|
+ descriptorBuffer->release();
|
|
|
|
|
+ }
|
|
|
|
|
+ if (previousResultBuffer)
|
|
|
|
|
+ {
|
|
|
|
|
+ previousResultBuffer->release();
|
|
|
|
|
+ }
|
|
|
|
|
+ for (const D3D12_RAYTRACING_INSTANCE_DESC* desc : overflowInstanceDescs)
|
|
|
|
|
+ {
|
|
|
|
|
+ delete desc;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void Framework::DX12TLAS::startUpdate()
|
|
|
|
|
+{
|
|
|
|
|
+ currentInstanceIndex = -1;
|
|
|
|
|
+ if (descriptorBuffer)
|
|
|
|
|
+ {
|
|
|
|
|
+ descriptorBuffer->zBuffer()->Map(0, 0, (void**)&mappedDescriptorBuffer);
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ mappedDescriptorBuffer = 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ overflowInstanceIterator = overflowInstanceDescs.begin();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+D3D12_RAYTRACING_INSTANCE_DESC* Framework::DX12TLAS::nextInstanceDesc()
|
|
|
|
|
+{
|
|
|
|
|
+ currentInstanceIndex++;
|
|
|
|
|
+ if (mappedDescriptorBuffer
|
|
|
|
|
+ && currentInstanceIndex < descriptorBuffer->getElementCount())
|
|
|
|
|
+ {
|
|
|
|
|
+ return mappedDescriptorBuffer
|
|
|
|
|
+ + currentInstanceIndex * sizeof(D3D12_RAYTRACING_INSTANCE_DESC);
|
|
|
|
|
+ }
|
|
|
|
|
+ else if (overflowInstanceIterator)
|
|
|
|
|
+ {
|
|
|
|
|
+ return *overflowInstanceIterator++;
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ D3D12_RAYTRACING_INSTANCE_DESC* desc
|
|
|
|
|
+ = new D3D12_RAYTRACING_INSTANCE_DESC();
|
|
|
|
|
+ overflowInstanceDescs.add(desc);
|
|
|
|
|
+ return desc;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void Framework::DX12TLAS::endUpdate()
|
|
|
|
|
+{
|
|
|
|
|
+ while (currentInstanceIndex < descriptorBuffer->getElementCount() - 1)
|
|
|
|
|
+ {
|
|
|
|
|
+ D3D12_RAYTRACING_INSTANCE_DESC* desc = nextInstanceDesc();
|
|
|
|
|
+ desc->InstanceMask = 0; // Mark unused instances with a mask of 0
|
|
|
|
|
+ }
|
|
|
|
|
+ descriptorBuffer->zBuffer()->Unmap(0, nullptr);
|
|
|
|
|
+ mappedDescriptorBuffer = 0;
|
|
|
|
|
+ if (currentInstanceIndex >= descriptorBuffer->getElementCount())
|
|
|
|
|
+ {
|
|
|
|
|
+ // recalculate the size of the descriptor buffer and reallocate it
|
|
|
|
|
+ D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS
|
|
|
|
|
+ prebuildDesc = {};
|
|
|
|
|
+ prebuildDesc.Type
|
|
|
|
|
+ = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL;
|
|
|
|
|
+ prebuildDesc.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY;
|
|
|
|
|
+ prebuildDesc.NumDescs = (unsigned)currentInstanceIndex + 1;
|
|
|
|
|
+ prebuildDesc.Flags
|
|
|
|
|
+ = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_ALLOW_UPDATE;
|
|
|
|
|
+
|
|
|
|
|
+ D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO info = {};
|
|
|
|
|
+
|
|
|
|
|
+ zDevice->GetRaytracingAccelerationStructurePrebuildInfo(
|
|
|
|
|
+ &prebuildDesc, &info);
|
|
|
|
|
+
|
|
|
|
|
+ // create new buffers witch fit the TLAS
|
|
|
|
|
+ if (resultBuffer)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (previousResultBuffer)
|
|
|
|
|
+ {
|
|
|
|
|
+ previousResultBuffer->release();
|
|
|
|
|
+ }
|
|
|
|
|
+ previousResultBuffer = resultBuffer;
|
|
|
|
|
+ }
|
|
|
|
|
+ resultBuffer = new DX12Buffer(
|
|
|
|
|
+ 1, zDevice, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS);
|
|
|
|
|
+ resultBuffer->setLength(
|
|
|
|
|
+ ROUND_UP_POWER_OF_2(info.ResultDataMaxSizeInBytes, 256));
|
|
|
|
|
+ resultBuffer->createBufferWithoutData(
|
|
|
|
|
+ D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE);
|
|
|
|
|
+ if (!scratchBuffer)
|
|
|
|
|
+ {
|
|
|
|
|
+ scratchBuffer = new DX12Buffer(
|
|
|
|
|
+ 1, zDevice, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS);
|
|
|
|
|
+ }
|
|
|
|
|
+ scratchBuffer->setLength(
|
|
|
|
|
+ ROUND_UP_POWER_OF_2(info.ScratchDataSizeInBytes, 256));
|
|
|
|
|
+ scratchBuffer->createBufferWithoutData(
|
|
|
|
|
+ D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
|
|
|
|
|
+ ID3D12Resource* oldDescriptorBuffer
|
|
|
|
|
+ = descriptorBuffer ? descriptorBuffer->zBuffer() : 0;
|
|
|
|
|
+ __int64 oldDescriptorBufferElementCount
|
|
|
|
|
+ = descriptorBuffer ? descriptorBuffer->getElementCount() : 0;
|
|
|
|
|
+ if (oldDescriptorBuffer)
|
|
|
|
|
+ {
|
|
|
|
|
+ oldDescriptorBuffer->AddRef();
|
|
|
|
|
+ oldDescriptorBuffer->Map(0, 0, (void**)&mappedDescriptorBuffer);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!descriptorBuffer)
|
|
|
|
|
+ {
|
|
|
|
|
+ descriptorBuffer
|
|
|
|
|
+ = new DX12Buffer(sizeof(D3D12_RAYTRACING_INSTANCE_DESC),
|
|
|
|
|
+ zDevice,
|
|
|
|
|
+ D3D12_RESOURCE_FLAG_NONE);
|
|
|
|
|
+ }
|
|
|
|
|
+ descriptorBuffer->setLength(ROUND_UP_POWER_OF_2(
|
|
|
|
|
+ (currentInstanceIndex + 1) * sizeof(D3D12_RAYTRACING_INSTANCE_DESC),
|
|
|
|
|
+ 256));
|
|
|
|
|
+ descriptorBuffer->createBufferWithoutData(
|
|
|
|
|
+ D3D12_RESOURCE_STATE_GENERIC_READ);
|
|
|
|
|
+ D3D12_RAYTRACING_INSTANCE_DESC* newMappedDescriptorBuffer = 0;
|
|
|
|
|
+
|
|
|
|
|
+ // copy the old and new instance descriptions to the new buffer
|
|
|
|
|
+ descriptorBuffer->zBuffer()->Map(
|
|
|
|
|
+ 0, 0, (void**)&newMappedDescriptorBuffer);
|
|
|
|
|
+ if (mappedDescriptorBuffer)
|
|
|
|
|
+ {
|
|
|
|
|
+ memcpy(newMappedDescriptorBuffer,
|
|
|
|
|
+ mappedDescriptorBuffer,
|
|
|
|
|
+ oldDescriptorBufferElementCount
|
|
|
|
|
+ * sizeof(D3D12_RAYTRACING_INSTANCE_DESC));
|
|
|
|
|
+ D3D12_RANGE range = {0, 0}; // do not write to the old buffer
|
|
|
|
|
+ oldDescriptorBuffer->Unmap(0, &range);
|
|
|
|
|
+ oldDescriptorBuffer->Release();
|
|
|
|
|
+ }
|
|
|
|
|
+ overflowInstanceIterator = overflowInstanceDescs.begin();
|
|
|
|
|
+ for (__int64 i = oldDescriptorBufferElementCount;
|
|
|
|
|
+ i <= currentInstanceIndex;
|
|
|
|
|
+ i++)
|
|
|
|
|
+ {
|
|
|
|
|
+ memcpy(newMappedDescriptorBuffer + i,
|
|
|
|
|
+ overflowInstanceIterator.val(),
|
|
|
|
|
+ sizeof(D3D12_RAYTRACING_INSTANCE_DESC));
|
|
|
|
|
+ overflowInstanceIterator++;
|
|
|
|
|
+ }
|
|
|
|
|
+ descriptorBuffer->zBuffer()->Unmap(0, nullptr);
|
|
|
|
|
+ }
|
|
|
|
|
+ D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC buildDesc = {};
|
|
|
|
|
+ buildDesc.Inputs.Type
|
|
|
|
|
+ = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL;
|
|
|
|
|
+ buildDesc.Inputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY;
|
|
|
|
|
+ buildDesc.Inputs.InstanceDescs
|
|
|
|
|
+ = descriptorBuffer->zBuffer()->GetGPUVirtualAddress();
|
|
|
|
|
+ buildDesc.Inputs.NumDescs = (unsigned)currentInstanceIndex + 1;
|
|
|
|
|
+ buildDesc.DestAccelerationStructureData
|
|
|
|
|
+ = {resultBuffer->zBuffer()->GetGPUVirtualAddress()};
|
|
|
|
|
+ buildDesc.ScratchAccelerationStructureData
|
|
|
|
|
+ = {scratchBuffer->zBuffer()->GetGPUVirtualAddress()};
|
|
|
|
|
+ buildDesc.SourceAccelerationStructureData
|
|
|
|
|
+ = previousResultBuffer
|
|
|
|
|
+ ? previousResultBuffer->zBuffer()->GetGPUVirtualAddress()
|
|
|
|
|
+ : 0;
|
|
|
|
|
+ buildDesc.Inputs.Flags
|
|
|
|
|
+ = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PERFORM_UPDATE;
|
|
|
|
|
+
|
|
|
|
|
+ // Build the top-level AS
|
|
|
|
|
+ zDirectQueue->zCommandList()->BuildRaytracingAccelerationStructure(
|
|
|
|
|
+ &buildDesc, 0, nullptr);
|
|
|
|
|
+
|
|
|
|
|
+ // Wait for the builder to complete by setting a barrier on the resulting
|
|
|
|
|
+ // buffer. This can be important in case the rendering is triggered
|
|
|
|
|
+ // immediately afterwards, without executing the command list
|
|
|
|
|
+ D3D12_RESOURCE_BARRIER uavBarrier;
|
|
|
|
|
+ uavBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV;
|
|
|
|
|
+ uavBarrier.UAV.pResource = resultBuffer->zBuffer();
|
|
|
|
|
+ uavBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
|
|
|
|
+ zDirectQueue->zCommandList()->ResourceBarrier(1, &uavBarrier);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+Framework::DX12Buffer* Framework::DX12TLAS::zResultBuffer() const
|
|
|
|
|
+{
|
|
|
|
|
+ return resultBuffer;
|
|
|
|
|
+}
|