From 3bd65816cf6276292c00e682766927a11e6ec6eb Mon Sep 17 00:00:00 2001 From: baldurk Date: Wed, 9 Oct 2024 17:40:57 +0100 Subject: [PATCH] Add a demos test that uses RT with ASs --- util/test/demos/d3d12/d3d12_helpers.cpp | 22 ++ util/test/demos/d3d12/d3d12_helpers.h | 4 + util/test/demos/d3d12/d3d12_rtas_zoo.cpp | 329 +++++++++++++++++++++++ util/test/demos/d3d12/d3d12_test.cpp | 7 + util/test/demos/d3d12/d3d12_test.h | 6 + util/test/demos/demos.vcxproj | 2 +- util/test/demos/demos.vcxproj.filters | 3 + util/test/demos/dx/d3d_helpers.h | 1 + 8 files changed, 373 insertions(+), 1 deletion(-) create mode 100644 util/test/demos/d3d12/d3d12_rtas_zoo.cpp diff --git a/util/test/demos/d3d12/d3d12_helpers.cpp b/util/test/demos/d3d12/d3d12_helpers.cpp index 0e671b47c..6a9238f04 100644 --- a/util/test/demos/d3d12/d3d12_helpers.cpp +++ b/util/test/demos/d3d12/d3d12_helpers.cpp @@ -260,6 +260,13 @@ D3D12BufferCreator &D3D12BufferCreator::UAV() return *this; } +D3D12BufferCreator &D3D12BufferCreator::ASB() +{ + m_InitialState = D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE; + m_BufDesc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; + return *this; +} + D3D12BufferCreator &D3D12BufferCreator::Upload() { m_HeapDesc.Type = D3D12_HEAP_TYPE_UPLOAD; @@ -442,6 +449,12 @@ D3D12ViewCreator::D3D12ViewCreator(ID3D12DevicePtr dev, ID3D12DescriptorHeap *he desc.cbv.BufferLocation = m_Res->GetGPUVirtualAddress(); desc.cbv.SizeInBytes = 0; } + else if(m_Type == ViewType::AS) + { + desc.srv.Format = DXGI_FORMAT_UNKNOWN; + desc.srv.ViewDimension = D3D12_SRV_DIMENSION_RAYTRACING_ACCELERATION_STRUCTURE; + desc.srv.RaytracingAccelerationStructure.Location = m_Res->GetGPUVirtualAddress(); + } else if(dim == D3D12_RESOURCE_DIMENSION_BUFFER) { SetupDescriptors(viewType, ResourceType::Buffer); @@ -835,6 +848,8 @@ D3D12ViewCreator &D3D12ViewCreator::Offset(UINT offset) { if(m_Type == ViewType::CBV) desc.cbv.BufferLocation += offset; + else if(m_Type == ViewType::AS) + desc.srv.RaytracingAccelerationStructure.Location += offset; else TEST_ERROR("This view & resource doesn't support SizeBytes"); return *this; @@ -969,6 +984,13 @@ D3D12_CPU_DESCRIPTOR_HANDLE D3D12ViewCreator::CreateCPU(ID3D12DescriptorHeap *he cpu.ptr += increment[D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV] * descriptor; m_Dev->CreateConstantBufferView(&desc.cbv, cpu); } + else if(m_Type == ViewType::AS) + { + desc.srv.Shader4ComponentMapping = Shader4ComponentMapping; + + cpu.ptr += increment[D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV] * descriptor; + m_Dev->CreateShaderResourceView(NULL, &desc.srv, cpu); + } else if(m_Type == ViewType::SRV) { if(desc.uav.ViewDimension == D3D12_SRV_DIMENSION_BUFFER) diff --git a/util/test/demos/d3d12/d3d12_helpers.h b/util/test/demos/d3d12/d3d12_helpers.h index e9244dc4e..04a06e7c6 100644 --- a/util/test/demos/d3d12/d3d12_helpers.h +++ b/util/test/demos/d3d12/d3d12_helpers.h @@ -80,6 +80,9 @@ COM_SMARTPTR(ID3D12InfoQueue); COM_SMARTPTR(ID3D12CommandQueueDownlevel); +COM_SMARTPTR(ID3D12StateObject); +COM_SMARTPTR(ID3D12StateObjectProperties); + struct D3D12GraphicsTest; class D3D12PSOCreator @@ -130,6 +133,7 @@ public: D3D12BufferCreator(ID3D12DevicePtr dev, D3D12GraphicsTest *test); D3D12BufferCreator &UAV(); + D3D12BufferCreator &ASB(); D3D12BufferCreator &Upload(); D3D12BufferCreator &Readback(); diff --git a/util/test/demos/d3d12/d3d12_rtas_zoo.cpp b/util/test/demos/d3d12/d3d12_rtas_zoo.cpp new file mode 100644 index 000000000..df600d01d --- /dev/null +++ b/util/test/demos/d3d12/d3d12_rtas_zoo.cpp @@ -0,0 +1,329 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2019-2024 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. + ******************************************************************************/ + +#include "d3d12_test.h" + +RD_TEST(D3D12_RTAS_Zoo, D3D12GraphicsTest) +{ + static constexpr const char *Description = "Test of different AS edge-cases and formats."; + + std::string rtshaders = R"EOSHADER( + +RaytracingAccelerationStructure Scene : register(t0); +RWTexture2D RenderTarget : register(u1); + +struct RayPayload +{ + float4 color; +}; + +[shader("raygeneration")] +void gen() +{ + float2 lerpValues = (float2)DispatchRaysIndex() / (float2)DispatchRaysDimensions(); + + { + RayDesc ray; + ray.Origin = float3(0, 0, 5); + ray.Direction = float3(lerp(-1.0f, 1.0f, lerpValues.x), + lerp(-1.0f, 1.0f, lerpValues.y), + -1.0f); + ray.TMin = 0.001; + ray.TMax = 10000.0; + RayPayload payload = { float4(0, 0, 1, 1) }; + TraceRay(Scene, RAY_FLAG_NONE, ~0, 0, 0, 0, ray, payload); + + // Write the raytraced color to the output texture. + RenderTarget[DispatchRaysIndex().xy] = payload.color; + } +} + +[shader("closesthit")] +void chit(inout RayPayload payload, in BuiltInTriangleIntersectionAttributes attrs) +{ + payload.color = float4(0, 1, 0, 1); +} + +[shader("miss")] +void miss(inout RayPayload payload) +{ + payload.color = float4(1, 0, 0, 1); +} + +)EOSHADER"; + + void Prepare(int argc, char **argv) + { + D3D12GraphicsTest::Prepare(argc, argv); + + if(!Avail.empty()) + return; + + if(opts5.RaytracingTier == D3D12_RAYTRACING_TIER_NOT_SUPPORTED) + Avail = "RT is not supported"; + + if(!m_DXILSupport) + Avail = "DXIL can't be compiled"; + } + + static const uint64_t scratchSpace = 1 * 1024 * 1024; + + static const uint64_t blasOffset = 0; + static const uint64_t blasSize = 1 * 1024 * 1024; + static const uint64_t tlasOffset = blasOffset + blasSize; + static const uint64_t tlasSize = 1 * 1024 * 1024; + static const uint64_t asbSize = tlasOffset + tlasSize; + + int main() + { + // initialise, create window, create device, etc + if(!Init()) + return 3; + + ID3D12ResourcePtr asb = MakeBuffer().ASB().Size(asbSize); + + asb->SetName(L"asb"); + + ID3D12ResourcePtr uav = MakeBuffer().UAV().Size(scratchSpace); + + { + ID3D12GraphicsCommandList4Ptr cmd = GetCommandBuffer(); + + Reset(cmd); + + D3D12_RAYTRACING_GEOMETRY_DESC geom = {}; + geom.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES; + geom.Triangles.VertexBuffer.StartAddress = DefaultTriVB->GetGPUVirtualAddress(); + geom.Triangles.VertexBuffer.StrideInBytes = sizeof(DefaultA2V); + geom.Triangles.VertexFormat = DXGI_FORMAT_R32G32B32_FLOAT; + geom.Triangles.VertexCount = 3; + geom.Flags = D3D12_RAYTRACING_GEOMETRY_FLAG_OPAQUE; + + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC desc = {}; + desc.DestAccelerationStructureData = asb->GetGPUVirtualAddress(); + desc.ScratchAccelerationStructureData = uav->GetGPUVirtualAddress(); + desc.Inputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY; + desc.Inputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL; + desc.Inputs.NumDescs = 1; + desc.Inputs.pGeometryDescs = &geom; + + cmd->BuildRaytracingAccelerationStructure(&desc, 0, NULL); + + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO prebuild = {}; + dev5->GetRaytracingAccelerationStructurePrebuildInfo(&desc.Inputs, &prebuild); + + TEST_ASSERT(prebuild.ScratchDataSizeInBytes < scratchSpace, "Insufficient scratch space"); + TEST_ASSERT(prebuild.ResultDataMaxSizeInBytes < tlasOffset, "BLAS too large"); + + cmd->Close(); + + Submit({cmd}); + } + + D3D12_RAYTRACING_INSTANCE_DESC instances[8] = {}; + for(int i = 0; i < 8; i++) + { + instances[i].AccelerationStructure = asb->GetGPUVirtualAddress(); + instances[i].InstanceMask = 1; + instances[i].Transform[0][0] = 1.0f; + instances[i].Transform[1][1] = 1.0f; + instances[i].Transform[2][2] = 1.0f; + + instances[i].Transform[0][3] = -4.0f + i * 1.0f; + } + + ID3D12ResourcePtr instData = MakeBuffer().Size(sizeof(instances)).Upload(); + + byte *instUpload = Map(instData, 0); + + instData->SetName(L"instData"); + + D3D12_GPU_VIRTUAL_ADDRESS instancesIndirect[8] = {}; + for(int i = 0; i < 8; i++) + instancesIndirect[i] = + instData->GetGPUVirtualAddress() + i * sizeof(D3D12_RAYTRACING_INSTANCE_DESC); + + ID3D12ResourcePtr instIndirectData = MakeBuffer().Data(instancesIndirect); + + instIndirectData->SetName(L"instIndirectData"); + + ID3D12StateObjectPtr rtpso; + + std::vector subObjs; + + ID3DBlobPtr lib = Compile(rtshaders, "", "lib_6_3"); + D3D12_DXIL_LIBRARY_DESC libDesc = {}; + libDesc.DXILLibrary.BytecodeLength = lib->GetBufferSize(); + libDesc.DXILLibrary.pShaderBytecode = lib->GetBufferPointer(); + + ID3D12RootSignaturePtr rootsig = MakeSig({ + tableParam(D3D12_SHADER_VISIBILITY_ALL, D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 0, 0, 100, 0), + tableParam(D3D12_SHADER_VISIBILITY_ALL, D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 0, 0, 100, 0), + }); + D3D12_GLOBAL_ROOT_SIGNATURE rootSigDesc = {rootsig}; + + D3D12_RAYTRACING_SHADER_CONFIG shadDesc = {}; + shadDesc.MaxPayloadSizeInBytes = 16; + shadDesc.MaxAttributeSizeInBytes = 8; + D3D12_RAYTRACING_PIPELINE_CONFIG pipeDesc = {}; + pipeDesc.MaxTraceRecursionDepth = 1; + D3D12_HIT_GROUP_DESC hitgroupDesc = {}; + hitgroupDesc.ClosestHitShaderImport = L"chit"; + hitgroupDesc.Type = D3D12_HIT_GROUP_TYPE_TRIANGLES; + hitgroupDesc.HitGroupExport = L"hitgroup"; + + subObjs.push_back({D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE, &rootSigDesc}); + subObjs.push_back({D3D12_STATE_SUBOBJECT_TYPE_DXIL_LIBRARY, &libDesc}); + subObjs.push_back({D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_SHADER_CONFIG, &shadDesc}); + subObjs.push_back({D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG, &pipeDesc}); + subObjs.push_back({D3D12_STATE_SUBOBJECT_TYPE_HIT_GROUP, &hitgroupDesc}); + + D3D12_STATE_OBJECT_DESC stateDesc = {}; + stateDesc.NumSubobjects = (UINT)subObjs.size(); + stateDesc.pSubobjects = subObjs.data(); + stateDesc.Type = D3D12_STATE_OBJECT_TYPE_RAYTRACING_PIPELINE; + + dev5->CreateStateObject(&stateDesc, __uuidof(ID3D12StateObject), (void **)&rtpso); + ID3D12StateObjectPropertiesPtr rtpso_props = rtpso; + + std::vector tablesData; + + tablesData.resize(D3D12_RAYTRACING_SHADER_TABLE_BYTE_ALIGNMENT * 3); + + memcpy(tablesData.data(), rtpso_props->GetShaderIdentifier(L"gen"), + D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES); + memcpy(tablesData.data() + D3D12_RAYTRACING_SHADER_TABLE_BYTE_ALIGNMENT, + rtpso_props->GetShaderIdentifier(L"miss"), D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES); + memcpy(tablesData.data() + D3D12_RAYTRACING_SHADER_TABLE_BYTE_ALIGNMENT * 2, + rtpso_props->GetShaderIdentifier(L"hitgroup"), D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES); + + ID3D12ResourcePtr tables = MakeBuffer().Data(tablesData); + + ID3D12ResourcePtr uavtex = MakeTexture(DXGI_FORMAT_R32G32B32A32_FLOAT, screenWidth, screenHeight) + .UAV() + .InitialState(D3D12_RESOURCE_STATE_UNORDERED_ACCESS); + + MakeUAV(uavtex).CreateCPU(1); + + while(Running()) + { + ID3D12GraphicsCommandListPtr cmd = GetCommandBuffer(); + ID3D12GraphicsCommandList4Ptr cmd4 = cmd; + + Reset(cmd); + + for(int i = 0; i < 8; i++) + { + instances[i].InstanceID = curFrame; + instances[i].Transform[1][3] = 2.5f * cosf(i * 0.29f + 0.05f * curFrame); + } + memcpy(instUpload, instances, sizeof(instances)); + + cmd->SetDescriptorHeaps(1, &m_CBVUAVSRV.GetInterfacePtr()); + + cmd->SetComputeRootSignature(rootsig); + cmd4->SetPipelineState1(rtpso); + cmd->SetComputeRootDescriptorTable(0, m_CBVUAVSRV->GetGPUDescriptorHandleForHeapStart()); + cmd->SetComputeRootDescriptorTable(1, m_CBVUAVSRV->GetGPUDescriptorHandleForHeapStart()); + + D3D12_DISPATCH_RAYS_DESC rayDispatch = {}; + rayDispatch.Width = screenWidth; + rayDispatch.Height = screenHeight; + rayDispatch.Depth = 1; + rayDispatch.RayGenerationShaderRecord.StartAddress = tables->GetGPUVirtualAddress(); + rayDispatch.RayGenerationShaderRecord.SizeInBytes = D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES; + rayDispatch.MissShaderTable.StartAddress = + tables->GetGPUVirtualAddress() + D3D12_RAYTRACING_SHADER_TABLE_BYTE_ALIGNMENT; + rayDispatch.MissShaderTable.SizeInBytes = D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES; + rayDispatch.MissShaderTable.StrideInBytes = D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES; + rayDispatch.HitGroupTable.StartAddress = + tables->GetGPUVirtualAddress() + D3D12_RAYTRACING_SHADER_TABLE_BYTE_ALIGNMENT * 2; + rayDispatch.HitGroupTable.StrideInBytes = 0; + rayDispatch.HitGroupTable.SizeInBytes = D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES; + cmd4->DispatchRays(&rayDispatch); + + ResourceBarrier(cmd); + + cmd->Close(); + + Submit({cmd}); + + cmd = GetCommandBuffer(); + cmd4 = cmd; + + Reset(cmd); + + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC desc = {}; + desc.DestAccelerationStructureData = asb->GetGPUVirtualAddress() + tlasOffset; + desc.ScratchAccelerationStructureData = uav->GetGPUVirtualAddress(); + desc.Inputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY_OF_POINTERS; + desc.Inputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL; + desc.Inputs.NumDescs = 8; + desc.Inputs.InstanceDescs = instIndirectData->GetGPUVirtualAddress(); + + cmd4->BuildRaytracingAccelerationStructure(&desc, 0, NULL); + MakeAS(asb).Offset(tlasOffset).CreateCPU(0); + + ResourceBarrier(cmd); + + cmd->Close(); + + Submit({cmd}); + + cmd = GetCommandBuffer(); + cmd4 = cmd; + + Reset(cmd); + + cmd->SetDescriptorHeaps(1, &m_CBVUAVSRV.GetInterfacePtr()); + + cmd->SetComputeRootSignature(rootsig); + cmd4->SetPipelineState1(rtpso); + cmd->SetComputeRootDescriptorTable(0, m_CBVUAVSRV->GetGPUDescriptorHandleForHeapStart()); + cmd->SetComputeRootDescriptorTable(1, m_CBVUAVSRV->GetGPUDescriptorHandleForHeapStart()); + + cmd4->DispatchRays(&rayDispatch); + + ID3D12ResourcePtr bb = StartUsingBackbuffer(cmd, D3D12_RESOURCE_STATE_RENDER_TARGET); + + ResourceBarrier(cmd, uavtex, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, + D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); + + blitToSwap(cmd, uavtex, bb); + + ResourceBarrier(cmd, uavtex, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, + D3D12_RESOURCE_STATE_UNORDERED_ACCESS); + + FinishUsingBackbuffer(cmd, D3D12_RESOURCE_STATE_RENDER_TARGET); + + cmd->Close(); + + SubmitAndPresent({cmd}); + } + + return 0; + } +}; + +REGISTER_TEST(); diff --git a/util/test/demos/d3d12/d3d12_test.cpp b/util/test/demos/d3d12/d3d12_test.cpp index 06c621f36..55b1e8baf 100644 --- a/util/test/demos/d3d12/d3d12_test.cpp +++ b/util/test/demos/d3d12/d3d12_test.cpp @@ -1233,6 +1233,13 @@ void D3D12GraphicsTest::ResourceBarrier(ID3D12ResourcePtr res, D3D12_RESOURCE_ST Submit({cmd}); } +void D3D12GraphicsTest::ResourceBarrier(ID3D12GraphicsCommandListPtr cmd) +{ + D3D12_RESOURCE_BARRIER barrier = {}; + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; + cmd->ResourceBarrier(1, &barrier); +} + void D3D12GraphicsTest::IASetVertexBuffer(ID3D12GraphicsCommandListPtr cmd, ID3D12ResourcePtr vb, UINT stride, UINT offset) { diff --git a/util/test/demos/d3d12/d3d12_test.h b/util/test/demos/d3d12/d3d12_test.h index 39f405859..ebd2cda84 100644 --- a/util/test/demos/d3d12/d3d12_test.h +++ b/util/test/demos/d3d12/d3d12_test.h @@ -120,6 +120,11 @@ struct D3D12GraphicsTest : public GraphicsTest return D3D12ViewCreator(dev, m_CBVUAVSRV, NULL, ViewType::SRV, res); } template + D3D12ViewCreator MakeAS(T res) + { + return D3D12ViewCreator(dev, m_CBVUAVSRV, NULL, ViewType::AS, res); + } + template D3D12ViewCreator MakeRTV(T res) { return D3D12ViewCreator(dev, m_RTV, NULL, ViewType::RTV, res); @@ -158,6 +163,7 @@ struct D3D12GraphicsTest : public GraphicsTest D3D12_RESOURCE_STATES before, D3D12_RESOURCE_STATES after); void ResourceBarrier(ID3D12ResourcePtr res, D3D12_RESOURCE_STATES before, D3D12_RESOURCE_STATES after); + void ResourceBarrier(ID3D12GraphicsCommandListPtr cmd); void IASetVertexBuffer(ID3D12GraphicsCommandListPtr cmd, ID3D12ResourcePtr vb, UINT stride, UINT offset); diff --git a/util/test/demos/demos.vcxproj b/util/test/demos/demos.vcxproj index 33bcdcb47..9be5d7296 100644 --- a/util/test/demos/demos.vcxproj +++ b/util/test/demos/demos.vcxproj @@ -211,6 +211,7 @@ + @@ -448,7 +449,6 @@ - diff --git a/util/test/demos/demos.vcxproj.filters b/util/test/demos/demos.vcxproj.filters index 7b50263e4..a5a39d1c9 100644 --- a/util/test/demos/demos.vcxproj.filters +++ b/util/test/demos/demos.vcxproj.filters @@ -691,6 +691,9 @@ D3D12\demos + + D3D12\demos + diff --git a/util/test/demos/dx/d3d_helpers.h b/util/test/demos/dx/d3d_helpers.h index 5a18199c3..ae04f229e 100644 --- a/util/test/demos/dx/d3d_helpers.h +++ b/util/test/demos/dx/d3d_helpers.h @@ -75,4 +75,5 @@ enum class ViewType DSV, UAV, CBV, + AS, };