diff options
| author | assiduous <assiduous@diligentgraphics.com> | 2020-12-15 19:32:55 +0000 |
|---|---|---|
| committer | assiduous <assiduous@diligentgraphics.com> | 2020-12-15 19:32:55 +0000 |
| commit | 2cbe12c8541f63719ae3662cda827ed53004c0b2 (patch) | |
| tree | 6ff68d7ee7d386d1c0e30c00fcd551fcbf819c6c /Graphics/GraphicsEngineD3D12 | |
| parent | Math Lib: added Matrix4x4 constructor from float4 rows (diff) | |
| parent | BasicMath: minor code formatting (diff) | |
| download | DiligentCore-2cbe12c8541f63719ae3662cda827ed53004c0b2.tar.gz DiligentCore-2cbe12c8541f63719ae3662cda827ed53004c0b2.zip | |
Merge branch 'azhirnov-ray_tracing_2'
Diffstat (limited to 'Graphics/GraphicsEngineD3D12')
42 files changed, 3240 insertions, 885 deletions
diff --git a/Graphics/GraphicsEngineD3D12/CMakeLists.txt b/Graphics/GraphicsEngineD3D12/CMakeLists.txt index 24c6201a..a4f0c4c9 100644 --- a/Graphics/GraphicsEngineD3D12/CMakeLists.txt +++ b/Graphics/GraphicsEngineD3D12/CMakeLists.txt @@ -37,6 +37,9 @@ set(INCLUDE include/SwapChainD3D12Impl.hpp include/TextureD3D12Impl.hpp include/TextureViewD3D12Impl.hpp + include/BottomLevelASD3D12Impl.hpp + include/TopLevelASD3D12Impl.hpp + include/ShaderBindingTableD3D12Impl.hpp ) set(INTERFACE @@ -55,6 +58,9 @@ set(INTERFACE interface/SwapChainD3D12.h interface/TextureD3D12.h interface/TextureViewD3D12.h + interface/BottomLevelASD3D12.h + interface/TopLevelASD3D12.h + interface/ShaderBindingTableD3D12.h ) @@ -89,6 +95,9 @@ set(SRC src/SwapChainD3D12Impl.cpp src/TextureD3D12Impl.cpp src/TextureViewD3D12Impl.cpp + src/BottomLevelASD3D12Impl.cpp + src/TopLevelASD3D12Impl.cpp + src/ShaderBindingTableD3D12Impl.cpp ) if(PLATFORM_WIN32) diff --git a/Graphics/GraphicsEngineD3D12/include/BottomLevelASD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/BottomLevelASD3D12Impl.hpp new file mode 100644 index 00000000..12118e18 --- /dev/null +++ b/Graphics/GraphicsEngineD3D12/include/BottomLevelASD3D12Impl.hpp @@ -0,0 +1,72 @@ +/* + * Copyright 2019-2020 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#pragma once + +/// \file +/// Declaration of Diligent::BottomLevelASD3D12Impl class + +#include "BottomLevelASD3D12.h" +#include "RenderDeviceD3D12.h" +#include "BottomLevelASBase.hpp" +#include "D3D12ResourceBase.hpp" +#include "RenderDeviceD3D12Impl.hpp" + +namespace Diligent +{ + +/// Bottom-level acceleration structure object implementation in Direct3D12 backend. +class BottomLevelASD3D12Impl final : public BottomLevelASBase<IBottomLevelASD3D12, RenderDeviceD3D12Impl>, public D3D12ResourceBase +{ +public: + using TBottomLevelASBase = BottomLevelASBase<IBottomLevelASD3D12, RenderDeviceD3D12Impl>; + + BottomLevelASD3D12Impl(IReferenceCounters* pRefCounters, + class RenderDeviceD3D12Impl* pDeviceD3D12, + const BottomLevelASDesc& Desc); + BottomLevelASD3D12Impl(IReferenceCounters* pRefCounters, + class RenderDeviceD3D12Impl* pDeviceD3D12, + const BottomLevelASDesc& Desc, + RESOURCE_STATE InitialState, + ID3D12Resource* pd3d12BLAS); + ~BottomLevelASD3D12Impl(); + + IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_BottomLevelASD3D12, TBottomLevelASBase); + + /// Implementation of IBottomLevelASD3D12::GetD3D12BLAS(). + virtual ID3D12Resource* DILIGENT_CALL_TYPE GetD3D12BLAS() override final { return GetD3D12Resource(); } + + /// Implementation of IBottomLevelAS::GetNativeHandle() in Direct3D12 backend. + virtual void* DILIGENT_CALL_TYPE GetNativeHandle() override final { return GetD3D12BLAS(); } + + D3D12_GPU_VIRTUAL_ADDRESS GetGPUAddress() + { + return GetD3D12Resource()->GetGPUVirtualAddress(); + } +}; + +} // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/include/BufferD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/BufferD3D12Impl.hpp index ab90dfe7..ad3027a8 100644 --- a/Graphics/GraphicsEngineD3D12/include/BufferD3D12Impl.hpp +++ b/Graphics/GraphicsEngineD3D12/include/BufferD3D12Impl.hpp @@ -103,6 +103,12 @@ public: } } + __forceinline D3D12_GPU_VIRTUAL_ADDRESS GetGPUAddress() + { + VERIFY_EXPR(m_Desc.Usage != USAGE_DYNAMIC); + return GetD3D12Resource()->GetGPUVirtualAddress(); + } + D3D12_CPU_DESCRIPTOR_HANDLE GetCBVHandle() { return m_CBVDescriptorAllocation.GetCpuHandle(); } private: diff --git a/Graphics/GraphicsEngineD3D12/include/CommandContext.hpp b/Graphics/GraphicsEngineD3D12/include/CommandContext.hpp index d6477b79..1d1f0082 100644 --- a/Graphics/GraphicsEngineD3D12/include/CommandContext.hpp +++ b/Graphics/GraphicsEngineD3D12/include/CommandContext.hpp @@ -34,6 +34,8 @@ #include "TextureViewD3D12.h" #include "TextureD3D12.h" #include "BufferD3D12.h" +#include "BottomLevelASD3D12.h" +#include "TopLevelASD3D12.h" #include "DescriptorHeap.hpp" namespace Diligent @@ -114,6 +116,8 @@ public: void TransitionResource(ITextureD3D12* pTexture, RESOURCE_STATE NewState); void TransitionResource(IBufferD3D12* pBuffer, RESOURCE_STATE NewState); + void TransitionResource(IBottomLevelASD3D12* pBLAS, RESOURCE_STATE NewState); + void TransitionResource(ITopLevelASD3D12* pTLAS, RESOURCE_STATE NewState); void TransitionResource(const StateTransitionDesc& Barrier); //void BeginResourceTransition(GpuResource& Resource, D3D12_RESOURCE_STATES NewState, bool FlushImmediate = false); @@ -183,7 +187,8 @@ public: { if (pPSO != m_pCurPipelineState) { - m_pCommandList->SetPipelineState(m_pCurPipelineState = pPSO); + m_pCommandList->SetPipelineState(pPSO); + m_pCurPipelineState = pPSO; } } @@ -218,7 +223,7 @@ protected: CComPtr<ID3D12GraphicsCommandList> m_pCommandList; CComPtr<ID3D12CommandAllocator> m_pCurrentAllocator; - ID3D12PipelineState* m_pCurPipelineState = nullptr; + void* m_pCurPipelineState = nullptr; ID3D12RootSignature* m_pCurGraphicsRootSignature = nullptr; ID3D12RootSignature* m_pCurComputeRootSignature = nullptr; @@ -237,8 +242,25 @@ protected: Uint32 m_MaxInterfaceVer = 0; }; +class ComputeContext : public CommandContext +{ +public: + void SetComputeRootSignature(ID3D12RootSignature* pRootSig) + { + if (pRootSig != m_pCurComputeRootSignature) + { + m_pCommandList->SetComputeRootSignature(m_pCurComputeRootSignature = pRootSig); + } + } -class GraphicsContext : public CommandContext + void Dispatch(size_t GroupCountX = 1, size_t GroupCountY = 1, size_t GroupCountZ = 1) + { + FlushResourceBarriers(); + m_pCommandList->Dispatch((UINT)GroupCountX, (UINT)GroupCountY, (UINT)GroupCountZ); + } +}; + +class GraphicsContext : public ComputeContext { public: void ClearRenderTarget(D3D12_CPU_DESCRIPTOR_HANDLE RTV, const float* Color) @@ -253,7 +275,7 @@ public: m_pCommandList->ClearDepthStencilView(DSV, ClearFlags, Depth, Stencil, 0, nullptr); } - void SetRootSignature(ID3D12RootSignature* pRootSig) + void SetGraphicsRootSignature(ID3D12RootSignature* pRootSig) { if (pRootSig != m_pCurGraphicsRootSignature) { @@ -290,47 +312,6 @@ public: } } - void SetConstants(UINT RootIndex, UINT NumConstants, const void* pConstants) - { - m_pCommandList->SetGraphicsRoot32BitConstants(RootIndex, NumConstants, pConstants, 0); - } - - void SetConstants(UINT RootIndex, DWParam X) - { - m_pCommandList->SetGraphicsRoot32BitConstant(RootIndex, X.Uint, 0); - } - - void SetConstants(UINT RootIndex, DWParam X, DWParam Y) - { - m_pCommandList->SetGraphicsRoot32BitConstant(RootIndex, X.Uint, 0); - m_pCommandList->SetGraphicsRoot32BitConstant(RootIndex, Y.Uint, 1); - } - - void SetConstants(UINT RootIndex, DWParam X, DWParam Y, DWParam Z) - { - m_pCommandList->SetGraphicsRoot32BitConstant(RootIndex, X.Uint, 0); - m_pCommandList->SetGraphicsRoot32BitConstant(RootIndex, Y.Uint, 1); - m_pCommandList->SetGraphicsRoot32BitConstant(RootIndex, Z.Uint, 2); - } - - void SetConstants(UINT RootIndex, DWParam X, DWParam Y, DWParam Z, DWParam W) - { - m_pCommandList->SetGraphicsRoot32BitConstant(RootIndex, X.Uint, 0); - m_pCommandList->SetGraphicsRoot32BitConstant(RootIndex, Y.Uint, 1); - m_pCommandList->SetGraphicsRoot32BitConstant(RootIndex, Z.Uint, 2); - m_pCommandList->SetGraphicsRoot32BitConstant(RootIndex, W.Uint, 3); - } - - void SetConstantBuffer(UINT RootIndex, D3D12_GPU_VIRTUAL_ADDRESS CBV) - { - m_pCommandList->SetGraphicsRootConstantBufferView(RootIndex, CBV); - } - - void SetDescriptorTable(UINT RootIndex, D3D12_GPU_DESCRIPTOR_HANDLE FirstHandle) - { - m_pCommandList->SetGraphicsRootDescriptorTable(RootIndex, FirstHandle); - } - void SetIndexBuffer(const D3D12_INDEX_BUFFER_VIEW& IBView) { m_pCommandList->IASetIndexBuffer(&IBView); @@ -383,83 +364,61 @@ public: { static_cast<ID3D12GraphicsCommandList4*>(m_pCommandList.p)->EndRenderPass(); } -}; - -class GraphicsContext5 : public GraphicsContext4 -{ -}; - -class GraphicsContext6 : public GraphicsContext5 -{ -public: - void DrawMesh(UINT ThreadGroupCountX, UINT ThreadGroupCountY, UINT ThreadGroupCountZ) - { -#ifdef D3D12_H_HAS_MESH_SHADER - FlushResourceBarriers(); - static_cast<ID3D12GraphicsCommandList6*>(m_pCommandList.p)->DispatchMesh(ThreadGroupCountX, ThreadGroupCountY, ThreadGroupCountZ); -#else - UNSUPPORTED("DrawMesh is not supported in current D3D12 header"); -#endif - } -}; -class ComputeContext : public CommandContext -{ -public: - void SetRootSignature(ID3D12RootSignature* pRootSig) + void SetRayTracingPipelineState(ID3D12StateObject* pPSO) { - if (pRootSig != m_pCurComputeRootSignature) + if (pPSO != m_pCurPipelineState) { - m_pCommandList->SetComputeRootSignature(m_pCurComputeRootSignature = pRootSig); + static_cast<ID3D12GraphicsCommandList4*>(m_pCommandList.p)->SetPipelineState1(pPSO); + m_pCurPipelineState = pPSO; } } - void SetConstants(UINT RootIndex, UINT NumConstants, const void* pConstants) - { - m_pCommandList->SetComputeRoot32BitConstants(RootIndex, NumConstants, pConstants, 0); - } - - void SetConstants(UINT RootIndex, DWParam X) - { - m_pCommandList->SetComputeRoot32BitConstant(RootIndex, X.Uint, 0); - } - - void SetConstants(UINT RootIndex, DWParam X, DWParam Y) + void BuildRaytracingAccelerationStructure(const D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC& Desc, + UINT NumPostbuildInfoDescs, + const D3D12_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_DESC* pPostbuildInfoDescs) { - m_pCommandList->SetComputeRoot32BitConstant(RootIndex, X.Uint, 0); - m_pCommandList->SetComputeRoot32BitConstant(RootIndex, Y.Uint, 1); + FlushResourceBarriers(); + static_cast<ID3D12GraphicsCommandList4*>(m_pCommandList.p)->BuildRaytracingAccelerationStructure(&Desc, NumPostbuildInfoDescs, pPostbuildInfoDescs); } - void SetConstants(UINT RootIndex, DWParam X, DWParam Y, DWParam Z) + void EmitRaytracingAccelerationStructurePostbuildInfo(const D3D12_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_DESC& Desc, + D3D12_GPU_VIRTUAL_ADDRESS SourceAccelerationStructureAddress) { - m_pCommandList->SetComputeRoot32BitConstant(RootIndex, X.Uint, 0); - m_pCommandList->SetComputeRoot32BitConstant(RootIndex, Y.Uint, 1); - m_pCommandList->SetComputeRoot32BitConstant(RootIndex, Z.Uint, 2); + FlushResourceBarriers(); + static_cast<ID3D12GraphicsCommandList4*>(m_pCommandList.p)->EmitRaytracingAccelerationStructurePostbuildInfo(&Desc, 1, &SourceAccelerationStructureAddress); } - void SetConstants(UINT RootIndex, DWParam X, DWParam Y, DWParam Z, DWParam W) + void CopyRaytracingAccelerationStructure(D3D12_GPU_VIRTUAL_ADDRESS DestAccelerationStructureData, + D3D12_GPU_VIRTUAL_ADDRESS SourceAccelerationStructureData, + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_COPY_MODE Mode) { - m_pCommandList->SetComputeRoot32BitConstant(RootIndex, X.Uint, 0); - m_pCommandList->SetComputeRoot32BitConstant(RootIndex, Y.Uint, 1); - m_pCommandList->SetComputeRoot32BitConstant(RootIndex, Z.Uint, 2); - m_pCommandList->SetComputeRoot32BitConstant(RootIndex, W.Uint, 3); + FlushResourceBarriers(); + static_cast<ID3D12GraphicsCommandList4*>(m_pCommandList.p)->CopyRaytracingAccelerationStructure(DestAccelerationStructureData, SourceAccelerationStructureData, Mode); } - - void SetConstantBuffer(UINT RootIndex, D3D12_GPU_VIRTUAL_ADDRESS CBV) + void DispatchRays(const D3D12_DISPATCH_RAYS_DESC& Desc) { - m_pCommandList->SetComputeRootConstantBufferView(RootIndex, CBV); + FlushResourceBarriers(); + static_cast<ID3D12GraphicsCommandList4*>(m_pCommandList.p)->DispatchRays(&Desc); } +}; - void SetDescriptorTable(UINT RootIndex, D3D12_GPU_DESCRIPTOR_HANDLE FirstHandle) - { - m_pCommandList->SetComputeRootDescriptorTable(RootIndex, FirstHandle); - } +class GraphicsContext5 : public GraphicsContext4 +{ +}; - void Dispatch(size_t GroupCountX = 1, size_t GroupCountY = 1, size_t GroupCountZ = 1) +class GraphicsContext6 : public GraphicsContext5 +{ +public: + void DrawMesh(UINT ThreadGroupCountX, UINT ThreadGroupCountY, UINT ThreadGroupCountZ) { +#ifdef D3D12_H_HAS_MESH_SHADER FlushResourceBarriers(); - m_pCommandList->Dispatch((UINT)GroupCountX, (UINT)GroupCountY, (UINT)GroupCountZ); + static_cast<ID3D12GraphicsCommandList6*>(m_pCommandList.p)->DispatchMesh(ThreadGroupCountX, ThreadGroupCountY, ThreadGroupCountZ); +#else + UNSUPPORTED("DrawMesh is not supported in current D3D12 header"); +#endif } }; diff --git a/Graphics/GraphicsEngineD3D12/include/D3D12ResourceBase.hpp b/Graphics/GraphicsEngineD3D12/include/D3D12ResourceBase.hpp index 240ea165..e3a78c6c 100644 --- a/Graphics/GraphicsEngineD3D12/include/D3D12ResourceBase.hpp +++ b/Graphics/GraphicsEngineD3D12/include/D3D12ResourceBase.hpp @@ -43,7 +43,7 @@ public: ID3D12Resource* GetD3D12Resource() { return m_pd3d12Resource; } protected: - CComPtr<ID3D12Resource> m_pd3d12Resource; ///< D3D12 buffer object + CComPtr<ID3D12Resource> m_pd3d12Resource; ///< D3D12 resource object }; } // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/include/D3D12TypeConversions.hpp b/Graphics/GraphicsEngineD3D12/include/D3D12TypeConversions.hpp index 89e52955..774fefcd 100644 --- a/Graphics/GraphicsEngineD3D12/include/D3D12TypeConversions.hpp +++ b/Graphics/GraphicsEngineD3D12/include/D3D12TypeConversions.hpp @@ -75,4 +75,17 @@ D3D12_QUERY_TYPE QueryTypeToD3D12QueryType(QUERY_TYPE QueryType); D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE AttachmentLoadOpToD3D12BeginningAccessType(ATTACHMENT_LOAD_OP LoadOp); D3D12_RENDER_PASS_ENDING_ACCESS_TYPE AttachmentStoreOpToD3D12EndingAccessType(ATTACHMENT_STORE_OP StoreOp); +D3D12_SHADER_VISIBILITY ShaderTypeToD3D12ShaderVisibility(SHADER_TYPE ShaderType); +SHADER_TYPE D3D12ShaderVisibilityToShaderType(D3D12_SHADER_VISIBILITY ShaderVisibility); + +DXGI_FORMAT ValueTypeToIndexType(VALUE_TYPE Type); + +D3D12_RAYTRACING_GEOMETRY_FLAGS GeometryFlagsToD3D12RTGeometryFlags(RAYTRACING_GEOMETRY_FLAGS Flags); +D3D12_RAYTRACING_INSTANCE_FLAGS InstanceFlagsToD3D12RTInstanceFlags(RAYTRACING_INSTANCE_FLAGS Flags); + +D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS BuildASFlagsToD3D12ASBuildFlags(RAYTRACING_BUILD_AS_FLAGS Flags); +D3D12_RAYTRACING_ACCELERATION_STRUCTURE_COPY_MODE CopyASModeToD3D12ASCopyMode(COPY_AS_MODE Mode); + +DXGI_FORMAT TypeToRayTracingVertexFormat(VALUE_TYPE ValueType, Uint32 ComponentCount); + } // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.hpp index 4eb3585b..23c78abb 100644 --- a/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.hpp +++ b/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.hpp @@ -42,6 +42,8 @@ #include "RenderPassD3D12Impl.hpp" #include "PipelineStateD3D12Impl.hpp" #include "D3D12DynamicHeap.hpp" +#include "BottomLevelASD3D12Impl.hpp" +#include "TopLevelASD3D12Impl.hpp" namespace Diligent { @@ -56,6 +58,8 @@ struct DeviceContextD3D12ImplTraits using QueryType = QueryD3D12Impl; using FramebufferType = FramebufferD3D12Impl; using RenderPassType = RenderPassD3D12Impl; + using BottomLevelASType = BottomLevelASD3D12Impl; + using TopLevelASType = TopLevelASD3D12Impl; }; /// Device context implementation in Direct3D12 backend. @@ -125,13 +129,13 @@ public: ITextureView* pDepthStencil, RESOURCE_STATE_TRANSITION_MODE StateTransitionMode) override final; - /// Implementation of IDeviceContext::BeginRenderPass() in Direct3D11 backend. + /// Implementation of IDeviceContext::BeginRenderPass() in Direct3D12 backend. virtual void DILIGENT_CALL_TYPE BeginRenderPass(const BeginRenderPassAttribs& Attribs) override final; - /// Implementation of IDeviceContext::NextSubpass() in Direct3D11 backend. + /// Implementation of IDeviceContext::NextSubpass() in Direct3D12 backend. virtual void DILIGENT_CALL_TYPE NextSubpass() override final; - /// Implementation of IDeviceContext::EndRenderPass() in Direct3D11 backend. + /// Implementation of IDeviceContext::EndRenderPass() in Direct3D12 backend. virtual void DILIGENT_CALL_TYPE EndRenderPass() override final; // clang-format off @@ -257,6 +261,27 @@ public: /// Implementation of IDeviceContext::TransitionBufferState() in Direct3D12 backend. virtual void DILIGENT_CALL_TYPE TransitionBufferState(IBuffer* pBuffer, D3D12_RESOURCE_STATES State) override final; + /// Implementation of IDeviceContext::BuildBLAS() in Direct3D12 backend. + virtual void DILIGENT_CALL_TYPE BuildBLAS(const BuildBLASAttribs& Attribs) override final; + + /// Implementation of IDeviceContext::BuildTLAS() in Direct3D12 backend. + virtual void DILIGENT_CALL_TYPE BuildTLAS(const BuildTLASAttribs& Attribs) override final; + + /// Implementation of IDeviceContext::CopyBLAS() in Direct3D12 backend. + virtual void DILIGENT_CALL_TYPE CopyBLAS(const CopyBLASAttribs& Attribs) override final; + + /// Implementation of IDeviceContext::CopyTLAS() in Direct3D12 backend. + virtual void DILIGENT_CALL_TYPE CopyTLAS(const CopyTLASAttribs& Attribs) override final; + + /// Implementation of IDeviceContext::WriteBLASCompactedSize() in Direct3D12 backend. + virtual void DILIGENT_CALL_TYPE WriteBLASCompactedSize(const WriteBLASCompactedSizeAttribs& Attribs) override final; + + /// Implementation of IDeviceContext::WriteTLASCompactedSize() in Direct3D12 backend. + virtual void DILIGENT_CALL_TYPE WriteTLASCompactedSize(const WriteTLASCompactedSizeAttribs& Attribs) override final; + + /// Implementation of IDeviceContext::TraceRays() in Direct3D12 backend. + virtual void DILIGENT_CALL_TYPE TraceRays(const TraceRaysAttribs& Attribs) override final; + /// Implementation of IDeviceContextD3D12::ID3D12GraphicsCommandList() in Direct3D12 backend. virtual ID3D12GraphicsCommandList* DILIGENT_CALL_TYPE GetD3D12CommandList() override final; @@ -334,12 +359,23 @@ private: RESOURCE_STATE_TRANSITION_MODE TransitionMode, RESOURCE_STATE RequiredState, const char* OperationName); + __forceinline void TransitionOrVerifyBLASState(CommandContext& CmdCtx, + BottomLevelASD3D12Impl& BLAS, + RESOURCE_STATE_TRANSITION_MODE TransitionMode, + RESOURCE_STATE RequiredState, + const char* OperationName); + __forceinline void TransitionOrVerifyTLASState(CommandContext& CmdCtx, + TopLevelASD3D12Impl& TLAS, + RESOURCE_STATE_TRANSITION_MODE TransitionMode, + RESOURCE_STATE RequiredState, + const char* OperationName); __forceinline void PrepareForDraw(GraphicsContext& GraphCtx, DRAW_FLAGS Flags); __forceinline void PrepareForIndexedDraw(GraphicsContext& GraphCtx, DRAW_FLAGS Flags, VALUE_TYPE IndexType); __forceinline void PrepareForDispatchCompute(ComputeContext& GraphCtx); + __forceinline void PrepareForDispatchRays(GraphicsContext& GraphCtx); __forceinline void PrepareDrawIndirectBuffer(GraphicsContext& GraphCtx, IBuffer* pAttribsBuffer, diff --git a/Graphics/GraphicsEngineD3D12/include/FramebufferD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/FramebufferD3D12Impl.hpp index 59642660..31b65866 100644 --- a/Graphics/GraphicsEngineD3D12/include/FramebufferD3D12Impl.hpp +++ b/Graphics/GraphicsEngineD3D12/include/FramebufferD3D12Impl.hpp @@ -39,7 +39,7 @@ namespace Diligent class FixedBlockMemoryAllocator; -/// Render pass implementation in Direct3D11 backend. +/// Render pass implementation in Direct3D12 backend. class FramebufferD3D12Impl final : public FramebufferBase<IFramebuffer, RenderDeviceD3D12Impl> { public: diff --git a/Graphics/GraphicsEngineD3D12/include/PipelineStateD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/PipelineStateD3D12Impl.hpp index fa761fc7..021a38b0 100644 --- a/Graphics/GraphicsEngineD3D12/include/PipelineStateD3D12Impl.hpp +++ b/Graphics/GraphicsEngineD3D12/include/PipelineStateD3D12Impl.hpp @@ -53,6 +53,7 @@ public: PipelineStateD3D12Impl(IReferenceCounters* pRefCounters, RenderDeviceD3D12Impl* pDeviceD3D12, const GraphicsPipelineStateCreateInfo& CreateInfo); PipelineStateD3D12Impl(IReferenceCounters* pRefCounters, RenderDeviceD3D12Impl* pDeviceD3D12, const ComputePipelineStateCreateInfo& CreateInfo); + PipelineStateD3D12Impl(IReferenceCounters* pRefCounters, RenderDeviceD3D12Impl* pDeviceD3D12, const RayTracingPipelineStateCreateInfo& CreateInfo); ~PipelineStateD3D12Impl(); virtual void DILIGENT_CALL_TYPE QueryInterface(const INTERFACE_ID& IID, IObject** ppInterface) override final; @@ -76,7 +77,10 @@ public: virtual bool DILIGENT_CALL_TYPE IsCompatibleWith(const IPipelineState* pPSO) const override final; /// Implementation of IPipelineStateD3D12::GetD3D12PipelineState(). - virtual ID3D12PipelineState* DILIGENT_CALL_TYPE GetD3D12PipelineState() const override final { return m_pd3d12PSO; } + virtual ID3D12PipelineState* DILIGENT_CALL_TYPE GetD3D12PipelineState() const override final { return static_cast<ID3D12PipelineState*>(m_pd3d12PSO.p); } + + /// Implementation of IPipelineStateD3D12::GetD3D12StateObject(). + virtual ID3D12StateObject* DILIGENT_CALL_TYPE GetD3D12StateObject() const override final { return static_cast<ID3D12StateObject*>(m_pd3d12PSO.p); } /// Implementation of IPipelineStateD3D12::GetD3D12RootSignature(). virtual ID3D12RootSignature* DILIGENT_CALL_TYPE GetD3D12RootSignature() const override final { return m_RootSig.GetD3D12RootSignature(); } @@ -121,27 +125,27 @@ public: } private: - struct D3D12PipelineShaderStageInfo + struct ShaderStageInfo { - const SHADER_TYPE Type; - ShaderD3D12Impl* const pShader; - D3D12PipelineShaderStageInfo(SHADER_TYPE _Type, - ShaderD3D12Impl* _pShader) : - Type{_Type}, - pShader{_pShader} - {} - }; + ShaderStageInfo() {} + ShaderStageInfo(SHADER_TYPE _Type, ShaderD3D12Impl* _pShader); - template <typename PSOCreateInfoType> - void InitInternalObjects(const PSOCreateInfoType& CreateInfo, std::vector<D3D12PipelineShaderStageInfo>& ShaderStages); + void Append(ShaderD3D12Impl* pShader); + size_t Count() const; + + SHADER_TYPE Type = SHADER_TYPE_UNKNOWN; + std::vector<ShaderD3D12Impl*> Shaders; + }; + using TShaderStages = std::vector<ShaderStageInfo>; - void InitResourceLayouts(const PipelineStateCreateInfo& CreateInfo, - std::vector<D3D12PipelineShaderStageInfo>& ShaderStages); + template <typename PSOCreateInfoType, typename InitPSODescType> + void InitInternalObjects(const PSOCreateInfoType& CreateInfo, RootSignatureBuilder& RootSigBuilder, TShaderStages& ShaderStages, LocalRootSignature* pLocalRoot, InitPSODescType InitPSODesc); + void InitResourceLayouts(const PipelineStateCreateInfo& CreateInfo, RootSignatureBuilder& RootSigBuilder, TShaderStages& ShaderStages, LocalRootSignature* pLocalRoot); void Destruct(); - CComPtr<ID3D12PipelineState> m_pd3d12PSO; - RootSignature m_RootSig; + CComPtr<ID3D12DeviceChild> m_pd3d12PSO; + RootSignature m_RootSig; // Must be defined before default SRB SRBMemoryAllocator m_SRBMemAllocator; @@ -152,7 +156,8 @@ private: // Resource layout index in m_pShaderResourceLayouts array for every shader stage, // indexed by the shader type pipeline index (returned by GetShaderTypePipelineIndex) - std::array<Int8, MAX_SHADERS_IN_PIPELINE> m_ResourceLayoutIndex = {-1, -1, -1, -1, -1}; + std::array<Int8, MAX_SHADERS_IN_PIPELINE> m_ResourceLayoutIndex = {-1, -1, -1, -1, -1, -1}; + static_assert(MAX_SHADERS_IN_PIPELINE == 6, "Please update the initializer list above"); }; } // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.hpp index 34a77213..bf44fbb6 100644 --- a/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.hpp +++ b/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.hpp @@ -68,6 +68,9 @@ public: /// Implementation of IRenderDevice::CreateComputePipelineState() in Direct3D12 backend. virtual void DILIGENT_CALL_TYPE CreateComputePipelineState(const ComputePipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState) override final; + /// Implementation of IRenderDevice::CreateRayTracingPipelineState() in Direct3D12 backend. + virtual void DILIGENT_CALL_TYPE CreateRayTracingPipelineState(const RayTracingPipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState) override final; + /// Implementation of IRenderDevice::CreateBuffer() in Direct3D12 backend. virtual void DILIGENT_CALL_TYPE CreateBuffer(const BufferDesc& BuffDesc, const BufferData* pBuffData, @@ -104,6 +107,18 @@ public: virtual void DILIGENT_CALL_TYPE CreateFramebuffer(const FramebufferDesc& Desc, IFramebuffer** ppFramebuffer) override final; + /// Implementation of IRenderDevice::CreateBLAS() in Direct3D12 backend. + virtual void DILIGENT_CALL_TYPE CreateBLAS(const BottomLevelASDesc& Desc, + IBottomLevelAS** ppBLAS) override final; + + /// Implementation of IRenderDevice::CreateTLAS() in Direct3D12 backend. + virtual void DILIGENT_CALL_TYPE CreateTLAS(const TopLevelASDesc& Desc, + ITopLevelAS** ppTLAS) override final; + + /// Implementation of IRenderDevice::CreateSBT() in Direct3D12 backend. + virtual void DILIGENT_CALL_TYPE CreateSBT(const ShaderBindingTableDesc& Desc, + IShaderBindingTable** ppSBT) override final; + /// Implementation of IRenderDeviceD3D12::GetD3D12Device(). virtual ID3D12Device* DILIGENT_CALL_TYPE GetD3D12Device() override final { return m_pd3d12Device; } @@ -118,6 +133,18 @@ public: RESOURCE_STATE InitialState, IBuffer** ppBuffer) override final; + /// Implementation of IRenderDeviceD3D12::CreateBLASFromD3DResource(). + virtual void DILIGENT_CALL_TYPE CreateBLASFromD3DResource(ID3D12Resource* pd3d12BLAS, + const BottomLevelASDesc& Desc, + RESOURCE_STATE InitialState, + IBottomLevelAS** ppBLAS) override final; + + /// Implementation of IRenderDeviceD3D12::CreateTLASFromD3DResource(). + virtual void DILIGENT_CALL_TYPE CreateTLASFromD3DResource(ID3D12Resource* pd3d12TLAS, + const TopLevelASDesc& Desc, + RESOURCE_STATE InitialState, + ITopLevelAS** ppTLAS) override final; + DescriptorHeapAllocation AllocateDescriptor(D3D12_DESCRIPTOR_HEAP_TYPE Type, UINT Count = 1); DescriptorHeapAllocation AllocateGPUDescriptors(D3D12_DESCRIPTOR_HEAP_TYPE Type, UINT Count = 1); @@ -157,12 +184,25 @@ public: IDXCompiler* GetDxCompiler() const { return m_pDxCompiler.get(); } -#ifdef D3D12_H_HAS_MESH_SHADER ID3D12Device2* GetD3D12Device2(); -#endif + ID3D12Device5* GetD3D12Device5(); - ShaderVersion GetMaxShaderModel() const; - D3D_FEATURE_LEVEL GetD3DFeatureLevel() const; + struct Properties + { + const Uint32 ShaderGroupHandleSize = D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES; + const Uint32 MaxShaderRecordStride = D3D12_RAYTRACING_MAX_SHADER_RECORD_STRIDE; + const Uint32 ShaderGroupBaseAlignment = D3D12_RAYTRACING_SHADER_TABLE_BYTE_ALIGNMENT; + const Uint32 MaxDrawMeshTasksCount = 64000; // from specs: https://microsoft.github.io/DirectX-Specs/d3d/MeshShader.html#dispatchmesh-api + const Uint32 MaxRayTracingRecursionDepth = D3D12_RAYTRACING_MAX_DECLARABLE_TRACE_RECURSION_DEPTH; + const Uint32 MaxRayGenThreads = D3D12_RAYTRACING_MAX_RAY_GENERATION_SHADER_THREADS; + + ShaderVersion MaxShaderVersion; + }; + + const Properties& GetProperties() const + { + return m_Properties; + } private: template <typename PSOCreateInfoType> @@ -173,9 +213,8 @@ private: CComPtr<ID3D12Device> m_pd3d12Device; -#ifdef D3D12_H_HAS_MESH_SHADER CComPtr<ID3D12Device2> m_pd3d12Device2; -#endif + CComPtr<ID3D12Device5> m_pd3d12Device5; EngineD3D12CreateInfo m_EngineAttribs; @@ -198,7 +237,7 @@ private: QueryManagerD3D12 m_QueryMgr; - D3D_SHADER_MODEL m_MaxShaderModel = D3D_SHADER_MODEL_5_1; + Properties m_Properties; std::unique_ptr<IDXCompiler> m_pDxCompiler; }; diff --git a/Graphics/GraphicsEngineD3D12/include/RenderPassD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/RenderPassD3D12Impl.hpp index 501e62df..00984731 100644 --- a/Graphics/GraphicsEngineD3D12/include/RenderPassD3D12Impl.hpp +++ b/Graphics/GraphicsEngineD3D12/include/RenderPassD3D12Impl.hpp @@ -39,7 +39,7 @@ namespace Diligent class FixedBlockMemoryAllocator; -/// Render pass implementation in Direct3D11 backend. +/// Render pass implementation in Direct3D12 backend. class RenderPassD3D12Impl final : public RenderPassBase<IRenderPass, RenderDeviceD3D12Impl> { public: diff --git a/Graphics/GraphicsEngineD3D12/include/RootSignature.hpp b/Graphics/GraphicsEngineD3D12/include/RootSignature.hpp index 232bce65..44b83433 100644 --- a/Graphics/GraphicsEngineD3D12/include/RootSignature.hpp +++ b/Graphics/GraphicsEngineD3D12/include/RootSignature.hpp @@ -32,12 +32,11 @@ #include <array> #include "ShaderResourceLayoutD3D12.hpp" #include "BufferD3D12Impl.hpp" +#include "D3D12TypeConversions.hpp" namespace Diligent { -SHADER_TYPE ShaderTypeFromShaderVisibility(D3D12_SHADER_VISIBILITY ShaderVisibility); -D3D12_SHADER_VISIBILITY GetShaderVisibility(SHADER_TYPE ShaderType); D3D12_DESCRIPTOR_HEAP_TYPE dbgHeapTypeFromRangeType(D3D12_DESCRIPTOR_RANGE_TYPE RangeType); class RootParameter @@ -299,32 +298,15 @@ private: /// Implementation of the Diligent::RootSignature class class RootSignature { + friend class RootSignatureBuilder; + public: RootSignature(); - void AllocateImmutableSamplers(const PipelineResourceLayoutDesc& ResourceLayout); - - void Finalize(ID3D12Device* pd3d12Device); - ID3D12RootSignature* GetD3D12RootSignature() const { return m_pd3d12RootSignature; } - size_t GetResourceCacheRequiredMemSize() const; - void InitResourceCache(class RenderDeviceD3D12Impl* pDeviceD3D12Impl, class ShaderResourceCacheD3D12& ResourceCache, IMemoryAllocator& CacheMemAllocator) const; - void InitImmutableSampler(SHADER_TYPE ShaderType, - const char* SamplerName, - const char* SamplerSuffix, - const D3DShaderResourceAttribs& ShaderResAttribs); - - void AllocateResourceSlot(SHADER_TYPE ShaderType, - PIPELINE_TYPE PipelineType, - const D3DShaderResourceAttribs& ShaderResAttribs, - SHADER_RESOURCE_VARIABLE_TYPE VariableType, - D3D12_DESCRIPTOR_RANGE_TYPE RangeType, - Uint32& RootIndex, - Uint32& OffsetFromTableStart); - // This method should be thread-safe as it does not modify any object state void (RootSignature::*CommitDescriptorHandles)(class RenderDeviceD3D12Impl* pRenderDeviceD3D12, ShaderResourceCacheD3D12& ResourceCache, @@ -375,10 +357,6 @@ public: } private: -#ifdef DILIGENT_DEBUG - void dbgVerifyRootParameters() const; -#endif - #ifdef DILIGENT_DEVELOPMENT static void DvpVerifyResourceState(const ShaderResourceCacheD3D12::Resource& Res, D3D12_DESCRIPTOR_RANGE_TYPE RangeType); @@ -481,23 +459,6 @@ private: RootParamsManager m_RootParams; - struct ImmutableSamplerAttribs - { - ImmutableSamplerDesc SamplerDesc; - UINT ShaderRegister = static_cast<UINT>(-1); - UINT ArraySize = 0; - UINT RegisterSpace = 0; - D3D12_SHADER_VISIBILITY ShaderVisibility = static_cast<D3D12_SHADER_VISIBILITY>(-1); - - ImmutableSamplerAttribs() noexcept {} - ImmutableSamplerAttribs(const ImmutableSamplerDesc& SamDesc, D3D12_SHADER_VISIBILITY Visibility) noexcept : - SamplerDesc(SamDesc), - ShaderVisibility(Visibility) - {} - }; - // Note: sizeof(m_ImmutableSamplers) == 56 (MS compiler, release x64) - std::vector<ImmutableSamplerAttribs, STDAllocatorRawMem<ImmutableSamplerAttribs>> m_ImmutableSamplers; - IMemoryAllocator& m_MemAllocator; // Commits descriptor handles for static and mutable variables @@ -516,6 +477,71 @@ private: bool ValidateStates) const; }; + +class RootSignatureBuilder +{ +public: + explicit RootSignatureBuilder(RootSignature& RootSig); + + void AllocateImmutableSamplers(const PipelineResourceLayoutDesc& ResourceLayout); + + void InitImmutableSampler(SHADER_TYPE ShaderType, + const char* SamplerName, + const char* SamplerSuffix, + const D3DShaderResourceAttribs& ShaderResAttribs); + + void AllocateResourceSlot(SHADER_TYPE ShaderType, + PIPELINE_TYPE PipelineType, + const D3DShaderResourceAttribs& ShaderResAttribs, + SHADER_RESOURCE_VARIABLE_TYPE VariableType, + D3D12_DESCRIPTOR_RANGE_TYPE RangeType, + Uint32& BindPoint, + Uint32& RootIndex, + Uint32& OffsetFromTableStart); + + void Finalize(ID3D12Device* pd3d12Device); + + size_t GetResourceCacheRequiredMemSize() const; + + size_t GetHash() const + { + return m_RootSig.GetHash(); + } + + // Note: sizeof(m_ImmutableSamplers) == 56 (MS compiler, release x64) + struct ImmutableSamplerAttribs + { + ImmutableSamplerDesc SamplerDesc; + UINT ShaderRegister = static_cast<UINT>(-1); + UINT ArraySize = 0; + UINT RegisterSpace = 0; + D3D12_SHADER_VISIBILITY ShaderVisibility = static_cast<D3D12_SHADER_VISIBILITY>(-1); + String Name; + SHADER_TYPE ShaderType = SHADER_TYPE_UNKNOWN; + + ImmutableSamplerAttribs() noexcept {} + ImmutableSamplerAttribs(const ImmutableSamplerDesc& SamDesc, D3D12_SHADER_VISIBILITY Visibility, SHADER_TYPE Stage) noexcept : + SamplerDesc(SamDesc), + ShaderVisibility(Visibility), + ShaderType{Stage} + {} + }; + const ImmutableSamplerAttribs* GetImmutableSamplers() const { return m_ImmutableSamplers.data(); } + size_t GetImmutableSamplerCount() const { return m_ImmutableSamplers.size(); } + +private: +#ifdef DILIGENT_DEBUG + void dbgVerifyRootParameters() const; +#endif + + RootSignature& m_RootSig; + + std::array<Uint16, D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER + 1> m_NumResources = {}; + + std::vector<ImmutableSamplerAttribs, STDAllocatorRawMem<ImmutableSamplerAttribs>> m_ImmutableSamplers; +}; + + void RootSignature::CommitRootViews(ShaderResourceCacheD3D12& ResourceCache, CommandContext& CmdCtx, bool IsCompute, @@ -537,7 +563,7 @@ void RootSignature::CommitRootViews(ShaderResourceCacheD3D12& ResourceCache, { auto& Param = static_cast<const D3D12_ROOT_PARAMETER&>(RootView); VERIFY_EXPR(Param.ParameterType == D3D12_ROOT_PARAMETER_TYPE_CBV); - dbgShaderType = ShaderTypeFromShaderVisibility(Param.ShaderVisibility); + dbgShaderType = D3D12ShaderVisibilityToShaderType(Param.ShaderVisibility); } #endif @@ -588,4 +614,23 @@ void RootSignature::CommitRootViews(ShaderResourceCacheD3D12& ResourceCache, } } + +class LocalRootSignature +{ +public: + LocalRootSignature(const char* pCBName, Uint32 ShaderRecordSize); + + bool SetOrMerge(const D3DShaderResourceAttribs& CB); + + ID3D12RootSignature* Create(ID3D12Device* pDevice); + +private: + static constexpr Uint32 InvalidBindPoint = ~0u; + + const char* m_pName = nullptr; + Uint32 m_BindPoint = InvalidBindPoint; + const Uint32 m_ShaderRecordSize = 0; + CComPtr<ID3D12RootSignature> m_pd3d12RootSignature; +}; + } // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/include/ShaderBindingTableD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/ShaderBindingTableD3D12Impl.hpp new file mode 100644 index 00000000..ca1442c5 --- /dev/null +++ b/Graphics/GraphicsEngineD3D12/include/ShaderBindingTableD3D12Impl.hpp @@ -0,0 +1,59 @@ +/* + * Copyright 2019-2020 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#pragma once + +/// \file +/// Declaration of Diligent::ShaderBindingTableD3D12Impl class + +#include "ShaderBindingTableD3D12.h" +#include "RenderDeviceD3D12.h" +#include "ShaderBindingTableBase.hpp" +#include "TopLevelASD3D12Impl.hpp" +#include "D3D12ResourceBase.hpp" +#include "RenderDeviceD3D12Impl.hpp" +#include "PipelineStateD3D12Impl.hpp" + +namespace Diligent +{ + +/// Shader binding table object implementation in Direct3D12 backend. +class ShaderBindingTableD3D12Impl final : public ShaderBindingTableBase<IShaderBindingTableD3D12, PipelineStateD3D12Impl, TopLevelASD3D12Impl, RenderDeviceD3D12Impl>, public D3D12ResourceBase +{ +public: + using TShaderBindingTableBase = ShaderBindingTableBase<IShaderBindingTableD3D12, PipelineStateD3D12Impl, TopLevelASD3D12Impl, RenderDeviceD3D12Impl>; + + ShaderBindingTableD3D12Impl(IReferenceCounters* pRefCounters, + class RenderDeviceD3D12Impl* pDeviceD3D12, + const ShaderBindingTableDesc& Desc, + bool bIsDeviceInternal = false); + ~ShaderBindingTableD3D12Impl(); + + virtual void DILIGENT_CALL_TYPE QueryInterface(const INTERFACE_ID& IID, IObject** ppInterface) override final; +}; + +} // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/include/ShaderD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/ShaderD3D12Impl.hpp index b2143b76..0b9b6fee 100644 --- a/Graphics/GraphicsEngineD3D12/include/ShaderD3D12Impl.hpp +++ b/Graphics/GraphicsEngineD3D12/include/ShaderD3D12Impl.hpp @@ -34,9 +34,8 @@ #include "ShaderD3D12.h" #include "ShaderBase.hpp" #include "ShaderD3DBase.hpp" -#include "ShaderResourceLayoutD3D12.hpp" #include "RenderDeviceD3D12Impl.hpp" -#include "ShaderVariableD3D12.hpp" +#include "ShaderResourcesD3D12.hpp" namespace Diligent { @@ -74,7 +73,8 @@ public: ResourceDesc = m_pShaderResources->GetHLSLShaderResourceDesc(Index); } - ID3DBlob* GetShaderByteCode() { return m_pShaderByteCode; } + ID3DBlob* GetShaderByteCode() { return m_pShaderByteCode; } + const Char* GetEntryPoint() const { return m_EntryPoint.c_str(); } const std::shared_ptr<const ShaderResourcesD3D12>& GetShaderResources() const { return m_pShaderResources; } @@ -82,6 +82,8 @@ private: // ShaderResources class instance must be referenced through the shared pointer, because // it is referenced by ShaderResourceLayoutD3D12 class instances std::shared_ptr<const ShaderResourcesD3D12> m_pShaderResources; + + String m_EntryPoint; }; } // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/include/ShaderResourceBindingD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/ShaderResourceBindingD3D12Impl.hpp index 7be3372d..f1eb5c85 100644 --- a/Graphics/GraphicsEngineD3D12/include/ShaderResourceBindingD3D12Impl.hpp +++ b/Graphics/GraphicsEngineD3D12/include/ShaderResourceBindingD3D12Impl.hpp @@ -85,7 +85,8 @@ private: // Resource layout index in m_ShaderResourceCache array for every shader stage, // indexed by the shader type pipeline index (returned by GetShaderTypePipelineIndex) - std::array<Int8, MAX_SHADERS_IN_PIPELINE> m_ResourceLayoutIndex = {-1, -1, -1, -1, -1}; + std::array<Int8, MAX_SHADERS_IN_PIPELINE> m_ResourceLayoutIndex = {-1, -1, -1, -1, -1, -1}; + static_assert(MAX_SHADERS_IN_PIPELINE == 6, "Please update the initializer list above"); bool m_bStaticResourcesInitialized = false; const Uint8 m_NumShaders = 0; diff --git a/Graphics/GraphicsEngineD3D12/include/ShaderResourceCacheD3D12.hpp b/Graphics/GraphicsEngineD3D12/include/ShaderResourceCacheD3D12.hpp index 8a8f7b25..73ebe3b8 100644 --- a/Graphics/GraphicsEngineD3D12/include/ShaderResourceCacheD3D12.hpp +++ b/Graphics/GraphicsEngineD3D12/include/ShaderResourceCacheD3D12.hpp @@ -97,6 +97,7 @@ enum class CachedResourceType : Int32 TexUAV, BufUAV, Sampler, + AccelStruct, NumTypes }; @@ -166,7 +167,7 @@ public: const SHADER_TYPE dbgRefShaderType) const { VERIFY(m_dbgHeapType == dbgDescriptorHeapType, "Incosistent descriptor heap type"); - VERIFY(m_dbgShaderType == dbgRefShaderType, "Incosistent shader type"); + VERIFY(dbgRefShaderType == SHADER_TYPE_UNKNOWN || m_dbgShaderType == SHADER_TYPE_UNKNOWN || m_dbgShaderType == dbgRefShaderType, "Incosistent shader type"); VERIFY(OffsetFromTableStart < m_NumResources, "Root table is not large enough to store descriptor at offset ", OffsetFromTableStart); return m_pResources[OffsetFromTableStart]; diff --git a/Graphics/GraphicsEngineD3D12/include/ShaderResourceLayoutD3D12.hpp b/Graphics/GraphicsEngineD3D12/include/ShaderResourceLayoutD3D12.hpp index 719345fc..de0ecc29 100644 --- a/Graphics/GraphicsEngineD3D12/include/ShaderResourceLayoutD3D12.hpp +++ b/Graphics/GraphicsEngineD3D12/include/ShaderResourceLayoutD3D12.hpp @@ -50,22 +50,9 @@ // m' == NumSamplers[SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE] // d' == NumSamplers[SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC] // -// Every D3D12Resource structure holds a reference to D3DShaderResourceAttribs structure from ShaderResourcesD3D12. -// ShaderResourceLayoutD3D12 holds shared pointer to ShaderResourcesD3D12 instance. Note that ShaderResourcesD3D12::SamplerId -// references a sampler in ShaderResourcesD3D12, while D3D12Resource::SamplerId references a sampler in ShaderResourceLayoutD3D12, -// and the two are not necessarily the same // // -// ________________SamplerId____________________ -// | | -// _____________________ ______________|_____________________________________________V________ -// | | unique_ptr | | | | | | | -// |ShaderResourcesD3D12 |--------------->| CBs | TexSRVs | TexUAVs | BufSRVs | BufUAVs | Samplers | -// |_____________________| |________|___________|___________|___________|___________|____________| -// A A A A -// | \ / \ -// |shared_ptr Ref Ref Ref -// ________|__________________ ________\________________________/_________________________\________________________________________________ +// ___________________________ ____________________________________________________________________________________________________________ // | | unique_ptr | | | | | | | // | ShaderResourceLayoutD3D12 |--------------->| D3D12Resource[0] | D3D12Resource[1] | ... | D3D12Resource[smd] | D3D12Resource[smd+1] | ... | // |___________________________| |__________________|__________________|_______________|____________________|______________________|__________| @@ -79,9 +66,27 @@ // | | | | | | // | ShaderVariableManagerD3D12 |---------------->| ShaderVariableD3D12Impl[0] | ShaderVariableD3D12Impl[1] | ... | // |____________________________| |____________________________|____________________________|_________________| - // -// http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-layout#Figure2 +// +// +// +// +// One ShaderResourceLayoutD3D12 instance can be referenced by multiple objects +// +// +// ________________________ _<m_pShaderResourceLayouts>_ _____<m_pShaderVarMgrs>_____ ________________________________ +// | | | | | | | | +// | PipelineStateD3D12Impl |========>| ShaderResourceLayoutD3D12 |<-------| ShaderVariableManagerD3D12 |<====| ShaderResourceBindingD3D12Impl | +// |________________________| |____________________________| |____________________________| |________________________________| +// A +// \ +// \ _____<m_pShaderVarMgrs>_____ ________________________________ +// \ | | | | +// '-------| ShaderVariableManagerD3D12 |<====| ShaderResourceBindingD3D12Impl | +// |____________________________| |________________________________| +// +// +// // Resources in the resource cache are identified by the root index and offset in the descriptor table // // @@ -101,35 +106,42 @@ #include <array> #include "ShaderBase.hpp" -#include "ShaderResourcesD3D12.hpp" #include "ShaderResourceCacheD3D12.hpp" +#include "ShaderD3D12Impl.hpp" +#include "StringPool.hpp" +#include "D3DCommonTypeConversions.hpp" namespace Diligent { /// Diligent::ShaderResourceLayoutD3D12 class -// sizeof(ShaderResourceLayoutD3D12) == 64 (MS compiler, x64) +// sizeof(ShaderResourceLayoutD3D12) == 56 (MS compiler, x64) class ShaderResourceLayoutD3D12 final { public: explicit ShaderResourceLayoutD3D12(IObject& Owner) noexcept : m_Owner{Owner} - {} + { +#if defined(_MSC_VER) && defined(_WIN64) + static_assert(sizeof(*this) == 56, "Unexpected sizeof(ShaderResourceLayoutD3D12)"); +#endif + } // There are two modes a layout can be initialized: // - initialize static resource layout and initialize shader resource cache to hold static resources // - initialize reference layouts that address all types of resources (static, mutable, dynamic). // Root indices and descriptor table offsets are assigned during the initialization; // no shader resource cache is provided - void Initialize(ID3D12Device* pd3d12Device, - PIPELINE_TYPE PipelineType, - const PipelineResourceLayoutDesc& ResourceLayout, - std::shared_ptr<const ShaderResourcesD3D12> pSrcResources, - IMemoryAllocator& LayoutDataAllocator, - const SHADER_RESOURCE_VARIABLE_TYPE* const VarTypes, - Uint32 NumAllowedTypes, - ShaderResourceCacheD3D12* pResourceCache, - class RootSignature* pRootSig); + void Initialize(ID3D12Device* pd3d12Device, + PIPELINE_TYPE PipelineType, + const PipelineResourceLayoutDesc& ResourceLayout, + const std::vector<ShaderD3D12Impl*>& Shaders, + IMemoryAllocator& LayoutDataAllocator, + const SHADER_RESOURCE_VARIABLE_TYPE* const VarTypes, + Uint32 NumAllowedTypes, + ShaderResourceCacheD3D12* pResourceCache, + class RootSignatureBuilder* pRootSig, + class LocalRootSignature* pLocalRootSig); // clang-format off ShaderResourceLayoutD3D12 (const ShaderResourceLayoutD3D12&) = delete; @@ -140,7 +152,7 @@ public: ~ShaderResourceLayoutD3D12(); - // sizeof(D3D12Resource) == 24 (x64) + // sizeof(D3D12Resource) == 32 (x64) struct D3D12Resource final { // clang-format off @@ -152,52 +164,59 @@ public: static constexpr const Uint32 ResourceTypeBits = 3; static constexpr const Uint32 VariableTypeBits = 2; - static constexpr const Uint32 RootIndexBits = 16 - ResourceTypeBits - VariableTypeBits; + static constexpr const Uint32 RootIndexBits = 32 - ResourceTypeBits - VariableTypeBits; - static constexpr const Uint32 InvalidRootIndex = (1 << RootIndexBits) - 1; - static constexpr const Uint32 MaxRootIndex = InvalidRootIndex - 1; + static constexpr const Uint32 InvalidRootIndex = (1U << RootIndexBits) - 1U; + static constexpr const Uint32 MaxRootIndex = InvalidRootIndex - 1U; - static constexpr const Uint32 InvalidSamplerId = 0xFFFF; - static constexpr const Uint32 MaxSamplerId = InvalidSamplerId-1; static constexpr const Uint32 InvalidOffset = static_cast<Uint32>(-1); - static_assert( SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES < (1 << VariableTypeBits), "2 bits is not enough to store SHADER_RESOURCE_VARIABLE_TYPE"); - static_assert( static_cast<int>(CachedResourceType::NumTypes) < (1 << ResourceTypeBits), "3 bits is not enough to store CachedResourceType"); - + static_assert(SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES < (1 << VariableTypeBits), "Not enough bits to represent SHADER_RESOURCE_VARIABLE_TYPE"); + static_assert(static_cast<int>(CachedResourceType::NumTypes) < (1 << ResourceTypeBits), "Not enough bits to represent CachedResourceType"); + /* 0 */ const ShaderResourceLayoutD3D12& ParentResLayout; -/* 8 */ const D3DShaderResourceAttribs& Attribs; -/*16 */ const Uint32 OffsetFromTableStart; -/*20.0*/ const Uint16 ResourceType : ResourceTypeBits; // | 0 1 2 | -/*20.3*/ const Uint16 VariableType : VariableTypeBits; // | 3 4 | -/*20.5*/ const Uint16 RootIndex : RootIndexBits; // | 5 6 7 ... 15 | -/*22 */ const Uint16 SamplerId; -/*24 */ // End of data +/* 8 */ const D3DShaderResourceAttribs Attribs; +/*24 */ const Uint32 OffsetFromTableStart; +/*28.0*/ const Uint32 ResourceType : ResourceTypeBits; // | 0 1 2 | +/*28.3*/ const Uint32 VariableType : VariableTypeBits; // | 3 4 | +/*28.5*/ const Uint32 RootIndex : RootIndexBits; // | 5 6 7 ... 15 | +/*32 */ // End of data // clang-format on D3D12Resource(const ShaderResourceLayoutD3D12& _ParentLayout, + StringPool& _StringPool, const D3DShaderResourceAttribs& _Attribs, + Uint32 _SamplerId, SHADER_RESOURCE_VARIABLE_TYPE _VariableType, CachedResourceType _ResType, + Uint32 _BindPoint, Uint32 _RootIndex, - Uint32 _OffsetFromTableStart, - Uint32 _SamplerId) noexcept : + Uint32 _OffsetFromTableStart) noexcept : // clang-format off - ParentResLayout {_ParentLayout }, - Attribs {_Attribs }, - ResourceType {static_cast<Uint16>(_ResType) }, - VariableType {static_cast<Uint16>(_VariableType)}, - RootIndex {static_cast<Uint16>(_RootIndex) }, - SamplerId {static_cast<Uint16>(_SamplerId) }, + ParentResLayout{_ParentLayout}, + Attribs + { + _StringPool, + _Attribs, + _SamplerId, + _BindPoint + }, + ResourceType {static_cast<Uint32>(_ResType) }, + VariableType {static_cast<Uint32>(_VariableType)}, + RootIndex {static_cast<Uint32>(_RootIndex) }, OffsetFromTableStart{ _OffsetFromTableStart } // clang-format on { +#if defined(_MSC_VER) && defined(_WIN64) + static_assert(sizeof(*this) == 32, "Unexpected sizeof(D3D12Resource)"); +#endif + VERIFY(IsValidOffset(), "Offset must be valid"); VERIFY(IsValidRootIndex(), "Root index must be valid"); VERIFY(_RootIndex <= MaxRootIndex, "Root index (", _RootIndex, ") exceeds max allowed value (", MaxRootIndex, ")"); + VERIFY(static_cast<Uint32>(_ResType) < (1 << ResourceTypeBits), "Resource type is out of representable range"); VERIFY(_VariableType < (1 << VariableTypeBits), "Variable type is out of representable range"); - VERIFY(_SamplerId == InvalidSamplerId || _SamplerId <= MaxSamplerId, "Sampler id (", _SamplerId, ") exceeds max allowed value (", MaxSamplerId, ")"); - VERIFY(_SamplerId == InvalidSamplerId || GetResType() == CachedResourceType::TexSRV, "A sampler can only be assigned to a Texture SRV"); } bool IsBound(Uint32 ArrayIndex, @@ -208,9 +227,8 @@ public: ShaderResourceCacheD3D12& ResourceCache) const; // clang-format off - bool ValidSamplerAssigned()const { return SamplerId != InvalidSamplerId; } - bool IsValidRootIndex() const { return RootIndex != InvalidRootIndex; } - bool IsValidOffset() const { return OffsetFromTableStart != InvalidOffset; } + bool IsValidRootIndex() const { return RootIndex != InvalidRootIndex; } + bool IsValidOffset() const { return OffsetFromTableStart != InvalidOffset; } // clang-format on CachedResourceType GetResType() const { return static_cast<CachedResourceType>(ResourceType); } @@ -237,6 +255,11 @@ public: ShaderResourceCacheD3D12::Resource& DstSam, Uint32 ArrayIndex, D3D12_CPU_DESCRIPTOR_HANDLE ShdrVisibleHeapCPUDescriptorHandle) const; + + void CacheAccelStruct(IDeviceObject* pTLAS, + ShaderResourceCacheD3D12::Resource& DstRes, + Uint32 ArrayIndex, + D3D12_CPU_DESCRIPTOR_HANDLE ShdrVisibleHeapCPUDescriptorHandle) const; }; void CopyStaticResourceDesriptorHandles(const ShaderResourceCacheD3D12& SrcCache, @@ -272,11 +295,11 @@ public: return GetResource(GetSamplerOffset(VarType, s)); } - const bool IsUsingSeparateSamplers() const { return !m_pResources->IsUsingCombinedTextureSamplers(); } + const bool IsUsingSeparateSamplers() const { return m_IsUsingSeparateSamplers; } - SHADER_TYPE GetShaderType() const { return m_pResources->GetShaderType(); } + SHADER_TYPE GetShaderType() const { return m_ShaderType; } - const ShaderResourcesD3D12& GetResources() const { return *m_pResources; } + bool IsCompatibleWith(const ShaderResourceLayoutD3D12& ResLayout) const; private: const D3D12Resource& GetAssignedSampler(const D3D12Resource& TexSrv) const; @@ -284,7 +307,7 @@ private: const Char* GetShaderName() const { - return m_pResources->GetShaderName(); + return GetStringPoolData(); } @@ -305,14 +328,14 @@ private: D3D12Resource& GetResource(Uint32 r) { VERIFY_EXPR(r < GetTotalResourceCount()); - auto* Resource = reinterpret_cast<D3D12Resource*>(m_ResourceBuffer.get()); - return Resource[r]; + auto* Resources = reinterpret_cast<D3D12Resource*>(m_ResourceBuffer.get()); + return Resources[r]; } const D3D12Resource& GetResource(Uint32 r) const { VERIFY_EXPR(r < GetTotalResourceCount()); - auto* Resource = reinterpret_cast<const D3D12Resource*>(m_ResourceBuffer.get()); - return Resource[r]; + const auto* Resources = reinterpret_cast<const D3D12Resource*>(m_ResourceBuffer.get()); + return Resources[r]; } Uint32 GetSrvCbvUavOffset(SHADER_RESOURCE_VARIABLE_TYPE VarType, Uint32 r) const @@ -344,21 +367,27 @@ private: return GetResource(m_SamplersOffsets[0] + s); } - void AllocateMemory(IMemoryAllocator& Allocator, - const std::array<Uint32, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES>& CbvSrvUavCount, - const std::array<Uint32, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES>& SamplerCount); + const char* GetStringPoolData() const + { + const auto* Resources = reinterpret_cast<const D3D12Resource*>(m_ResourceBuffer.get()); + return reinterpret_cast<const char*>(Resources + GetTotalResourceCount()); + } + + StringPool AllocateMemory(IMemoryAllocator& Allocator, + const std::array<Uint32, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES>& CbvSrvUavCount, + const std::array<Uint32, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES>& SamplerCount, + size_t StringPoolSize); // clang-format off /* 0 */ std::unique_ptr<void, STDDeleterRawMem<void> > m_ResourceBuffer; /* 16 */ std::array<Uint16, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES + 1> m_CbvSrvUavOffsets = {}; /* 24 */ std::array<Uint16, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES + 1> m_SamplersOffsets = {}; -/* 32 */ IObject& m_Owner; -/* 48 */ CComPtr<ID3D12Device> m_pd3d12Device; - // We must use shared_ptr to reference ShaderResources instance, because - // there may be multiple objects referencing the same set of resources -/* 48 */ std::shared_ptr<const ShaderResourcesD3D12> m_pResources; -/* 64 */ // End of data +/* 32 */ IObject& m_Owner; +/* 40 */ CComPtr<ID3D12Device> m_pd3d12Device; +/* 48 */ SHADER_TYPE m_ShaderType = SHADER_TYPE_UNKNOWN; +/* */ bool m_IsUsingSeparateSamplers = false; +/* 56 */ // End of data // clang-format on }; diff --git a/Graphics/GraphicsEngineD3D12/include/ShaderResourcesD3D12.hpp b/Graphics/GraphicsEngineD3D12/include/ShaderResourcesD3D12.hpp index fe867d89..1c4af270 100644 --- a/Graphics/GraphicsEngineD3D12/include/ShaderResourcesD3D12.hpp +++ b/Graphics/GraphicsEngineD3D12/include/ShaderResourcesD3D12.hpp @@ -30,7 +30,7 @@ /// \file /// Declaration of Diligent::ShaderResourcesD3D12 class -// ShaderResourcesD3D12 are created by ShaderD3D12Impl instances. They are then referenced by ShaderResourceLayoutD3D12 objects, which are in turn +// ShaderResourcesD3D12 are created by ShaderD3D12Impl instances. They are then used by ShaderResourceLayoutD3D12 objects, which are // created by instances of PipelineStatesD3D12Impl and ShaderD3D12Impl // // _________________ @@ -43,10 +43,10 @@ // | | unique_ptr | | | | | | | // | ShaderResourcesD3D12 |--------------->| CBs | TexSRVs | TexUAVs | BufSRVs | BufUAVs | Samplers | // |______________________| |________|___________|___________|___________|___________|____________| -// A A A A -// | \ / \ -// |shared_ptr Ref Ref Ref -// ________|__________________ ________\________________________/_________________________\_________________________________________ +// A A A +// \ / \ +// Copy Copy Copy +// ___________________________ ________\________________________/_________________________\_________________________________________ // | | unique_ptr | | | | | | | // | ShaderResourceLayoutD3D12 |--------------->| SRV_CBV_UAV[0] | SRV_CBV_UAV[1] | ... | Sampler[0] | Sampler[1] | ... | // |___________________________| |___________________|_________________|_______________|__________________|_________________|__________| @@ -58,29 +58,6 @@ // | PipelineStateD3D12Impl | // |________________________| // -// -// -// One ShaderResourcesD3D12 instance can be referenced by multiple objects -// -// -// ________________________ _<m_pShaderResourceLayouts>_ _____<m_pShaderVarMgrs>_____ ________________________________ -// | | | | | | | | -// | PipelineStateD3D12Impl |========>| ShaderResourceLayoutD3D12 |<-------| ShaderVariableManagerD3D12 |<====| ShaderResourceBindingD3D12Impl | -// |________________________| |____________________________| |____________________________| |________________________________| -// | A -// |shared_ptr \ -// _________________ ___________V__________ \ _____<m_pShaderVarMgrs>_____ ________________________________ -// | | shared_ptr | | \ | | | | -// | ShaderD3D12Impl |---------------->| ShaderResourcesD3D12 | '-------| ShaderVariableManagerD3D12 |<====| ShaderResourceBindingD3D12Impl | -// |_________________| |______________________| |____________________________| |________________________________| -// | |___________________ A -// | | | -// V V |shared_ptr -// _______<m_StaticVarsMgr>____ ___<m_StaticResLayout>_|___ -// | | | | -// | ShaderVariableManagerD3D12 |------>| ShaderResourceLayoutD3D12 | -// |____________________________| |___________________________| -// #include "ShaderResources.hpp" diff --git a/Graphics/GraphicsEngineD3D12/include/TopLevelASD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/TopLevelASD3D12Impl.hpp new file mode 100644 index 00000000..522fd426 --- /dev/null +++ b/Graphics/GraphicsEngineD3D12/include/TopLevelASD3D12Impl.hpp @@ -0,0 +1,83 @@ +/* + * Copyright 2019-2020 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#pragma once + +/// \file +/// Declaration of Diligent::TopLevelASD3D12Impl class + +#include "TopLevelASD3D12.h" +#include "RenderDeviceD3D12.h" +#include "TopLevelASBase.hpp" +#include "BottomLevelASD3D12Impl.hpp" +#include "D3D12ResourceBase.hpp" +#include "RenderDeviceD3D12Impl.hpp" + +namespace Diligent +{ + +/// Top-level acceleration structure object implementation in Direct3D12 backend. +class TopLevelASD3D12Impl final : public TopLevelASBase<ITopLevelASD3D12, BottomLevelASD3D12Impl, RenderDeviceD3D12Impl>, public D3D12ResourceBase +{ +public: + using TTopLevelASBase = TopLevelASBase<ITopLevelASD3D12, BottomLevelASD3D12Impl, RenderDeviceD3D12Impl>; + + TopLevelASD3D12Impl(IReferenceCounters* pRefCounters, + class RenderDeviceD3D12Impl* pDeviceD3D12, + const TopLevelASDesc& Desc); + TopLevelASD3D12Impl(IReferenceCounters* pRefCounters, + class RenderDeviceD3D12Impl* pDeviceD3D12, + const TopLevelASDesc& Desc, + RESOURCE_STATE InitialState, + ID3D12Resource* pd3d12TLAS); + ~TopLevelASD3D12Impl(); + + IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_TopLevelASD3D12, TTopLevelASBase); + + /// Implementation of ITopLevelASD3D12D3D12::GetD3D12TLAS(). + virtual ID3D12Resource* DILIGENT_CALL_TYPE GetD3D12TLAS() override final { return GetD3D12Resource(); } + + /// Implementation of ITopLevelASD3D12::GetNativeHandle() in Direct3D12 backend. + virtual void* DILIGENT_CALL_TYPE GetNativeHandle() override final { return GetD3D12TLAS(); } + + D3D12_GPU_VIRTUAL_ADDRESS GetGPUAddress() + { + return GetD3D12Resource()->GetGPUVirtualAddress(); + } + + /// Implementation of ITopLevelASD3D12::GetCPUDescriptorHandle() in Direct3D12 backend. + virtual D3D12_CPU_DESCRIPTOR_HANDLE DILIGENT_CALL_TYPE GetCPUDescriptorHandle() override final + { + return m_DescriptorHandle.GetCpuHandle(); + } + +private: + // Allocation in a CPU-only descriptor heap + DescriptorHeapAllocation m_DescriptorHandle; +}; + +} // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/interface/BottomLevelASD3D12.h b/Graphics/GraphicsEngineD3D12/interface/BottomLevelASD3D12.h new file mode 100644 index 00000000..bcfe3d73 --- /dev/null +++ b/Graphics/GraphicsEngineD3D12/interface/BottomLevelASD3D12.h @@ -0,0 +1,70 @@ +/* + * Copyright 2019-2020 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#pragma once + +/// \file +/// Definition of the Diligent::IBottomLevelASD3D12 interface + +#include "../../GraphicsEngine/interface/BottomLevelAS.h" +#include "../../GraphicsEngine/interface/DeviceContext.h" + +DILIGENT_BEGIN_NAMESPACE(Diligent) + +// {610228AF-F161-4B12-A00E-71E6E3BB97FE} +static const INTERFACE_ID IID_BottomLevelASD3D12 = + {0x610228af, 0xf161, 0x4b12, {0xa0, 0xe, 0x71, 0xe6, 0xe3, 0xbb, 0x97, 0xfe}}; + +#define DILIGENT_INTERFACE_NAME IBottomLevelASD3D12 +#include "../../../Primitives/interface/DefineInterfaceHelperMacros.h" + +#define IBottomLevelASD3D12InclusiveMethods \ + IBottomLevelASInclusiveMethods; \ + IBottomLevelASD3D12Methods BottomLevelASD3D12 + +// clang-format off + +/// Exposes Direct3D12-specific functionality of a bottom-level acceleration structure object. +DILIGENT_BEGIN_INTERFACE(IBottomLevelASD3D12, IBottomLevelAS) +{ + /// Returns ID3D12Resource interface of the internal D3D12 acceleration structure object. + + /// The method does *NOT* call AddRef() on the returned interface, + /// so Release() must not be called. + VIRTUAL ID3D12Resource* METHOD(GetD3D12BLAS)(THIS) PURE; +}; +DILIGENT_END_INTERFACE + +#include "../../../Primitives/interface/UndefInterfaceHelperMacros.h" + +#if DILIGENT_C_INTERFACE + +# define IBottomLevelASD3D12_GetD3D12BLAS(This) CALL_IFACE_METHOD(BottomLevelASD3D12, GetD3D12BLAS, This) + +#endif + +DILIGENT_END_NAMESPACE // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/interface/PipelineStateD3D12.h b/Graphics/GraphicsEngineD3D12/interface/PipelineStateD3D12.h index fd219b95..bec8d338 100644 --- a/Graphics/GraphicsEngineD3D12/interface/PipelineStateD3D12.h +++ b/Graphics/GraphicsEngineD3D12/interface/PipelineStateD3D12.h @@ -54,6 +54,12 @@ DILIGENT_BEGIN_INTERFACE(IPipelineStateD3D12, IPipelineState) /// so Release() must not be called. VIRTUAL ID3D12PipelineState* METHOD(GetD3D12PipelineState)(THIS) CONST PURE; + /// Returns ID3D12StateObject interface of the internal D3D12 state object for ray tracing. + + /// The method does *NOT* call AddRef() on the returned interface, + /// so Release() must not be called. + VIRTUAL ID3D12StateObject* METHOD(GetD3D12StateObject)(THIS) CONST PURE; + /// Returns a pointer to the root signature object associated with this pipeline state. /// The method does *NOT* call AddRef() on the returned interface, @@ -69,6 +75,7 @@ DILIGENT_END_INTERFACE // clang-format off # define IPipelineStateD3D12_GetD3D12PipelineState(This) CALL_IFACE_METHOD(PipelineStateD3D12, GetD3D12PipelineState, This) +# define IPipelineStateD3D12_GetD3D12StateObject(This) CALL_IFACE_METHOD(PipelineStateD3D12, GetD3D12StateObject, This) # define IPipelineStateD3D12_GetD3D12RootSignature(This) CALL_IFACE_METHOD(PipelineStateD3D12, GetD3D12RootSignature, This) // clang-format on diff --git a/Graphics/GraphicsEngineD3D12/interface/RenderDeviceD3D12.h b/Graphics/GraphicsEngineD3D12/interface/RenderDeviceD3D12.h index 136f7307..6616126c 100644 --- a/Graphics/GraphicsEngineD3D12/interface/RenderDeviceD3D12.h +++ b/Graphics/GraphicsEngineD3D12/interface/RenderDeviceD3D12.h @@ -99,6 +99,38 @@ DILIGENT_BEGIN_INTERFACE(IRenderDeviceD3D12, IRenderDevice) const BufferDesc REF BuffDesc, RESOURCE_STATE InitialState, IBuffer** ppBuffer) PURE; + + /// Creates a bottom-level AS object from native d3d12 resoruce + + /// \param [in] pd3d12BLAS - Pointer to the native d3d12 acceleration structure resource + /// \param [in] Desc - Bottom-level AS description. + /// \param [in] InitialState - Initial BLAS state. Can be RESOURCE_STATE_UNKNOWN, RESOURCE_STATE_BUILD_AS_READ, RESOURCE_STATE_BUILD_AS_WRITE. + /// See Diligent::RESOURCE_STATE. + /// \param [out] ppBLAS - Address of the memory location where the pointer to the + /// bottom-level AS interface will be stored. + /// The function calls AddRef(), so that the new object will contain + /// one reference. + VIRTUAL void METHOD(CreateBLASFromD3DResource)(THIS_ + ID3D12Resource* pd3d12BLAS, + const BottomLevelASDesc REF Desc, + RESOURCE_STATE InitialState, + IBottomLevelAS** ppBLAS) PURE; + + /// Creates a top-level AS object from native d3d12 resoruce + + /// \param [in] pd3d12TLAS - Pointer to the native d3d12 acceleration structure resource + /// \param [in] Desc - Top-level AS description. + /// \param [in] InitialState - Initial TLAS state. Can be RESOURCE_STATE_UNKNOWN, RESOURCE_STATE_BUILD_AS_READ, RESOURCE_STATE_BUILD_AS_WRITE, RESOURCE_STATE_RAY_TRACING. + /// See Diligent::RESOURCE_STATE. + /// \param [out] ppTLAS - Address of the memory location where the pointer to the + /// top-level AS interface will be stored. + /// The function calls AddRef(), so that the new object will contain + /// one reference. + VIRTUAL void METHOD(CreateTLASFromD3DResource)(THIS_ + ID3D12Resource* pd3d12TLAS, + const TopLevelASDesc REF Desc, + RESOURCE_STATE InitialState, + ITopLevelAS** ppTLAS) PURE; }; DILIGENT_END_INTERFACE @@ -114,6 +146,8 @@ DILIGENT_END_INTERFACE # define IRenderDeviceD3D12_IsFenceSignaled(This, ...) CALL_IFACE_METHOD(RenderDeviceD3D12, IsFenceSignaled, This, __VA_ARGS__) # define IRenderDeviceD3D12_CreateTextureFromD3DResource(This, ...) CALL_IFACE_METHOD(RenderDeviceD3D12, CreateTextureFromD3DResource, This, __VA_ARGS__) # define IRenderDeviceD3D12_CreateBufferFromD3DResource(This, ...) CALL_IFACE_METHOD(RenderDeviceD3D12, CreateBufferFromD3DResource, This, __VA_ARGS__) +# define IRenderDeviceD3D12_CreateBLASFromD3DResource(This, ...) CALL_IFACE_METHOD(RenderDeviceD3D12, CreateBLASFromD3DResource, This, __VA_ARGS__) +# define IRenderDeviceD3D12_CreateTLASFromD3DResource(This, ...) CALL_IFACE_METHOD(RenderDeviceD3D12, CreateTLASFromD3DResource, This, __VA_ARGS__) // clang-format on diff --git a/Graphics/GraphicsEngineD3D12/interface/ShaderBindingTableD3D12.h b/Graphics/GraphicsEngineD3D12/interface/ShaderBindingTableD3D12.h new file mode 100644 index 00000000..827df3b7 --- /dev/null +++ b/Graphics/GraphicsEngineD3D12/interface/ShaderBindingTableD3D12.h @@ -0,0 +1,66 @@ +/* + * Copyright 2019-2020 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#pragma once + +/// \file +/// Definition of the Diligent::IShaderBindingTableD3D12 interface + +#include "../../GraphicsEngine/interface/ShaderBindingTable.h" +#include "DeviceContextD3D12.h" + +DILIGENT_BEGIN_NAMESPACE(Diligent) + +// {DCA2FAD9-2C41-4419-9D16-79731C0ED9D8} +static const INTERFACE_ID IID_ShaderBindingTableD3D12 = + {0xdca2fad9, 0x2c41, 0x4419, {0x9d, 0x16, 0x79, 0x73, 0x1c, 0xe, 0xd9, 0xd8}}; + +#define DILIGENT_INTERFACE_NAME IShaderBindingTableD3D12 +#include "../../../Primitives/interface/DefineInterfaceHelperMacros.h" + +#define IShaderBindingTableD3D12InclusiveMethods \ + IShaderBindingTableInclusiveMethods; \ + IShaderBindingTableD3D12Methods ShaderBindingTableD3D12 +// clang-format off + +#if DILIGENT_CPP_INTERFACE // Empty structs are not allwed in C + +/// Exposes Direct3D12-specific functionality of a shader binding table object. +DILIGENT_BEGIN_INTERFACE(IShaderBindingTableD3D12, IShaderBindingTable) +{ +}; +DILIGENT_END_INTERFACE + +#endif + +#include "../../../Primitives/interface/UndefInterfaceHelperMacros.h" + +#if DILIGENT_C_INTERFACE + +#endif + +DILIGENT_END_NAMESPACE // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/interface/TopLevelASD3D12.h b/Graphics/GraphicsEngineD3D12/interface/TopLevelASD3D12.h new file mode 100644 index 00000000..6434eaba --- /dev/null +++ b/Graphics/GraphicsEngineD3D12/interface/TopLevelASD3D12.h @@ -0,0 +1,77 @@ +/* + * Copyright 2019-2020 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#pragma once + +/// \file +/// Definition of the Diligent::ITopLevelASD3D12 interface + +#include "../../GraphicsEngine/interface/TopLevelAS.h" +#include "../../GraphicsEngine/interface/DeviceContext.h" + +DILIGENT_BEGIN_NAMESPACE(Diligent) + +// {46334F12-64CB-4F7C-BB71-31515B6F386D} +static const INTERFACE_ID IID_TopLevelASD3D12 = + {0x46334f12, 0x64cb, 0x4f7c, {0xbb, 0x71, 0x31, 0x51, 0x5b, 0x6f, 0x38, 0x6d}}; + +#define DILIGENT_INTERFACE_NAME ITopLevelASD3D12 +#include "../../../Primitives/interface/DefineInterfaceHelperMacros.h" + +#define ITopLevelASD3D12InclusiveMethods \ + ITopLevelASInclusiveMethods; \ + ITopLevelASD3D12Methods TopLevelASD3D12 + +// clang-format off + +/// Exposes Direct3D12-specific functionality of a top-level acceleration structure object. +DILIGENT_BEGIN_INTERFACE(ITopLevelASD3D12, ITopLevelAS) +{ + /// Returns ID3D12Resource interface of the internal D3D12 acceleration structure object. + + /// The method does *NOT* call AddRef() on the returned interface, + /// so Release() must not be called. + VIRTUAL ID3D12Resource* METHOD(GetD3D12TLAS)(THIS) PURE; + + /// Returns a CPU descriptor handle of the D3D12 acceleration structure + + /// The method does *NOT* call AddRef() on the returned interface, + /// so Release() must not be called. + VIRTUAL D3D12_CPU_DESCRIPTOR_HANDLE METHOD(GetCPUDescriptorHandle)(THIS) PURE; +}; +DILIGENT_END_INTERFACE + +#include "../../../Primitives/interface/UndefInterfaceHelperMacros.h" + +#if DILIGENT_C_INTERFACE + +# define ITopLevelASD3D12_GetD3D12TLAS(This) CALL_IFACE_METHOD(TopLevelASD3D12, GetD3D12TLAS, This) +# define ITopLevelASD3D12_GetCPUDescriptorHandle(This) CALL_IFACE_METHOD(TopLevelASD3D12, GetCPUDescriptorHandle, This) + +#endif + +DILIGENT_END_NAMESPACE // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/src/BottomLevelASD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/BottomLevelASD3D12Impl.cpp new file mode 100644 index 00000000..d2e119b3 --- /dev/null +++ b/Graphics/GraphicsEngineD3D12/src/BottomLevelASD3D12Impl.cpp @@ -0,0 +1,177 @@ +/* + * Copyright 2019-2020 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include "pch.h" +#include "BottomLevelASD3D12Impl.hpp" +#include "RenderDeviceD3D12Impl.hpp" +#include "D3D12TypeConversions.hpp" +#include "GraphicsAccessories.hpp" +#include "DXGITypeConversions.hpp" +#include "StringTools.hpp" + +namespace Diligent +{ + +BottomLevelASD3D12Impl::BottomLevelASD3D12Impl(IReferenceCounters* pRefCounters, + class RenderDeviceD3D12Impl* pDeviceD3D12, + const BottomLevelASDesc& Desc) : + TBottomLevelASBase{pRefCounters, pDeviceD3D12, Desc} +{ + auto* pd3d12Device = pDeviceD3D12->GetD3D12Device5(); + UINT64 ResultDataMaxSizeInBytes = 0; + + if (m_Desc.CompactedSize) + { + ResultDataMaxSizeInBytes = m_Desc.CompactedSize; + } + else + { + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO d3d12BottomLevelPrebuildInfo = {}; + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS d3d12BottomLevelInputs = {}; + std::vector<D3D12_RAYTRACING_GEOMETRY_DESC> d3d12Geometries; + + if (m_Desc.pTriangles != nullptr) + { + d3d12Geometries.resize(m_Desc.TriangleCount); + Uint32 MaxPrimitiveCount = 0; + for (uint32_t i = 0; i < m_Desc.TriangleCount; ++i) + { + auto& src = m_Desc.pTriangles[i]; + auto& dst = d3d12Geometries[i]; + + dst.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES; + dst.Flags = D3D12_RAYTRACING_GEOMETRY_FLAG_NONE; + dst.Triangles.IndexCount = src.IndexType == VT_UNDEFINED ? 0 : src.MaxPrimitiveCount * 3; + dst.Triangles.IndexFormat = ValueTypeToIndexType(src.IndexType); + dst.Triangles.IndexBuffer = 0; + dst.Triangles.Transform3x4 = 0; + dst.Triangles.VertexBuffer.StartAddress = 0; + dst.Triangles.VertexBuffer.StrideInBytes = 0; + dst.Triangles.VertexCount = src.MaxVertexCount; + dst.Triangles.VertexFormat = TypeToRayTracingVertexFormat(src.VertexValueType, src.VertexComponentCount); + VERIFY(dst.Triangles.VertexFormat != DXGI_FORMAT_UNKNOWN, "Unsupported combination of vertex value type and component count"); + + MaxPrimitiveCount += src.MaxPrimitiveCount; + } + VERIFY_EXPR(MaxPrimitiveCount <= D3D12_RAYTRACING_MAX_PRIMITIVES_PER_BOTTOM_LEVEL_ACCELERATION_STRUCTURE); + } + else if (m_Desc.pBoxes != nullptr) + { + d3d12Geometries.resize(m_Desc.BoxCount); + Uint32 MaxBoxCount = 0; + for (uint32_t i = 0; i < m_Desc.BoxCount; ++i) + { + auto& src = m_Desc.pBoxes[i]; + auto& dst = d3d12Geometries[i]; + + dst.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_PROCEDURAL_PRIMITIVE_AABBS; + dst.Flags = D3D12_RAYTRACING_GEOMETRY_FLAG_NONE; + dst.AABBs.AABBCount = src.MaxBoxCount; + dst.AABBs.AABBs.StartAddress = 0; + dst.AABBs.AABBs.StrideInBytes = 0; + + MaxBoxCount += src.MaxBoxCount; + } + VERIFY_EXPR(MaxBoxCount <= D3D12_RAYTRACING_MAX_PRIMITIVES_PER_BOTTOM_LEVEL_ACCELERATION_STRUCTURE); + } + else + { + UNEXPECTED("Either pTriangles or pBoxes must not be null"); + } + + VERIFY_EXPR(d3d12Geometries.size() <= D3D12_RAYTRACING_MAX_GEOMETRIES_PER_BOTTOM_LEVEL_ACCELERATION_STRUCTURE); + + d3d12BottomLevelInputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL; + d3d12BottomLevelInputs.Flags = BuildASFlagsToD3D12ASBuildFlags(m_Desc.Flags); + d3d12BottomLevelInputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY; + d3d12BottomLevelInputs.pGeometryDescs = d3d12Geometries.data(); + d3d12BottomLevelInputs.NumDescs = static_cast<UINT>(d3d12Geometries.size()); + + pd3d12Device->GetRaytracingAccelerationStructurePrebuildInfo(&d3d12BottomLevelInputs, &d3d12BottomLevelPrebuildInfo); + if (d3d12BottomLevelPrebuildInfo.ResultDataMaxSizeInBytes == 0) + LOG_ERROR_AND_THROW("Failed to get ray tracing acceleration structure prebuild info"); + + ResultDataMaxSizeInBytes = d3d12BottomLevelPrebuildInfo.ResultDataMaxSizeInBytes; + + m_ScratchSize.Build = static_cast<Uint32>(d3d12BottomLevelPrebuildInfo.ScratchDataSizeInBytes); + m_ScratchSize.Update = static_cast<Uint32>(d3d12BottomLevelPrebuildInfo.UpdateScratchDataSizeInBytes); + } + + D3D12_HEAP_PROPERTIES HeapProps; + HeapProps.Type = D3D12_HEAP_TYPE_DEFAULT; + HeapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; + HeapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; + HeapProps.CreationNodeMask = 1; + HeapProps.VisibleNodeMask = 1; + + D3D12_RESOURCE_DESC ASDesc = {}; + ASDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + ASDesc.Alignment = 0; + ASDesc.Width = ResultDataMaxSizeInBytes; + ASDesc.Height = 1; + ASDesc.DepthOrArraySize = 1; + ASDesc.MipLevels = 1; + ASDesc.Format = DXGI_FORMAT_UNKNOWN; + ASDesc.SampleDesc.Count = 1; + ASDesc.SampleDesc.Quality = 0; + ASDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + ASDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; + + auto hr = pd3d12Device->CreateCommittedResource(&HeapProps, D3D12_HEAP_FLAG_NONE, + &ASDesc, D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE, nullptr, + __uuidof(m_pd3d12Resource), + reinterpret_cast<void**>(static_cast<ID3D12Resource**>(&m_pd3d12Resource))); + if (FAILED(hr)) + LOG_ERROR_AND_THROW("Failed to create D3D12 Bottom-level acceleration structure"); + + if (*m_Desc.Name != 0) + m_pd3d12Resource->SetName(WidenString(m_Desc.Name).c_str()); + + VERIFY_EXPR(GetGPUAddress() % D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BYTE_ALIGNMENT == 0); + + SetState(RESOURCE_STATE_BUILD_AS_READ); +} + +BottomLevelASD3D12Impl::BottomLevelASD3D12Impl(IReferenceCounters* pRefCounters, + class RenderDeviceD3D12Impl* pDeviceD3D12, + const BottomLevelASDesc& Desc, + RESOURCE_STATE InitialState, + ID3D12Resource* pd3d12BLAS) : + TBottomLevelASBase{pRefCounters, pDeviceD3D12, Desc} +{ + m_pd3d12Resource = pd3d12BLAS; + SetState(InitialState); +} + +BottomLevelASD3D12Impl::~BottomLevelASD3D12Impl() +{ + // D3D12 object can only be destroyed when it is no longer used by the GPU + auto* pDeviceD3D12Impl = ValidatedCast<RenderDeviceD3D12Impl>(GetDevice()); + pDeviceD3D12Impl->SafeReleaseDeviceObject(std::move(m_pd3d12Resource), m_Desc.CommandQueueMask); +} + +} // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/src/BufferD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/BufferD3D12Impl.cpp index 0d0ac327..e17b645b 100644 --- a/Graphics/GraphicsEngineD3D12/src/BufferD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/BufferD3D12Impl.cpp @@ -118,9 +118,9 @@ BufferD3D12Impl::BufferD3D12Impl(IReferenceCounters* pRefCounters, // understood by applications and row-major texture data is commonly marshaled through buffers. D3D12BuffDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; D3D12BuffDesc.Flags = D3D12_RESOURCE_FLAG_NONE; - if (m_Desc.BindFlags & BIND_UNORDERED_ACCESS) + if ((m_Desc.BindFlags & BIND_UNORDERED_ACCESS) || (m_Desc.BindFlags & BIND_RAY_TRACING)) D3D12BuffDesc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; - if (!(m_Desc.BindFlags & BIND_SHADER_RESOURCE)) + if (!(m_Desc.BindFlags & BIND_SHADER_RESOURCE) && !(m_Desc.BindFlags & BIND_RAY_TRACING)) D3D12BuffDesc.Flags |= D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE; auto* pd3d12Device = pRenderDeviceD3D12->GetD3D12Device(); @@ -348,7 +348,7 @@ void BufferD3D12Impl::CreateViewInternal(const BufferViewDesc& OrigViewDesc, IBu void BufferD3D12Impl::CreateUAV(BufferViewDesc& UAVDesc, D3D12_CPU_DESCRIPTOR_HANDLE UAVDescriptor) { - CorrectBufferViewDesc(UAVDesc); + ValidateAndCorrectBufferViewDesc(m_Desc, UAVDesc); D3D12_UNORDERED_ACCESS_VIEW_DESC D3D12_UAVDesc; BufferViewDesc_to_D3D12_UAV_DESC(m_Desc, UAVDesc, D3D12_UAVDesc); @@ -359,7 +359,7 @@ void BufferD3D12Impl::CreateUAV(BufferViewDesc& UAVDesc, D3D12_CPU_DESCRIPTOR_HA void BufferD3D12Impl::CreateSRV(struct BufferViewDesc& SRVDesc, D3D12_CPU_DESCRIPTOR_HANDLE SRVDescriptor) { - CorrectBufferViewDesc(SRVDesc); + ValidateAndCorrectBufferViewDesc(m_Desc, SRVDesc); D3D12_SHADER_RESOURCE_VIEW_DESC D3D12_SRVDesc; BufferViewDesc_to_D3D12_SRV_DESC(m_Desc, SRVDesc, D3D12_SRVDesc); diff --git a/Graphics/GraphicsEngineD3D12/src/CommandContext.cpp b/Graphics/GraphicsEngineD3D12/src/CommandContext.cpp index 389bf3eb..fdb93efb 100644 --- a/Graphics/GraphicsEngineD3D12/src/CommandContext.cpp +++ b/Graphics/GraphicsEngineD3D12/src/CommandContext.cpp @@ -30,6 +30,8 @@ #include "CommandContext.hpp" #include "TextureD3D12Impl.hpp" #include "BufferD3D12Impl.hpp" +#include "BottomLevelASD3D12Impl.hpp" +#include "TopLevelASD3D12Impl.hpp" #include "CommandListManager.hpp" #include "D3D12TypeConversions.hpp" @@ -39,9 +41,9 @@ namespace Diligent CommandContext::CommandContext(CommandListManager& CmdListManager) : // clang-format off - m_pCurGraphicsRootSignature {nullptr}, - m_pCurPipelineState {nullptr}, - m_pCurComputeRootSignature {nullptr}, + m_pCurGraphicsRootSignature {nullptr}, + m_pCurPipelineState {nullptr}, + m_pCurComputeRootSignature {nullptr}, m_PendingResourceBarriers (STD_ALLOCATOR_RAW_MEM(D3D12_RESOURCE_BARRIER, GetRawAllocator(), "Allocator for vector<D3D12_RESOURCE_BARRIER>")) // clang-format on { @@ -78,7 +80,7 @@ void CommandContext::Reset(CommandListManager& CmdListManager) m_PrimitiveTopology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; #if 0 - BindDescriptorHeaps(); + BindDescriptorHeaps(); #endif } @@ -115,6 +117,24 @@ void CommandContext::TransitionResource(IBufferD3D12* pBuffer, RESOURCE_STATE Ne TransitionResource(BufferBarrier); } +void CommandContext::TransitionResource(IBottomLevelASD3D12* pBLAS, RESOURCE_STATE NewState) +{ + VERIFY_EXPR(pBLAS != nullptr); + auto* pBLASfD3D12 = ValidatedCast<BottomLevelASD3D12Impl>(pBLAS); + VERIFY(pBLASfD3D12->IsInKnownState(), "BLAS state can't be unknown"); + StateTransitionDesc ASBarrier(pBLAS, RESOURCE_STATE_UNKNOWN, NewState, true); + TransitionResource(ASBarrier); +} + +void CommandContext::TransitionResource(ITopLevelASD3D12* pTLAS, RESOURCE_STATE NewState) +{ + VERIFY_EXPR(pTLAS != nullptr); + auto* pTLASfD3D12 = ValidatedCast<TopLevelASD3D12Impl>(pTLAS); + VERIFY(pTLASfD3D12->IsInKnownState(), "TLAS state can't be unknown"); + StateTransitionDesc ASBarrier(pTLAS, RESOURCE_STATE_UNKNOWN, NewState, true); + TransitionResource(ASBarrier); +} + void CommandContext::InsertUAVBarrier(ID3D12Resource* pd3d12Resource) { m_PendingResourceBarriers.emplace_back(); @@ -147,25 +167,23 @@ static D3D12_RESOURCE_BARRIER_FLAGS TransitionTypeToD3D12ResourceBarrierFlag(STA void CommandContext::TransitionResource(const StateTransitionDesc& Barrier) { - DEV_CHECK_ERR((Barrier.pTexture != nullptr) ^ (Barrier.pBuffer != nullptr), "Exactly one of pTexture or pBuffer must not be null"); - DEV_CHECK_ERR(Barrier.NewState != RESOURCE_STATE_UNKNOWN, "New resource state can't be unknown"); - RESOURCE_STATE OldState = RESOURCE_STATE_UNKNOWN; - ID3D12Resource* pd3d12Resource = nullptr; - TextureD3D12Impl* pTextureD3D12Impl = nullptr; - BufferD3D12Impl* pBufferD3D12Impl = nullptr; - if (Barrier.pTexture) + RESOURCE_STATE OldState = RESOURCE_STATE_UNKNOWN; + ID3D12Resource* pd3d12Resource = nullptr; + RefCntAutoPtr<TextureD3D12Impl> pTextureD3D12Impl{Barrier.pResource, IID_TextureD3D12}; + RefCntAutoPtr<BufferD3D12Impl> pBufferD3D12Impl{pTextureD3D12Impl ? nullptr : Barrier.pResource, IID_BufferD3D12}; + RefCntAutoPtr<BottomLevelASD3D12Impl> pBLASD3D12Impl{pBufferD3D12Impl ? nullptr : Barrier.pResource, IID_BottomLevelASD3D12}; + RefCntAutoPtr<TopLevelASD3D12Impl> pTLASD3D12Impl{pBLASD3D12Impl ? nullptr : Barrier.pResource, IID_TopLevelASD3D12}; + + if (pTextureD3D12Impl) { - pTextureD3D12Impl = ValidatedCast<TextureD3D12Impl>(Barrier.pTexture); - pd3d12Resource = pTextureD3D12Impl->GetD3D12Resource(); - OldState = pTextureD3D12Impl->GetState(); + pd3d12Resource = pTextureD3D12Impl->GetD3D12Resource(); + OldState = pTextureD3D12Impl->GetState(); } - else + else if (pBufferD3D12Impl) { - VERIFY_EXPR(Barrier.pBuffer != nullptr); - pBufferD3D12Impl = ValidatedCast<BufferD3D12Impl>(Barrier.pBuffer); - pd3d12Resource = pBufferD3D12Impl->GetD3D12Resource(); - OldState = pBufferD3D12Impl->GetState(); + pd3d12Resource = pBufferD3D12Impl->GetD3D12Resource(); + OldState = pBufferD3D12Impl->GetState(); #ifdef DILIGENT_DEVELOPMENT // Dynamic buffers wtih no SRV/UAV bind flags are suballocated in @@ -178,6 +196,20 @@ void CommandContext::TransitionResource(const StateTransitionDesc& Barrier) } #endif } + else if (pBLASD3D12Impl) + { + pd3d12Resource = pBLASD3D12Impl->GetD3D12Resource(); + OldState = pBLASD3D12Impl->GetState(); + } + else if (pTLASD3D12Impl) + { + pd3d12Resource = pTLASD3D12Impl->GetD3D12Resource(); + OldState = pTLASD3D12Impl->GetState(); + } + else + { + UNEXPECTED("unsupported resource type"); + } if (OldState == RESOURCE_STATE_UNKNOWN) { @@ -192,6 +224,12 @@ void CommandContext::TransitionResource(const StateTransitionDesc& Barrier) "RESOURCE_STATE_UNKNOWN to make the engine use current resource state"); } + // RESOURCE_STATE_UNORDERED_ACCESS and RESOURCE_STATE_BUILD_AS_WRITE are converted to D3D12_RESOURCE_STATE_UNORDERED_ACCESS. + // UAV barrier must be inserted between D3D12_RESOURCE_STATE_UNORDERED_ACCESS resource usages. + bool RequireUAVBarrier = + (OldState == RESOURCE_STATE_UNORDERED_ACCESS || OldState == RESOURCE_STATE_BUILD_AS_WRITE) && + (Barrier.NewState == RESOURCE_STATE_UNORDERED_ACCESS || Barrier.NewState == RESOURCE_STATE_BUILD_AS_WRITE); + // Check if required state is already set if ((OldState & Barrier.NewState) != Barrier.NewState) { @@ -243,9 +281,8 @@ void CommandContext::TransitionResource(const StateTransitionDesc& Barrier) } } } - else + else if (pBufferD3D12Impl) { - VERIFY_EXPR(pBufferD3D12Impl); m_PendingResourceBarriers.emplace_back(BarrierDesc); } } @@ -259,10 +296,8 @@ void CommandContext::TransitionResource(const StateTransitionDesc& Barrier) pTextureD3D12Impl->SetState(NewState); } } - else + else if (pBufferD3D12Impl) { - VERIFY_EXPR(pBufferD3D12Impl); - VERIFY(!Barrier.UpdateResourceState || (Barrier.TransitionType == STATE_TRANSITION_TYPE_IMMEDIATE || Barrier.TransitionType == STATE_TRANSITION_TYPE_END), "Buffer state can't be updated in begin-split barrier"); if (Barrier.UpdateResourceState) @@ -275,9 +310,36 @@ void CommandContext::TransitionResource(const StateTransitionDesc& Barrier) "Dynamic buffers without SRV/UAV bind flag are expected to never " "transition from RESOURCE_STATE_GENERIC_READ state"); } + else if (pBLASD3D12Impl) + { + if (Barrier.UpdateResourceState) + { + pBLASD3D12Impl->SetState(NewState); + } + + // acceleration structure is always in D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE but requires UAV barrier instead of state transition. + RequireUAVBarrier |= (OldState == RESOURCE_STATE_BUILD_AS_WRITE); + } + else if (pTLASD3D12Impl) + { + if (Barrier.UpdateResourceState) + { + pTLASD3D12Impl->SetState(NewState); + } + + // acceleration structure is always in D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE but requires UAV barrier instead of state transition. + RequireUAVBarrier |= (OldState == RESOURCE_STATE_BUILD_AS_WRITE); + +#ifdef DILIGENT_DEVELOPMENT + if (Barrier.NewState & RESOURCE_STATE_RAY_TRACING) + { + pTLASD3D12Impl->ValidateContent(); + } +#endif + } } - if (OldState == RESOURCE_STATE_UNORDERED_ACCESS && Barrier.NewState == RESOURCE_STATE_UNORDERED_ACCESS) + if (RequireUAVBarrier) { DEV_CHECK_ERR(Barrier.TransitionType == STATE_TRANSITION_TYPE_IMMEDIATE, "UAV barriers must not be split"); InsertUAVBarrier(pd3d12Resource); diff --git a/Graphics/GraphicsEngineD3D12/src/CommandQueueD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/CommandQueueD3D12Impl.cpp index 74e65559..63d19ce4 100644 --- a/Graphics/GraphicsEngineD3D12/src/CommandQueueD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/CommandQueueD3D12Impl.cpp @@ -94,6 +94,8 @@ Uint64 CommandQueueD3D12Impl::WaitForIdle() Uint64 CommandQueueD3D12Impl::GetCompletedFenceValue() { auto CompletedFenceValue = m_d3d12Fence->GetCompletedValue(); + VERIFY(CompletedFenceValue != UINT64_MAX, "If the device has been removed, the return value will be UINT64_MAX"); + if (CompletedFenceValue > m_LastCompletedFenceValue) m_LastCompletedFenceValue = CompletedFenceValue; return m_LastCompletedFenceValue; diff --git a/Graphics/GraphicsEngineD3D12/src/D3D12TypeConversions.cpp b/Graphics/GraphicsEngineD3D12/src/D3D12TypeConversions.cpp index 34a98a45..e9ae5af6 100644 --- a/Graphics/GraphicsEngineD3D12/src/D3D12TypeConversions.cpp +++ b/Graphics/GraphicsEngineD3D12/src/D3D12TypeConversions.cpp @@ -329,7 +329,7 @@ D3D12_STATIC_BORDER_COLOR BorderColorToD3D12StaticBorderColor(const Float32 Bord static D3D12_RESOURCE_STATES ResourceStateFlagToD3D12ResourceState(RESOURCE_STATE StateFlag) { - static_assert(RESOURCE_STATE_MAX_BIT == 0x10000, "This function must be updated to handle new resource state flag"); + static_assert(RESOURCE_STATE_MAX_BIT == RESOURCE_STATE_RAY_TRACING, "This function must be updated to handle new resource state flag"); VERIFY((StateFlag & (StateFlag - 1)) == 0, "Only single bit must be set"); switch (StateFlag) { @@ -351,6 +351,9 @@ static D3D12_RESOURCE_STATES ResourceStateFlagToD3D12ResourceState(RESOURCE_STAT case RESOURCE_STATE_RESOLVE_SOURCE: return D3D12_RESOURCE_STATE_RESOLVE_SOURCE; case RESOURCE_STATE_INPUT_ATTACHMENT: return D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; case RESOURCE_STATE_PRESENT: return D3D12_RESOURCE_STATE_PRESENT; + case RESOURCE_STATE_BUILD_AS_READ: return D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; + case RESOURCE_STATE_BUILD_AS_WRITE: return D3D12_RESOURCE_STATE_UNORDERED_ACCESS; + case RESOURCE_STATE_RAY_TRACING: return D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; // clang-format on default: UNEXPECTED("Unexpected resource state flag"); @@ -364,7 +367,7 @@ public: StateFlagBitPosToD3D12ResourceState() { static_assert((1 << MaxFlagBitPos) == RESOURCE_STATE_MAX_BIT, "This function must be updated to handle new resource state flag"); - for (Uint32 bit = 0; bit <= MaxFlagBitPos; ++bit) + for (Uint32 bit = 0; bit < FlagBitPosToResStateMap.size(); ++bit) { FlagBitPosToResStateMap[bit] = ResourceStateFlagToD3D12ResourceState(static_cast<RESOURCE_STATE>(1 << bit)); } @@ -377,7 +380,7 @@ public: } private: - static constexpr Uint32 MaxFlagBitPos = 16; + static constexpr Uint32 MaxFlagBitPos = 19; std::array<D3D12_RESOURCE_STATES, MaxFlagBitPos + 1> FlagBitPosToResStateMap; }; @@ -399,7 +402,7 @@ D3D12_RESOURCE_STATES ResourceStateFlagsToD3D12ResourceStates(RESOURCE_STATE Sta static RESOURCE_STATE D3D12ResourceStateToResourceStateFlags(D3D12_RESOURCE_STATES state) { - static_assert(RESOURCE_STATE_MAX_BIT == 0x10000, "This function must be updated to handle new resource state flag"); + static_assert(RESOURCE_STATE_MAX_BIT == RESOURCE_STATE_RAY_TRACING, "This function must be updated to handle new resource state flag"); VERIFY((state & (state - 1)) == 0, "Only single state must be set"); switch (state) { @@ -433,7 +436,7 @@ class D3D12StateFlagBitPosToResourceState public: D3D12StateFlagBitPosToResourceState() { - for (Uint32 bit = 0; bit <= MaxFlagBitPos; ++bit) + for (Uint32 bit = 0; bit < FlagBitPosToResStateMap.size(); ++bit) { FlagBitPosToResStateMap[bit] = D3D12ResourceStateToResourceStateFlags(static_cast<D3D12_RESOURCE_STATES>(1 << bit)); } @@ -537,4 +540,213 @@ D3D12_RENDER_PASS_ENDING_ACCESS_TYPE AttachmentStoreOpToD3D12EndingAccessType(AT // clang-format on } +D3D12_SHADER_VISIBILITY ShaderTypeToD3D12ShaderVisibility(SHADER_TYPE ShaderType) +{ + static_assert(SHADER_TYPE_LAST == SHADER_TYPE_CALLABLE, "Please update the switch below to handle the new shader type"); + switch (ShaderType) + { + // clang-format off + case SHADER_TYPE_VERTEX: return D3D12_SHADER_VISIBILITY_VERTEX; + case SHADER_TYPE_PIXEL: return D3D12_SHADER_VISIBILITY_PIXEL; + case SHADER_TYPE_GEOMETRY: return D3D12_SHADER_VISIBILITY_GEOMETRY; + case SHADER_TYPE_HULL: return D3D12_SHADER_VISIBILITY_HULL; + case SHADER_TYPE_DOMAIN: return D3D12_SHADER_VISIBILITY_DOMAIN; + case SHADER_TYPE_COMPUTE: return D3D12_SHADER_VISIBILITY_ALL; +# ifdef D3D12_H_HAS_MESH_SHADER + case SHADER_TYPE_AMPLIFICATION: return D3D12_SHADER_VISIBILITY_AMPLIFICATION; + case SHADER_TYPE_MESH: return D3D12_SHADER_VISIBILITY_MESH; +# endif + case SHADER_TYPE_RAY_GEN: + case SHADER_TYPE_RAY_MISS: + case SHADER_TYPE_RAY_CLOSEST_HIT: + case SHADER_TYPE_RAY_ANY_HIT: + case SHADER_TYPE_RAY_INTERSECTION: + case SHADER_TYPE_CALLABLE: return D3D12_SHADER_VISIBILITY_ALL; + // clang-format on + default: + LOG_ERROR("Unknown shader type (", ShaderType, ")"); + return D3D12_SHADER_VISIBILITY_ALL; + } +} + +SHADER_TYPE D3D12ShaderVisibilityToShaderType(D3D12_SHADER_VISIBILITY ShaderVisibility) +{ + static_assert(SHADER_TYPE_LAST == SHADER_TYPE_CALLABLE, "Please update the switch below to handle the new shader type"); + switch (ShaderVisibility) + { + // clang-format off + case D3D12_SHADER_VISIBILITY_ALL: return SHADER_TYPE_UNKNOWN; + case D3D12_SHADER_VISIBILITY_VERTEX: return SHADER_TYPE_VERTEX; + case D3D12_SHADER_VISIBILITY_PIXEL: return SHADER_TYPE_PIXEL; + case D3D12_SHADER_VISIBILITY_GEOMETRY: return SHADER_TYPE_GEOMETRY; + case D3D12_SHADER_VISIBILITY_HULL: return SHADER_TYPE_HULL; + case D3D12_SHADER_VISIBILITY_DOMAIN: return SHADER_TYPE_DOMAIN; +# ifdef D3D12_H_HAS_MESH_SHADER + case D3D12_SHADER_VISIBILITY_AMPLIFICATION: return SHADER_TYPE_AMPLIFICATION; + case D3D12_SHADER_VISIBILITY_MESH: return SHADER_TYPE_MESH; +# endif + // clang-format on + default: + LOG_ERROR("Unknown shader visibility (", ShaderVisibility, ")"); + return SHADER_TYPE_UNKNOWN; + } +} + +DXGI_FORMAT ValueTypeToIndexType(VALUE_TYPE IndexType) +{ + switch (IndexType) + { + // clang-format off + case VT_UNDEFINED: return DXGI_FORMAT_UNKNOWN; // only for ray tracing + case VT_UINT16: return DXGI_FORMAT_R16_UINT; + case VT_UINT32: return DXGI_FORMAT_R32_UINT; + // clang-format on + default: + UNEXPECTED("Unexpected index type"); + return DXGI_FORMAT_R32_UINT; + } +} + +D3D12_RAYTRACING_GEOMETRY_FLAGS GeometryFlagsToD3D12RTGeometryFlags(RAYTRACING_GEOMETRY_FLAGS Flags) +{ + static_assert(RAYTRACING_GEOMETRY_FLAGS_LAST == RAYTRACING_GEOMETRY_FLAG_NO_DUPLICATE_ANY_HIT_INVOCATION, + "Please update the switch below to handle the new ray tracing geometry flag"); + + D3D12_RAYTRACING_GEOMETRY_FLAGS Result = D3D12_RAYTRACING_GEOMETRY_FLAG_NONE; + while (Flags != RAYTRACING_GEOMETRY_FLAG_NONE) + { + auto FlagBit = static_cast<RAYTRACING_GEOMETRY_FLAGS>(1 << PlatformMisc::GetLSB(Uint32{Flags})); + switch (FlagBit) + { + // clang-format off + case RAYTRACING_GEOMETRY_FLAG_OPAQUE: Result |= D3D12_RAYTRACING_GEOMETRY_FLAG_OPAQUE; break; + case RAYTRACING_GEOMETRY_FLAG_NO_DUPLICATE_ANY_HIT_INVOCATION: Result |= D3D12_RAYTRACING_GEOMETRY_FLAG_NO_DUPLICATE_ANYHIT_INVOCATION; break; + // clang-format on + default: UNEXPECTED("unknown geometry flag"); + } + Flags &= ~FlagBit; + } + return Result; +} + +D3D12_RAYTRACING_INSTANCE_FLAGS InstanceFlagsToD3D12RTInstanceFlags(RAYTRACING_INSTANCE_FLAGS Flags) +{ + static_assert(RAYTRACING_INSTANCE_FLAGS_LAST == RAYTRACING_INSTANCE_FORCE_NO_OPAQUE, + "Please update the switch below to handle the new ray tracing instance flag"); + + D3D12_RAYTRACING_INSTANCE_FLAGS Result = D3D12_RAYTRACING_INSTANCE_FLAG_NONE; + while (Flags != RAYTRACING_INSTANCE_NONE) + { + auto FlagBit = static_cast<RAYTRACING_INSTANCE_FLAGS>(1 << PlatformMisc::GetLSB(Uint32{Flags})); + switch (FlagBit) + { + // clang-format off + case RAYTRACING_INSTANCE_TRIANGLE_FACING_CULL_DISABLE: Result |= D3D12_RAYTRACING_INSTANCE_FLAG_TRIANGLE_CULL_DISABLE; break; + case RAYTRACING_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE: Result |= D3D12_RAYTRACING_INSTANCE_FLAG_TRIANGLE_FRONT_COUNTERCLOCKWISE; break; + case RAYTRACING_INSTANCE_FORCE_OPAQUE: Result |= D3D12_RAYTRACING_INSTANCE_FLAG_FORCE_OPAQUE; break; + case RAYTRACING_INSTANCE_FORCE_NO_OPAQUE: Result |= D3D12_RAYTRACING_INSTANCE_FLAG_FORCE_NON_OPAQUE; break; + // clang-format on + default: UNEXPECTED("unknown instance flag"); + } + Flags &= ~FlagBit; + } + return Result; +} + +D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS BuildASFlagsToD3D12ASBuildFlags(RAYTRACING_BUILD_AS_FLAGS Flags) +{ + static_assert(RAYTRACING_BUILD_AS_FLAGS_LAST == RAYTRACING_BUILD_AS_LOW_MEMORY, + "Please update the switch below to handle the new acceleration structure build flag"); + + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS Result = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_NONE; + while (Flags != RAYTRACING_BUILD_AS_NONE) + { + auto FlagBit = static_cast<RAYTRACING_BUILD_AS_FLAGS>(1 << PlatformMisc::GetLSB(Uint32{Flags})); + switch (FlagBit) + { + // clang-format off + case RAYTRACING_BUILD_AS_ALLOW_UPDATE: Result |= D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_ALLOW_UPDATE; break; + case RAYTRACING_BUILD_AS_ALLOW_COMPACTION: Result |= D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_ALLOW_COMPACTION; break; + case RAYTRACING_BUILD_AS_PREFER_FAST_TRACE: Result |= D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_TRACE; break; + case RAYTRACING_BUILD_AS_PREFER_FAST_BUILD: Result |= D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_BUILD; break; + case RAYTRACING_BUILD_AS_LOW_MEMORY: Result |= D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_MINIMIZE_MEMORY; break; + // clang-format on + default: UNEXPECTED("unknown build AS flag"); + } + Flags &= ~FlagBit; + } + return Result; +} + +D3D12_RAYTRACING_ACCELERATION_STRUCTURE_COPY_MODE CopyASModeToD3D12ASCopyMode(COPY_AS_MODE Mode) +{ + static_assert(COPY_AS_MODE_LAST == COPY_AS_MODE_COMPACT, + "Please update the switch below to handle the new copy AS mode"); + + switch (Mode) + { + // clang-format off + case COPY_AS_MODE_CLONE: return D3D12_RAYTRACING_ACCELERATION_STRUCTURE_COPY_MODE_CLONE; + case COPY_AS_MODE_COMPACT: return D3D12_RAYTRACING_ACCELERATION_STRUCTURE_COPY_MODE_COMPACT; + // clang-format on + default: + UNEXPECTED("unknown AS copy mode"); + return static_cast<D3D12_RAYTRACING_ACCELERATION_STRUCTURE_COPY_MODE>(~0u); + } +} + +DXGI_FORMAT TypeToRayTracingVertexFormat(VALUE_TYPE ValueType, Uint32 ComponentCount) +{ + // Vertex format must be one of the following (https://docs.microsoft.com/en-us/windows/win32/api/d3d12/ns-d3d12-d3d12_raytracing_geometry_triangles_desc): + // * DXGI_FORMAT_R32G32_FLOAT - third component is assumed 0 + // * DXGI_FORMAT_R32G32B32_FLOAT + // * DXGI_FORMAT_R16G16_FLOAT - third component is assumed 0 + // * DXGI_FORMAT_R16G16B16A16_FLOAT - A16 component is ignored, other data can be packed there, such as setting vertex stride to 6 bytes. + // * DXGI_FORMAT_R16G16_SNORM - third component is assumed 0 + // * DXGI_FORMAT_R16G16B16A16_SNORM - A16 component is ignored, other data can be packed there, such as setting vertex stride to 6 bytes. + // Note that DXGI_FORMAT_R16G16B16A16_FLOAT and DXGI_FORMAT_R16G16B16A16_SNORM are merely workarounds for missing 16-bit 3-component DXGI formats + switch (ValueType) + { + case VT_FLOAT16: + switch (ComponentCount) + { + case 2: return DXGI_FORMAT_R16G16_FLOAT; + case 3: return DXGI_FORMAT_R16G16B16A16_FLOAT; + + default: + UNEXPECTED("Only 2 and 3 component vertex formats are expected"); + return DXGI_FORMAT_UNKNOWN; + } + break; + + case VT_FLOAT32: + switch (ComponentCount) + { + case 2: return DXGI_FORMAT_R32G32_FLOAT; + case 3: return DXGI_FORMAT_R32G32B32_FLOAT; + + default: + UNEXPECTED("Only 2 and 3 component vertex formats are expected"); + return DXGI_FORMAT_UNKNOWN; + } + break; + + case VT_INT16: + switch (ComponentCount) + { + case 2: return DXGI_FORMAT_R16G16_SNORM; + case 3: return DXGI_FORMAT_R16G16B16A16_SNORM; + + default: + UNEXPECTED("Only 2 and 3 component vertex formats are expected"); + return DXGI_FORMAT_UNKNOWN; + } + break; + + default: + UNEXPECTED(GetValueTypeString(ValueType), " is not a valid vertex component type"); + return DXGI_FORMAT_UNKNOWN; + } +} + } // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp index 45e6be49..9a833fe1 100644 --- a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp @@ -39,6 +39,7 @@ #include "D3D12DynamicHeap.hpp" #include "CommandListD3D12Impl.hpp" #include "DXGITypeConversions.hpp" +#include "ShaderBindingTableD3D12Impl.hpp" namespace Diligent { @@ -219,8 +220,7 @@ void DeviceContextD3D12Impl::SetPipelineState(IPipelineState* pPipelineState) TDeviceContextBase::SetPipelineState(pPipelineStateD3D12, 0 /*Dummy*/); - auto& CmdCtx = GetCmdContext(); - auto* pd3d12PSO = pPipelineStateD3D12->GetD3D12PipelineState(); + auto& CmdCtx = GetCmdContext(); switch (PSODesc.PipelineType) { @@ -229,6 +229,7 @@ void DeviceContextD3D12Impl::SetPipelineState(IPipelineState* pPipelineState) { auto& GraphicsPipeline = pPipelineStateD3D12->GetGraphicsPipelineDesc(); auto& GraphicsCtx = CmdCtx.AsGraphicsContext(); + auto* pd3d12PSO = pPipelineStateD3D12->GetD3D12PipelineState(); GraphicsCtx.SetPipelineState(pd3d12PSO); if (PSODesc.PipelineType == PIPELINE_TYPE_GRAPHICS) @@ -254,13 +255,18 @@ void DeviceContextD3D12Impl::SetPipelineState(IPipelineState* pPipelineState) } break; } - case PIPELINE_TYPE_COMPUTE: { + auto* pd3d12PSO = pPipelineStateD3D12->GetD3D12PipelineState(); CmdCtx.AsComputeContext().SetPipelineState(pd3d12PSO); break; } - + case PIPELINE_TYPE_RAY_TRACING: + { + auto* pd3d12SO = pPipelineStateD3D12->GetD3D12StateObject(); + CmdCtx.AsGraphicsContext4().SetRayTracingPipelineState(pd3d12SO); + break; + } default: UNEXPECTED("unknown pipeline type"); } @@ -446,7 +452,7 @@ void DeviceContextD3D12Impl::PrepareForDraw(GraphicsContext& GraphCtx, DRAW_FLAG } #endif - GraphCtx.SetRootSignature(m_pPipelineState->GetD3D12RootSignature()); + GraphCtx.SetGraphicsRootSignature(m_pPipelineState->GetD3D12RootSignature()); if (m_State.pCommittedResourceCache != nullptr) { @@ -602,7 +608,7 @@ void DeviceContextD3D12Impl::DrawMeshIndirect(const DrawMeshIndirectAttribs& Att void DeviceContextD3D12Impl::PrepareForDispatchCompute(ComputeContext& ComputeCtx) { - ComputeCtx.SetRootSignature(m_pPipelineState->GetD3D12RootSignature()); + ComputeCtx.SetComputeRootSignature(m_pPipelineState->GetD3D12RootSignature()); if (m_State.pCommittedResourceCache != nullptr) { if (m_State.pCommittedResourceCache->GetNumDynamicCBsBound() > 0) @@ -631,6 +637,37 @@ void DeviceContextD3D12Impl::PrepareForDispatchCompute(ComputeContext& ComputeCt #endif } +void DeviceContextD3D12Impl::PrepareForDispatchRays(GraphicsContext& GraphCtx) +{ + GraphCtx.SetComputeRootSignature(m_pPipelineState->GetD3D12RootSignature()); + if (m_State.pCommittedResourceCache != nullptr) + { + if (m_State.pCommittedResourceCache->GetNumDynamicCBsBound() > 0) + { + // Only process dynamic buffers. Non-dynamic buffers are committed by CommitShaderResources + m_pPipelineState->GetRootSignature() + .CommitRootViews(*m_State.pCommittedResourceCache, + GraphCtx, + true, // IsCompute + m_ContextId, + this, + true, // CommitViews + true, // ProcessDynamicBuffers + false, // ProcessNonDynamicBuffers + false, // TransitionStates + false // ValidateStates + ); + } + } +#ifdef DILIGENT_DEVELOPMENT + else + { + if (m_pPipelineState->ContainsShaderResources()) + LOG_ERROR_MESSAGE("Pipeline state '", m_pPipelineState->GetDesc().Name, "' contains shader resources, but IDeviceContext::CommitShaderResources() was not called with non-null SRB"); + } +#endif +} + void DeviceContextD3D12Impl::DispatchCompute(const DispatchComputeAttribs& Attribs) { if (!DvpVerifyDispatchArguments(Attribs)) @@ -2106,7 +2143,7 @@ void DeviceContextD3D12Impl::TransitionOrVerifyBufferState(CommandContext& { if (TransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION) { - if (Buffer.IsInKnownState() && !Buffer.CheckState(RequiredState)) + if (Buffer.IsInKnownState()) CmdCtx.TransitionResource(&Buffer, RequiredState); } #ifdef DILIGENT_DEVELOPMENT @@ -2125,7 +2162,7 @@ void DeviceContextD3D12Impl::TransitionOrVerifyTextureState(CommandContext& { if (TransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION) { - if (Texture.IsInKnownState() && !Texture.CheckState(RequiredState)) + if (Texture.IsInKnownState()) CmdCtx.TransitionResource(&Texture, RequiredState); } #ifdef DILIGENT_DEVELOPMENT @@ -2136,6 +2173,44 @@ void DeviceContextD3D12Impl::TransitionOrVerifyTextureState(CommandContext& #endif } +void DeviceContextD3D12Impl::TransitionOrVerifyBLASState(CommandContext& CmdCtx, + BottomLevelASD3D12Impl& BLAS, + RESOURCE_STATE_TRANSITION_MODE TransitionMode, + RESOURCE_STATE RequiredState, + const char* OperationName) +{ + if (TransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION) + { + if (BLAS.IsInKnownState()) + CmdCtx.TransitionResource(&BLAS, RequiredState); + } +#ifdef DILIGENT_DEVELOPMENT + else if (TransitionMode == RESOURCE_STATE_TRANSITION_MODE_VERIFY) + { + DvpVerifyBLASState(BLAS, RequiredState, OperationName); + } +#endif +} + +void DeviceContextD3D12Impl::TransitionOrVerifyTLASState(CommandContext& CmdCtx, + TopLevelASD3D12Impl& TLAS, + RESOURCE_STATE_TRANSITION_MODE TransitionMode, + RESOURCE_STATE RequiredState, + const char* OperationName) +{ + if (TransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION) + { + if (TLAS.IsInKnownState()) + CmdCtx.TransitionResource(&TLAS, RequiredState); + } +#ifdef DILIGENT_DEVELOPMENT + else if (TransitionMode == RESOURCE_STATE_TRANSITION_MODE_VERIFY) + { + DvpVerifyTLASState(TLAS, RequiredState, OperationName); + } +#endif +} + void DeviceContextD3D12Impl::TransitionTextureState(ITexture* pTexture, D3D12_RESOURCE_STATES State) { VERIFY_EXPR(pTexture != nullptr); @@ -2196,4 +2271,408 @@ void DeviceContextD3D12Impl::ResolveTextureSubresource(ITexture* CmdCtx.ResolveSubresource(pDstTexD3D12->GetD3D12Resource(), DstSubresIndex, pSrcTexD3D12->GetD3D12Resource(), SrcSubresIndex, DXGIFmt); } + +void DeviceContextD3D12Impl::BuildBLAS(const BuildBLASAttribs& Attribs) +{ + if (!TDeviceContextBase::BuildBLAS(Attribs, 0)) + return; + + auto* const pBLASD3D12 = ValidatedCast<BottomLevelASD3D12Impl>(Attribs.pBLAS); + auto* const pScratchD3D12 = ValidatedCast<BufferD3D12Impl>(Attribs.pScratchBuffer); + const auto& BLASDesc = pBLASD3D12->GetDesc(); + + auto& CmdCtx = GetCmdContext(); + const char* OpName = "Build BottomLevelAS (DeviceContextD3D12Impl::BuildBLAS)"; + TransitionOrVerifyBLASState(CmdCtx, *pBLASD3D12, Attribs.BLASTransitionMode, RESOURCE_STATE_BUILD_AS_WRITE, OpName); + TransitionOrVerifyBufferState(CmdCtx, *pScratchD3D12, Attribs.ScratchBufferTransitionMode, RESOURCE_STATE_BUILD_AS_WRITE, OpName); + + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC d3d12BuildASDesc = {}; + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS& d3d12BuildASInputs = d3d12BuildASDesc.Inputs; + std::vector<D3D12_RAYTRACING_GEOMETRY_DESC> Geometries; + + if (Attribs.pTriangleData != nullptr) + { + Geometries.resize(Attribs.TriangleDataCount); + pBLASD3D12->SetActualGeometryCount(Attribs.TriangleDataCount); + + for (Uint32 i = 0; i < Attribs.TriangleDataCount; ++i) + { + const auto& SrcTris = Attribs.pTriangleData[i]; + Uint32 Idx = i; + Uint32 GeoIdx = pBLASD3D12->UpdateGeometryIndex(SrcTris.GeometryName, Idx, Attribs.Update); + + if (GeoIdx == INVALID_INDEX || Idx == INVALID_INDEX) + { + UNEXPECTED("Failed to find geometry by name"); + continue; + } + + auto& d3d12Geo = Geometries[Idx]; + auto& d3d12Tris = d3d12Geo.Triangles; + const auto& TriDesc = BLASDesc.pTriangles[GeoIdx]; + + d3d12Geo.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES; + d3d12Geo.Flags = GeometryFlagsToD3D12RTGeometryFlags(SrcTris.Flags); + + auto* const pVB = ValidatedCast<BufferD3D12Impl>(SrcTris.pVertexBuffer); + + // vertex format in SrcTris may be undefined, so use vertex format from description + d3d12Tris.VertexBuffer.StartAddress = pVB->GetGPUAddress() + SrcTris.VertexOffset; + d3d12Tris.VertexBuffer.StrideInBytes = SrcTris.VertexStride; + d3d12Tris.VertexCount = SrcTris.VertexCount; + d3d12Tris.VertexFormat = TypeToRayTracingVertexFormat(TriDesc.VertexValueType, TriDesc.VertexComponentCount); + VERIFY(d3d12Tris.VertexFormat != DXGI_FORMAT_UNKNOWN, "Unsupported combination of vertex value type and component count"); + + VERIFY(d3d12Tris.VertexBuffer.StartAddress % GetValueSize(TriDesc.VertexValueType) == 0, "Vertex start address is not properly aligned"); + VERIFY(d3d12Tris.VertexBuffer.StrideInBytes % GetValueSize(TriDesc.VertexValueType) == 0, "Vertex stride is not properly aligned"); + + TransitionOrVerifyBufferState(CmdCtx, *pVB, Attribs.GeometryTransitionMode, RESOURCE_STATE_BUILD_AS_READ, OpName); + + if (SrcTris.pIndexBuffer) + { + auto* const pIB = ValidatedCast<BufferD3D12Impl>(SrcTris.pIndexBuffer); + + // index type in SrcTris may be undefined, so use index type from description + d3d12Tris.IndexFormat = ValueTypeToIndexType(TriDesc.IndexType); + d3d12Tris.IndexBuffer = pIB->GetGPUAddress() + SrcTris.IndexOffset; + d3d12Tris.IndexCount = SrcTris.PrimitiveCount * 3; + + VERIFY(d3d12Tris.IndexBuffer % GetValueSize(TriDesc.IndexType) == 0, "Index start address is not properly aligned"); + + TransitionOrVerifyBufferState(CmdCtx, *pIB, Attribs.GeometryTransitionMode, RESOURCE_STATE_BUILD_AS_READ, OpName); + } + else + { + d3d12Tris.IndexFormat = DXGI_FORMAT_UNKNOWN; + d3d12Tris.IndexBuffer = 0; + } + + if (SrcTris.pTransformBuffer) + { + auto* const pTB = ValidatedCast<BufferD3D12Impl>(SrcTris.pTransformBuffer); + d3d12Tris.Transform3x4 = pTB->GetGPUAddress() + SrcTris.TransformBufferOffset; + + VERIFY(d3d12Tris.Transform3x4 % D3D12_RAYTRACING_TRANSFORM3X4_BYTE_ALIGNMENT == 0, "Transform start address is not properly aligned"); + + TransitionOrVerifyBufferState(CmdCtx, *pTB, Attribs.GeometryTransitionMode, RESOURCE_STATE_BUILD_AS_READ, OpName); + } + else + { + d3d12Tris.Transform3x4 = 0; + } + } + } + else if (Attribs.pBoxData != nullptr) + { + Geometries.resize(Attribs.BoxDataCount); + pBLASD3D12->SetActualGeometryCount(Attribs.BoxDataCount); + + for (Uint32 i = 0; i < Attribs.BoxDataCount; ++i) + { + const auto& SrcBoxes = Attribs.pBoxData[i]; + Uint32 Idx = i; + Uint32 GeoIdx = pBLASD3D12->UpdateGeometryIndex(SrcBoxes.GeometryName, Idx, Attribs.Update); + + if (GeoIdx == INVALID_INDEX || Idx == INVALID_INDEX) + { + UNEXPECTED("Failed to find geometry by name"); + continue; + } + + auto& d3d12Geo = Geometries[Idx]; + auto& d3d12AABs = d3d12Geo.AABBs; + + d3d12Geo.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_PROCEDURAL_PRIMITIVE_AABBS; + d3d12Geo.Flags = GeometryFlagsToD3D12RTGeometryFlags(SrcBoxes.Flags); + + auto* pBB = ValidatedCast<BufferD3D12Impl>(SrcBoxes.pBoxBuffer); + d3d12AABs.AABBCount = SrcBoxes.BoxCount; + d3d12AABs.AABBs.StartAddress = pBB->GetGPUAddress() + SrcBoxes.BoxOffset; + d3d12AABs.AABBs.StrideInBytes = SrcBoxes.BoxStride; + + DEV_CHECK_ERR(d3d12AABs.AABBs.StartAddress % D3D12_RAYTRACING_AABB_BYTE_ALIGNMENT == 0, "AABB start address is not properly aligned"); + DEV_CHECK_ERR(d3d12AABs.AABBs.StrideInBytes % D3D12_RAYTRACING_AABB_BYTE_ALIGNMENT == 0, "AABB stride is not properly aligned"); + + TransitionOrVerifyBufferState(CmdCtx, *pBB, Attribs.GeometryTransitionMode, RESOURCE_STATE_BUILD_AS_READ, OpName); + } + } + + d3d12BuildASInputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL; + d3d12BuildASInputs.Flags = BuildASFlagsToD3D12ASBuildFlags(BLASDesc.Flags); + d3d12BuildASInputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY; + d3d12BuildASInputs.NumDescs = static_cast<UINT>(Geometries.size()); + d3d12BuildASInputs.pGeometryDescs = Geometries.data(); + + d3d12BuildASDesc.DestAccelerationStructureData = pBLASD3D12->GetGPUAddress(); + d3d12BuildASDesc.ScratchAccelerationStructureData = pScratchD3D12->GetGPUAddress() + Attribs.ScratchBufferOffset; + d3d12BuildASDesc.SourceAccelerationStructureData = 0; + + if (Attribs.Update) + { + d3d12BuildASInputs.Flags |= D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PERFORM_UPDATE; + d3d12BuildASDesc.SourceAccelerationStructureData = d3d12BuildASDesc.DestAccelerationStructureData; + } + + DEV_CHECK_ERR(d3d12BuildASDesc.ScratchAccelerationStructureData % D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BYTE_ALIGNMENT == 0, + "Scratch data address is not properly aligned"); + + CmdCtx.AsGraphicsContext4().BuildRaytracingAccelerationStructure(d3d12BuildASDesc, 0, nullptr); + ++m_State.NumCommands; + +#ifdef DILIGENT_DEVELOPMENT + pBLASD3D12->UpdateVersion(); +#endif +} + +void DeviceContextD3D12Impl::BuildTLAS(const BuildTLASAttribs& Attribs) +{ + if (!TDeviceContextBase::BuildTLAS(Attribs, 0)) + return; + + static_assert(TLAS_INSTANCE_DATA_SIZE == sizeof(D3D12_RAYTRACING_INSTANCE_DESC), "Value in TLAS_INSTANCE_DATA_SIZE doesn't match the actual instance description size"); + + auto* pTLASD3D12 = ValidatedCast<TopLevelASD3D12Impl>(Attribs.pTLAS); + auto* pScratchD3D12 = ValidatedCast<BufferD3D12Impl>(Attribs.pScratchBuffer); + auto* pInstancesD3D12 = ValidatedCast<BufferD3D12Impl>(Attribs.pInstanceBuffer); + + auto& CmdCtx = GetCmdContext(); + const char* OpName = "Build TopLevelAS (DeviceContextD3D12Impl::BuildTLAS)"; + TransitionOrVerifyTLASState(CmdCtx, *pTLASD3D12, Attribs.TLASTransitionMode, RESOURCE_STATE_BUILD_AS_WRITE, OpName); + TransitionOrVerifyBufferState(CmdCtx, *pScratchD3D12, Attribs.ScratchBufferTransitionMode, RESOURCE_STATE_BUILD_AS_WRITE, OpName); + + if (Attribs.Update) + { + if (!pTLASD3D12->UpdateInstances(Attribs.pInstances, Attribs.InstanceCount, Attribs.BaseContributionToHitGroupIndex, Attribs.HitGroupStride, Attribs.BindingMode)) + return; + } + else + { + if (!pTLASD3D12->SetInstanceData(Attribs.pInstances, Attribs.InstanceCount, Attribs.BaseContributionToHitGroupIndex, Attribs.HitGroupStride, Attribs.BindingMode)) + return; + } + + // copy instance data into instance buffer + { + size_t Size = Attribs.InstanceCount * sizeof(D3D12_RAYTRACING_INSTANCE_DESC); + auto TmpSpace = m_DynamicHeap.Allocate(Size, 16, m_ContextFrameNumber); + + for (Uint32 i = 0; i < Attribs.InstanceCount; ++i) + { + const auto& Inst = Attribs.pInstances[i]; + const auto InstDesc = pTLASD3D12->GetInstanceDesc(Inst.InstanceName); + + if (InstDesc.InstanceIndex >= Attribs.InstanceCount) + { + UNEXPECTED("Failed to find instance by name"); + return; + } + + auto& d3d12Inst = static_cast<D3D12_RAYTRACING_INSTANCE_DESC*>(TmpSpace.CPUAddress)[InstDesc.InstanceIndex]; + auto* pBLASD3D12 = ValidatedCast<BottomLevelASD3D12Impl>(Inst.pBLAS); + + static_assert(sizeof(d3d12Inst.Transform) == sizeof(Inst.Transform), "size mismatch"); + std::memcpy(&d3d12Inst.Transform, Inst.Transform.data, sizeof(d3d12Inst.Transform)); + + d3d12Inst.InstanceID = Inst.CustomId; + d3d12Inst.InstanceContributionToHitGroupIndex = InstDesc.ContributionToHitGroupIndex; + d3d12Inst.InstanceMask = Inst.Mask; + d3d12Inst.Flags = InstanceFlagsToD3D12RTInstanceFlags(Inst.Flags); + d3d12Inst.AccelerationStructure = pBLASD3D12->GetGPUAddress(); + + TransitionOrVerifyBLASState(CmdCtx, *pBLASD3D12, Attribs.BLASTransitionMode, RESOURCE_STATE_BUILD_AS_READ, OpName); + } + UpdateBufferRegion(pInstancesD3D12, TmpSpace, Attribs.InstanceBufferOffset, Size, Attribs.InstanceBufferTransitionMode); + } + TransitionOrVerifyBufferState(CmdCtx, *pInstancesD3D12, Attribs.InstanceBufferTransitionMode, RESOURCE_STATE_BUILD_AS_READ, OpName); + + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC d3d12BuildASDesc = {}; + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS& d3d12BuildASInputs = d3d12BuildASDesc.Inputs; + + d3d12BuildASInputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL; + d3d12BuildASInputs.Flags = BuildASFlagsToD3D12ASBuildFlags(pTLASD3D12->GetDesc().Flags); + d3d12BuildASInputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY; + d3d12BuildASInputs.NumDescs = Attribs.InstanceCount; + d3d12BuildASInputs.InstanceDescs = pInstancesD3D12->GetGPUAddress() + Attribs.InstanceBufferOffset; + + d3d12BuildASDesc.DestAccelerationStructureData = pTLASD3D12->GetGPUAddress(); + d3d12BuildASDesc.ScratchAccelerationStructureData = pScratchD3D12->GetGPUAddress() + Attribs.ScratchBufferOffset; + d3d12BuildASDesc.SourceAccelerationStructureData = 0; + + if (Attribs.Update) + { + d3d12BuildASInputs.Flags |= D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PERFORM_UPDATE; + d3d12BuildASDesc.SourceAccelerationStructureData = d3d12BuildASDesc.DestAccelerationStructureData; + } + + DEV_CHECK_ERR(d3d12BuildASInputs.InstanceDescs % D3D12_RAYTRACING_INSTANCE_DESCS_BYTE_ALIGNMENT == 0, + "Instance data address is not properly aligned"); + DEV_CHECK_ERR(d3d12BuildASDesc.ScratchAccelerationStructureData % D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BYTE_ALIGNMENT == 0, + "Scratch data address is not properly algined"); + + CmdCtx.AsGraphicsContext4().BuildRaytracingAccelerationStructure(d3d12BuildASDesc, 0, nullptr); + ++m_State.NumCommands; +} + +void DeviceContextD3D12Impl::CopyBLAS(const CopyBLASAttribs& Attribs) +{ + if (!TDeviceContextBase::CopyBLAS(Attribs, 0)) + return; + + auto* pSrcD3D12 = ValidatedCast<BottomLevelASD3D12Impl>(Attribs.pSrc); + auto* pDstD3D12 = ValidatedCast<BottomLevelASD3D12Impl>(Attribs.pDst); + auto& CmdCtx = GetCmdContext(); + auto Mode = CopyASModeToD3D12ASCopyMode(Attribs.Mode); + + // Dst BLAS description has specified CompactedSize, but doesn't have specified pTriangles and pBoxes. + // We should copy geometries because it required for SBT to map geometry name to hit group. + pDstD3D12->CopyGeometryDescription(*pSrcD3D12); + pDstD3D12->SetActualGeometryCount(pSrcD3D12->GetActualGeometryCount()); + + const char* OpName = "Copy BottomLevelAS (DeviceContextD3D12Impl::CopyBLAS)"; + TransitionOrVerifyBLASState(CmdCtx, *pSrcD3D12, Attribs.SrcTransitionMode, RESOURCE_STATE_BUILD_AS_READ, OpName); + TransitionOrVerifyBLASState(CmdCtx, *pDstD3D12, Attribs.DstTransitionMode, RESOURCE_STATE_BUILD_AS_WRITE, OpName); + + CmdCtx.AsGraphicsContext4().CopyRaytracingAccelerationStructure(pDstD3D12->GetGPUAddress(), pSrcD3D12->GetGPUAddress(), Mode); + ++m_State.NumCommands; + +#ifdef DILIGENT_DEVELOPMENT + pDstD3D12->UpdateVersion(); +#endif +} + +void DeviceContextD3D12Impl::CopyTLAS(const CopyTLASAttribs& Attribs) +{ + if (!TDeviceContextBase::CopyTLAS(Attribs, 0)) + return; + + auto* pSrcD3D12 = ValidatedCast<TopLevelASD3D12Impl>(Attribs.pSrc); + auto* pDstD3D12 = ValidatedCast<TopLevelASD3D12Impl>(Attribs.pDst); + auto& CmdCtx = GetCmdContext(); + auto Mode = CopyASModeToD3D12ASCopyMode(Attribs.Mode); + + // Instances specified in BuildTLAS command. + // We should copy instances because it required for SBT to map instance name to hit group. + pDstD3D12->CopyInstancceData(*pSrcD3D12); + + const char* OpName = "Copy BottomLevelAS (DeviceContextD3D12Impl::CopyTLAS)"; + TransitionOrVerifyTLASState(CmdCtx, *pSrcD3D12, Attribs.SrcTransitionMode, RESOURCE_STATE_BUILD_AS_READ, OpName); + TransitionOrVerifyTLASState(CmdCtx, *pDstD3D12, Attribs.DstTransitionMode, RESOURCE_STATE_BUILD_AS_WRITE, OpName); + + CmdCtx.AsGraphicsContext4().CopyRaytracingAccelerationStructure(pDstD3D12->GetGPUAddress(), pSrcD3D12->GetGPUAddress(), Mode); + ++m_State.NumCommands; +} + +void DeviceContextD3D12Impl::WriteBLASCompactedSize(const WriteBLASCompactedSizeAttribs& Attribs) +{ + if (!TDeviceContextBase::WriteBLASCompactedSize(Attribs, 0)) + return; + + static_assert(sizeof(D3D12_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_COMPACTED_SIZE_DESC) == sizeof(Uint64), + "Engine api specifies that compacted size is 64 bits"); + + auto* pBLASD3D12 = ValidatedCast<BottomLevelASD3D12Impl>(Attribs.pBLAS); + auto* pDestBuffD3D12 = ValidatedCast<BufferD3D12Impl>(Attribs.pDestBuffer); + auto& CmdCtx = GetCmdContext(); + + const char* OpName = "Write AS compacted size (DeviceContextD3D12Impl::WriteBLASCompactedSize)"; + TransitionOrVerifyBLASState(CmdCtx, *pBLASD3D12, Attribs.BLASTransitionMode, RESOURCE_STATE_BUILD_AS_READ, OpName); + TransitionOrVerifyBufferState(CmdCtx, *pDestBuffD3D12, Attribs.BufferTransitionMode, RESOURCE_STATE_UNORDERED_ACCESS, OpName); + + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_DESC d3d12Desc = {}; + + d3d12Desc.DestBuffer = pDestBuffD3D12->GetGPUAddress() + Attribs.DestBufferOffset; + d3d12Desc.InfoType = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_COMPACTED_SIZE; + + CmdCtx.AsGraphicsContext4().EmitRaytracingAccelerationStructurePostbuildInfo(d3d12Desc, pBLASD3D12->GetGPUAddress()); + ++m_State.NumCommands; +} + +void DeviceContextD3D12Impl::WriteTLASCompactedSize(const WriteTLASCompactedSizeAttribs& Attribs) +{ + if (!TDeviceContextBase::WriteTLASCompactedSize(Attribs, 0)) + return; + + static_assert(sizeof(D3D12_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_COMPACTED_SIZE_DESC) == sizeof(Uint64), + "Engine api specifies that compacted size is 64 bits"); + + auto* pTLASD3D12 = ValidatedCast<TopLevelASD3D12Impl>(Attribs.pTLAS); + auto* pDestBuffD3D12 = ValidatedCast<BufferD3D12Impl>(Attribs.pDestBuffer); + auto& CmdCtx = GetCmdContext(); + + const char* OpName = "Write AS compacted size (DeviceContextD3D12Impl::WriteTLASCompactedSize)"; + TransitionOrVerifyTLASState(CmdCtx, *pTLASD3D12, Attribs.TLASTransitionMode, RESOURCE_STATE_BUILD_AS_READ, OpName); + TransitionOrVerifyBufferState(CmdCtx, *pDestBuffD3D12, Attribs.BufferTransitionMode, RESOURCE_STATE_UNORDERED_ACCESS, OpName); + + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_DESC d3d12Desc = {}; + + d3d12Desc.DestBuffer = pDestBuffD3D12->GetGPUAddress() + Attribs.DestBufferOffset; + d3d12Desc.InfoType = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_COMPACTED_SIZE; + + CmdCtx.AsGraphicsContext4().EmitRaytracingAccelerationStructurePostbuildInfo(d3d12Desc, pTLASD3D12->GetGPUAddress()); + ++m_State.NumCommands; +} + +void DeviceContextD3D12Impl::TraceRays(const TraceRaysAttribs& Attribs) +{ + if (!TDeviceContextBase::TraceRays(Attribs, 0)) + return; + + auto& CmdCtx = GetCmdContext().AsGraphicsContext4(); + auto* pSBTD3D12 = ValidatedCast<ShaderBindingTableD3D12Impl>(Attribs.pSBT); + IBuffer* pBuffer = nullptr; + + ShaderBindingTableD3D12Impl::BindingTable RayGenShaderRecord = {}; + ShaderBindingTableD3D12Impl::BindingTable MissShaderTable = {}; + ShaderBindingTableD3D12Impl::BindingTable HitGroupTable = {}; + ShaderBindingTableD3D12Impl::BindingTable CallableShaderTable = {}; + + pSBTD3D12->GetData(pBuffer, RayGenShaderRecord, MissShaderTable, HitGroupTable, CallableShaderTable); + + auto* pBufferD3D12 = ValidatedCast<BufferD3D12Impl>(pBuffer); + + const char* OpName = "Trace rays (DeviceContextD3D12Impl::TraceRays)"; + TransitionOrVerifyBufferState(CmdCtx, *pBufferD3D12, Attribs.SBTTransitionMode, RESOURCE_STATE_COPY_DEST, OpName); + + // buffer ranges are not intersected, so we don't need to add barriers between them + if (RayGenShaderRecord.pData) + UpdateBuffer(pBufferD3D12, RayGenShaderRecord.Offset, RayGenShaderRecord.Size, RayGenShaderRecord.pData, RESOURCE_STATE_TRANSITION_MODE_VERIFY); + + if (MissShaderTable.pData) + UpdateBuffer(pBufferD3D12, MissShaderTable.Offset, MissShaderTable.Size, MissShaderTable.pData, RESOURCE_STATE_TRANSITION_MODE_VERIFY); + + if (HitGroupTable.pData) + UpdateBuffer(pBufferD3D12, HitGroupTable.Offset, HitGroupTable.Size, HitGroupTable.pData, RESOURCE_STATE_TRANSITION_MODE_VERIFY); + + if (CallableShaderTable.pData) + UpdateBuffer(pBufferD3D12, CallableShaderTable.Offset, CallableShaderTable.Size, CallableShaderTable.pData, RESOURCE_STATE_TRANSITION_MODE_VERIFY); + + TransitionOrVerifyBufferState(CmdCtx, *pBufferD3D12, Attribs.SBTTransitionMode, RESOURCE_STATE_RAY_TRACING, OpName); + + D3D12_DISPATCH_RAYS_DESC d3d12DispatchDesc = {}; + + d3d12DispatchDesc.Width = Attribs.DimensionX; + d3d12DispatchDesc.Height = Attribs.DimensionY; + d3d12DispatchDesc.Depth = Attribs.DimensionZ; + + d3d12DispatchDesc.RayGenerationShaderRecord.StartAddress = pBufferD3D12->GetGPUAddress() + RayGenShaderRecord.Offset; + d3d12DispatchDesc.RayGenerationShaderRecord.SizeInBytes = RayGenShaderRecord.Size; + + d3d12DispatchDesc.MissShaderTable.StartAddress = pBufferD3D12->GetGPUAddress() + MissShaderTable.Offset; + d3d12DispatchDesc.MissShaderTable.SizeInBytes = MissShaderTable.Size; + d3d12DispatchDesc.MissShaderTable.StrideInBytes = MissShaderTable.Stride; + + d3d12DispatchDesc.HitGroupTable.StartAddress = pBufferD3D12->GetGPUAddress() + HitGroupTable.Offset; + d3d12DispatchDesc.HitGroupTable.SizeInBytes = HitGroupTable.Size; + d3d12DispatchDesc.HitGroupTable.StrideInBytes = HitGroupTable.Stride; + + d3d12DispatchDesc.CallableShaderTable.StartAddress = pBufferD3D12->GetGPUAddress() + CallableShaderTable.Offset; + d3d12DispatchDesc.CallableShaderTable.SizeInBytes = CallableShaderTable.Size; + d3d12DispatchDesc.CallableShaderTable.StrideInBytes = CallableShaderTable.Stride; + + PrepareForDispatchRays(CmdCtx); + + CmdCtx.DispatchRays(d3d12DispatchDesc); + ++m_State.NumCommands; +} + } // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/src/FenceD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/FenceD3D12Impl.cpp index a9e1c7d8..02308ca0 100644 --- a/Graphics/GraphicsEngineD3D12/src/FenceD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/FenceD3D12Impl.cpp @@ -51,7 +51,9 @@ FenceD3D12Impl::~FenceD3D12Impl() Uint64 FenceD3D12Impl::GetCompletedValue() { - return m_pd3d12Fence->GetCompletedValue(); + Uint64 Result = m_pd3d12Fence->GetCompletedValue(); + VERIFY(Result != UINT64_MAX, "If the device has been removed, the return value will be UINT64_MAX"); + return Result; } void FenceD3D12Impl::Reset(Uint64 Value) @@ -61,7 +63,7 @@ void FenceD3D12Impl::Reset(Uint64 Value) void FenceD3D12Impl::WaitForCompletion(Uint64 Value) { - while (m_pd3d12Fence->GetCompletedValue() < Value) + while (GetCompletedValue() < Value) std::this_thread::yield(); } diff --git a/Graphics/GraphicsEngineD3D12/src/GenerateMips.cpp b/Graphics/GraphicsEngineD3D12/src/GenerateMips.cpp index be5c68eb..0da4470b 100644 --- a/Graphics/GraphicsEngineD3D12/src/GenerateMips.cpp +++ b/Graphics/GraphicsEngineD3D12/src/GenerateMips.cpp @@ -113,7 +113,7 @@ GenerateMipsHelper::GenerateMipsHelper(ID3D12Device* pd3d12Device) void GenerateMipsHelper::GenerateMips(ID3D12Device* pd3d12Device, TextureViewD3D12Impl* pTexView, CommandContext& Ctx) const { auto& ComputeCtx = Ctx.AsComputeContext(); - ComputeCtx.SetRootSignature(m_pGenerateMipsRS); + ComputeCtx.SetComputeRootSignature(m_pGenerateMipsRS); auto* pTexD3D12 = pTexView->GetTexture<TextureD3D12Impl>(); const auto& TexDesc = pTexD3D12->GetDesc(); const auto& ViewDesc = pTexView->GetDesc(); diff --git a/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp index 93125bea..bb2cb5c4 100644 --- a/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp @@ -37,6 +37,9 @@ #include "EngineMemory.h" #include "StringTools.hpp" #include "ShaderVariableD3D12.hpp" +#include "DynamicLinearAllocator.hpp" +#include "DXCompiler.hpp" +#include "dxc/dxcapi.h" namespace Diligent { @@ -70,7 +73,6 @@ struct alignas(void*) PSS_SubObject # pragma warning(pop) #endif -} // namespace class PrimitiveTopology_To_D3D12_PRIMITIVE_TOPOLOGY_TYPE { @@ -98,15 +100,276 @@ private: std::array<D3D12_PRIMITIVE_TOPOLOGY_TYPE, PRIMITIVE_TOPOLOGY_NUM_TOPOLOGIES> m_Map; }; -template <typename PSOCreateInfoType> -void PipelineStateD3D12Impl::InitInternalObjects(const PSOCreateInfoType& CreateInfo, - std::vector<D3D12PipelineShaderStageInfo>& ShaderStages) +using TBindingMapPerStage = std::array<IDXCompiler::TResourceBindingMap, MAX_SHADERS_IN_PIPELINE>; + +void BuildRTPipelineDescription(const RayTracingPipelineStateCreateInfo& CreateInfo, + std::vector<D3D12_STATE_SUBOBJECT>& Subobjects, + std::vector<CComPtr<IDxcBlob>>& ShaderBlobs, + DynamicLinearAllocator& TempPool, + IDXCompiler* compiler, + const TBindingMapPerStage& BindingMapPerStage) noexcept(false) +{ +#define LOG_PSO_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Description of ray tracing PSO '", CreateInfo.PSODesc.Name, "' is invalid: ", ##__VA_ARGS__) + + Uint32 ShaderIndex = 0; + + std::unordered_map<IShader*, LPCWSTR> UniqueShaders; + + const auto ShaderIndexToStr = [&TempPool](Uint32 Index) -> LPCWSTR { + const Uint32 Len = sizeof(Index) * 2; + auto* Dst = TempPool.Allocate<WCHAR>(Len + 1); + for (Uint32 i = 0; i < Len; ++i) + { + Uint32 c = Index & 0xF; + Dst[i] = static_cast<WCHAR>(c < 10 ? '0' + c : 'A' + c - 10); + Index >>= 4; + } + Dst[Len] = 0; + return Dst; + }; + + const auto AddDxilLib = [&](IShader* pShader, const char* Name) -> LPCWSTR { + if (pShader != nullptr) + { + auto Result = UniqueShaders.emplace(pShader, nullptr); + if (Result.second) + { + auto& LibDesc = *TempPool.Construct<D3D12_DXIL_LIBRARY_DESC>(); + auto& ExportDesc = *TempPool.Construct<D3D12_EXPORT_DESC>(); + auto* pShaderD3D12 = ValidatedCast<ShaderD3D12Impl>(pShader); + Uint32 ShaderIdx = GetShaderTypePipelineIndex(pShaderD3D12->GetDesc().ShaderType, PIPELINE_TYPE_RAY_TRACING); + auto& BindingMap = BindingMapPerStage[ShaderIdx]; + + CComPtr<IDxcBlob> pBlob; + if (!compiler->RemapResourceBinding(BindingMap, reinterpret_cast<IDxcBlob*>(pShaderD3D12->GetShaderByteCode()), &pBlob)) + LOG_ERROR_AND_THROW("Failed to remap resource bindings"); + + LibDesc.DXILLibrary.BytecodeLength = pBlob->GetBufferSize(); + LibDesc.DXILLibrary.pShaderBytecode = pBlob->GetBufferPointer(); + LibDesc.NumExports = 1; + LibDesc.pExports = &ExportDesc; + + ExportDesc.Flags = D3D12_EXPORT_FLAG_NONE; + ExportDesc.ExportToRename = TempPool.CopyWString(pShaderD3D12->GetEntryPoint()); + + if (Name != nullptr) + ExportDesc.Name = TempPool.CopyWString(Name); + else + ExportDesc.Name = ShaderIndexToStr(++ShaderIndex); + + Subobjects.push_back({D3D12_STATE_SUBOBJECT_TYPE_DXIL_LIBRARY, &LibDesc}); + ShaderBlobs.push_back(pBlob); + + Result.first->second = ExportDesc.Name; + return ExportDesc.Name; + } + else + return Result.first->second; + } + return nullptr; + }; + + ShaderBlobs.reserve(CreateInfo.GeneralShaderCount + CreateInfo.TriangleHitShaderCount + CreateInfo.ProceduralHitShaderCount); + + for (Uint32 i = 0; i < CreateInfo.GeneralShaderCount; ++i) + { + const auto& GeneralShader = CreateInfo.pGeneralShaders[i]; + AddDxilLib(GeneralShader.pShader, GeneralShader.Name); + } + + for (Uint32 i = 0; i < CreateInfo.TriangleHitShaderCount; ++i) + { + const auto& TriHitShader = CreateInfo.pTriangleHitShaders[i]; + + auto& HitGroupDesc = *TempPool.Construct<D3D12_HIT_GROUP_DESC>(); + HitGroupDesc.HitGroupExport = TempPool.CopyWString(TriHitShader.Name); + HitGroupDesc.Type = D3D12_HIT_GROUP_TYPE_TRIANGLES; + HitGroupDesc.ClosestHitShaderImport = AddDxilLib(TriHitShader.pClosestHitShader, nullptr); + HitGroupDesc.AnyHitShaderImport = AddDxilLib(TriHitShader.pAnyHitShader, nullptr); + HitGroupDesc.IntersectionShaderImport = nullptr; + + Subobjects.push_back({D3D12_STATE_SUBOBJECT_TYPE_HIT_GROUP, &HitGroupDesc}); + } + + for (Uint32 i = 0; i < CreateInfo.ProceduralHitShaderCount; ++i) + { + const auto& ProcHitShader = CreateInfo.pProceduralHitShaders[i]; + + auto& HitGroupDesc = *TempPool.Construct<D3D12_HIT_GROUP_DESC>(); + HitGroupDesc.HitGroupExport = TempPool.CopyWString(ProcHitShader.Name); + HitGroupDesc.Type = D3D12_HIT_GROUP_TYPE_PROCEDURAL_PRIMITIVE; + HitGroupDesc.ClosestHitShaderImport = AddDxilLib(ProcHitShader.pClosestHitShader, nullptr); + HitGroupDesc.AnyHitShaderImport = AddDxilLib(ProcHitShader.pAnyHitShader, nullptr); + HitGroupDesc.IntersectionShaderImport = AddDxilLib(ProcHitShader.pIntersectionShader, nullptr); + + Subobjects.push_back({D3D12_STATE_SUBOBJECT_TYPE_HIT_GROUP, &HitGroupDesc}); + } + + constexpr Uint32 DefaultPayloadSize = sizeof(float) * 8; + + auto& PipelineConfig = *TempPool.Construct<D3D12_RAYTRACING_PIPELINE_CONFIG>(); + // For compatibility with Vulkan set minimal recursion depth to one, zero means no tracing of rays at all. + PipelineConfig.MaxTraceRecursionDepth = CreateInfo.RayTracingPipeline.MaxRecursionDepth + 1; + Subobjects.push_back({D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG, &PipelineConfig}); + + auto& ShaderConfig = *TempPool.Construct<D3D12_RAYTRACING_SHADER_CONFIG>(); + ShaderConfig.MaxAttributeSizeInBytes = CreateInfo.MaxAttributeSize == 0 ? D3D12_RAYTRACING_MAX_ATTRIBUTE_SIZE_IN_BYTES : CreateInfo.MaxAttributeSize; + ShaderConfig.MaxPayloadSizeInBytes = CreateInfo.MaxPayloadSize == 0 ? DefaultPayloadSize : CreateInfo.MaxPayloadSize; + Subobjects.push_back({D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_SHADER_CONFIG, &ShaderConfig}); +#undef LOG_PSO_ERROR_AND_THROW +} + +template <typename TNameToGroupIndexMap> +void GetShaderIdentifiers(ID3D12DeviceChild* pSO, + const RayTracingPipelineStateCreateInfo& CreateInfo, + const TNameToGroupIndexMap& NameToGroupIndex, + Uint8* ShaderData) +{ + const Uint32 ShaderIdentifierSize = D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES; + + CComPtr<ID3D12StateObjectProperties> pStateObjectProperties; + + auto hr = pSO->QueryInterface(IID_PPV_ARGS(&pStateObjectProperties)); + if (FAILED(hr)) + LOG_ERROR_AND_THROW("Failed to get state object properties"); + + for (Uint32 i = 0; i < CreateInfo.GeneralShaderCount; ++i) + { + const auto& GeneralShader = CreateInfo.pGeneralShaders[i]; + + auto iter = NameToGroupIndex.find(GeneralShader.Name); + if (iter == NameToGroupIndex.end()) + LOG_ERROR_AND_THROW("Failed to get shader group index for general shader group '", GeneralShader.Name, "'"); + + const auto* ShaderID = pStateObjectProperties->GetShaderIdentifier(WidenString(GeneralShader.Name).c_str()); + if (ShaderID == nullptr) + LOG_ERROR_AND_THROW("Failed to get shader identifier for general shader group '", GeneralShader.Name, "'"); + + std::memcpy(&ShaderData[ShaderIdentifierSize * iter->second], ShaderID, ShaderIdentifierSize); + } + for (Uint32 i = 0; i < CreateInfo.TriangleHitShaderCount; ++i) + { + const auto& TriHitShader = CreateInfo.pTriangleHitShaders[i]; + + auto iter = NameToGroupIndex.find(TriHitShader.Name); + if (iter == NameToGroupIndex.end()) + LOG_ERROR_AND_THROW("Failed to get shader group index for triangle hit group '", TriHitShader.Name, "'"); + + const auto* ShaderID = pStateObjectProperties->GetShaderIdentifier(WidenString(TriHitShader.Name).c_str()); + if (ShaderID == nullptr) + LOG_ERROR_AND_THROW("Failed to get shader identifier for triangle hit group '", TriHitShader.Name, "'"); + + std::memcpy(&ShaderData[ShaderIdentifierSize * iter->second], ShaderID, ShaderIdentifierSize); + } + for (Uint32 i = 0; i < CreateInfo.ProceduralHitShaderCount; ++i) + { + const auto& ProcHitShader = CreateInfo.pProceduralHitShaders[i]; + + auto iter = NameToGroupIndex.find(ProcHitShader.Name); + if (iter == NameToGroupIndex.end()) + LOG_ERROR_AND_THROW("Failed to get shader group index for procedural hit shader group '", ProcHitShader.Name, "'"); + + const auto* ShaderID = pStateObjectProperties->GetShaderIdentifier(WidenString(ProcHitShader.Name).c_str()); + if (ShaderID == nullptr) + LOG_ERROR_AND_THROW("Failed to get shader identifier for procedural hit shader group '", ProcHitShader.Name, "'"); + + std::memcpy(&ShaderData[ShaderIdentifierSize * iter->second], ShaderID, ShaderIdentifierSize); + } +} + +void ExtractResourceBindingMap(const RootSignatureBuilder& RootSig, + const std::array<Int8, MAX_SHADERS_IN_PIPELINE>& ResourceLayoutIndex, + const ShaderResourceLayoutD3D12* pResourceLayouts, + const ShaderResourceLayoutD3D12* pStaticLayouts, + TBindingMapPerStage& BindingMapPerStage) noexcept(false) +{ + const auto ExtractResources = [&](const ShaderResourceLayoutD3D12* pLayouts) // + { + for (Uint32 ShaderIdx = 0; ShaderIdx < ResourceLayoutIndex.size(); ++ShaderIdx) + { + const Int8 LayoutIdx = ResourceLayoutIndex[ShaderIdx]; + if (LayoutIdx < 0) + continue; + + auto& BindingMap = BindingMapPerStage[ShaderIdx]; + const auto& ResLayout = pLayouts[LayoutIdx]; + for (Uint32 v = 0; v < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; ++v) + { + auto VarType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(v); + Uint32 ResCount = ResLayout.GetCbvSrvUavCount(VarType); + Uint32 SampCount = ResLayout.GetSamplerCount(VarType); + + for (Uint32 i = 0; i < ResCount; ++i) + { + const auto& Attribs = ResLayout.GetSrvCbvUav(VarType, i).Attribs; + VERIFY_EXPR(Attribs.Name != nullptr && strlen(Attribs.Name) > 0); + + auto Iter = BindingMap.emplace(HashMapStringKey{Attribs.Name}, Attribs.BindPoint).first; + VERIFY_EXPR(Iter->second == Attribs.BindPoint); + } + for (Uint32 i = 0; i < SampCount; ++i) + { + const auto& Attribs = ResLayout.GetSampler(VarType, i).Attribs; + VERIFY_EXPR(Attribs.Name != nullptr && strlen(Attribs.Name) > 0); + + auto Iter = BindingMap.emplace(HashMapStringKey{Attribs.Name}, Attribs.BindPoint).first; + VERIFY_EXPR(Iter->second == Attribs.BindPoint); + } + } + } + }; + ExtractResources(pResourceLayouts); + ExtractResources(pStaticLayouts); + + for (size_t i = 0; i < RootSig.GetImmutableSamplerCount(); ++i) + { + const auto& ImtblSmplr = RootSig.GetImmutableSamplers()[i]; + const Uint32 ShaderIdx = GetShaderTypePipelineIndex(ImtblSmplr.ShaderType, PIPELINE_TYPE_RAY_TRACING); + const Int8 LayoutIdx = ResourceLayoutIndex[ShaderIdx]; + if (LayoutIdx < 0) + continue; + + VERIFY_EXPR(ImtblSmplr.Name.length() > 0); + if (ImtblSmplr.Name.empty()) + continue; + + auto& BindingMap = BindingMapPerStage[ShaderIdx]; + BindingMap.emplace(HashMapStringKey{ImtblSmplr.Name.c_str()}, ImtblSmplr.ShaderRegister); + } +} + +} // namespace + + +PipelineStateD3D12Impl::ShaderStageInfo::ShaderStageInfo(SHADER_TYPE _Type, ShaderD3D12Impl* _pShader) : + Type{_Type}, + Shaders{_pShader} +{ +} + +void PipelineStateD3D12Impl::ShaderStageInfo::Append(ShaderD3D12Impl* pShader) +{ + Shaders.push_back(pShader); +} + +size_t PipelineStateD3D12Impl::ShaderStageInfo::Count() const +{ + return Shaders.size(); +} + + +template <typename PSOCreateInfoType, typename InitPSODescType> +void PipelineStateD3D12Impl::InitInternalObjects(const PSOCreateInfoType& CreateInfo, + RootSignatureBuilder& RootSigBuilder, + TShaderStages& ShaderStages, + LocalRootSignature* pLocalRoot, + InitPSODescType InitPSODesc) { m_ResourceLayoutIndex.fill(-1); ExtractShaders<ShaderD3D12Impl>(CreateInfo, ShaderStages); - LinearAllocator MemPool{GetRawAllocator()}; + FixedLinearAllocator MemPool{GetRawAllocator()}; const auto NumShaderStages = GetNumShaderStages(); VERIFY_EXPR(NumShaderStages > 0 && NumShaderStages == ShaderStages.size()); @@ -132,14 +395,14 @@ void PipelineStateD3D12Impl::InitInternalObjects(const PSOCreateInfoType& for (Uint32 s = 0; s < NumShaderStages; ++s) new (m_pStaticVarManagers + s) ShaderVariableManagerD3D12{*this, GetStaticShaderResCache(s)}; - InitializePipelineDesc(CreateInfo, MemPool); + InitPSODesc(CreateInfo, MemPool); - m_RootSig.AllocateImmutableSamplers(CreateInfo.PSODesc.ResourceLayout); + RootSigBuilder.AllocateImmutableSamplers(CreateInfo.PSODesc.ResourceLayout); // It is important to construct all objects before initializing them because if an exception is thrown, // destructors will be called for all objects - InitResourceLayouts(CreateInfo, ShaderStages); + InitResourceLayouts(CreateInfo, RootSigBuilder, ShaderStages, pLocalRoot); } @@ -151,9 +414,14 @@ PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* { try { - std::vector<D3D12PipelineShaderStageInfo> ShaderStages; - - InitInternalObjects(CreateInfo, ShaderStages); + RootSignatureBuilder RootSigBuilder{m_RootSig}; + TShaderStages ShaderStages; + InitInternalObjects(CreateInfo, RootSigBuilder, ShaderStages, nullptr, + [this](const GraphicsPipelineStateCreateInfo& CreateInfo, FixedLinearAllocator& MemPool) // + { + InitializePipelineDesc(CreateInfo, MemPool); + } // + ); auto pd3d12Device = pDeviceD3D12->GetD3D12Device(); if (m_Desc.PipelineType == PIPELINE_TYPE_GRAPHICS) @@ -164,19 +432,20 @@ PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* for (const auto& Stage : ShaderStages) { - auto* pShaderD3D12 = Stage.pShader; + VERIFY_EXPR(Stage.Shaders.size() == 1); + auto* pShaderD3D12 = Stage.Shaders[0]; auto ShaderType = pShaderD3D12->GetDesc().ShaderType; VERIFY_EXPR(ShaderType == Stage.Type); D3D12_SHADER_BYTECODE* pd3d12ShaderBytecode = nullptr; switch (ShaderType) { - // clang-format off - case SHADER_TYPE_VERTEX: pd3d12ShaderBytecode = &d3d12PSODesc.VS; break; - case SHADER_TYPE_PIXEL: pd3d12ShaderBytecode = &d3d12PSODesc.PS; break; - case SHADER_TYPE_GEOMETRY: pd3d12ShaderBytecode = &d3d12PSODesc.GS; break; - case SHADER_TYPE_HULL: pd3d12ShaderBytecode = &d3d12PSODesc.HS; break; - case SHADER_TYPE_DOMAIN: pd3d12ShaderBytecode = &d3d12PSODesc.DS; break; + // clang-format off + case SHADER_TYPE_VERTEX: pd3d12ShaderBytecode = &d3d12PSODesc.VS; break; + case SHADER_TYPE_PIXEL: pd3d12ShaderBytecode = &d3d12PSODesc.PS; break; + case SHADER_TYPE_GEOMETRY: pd3d12ShaderBytecode = &d3d12PSODesc.GS; break; + case SHADER_TYPE_HULL: pd3d12ShaderBytecode = &d3d12PSODesc.HS; break; + case SHADER_TYPE_DOMAIN: pd3d12ShaderBytecode = &d3d12PSODesc.DS; break; // clang-format on default: UNEXPECTED("Unexpected shader type"); } @@ -237,7 +506,7 @@ PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* // The only valid bit is D3D12_PIPELINE_STATE_FLAG_TOOL_DEBUG, which can only be set on WARP devices. d3d12PSODesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE; - HRESULT hr = pd3d12Device->CreateGraphicsPipelineState(&d3d12PSODesc, __uuidof(ID3D12PipelineState), reinterpret_cast<void**>(static_cast<ID3D12PipelineState**>(&m_pd3d12PSO))); + HRESULT hr = pd3d12Device->CreateGraphicsPipelineState(&d3d12PSODesc, IID_PPV_ARGS(&m_pd3d12PSO)); if (FAILED(hr)) LOG_ERROR_AND_THROW("Failed to create pipeline state"); } @@ -268,17 +537,18 @@ PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* for (const auto& Stage : ShaderStages) { - auto* pShaderD3D12 = Stage.pShader; + VERIFY_EXPR(Stage.Shaders.size() == 1); + auto* pShaderD3D12 = Stage.Shaders[0]; auto ShaderType = pShaderD3D12->GetDesc().ShaderType; VERIFY_EXPR(ShaderType == Stage.Type); D3D12_SHADER_BYTECODE* pd3d12ShaderBytecode = nullptr; switch (ShaderType) { - // clang-format off - case SHADER_TYPE_AMPLIFICATION: pd3d12ShaderBytecode = &d3d12PSODesc.AS; break; - case SHADER_TYPE_MESH: pd3d12ShaderBytecode = &d3d12PSODesc.MS; break; - case SHADER_TYPE_PIXEL: pd3d12ShaderBytecode = &d3d12PSODesc.PS; break; + // clang-format off + case SHADER_TYPE_AMPLIFICATION: pd3d12ShaderBytecode = &d3d12PSODesc.AS; break; + case SHADER_TYPE_MESH: pd3d12ShaderBytecode = &d3d12PSODesc.MS; break; + case SHADER_TYPE_PIXEL: pd3d12ShaderBytecode = &d3d12PSODesc.PS; break; // clang-format on default: UNEXPECTED("Unexpected shader type"); } @@ -321,9 +591,10 @@ PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* streamDesc.SizeInBytes = sizeof(d3d12PSODesc); streamDesc.pPipelineStateSubobjectStream = &d3d12PSODesc; - auto* device2 = pDeviceD3D12->GetD3D12Device2(); - - CHECK_D3D_RESULT_THROW(device2->CreatePipelineState(&streamDesc, IID_PPV_ARGS(&m_pd3d12PSO)), "Failed to create pipeline state"); + auto* device2 = pDeviceD3D12->GetD3D12Device2(); + HRESULT hr = device2->CreatePipelineState(&streamDesc, IID_PPV_ARGS(&m_pd3d12PSO)); + if (FAILED(hr)) + LOG_ERROR_AND_THROW("Failed to create pipeline state"); } #endif // D3D12_H_HAS_MESH_SHADER else @@ -355,16 +626,22 @@ PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* { try { - std::vector<D3D12PipelineShaderStageInfo> ShaderStages; - - InitInternalObjects(CreateInfo, ShaderStages); + RootSignatureBuilder RootSigBuilder{m_RootSig}; + TShaderStages ShaderStages; + InitInternalObjects(CreateInfo, RootSigBuilder, ShaderStages, nullptr, + [this](const ComputePipelineStateCreateInfo& CreateInfo, FixedLinearAllocator& MemPool) // + { + InitializePipelineDesc(CreateInfo, MemPool); + } // + ); auto pd3d12Device = pDeviceD3D12->GetD3D12Device(); D3D12_COMPUTE_PIPELINE_STATE_DESC d3d12PSODesc = {}; VERIFY_EXPR(ShaderStages[0].Type == SHADER_TYPE_COMPUTE); - auto* pByteCode = ShaderStages[0].pShader->GetShaderByteCode(); + VERIFY_EXPR(ShaderStages[0].Shaders.size() == 1); + auto* pByteCode = ShaderStages[0].Shaders[0]->GetShaderByteCode(); d3d12PSODesc.CS.pShaderBytecode = pByteCode->GetBufferPointer(); d3d12PSODesc.CS.BytecodeLength = pByteCode->GetBufferSize(); @@ -381,7 +658,7 @@ PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* d3d12PSODesc.pRootSignature = m_RootSig.GetD3D12RootSignature(); - HRESULT hr = pd3d12Device->CreateComputePipelineState(&d3d12PSODesc, __uuidof(ID3D12PipelineState), reinterpret_cast<void**>(static_cast<ID3D12PipelineState**>(&m_pd3d12PSO))); + HRESULT hr = pd3d12Device->CreateComputePipelineState(&d3d12PSODesc, IID_PPV_ARGS(&m_pd3d12PSO)); if (FAILED(hr)) LOG_ERROR_AND_THROW("Failed to create pipeline state"); @@ -401,6 +678,69 @@ PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* } } +PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* pRefCounters, + RenderDeviceD3D12Impl* pDeviceD3D12, + const RayTracingPipelineStateCreateInfo& CreateInfo) : + TPipelineStateBase{pRefCounters, pDeviceD3D12, CreateInfo}, + m_SRBMemAllocator{GetRawAllocator()} +{ + try + { + LocalRootSignature LocalRootSig{CreateInfo.pShaderRecordName, CreateInfo.RayTracingPipeline.ShaderRecordSize}; + TShaderStages ShaderStages; + DynamicLinearAllocator TempPool{GetRawAllocator(), 4 << 10}; + RootSignatureBuilder RootSigBuilder{m_RootSig}; + + InitInternalObjects(CreateInfo, RootSigBuilder, ShaderStages, &LocalRootSig, + [&](const RayTracingPipelineStateCreateInfo& CreateInfo, FixedLinearAllocator& MemPool) // + { + InitializePipelineDesc(CreateInfo, MemPool); + } // + ); + + auto pd3d12Device = pDeviceD3D12->GetD3D12Device5(); + + TBindingMapPerStage BindingMapPerStage; + ExtractResourceBindingMap(RootSigBuilder, m_ResourceLayoutIndex, &m_pShaderResourceLayouts[0], &m_pShaderResourceLayouts[GetNumShaderStages()], BindingMapPerStage); + + std::vector<D3D12_STATE_SUBOBJECT> Subobjects; + std::vector<CComPtr<IDxcBlob>> ShaderBlobs; + BuildRTPipelineDescription(CreateInfo, Subobjects, ShaderBlobs, TempPool, pDeviceD3D12->GetDxCompiler(), BindingMapPerStage); + + D3D12_GLOBAL_ROOT_SIGNATURE GlobalRoot = {m_RootSig.GetD3D12RootSignature()}; + Subobjects.push_back({D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE, &GlobalRoot}); + + D3D12_LOCAL_ROOT_SIGNATURE LocalRoot = {LocalRootSig.Create(pd3d12Device)}; + if (LocalRoot.pLocalRootSignature) + Subobjects.push_back({D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE, &LocalRoot}); + + D3D12_STATE_OBJECT_DESC RTPipelineDesc = {}; + RTPipelineDesc.Type = D3D12_STATE_OBJECT_TYPE_RAYTRACING_PIPELINE; + RTPipelineDesc.NumSubobjects = static_cast<UINT>(Subobjects.size()); + RTPipelineDesc.pSubobjects = Subobjects.data(); + + HRESULT hr = pd3d12Device->CreateStateObject(&RTPipelineDesc, IID_PPV_ARGS(&m_pd3d12PSO)); + if (FAILED(hr)) + LOG_ERROR_AND_THROW("Failed to create ray tracing state object"); + + GetShaderIdentifiers(m_pd3d12PSO, CreateInfo, m_pRayTracingPipelineData->NameToGroupIndex, m_pRayTracingPipelineData->Shaders); + + if (*m_Desc.Name != 0) + { + m_pd3d12PSO->SetName(WidenString(m_Desc.Name).c_str()); + String RootSignatureDesc("Root signature for PSO '"); + RootSignatureDesc.append(m_Desc.Name); + RootSignatureDesc.push_back('\''); + m_RootSig.GetD3D12RootSignature()->SetName(WidenString(RootSignatureDesc).c_str()); + } + } + catch (...) + { + Destruct(); + throw; + } +} + PipelineStateD3D12Impl::~PipelineStateD3D12Impl() { Destruct(); @@ -408,6 +748,8 @@ PipelineStateD3D12Impl::~PipelineStateD3D12Impl() void PipelineStateD3D12Impl::Destruct() { + TPipelineStateBase::Destruct(); + auto& ShaderResLayoutAllocator = GetRawAllocator(); for (Uint32 s = 0; s < GetNumShaderStages(); ++s) { @@ -443,22 +785,25 @@ void PipelineStateD3D12Impl::Destruct() IMPLEMENT_QUERY_INTERFACE(PipelineStateD3D12Impl, IID_PipelineStateD3D12, TPipelineStateBase) - -void PipelineStateD3D12Impl::InitResourceLayouts(const PipelineStateCreateInfo& CreateInfo, - std::vector<D3D12PipelineShaderStageInfo>& ShaderStages) +void PipelineStateD3D12Impl::InitResourceLayouts(const PipelineStateCreateInfo& CreateInfo, + RootSignatureBuilder& RootSigBuilder, + TShaderStages& ShaderStages, + LocalRootSignature* pLocalRoot) { auto pd3d12Device = GetDevice()->GetD3D12Device(); const auto& ResourceLayout = m_Desc.ResourceLayout; #ifdef DILIGENT_DEVELOPMENT { - const ShaderResources* pResources[MAX_SHADERS_IN_PIPELINE] = {}; + std::vector<const ShaderResources*> Resources; for (size_t s = 0; s < ShaderStages.size(); ++s) { - const auto* pShader = ShaderStages[s].pShader; - pResources[s] = &(*pShader->GetShaderResources()); + for (auto* pShader : ShaderStages[s].Shaders) + { + Resources.push_back(&(*pShader->GetShaderResources())); + } } - ShaderResources::DvpVerifyResourceLayout(ResourceLayout, pResources, GetNumShaderStages(), + ShaderResources::DvpVerifyResourceLayout(ResourceLayout, Resources.data(), static_cast<Uint32>(Resources.size()), (CreateInfo.Flags & PSO_CREATE_FLAG_IGNORE_MISSING_VARIABLES) == 0, (CreateInfo.Flags & PSO_CREATE_FLAG_IGNORE_MISSING_IMMUTABLE_SAMPLERS) == 0); } @@ -466,9 +811,9 @@ void PipelineStateD3D12Impl::InitResourceLayouts(const PipelineStateCreateInfo& for (size_t s = 0; s < ShaderStages.size(); ++s) { - auto* pShaderD3D12 = ShaderStages[s].pShader; - auto ShaderType = pShaderD3D12->GetDesc().ShaderType; - auto ShaderInd = GetShaderTypePipelineIndex(ShaderType, m_Desc.PipelineType); + auto Shaders = ShaderStages[s].Shaders; + auto ShaderType = ShaderStages[s].Type; + auto ShaderInd = GetShaderTypePipelineIndex(ShaderType, m_Desc.PipelineType); m_ResourceLayoutIndex[ShaderInd] = static_cast<Int8>(s); @@ -476,12 +821,13 @@ void PipelineStateD3D12Impl::InitResourceLayouts(const PipelineStateCreateInfo& pd3d12Device, m_Desc.PipelineType, ResourceLayout, - pShaderD3D12->GetShaderResources(), + Shaders, GetRawAllocator(), nullptr, 0, nullptr, - &m_RootSig // + &RootSigBuilder, + pLocalRoot // ); const SHADER_RESOURCE_VARIABLE_TYPE StaticVarType[] = {SHADER_RESOURCE_VARIABLE_TYPE_STATIC}; @@ -489,12 +835,13 @@ void PipelineStateD3D12Impl::InitResourceLayouts(const PipelineStateCreateInfo& pd3d12Device, m_Desc.PipelineType, ResourceLayout, - pShaderD3D12->GetShaderResources(), + Shaders, GetRawAllocator(), StaticVarType, _countof(StaticVarType), m_pStaticResourceCaches + s, - nullptr // + nullptr, + pLocalRoot // ); m_pStaticVarManagers[s].Initialize( @@ -504,7 +851,7 @@ void PipelineStateD3D12Impl::InitResourceLayouts(const PipelineStateCreateInfo& 0 // ); } - m_RootSig.Finalize(pd3d12Device); + RootSigBuilder.Finalize(pd3d12Device); if (m_Desc.SRBAllocationGranularity > 1) { @@ -521,11 +868,11 @@ void PipelineStateD3D12Impl::InitResourceLayouts(const PipelineStateCreateInfo& ShaderVarMgrDataSizes[s] = ShaderVariableManagerD3D12::GetRequiredMemorySize(m_pShaderResourceLayouts[s], AllowedVarTypes.data(), static_cast<Uint32>(AllowedVarTypes.size()), NumVariablesUnused); } - auto CacheMemorySize = m_RootSig.GetResourceCacheRequiredMemSize(); + auto CacheMemorySize = RootSigBuilder.GetResourceCacheRequiredMemSize(); m_SRBMemAllocator.Initialize(m_Desc.SRBAllocationGranularity, GetNumShaderStages(), ShaderVarMgrDataSizes.data(), 1, &CacheMemorySize); } - m_ShaderResourceLayoutHash = m_RootSig.GetHash(); + m_ShaderResourceLayoutHash = RootSigBuilder.GetHash(); } void PipelineStateD3D12Impl::CreateShaderResourceBinding(IShaderResourceBinding** ppShaderResourceBinding, bool InitStaticResources) @@ -566,8 +913,8 @@ bool PipelineStateD3D12Impl::IsCompatibleWith(const IPipelineState* pPSO) const break; } - const auto& Res0 = GetShaderResLayout(s).GetResources(); - const auto& Res1 = pPSOD3D12->GetShaderResLayout(s).GetResources(); + const auto& Res0 = GetShaderResLayout(s); + const auto& Res1 = pPSOD3D12->GetShaderResLayout(s); if (!Res0.IsCompatibleWith(Res1)) { IsCompatibleShaders = false; @@ -601,10 +948,10 @@ ShaderResourceCacheD3D12* PipelineStateD3D12Impl::CommitAndTransitionShaderResou { if (Attrib.CommitResources) { - if (m_Desc.IsComputePipeline()) - CmdCtx.AsComputeContext().SetRootSignature(GetD3D12RootSignature()); + if (m_Desc.IsAnyGraphicsPipeline()) + CmdCtx.AsGraphicsContext().SetGraphicsRootSignature(GetD3D12RootSignature()); else - CmdCtx.AsGraphicsContext().SetRootSignature(GetD3D12RootSignature()); + CmdCtx.AsComputeContext().SetComputeRootSignature(GetD3D12RootSignature()); } return nullptr; } @@ -630,18 +977,18 @@ ShaderResourceCacheD3D12* PipelineStateD3D12Impl::CommitAndTransitionShaderResou auto& ResourceCache = pResBindingD3D12Impl->GetResourceCache(); if (Attrib.CommitResources) { - if (m_Desc.IsComputePipeline()) - CmdCtx.AsComputeContext().SetRootSignature(GetD3D12RootSignature()); + if (m_Desc.IsAnyGraphicsPipeline()) + CmdCtx.AsGraphicsContext().SetGraphicsRootSignature(GetD3D12RootSignature()); else - CmdCtx.AsGraphicsContext().SetRootSignature(GetD3D12RootSignature()); + CmdCtx.AsComputeContext().SetComputeRootSignature(GetD3D12RootSignature()); if (Attrib.TransitionResources) { - (m_RootSig.*m_RootSig.TransitionAndCommitDescriptorHandles)(m_pDevice, ResourceCache, CmdCtx, m_Desc.IsComputePipeline(), Attrib.ValidateStates); + (m_RootSig.*m_RootSig.TransitionAndCommitDescriptorHandles)(m_pDevice, ResourceCache, CmdCtx, !m_Desc.IsAnyGraphicsPipeline(), Attrib.ValidateStates); } else { - (m_RootSig.*m_RootSig.CommitDescriptorHandles)(m_pDevice, ResourceCache, CmdCtx, m_Desc.IsComputePipeline(), Attrib.ValidateStates); + (m_RootSig.*m_RootSig.CommitDescriptorHandles)(m_pDevice, ResourceCache, CmdCtx, !m_Desc.IsAnyGraphicsPipeline(), Attrib.ValidateStates); } } else @@ -653,7 +1000,7 @@ ShaderResourceCacheD3D12* PipelineStateD3D12Impl::CommitAndTransitionShaderResou // Process only non-dynamic buffers at this point. Dynamic buffers will be handled by the Draw/Dispatch command. m_RootSig.CommitRootViews(ResourceCache, CmdCtx, - m_Desc.IsComputePipeline(), + !m_Desc.IsAnyGraphicsPipeline(), Attrib.CtxId, pDeviceCtx, Attrib.CommitResources, // CommitViews diff --git a/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp index 377eb5a7..56588dee 100644 --- a/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp @@ -40,6 +40,9 @@ #include "QueryD3D12Impl.hpp" #include "RenderPassD3D12Impl.hpp" #include "FramebufferD3D12Impl.hpp" +#include "BottomLevelASD3D12Impl.hpp" +#include "TopLevelASD3D12Impl.hpp" +#include "ShaderBindingTableD3D12Impl.hpp" #include "EngineMemory.h" namespace Diligent @@ -65,12 +68,8 @@ static CComPtr<IDXGIAdapter1> DXGIAdapterFromD3D12Device(ID3D12Device* pd3d12Dev return nullptr; } -ShaderVersion RenderDeviceD3D12Impl::GetMaxShaderModel() const -{ - return ShaderVersion{static_cast<Uint8>((m_MaxShaderModel >> 4) & 0xF), static_cast<Uint8>(m_MaxShaderModel & 0xF)}; -} -D3D_FEATURE_LEVEL RenderDeviceD3D12Impl::GetD3DFeatureLevel() const +static D3D_FEATURE_LEVEL GetD3DFeatureLevel(ID3D12Device* pd3d12Device) { D3D_FEATURE_LEVEL FeatureLevels[] = { @@ -85,11 +84,10 @@ D3D_FEATURE_LEVEL RenderDeviceD3D12Impl::GetD3DFeatureLevel() const FeatureLevelsData.pFeatureLevelsRequested = FeatureLevels; FeatureLevelsData.NumFeatureLevels = _countof(FeatureLevels); - m_pd3d12Device->CheckFeatureSupport(D3D12_FEATURE_FEATURE_LEVELS, &FeatureLevelsData, sizeof(FeatureLevelsData)); + pd3d12Device->CheckFeatureSupport(D3D12_FEATURE_FEATURE_LEVELS, &FeatureLevelsData, sizeof(FeatureLevelsData)); return FeatureLevelsData.MaxSupportedFeatureLevel; } -#ifdef D3D12_H_HAS_MESH_SHADER ID3D12Device2* RenderDeviceD3D12Impl::GetD3D12Device2() { if (!m_pd3d12Device2) @@ -98,7 +96,15 @@ ID3D12Device2* RenderDeviceD3D12Impl::GetD3D12Device2() } return m_pd3d12Device2; } -#endif + +ID3D12Device5* RenderDeviceD3D12Impl::GetD3D12Device5() +{ + if (!m_pd3d12Device5) + { + CHECK_D3D_RESULT_THROW(m_pd3d12Device->QueryInterface(IID_PPV_ARGS(&m_pd3d12Device5)), "Failed to get ID3D12Device5"); + } + return m_pd3d12Device5; +} RenderDeviceD3D12Impl::RenderDeviceD3D12Impl(IReferenceCounters* pRefCounters, IMemoryAllocator& RawMemAllocator, @@ -129,7 +135,10 @@ RenderDeviceD3D12Impl::RenderDeviceD3D12Impl(IReferenceCounters* pRefCo sizeof(FenceD3D12Impl), sizeof(QueryD3D12Impl), sizeof(RenderPassD3D12Impl), - sizeof(FramebufferD3D12Impl) + sizeof(FramebufferD3D12Impl), + sizeof(BottomLevelASD3D12Impl), + sizeof(TopLevelASD3D12Impl), + sizeof(ShaderBindingTableD3D12Impl) } }, m_pd3d12Device {pd3d12Device}, @@ -154,10 +163,18 @@ RenderDeviceD3D12Impl::RenderDeviceD3D12Impl(IReferenceCounters* pRefCo m_pDxCompiler {CreateDXCompiler(DXCompilerTarget::Direct3D12, EngineCI.pDxCompilerPath)} // clang-format on { + static_assert(sizeof(DeviceObjectSizes) == sizeof(size_t) * 15, "Please add new objects to DeviceObjectSizes constructor"); + + // set device properties + { + static_assert(sizeof(DeviceProperties) == sizeof(Uint32) * 1, "Please set new properties below"); + m_DeviceProperties.MaxRayTracingRecursionDepth = D3D12_RAYTRACING_MAX_DECLARABLE_TRACE_RECURSION_DEPTH; + } + try { m_DeviceCaps.DevType = RENDER_DEVICE_TYPE_D3D12; - auto FeatureLevel = GetD3DFeatureLevel(); + auto FeatureLevel = GetD3DFeatureLevel(m_pd3d12Device); switch (FeatureLevel) { case D3D_FEATURE_LEVEL_12_0: @@ -195,17 +212,18 @@ RenderDeviceD3D12Impl::RenderDeviceD3D12Impl(IReferenceCounters* pRefCo m_DeviceCaps.Features.VertexPipelineUAVWritesAndAtomics = DEVICE_FEATURE_STATE_ENABLED; // Detect maximum shader model. + D3D_SHADER_MODEL MaxShaderModel = D3D_SHADER_MODEL_5_1; { // Direct3D12 supports shader model 5.1 on all feature levels. // https://docs.microsoft.com/en-us/windows/win32/direct3d12/hardware-feature-levels#feature-level-support - m_MaxShaderModel = D3D_SHADER_MODEL_5_1; + MaxShaderModel = D3D_SHADER_MODEL_5_1; // Header may not have constants for D3D_SHADER_MODEL_6_1 and above. const D3D_SHADER_MODEL Models[] = // { - static_cast<D3D_SHADER_MODEL>(0x65), // minimum required for mesh shader + static_cast<D3D_SHADER_MODEL>(0x65), // minimum required for mesh shader and DXR 1.1 static_cast<D3D_SHADER_MODEL>(0x64), - static_cast<D3D_SHADER_MODEL>(0x63), + static_cast<D3D_SHADER_MODEL>(0x63), // minimum required for DXR 1.0 static_cast<D3D_SHADER_MODEL>(0x62), static_cast<D3D_SHADER_MODEL>(0x61), D3D_SHADER_MODEL_6_0 // @@ -216,13 +234,16 @@ RenderDeviceD3D12Impl::RenderDeviceD3D12Impl(IReferenceCounters* pRefCo D3D12_FEATURE_DATA_SHADER_MODEL ShaderModel = {Model}; if (SUCCEEDED(m_pd3d12Device->CheckFeatureSupport(D3D12_FEATURE_SHADER_MODEL, &ShaderModel, sizeof(ShaderModel)))) { - m_MaxShaderModel = ShaderModel.HighestShaderModel; + MaxShaderModel = ShaderModel.HighestShaderModel; break; } } - LOG_INFO_MESSAGE("Max device shader model: ", (m_MaxShaderModel >> 4) & 0xF, '_', m_MaxShaderModel & 0xF); + LOG_INFO_MESSAGE("Max device shader model: ", (MaxShaderModel >> 4) & 0xF, '_', MaxShaderModel & 0xF); } + m_Properties.MaxShaderVersion.Major = static_cast<Uint8>((MaxShaderModel >> 4) & 0xF); + m_Properties.MaxShaderVersion.Minor = static_cast<Uint8>(MaxShaderModel & 0xF); + // Check if mesh shader is supported. bool MeshShadersSupported = false; #ifdef D3D12_H_HAS_MESH_SHADER @@ -233,7 +254,7 @@ RenderDeviceD3D12Impl::RenderDeviceD3D12Impl(IReferenceCounters* pRefCo SUCCEEDED(m_pd3d12Device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS7, &FeatureData, sizeof(FeatureData))) && FeatureData.MeshShaderTier != D3D12_MESH_SHADER_TIER_NOT_SUPPORTED; - MeshShadersSupported = (m_MaxShaderModel >= D3D_SHADER_MODEL_6_5 && MeshShadersSupported); + MeshShadersSupported = (MaxShaderModel >= D3D_SHADER_MODEL_6_5 && MeshShadersSupported); } #else if (EngineCI.Features.MeshShaders == DEVICE_FEATURE_STATE_ENABLED) @@ -251,6 +272,16 @@ RenderDeviceD3D12Impl::RenderDeviceD3D12Impl(IReferenceCounters* pRefCo m_DeviceCaps.Features.MeshShaders = MeshShadersSupported ? DEVICE_FEATURE_STATE_ENABLED : DEVICE_FEATURE_STATE_DISABLED; + { + D3D12_FEATURE_DATA_D3D12_OPTIONS5 d3d12Features = {}; + if (SUCCEEDED(m_pd3d12Device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS5, &d3d12Features, sizeof(d3d12Features)))) + { + if (d3d12Features.RaytracingTier >= D3D12_RAYTRACING_TIER_1_0) + { + m_DeviceCaps.Features.RayTracing = DEVICE_FEATURE_STATE_ENABLED; + } + } + } { D3D12_FEATURE_DATA_D3D12_OPTIONS d3d12Features = {}; @@ -293,11 +324,13 @@ RenderDeviceD3D12Impl::RenderDeviceD3D12Impl(IReferenceCounters* pRefCo CHECK_REQUIRED_FEATURE(ShaderInt8, "8-bit shader operations are"); CHECK_REQUIRED_FEATURE(ResourceBuffer8BitAccess, "8-bit resoure buffer access is"); CHECK_REQUIRED_FEATURE(UniformBuffer8BitAccess, "8-bit uniform buffer access is"); + + CHECK_REQUIRED_FEATURE(RayTracing, "ray tracing is"); // clang-format on #undef CHECK_REQUIRED_FEATURE #if defined(_MSC_VER) && defined(_WIN64) - static_assert(sizeof(DeviceFeatures) == 31, "Did you add a new feature to DeviceFeatures? Please handle its satus here."); + static_assert(sizeof(DeviceFeatures) == 32, "Did you add a new feature to DeviceFeatures? Please handle its satus here."); #endif auto& TexCaps = m_DeviceCaps.TexCaps; @@ -557,6 +590,11 @@ void RenderDeviceD3D12Impl::CreateComputePipelineState(const ComputePipelineStat CreatePipelineState(PSOCreateInfo, ppPipelineState); } +void RenderDeviceD3D12Impl::CreateRayTracingPipelineState(const RayTracingPipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState) +{ + CreatePipelineState(PSOCreateInfo, ppPipelineState); +} + void RenderDeviceD3D12Impl::CreateBufferFromD3DResource(ID3D12Resource* pd3d12Buffer, const BufferDesc& BuffDesc, RESOURCE_STATE InitialState, IBuffer** ppBuffer) { CreateDeviceObject("buffer", BuffDesc, ppBuffer, @@ -692,6 +730,70 @@ void RenderDeviceD3D12Impl::CreateFramebuffer(const FramebufferDesc& Desc, IFram }); } +void RenderDeviceD3D12Impl::CreateBLASFromD3DResource(ID3D12Resource* pd3d12BLAS, + const BottomLevelASDesc& Desc, + RESOURCE_STATE InitialState, + IBottomLevelAS** ppBLAS) +{ + CreateDeviceObject("buffer", Desc, ppBLAS, + [&]() // + { + BottomLevelASD3D12Impl* pBottomLevelASD3D12{NEW_RC_OBJ(m_BLASAllocator, "BottomLevelASD3D12Impl instance", BottomLevelASD3D12Impl)(this, Desc, InitialState, pd3d12BLAS)}; + pBottomLevelASD3D12->QueryInterface(IID_BottomLevelAS, reinterpret_cast<IObject**>(ppBLAS)); + OnCreateDeviceObject(pBottomLevelASD3D12); + }); +} + +void RenderDeviceD3D12Impl::CreateBLAS(const BottomLevelASDesc& Desc, + IBottomLevelAS** ppBLAS) +{ + CreateDeviceObject("BottomLevelAS", Desc, ppBLAS, + [&]() // + { + BottomLevelASD3D12Impl* pBottomLevelASD3D12(NEW_RC_OBJ(m_BLASAllocator, "BottomLevelASD3D12Impl instance", BottomLevelASD3D12Impl)(this, Desc)); + pBottomLevelASD3D12->QueryInterface(IID_BottomLevelAS, reinterpret_cast<IObject**>(ppBLAS)); + OnCreateDeviceObject(pBottomLevelASD3D12); + }); +} + +void RenderDeviceD3D12Impl::CreateTLASFromD3DResource(ID3D12Resource* pd3d12TLAS, + const TopLevelASDesc& Desc, + RESOURCE_STATE InitialState, + ITopLevelAS** ppTLAS) +{ + CreateDeviceObject("TopLevelAS", Desc, ppTLAS, + [&]() // + { + TopLevelASD3D12Impl* pTopLevelASD3D12{NEW_RC_OBJ(m_TLASAllocator, "TopLevelASD3D12Impl instance", TopLevelASD3D12Impl)(this, Desc, InitialState, pd3d12TLAS)}; + pTopLevelASD3D12->QueryInterface(IID_TopLevelAS, reinterpret_cast<IObject**>(ppTLAS)); + OnCreateDeviceObject(pTopLevelASD3D12); + }); +} + +void RenderDeviceD3D12Impl::CreateTLAS(const TopLevelASDesc& Desc, + ITopLevelAS** ppTLAS) +{ + CreateDeviceObject("TopLevelAS", Desc, ppTLAS, + [&]() // + { + TopLevelASD3D12Impl* pTopLevelASD3D12(NEW_RC_OBJ(m_TLASAllocator, "TopLevelASD3D12Impl instance", TopLevelASD3D12Impl)(this, Desc)); + pTopLevelASD3D12->QueryInterface(IID_TopLevelAS, reinterpret_cast<IObject**>(ppTLAS)); + OnCreateDeviceObject(pTopLevelASD3D12); + }); +} + +void RenderDeviceD3D12Impl::CreateSBT(const ShaderBindingTableDesc& Desc, + IShaderBindingTable** ppSBT) +{ + CreateDeviceObject("ShaderBindingTable", Desc, ppSBT, + [&]() // + { + ShaderBindingTableD3D12Impl* pSBTD3D12(NEW_RC_OBJ(m_SBTAllocator, "ShaderBindingTableD3D12Impl instance", ShaderBindingTableD3D12Impl)(this, Desc)); + pSBTD3D12->QueryInterface(IID_ShaderBindingTable, reinterpret_cast<IObject**>(ppSBT)); + OnCreateDeviceObject(pSBTD3D12); + }); +} + DescriptorHeapAllocation RenderDeviceD3D12Impl::AllocateDescriptor(D3D12_DESCRIPTOR_HEAP_TYPE Type, UINT Count /*= 1*/) { VERIFY(Type >= D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV && Type < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES, "Invalid heap type"); diff --git a/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp b/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp index 2afb9eb1..ab997d1d 100644 --- a/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp +++ b/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp @@ -33,11 +33,13 @@ #include "CommandContext.hpp" #include "RenderDeviceD3D12Impl.hpp" #include "TextureD3D12Impl.hpp" +#include "TopLevelASD3D12Impl.hpp" #include "D3D12TypeConversions.hpp" #include "HashUtils.hpp" namespace Diligent { +static constexpr auto RayTracingMask = SHADER_TYPE_RAY_GEN | SHADER_TYPE_RAY_MISS | SHADER_TYPE_RAY_CLOSEST_HIT | SHADER_TYPE_RAY_ANY_HIT | SHADER_TYPE_RAY_INTERSECTION | SHADER_TYPE_CALLABLE; RootSignature::RootParamsManager::RootParamsManager(IMemoryAllocator& MemAllocator) : m_MemAllocator{MemAllocator}, @@ -163,131 +165,20 @@ size_t RootSignature::RootParamsManager::GetHash() const return hash; } -RootSignature::RootSignature() : - m_RootParams{GetRawAllocator()}, - m_MemAllocator{GetRawAllocator()}, - m_ImmutableSamplers(STD_ALLOCATOR_RAW_MEM(ImmutableSamplerAttribs, GetRawAllocator(), "Allocator for vector<ImmutableSamplerAttribs>")) -{ - m_SrvCbvUavRootTablesMap.fill(InvalidRootTableIndex); - m_SamplerRootTablesMap.fill(InvalidRootTableIndex); -} - -// clang-format off -static constexpr D3D12_SHADER_VISIBILITY ShaderTypeInd2ShaderVisibilityMap[] -{ - D3D12_SHADER_VISIBILITY_VERTEX, // 0 - D3D12_SHADER_VISIBILITY_PIXEL, // 1 - D3D12_SHADER_VISIBILITY_GEOMETRY, // 2 - D3D12_SHADER_VISIBILITY_HULL, // 3 - D3D12_SHADER_VISIBILITY_DOMAIN, // 4 - D3D12_SHADER_VISIBILITY_ALL, // 5 -#ifdef D3D12_H_HAS_MESH_SHADER - D3D12_SHADER_VISIBILITY_AMPLIFICATION, // 6 - D3D12_SHADER_VISIBILITY_MESH // 7 -#endif -}; -// clang-format on -D3D12_SHADER_VISIBILITY GetShaderVisibility(SHADER_TYPE ShaderType) -{ - auto ShaderInd = GetShaderTypeIndex(ShaderType); - auto ShaderVisibility = ShaderTypeInd2ShaderVisibilityMap[ShaderInd]; -#ifdef DILIGENT_DEBUG - switch (ShaderType) - { - // clang-format off - case SHADER_TYPE_VERTEX: VERIFY_EXPR(ShaderVisibility == D3D12_SHADER_VISIBILITY_VERTEX); break; - case SHADER_TYPE_PIXEL: VERIFY_EXPR(ShaderVisibility == D3D12_SHADER_VISIBILITY_PIXEL); break; - case SHADER_TYPE_GEOMETRY: VERIFY_EXPR(ShaderVisibility == D3D12_SHADER_VISIBILITY_GEOMETRY); break; - case SHADER_TYPE_HULL: VERIFY_EXPR(ShaderVisibility == D3D12_SHADER_VISIBILITY_HULL); break; - case SHADER_TYPE_DOMAIN: VERIFY_EXPR(ShaderVisibility == D3D12_SHADER_VISIBILITY_DOMAIN); break; - case SHADER_TYPE_COMPUTE: VERIFY_EXPR(ShaderVisibility == D3D12_SHADER_VISIBILITY_ALL); break; -# ifdef D3D12_H_HAS_MESH_SHADER - case SHADER_TYPE_AMPLIFICATION: VERIFY_EXPR(ShaderVisibility == D3D12_SHADER_VISIBILITY_AMPLIFICATION); break; - case SHADER_TYPE_MESH: VERIFY_EXPR(ShaderVisibility == D3D12_SHADER_VISIBILITY_MESH); break; -# endif - // clang-format on - default: LOG_ERROR("Unknown shader type (", ShaderType, ")"); break; - } -#endif - return ShaderVisibility; -} - -// clang-format off -static SHADER_TYPE ShaderVisibility2ShaderTypeMap[] = -{ - SHADER_TYPE_COMPUTE, // D3D12_SHADER_VISIBILITY_ALL = 0 - SHADER_TYPE_VERTEX, // D3D12_SHADER_VISIBILITY_VERTEX = 1 - SHADER_TYPE_HULL, // D3D12_SHADER_VISIBILITY_HULL = 2 - SHADER_TYPE_DOMAIN, // D3D12_SHADER_VISIBILITY_DOMAIN = 3 - SHADER_TYPE_GEOMETRY, // D3D12_SHADER_VISIBILITY_GEOMETRY = 4 - SHADER_TYPE_PIXEL, // D3D12_SHADER_VISIBILITY_PIXEL = 5 - SHADER_TYPE_AMPLIFICATION, // D3D12_SHADER_VISIBILITY_AMPLIFICATION = 6 - SHADER_TYPE_MESH // D3D12_SHADER_VISIBILITY_MESH = 7 -}; -// clang-format on -SHADER_TYPE ShaderTypeFromShaderVisibility(D3D12_SHADER_VISIBILITY ShaderVisibility) -{ - VERIFY_EXPR(uint32_t(ShaderVisibility) < _countof(ShaderVisibility2ShaderTypeMap)); - auto ShaderType = ShaderVisibility2ShaderTypeMap[ShaderVisibility]; -#ifdef DILIGENT_DEBUG - switch (ShaderVisibility) - { - // clang-format off - case D3D12_SHADER_VISIBILITY_VERTEX: VERIFY_EXPR(ShaderType == SHADER_TYPE_VERTEX); break; - case D3D12_SHADER_VISIBILITY_PIXEL: VERIFY_EXPR(ShaderType == SHADER_TYPE_PIXEL); break; - case D3D12_SHADER_VISIBILITY_GEOMETRY: VERIFY_EXPR(ShaderType == SHADER_TYPE_GEOMETRY); break; - case D3D12_SHADER_VISIBILITY_HULL: VERIFY_EXPR(ShaderType == SHADER_TYPE_HULL); break; - case D3D12_SHADER_VISIBILITY_DOMAIN: VERIFY_EXPR(ShaderType == SHADER_TYPE_DOMAIN); break; - case D3D12_SHADER_VISIBILITY_ALL: VERIFY_EXPR(ShaderType == SHADER_TYPE_COMPUTE); break; -# ifdef D3D12_H_HAS_MESH_SHADER - case D3D12_SHADER_VISIBILITY_AMPLIFICATION: VERIFY_EXPR(ShaderType == SHADER_TYPE_AMPLIFICATION); break; - case D3D12_SHADER_VISIBILITY_MESH: VERIFY_EXPR(ShaderType == SHADER_TYPE_MESH); break; -# endif - // clang-format on - default: LOG_ERROR("Unknown shader visibility (", ShaderVisibility, ")"); break; - } -#endif - return ShaderType; -} - - -// clang-format off -static D3D12_DESCRIPTOR_HEAP_TYPE RangeType2HeapTypeMap[] -{ - D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, //D3D12_DESCRIPTOR_RANGE_TYPE_SRV = 0 - D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, //D3D12_DESCRIPTOR_RANGE_TYPE_UAV = ( D3D12_DESCRIPTOR_RANGE_TYPE_SRV + 1 ) - D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, //D3D12_DESCRIPTOR_RANGE_TYPE_CBV = ( D3D12_DESCRIPTOR_RANGE_TYPE_UAV + 1 ) - D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER //D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER = ( D3D12_DESCRIPTOR_RANGE_TYPE_CBV + 1 ) -}; -// clang-format on -D3D12_DESCRIPTOR_HEAP_TYPE HeapTypeFromRangeType(D3D12_DESCRIPTOR_RANGE_TYPE RangeType) +RootSignatureBuilder::RootSignatureBuilder(RootSignature& RootSig) : + m_RootSig{RootSig}, + m_ImmutableSamplers(STD_ALLOCATOR_RAW_MEM(ImmutableSamplerAttribs, GetRawAllocator(), "Allocator for vector<ImmutableSamplerAttribs>")) { - VERIFY_EXPR(RangeType >= D3D12_DESCRIPTOR_RANGE_TYPE_SRV && RangeType <= D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER); - auto HeapType = RangeType2HeapTypeMap[RangeType]; - -#ifdef DILIGENT_DEBUG - switch (RangeType) - { - // clang-format off - case D3D12_DESCRIPTOR_RANGE_TYPE_CBV: VERIFY_EXPR(HeapType == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); break; - case D3D12_DESCRIPTOR_RANGE_TYPE_SRV: VERIFY_EXPR(HeapType == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); break; - case D3D12_DESCRIPTOR_RANGE_TYPE_UAV: VERIFY_EXPR(HeapType == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); break; - case D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER: VERIFY_EXPR(HeapType == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); break; - // clang-format on - default: UNEXPECTED("Unexpected descriptor range type"); break; - } -#endif - return HeapType; } -void RootSignature::InitImmutableSampler(SHADER_TYPE ShaderType, - const char* SamplerName, - const char* SamplerSuffix, - const D3DShaderResourceAttribs& SamplerAttribs) +void RootSignatureBuilder::InitImmutableSampler(SHADER_TYPE ShaderType, + const char* SamplerName, + const char* SamplerSuffix, + const D3DShaderResourceAttribs& SamplerAttribs) { - auto ShaderVisibility = GetShaderVisibility(ShaderType); + auto ShaderVisibility = ShaderTypeToD3D12ShaderVisibility(ShaderType); auto SamplerFound = false; for (auto& ImtblSmplr : m_ImmutableSamplers) { @@ -297,6 +188,13 @@ void RootSignature::InitImmutableSampler(SHADER_TYPE ShaderT ImtblSmplr.ShaderRegister = SamplerAttribs.BindPoint; ImtblSmplr.ArraySize = SamplerAttribs.BindCount; ImtblSmplr.RegisterSpace = 0; + ImtblSmplr.Name = SamplerName; + + if (ShaderType & RayTracingMask) + { + ImtblSmplr.ShaderRegister = m_NumResources[D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER]; + m_NumResources[D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER] += SamplerAttribs.BindCount; + } SamplerFound = true; break; @@ -309,27 +207,40 @@ void RootSignature::InitImmutableSampler(SHADER_TYPE ShaderT } } + // http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-layout#Initializing-Shader-Resource-Layouts-and-Root-Signature-in-a-Pipeline-State-Object -void RootSignature::AllocateResourceSlot(SHADER_TYPE ShaderType, - PIPELINE_TYPE PipelineType, - const D3DShaderResourceAttribs& ShaderResAttribs, - SHADER_RESOURCE_VARIABLE_TYPE VariableType, - D3D12_DESCRIPTOR_RANGE_TYPE RangeType, - Uint32& RootIndex, // Output parameter - Uint32& OffsetFromTableStart // Output parameter +void RootSignatureBuilder::AllocateResourceSlot(SHADER_TYPE ShaderType, + PIPELINE_TYPE PipelineType, + const D3DShaderResourceAttribs& ShaderResAttribs, + SHADER_RESOURCE_VARIABLE_TYPE VariableType, + D3D12_DESCRIPTOR_RANGE_TYPE RangeType, + Uint32& BindPoint, // in/out parameter + Uint32& RootIndex, // Output parameter + Uint32& OffsetFromTableStart // Output parameter ) { - const auto ShaderVisibility = GetShaderVisibility(ShaderType); + const auto ShaderVisibility = ShaderTypeToD3D12ShaderVisibility(ShaderType); + auto& RootParams = m_RootSig.m_RootParams; + + // update resource binding for ray tracing + if (ShaderType & RayTracingMask) + { + BindPoint = m_NumResources[RangeType]; + m_NumResources[RangeType] += ShaderResAttribs.BindCount; + } + else + BindPoint = ShaderResAttribs.BindPoint; + if (RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_CBV && ShaderResAttribs.BindCount == 1) { // Allocate single CBV directly in the root signature // Get the next available root index past all allocated tables and root views - RootIndex = m_RootParams.GetNumRootTables() + m_RootParams.GetNumRootViews(); + RootIndex = RootParams.GetNumRootTables() + RootParams.GetNumRootViews(); OffsetFromTableStart = 0; // Add new root view to existing root parameters - m_RootParams.AddRootView(D3D12_ROOT_PARAMETER_TYPE_CBV, RootIndex, ShaderResAttribs.BindPoint, ShaderVisibility, VariableType); + RootParams.AddRootView(D3D12_ROOT_PARAMETER_TYPE_CBV, RootIndex, BindPoint, ShaderVisibility, VariableType); } else { @@ -338,26 +249,26 @@ void RootSignature::AllocateResourceSlot(SHADER_TYPE ShaderT const auto RootTableType = (VariableType == SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC) ? SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC : SHADER_RESOURCE_VARIABLE_TYPE_STATIC; const auto TableIndKey = ShaderInd * SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES + RootTableType; // Get the table array index (this is not the root index!) - auto& RootTableArrayInd = ((RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER) ? m_SamplerRootTablesMap : m_SrvCbvUavRootTablesMap)[TableIndKey]; - if (RootTableArrayInd == InvalidRootTableIndex) + auto& RootTableArrayInd = ((RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER) ? m_RootSig.m_SamplerRootTablesMap : m_RootSig.m_SrvCbvUavRootTablesMap)[TableIndKey]; + if (RootTableArrayInd == RootSignature::InvalidRootTableIndex) { // Root table has not been assigned to this combination yet // Get the next available root index past all allocated tables and root views - RootIndex = m_RootParams.GetNumRootTables() + m_RootParams.GetNumRootViews(); - VERIFY_EXPR(m_RootParams.GetNumRootTables() < 255); - RootTableArrayInd = static_cast<Uint8>(m_RootParams.GetNumRootTables()); + RootIndex = RootParams.GetNumRootTables() + RootParams.GetNumRootViews(); + VERIFY_EXPR(RootParams.GetNumRootTables() < 255); + RootTableArrayInd = static_cast<Uint8>(RootParams.GetNumRootTables()); // Add root table with one single-descriptor range - m_RootParams.AddRootTable(RootIndex, ShaderVisibility, RootTableType, 1); + RootParams.AddRootTable(RootIndex, ShaderVisibility, RootTableType, 1); } else { // Add a new single-descriptor range to the existing table at index RootTableArrayInd - m_RootParams.AddDescriptorRanges(RootTableArrayInd, 1); + RootParams.AddDescriptorRanges(RootTableArrayInd, 1); } // Reference to either existing or just added table - auto& CurrParam = m_RootParams.GetRootTable(RootTableArrayInd); + auto& CurrParam = RootParams.GetRootTable(RootTableArrayInd); RootIndex = CurrParam.GetRootIndex(); const auto& d3d12RootParam = static_cast<const D3D12_ROOT_PARAMETER&>(CurrParam); @@ -372,7 +283,7 @@ void RootSignature::AllocateResourceSlot(SHADER_TYPE ShaderT Uint32 NewDescriptorRangeIndex = d3d12RootParam.DescriptorTable.NumDescriptorRanges - 1; CurrParam.SetDescriptorRange(NewDescriptorRangeIndex, RangeType, // Range type (CBV, SRV, UAV or SAMPLER) - ShaderResAttribs.BindPoint, // Shader register + BindPoint, // Shader register ShaderResAttribs.BindCount, // Number of registers used (1 for non-array resources) 0, // Register space. Always 0 for now OffsetFromTableStart // Offset in descriptors from the table start @@ -381,73 +292,7 @@ void RootSignature::AllocateResourceSlot(SHADER_TYPE ShaderT } -#ifdef DILIGENT_DEBUG -void RootSignature::dbgVerifyRootParameters() const -{ - Uint32 dbgTotalSrvCbvUavSlots = 0; - Uint32 dbgTotalSamplerSlots = 0; - for (Uint32 rt = 0; rt < m_RootParams.GetNumRootTables(); ++rt) - { - auto& RootTable = m_RootParams.GetRootTable(rt); - auto& Param = static_cast<const D3D12_ROOT_PARAMETER&>(RootTable); - VERIFY(Param.ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, "Root parameter is expected to be a descriptor table"); - auto& Table = Param.DescriptorTable; - VERIFY(Table.NumDescriptorRanges > 0, "Descriptor table is expected to be non-empty"); - VERIFY(Table.pDescriptorRanges[0].OffsetInDescriptorsFromTableStart == 0, "Descriptor table is expected to start at 0 offset"); - bool IsResourceTable = Table.pDescriptorRanges[0].RangeType != D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; - for (Uint32 r = 0; r < Table.NumDescriptorRanges; ++r) - { - const auto& range = Table.pDescriptorRanges[r]; - if (IsResourceTable) - { - // clang-format off - VERIFY(range.RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SRV || - range.RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_CBV || - range.RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_UAV, - "Resource type is expected to be SRV, CBV or UAV"); - // clang-format on - dbgTotalSrvCbvUavSlots += range.NumDescriptors; - } - else - { - VERIFY(range.RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, "Resource type is expected to be sampler"); - dbgTotalSamplerSlots += range.NumDescriptors; - } - - if (r > 0) - { - VERIFY(Table.pDescriptorRanges[r].OffsetInDescriptorsFromTableStart == Table.pDescriptorRanges[r - 1].OffsetInDescriptorsFromTableStart + Table.pDescriptorRanges[r - 1].NumDescriptors, "Ranges in a descriptor table are expected to be consequtive"); - } - } - } - - Uint32 dbgTotalRootViews = 0; - for (Uint32 rv = 0; rv < m_RootParams.GetNumRootViews(); ++rv) - { - auto& RootView = m_RootParams.GetRootView(rv); - auto& Param = static_cast<const D3D12_ROOT_PARAMETER&>(RootView); - VERIFY(Param.ParameterType == D3D12_ROOT_PARAMETER_TYPE_CBV, "Root parameter is expected to be a CBV"); - ++dbgTotalRootViews; - } - - // clang-format off - VERIFY(dbgTotalSrvCbvUavSlots == - m_TotalSrvCbvUavSlots[SHADER_RESOURCE_VARIABLE_TYPE_STATIC] + - m_TotalSrvCbvUavSlots[SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE] + - m_TotalSrvCbvUavSlots[SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC], "Unexpected number of SRV CBV UAV resource slots"); - VERIFY(dbgTotalSamplerSlots == - m_TotalSamplerSlots[SHADER_RESOURCE_VARIABLE_TYPE_STATIC] + - m_TotalSamplerSlots[SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE] + - m_TotalSamplerSlots[SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC], "Unexpected number of sampler slots"); - VERIFY(dbgTotalRootViews == - m_TotalRootViews[SHADER_RESOURCE_VARIABLE_TYPE_STATIC] + - m_TotalRootViews[SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE] + - m_TotalRootViews[SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC], "Unexpected number of root views"); - // clang-format on -} -#endif - -void RootSignature::AllocateImmutableSamplers(const PipelineResourceLayoutDesc& ResourceLayout) +void RootSignatureBuilder::AllocateImmutableSamplers(const PipelineResourceLayoutDesc& ResourceLayout) { if (ResourceLayout.NumImmutableSamplers > 0) { @@ -455,22 +300,29 @@ void RootSignature::AllocateImmutableSamplers(const PipelineResourceLayoutDesc& for (Uint32 sam = 0; sam < ResourceLayout.NumImmutableSamplers; ++sam) { const auto& ImtblSamDesc = ResourceLayout.ImmutableSamplers[sam]; - Uint32 ShaderStages = ImtblSamDesc.ShaderStages; + SHADER_TYPE ShaderStages = ImtblSamDesc.ShaderStages; while (ShaderStages != 0) { - auto Stage = ShaderStages & ~(ShaderStages - 1); - m_ImmutableSamplers.emplace_back(ImtblSamDesc, GetShaderVisibility(static_cast<SHADER_TYPE>(Stage))); + auto Stage = ShaderStages & ~static_cast<SHADER_TYPE>(ShaderStages - 1); + m_ImmutableSamplers.emplace_back(ImtblSamDesc, ShaderTypeToD3D12ShaderVisibility(Stage), Stage); ShaderStages &= ~Stage; } } } } -void RootSignature::Finalize(ID3D12Device* pd3d12Device) + +void RootSignatureBuilder::Finalize(ID3D12Device* pd3d12Device) { - for (Uint32 rt = 0; rt < m_RootParams.GetNumRootTables(); ++rt) + auto& RootParams = m_RootSig.m_RootParams; + auto& TotalSamplerSlots = m_RootSig.m_TotalSamplerSlots; + auto& TotalSrvCbvUavSlots = m_RootSig.m_TotalSrvCbvUavSlots; + auto& TotalRootViews = m_RootSig.m_TotalRootViews; + auto& d3d12RootSignature = m_RootSig.m_pd3d12RootSignature; + + for (Uint32 rt = 0; rt < RootParams.GetNumRootTables(); ++rt) { - const auto& RootTbl = m_RootParams.GetRootTable(rt); + const auto& RootTbl = RootParams.GetRootTable(rt); const auto& d3d12RootParam = static_cast<const D3D12_ROOT_PARAMETER&>(RootTbl); VERIFY_EXPR(d3d12RootParam.ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE); @@ -478,13 +330,13 @@ void RootSignature::Finalize(ID3D12Device* pd3d12Device) VERIFY(d3d12RootParam.DescriptorTable.NumDescriptorRanges > 0 && TableSize > 0, "Unexpected empty descriptor table"); auto IsSamplerTable = d3d12RootParam.DescriptorTable.pDescriptorRanges[0].RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; auto VarType = RootTbl.GetShaderVariableType(); - (IsSamplerTable ? m_TotalSamplerSlots : m_TotalSrvCbvUavSlots)[VarType] += TableSize; + (IsSamplerTable ? TotalSamplerSlots : TotalSrvCbvUavSlots)[VarType] += TableSize; } - for (Uint32 rv = 0; rv < m_RootParams.GetNumRootViews(); ++rv) + for (Uint32 rv = 0; rv < RootParams.GetNumRootViews(); ++rv) { - const auto& RootView = m_RootParams.GetRootView(rv); - ++m_TotalRootViews[RootView.GetShaderVariableType()]; + const auto& RootView = RootParams.GetRootView(rv); + ++TotalRootViews[RootView.GetShaderVariableType()]; } #ifdef DILIGENT_DEBUG @@ -494,19 +346,19 @@ void RootSignature::Finalize(ID3D12Device* pd3d12Device) D3D12_ROOT_SIGNATURE_DESC rootSignatureDesc; rootSignatureDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; - auto TotalParams = m_RootParams.GetNumRootTables() + m_RootParams.GetNumRootViews(); + auto TotalParams = RootParams.GetNumRootTables() + RootParams.GetNumRootViews(); std::vector<D3D12_ROOT_PARAMETER, STDAllocatorRawMem<D3D12_ROOT_PARAMETER>> D3D12Parameters(TotalParams, D3D12_ROOT_PARAMETER{}, STD_ALLOCATOR_RAW_MEM(D3D12_ROOT_PARAMETER, GetRawAllocator(), "Allocator for vector<D3D12_ROOT_PARAMETER>")); - for (Uint32 rt = 0; rt < m_RootParams.GetNumRootTables(); ++rt) + for (Uint32 rt = 0; rt < RootParams.GetNumRootTables(); ++rt) { - const auto& RootTable = m_RootParams.GetRootTable(rt); + const auto& RootTable = RootParams.GetRootTable(rt); const D3D12_ROOT_PARAMETER& SrcParam = RootTable; VERIFY(SrcParam.ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE && SrcParam.DescriptorTable.NumDescriptorRanges > 0, "Non-empty descriptor table is expected"); D3D12Parameters[RootTable.GetRootIndex()] = SrcParam; } - for (Uint32 rv = 0; rv < m_RootParams.GetNumRootViews(); ++rv) + for (Uint32 rv = 0; rv < RootParams.GetNumRootViews(); ++rv) { - const auto& RootView = m_RootParams.GetRootView(rv); + const auto& RootView = RootParams.GetRootView(rv); const D3D12_ROOT_PARAMETER& SrcParam = RootView; VERIFY(SrcParam.ParameterType == D3D12_ROOT_PARAMETER_TYPE_CBV, "Root CBV is expected"); D3D12Parameters[RootView.GetRootIndex()] = SrcParam; @@ -554,8 +406,8 @@ void RootSignature::Finalize(ID3D12Device* pd3d12Device) rootSignatureDesc.pStaticSamplers = D3D12StaticSamplers.data(); // Release immutable samplers array, we no longer need it - std::vector<ImmutableSamplerAttribs, STDAllocatorRawMem<ImmutableSamplerAttribs>> EmptySamplers(STD_ALLOCATOR_RAW_MEM(ImmutableSamplerAttribs, GetRawAllocator(), "Allocator for vector<ImmutableSamplerAttribs>")); - m_ImmutableSamplers.swap(EmptySamplers); + //std::vector<ImmutableSamplerAttribs, STDAllocatorRawMem<ImmutableSamplerAttribs>> EmptySamplers(STD_ALLOCATOR_RAW_MEM(ImmutableSamplerAttribs, GetRawAllocator(), "Allocator for vector<ImmutableSamplerAttribs>")); + //m_ImmutableSamplers.swap(EmptySamplers); VERIFY_EXPR(D3D12StaticSamplers.size() == TotalD3D12StaticSamplers); } @@ -564,28 +416,144 @@ void RootSignature::Finalize(ID3D12Device* pd3d12Device) CComPtr<ID3DBlob> signature; CComPtr<ID3DBlob> error; HRESULT hr = D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error); - hr = pd3d12Device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), __uuidof(m_pd3d12RootSignature), reinterpret_cast<void**>(static_cast<ID3D12RootSignature**>(&m_pd3d12RootSignature))); + if (error) + { + LOG_ERROR_MESSAGE("Error: ", (const char*)error->GetBufferPointer()); + } + CHECK_D3D_RESULT_THROW(hr, "Failed to serialize root signature"); + + hr = pd3d12Device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), __uuidof(d3d12RootSignature), reinterpret_cast<void**>(static_cast<ID3D12RootSignature**>(&d3d12RootSignature))); CHECK_D3D_RESULT_THROW(hr, "Failed to create root signature"); - bool bHasDynamicDescriptors = m_TotalSrvCbvUavSlots[SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC] != 0 || m_TotalSamplerSlots[SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC] != 0; + bool bHasDynamicDescriptors = TotalSrvCbvUavSlots[SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC] != 0 || TotalSamplerSlots[SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC] != 0; if (bHasDynamicDescriptors) { - CommitDescriptorHandles = &RootSignature::CommitDescriptorHandlesInternal_SMD<false>; - TransitionAndCommitDescriptorHandles = &RootSignature::CommitDescriptorHandlesInternal_SMD<true>; + m_RootSig.CommitDescriptorHandles = &RootSignature::CommitDescriptorHandlesInternal_SMD<false>; + m_RootSig.TransitionAndCommitDescriptorHandles = &RootSignature::CommitDescriptorHandlesInternal_SMD<true>; } else { - CommitDescriptorHandles = &RootSignature::CommitDescriptorHandlesInternal_SM<false>; - TransitionAndCommitDescriptorHandles = &RootSignature::CommitDescriptorHandlesInternal_SM<true>; + m_RootSig.CommitDescriptorHandles = &RootSignature::CommitDescriptorHandlesInternal_SM<false>; + m_RootSig.TransitionAndCommitDescriptorHandles = &RootSignature::CommitDescriptorHandlesInternal_SM<true>; } } -size_t RootSignature::GetResourceCacheRequiredMemSize() const + +#ifdef DILIGENT_DEBUG +void RootSignatureBuilder::dbgVerifyRootParameters() const { - auto CacheTableSizes = GetCacheTableSizes(); + auto& RootParams = m_RootSig.m_RootParams; + auto& TotalSamplerSlots = m_RootSig.m_TotalSamplerSlots; + auto& TotalSrvCbvUavSlots = m_RootSig.m_TotalSrvCbvUavSlots; + auto& TotalRootViews = m_RootSig.m_TotalRootViews; + + Uint32 dbgTotalSrvCbvUavSlots = 0; + Uint32 dbgTotalSamplerSlots = 0; + for (Uint32 rt = 0; rt < RootParams.GetNumRootTables(); ++rt) + { + auto& RootTable = RootParams.GetRootTable(rt); + auto& Param = static_cast<const D3D12_ROOT_PARAMETER&>(RootTable); + VERIFY(Param.ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, "Root parameter is expected to be a descriptor table"); + auto& Table = Param.DescriptorTable; + VERIFY(Table.NumDescriptorRanges > 0, "Descriptor table is expected to be non-empty"); + VERIFY(Table.pDescriptorRanges[0].OffsetInDescriptorsFromTableStart == 0, "Descriptor table is expected to start at 0 offset"); + bool IsResourceTable = Table.pDescriptorRanges[0].RangeType != D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; + for (Uint32 r = 0; r < Table.NumDescriptorRanges; ++r) + { + const auto& range = Table.pDescriptorRanges[r]; + if (IsResourceTable) + { + // clang-format off + VERIFY(range.RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SRV || + range.RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_CBV || + range.RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_UAV, + "Resource type is expected to be SRV, CBV or UAV"); + // clang-format on + dbgTotalSrvCbvUavSlots += range.NumDescriptors; + } + else + { + VERIFY(range.RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, "Resource type is expected to be sampler"); + dbgTotalSamplerSlots += range.NumDescriptors; + } + + if (r > 0) + { + VERIFY(Table.pDescriptorRanges[r].OffsetInDescriptorsFromTableStart == Table.pDescriptorRanges[r - 1].OffsetInDescriptorsFromTableStart + Table.pDescriptorRanges[r - 1].NumDescriptors, "Ranges in a descriptor table are expected to be consequtive"); + } + } + } + + Uint32 dbgTotalRootViews = 0; + for (Uint32 rv = 0; rv < RootParams.GetNumRootViews(); ++rv) + { + auto& RootView = RootParams.GetRootView(rv); + auto& Param = static_cast<const D3D12_ROOT_PARAMETER&>(RootView); + VERIFY(Param.ParameterType == D3D12_ROOT_PARAMETER_TYPE_CBV, "Root parameter is expected to be a CBV"); + ++dbgTotalRootViews; + } + + // clang-format off + VERIFY(dbgTotalSrvCbvUavSlots == + TotalSrvCbvUavSlots[SHADER_RESOURCE_VARIABLE_TYPE_STATIC] + + TotalSrvCbvUavSlots[SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE] + + TotalSrvCbvUavSlots[SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC], "Unexpected number of SRV CBV UAV resource slots"); + VERIFY(dbgTotalSamplerSlots == + TotalSamplerSlots[SHADER_RESOURCE_VARIABLE_TYPE_STATIC] + + TotalSamplerSlots[SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE] + + TotalSamplerSlots[SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC], "Unexpected number of sampler slots"); + VERIFY(dbgTotalRootViews == + TotalRootViews[SHADER_RESOURCE_VARIABLE_TYPE_STATIC] + + TotalRootViews[SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE] + + TotalRootViews[SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC], "Unexpected number of root views"); + // clang-format on +} +#endif + +size_t RootSignatureBuilder::GetResourceCacheRequiredMemSize() const +{ + auto CacheTableSizes = m_RootSig.GetCacheTableSizes(); return ShaderResourceCacheD3D12::GetRequiredMemorySize(static_cast<Uint32>(CacheTableSizes.size()), CacheTableSizes.data()); } + +RootSignature::RootSignature() : + m_RootParams{GetRawAllocator()}, + m_MemAllocator{GetRawAllocator()} +{ + m_SrvCbvUavRootTablesMap.fill(InvalidRootTableIndex); + m_SamplerRootTablesMap.fill(InvalidRootTableIndex); +} + +// clang-format off +static D3D12_DESCRIPTOR_HEAP_TYPE RangeType2HeapTypeMap[] +{ + D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, //D3D12_DESCRIPTOR_RANGE_TYPE_SRV = 0 + D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, //D3D12_DESCRIPTOR_RANGE_TYPE_UAV = ( D3D12_DESCRIPTOR_RANGE_TYPE_SRV + 1 ) + D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, //D3D12_DESCRIPTOR_RANGE_TYPE_CBV = ( D3D12_DESCRIPTOR_RANGE_TYPE_UAV + 1 ) + D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER //D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER = ( D3D12_DESCRIPTOR_RANGE_TYPE_CBV + 1 ) +}; +// clang-format on +D3D12_DESCRIPTOR_HEAP_TYPE HeapTypeFromRangeType(D3D12_DESCRIPTOR_RANGE_TYPE RangeType) +{ + VERIFY_EXPR(RangeType >= D3D12_DESCRIPTOR_RANGE_TYPE_SRV && RangeType <= D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER); + auto HeapType = RangeType2HeapTypeMap[RangeType]; + +#ifdef DILIGENT_DEBUG + switch (RangeType) + { + // clang-format off + case D3D12_DESCRIPTOR_RANGE_TYPE_CBV: VERIFY_EXPR(HeapType == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); break; + case D3D12_DESCRIPTOR_RANGE_TYPE_SRV: VERIFY_EXPR(HeapType == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); break; + case D3D12_DESCRIPTOR_RANGE_TYPE_UAV: VERIFY_EXPR(HeapType == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); break; + case D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER: VERIFY_EXPR(HeapType == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); break; + // clang-format on + default: UNEXPECTED("Unexpected descriptor range type"); break; + } +#endif + return HeapType; +} + std::vector<Uint32, STDAllocatorRawMem<Uint32>> RootSignature::GetCacheTableSizes() const { // Get root table size for every root index @@ -658,10 +626,6 @@ void RootSignature::InitResourceCache(RenderDeviceD3D12Impl* pDeviceD3D12Impl const auto& D3D12RootParam = static_cast<const D3D12_ROOT_PARAMETER&>(RootParam); auto& RootTableCache = ResourceCache.GetRootTable(RootParam.GetRootIndex()); - SHADER_TYPE dbgShaderType = SHADER_TYPE_UNKNOWN; -#ifdef DILIGENT_DEBUG - dbgShaderType = ShaderTypeFromShaderVisibility(D3D12RootParam.ShaderVisibility); -#endif VERIFY_EXPR(D3D12RootParam.ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE); auto TableSize = RootParam.GetDescriptorTableSize(); @@ -670,7 +634,7 @@ void RootSignature::InitResourceCache(RenderDeviceD3D12Impl* pDeviceD3D12Impl auto HeapType = HeapTypeFromRangeType(D3D12RootParam.DescriptorTable.pDescriptorRanges[0].RangeType); #ifdef DILIGENT_DEBUG - RootTableCache.SetDebugAttribs(TableSize, HeapType, dbgShaderType); + RootTableCache.SetDebugAttribs(TableSize, HeapType, D3D12ShaderVisibilityToShaderType(D3D12RootParam.ShaderVisibility)); #endif // Space for dynamic variables is allocated at every draw call @@ -702,9 +666,8 @@ void RootSignature::InitResourceCache(RenderDeviceD3D12Impl* pDeviceD3D12Impl // Root views are not assigned valid table start offset VERIFY_EXPR(RootTableCache.m_TableStartOffset == ShaderResourceCacheD3D12::InvalidDescriptorOffset); - SHADER_TYPE dbgShaderType = ShaderTypeFromShaderVisibility(D3D12RootParam.ShaderVisibility); VERIFY_EXPR(D3D12RootParam.ParameterType == D3D12_ROOT_PARAMETER_TYPE_CBV); - RootTableCache.SetDebugAttribs(1, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, dbgShaderType); + RootTableCache.SetDebugAttribs(1, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12ShaderVisibilityToShaderType(D3D12RootParam.ShaderVisibility)); } #endif @@ -718,6 +681,7 @@ __forceinline void TransitionResource(CommandContext& Ctx, ShaderResourceCacheD3D12::Resource& Res, D3D12_DESCRIPTOR_RANGE_TYPE RangeType) { + static_assert(static_cast<int>(CachedResourceType::NumTypes) == 7, "Please update this function to handle the new resource type"); switch (Res.Type) { case CachedResourceType::CBV: @@ -782,6 +746,15 @@ __forceinline void TransitionResource(CommandContext& Ctx, VERIFY(RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, "Unexpected descriptor range type"); break; + case CachedResourceType::AccelStruct: + { + VERIFY(RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SRV, "Unexpected descriptor range type"); + auto* pTLASD3D12 = Res.pObject.RawPtr<TopLevelASD3D12Impl>(); + if (pTLASD3D12->IsInKnownState()) + Ctx.TransitionResource(pTLASD3D12, RESOURCE_STATE_RAY_TRACING); + } + break; + default: // Resource not bound VERIFY(Res.Type == CachedResourceType::Unknown, "Unexpected resource type"); @@ -794,6 +767,7 @@ __forceinline void TransitionResource(CommandContext& Ctx, void RootSignature::DvpVerifyResourceState(const ShaderResourceCacheD3D12::Resource& Res, D3D12_DESCRIPTOR_RANGE_TYPE RangeType) { + static_assert(static_cast<int>(CachedResourceType::NumTypes) == 7, "Please update this function to handle the new resource type"); switch (Res.Type) { case CachedResourceType::CBV: @@ -880,6 +854,21 @@ void RootSignature::DvpVerifyResourceState(const ShaderResourceCacheD3D12::Resou VERIFY(RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, "Unexpected descriptor range type"); break; + case CachedResourceType::AccelStruct: + { + VERIFY(RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SRV, "Unexpected descriptor range type"); + const auto* pTLASD3D12 = Res.pObject.RawPtr<const TopLevelASD3D12Impl>(); + if (pTLASD3D12->IsInKnownState() && !pTLASD3D12->CheckState(RESOURCE_STATE_RAY_TRACING)) + { + LOG_ERROR_MESSAGE("TLAS '", pTLASD3D12->GetDesc().Name, "' must be in RESOURCE_STATE_RAY_TRACING state. Actual state: ", + GetResourceStateString(pTLASD3D12->GetState()), + ". Call IDeviceContext::TransitionShaderResources(), use RESOURCE_STATE_TRANSITION_MODE_TRANSITION " + "when calling IDeviceContext::CommitShaderResources() or explicitly transition the TLAS state " + "with IDeviceContext::TransitionResourceStates()."); + } + } + break; + default: // Resource not bound VERIFY(Res.Type == CachedResourceType::Unknown, "Unexpected resource type"); @@ -924,9 +913,10 @@ __forceinline void ProcessCachedTableResources(Uint32 RootI { SHADER_TYPE dbgShaderType = SHADER_TYPE_UNKNOWN; #ifdef DILIGENT_DEBUG - dbgShaderType = ShaderTypeFromShaderVisibility(D3D12Param.ShaderVisibility); - VERIFY(dbgHeapType == HeapTypeFromRangeType(range.RangeType), "Mistmatch between descriptor heap type and descriptor range type"); + dbgShaderType = D3D12ShaderVisibilityToShaderType(D3D12Param.ShaderVisibility); #endif + VERIFY(dbgHeapType == HeapTypeFromRangeType(range.RangeType), "Mistmatch between descriptor heap type and descriptor range type"); + auto OffsetFromTableStart = range.OffsetInDescriptorsFromTableStart + d; auto& Res = ResourceCache.GetRootTable(RootInd).GetResource(OffsetFromTableStart, dbgHeapType, dbgShaderType); @@ -1164,4 +1154,57 @@ void RootSignature::TransitionResources(ShaderResourceCacheD3D12& ResourceCache, ); } + +LocalRootSignature::LocalRootSignature(const char* pCBName, Uint32 ShaderRecordSize) : + m_pName{pCBName}, + m_ShaderRecordSize{ShaderRecordSize} +{ + VERIFY_EXPR((m_pName != nullptr) == (m_ShaderRecordSize > 0)); +} + +bool LocalRootSignature::SetOrMerge(const D3DShaderResourceAttribs& CB) +{ + if (m_ShaderRecordSize > 0 && + CB.GetInputType() == D3D_SIT_CBUFFER && + strcmp(m_pName, CB.Name) == 0) + { + if (m_BindPoint == InvalidBindPoint) + m_BindPoint = CB.BindPoint; + + VERIFY_EXPR(CB.BindCount == 1); + VERIFY_EXPR(m_BindPoint == CB.BindPoint); + + return true; + } + return false; +} + +ID3D12RootSignature* LocalRootSignature::Create(ID3D12Device* pDevice) +{ + if (m_ShaderRecordSize == 0 || m_BindPoint == InvalidBindPoint) + return nullptr; + + D3D12_ROOT_SIGNATURE_DESC d3d12RootSignatureDesc = {}; + D3D12_ROOT_PARAMETER d3d12Params = {}; + + d3d12Params.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; + d3d12Params.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + d3d12Params.Constants.Num32BitValues = m_ShaderRecordSize / 4; + d3d12Params.Constants.RegisterSpace = 0; + d3d12Params.Constants.ShaderRegister = m_BindPoint; + + d3d12RootSignatureDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_LOCAL_ROOT_SIGNATURE; + d3d12RootSignatureDesc.NumParameters = 1; + d3d12RootSignatureDesc.pParameters = &d3d12Params; + + CComPtr<ID3DBlob> signature; + auto hr = D3D12SerializeRootSignature(&d3d12RootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, nullptr); + CHECK_D3D_RESULT_THROW(hr, "Failed to serialize local root signature"); + + hr = pDevice->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_pd3d12RootSignature)); + CHECK_D3D_RESULT_THROW(hr, "Failed to create D3D12 local root signature"); + + return m_pd3d12RootSignature; +} + } // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/src/ShaderBindingTableD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/ShaderBindingTableD3D12Impl.cpp new file mode 100644 index 00000000..0e15bd4f --- /dev/null +++ b/Graphics/GraphicsEngineD3D12/src/ShaderBindingTableD3D12Impl.cpp @@ -0,0 +1,55 @@ +/* + * Copyright 2019-2020 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include "pch.h" +#include "ShaderBindingTableD3D12Impl.hpp" +#include "RenderDeviceD3D12Impl.hpp" +#include "DeviceContextD3D12Impl.hpp" +#include "D3D12TypeConversions.hpp" +#include "GraphicsAccessories.hpp" +#include "DXGITypeConversions.hpp" +#include "EngineMemory.h" +#include "StringTools.hpp" + +namespace Diligent +{ + +ShaderBindingTableD3D12Impl::ShaderBindingTableD3D12Impl(IReferenceCounters* pRefCounters, + class RenderDeviceD3D12Impl* pDeviceD3D12, + const ShaderBindingTableDesc& Desc, + bool bIsDeviceInternal) : + TShaderBindingTableBase{pRefCounters, pDeviceD3D12, Desc, bIsDeviceInternal} +{ +} + +ShaderBindingTableD3D12Impl::~ShaderBindingTableD3D12Impl() +{ +} + +IMPLEMENT_QUERY_INTERFACE(ShaderBindingTableD3D12Impl, IID_ShaderBindingTableD3D12, TShaderBindingTableBase) + +} // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/src/ShaderD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/ShaderD3D12Impl.cpp index 36a14167..52c39f23 100644 --- a/Graphics/GraphicsEngineD3D12/src/ShaderD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/ShaderD3D12Impl.cpp @@ -59,7 +59,7 @@ static ShaderVersion GetD3D12ShaderModel(RenderDeviceD3D12Impl* pDevice, const S CompilerSM = ShaderVersion{5, 1}; } - ShaderVersion DeviceSM = pDevice->GetMaxShaderModel(); + ShaderVersion DeviceSM = pDevice->GetProperties().MaxShaderVersion; ShaderVersion MaxSupportedSM = DeviceSM.Major == CompilerSM.Major ? (DeviceSM.Minor < CompilerSM.Minor ? DeviceSM : CompilerSM) : @@ -94,7 +94,8 @@ ShaderD3D12Impl::ShaderD3D12Impl(IReferenceCounters* pRefCounters, pRenderDeviceD3D12, ShaderCI.Desc }, - ShaderD3DBase{ShaderCI, GetD3D12ShaderModel(pRenderDeviceD3D12, ShaderCI.HLSLVersion, ShaderCI.ShaderCompiler), pRenderDeviceD3D12->GetDxCompiler()} + ShaderD3DBase{ShaderCI, GetD3D12ShaderModel(pRenderDeviceD3D12, ShaderCI.HLSLVersion, ShaderCI.ShaderCompiler), pRenderDeviceD3D12->GetDxCompiler()}, + m_EntryPoint{ShaderCI.EntryPoint} // clang-format on { // Load shader resources diff --git a/Graphics/GraphicsEngineD3D12/src/ShaderResourceBindingD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/ShaderResourceBindingD3D12Impl.cpp index 1511bd01..c7c3ede6 100644 --- a/Graphics/GraphicsEngineD3D12/src/ShaderResourceBindingD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/ShaderResourceBindingD3D12Impl.cpp @@ -30,7 +30,7 @@ #include "PipelineStateD3D12Impl.hpp" #include "ShaderD3D12Impl.hpp" #include "RenderDeviceD3D12Impl.hpp" -#include "LinearAllocator.hpp" +#include "FixedLinearAllocator.hpp" namespace Diligent { @@ -53,7 +53,7 @@ ShaderResourceBindingD3D12Impl::ShaderResourceBindingD3D12Impl(IReferenceCounter { m_ResourceLayoutIndex.fill(-1); - LinearAllocator MemPool{GetRawAllocator()}; + FixedLinearAllocator MemPool{GetRawAllocator()}; MemPool.AddSpace<ShaderVariableManagerD3D12>(m_NumShaders); MemPool.Reserve(); m_pShaderVarMgrs = MemPool.ConstructArray<ShaderVariableManagerD3D12>(m_NumShaders, std::ref(*this), std::ref(m_ShaderResourceCache)); diff --git a/Graphics/GraphicsEngineD3D12/src/ShaderResourceLayoutD3D12.cpp b/Graphics/GraphicsEngineD3D12/src/ShaderResourceLayoutD3D12.cpp index c0428e7e..771e2c23 100644 --- a/Graphics/GraphicsEngineD3D12/src/ShaderResourceLayoutD3D12.cpp +++ b/Graphics/GraphicsEngineD3D12/src/ShaderResourceLayoutD3D12.cpp @@ -39,6 +39,8 @@ #include "PipelineStateD3D12Impl.hpp" #include "ShaderResourceVariableBase.hpp" #include "ShaderVariableD3DBase.hpp" +#include "FixedLinearAllocator.hpp" +#include "TopLevelASD3D12.h" namespace Diligent { @@ -57,12 +59,13 @@ D3D12_DESCRIPTOR_RANGE_TYPE GetDescriptorRangeType(CachedResourceType ResType) ResTypeToD3D12DescrRangeType() { // clang-format off - m_Map[(size_t)CachedResourceType::CBV] = D3D12_DESCRIPTOR_RANGE_TYPE_CBV; - m_Map[(size_t)CachedResourceType::TexSRV] = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; - m_Map[(size_t)CachedResourceType::BufSRV] = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; - m_Map[(size_t)CachedResourceType::TexUAV] = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; - m_Map[(size_t)CachedResourceType::BufUAV] = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; - m_Map[(size_t)CachedResourceType::Sampler] = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; + m_Map[(size_t)CachedResourceType::CBV] = D3D12_DESCRIPTOR_RANGE_TYPE_CBV; + m_Map[(size_t)CachedResourceType::TexSRV] = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; + m_Map[(size_t)CachedResourceType::BufSRV] = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; + m_Map[(size_t)CachedResourceType::TexUAV] = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; + m_Map[(size_t)CachedResourceType::BufUAV] = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; + m_Map[(size_t)CachedResourceType::Sampler] = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; + m_Map[(size_t)CachedResourceType::AccelStruct] = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; // clang-format on } @@ -82,12 +85,15 @@ D3D12_DESCRIPTOR_RANGE_TYPE GetDescriptorRangeType(CachedResourceType ResType) } -void ShaderResourceLayoutD3D12::AllocateMemory(IMemoryAllocator& Allocator, - const std::array<Uint32, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES>& CbvSrvUavCount, - const std::array<Uint32, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES>& SamplerCount) +StringPool ShaderResourceLayoutD3D12::AllocateMemory(IMemoryAllocator& Allocator, + const std::array<Uint32, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES>& CbvSrvUavCount, + const std::array<Uint32, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES>& SamplerCount, + size_t StringPoolSize) { m_CbvSrvUavOffsets[0] = 0; - for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(VarType + 1)) + for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; + VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; + VarType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(VarType + 1)) { VERIFY(m_CbvSrvUavOffsets[VarType] + CbvSrvUavCount[VarType] <= std::numeric_limits<Uint16>::max(), "Offset is not representable in 16 bits"); m_CbvSrvUavOffsets[VarType + 1] = static_cast<Uint16>(m_CbvSrvUavOffsets[VarType] + CbvSrvUavCount[VarType]); @@ -95,260 +101,345 @@ void ShaderResourceLayoutD3D12::AllocateMemory(IMemoryAllocator& } m_SamplersOffsets[0] = m_CbvSrvUavOffsets[SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES]; - for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(VarType + 1)) + for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; + VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; + VarType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(VarType + 1)) { VERIFY(m_SamplersOffsets[VarType] + SamplerCount[VarType] <= std::numeric_limits<Uint16>::max(), "Offset is not representable in 16 bits"); m_SamplersOffsets[VarType + 1] = static_cast<Uint16>(m_SamplersOffsets[VarType] + SamplerCount[VarType]); VERIFY_EXPR(GetSamplerCount(VarType) == SamplerCount[VarType]); } - size_t MemSize = GetTotalResourceCount() * sizeof(D3D12Resource); - if (MemSize == 0) - return; + FixedLinearAllocator MemPool{Allocator}; + MemPool.AddSpace<D3D12Resource>(GetTotalResourceCount()); + MemPool.AddSpace<char>(StringPoolSize); + + MemPool.Reserve(); + + auto* pResources = MemPool.Allocate<D3D12Resource>(GetTotalResourceCount()); + auto* pStringPoolData = MemPool.ConstructArray<char>(StringPoolSize); + + m_ResourceBuffer = std::unique_ptr<void, STDDeleterRawMem<void>>(MemPool.Release(), Allocator); + VERIFY_EXPR(pResources == nullptr || m_ResourceBuffer.get() == pResources); + VERIFY_EXPR(pStringPoolData == GetStringPoolData()); - auto* pRawMem = ALLOCATE_RAW(Allocator, "Raw memory buffer for shader resource layout resources", MemSize); - m_ResourceBuffer = std::unique_ptr<void, STDDeleterRawMem<void>>(pRawMem, Allocator); + StringPool stringPool; + stringPool.AssignMemory(pStringPoolData, StringPoolSize); + return stringPool; } // http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-layout#Initializing-Shader-Resource-Layouts-and-Root-Signature-in-a-Pipeline-State-Object // http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-cache#Initializing-Shader-Resource-Layouts-in-a-Pipeline-State -void ShaderResourceLayoutD3D12::Initialize(ID3D12Device* pd3d12Device, - PIPELINE_TYPE PipelineType, - const PipelineResourceLayoutDesc& ResourceLayout, - std::shared_ptr<const ShaderResourcesD3D12> pSrcResources, - IMemoryAllocator& LayoutDataAllocator, - const SHADER_RESOURCE_VARIABLE_TYPE* const AllowedVarTypes, - Uint32 NumAllowedTypes, - ShaderResourceCacheD3D12* pResourceCache, - RootSignature* pRootSig) +void ShaderResourceLayoutD3D12::Initialize(ID3D12Device* pd3d12Device, + PIPELINE_TYPE PipelineType, + const PipelineResourceLayoutDesc& ResourceLayout, + const std::vector<ShaderD3D12Impl*>& Shaders, + IMemoryAllocator& LayoutDataAllocator, + const SHADER_RESOURCE_VARIABLE_TYPE* const AllowedVarTypes, + Uint32 NumAllowedTypes, + ShaderResourceCacheD3D12* pResourceCache, + RootSignatureBuilder* pRootSig, + LocalRootSignature* pLocalRootSig) { m_pd3d12Device = pd3d12Device; - m_pResources = std::move(pSrcResources); VERIFY_EXPR((pResourceCache != nullptr) ^ (pRootSig != nullptr)); + VERIFY_EXPR(Shaders.size() > 0); const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes); std::array<Uint32, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES> CbvSrvUavCount = {}; std::array<Uint32, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES> SamplerCount = {}; - // Count number of resources to allocate all needed memory - m_pResources->ProcessResources( - [&](const D3DShaderResourceAttribs& CB, Uint32) // - { - auto VarType = m_pResources->FindVariableType(CB, ResourceLayout); - if (IsAllowedType(VarType, AllowedTypeBits)) - ++CbvSrvUavCount[VarType]; - }, - [&](const D3DShaderResourceAttribs& Sam, Uint32) // + // Maps resource name to its index in m_ResourceBuffer + std::unordered_map<HashMapStringKey, Uint32, HashMapStringKey::Hasher> ResourceNameToIndex; + + // Count the number of resources to allocate all needed memory + m_IsUsingSeparateSamplers = !Shaders[0]->GetShaderResources()->IsUsingCombinedTextureSamplers(); + m_ShaderType = Shaders[0]->GetDesc().ShaderType; + + // Construct shader or shader group name + const auto ShaderName = GetShaderGroupName(Shaders); + + size_t StringPoolSize = ShaderName.length() + 1; + + static constexpr Uint32 InvalidResourceIndex = ~0u; + + for (auto* pShader : Shaders) + { + auto pResources = pShader->GetShaderResources(); + VERIFY_EXPR(pResources->GetShaderType() == m_ShaderType); + const auto HandleCbvSrvUav = [&](const auto& Res, Uint32) // { - auto VarType = m_pResources->FindVariableType(Sam, ResourceLayout); + auto VarType = pResources->FindVariableType(Res, ResourceLayout); if (IsAllowedType(VarType, AllowedTypeBits)) { - constexpr bool LogImtblSamplerArrayError = true; + if (pLocalRootSig && pLocalRootSig->SetOrMerge(Res)) + return; - auto ImtblSamplerInd = m_pResources->FindImmutableSampler(Sam, ResourceLayout, LogImtblSamplerArrayError); - // Skip immutable samplers - if (ImtblSamplerInd < 0) - ++SamplerCount[VarType]; + bool IsUniqueName = ResourceNameToIndex.emplace(HashMapStringKey{Res.Name}, InvalidResourceIndex).second; + if (IsUniqueName) + { + StringPoolSize += strlen(Res.Name) + 1; + ++CbvSrvUavCount[VarType]; + } } - }, - [&](const D3DShaderResourceAttribs& TexSRV, Uint32) // - { - auto VarType = m_pResources->FindVariableType(TexSRV, ResourceLayout); - if (IsAllowedType(VarType, AllowedTypeBits)) + }; + + pResources->ProcessResources( + HandleCbvSrvUav, + [&](const D3DShaderResourceAttribs& Sam, Uint32) // { - ++CbvSrvUavCount[VarType]; - if (TexSRV.IsCombinedWithSampler()) + auto VarType = pResources->FindVariableType(Sam, ResourceLayout); + if (IsAllowedType(VarType, AllowedTypeBits)) { - const auto& SamplerAttribs = m_pResources->GetCombinedSampler(TexSRV); - auto SamplerVarType = m_pResources->FindVariableType(SamplerAttribs, ResourceLayout); - DEV_CHECK_ERR(SamplerVarType == VarType, - "The type (", GetShaderVariableTypeLiteralName(VarType), ") of texture SRV variable '", TexSRV.Name, - "' is not consistent with the type (", GetShaderVariableTypeLiteralName(SamplerVarType), - ") of the sampler '", SamplerAttribs.Name, "' that is assigned to it"); - (void)SamplerVarType; + constexpr bool LogImtblSamplerArrayError = true; + + auto ImtblSamplerInd = pResources->FindImmutableSampler(Sam, ResourceLayout, LogImtblSamplerArrayError); + // Skip immutable samplers + if (ImtblSamplerInd < 0) + { + bool IsUniqueName = ResourceNameToIndex.emplace(HashMapStringKey{Sam.Name}, InvalidResourceIndex).second; + if (IsUniqueName) + { + StringPoolSize += strlen(Sam.Name) + 1; + ++SamplerCount[VarType]; + } + } } - } - }, - [&](const D3DShaderResourceAttribs& TexUAV, Uint32) // - { - auto VarType = m_pResources->FindVariableType(TexUAV, ResourceLayout); - if (IsAllowedType(VarType, AllowedTypeBits)) - ++CbvSrvUavCount[VarType]; - }, - [&](const D3DShaderResourceAttribs& BufSRV, Uint32) // - { - auto VarType = m_pResources->FindVariableType(BufSRV, ResourceLayout); - if (IsAllowedType(VarType, AllowedTypeBits)) - ++CbvSrvUavCount[VarType]; - }, - [&](const D3DShaderResourceAttribs& BufUAV, Uint32) // - { - auto VarType = m_pResources->FindVariableType(BufUAV, ResourceLayout); - if (IsAllowedType(VarType, AllowedTypeBits)) - ++CbvSrvUavCount[VarType]; - } // - ); + }, + [&](const D3DShaderResourceAttribs& TexSRV, Uint32) // + { + auto VarType = pResources->FindVariableType(TexSRV, ResourceLayout); + if (IsAllowedType(VarType, AllowedTypeBits)) + { + bool IsUniqueName = ResourceNameToIndex.emplace(HashMapStringKey{TexSRV.Name}, InvalidResourceIndex).second; + if (IsUniqueName) + { + StringPoolSize += strlen(TexSRV.Name) + 1; + ++CbvSrvUavCount[VarType]; + if (TexSRV.IsCombinedWithSampler()) + { + const auto& SamplerAttribs = pResources->GetCombinedSampler(TexSRV); + auto SamplerVarType = pResources->FindVariableType(SamplerAttribs, ResourceLayout); + DEV_CHECK_ERR(SamplerVarType == VarType, + "The type (", GetShaderVariableTypeLiteralName(VarType), ") of texture SRV variable '", TexSRV.Name, + "' is not consistent with the type (", GetShaderVariableTypeLiteralName(SamplerVarType), + ") of the sampler '", SamplerAttribs.Name, "' that is assigned to it"); + (void)SamplerVarType; + } + } + } + }, + HandleCbvSrvUav, + HandleCbvSrvUav, + HandleCbvSrvUav, + HandleCbvSrvUav); + } - AllocateMemory(LayoutDataAllocator, CbvSrvUavCount, SamplerCount); + auto stringPool = AllocateMemory(LayoutDataAllocator, CbvSrvUavCount, SamplerCount, StringPoolSize); - std::array<Uint32, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES> CurrCbvSrvUav = {}; - std::array<Uint32, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES> CurrSampler = {}; + stringPool.CopyString(ShaderName); - Uint32 StaticResCacheTblSizes[4] = {0, 0, 0, 0}; + std::array<Uint32, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES> CurrCbvSrvUav = {}; + std::array<Uint32, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES> CurrSampler = {}; + std::array<Uint32, D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER + 1> StaticResCacheTblSizes = {}; auto AddResource = [&](const D3DShaderResourceAttribs& Attribs, CachedResourceType ResType, SHADER_RESOURCE_VARIABLE_TYPE VarType, - Uint32 SamplerId = D3D12Resource::InvalidSamplerId) // + Uint32 SamplerId = D3DShaderResourceAttribs::InvalidSamplerId) // { - Uint32 RootIndex = D3D12Resource::InvalidRootIndex; - Uint32 Offset = D3D12Resource::InvalidOffset; + auto ResIter = ResourceNameToIndex.find(HashMapStringKey{Attribs.Name}); + VERIFY_EXPR(ResIter != ResourceNameToIndex.end()); - D3D12_DESCRIPTOR_RANGE_TYPE DescriptorRangeType = GetDescriptorRangeType(ResType); - - if (pRootSig) + if (ResIter->second == InvalidResourceIndex) { - pRootSig->AllocateResourceSlot(m_pResources->GetShaderType(), PipelineType, Attribs, VarType, DescriptorRangeType, RootIndex, Offset); - VERIFY(RootIndex <= D3D12Resource::MaxRootIndex, "Root index excceeds allowed limit"); + Uint32 RootIndex = D3D12Resource::InvalidRootIndex; + Uint32 Offset = D3D12Resource::InvalidOffset; + Uint32 BindPoint = D3DShaderResourceAttribs::InvalidBindPoint; + + D3D12_DESCRIPTOR_RANGE_TYPE DescriptorRangeType = GetDescriptorRangeType(ResType); + + if (pRootSig) + { + pRootSig->AllocateResourceSlot(GetShaderType(), PipelineType, Attribs, VarType, DescriptorRangeType, BindPoint, RootIndex, Offset); + VERIFY(RootIndex <= D3D12Resource::MaxRootIndex, "Root index excceeds allowed limit"); + VERIFY(BindPoint <= D3DShaderResourceAttribs::MaxBindPoint, "Bind point excceeds allowed limit"); + } + else + { + // If root signature is not provided - use artifial root signature to store + // static shader resources: + // SRVs at root index D3D12_DESCRIPTOR_RANGE_TYPE_SRV (0) + // UAVs at root index D3D12_DESCRIPTOR_RANGE_TYPE_UAV (1) + // CBVs at root index D3D12_DESCRIPTOR_RANGE_TYPE_CBV (2) + // Samplers at root index D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER (3) + + // http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-layout#Initializing-Special-Resource-Layout-for-Managing-Static-Shader-Resources + + VERIFY_EXPR(pResourceCache != nullptr); + + RootIndex = DescriptorRangeType; + Offset = Attribs.BindPoint; + BindPoint = Attribs.BindPoint; + // Resources in the static resource cache are indexed by the bind point + StaticResCacheTblSizes[RootIndex] = std::max(StaticResCacheTblSizes[RootIndex], Offset + Attribs.BindCount); + } + VERIFY(RootIndex != D3D12Resource::InvalidRootIndex, "Root index must be valid"); + VERIFY(Offset != D3D12Resource::InvalidOffset, "Offset must be valid"); + + // Immutable samplers are never copied, and SamplerId == InvalidSamplerId + Uint32 ResOffset = (ResType == CachedResourceType::Sampler) ? + GetSamplerOffset(VarType, CurrSampler[VarType]++) : + GetSrvCbvUavOffset(VarType, CurrCbvSrvUav[VarType]++); + ResIter->second = ResOffset; + auto& NewResource = GetResource(ResOffset); + ::new (&NewResource) D3D12Resource // + { + *this, + stringPool, + Attribs, + SamplerId, + VarType, + ResType, + BindPoint, + RootIndex, + Offset // + }; } else { - // If root signature is not provided - use artifial root signature to store - // static shader resources: - // SRVs at root index D3D12_DESCRIPTOR_RANGE_TYPE_SRV (0) - // UAVs at root index D3D12_DESCRIPTOR_RANGE_TYPE_UAV (1) - // CBVs at root index D3D12_DESCRIPTOR_RANGE_TYPE_CBV (2) - // Samplers at root index D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER (3) - - // http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-layout#Initializing-Special-Resource-Layout-for-Managing-Static-Shader-Resources - - VERIFY_EXPR(pResourceCache != nullptr); - - RootIndex = DescriptorRangeType; - Offset = Attribs.BindPoint; - // Resources in the static resource cache are indexed by the bind point - StaticResCacheTblSizes[RootIndex] = std::max(StaticResCacheTblSizes[RootIndex], Offset + Attribs.BindCount); + // merge with existing + auto& ExistingRes = GetResource(ResIter->second); + VERIFY_EXPR(ExistingRes.VariableType == VarType); + VERIFY_EXPR(ExistingRes.Attribs.GetInputType() == Attribs.GetInputType()); + VERIFY_EXPR(ExistingRes.Attribs.GetSRVDimension() == Attribs.GetSRVDimension()); + VERIFY_EXPR(ExistingRes.Attribs.BindCount == Attribs.BindCount); + VERIFY_EXPR(ExistingRes.Attribs.BindPoint == Attribs.BindPoint || + Attribs.BindPoint == D3DShaderResourceAttribs::InvalidBindPoint); } - VERIFY(RootIndex != D3D12Resource::InvalidRootIndex, "Root index must be valid"); - VERIFY(Offset != D3D12Resource::InvalidOffset, "Offset must be valid"); - - // Immutable samplers are never copied, and SamplerId == InvalidSamplerId - auto& NewResource = (ResType == CachedResourceType::Sampler) ? - GetSampler(VarType, CurrSampler[VarType]++) : - GetSrvCbvUav(VarType, CurrCbvSrvUav[VarType]++); - ::new (&NewResource) D3D12Resource(*this, Attribs, VarType, ResType, RootIndex, Offset, SamplerId); }; - - m_pResources->ProcessResources( - [&](const D3DShaderResourceAttribs& CB, Uint32) // - { - auto VarType = m_pResources->FindVariableType(CB, ResourceLayout); - if (IsAllowedType(VarType, AllowedTypeBits)) - AddResource(CB, CachedResourceType::CBV, VarType); - }, - [&](const D3DShaderResourceAttribs& Sam, Uint32) // - { - auto VarType = m_pResources->FindVariableType(Sam, ResourceLayout); - if (IsAllowedType(VarType, AllowedTypeBits)) + for (auto* pShader : Shaders) + { + auto pResources = pShader->GetShaderResources(); + pResources->ProcessResources( + [&](const D3DShaderResourceAttribs& CB, Uint32) // { - // The error (if any) have already been logged when counting the resources - constexpr bool LogImtblSamplerArrayError = false; - - auto ImtblSamplerInd = m_pResources->FindImmutableSampler(Sam, ResourceLayout, LogImtblSamplerArrayError); - if (ImtblSamplerInd >= 0) - { - if (pRootSig != nullptr) - pRootSig->InitImmutableSampler(m_pResources->GetShaderType(), Sam.Name, m_pResources->GetCombinedSamplerSuffix(), Sam); - } - else - { - AddResource(Sam, CachedResourceType::Sampler, VarType); - } - } - }, - [&](const D3DShaderResourceAttribs& TexSRV, Uint32) // - { - auto VarType = m_pResources->FindVariableType(TexSRV, ResourceLayout); - if (IsAllowedType(VarType, AllowedTypeBits)) + if (pLocalRootSig && pLocalRootSig->SetOrMerge(CB)) + return; + + auto VarType = pResources->FindVariableType(CB, ResourceLayout); + if (IsAllowedType(VarType, AllowedTypeBits)) + AddResource(CB, CachedResourceType::CBV, VarType); + }, + [&](const D3DShaderResourceAttribs& Sam, Uint32) // { - static_assert(SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES == 3, "Unexpected number of shader variable types"); - VERIFY(CurrSampler[SHADER_RESOURCE_VARIABLE_TYPE_STATIC] + CurrSampler[SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE] + CurrSampler[SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC] == GetTotalSamplerCount(), "All samplers must be initialized before texture SRVs"); - - Uint32 SamplerId = D3D12Resource::InvalidSamplerId; - if (TexSRV.IsCombinedWithSampler()) + auto VarType = pResources->FindVariableType(Sam, ResourceLayout); + if (IsAllowedType(VarType, AllowedTypeBits)) { - const auto& SamplerAttribs = m_pResources->GetCombinedSampler(TexSRV); - auto SamplerVarType = m_pResources->FindVariableType(SamplerAttribs, ResourceLayout); - DEV_CHECK_ERR(SamplerVarType == VarType, - "The type (", GetShaderVariableTypeLiteralName(VarType), ") of texture SRV variable '", TexSRV.Name, - "' is not consistent with the type (", GetShaderVariableTypeLiteralName(SamplerVarType), - ") of the sampler '", SamplerAttribs.Name, "' that is assigned to it"); - // The error (if any) have already been logged when counting the resources constexpr bool LogImtblSamplerArrayError = false; - - auto ImtblSamplerInd = m_pResources->FindImmutableSampler(SamplerAttribs, ResourceLayout, LogImtblSamplerArrayError); + const auto ImtblSamplerInd = pResources->FindImmutableSampler(Sam, ResourceLayout, LogImtblSamplerArrayError); if (ImtblSamplerInd >= 0) { - // Immutable samplers are never copied, and SamplerId == InvalidSamplerId -#ifdef DILIGENT_DEBUG - auto SamplerCount = GetTotalSamplerCount(); - for (Uint32 s = 0; s < SamplerCount; ++s) - { - const auto& Sampler = GetSampler(s); - if (strcmp(Sampler.Attribs.Name, SamplerAttribs.Name) == 0) - LOG_ERROR("Immutable sampler '", Sampler.Attribs.Name, "' was found among resources. This seems to be a bug"); - } -#endif + if (pRootSig != nullptr) + pRootSig->InitImmutableSampler(pResources->GetShaderType(), Sam.Name, pResources->GetCombinedSamplerSuffix(), Sam); } else { - auto SamplerCount = GetTotalSamplerCount(); - bool SamplerFound = false; - for (SamplerId = 0; SamplerId < SamplerCount; ++SamplerId) + AddResource(Sam, CachedResourceType::Sampler, VarType); + } + } + }, + [&](const D3DShaderResourceAttribs& TexSRV, Uint32) // + { + auto VarType = pResources->FindVariableType(TexSRV, ResourceLayout); + if (IsAllowedType(VarType, AllowedTypeBits)) + { + static_assert(SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES == 3, "Unexpected number of shader variable types"); + VERIFY(CurrSampler[SHADER_RESOURCE_VARIABLE_TYPE_STATIC] + CurrSampler[SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE] + CurrSampler[SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC] == GetTotalSamplerCount(), "All samplers must be initialized before texture SRVs"); + + Uint32 SamplerId = D3DShaderResourceAttribs::InvalidSamplerId; + if (TexSRV.IsCombinedWithSampler()) + { + const auto& SamplerAttribs = pResources->GetCombinedSampler(TexSRV); + auto SamplerVarType = pResources->FindVariableType(SamplerAttribs, ResourceLayout); + DEV_CHECK_ERR(SamplerVarType == VarType, + "The type (", GetShaderVariableTypeLiteralName(VarType), ") of texture SRV variable '", TexSRV.Name, + "' is not consistent with the type (", GetShaderVariableTypeLiteralName(SamplerVarType), + ") of the sampler '", SamplerAttribs.Name, "' that is assigned to it"); + + // The error (if any) have already been logged when counting the resources + constexpr bool LogImtblSamplerArrayError = false; + const auto ImtblSamplerInd = pResources->FindImmutableSampler(SamplerAttribs, ResourceLayout, LogImtblSamplerArrayError); + if (ImtblSamplerInd >= 0) { - const auto& Sampler = GetSampler(SamplerId); - SamplerFound = strcmp(Sampler.Attribs.Name, SamplerAttribs.Name) == 0; - if (SamplerFound) - break; + // Immutable samplers are never copied, and SamplerId == InvalidSamplerId +#ifdef DILIGENT_DEBUG + auto SamplerCount = GetTotalSamplerCount(); + for (Uint32 s = 0; s < SamplerCount; ++s) + { + const auto& Sampler = GetSampler(s); + if (strcmp(Sampler.Attribs.Name, SamplerAttribs.Name) == 0) + LOG_ERROR("Immutable sampler '", Sampler.Attribs.Name, "' was found among resources. This seems to be a bug"); + } +#endif } - - if (!SamplerFound) + else { - LOG_ERROR("Unable to find sampler '", SamplerAttribs.Name, "' assigned to texture SRV '", TexSRV.Name, "' in the list of already created resources. This seems to be a bug."); - SamplerId = D3D12Resource::InvalidSamplerId; + auto SamplerCount = GetTotalSamplerCount(); + bool SamplerFound = false; + for (SamplerId = 0; SamplerId < SamplerCount; ++SamplerId) + { + const auto& Sampler = GetSampler(SamplerId); + SamplerFound = strcmp(Sampler.Attribs.Name, SamplerAttribs.Name) == 0; + if (SamplerFound) + break; + } + + if (!SamplerFound) + { + LOG_ERROR("Unable to find sampler '", SamplerAttribs.Name, "' assigned to texture SRV '", TexSRV.Name, "' in the list of already created resources. This seems to be a bug."); + SamplerId = D3DShaderResourceAttribs::InvalidSamplerId; + } + VERIFY(SamplerId <= D3DShaderResourceAttribs::MaxSamplerId, "Sampler index excceeds allowed limit"); } - VERIFY(SamplerId <= D3D12Resource::MaxSamplerId, "Sampler index excceeds allowed limit"); } + AddResource(TexSRV, CachedResourceType::TexSRV, VarType, SamplerId); } - AddResource(TexSRV, CachedResourceType::TexSRV, VarType, SamplerId); - } - }, - [&](const D3DShaderResourceAttribs& TexUAV, Uint32) // - { - auto VarType = m_pResources->FindVariableType(TexUAV, ResourceLayout); - if (IsAllowedType(VarType, AllowedTypeBits)) - AddResource(TexUAV, CachedResourceType::TexUAV, VarType); - }, - [&](const D3DShaderResourceAttribs& BufSRV, Uint32) // - { - auto VarType = m_pResources->FindVariableType(BufSRV, ResourceLayout); - if (IsAllowedType(VarType, AllowedTypeBits)) - AddResource(BufSRV, CachedResourceType::BufSRV, VarType); - }, - [&](const D3DShaderResourceAttribs& BufUAV, Uint32) // - { - auto VarType = m_pResources->FindVariableType(BufUAV, ResourceLayout); - if (IsAllowedType(VarType, AllowedTypeBits)) - AddResource(BufUAV, CachedResourceType::BufUAV, VarType); - } // - ); + }, + [&](const D3DShaderResourceAttribs& TexUAV, Uint32) // + { + auto VarType = pResources->FindVariableType(TexUAV, ResourceLayout); + if (IsAllowedType(VarType, AllowedTypeBits)) + AddResource(TexUAV, CachedResourceType::TexUAV, VarType); + }, + [&](const D3DShaderResourceAttribs& BufSRV, Uint32) // + { + auto VarType = pResources->FindVariableType(BufSRV, ResourceLayout); + if (IsAllowedType(VarType, AllowedTypeBits)) + AddResource(BufSRV, CachedResourceType::BufSRV, VarType); + }, + [&](const D3DShaderResourceAttribs& BufUAV, Uint32) // + { + auto VarType = pResources->FindVariableType(BufUAV, ResourceLayout); + if (IsAllowedType(VarType, AllowedTypeBits)) + AddResource(BufUAV, CachedResourceType::BufUAV, VarType); + }, + [&](const D3DShaderResourceAttribs& AccelStruct, Uint32) // + { + auto VarType = pResources->FindVariableType(AccelStruct, ResourceLayout); + if (IsAllowedType(VarType, AllowedTypeBits)) + AddResource(AccelStruct, CachedResourceType::AccelStruct, VarType); + } // + ); + } #ifdef DILIGENT_DEBUG + VERIFY_EXPR(stringPool.GetRemainingSize() == 0); for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(VarType + 1)) { VERIFY(CurrCbvSrvUav[VarType] == CbvSrvUavCount[VarType], "Not all Srv/Cbv/Uavs are initialized, which result in a crash when dtor is called"); @@ -362,12 +453,12 @@ void ShaderResourceLayoutD3D12::Initialize(ID3D12Device* // http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-cache#Initializing-the-Cache-for-Static-Shader-Resources // http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-cache#Initializing-Shader-Objects VERIFY_EXPR(pRootSig == nullptr); - pResourceCache->Initialize(GetRawAllocator(), _countof(StaticResCacheTblSizes), StaticResCacheTblSizes); + pResourceCache->Initialize(GetRawAllocator(), static_cast<Uint32>(StaticResCacheTblSizes.size()), StaticResCacheTblSizes.data()); #ifdef DILIGENT_DEBUG - pResourceCache->GetRootTable(D3D12_DESCRIPTOR_RANGE_TYPE_SRV).SetDebugAttribs(StaticResCacheTblSizes[D3D12_DESCRIPTOR_RANGE_TYPE_SRV], D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, m_pResources->GetShaderType()); - pResourceCache->GetRootTable(D3D12_DESCRIPTOR_RANGE_TYPE_UAV).SetDebugAttribs(StaticResCacheTblSizes[D3D12_DESCRIPTOR_RANGE_TYPE_UAV], D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, m_pResources->GetShaderType()); - pResourceCache->GetRootTable(D3D12_DESCRIPTOR_RANGE_TYPE_CBV).SetDebugAttribs(StaticResCacheTblSizes[D3D12_DESCRIPTOR_RANGE_TYPE_CBV], D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, m_pResources->GetShaderType()); - pResourceCache->GetRootTable(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER).SetDebugAttribs(StaticResCacheTblSizes[D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER], D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, m_pResources->GetShaderType()); + pResourceCache->GetRootTable(D3D12_DESCRIPTOR_RANGE_TYPE_SRV).SetDebugAttribs(StaticResCacheTblSizes[D3D12_DESCRIPTOR_RANGE_TYPE_SRV], D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, GetShaderType()); + pResourceCache->GetRootTable(D3D12_DESCRIPTOR_RANGE_TYPE_UAV).SetDebugAttribs(StaticResCacheTblSizes[D3D12_DESCRIPTOR_RANGE_TYPE_UAV], D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, GetShaderType()); + pResourceCache->GetRootTable(D3D12_DESCRIPTOR_RANGE_TYPE_CBV).SetDebugAttribs(StaticResCacheTblSizes[D3D12_DESCRIPTOR_RANGE_TYPE_CBV], D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, GetShaderType()); + pResourceCache->GetRootTable(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER).SetDebugAttribs(StaticResCacheTblSizes[D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER], D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, GetShaderType()); #endif } } @@ -383,7 +474,7 @@ void ShaderResourceLayoutD3D12::D3D12Resource::CacheCB(IDeviceObject* // We cannot use ValidatedCast<> here as the resource retrieved from the // resource mapping can be of wrong type - RefCntAutoPtr<BufferD3D12Impl> pBuffD3D12(pBuffer, IID_BufferD3D12); + RefCntAutoPtr<BufferD3D12Impl> pBuffD3D12{pBuffer, IID_BufferD3D12}; #ifdef DILIGENT_DEVELOPMENT VerifyConstantBufferBinding(Attribs, GetVariableType(), ArrayInd, pBuffer, pBuffD3D12.RawPtr(), DstRes.pObject.RawPtr(), ParentResLayout.GetShaderName()); #endif @@ -421,7 +512,6 @@ void ShaderResourceLayoutD3D12::D3D12Resource::CacheCB(IDeviceObject* } } - template <typename TResourceViewType> struct ResourceViewTraits {}; @@ -504,7 +594,7 @@ void ShaderResourceLayoutD3D12::D3D12Resource::CacheSampler(IDeviceObject* VERIFY(Attribs.IsValidBindPoint(), "Invalid bind point"); VERIFY_EXPR(ArrayIndex < Attribs.BindCount); - RefCntAutoPtr<ISamplerD3D12> pSamplerD3D12(pSampler, IID_SamplerD3D12); + RefCntAutoPtr<ISamplerD3D12> pSamplerD3D12{pSampler, IID_SamplerD3D12}; if (pSamplerD3D12) { if (GetVariableType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC && DstSam.pObject != nullptr) @@ -546,13 +636,49 @@ void ShaderResourceLayoutD3D12::D3D12Resource::CacheSampler(IDeviceObject* } } +void ShaderResourceLayoutD3D12::D3D12Resource::CacheAccelStruct(IDeviceObject* pTLAS, + ShaderResourceCacheD3D12::Resource& DstRes, + Uint32 ArrayIndex, + D3D12_CPU_DESCRIPTOR_HANDLE ShdrVisibleHeapCPUDescriptorHandle) const +{ + VERIFY(Attribs.IsValidBindPoint(), "Invalid bind point"); + VERIFY_EXPR(ArrayIndex < Attribs.BindCount); + + RefCntAutoPtr<ITopLevelASD3D12> pTLASD3D12{pTLAS, IID_TopLevelASD3D12}; + if (pTLASD3D12) + { + if (GetVariableType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC && DstRes.pObject != nullptr) + { + // Do not update resource if one is already bound unless it is dynamic. This may be + // dangerous as CopyDescriptorsSimple() may interfere with GPU reading the same descriptor. + return; + } + + DstRes.Type = GetResType(); + DstRes.CPUDescriptorHandle = pTLASD3D12->GetCPUDescriptorHandle(); + VERIFY(DstRes.CPUDescriptorHandle.ptr != 0, "No relevant D3D12 resource"); + + if (ShdrVisibleHeapCPUDescriptorHandle.ptr != 0) + { + // Dynamic resources are assigned descriptor in the GPU-visible heap at every draw call, and + // the descriptor is copied by the RootSignature when resources are committed + VERIFY(DstRes.pObject == nullptr, "Static and mutable resource descriptors must be copied only once"); + + ID3D12Device* pd3d12Device = ParentResLayout.m_pd3d12Device; + pd3d12Device->CopyDescriptorsSimple(1, ShdrVisibleHeapCPUDescriptorHandle, DstRes.CPUDescriptorHandle, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + } + + DstRes.pObject = std::move(pTLASD3D12); + } +} + const ShaderResourceLayoutD3D12::D3D12Resource& ShaderResourceLayoutD3D12::GetAssignedSampler(const D3D12Resource& TexSrv) const { VERIFY(TexSrv.GetResType() == CachedResourceType::TexSRV, "Unexpected resource type: texture SRV is expected"); - VERIFY(TexSrv.ValidSamplerAssigned(), "Texture SRV has no associated sampler"); - const auto& SamInfo = GetSampler(TexSrv.SamplerId); + VERIFY(TexSrv.Attribs.IsCombinedWithSampler(), "Texture SRV has no associated sampler"); + const auto& SamInfo = GetSampler(TexSrv.Attribs.GetCombinedSamplerId()); VERIFY(SamInfo.GetVariableType() == TexSrv.GetVariableType(), "Inconsistent texture and sampler variable types"); - VERIFY(StreqSuff(SamInfo.Attribs.Name, TexSrv.Attribs.Name, m_pResources->GetCombinedSamplerSuffix()), "Sampler name '", SamInfo.Attribs.Name, "' does not match texture name '", TexSrv.Attribs.Name, '\''); + //VERIFY(StreqSuff(SamInfo.Name, TexSrv.Name, GetCombinedSamplerSuffix()), "Sampler name '", SamInfo.Name, "' does not match texture name '", TexSrv.Name, '\''); return SamInfo; } @@ -570,7 +696,7 @@ void ShaderResourceLayoutD3D12::D3D12Resource::BindResource(IDeviceObject* const bool IsSampler = GetResType() == CachedResourceType::Sampler; auto DescriptorHeapType = IsSampler ? D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER : D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; - auto& DstRes = ResourceCache.GetRootTable(RootIndex).GetResource(OffsetFromTableStart + ArrayIndex, DescriptorHeapType, ParentResLayout.m_pResources->GetShaderType()); + auto& DstRes = ResourceCache.GetRootTable(RootIndex).GetResource(OffsetFromTableStart + ArrayIndex, DescriptorHeapType, ParentResLayout.GetShaderType()); auto ShdrVisibleHeapCPUDescriptorHandle = IsSampler ? ResourceCache.GetShaderVisibleTableCPUDescriptorHandle<D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER>(RootIndex, OffsetFromTableStart + ArrayIndex) : @@ -605,6 +731,7 @@ void ShaderResourceLayoutD3D12::D3D12Resource::BindResource(IDeviceObject* if (pObj) { + static_assert(static_cast<int>(CachedResourceType::NumTypes) == 7, "Please update this function to handle the new resource type"); switch (GetResType()) { case CachedResourceType::CBV: @@ -616,16 +743,16 @@ void ShaderResourceLayoutD3D12::D3D12Resource::BindResource(IDeviceObject* pObj, DstRes, ArrayIndex, ShdrVisibleHeapCPUDescriptorHandle, TEXTURE_VIEW_SHADER_RESOURCE, [&](ITextureViewD3D12* pTexView) // { - if (ValidSamplerAssigned()) + if (Attribs.IsCombinedWithSampler()) { auto& Sam = ParentResLayout.GetAssignedSampler(*this); - //VERIFY( !Sam.Attribs.IsImmutableSampler(), "Immutable samplers should never be assigned space in the cache" ); + //VERIFY( !Sam.IsImmutableSampler(), "Immutable samplers should never be assigned space in the cache" ); VERIFY_EXPR(Attribs.BindCount == Sam.Attribs.BindCount || Sam.Attribs.BindCount == 1); auto SamplerArrInd = Sam.Attribs.BindCount > 1 ? ArrayIndex : 0; auto ShdrVisibleSamplerHeapCPUDescriptorHandle = ResourceCache.GetShaderVisibleTableCPUDescriptorHandle<D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER>(Sam.RootIndex, Sam.OffsetFromTableStart + SamplerArrInd); - auto& DstSam = ResourceCache.GetRootTable(Sam.RootIndex).GetResource(Sam.OffsetFromTableStart + SamplerArrInd, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, ParentResLayout.m_pResources->GetShaderType()); + auto& DstSam = ResourceCache.GetRootTable(Sam.RootIndex).GetResource(Sam.OffsetFromTableStart + SamplerArrInd, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, ParentResLayout.GetShaderType()); #ifdef DILIGENT_DEBUG { if (ResourceCache.DbgGetContentType() == ShaderResourceCacheD3D12::DbgCacheContentType::StaticShaderResources) @@ -675,6 +802,10 @@ void ShaderResourceLayoutD3D12::D3D12Resource::BindResource(IDeviceObject* CacheSampler(pObj, DstRes, ArrayIndex, ShdrVisibleHeapCPUDescriptorHandle); break; + case CachedResourceType::AccelStruct: + CacheAccelStruct(pObj, DstRes, ArrayIndex, ShdrVisibleHeapCPUDescriptorHandle); + break; + default: UNEXPECTED("Unknown resource type ", static_cast<Int32>(GetResType())); } } @@ -684,12 +815,12 @@ void ShaderResourceLayoutD3D12::D3D12Resource::BindResource(IDeviceObject* LOG_ERROR_MESSAGE("Shader variable '", Attribs.Name, "' in shader '", ParentResLayout.GetShaderName(), "' is not dynamic but is being reset to null. This is an error and may cause unpredicted behavior. Use another shader resource binding instance or label the variable as dynamic if you need to bind another resource."); DstRes = ShaderResourceCacheD3D12::Resource{}; - if (ValidSamplerAssigned()) + if (Attribs.IsCombinedWithSampler()) { auto& Sam = ParentResLayout.GetAssignedSampler(*this); D3D12_CPU_DESCRIPTOR_HANDLE NullHandle = {0}; auto SamplerArrInd = Sam.Attribs.BindCount > 1 ? ArrayIndex : 0; - auto& DstSam = ResourceCache.GetRootTable(Sam.RootIndex).GetResource(Sam.OffsetFromTableStart + SamplerArrInd, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, ParentResLayout.m_pResources->GetShaderType()); + auto& DstSam = ResourceCache.GetRootTable(Sam.RootIndex).GetResource(Sam.OffsetFromTableStart + SamplerArrInd, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, ParentResLayout.GetShaderType()); if (DstSam.pObject != nullptr && Sam.GetVariableType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC) LOG_ERROR_MESSAGE("Sampler variable '", Sam.Attribs.Name, "' in shader '", ParentResLayout.GetShaderName(), "' is not dynamic but is being reset to null. This is an error and may cause unpredicted behavior. Use another shader resource binding instance or label the variable as dynamic if you need to bind another sampler."); DstSam = ShaderResourceCacheD3D12::Resource{}; @@ -709,7 +840,7 @@ bool ShaderResourceLayoutD3D12::D3D12Resource::IsBound(Uint32 ArrayIndex, const const auto& CachedRes = RootTable.GetResource(OffsetFromTableStart + ArrayIndex, GetResType() == CachedResourceType::Sampler ? D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER : D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, - ParentResLayout.m_pResources->GetShaderType()); + ParentResLayout.GetShaderType()); if (CachedRes.pObject != nullptr) { VERIFY(CachedRes.CPUDescriptorHandle.ptr != 0 || CachedRes.pObject.RawPtr<BufferD3D12Impl>()->GetDesc().Usage == USAGE_DYNAMIC, "No relevant descriptor handle"); @@ -721,7 +852,6 @@ bool ShaderResourceLayoutD3D12::D3D12Resource::IsBound(Uint32 ArrayIndex, const return false; } - void ShaderResourceLayoutD3D12::CopyStaticResourceDesriptorHandles(const ShaderResourceCacheD3D12& SrcCache, const ShaderResourceLayoutD3D12& DstLayout, ShaderResourceCacheD3D12& DstCache) const { // Static shader resources are stored as follows: @@ -746,11 +876,11 @@ void ShaderResourceLayoutD3D12::CopyStaticResourceDesriptorHandles(const ShaderR // D3D12_DESCRIPTOR_RANGE_TYPE_SRV = 0, // D3D12_DESCRIPTOR_RANGE_TYPE_UAV = 1 // D3D12_DESCRIPTOR_RANGE_TYPE_CBV = 2 - const auto& SrcRes = SrcCache.GetRootTable(RangeType).GetResource(BindPoint, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, m_pResources->GetShaderType()); + const auto& SrcRes = SrcCache.GetRootTable(RangeType).GetResource(BindPoint, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, GetShaderType()); if (!SrcRes.pObject) LOG_ERROR_MESSAGE("No resource is assigned to static shader variable '", res.Attribs.GetPrintName(ArrInd), "' in shader '", GetShaderName(), "'."); // Destination resource is at the root index and offset defined by the resource layout - auto& DstRes = DstCache.GetRootTable(res.RootIndex).GetResource(res.OffsetFromTableStart + ArrInd, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, m_pResources->GetShaderType()); + auto& DstRes = DstCache.GetRootTable(res.RootIndex).GetResource(res.OffsetFromTableStart + ArrInd, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, GetShaderType()); if (DstRes.pObject != SrcRes.pObject) { @@ -789,11 +919,11 @@ void ShaderResourceLayoutD3D12::CopyStaticResourceDesriptorHandles(const ShaderR } } - if (res.ValidSamplerAssigned()) + if (res.Attribs.IsCombinedWithSampler()) { const auto& SamInfo = DstLayout.GetAssignedSampler(res); - //VERIFY(!SamInfo.Attribs.IsImmutableSampler(), "Immutable samplers should never be assigned space in the cache"); + //VERIFY(!SamInfo.IsImmutableSampler(), "Immutable samplers should never be assigned space in the cache"); VERIFY(SamInfo.Attribs.IsValidBindPoint(), "Sampler bind point must be valid"); VERIFY_EXPR(SamInfo.Attribs.BindCount == res.Attribs.BindCount || SamInfo.Attribs.BindCount == 1); @@ -810,10 +940,10 @@ void ShaderResourceLayoutD3D12::CopyStaticResourceDesriptorHandles(const ShaderR auto BindPoint = SamInfo.Attribs.BindPoint + ArrInd; // Source sampler in the static resource cache is in the root table at index 3 // (D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER = 3), at offset BindPoint - const auto& SrcSampler = SrcCache.GetRootTable(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER).GetResource(BindPoint, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, m_pResources->GetShaderType()); + const auto& SrcSampler = SrcCache.GetRootTable(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER).GetResource(BindPoint, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, GetShaderType()); if (!SrcSampler.pObject) LOG_ERROR_MESSAGE("No sampler assigned to static shader variable '", SamInfo.Attribs.GetPrintName(ArrInd), "' in shader '", GetShaderName(), "'."); - auto& DstSampler = DstCache.GetRootTable(SamInfo.RootIndex).GetResource(SamInfo.OffsetFromTableStart + ArrInd, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, m_pResources->GetShaderType()); + auto& DstSampler = DstCache.GetRootTable(SamInfo.RootIndex).GetResource(SamInfo.OffsetFromTableStart + ArrInd, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, GetShaderType()); if (DstSampler.pObject != SrcSampler.pObject) { @@ -854,7 +984,7 @@ bool ShaderResourceLayoutD3D12::dvpVerifyBindings(const ShaderResourceCacheD3D12 for (Uint32 ArrInd = 0; ArrInd < res.Attribs.BindCount; ++ArrInd) { - const auto& CachedRes = ResourceCache.GetRootTable(res.RootIndex).GetResource(res.OffsetFromTableStart + ArrInd, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, m_pResources->GetShaderType()); + const auto& CachedRes = ResourceCache.GetRootTable(res.RootIndex).GetResource(res.OffsetFromTableStart + ArrInd, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, GetShaderType()); if (CachedRes.pObject) VERIFY(CachedRes.Type == res.GetResType(), "Inconsistent cached resource types"); else @@ -868,13 +998,13 @@ bool ShaderResourceLayoutD3D12::dvpVerifyBindings(const ShaderResourceCacheD3D12 BindingsOK = false; } - if (res.Attribs.BindCount > 1 && res.ValidSamplerAssigned()) + if (res.Attribs.BindCount > 1 && res.Attribs.IsCombinedWithSampler()) { // Verify that if single sampler is used for all texture array elements, all samplers set in the resource views are consistent const auto& SamInfo = GetAssignedSampler(res); if (SamInfo.Attribs.BindCount == 1) { - const auto& CachedSampler = ResourceCache.GetRootTable(SamInfo.RootIndex).GetResource(SamInfo.OffsetFromTableStart, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, m_pResources->GetShaderType()); + const auto& CachedSampler = ResourceCache.GetRootTable(SamInfo.RootIndex).GetResource(SamInfo.OffsetFromTableStart, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, GetShaderType()); // Conversion must always succeed as the type is verified when resource is bound to the variable if (const auto* pTexView = CachedRes.pObject.RawPtr<const TextureViewD3D12Impl>()) { @@ -916,16 +1046,16 @@ bool ShaderResourceLayoutD3D12::dvpVerifyBindings(const ShaderResourceCacheD3D12 # endif } - if (res.ValidSamplerAssigned()) + if (res.Attribs.IsCombinedWithSampler()) { VERIFY(res.GetResType() == CachedResourceType::TexSRV, "Sampler can only be assigned to a texture SRV"); const auto& SamInfo = GetAssignedSampler(res); - //VERIFY(!SamInfo.Attribs.IsImmutableSampler(), "Immutable samplers should never be assigned space in the cache" ); + //VERIFY(!SamInfo.IsImmutableSampler(), "Immutable samplers should never be assigned space in the cache" ); VERIFY(SamInfo.Attribs.IsValidBindPoint(), "Sampler bind point must be valid"); for (Uint32 ArrInd = 0; ArrInd < SamInfo.Attribs.BindCount; ++ArrInd) { - const auto& CachedSampler = ResourceCache.GetRootTable(SamInfo.RootIndex).GetResource(SamInfo.OffsetFromTableStart + ArrInd, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, m_pResources->GetShaderType()); + const auto& CachedSampler = ResourceCache.GetRootTable(SamInfo.RootIndex).GetResource(SamInfo.OffsetFromTableStart + ArrInd, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, GetShaderType()); if (CachedSampler.pObject) VERIFY(CachedSampler.Type == CachedResourceType::Sampler, "Incorrect cached sampler type"); else @@ -967,7 +1097,7 @@ bool ShaderResourceLayoutD3D12::dvpVerifyBindings(const ShaderResourceCacheD3D12 for (Uint32 ArrInd = 0; ArrInd < sam.Attribs.BindCount; ++ArrInd) { - const auto& CachedSampler = ResourceCache.GetRootTable(sam.RootIndex).GetResource(sam.OffsetFromTableStart + ArrInd, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, m_pResources->GetShaderType()); + const auto& CachedSampler = ResourceCache.GetRootTable(sam.RootIndex).GetResource(sam.OffsetFromTableStart + ArrInd, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, GetShaderType()); if (CachedSampler.pObject) VERIFY(CachedSampler.Type == CachedResourceType::Sampler, "Incorrect cached sampler type"); else @@ -985,4 +1115,21 @@ bool ShaderResourceLayoutD3D12::dvpVerifyBindings(const ShaderResourceCacheD3D12 } #endif +bool ShaderResourceLayoutD3D12::IsCompatibleWith(const ShaderResourceLayoutD3D12& ResLayout) const +{ + if (GetTotalResourceCount() != ResLayout.GetTotalResourceCount()) + return false; + + for (Uint32 i = 0; i < GetTotalResourceCount(); ++i) + { + const auto& lRes = GetResource(i); + const auto& rRes = ResLayout.GetResource(i); + + if (!lRes.Attribs.IsCompatibleWith(rRes.Attribs)) + return false; + } + + return true; +} + } // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/src/ShaderResourcesD3D12.cpp b/Graphics/GraphicsEngineD3D12/src/ShaderResourcesD3D12.cpp index 26f889e5..093a5480 100644 --- a/Graphics/GraphicsEngineD3D12/src/ShaderResourcesD3D12.cpp +++ b/Graphics/GraphicsEngineD3D12/src/ShaderResourcesD3D12.cpp @@ -106,12 +106,13 @@ ShaderResourcesD3D12::ShaderResourcesD3D12(ID3DBlob* pShaderBytecode, { public: // clang-format off - void OnNewCB (const D3DShaderResourceAttribs& CBAttribs) {} - void OnNewTexUAV (const D3DShaderResourceAttribs& TexUAV) {} - void OnNewBuffUAV(const D3DShaderResourceAttribs& BuffUAV) {} - void OnNewBuffSRV(const D3DShaderResourceAttribs& BuffSRV) {} - void OnNewSampler(const D3DShaderResourceAttribs& SamplerAttribs){} - void OnNewTexSRV (const D3DShaderResourceAttribs& TexAttribs) {} + void OnNewCB (const D3DShaderResourceAttribs& CBAttribs) {} + void OnNewTexUAV (const D3DShaderResourceAttribs& TexUAV) {} + void OnNewBuffUAV (const D3DShaderResourceAttribs& BuffUAV) {} + void OnNewBuffSRV (const D3DShaderResourceAttribs& BuffSRV) {} + void OnNewSampler (const D3DShaderResourceAttribs& SamplerAttribs){} + void OnNewTexSRV (const D3DShaderResourceAttribs& TexAttribs) {} + void OnNewAccelStruct(const D3DShaderResourceAttribs& ASAttribs) {} // clang-format on }; diff --git a/Graphics/GraphicsEngineD3D12/src/TextureD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/TextureD3D12Impl.cpp index 22829770..1c15b351 100644 --- a/Graphics/GraphicsEngineD3D12/src/TextureD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/TextureD3D12Impl.cpp @@ -424,7 +424,7 @@ void TextureD3D12Impl::CreateViewInternal(const struct TextureViewDesc& ViewDesc VERIFY(&TexViewAllocator == &m_dbgTexViewObjAllocator, "Texture view allocator does not match allocator provided during texture initialization"); auto UpdatedViewDesc = ViewDesc; - CorrectTextureViewDesc(UpdatedViewDesc); + ValidatedAndCorrectTextureViewDesc(m_Desc, UpdatedViewDesc); DescriptorHeapAllocation ViewDescriptor; switch (ViewDesc.ViewType) diff --git a/Graphics/GraphicsEngineD3D12/src/TopLevelASD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/TopLevelASD3D12Impl.cpp new file mode 100644 index 00000000..dff2dcfb --- /dev/null +++ b/Graphics/GraphicsEngineD3D12/src/TopLevelASD3D12Impl.cpp @@ -0,0 +1,135 @@ +/* + * Copyright 2019-2020 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include "pch.h" +#include "TopLevelASD3D12Impl.hpp" +#include "RenderDeviceD3D12Impl.hpp" +#include "D3D12TypeConversions.hpp" +#include "GraphicsAccessories.hpp" +#include "DXGITypeConversions.hpp" +#include "StringTools.hpp" + +namespace Diligent +{ + +TopLevelASD3D12Impl::TopLevelASD3D12Impl(IReferenceCounters* pRefCounters, + class RenderDeviceD3D12Impl* pDeviceD3D12, + const TopLevelASDesc& Desc) : + TTopLevelASBase{pRefCounters, pDeviceD3D12, Desc} +{ + auto* pd3d12Device = pDeviceD3D12->GetD3D12Device5(); + UINT64 ResultDataMaxSizeInBytes = 0; + + if (m_Desc.CompactedSize > 0) + { + ResultDataMaxSizeInBytes = m_Desc.CompactedSize; + } + else + { + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO d3d12TopLevelPrebuildInfo = {}; + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS d3d12TopLevelInputs = {}; + + d3d12TopLevelInputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL; + d3d12TopLevelInputs.Flags = BuildASFlagsToD3D12ASBuildFlags(m_Desc.Flags); + d3d12TopLevelInputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY; + d3d12TopLevelInputs.NumDescs = m_Desc.MaxInstanceCount; + + VERIFY_EXPR(m_Desc.MaxInstanceCount <= D3D12_RAYTRACING_MAX_INSTANCES_PER_TOP_LEVEL_ACCELERATION_STRUCTURE); + + pd3d12Device->GetRaytracingAccelerationStructurePrebuildInfo(&d3d12TopLevelInputs, &d3d12TopLevelPrebuildInfo); + if (d3d12TopLevelPrebuildInfo.ResultDataMaxSizeInBytes == 0) + LOG_ERROR_AND_THROW("Failed to get ray tracing acceleration structure prebuild info"); + + ResultDataMaxSizeInBytes = d3d12TopLevelPrebuildInfo.ResultDataMaxSizeInBytes; + + m_ScratchSize.Build = static_cast<Uint32>(d3d12TopLevelPrebuildInfo.ScratchDataSizeInBytes); + m_ScratchSize.Update = static_cast<Uint32>(d3d12TopLevelPrebuildInfo.UpdateScratchDataSizeInBytes); + } + + D3D12_HEAP_PROPERTIES HeapProps; + HeapProps.Type = D3D12_HEAP_TYPE_DEFAULT; + HeapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; + HeapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; + HeapProps.CreationNodeMask = 1; + HeapProps.VisibleNodeMask = 1; + + D3D12_RESOURCE_DESC d3d12ASDesc = {}; + d3d12ASDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + d3d12ASDesc.Alignment = 0; + d3d12ASDesc.Width = ResultDataMaxSizeInBytes; + d3d12ASDesc.Height = 1; + d3d12ASDesc.DepthOrArraySize = 1; + d3d12ASDesc.MipLevels = 1; + d3d12ASDesc.Format = DXGI_FORMAT_UNKNOWN; + d3d12ASDesc.SampleDesc.Count = 1; + d3d12ASDesc.SampleDesc.Quality = 0; + d3d12ASDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + d3d12ASDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; + + auto hr = pd3d12Device->CreateCommittedResource(&HeapProps, D3D12_HEAP_FLAG_NONE, + &d3d12ASDesc, D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE, nullptr, + __uuidof(m_pd3d12Resource), + reinterpret_cast<void**>(static_cast<ID3D12Resource**>(&m_pd3d12Resource))); + if (FAILED(hr)) + LOG_ERROR_AND_THROW("Failed to create D3D12 Top-level acceleration structure"); + + if (*m_Desc.Name != 0) + m_pd3d12Resource->SetName(WidenString(m_Desc.Name).c_str()); + + m_DescriptorHandle = pDeviceD3D12->AllocateDescriptor(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + + D3D12_SHADER_RESOURCE_VIEW_DESC d3d12SRVDesc; + d3d12SRVDesc.ViewDimension = D3D12_SRV_DIMENSION_RAYTRACING_ACCELERATION_STRUCTURE; + d3d12SRVDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + d3d12SRVDesc.Format = DXGI_FORMAT_UNKNOWN; + d3d12SRVDesc.RaytracingAccelerationStructure.Location = GetGPUAddress(); + pd3d12Device->CreateShaderResourceView(nullptr, &d3d12SRVDesc, m_DescriptorHandle.GetCpuHandle()); + + DEV_CHECK_ERR(GetGPUAddress() % D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BYTE_ALIGNMENT == 0, "GPU virtual address is expect to be at least 256-byte aligned"); + + SetState(RESOURCE_STATE_BUILD_AS_READ); +} + +TopLevelASD3D12Impl::TopLevelASD3D12Impl(IReferenceCounters* pRefCounters, + class RenderDeviceD3D12Impl* pDeviceD3D12, + const TopLevelASDesc& Desc, + RESOURCE_STATE InitialState, + ID3D12Resource* pd3d12TLAS) : + TTopLevelASBase{pRefCounters, pDeviceD3D12, Desc} +{ + m_pd3d12Resource = pd3d12TLAS; + SetState(InitialState); +} + +TopLevelASD3D12Impl::~TopLevelASD3D12Impl() +{ + // D3D12 object can only be destroyed when it is no longer used by the GPU + auto* pDeviceD3D12Impl = ValidatedCast<RenderDeviceD3D12Impl>(GetDevice()); + pDeviceD3D12Impl->SafeReleaseDeviceObject(std::move(m_pd3d12Resource), m_Desc.CommandQueueMask); +} + +} // namespace Diligent |
