From dc9a4e784c8bb97fbb16a01624c7b8f0544977a4 Mon Sep 17 00:00:00 2001 From: azhirnov Date: Tue, 11 Aug 2020 22:48:23 +0300 Subject: Added mesh shader added mesh shader support to DX12 and Vulkan, added DXIL compiler for Shader Model 6.x --- Graphics/GLSLTools/src/GLSLSourceBuilder.cpp | 7 + Graphics/GLSLTools/src/SPIRVShaderResources.cpp | 16 +- Graphics/GLSLTools/src/SPIRVUtils.cpp | 14 +- .../src/GraphicsAccessories.cpp | 18 +- .../GraphicsEngine/include/DeviceContextBase.hpp | 90 ++- .../GraphicsEngine/include/PipelineStateBase.hpp | 42 +- Graphics/GraphicsEngine/include/ShaderBase.hpp | 18 +- Graphics/GraphicsEngine/interface/DeviceCaps.h | 3 + Graphics/GraphicsEngine/interface/DeviceContext.h | 85 ++ Graphics/GraphicsEngine/interface/GraphicsTypes.h | 2 +- Graphics/GraphicsEngine/interface/PipelineState.h | 36 +- Graphics/GraphicsEngine/interface/Shader.h | 17 +- .../include/DeviceContextD3D11Impl.hpp | 4 + .../src/DeviceContextD3D11Impl.cpp | 12 +- .../src/PipelineStateD3D11Impl.cpp | 2 +- .../GraphicsEngineD3D11/src/ShaderD3D11Impl.cpp | 24 +- .../src/ShaderResourcesD3D11.cpp | 889 +++++++++++---------- Graphics/GraphicsEngineD3D12/CMakeLists.txt | 8 + .../GraphicsEngineD3D12/include/CommandContext.hpp | 12 + .../include/DeviceContextD3D12Impl.hpp | 5 + .../include/RenderDeviceD3D12Impl.hpp | 1 + .../include/ShaderResourcesD3D12.hpp | 2 +- .../src/DeviceContextD3D12Impl.cpp | 34 +- .../src/PipelineStateD3D12Impl.cpp | 309 ++++--- .../src/RenderDeviceD3D12Impl.cpp | 41 + Graphics/GraphicsEngineD3D12/src/RootSignature.cpp | 64 +- .../GraphicsEngineD3D12/src/ShaderD3D12Impl.cpp | 15 +- .../src/ShaderResourcesD3D12.cpp | 36 +- Graphics/GraphicsEngineD3DBase/CMakeLists.txt | 8 + .../include/D3DShaderResourceLoader.hpp | 9 +- .../include/ShaderD3DBase.hpp | 3 +- .../include/ShaderResources.hpp | 8 +- .../GraphicsEngineD3DBase/src/ShaderD3DBase.cpp | 361 +++++++-- .../include/DeviceContextGLImpl.hpp | 4 + .../src/DeviceContextGLImpl.cpp | 12 +- .../src/PipelineStateGLImpl.cpp | 2 +- .../include/DeviceContextVkImpl.hpp | 4 + .../include/PipelineStateVkImpl.hpp | 2 +- .../VulkanUtilities/VulkanCommandBuffer.hpp | 26 + .../include/VulkanUtilities/VulkanInstance.hpp | 2 + .../VulkanUtilities/VulkanPhysicalDevice.hpp | 24 +- .../src/DeviceContextVkImpl.cpp | 31 +- .../GraphicsEngineVulkan/src/EngineFactoryVk.cpp | 22 +- .../src/GenerateMipsVkHelper.cpp | 2 +- .../GraphicsEngineVulkan/src/PipelineLayout.cpp | 16 +- .../src/PipelineStateVkImpl.cpp | 22 +- .../src/RenderDeviceVkImpl.cpp | 4 + .../src/VulkanUtilities/VulkanInstance.cpp | 21 +- .../src/VulkanUtilities/VulkanPhysicalDevice.cpp | 31 +- 49 files changed, 1663 insertions(+), 757 deletions(-) (limited to 'Graphics') diff --git a/Graphics/GLSLTools/src/GLSLSourceBuilder.cpp b/Graphics/GLSLTools/src/GLSLSourceBuilder.cpp index 8b369954..da1b6fec 100644 --- a/Graphics/GLSLTools/src/GLSLSourceBuilder.cpp +++ b/Graphics/GLSLTools/src/GLSLSourceBuilder.cpp @@ -64,6 +64,13 @@ const char* GetShaderTypeDefines(SHADER_TYPE Type) case SHADER_TYPE_COMPUTE: return "#define COMPUTE_SHADER 1\n"; + + case SHADER_TYPE_AMPLIFICATION: + return "#define TASK_SHADER 1\n" + "#define AMPLIFICATION_SHADER 1\n"; + + case SHADER_TYPE_MESH: + return "#define MESH_SHADER 1\n"; default: UNEXPECTED("Unexpected shader type"); diff --git a/Graphics/GLSLTools/src/SPIRVShaderResources.cpp b/Graphics/GLSLTools/src/SPIRVShaderResources.cpp index 46705ace..bf92e84b 100644 --- a/Graphics/GLSLTools/src/SPIRVShaderResources.cpp +++ b/Graphics/GLSLTools/src/SPIRVShaderResources.cpp @@ -149,13 +149,15 @@ static spv::ExecutionModel ShaderTypeToExecutionModel(SHADER_TYPE ShaderType) switch (ShaderType) { // clang-format off - case SHADER_TYPE_VERTEX: return spv::ExecutionModelVertex; - case SHADER_TYPE_HULL: return spv::ExecutionModelTessellationControl; - case SHADER_TYPE_DOMAIN: return spv::ExecutionModelTessellationEvaluation; - case SHADER_TYPE_GEOMETRY: return spv::ExecutionModelGeometry; - case SHADER_TYPE_PIXEL: return spv::ExecutionModelFragment; - case SHADER_TYPE_COMPUTE: return spv::ExecutionModelGLCompute; - // clang-format on + case SHADER_TYPE_VERTEX: return spv::ExecutionModelVertex; + case SHADER_TYPE_HULL: return spv::ExecutionModelTessellationControl; + case SHADER_TYPE_DOMAIN: return spv::ExecutionModelTessellationEvaluation; + case SHADER_TYPE_GEOMETRY: return spv::ExecutionModelGeometry; + case SHADER_TYPE_PIXEL: return spv::ExecutionModelFragment; + case SHADER_TYPE_COMPUTE: return spv::ExecutionModelGLCompute; + case SHADER_TYPE_AMPLIFICATION: return spv::ExecutionModelTaskNV; + case SHADER_TYPE_MESH: return spv::ExecutionModelMeshNV; + // clang-format on default: UNEXPECTED("Unexpected shader type"); diff --git a/Graphics/GLSLTools/src/SPIRVUtils.cpp b/Graphics/GLSLTools/src/SPIRVUtils.cpp index e02bc34e..5ae9d3a1 100644 --- a/Graphics/GLSLTools/src/SPIRVUtils.cpp +++ b/Graphics/GLSLTools/src/SPIRVUtils.cpp @@ -72,12 +72,14 @@ EShLanguage ShaderTypeToShLanguage(SHADER_TYPE ShaderType) switch (ShaderType) { // clang-format off - case SHADER_TYPE_VERTEX: return EShLangVertex; - case SHADER_TYPE_HULL: return EShLangTessControl; - case SHADER_TYPE_DOMAIN: return EShLangTessEvaluation; - case SHADER_TYPE_GEOMETRY: return EShLangGeometry; - case SHADER_TYPE_PIXEL: return EShLangFragment; - case SHADER_TYPE_COMPUTE: return EShLangCompute; + case SHADER_TYPE_VERTEX: return EShLangVertex; + case SHADER_TYPE_HULL: return EShLangTessControl; + case SHADER_TYPE_DOMAIN: return EShLangTessEvaluation; + case SHADER_TYPE_GEOMETRY: return EShLangGeometry; + case SHADER_TYPE_PIXEL: return EShLangFragment; + case SHADER_TYPE_COMPUTE: return EShLangCompute; + case SHADER_TYPE_AMPLIFICATION: return EShLangTaskNV; + case SHADER_TYPE_MESH: return EShLangMeshNV; // clang-format on default: UNEXPECTED("Unexpected shader type"); diff --git a/Graphics/GraphicsAccessories/src/GraphicsAccessories.cpp b/Graphics/GraphicsAccessories/src/GraphicsAccessories.cpp index fff50193..de16b059 100644 --- a/Graphics/GraphicsAccessories/src/GraphicsAccessories.cpp +++ b/Graphics/GraphicsAccessories/src/GraphicsAccessories.cpp @@ -480,13 +480,15 @@ const Char* GetShaderTypeLiteralName(SHADER_TYPE ShaderType) #define RETURN_SHADER_TYPE_NAME(ShaderType)\ case ShaderType: return #ShaderType; - RETURN_SHADER_TYPE_NAME( SHADER_TYPE_UNKNOWN ) - RETURN_SHADER_TYPE_NAME( SHADER_TYPE_VERTEX ) - RETURN_SHADER_TYPE_NAME( SHADER_TYPE_PIXEL ) - RETURN_SHADER_TYPE_NAME( SHADER_TYPE_GEOMETRY) - RETURN_SHADER_TYPE_NAME( SHADER_TYPE_HULL ) - RETURN_SHADER_TYPE_NAME( SHADER_TYPE_DOMAIN ) - RETURN_SHADER_TYPE_NAME( SHADER_TYPE_COMPUTE ) + RETURN_SHADER_TYPE_NAME( SHADER_TYPE_UNKNOWN ) + RETURN_SHADER_TYPE_NAME( SHADER_TYPE_VERTEX ) + RETURN_SHADER_TYPE_NAME( SHADER_TYPE_PIXEL ) + RETURN_SHADER_TYPE_NAME( SHADER_TYPE_GEOMETRY ) + RETURN_SHADER_TYPE_NAME( SHADER_TYPE_HULL ) + RETURN_SHADER_TYPE_NAME( SHADER_TYPE_DOMAIN ) + RETURN_SHADER_TYPE_NAME( SHADER_TYPE_COMPUTE ) + RETURN_SHADER_TYPE_NAME( SHADER_TYPE_AMPLIFICATION) + RETURN_SHADER_TYPE_NAME( SHADER_TYPE_MESH ) #undef RETURN_SHADER_TYPE_NAME // clang-format on @@ -497,7 +499,7 @@ const Char* GetShaderTypeLiteralName(SHADER_TYPE ShaderType) String GetShaderStagesString(SHADER_TYPE ShaderStages) { String StagesStr; - for (Uint32 Stage = SHADER_TYPE_VERTEX; ShaderStages != 0 && Stage <= SHADER_TYPE_COMPUTE; Stage <<= 1) + for (Uint32 Stage = SHADER_TYPE_VERTEX; ShaderStages != 0 && Stage < SHADER_TYPE_LAST; Stage <<= 1) { if (ShaderStages & Stage) { diff --git a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp index b4c271fa..d547ca6f 100644 --- a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp +++ b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp @@ -229,8 +229,10 @@ protected: // clang-format off bool DvpVerifyDrawArguments (const DrawAttribs& Attribs)const; bool DvpVerifyDrawIndexedArguments (const DrawIndexedAttribs& Attribs)const; + bool DvpVerifyDrawMeshArguments (const DrawMeshAttribs& Attribs)const; bool DvpVerifyDrawIndirectArguments (const DrawIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer)const; bool DvpVerifyDrawIndexedIndirectArguments(const DrawIndexedIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer)const; + bool DvpVerifyDrawMeshIndirectArguments (const DrawMeshIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer)const; bool DvpVerifyDispatchArguments (const DispatchComputeAttribs& Attribs)const; bool DvpVerifyDispatchIndirectArguments(const DispatchComputeIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer)const; @@ -242,8 +244,10 @@ protected: #else bool DvpVerifyDrawArguments (const DrawAttribs& Attribs)const {return true;} bool DvpVerifyDrawIndexedArguments (const DrawIndexedAttribs& Attribs)const {return true;} + bool DvpVerifyDrawMeshArguments (const DrawMeshAttribs& Attribs)const {return true;} bool DvpVerifyDrawIndirectArguments (const DrawIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer)const {return true;} bool DvpVerifyDrawIndexedIndirectArguments(const DrawIndexedIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer)const {return true;} + bool DvpVerifyDrawMeshIndirectArguments (const DrawMeshIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer)const {return true;} bool DvpVerifyDispatchArguments (const DispatchComputeAttribs& Attribs)const {return true;} bool DvpVerifyDispatchIndirectArguments(const DispatchComputeIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer)const {return true;} @@ -1175,7 +1179,7 @@ inline bool DeviceContextBase:: return false; } - if (m_pPipelineState->GetDesc().IsComputePipeline) + if (m_pPipelineState->GetDesc().PipelineType != GRAPHICS_PIPELINE) { LOG_ERROR_MESSAGE("Draw command arguments are invalid: pipeline state '", m_pPipelineState->GetDesc().Name, "' is a compute pipeline."); return false; @@ -1201,8 +1205,8 @@ inline bool DeviceContextBase:: LOG_ERROR_MESSAGE("DrawIndexed command arguments are invalid: no pipeline state is bound."); return false; } - - if (m_pPipelineState->GetDesc().IsComputePipeline) + + if (m_pPipelineState->GetDesc().PipelineType != GRAPHICS_PIPELINE) { LOG_ERROR_MESSAGE("DrawIndexed command arguments are invalid: pipeline state '", m_pPipelineState->GetDesc().Name, "' is a compute pipeline."); @@ -1230,6 +1234,34 @@ inline bool DeviceContextBase:: return true; } +template +inline bool DeviceContextBase:: + DvpVerifyDrawMeshArguments(const DrawMeshAttribs& Attribs)const +{ + if ((Attribs.Flags & DRAW_FLAG_VERIFY_DRAW_ATTRIBS) == 0) + return true; + + if (!m_pPipelineState) + { + LOG_ERROR_MESSAGE("DrawMesh command arguments are invalid: no pipeline state is bound."); + return false; + } + + if (m_pPipelineState->GetDesc().PipelineType != MESH_PIPELINE) + { + LOG_ERROR_MESSAGE("DrawMesh command arguments are invalid: pipeline state '", + m_pPipelineState->GetDesc().Name, "' is a compute pipeline."); + return false; + } + + if (Attribs.ThreadGroupCount == 0) + { + LOG_WARNING_MESSAGE("DrawMesh command arguments are invalid: number of groups to dispatch is zero."); + } + + return true; +} + template inline bool DeviceContextBase:: DvpVerifyDrawIndirectArguments(const DrawIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer) const @@ -1242,8 +1274,8 @@ inline bool DeviceContextBase:: LOG_ERROR_MESSAGE("DrawIndirect command arguments are invalid: no pipeline state is bound."); return false; } - - if (m_pPipelineState->GetDesc().IsComputePipeline) + + if (m_pPipelineState->GetDesc().PipelineType != GRAPHICS_PIPELINE) { LOG_ERROR_MESSAGE("DrawIndirect command arguments are invalid: pipeline state '", @@ -1281,8 +1313,8 @@ inline bool DeviceContextBase:: LOG_ERROR_MESSAGE("DrawIndexedIndirect command arguments are invalid: no pipeline state is bound."); return false; } - - if (m_pPipelineState->GetDesc().IsComputePipeline) + + if (m_pPipelineState->GetDesc().PipelineType != GRAPHICS_PIPELINE) { LOG_ERROR_MESSAGE("DrawIndexedIndirect command arguments are invalid: pipeline state '", m_pPipelineState->GetDesc().Name, "' is a compute pipeline."); @@ -1320,6 +1352,44 @@ inline bool DeviceContextBase:: return true; } +template +inline bool DeviceContextBase:: + DvpVerifyDrawMeshIndirectArguments(const DrawMeshIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer) const +{ + if ((Attribs.Flags & DRAW_FLAG_VERIFY_DRAW_ATTRIBS) == 0) + return true; + + if (!m_pPipelineState) + { + LOG_ERROR_MESSAGE("DrawMeshIndirect command arguments are invalid: no pipeline state is bound."); + return false; + } + + if (m_pPipelineState->GetDesc().PipelineType != MESH_PIPELINE) + { + LOG_ERROR_MESSAGE("DrawMeshIndirect command arguments are invalid: pipeline state '", + m_pPipelineState->GetDesc().Name, "' is a compute pipeline."); + return false; + } + + if (pAttribsBuffer != nullptr) + { + if ((pAttribsBuffer->GetDesc().BindFlags & BIND_INDIRECT_DRAW_ARGS) == 0) + { + LOG_ERROR_MESSAGE("DrawMeshIndirect command arguments are invalid: indirect draw arguments buffer '", + pAttribsBuffer->GetDesc().Name, "' was not created with BIND_INDIRECT_DRAW_ARGS flag."); + return false; + } + } + else + { + LOG_ERROR_MESSAGE("DrawMeshIndirect command arguments are invalid: indirect draw arguments buffer is null."); + return false; + } + + return true; +} + template inline void DeviceContextBase:: DvpVerifyRenderTargets() const @@ -1384,7 +1454,7 @@ inline bool DeviceContextBase:: return false; } - if (!m_pPipelineState->GetDesc().IsComputePipeline) + if (m_pPipelineState->GetDesc().PipelineType != COMPUTE_PIPELINE) { LOG_ERROR_MESSAGE("DispatchCompute command arguments are invalid: pipeline state '", m_pPipelineState->GetDesc().Name, "' is a graphics pipeline."); @@ -1412,8 +1482,8 @@ inline bool DeviceContextBase:: LOG_ERROR_MESSAGE("DispatchComputeIndirect command arguments are invalid: no pipeline state is bound."); return false; } - - if (!m_pPipelineState->GetDesc().IsComputePipeline) + + if (m_pPipelineState->GetDesc().PipelineType != COMPUTE_PIPELINE) { LOG_ERROR_MESSAGE("DispatchComputeIndirect command arguments are invalid: pipeline state '", m_pPipelineState->GetDesc().Name, "' is a graphics pipeline."); diff --git a/Graphics/GraphicsEngine/include/PipelineStateBase.hpp b/Graphics/GraphicsEngine/include/PipelineStateBase.hpp index 6d70f4da..37d4e7cd 100644 --- a/Graphics/GraphicsEngine/include/PipelineStateBase.hpp +++ b/Graphics/GraphicsEngine/include/PipelineStateBase.hpp @@ -83,7 +83,7 @@ public: StringPoolSize += strlen(SrcLayout.StaticSamplers[i].SamplerOrTextureName) + 1; } - if (!PSODesc.IsComputePipeline) + if (PSODesc.IsAnyGraphicsPipeline()) { CheckAndCorrectBlendStateDesc(); CheckRasterizerStateDesc(); @@ -142,7 +142,7 @@ public: } - if (this->m_Desc.IsComputePipeline) + if (this->m_Desc.IsComputePipeline()) { const auto& ComputePipeline = PSODesc.ComputePipeline; if (ComputePipeline.pCS == nullptr) @@ -171,20 +171,40 @@ public: VALIDATE_SHADER_TYPE(GraphicsPipeline.pGS, SHADER_TYPE_GEOMETRY, "geometry") VALIDATE_SHADER_TYPE(GraphicsPipeline.pHS, SHADER_TYPE_HULL, "hull") VALIDATE_SHADER_TYPE(GraphicsPipeline.pDS, SHADER_TYPE_DOMAIN, "domain") + VALIDATE_SHADER_TYPE(GraphicsPipeline.pAS, SHADER_TYPE_AMPLIFICATION, "amplification") + VALIDATE_SHADER_TYPE(GraphicsPipeline.pMS, SHADER_TYPE_MESH, "mesh") #undef VALIDATE_SHADER_TYPE - m_pVS = GraphicsPipeline.pVS; - m_pPS = GraphicsPipeline.pPS; - m_pGS = GraphicsPipeline.pGS; - m_pDS = GraphicsPipeline.pDS; - m_pHS = GraphicsPipeline.pHS; + if (PSODesc.PipelineType == GRAPHICS_PIPELINE) + { + CHECK_THROW(GraphicsPipeline.pVS, "Vertex shader must be defined"); + CHECK_THROW(!GraphicsPipeline.pAS && !GraphicsPipeline.pMS, "Mesh shaders are not supported in graphics pipeline"); + m_pVS = GraphicsPipeline.pVS; + m_pPS = GraphicsPipeline.pPS; + m_pGS = GraphicsPipeline.pGS; + m_pDS = GraphicsPipeline.pDS; + m_pHS = GraphicsPipeline.pHS; + } + else + if (PSODesc.PipelineType == MESH_PIPELINE) + { + CHECK_THROW(GraphicsPipeline.pMS, "Mesh shader must be defined"); + CHECK_THROW(!GraphicsPipeline.pVS && !GraphicsPipeline.pGS && !GraphicsPipeline.pDS && !GraphicsPipeline.pHS, + "Vertex, geometry and tessellation shaders are not supported in mesh pipeline"); + DEV_CHECK_ERR(GraphicsPipeline.InputLayout.NumElements == 0, "Input layout ignored in mesh shader"); + m_pAS = GraphicsPipeline.pAS; + m_pMS = GraphicsPipeline.pMS; + m_pPS = GraphicsPipeline.pPS; + } if (GraphicsPipeline.pVS) m_ppShaders[m_NumShaders++] = GraphicsPipeline.pVS; if (GraphicsPipeline.pPS) m_ppShaders[m_NumShaders++] = GraphicsPipeline.pPS; if (GraphicsPipeline.pGS) m_ppShaders[m_NumShaders++] = GraphicsPipeline.pGS; if (GraphicsPipeline.pHS) m_ppShaders[m_NumShaders++] = GraphicsPipeline.pHS; if (GraphicsPipeline.pDS) m_ppShaders[m_NumShaders++] = GraphicsPipeline.pDS; - + if (GraphicsPipeline.pAS) m_ppShaders[m_NumShaders++] = GraphicsPipeline.pAS; + if (GraphicsPipeline.pMS) m_ppShaders[m_NumShaders++] = GraphicsPipeline.pMS; + DEV_CHECK_ERR(m_NumShaders > 0, "There must be at least one shader in the Pipeline State"); for (Uint32 rt = GraphicsPipeline.NumRenderTargets; rt < _countof(GraphicsPipeline.RTVFormats); ++rt) @@ -388,9 +408,11 @@ protected: RefCntAutoPtr m_pDS; ///< Strong reference to the domain shader RefCntAutoPtr m_pHS; ///< Strong reference to the hull shader RefCntAutoPtr m_pCS; ///< Strong reference to the compute shader + RefCntAutoPtr m_pAS; ///< Strong reference to the amplification shader + RefCntAutoPtr m_pMS; ///< Strong reference to the mesh shader - IShader* m_ppShaders[5] = {}; ///< Array of pointers to the shaders used by this PSO - size_t m_ShaderResourceLayoutHash = 0; ///< Hash computed from the shader resource layout + IShader* m_ppShaders[MAX_SHADERS_IN_PIPELINE] = {}; ///< Array of pointers to the shaders used by this PSO + size_t m_ShaderResourceLayoutHash = 0; ///< Hash computed from the shader resource layout private: void CheckRasterizerStateDesc() const diff --git a/Graphics/GraphicsEngine/include/ShaderBase.hpp b/Graphics/GraphicsEngine/include/ShaderBase.hpp index 9874206a..5462c7a4 100644 --- a/Graphics/GraphicsEngine/include/ShaderBase.hpp +++ b/Graphics/GraphicsEngine/include/ShaderBase.hpp @@ -57,13 +57,15 @@ inline Int32 GetShaderTypeIndex(SHADER_TYPE Type) switch (Type) { // clang-format off - case SHADER_TYPE_UNKNOWN: VERIFY_EXPR(ShaderIndex == -1); break; - case SHADER_TYPE_VERTEX: VERIFY_EXPR(ShaderIndex == 0); break; - case SHADER_TYPE_PIXEL: VERIFY_EXPR(ShaderIndex == 1); break; - case SHADER_TYPE_GEOMETRY:VERIFY_EXPR(ShaderIndex == 2); break; - case SHADER_TYPE_HULL: VERIFY_EXPR(ShaderIndex == 3); break; - case SHADER_TYPE_DOMAIN: VERIFY_EXPR(ShaderIndex == 4); break; - case SHADER_TYPE_COMPUTE: VERIFY_EXPR(ShaderIndex == 5); break; + case SHADER_TYPE_UNKNOWN: VERIFY_EXPR(ShaderIndex == -1); break; + case SHADER_TYPE_VERTEX: VERIFY_EXPR(ShaderIndex == 0); break; + case SHADER_TYPE_PIXEL: VERIFY_EXPR(ShaderIndex == 1); break; + case SHADER_TYPE_GEOMETRY: VERIFY_EXPR(ShaderIndex == 2); break; + case SHADER_TYPE_HULL: VERIFY_EXPR(ShaderIndex == 3); break; + case SHADER_TYPE_DOMAIN: VERIFY_EXPR(ShaderIndex == 4); break; + case SHADER_TYPE_COMPUTE: VERIFY_EXPR(ShaderIndex == 5); break; + case SHADER_TYPE_AMPLIFICATION: VERIFY_EXPR(ShaderIndex == 6); break; + case SHADER_TYPE_MESH: VERIFY_EXPR(ShaderIndex == 7); break; // clang-format on default: UNEXPECTED("Unexpected shader type (", Type, ")"); break; } @@ -78,6 +80,8 @@ static const int GSInd = GetShaderTypeIndex(SHADER_TYPE_GEOMETRY); static const int HSInd = GetShaderTypeIndex(SHADER_TYPE_HULL); static const int DSInd = GetShaderTypeIndex(SHADER_TYPE_DOMAIN); static const int CSInd = GetShaderTypeIndex(SHADER_TYPE_COMPUTE); +static const int ASInd = GetShaderTypeIndex(SHADER_TYPE_AMPLIFICATION); +static const int MSInd = GetShaderTypeIndex(SHADER_TYPE_MESH); /// Template class implementing base functionality for a shader object diff --git a/Graphics/GraphicsEngine/interface/DeviceCaps.h b/Graphics/GraphicsEngine/interface/DeviceCaps.h index 1f0dc257..77095307 100644 --- a/Graphics/GraphicsEngine/interface/DeviceCaps.h +++ b/Graphics/GraphicsEngine/interface/DeviceCaps.h @@ -164,6 +164,9 @@ struct DeviceFeatures /// Specifies whether all the extended UAV texture formats are available in shader code. Bool TextureUAVExtendedFormats DEFAULT_INITIALIZER(False); + + /// Indicates if device supports mesh and amplification shaders + Bool MeshShaders DEFAULT_INITIALIZER(False); }; typedef struct DeviceFeatures DeviceFeatures; diff --git a/Graphics/GraphicsEngine/interface/DeviceContext.h b/Graphics/GraphicsEngine/interface/DeviceContext.h index 79f8bd39..db1c0175 100644 --- a/Graphics/GraphicsEngine/interface/DeviceContext.h +++ b/Graphics/GraphicsEngine/interface/DeviceContext.h @@ -362,6 +362,68 @@ struct DrawIndexedIndirectAttribs }; typedef struct DrawIndexedIndirectAttribs DrawIndexedIndirectAttribs; +/// Defines the mesh draw command attributes. + +/// This structure is used by IDeviceContext::DrawMesh(). +struct DrawMeshAttribs +{ + ///< Number of dispatched groups + Uint32 ThreadGroupCount DEFAULT_INITIALIZER(1); + + /// Additional flags, see Diligent::DRAW_FLAGS. + DRAW_FLAGS Flags DEFAULT_INITIALIZER(DRAW_FLAG_NONE); + +#if DILIGENT_CPP_INTERFACE + /// Initializes the structure members with default values. + DrawMeshAttribs()noexcept{} + + /// Initializes the structure with user-specified values. + DrawMeshAttribs(Uint32 _ThreadGroupCount, + DRAW_FLAGS _Flags)noexcept : + ThreadGroupCount {_ThreadGroupCount}, + Flags {_Flags} + {} +#endif +}; +typedef struct DrawMeshAttribs DrawMeshAttribs; + +/// Defines the mesh indirect draw command attributes. + +/// This structure is used by IDeviceContext::DrawMeshIndirect(). +struct DrawMeshIndirectAttribs +{ + /// Additional flags, see Diligent::DRAW_FLAGS. + DRAW_FLAGS Flags DEFAULT_INITIALIZER(DRAW_FLAG_NONE); + + /// State transition mode for indirect draw arguments buffer. + RESOURCE_STATE_TRANSITION_MODE IndirectAttribsBufferStateTransitionMode DEFAULT_INITIALIZER(RESOURCE_STATE_TRANSITION_MODE_NONE); + + /// Offset from the beginning of the buffer to the location of draw command attributes. + Uint32 IndirectDrawArgsOffset DEFAULT_INITIALIZER(0); + +#if DILIGENT_CPP_INTERFACE + /// Initializes the structure members with default values + + /// Default values: + /// Member | Default value + /// -----------------------------------------|-------------------------------------- + /// Flags | DRAW_FLAG_NONE + /// IndirectAttribsBufferStateTransitionMode | RESOURCE_STATE_TRANSITION_MODE_NONE + /// IndirectDrawArgsOffset | 0 + DrawMeshIndirectAttribs()noexcept{} + + /// Initializes the structure members with user-specified values. + DrawMeshIndirectAttribs(DRAW_FLAGS _Flags, + RESOURCE_STATE_TRANSITION_MODE _IndirectAttribsBufferStateTransitionMode, + Uint32 _IndirectDrawArgsOffset = 0)noexcept : + Flags {_Flags }, + IndirectAttribsBufferStateTransitionMode{_IndirectAttribsBufferStateTransitionMode}, + IndirectDrawArgsOffset {_IndirectDrawArgsOffset } + {} +#endif +}; +typedef struct DrawMeshIndirectAttribs DrawMeshIndirectAttribs; + /// Defines which parts of the depth-stencil buffer to clear. /// These flags are used by IDeviceContext::ClearDepthStencil(). @@ -930,6 +992,29 @@ DILIGENT_BEGIN_INTERFACE(IDeviceContext, IObject) VIRTUAL void METHOD(DrawIndexedIndirect)(THIS_ const DrawIndexedIndirectAttribs REF Attribs, IBuffer* pAttribsBuffer) PURE; + + + /// Executes an mesh draw command. + + /// \param [in] Attribs - Draw command attributes, see Diligent::DrawMeshAttribs for details. + VIRTUAL void METHOD(DrawMesh)(THIS_ + const DrawMeshAttribs REF Attribs) PURE; + + + /// Executes an mesh indirect draw command. + + /// \param [in] Attribs - Structure describing the command attributes, see Diligent::DrawMeshIndirectAttribs for details. + /// \param [in] pAttribsBuffer - Pointer to the buffer, from which indirect draw attributes will be read. + /// + /// \remarks If IndirectAttribsBufferStateTransitionMode member is Diligent::RESOURCE_STATE_TRANSITION_MODE_TRANSITION, + /// the method may transition the state of the indirect draw arguments buffer. This is not a thread safe operation, + /// so no other thread is allowed to read or write the state of the buffer. + /// + /// If the application intends to use the same resources in other threads simultaneously, it needs to + /// explicitly manage the states using IDeviceContext::TransitionResourceStates() method. + VIRTUAL void METHOD(DrawMeshIndirect)(THIS_ + const DrawMeshIndirectAttribs REF Attribs, + IBuffer* pAttribsBuffer) PURE; /// Executes a dispatch compute command. diff --git a/Graphics/GraphicsEngine/interface/GraphicsTypes.h b/Graphics/GraphicsEngine/interface/GraphicsTypes.h index 0d0631b7..b54ac7cb 100644 --- a/Graphics/GraphicsEngine/interface/GraphicsTypes.h +++ b/Graphics/GraphicsEngine/interface/GraphicsTypes.h @@ -920,7 +920,7 @@ DEFINE_FLAG_ENUM_OPERATORS(MISC_TEXTURE_FLAGS) /// Input primitive topology. -/// This enumeration is used by DrawAttribs structure to define input primitive topology. +/// This enumeration is used by GraphicsPipelineDesc structure to define input primitive topology. DILIGENT_TYPED_ENUM(PRIMITIVE_TOPOLOGY, Uint8) { /// Undefined topology diff --git a/Graphics/GraphicsEngine/interface/PipelineState.h b/Graphics/GraphicsEngine/interface/PipelineState.h index 5e99a392..6daa74b6 100644 --- a/Graphics/GraphicsEngine/interface/PipelineState.h +++ b/Graphics/GraphicsEngine/interface/PipelineState.h @@ -165,6 +165,12 @@ struct GraphicsPipelineDesc /// Geometry shader to be used with the pipeline IShader* pGS DEFAULT_INITIALIZER(nullptr); + /// Amplification shader to be used with the pipeline + IShader* pAS DEFAULT_INITIALIZER(nullptr); + + /// Mesh shader to be used with the pipeline + IShader* pMS DEFAULT_INITIALIZER(nullptr); + //D3D12_STREAM_OUTPUT_DESC StreamOutput; /// Blend state description @@ -182,11 +188,11 @@ struct GraphicsPipelineDesc /// Depth-stencil state description DepthStencilStateDesc DepthStencilDesc; - /// Input layout + /// Input layout, ignored in mesh pipeline InputLayoutDesc InputLayout; //D3D12_INDEX_BUFFER_STRIP_CUT_VALUE IBStripCutValue; - /// Primitive topology type + /// Primitive topology type, ignored in mesh pipeline PRIMITIVE_TOPOLOGY PrimitiveTopology DEFAULT_INITIALIZER(PRIMITIVE_TOPOLOGY_TRIANGLE_LIST); /// Number of viewports used by this pipeline @@ -223,12 +229,25 @@ struct ComputePipelineDesc }; typedef struct ComputePipelineDesc ComputePipelineDesc; +/// Pipeline type +DILIGENT_TYPED_ENUM(PIPELINE_TYPE, Uint8) +{ + /// Graphics pipeline used in IDeviceContext::Draw(), IDeviceContext::DrawIndexed(), + /// IDeviceContext::DrawIndirect(), IDeviceContext::DrawIndexedIndirect(). + GRAPHICS_PIPELINE, + + /// Compute pipeline used in IDeviceContext::DispatchCompute(), IDeviceContext::DispatchComputeIndirect(). + COMPUTE_PIPELINE, + + // Mesh pipeline used in IDeviceContext::DrawMesh(), IDeviceContext::DrawMeshIndirect(). + MESH_PIPELINE, +}; /// Pipeline state description struct PipelineStateDesc DILIGENT_DERIVE(DeviceObjectAttribs) - /// Flag indicating if pipeline state is a compute pipeline state - bool IsComputePipeline DEFAULT_INITIALIZER(false); + /// Pipeline type + PIPELINE_TYPE PipelineType DEFAULT_INITIALIZER(GRAPHICS_PIPELINE); /// Shader resource binding allocation granularity @@ -242,11 +261,16 @@ struct PipelineStateDesc DILIGENT_DERIVE(DeviceObjectAttribs) /// Pipeline layout description PipelineResourceLayoutDesc ResourceLayout; - /// Graphics pipeline state description. This memeber is ignored if IsComputePipeline == True + /// Graphics pipeline state description. This memeber is ignored if PipelineType == GRAPHICS_PIPELINE or MESH_PIPELINE GraphicsPipelineDesc GraphicsPipeline; - /// Compute pipeline state description. This memeber is ignored if IsComputePipeline == False + /// Compute pipeline state description. This memeber is ignored if PipelineType == COMPUTE_PIPELINE ComputePipelineDesc ComputePipeline; + +#if DILIGENT_CPP_INTERFACE + bool IsAnyGraphicsPipeline() const { return PipelineType == GRAPHICS_PIPELINE || PipelineType == MESH_PIPELINE; } + bool IsComputePipeline () const { return PipelineType == COMPUTE_PIPELINE; } +#endif }; typedef struct PipelineStateDesc PipelineStateDesc; diff --git a/Graphics/GraphicsEngine/interface/Shader.h b/Graphics/GraphicsEngine/interface/Shader.h index eacd35f0..867335a9 100644 --- a/Graphics/GraphicsEngine/interface/Shader.h +++ b/Graphics/GraphicsEngine/interface/Shader.h @@ -45,13 +45,16 @@ static const INTERFACE_ID IID_Shader = /// Describes the shader type DILIGENT_TYPED_ENUM(SHADER_TYPE, Uint32) { - SHADER_TYPE_UNKNOWN = 0x000, ///< Unknown shader type - SHADER_TYPE_VERTEX = 0x001, ///< Vertex shader - SHADER_TYPE_PIXEL = 0x002, ///< Pixel (fragment) shader - SHADER_TYPE_GEOMETRY = 0x004, ///< Geometry shader - SHADER_TYPE_HULL = 0x008, ///< Hull (tessellation control) shader - SHADER_TYPE_DOMAIN = 0x010, ///< Domain (tessellation evaluation) shader - SHADER_TYPE_COMPUTE = 0x020 ///< Compute shader + SHADER_TYPE_UNKNOWN = 0x000, ///< Unknown shader type + SHADER_TYPE_VERTEX = 0x001, ///< Vertex shader + SHADER_TYPE_PIXEL = 0x002, ///< Pixel (fragment) shader + SHADER_TYPE_GEOMETRY = 0x004, ///< Geometry shader + SHADER_TYPE_HULL = 0x008, ///< Hull (tessellation control) shader + SHADER_TYPE_DOMAIN = 0x010, ///< Domain (tessellation evaluation) shader + SHADER_TYPE_COMPUTE = 0x020, ///< Compute shader + SHADER_TYPE_AMPLIFICATION = 0x040, ///< Amplification (task) shader + SHADER_TYPE_MESH = 0x080, ///< Mesh shader + SHADER_TYPE_LAST }; DEFINE_FLAG_ENUM_OPERATORS(SHADER_TYPE); diff --git a/Graphics/GraphicsEngineD3D11/include/DeviceContextD3D11Impl.hpp b/Graphics/GraphicsEngineD3D11/include/DeviceContextD3D11Impl.hpp index f8db6f23..5230b833 100644 --- a/Graphics/GraphicsEngineD3D11/include/DeviceContextD3D11Impl.hpp +++ b/Graphics/GraphicsEngineD3D11/include/DeviceContextD3D11Impl.hpp @@ -130,6 +130,10 @@ public: virtual void DILIGENT_CALL_TYPE DrawIndirect(const DrawIndirectAttribs& Attribs, IBuffer* pAttribsBuffer) override final; /// Implementation of IDeviceContext::DrawIndexedIndirect() in Direct3D11 backend. virtual void DILIGENT_CALL_TYPE DrawIndexedIndirect(const DrawIndexedIndirectAttribs& Attribs, IBuffer* pAttribsBuffer) override final; + /// Implementation of IDeviceContext::DrawMesh() in Direct3D11 backend. + virtual void DILIGENT_CALL_TYPE DrawMesh(const DrawMeshAttribs& Attribs) override final; + /// Implementation of IDeviceContext::DrawMeshIndirect() in Direct3D11 backend. + virtual void DILIGENT_CALL_TYPE DrawMeshIndirect(const DrawMeshIndirectAttribs& Attribs, IBuffer* pAttribsBuffer) override final; /// Implementation of IDeviceContext::DispatchCompute() in Direct3D11 backend. virtual void DILIGENT_CALL_TYPE DispatchCompute(const DispatchComputeAttribs& Attribs) override final; diff --git a/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp b/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp index 0ff2227d..d936b247 100755 --- a/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp +++ b/Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp @@ -75,7 +75,7 @@ void DeviceContextD3D11Impl::SetPipelineState(IPipelineState* pPipelineState) TDeviceContextBase::SetPipelineState(pPipelineStateD3D11, 0 /*Dummy*/); auto& Desc = pPipelineStateD3D11->GetDesc(); - if (Desc.IsComputePipeline) + if (Desc.IsComputePipeline()) { auto* pd3d11CS = pPipelineStateD3D11->GetD3D11ComputeShader(); if (pd3d11CS == nullptr) @@ -870,6 +870,16 @@ void DeviceContextD3D11Impl::DrawIndexedIndirect(const DrawIndexedIndirectAttrib m_pd3d11DeviceContext->DrawIndexedInstancedIndirect(pd3d11ArgsBuff, Attribs.IndirectDrawArgsOffset); } +void DeviceContextD3D11Impl::DrawMesh(const DrawMeshAttribs& Attribs) +{ + UNSUPPORTED("DrawMesh is not supported in DirectX 11"); +} + +void DeviceContextD3D11Impl::DrawMeshIndirect(const DrawMeshIndirectAttribs& Attribs, IBuffer* pAttribsBuffer) +{ + UNSUPPORTED("DrawMeshIndirect is not supported in DirectX 11"); +} + void DeviceContextD3D11Impl::DispatchCompute(const DispatchComputeAttribs& Attribs) { if (!DvpVerifyDispatchArguments(Attribs)) diff --git a/Graphics/GraphicsEngineD3D11/src/PipelineStateD3D11Impl.cpp b/Graphics/GraphicsEngineD3D11/src/PipelineStateD3D11Impl.cpp index 3b787039..97d76fde 100644 --- a/Graphics/GraphicsEngineD3D11/src/PipelineStateD3D11Impl.cpp +++ b/Graphics/GraphicsEngineD3D11/src/PipelineStateD3D11Impl.cpp @@ -50,7 +50,7 @@ PipelineStateD3D11Impl::PipelineStateD3D11Impl(IReferenceCounters* pR m_StaticSamplers (STD_ALLOCATOR_RAW_MEM(StaticSamplerInfo, GetRawAllocator(), "Allocator for vector")) // clang-format on { - if (m_Desc.IsComputePipeline) + if (m_Desc.IsComputePipeline()) { auto* pCS = ValidatedCast(m_Desc.ComputePipeline.pCS); m_pCS = pCS; diff --git a/Graphics/GraphicsEngineD3D11/src/ShaderD3D11Impl.cpp b/Graphics/GraphicsEngineD3D11/src/ShaderD3D11Impl.cpp index b5b0194f..8bf17567 100644 --- a/Graphics/GraphicsEngineD3D11/src/ShaderD3D11Impl.cpp +++ b/Graphics/GraphicsEngineD3D11/src/ShaderD3D11Impl.cpp @@ -34,24 +34,24 @@ namespace Diligent { -static const std::string HLSLVersionToShaderModelString(const ShaderVersion& Version, Uint8 MaxMajorRevision, Uint8 MaxMinorRevision) +static const Uint8 HLSLVersionToShaderModelString(const ShaderVersion& Version, Uint8 MaxMajorRevision, Uint8 MaxMinorRevision) { - std::string ModelStr; + Uint8 ModelVer; if (Version.Major > MaxMajorRevision || Version.Major == MaxMajorRevision && Version.Minor > MaxMinorRevision) { - ModelStr = std::to_string(Uint32{MaxMajorRevision}) + '_' + std::to_string(Uint32{MaxMinorRevision}); + ModelVer = Uint8((MaxMajorRevision << 4) | MaxMinorRevision); LOG_ERROR_MESSAGE("Shader model ", Uint32{Version.Major}, "_", Uint32{Version.Minor}, " is not supported by this device. Maximum supported model: ", - ModelStr, ". Attempting to use ", ModelStr, '.'); + MaxMajorRevision, "_", MaxMinorRevision, ". Attempting to use ", MaxMajorRevision, "_", MaxMinorRevision, '.'); } else { - ModelStr = std::to_string(Uint32{Version.Major}) + '_' + std::to_string(Uint32{Version.Minor}); + ModelVer = Uint8((Version.Major << 4) | Version.Minor); } - return ModelStr; + return ModelVer; } -static const std::string GetD3D11ShaderModel(ID3D11Device* pd3d11Device, const ShaderVersion& HLSLVersion) +static const Uint8 GetD3D11ShaderModel(ID3D11Device* pd3d11Device, const ShaderVersion& HLSLVersion) { auto d3dDeviceFeatureLevel = pd3d11Device->GetFeatureLevel(); switch (d3dDeviceFeatureLevel) @@ -66,22 +66,22 @@ static const std::string GetD3D11ShaderModel(ID3D11Device* pd3d11Device, const S case D3D_FEATURE_LEVEL_11_1: case D3D_FEATURE_LEVEL_11_0: return (HLSLVersion.Major == 0 && HLSLVersion.Minor == 0) ? - std::string{"5_0"} : + Uint8(0x50) : HLSLVersionToShaderModelString(HLSLVersion, 5, 0); case D3D_FEATURE_LEVEL_10_1: return (HLSLVersion.Major == 0 && HLSLVersion.Minor == 0) ? - std::string{"4_1"} : + Uint8(0x41) : HLSLVersionToShaderModelString(HLSLVersion, 4, 1); case D3D_FEATURE_LEVEL_10_0: return (HLSLVersion.Major == 0 && HLSLVersion.Minor == 0) ? - std::string{"4_0"} : + Uint8(0x40) : HLSLVersionToShaderModelString(HLSLVersion, 4, 0); default: UNEXPECTED("Unexpected D3D feature level ", static_cast(d3dDeviceFeatureLevel)); - return "4_0"; + return Uint8(0x40); } } @@ -95,7 +95,7 @@ ShaderD3D11Impl::ShaderD3D11Impl(IReferenceCounters* pRefCounters, pRenderDeviceD3D11, ShaderCI.Desc }, - ShaderD3DBase{ShaderCI, GetD3D11ShaderModel(pRenderDeviceD3D11->GetD3D11Device(), ShaderCI.HLSLVersion).c_str()} + ShaderD3DBase{ShaderCI, GetD3D11ShaderModel(pRenderDeviceD3D11->GetD3D11Device(), ShaderCI.HLSLVersion)} // clang-format on { auto* pDeviceD3D11 = pRenderDeviceD3D11->GetD3D11Device(); diff --git a/Graphics/GraphicsEngineD3D11/src/ShaderResourcesD3D11.cpp b/Graphics/GraphicsEngineD3D11/src/ShaderResourcesD3D11.cpp index 769c91e2..779ce893 100755 --- a/Graphics/GraphicsEngineD3D11/src/ShaderResourcesD3D11.cpp +++ b/Graphics/GraphicsEngineD3D11/src/ShaderResourcesD3D11.cpp @@ -1,442 +1,447 @@ -/* - * 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 -#include "ShaderResourcesD3D11.hpp" -#include "ShaderBase.hpp" -#include "ShaderResourceCacheD3D11.hpp" -#include "RenderDeviceD3D11Impl.hpp" - -namespace Diligent -{ - - -ShaderResourcesD3D11::ShaderResourcesD3D11(RenderDeviceD3D11Impl* pDeviceD3D11Impl, - ID3DBlob* pShaderBytecode, - const ShaderDesc& ShdrDesc, - const char* CombinedSamplerSuffix) : - ShaderResources{ShdrDesc.ShaderType} -{ - class NewResourceHandler - { - public: - NewResourceHandler(RenderDeviceD3D11Impl* const _pDeviceD3D11Impl, - const ShaderDesc& _ShdrDesc, - const char* _CombinedSamplerSuffix, - ShaderResourcesD3D11& _Resources) : - // clang-format off - pDeviceD3D11Impl {_pDeviceD3D11Impl }, - ShdrDesc {_ShdrDesc }, - CombinedSamplerSuffix{_CombinedSamplerSuffix}, - Resources {_Resources } - // clang-format on - {} - - void OnNewCB(const D3DShaderResourceAttribs& CBAttribs) - { - VERIFY(CBAttribs.BindPoint + CBAttribs.BindCount - 1 <= MaxAllowedBindPoint, "CB bind point exceeds supported range"); - Resources.m_MaxCBBindPoint = std::max(Resources.m_MaxCBBindPoint, static_cast(CBAttribs.BindPoint + CBAttribs.BindCount - 1)); - } - - void OnNewTexUAV(const D3DShaderResourceAttribs& TexUAV) - { - VERIFY(TexUAV.BindPoint + TexUAV.BindCount - 1 <= MaxAllowedBindPoint, "Tex UAV bind point exceeds supported range"); - Resources.m_MaxUAVBindPoint = std::max(Resources.m_MaxUAVBindPoint, static_cast(TexUAV.BindPoint + TexUAV.BindCount - 1)); - } - - void OnNewBuffUAV(const D3DShaderResourceAttribs& BuffUAV) - { - VERIFY(BuffUAV.BindPoint + BuffUAV.BindCount - 1 <= MaxAllowedBindPoint, "Buff UAV bind point exceeds supported range"); - Resources.m_MaxUAVBindPoint = std::max(Resources.m_MaxUAVBindPoint, static_cast(BuffUAV.BindPoint + BuffUAV.BindCount - 1)); - } - - void OnNewBuffSRV(const D3DShaderResourceAttribs& BuffSRV) - { - VERIFY(BuffSRV.BindPoint + BuffSRV.BindCount - 1 <= MaxAllowedBindPoint, "Buff SRV bind point exceeds supported range"); - Resources.m_MaxSRVBindPoint = std::max(Resources.m_MaxSRVBindPoint, static_cast(BuffSRV.BindPoint + BuffSRV.BindCount - 1)); - } - - void OnNewSampler(const D3DShaderResourceAttribs& SamplerAttribs) - { - VERIFY(SamplerAttribs.BindPoint + SamplerAttribs.BindCount - 1 <= MaxAllowedBindPoint, "Sampler bind point exceeds supported range"); - Resources.m_MaxSamplerBindPoint = std::max(Resources.m_MaxSamplerBindPoint, static_cast(SamplerAttribs.BindPoint + SamplerAttribs.BindCount - 1)); - } - - void OnNewTexSRV(const D3DShaderResourceAttribs& TexAttribs) - { - VERIFY(TexAttribs.BindPoint + TexAttribs.BindCount - 1 <= MaxAllowedBindPoint, "Tex SRV bind point exceeds supported range"); - Resources.m_MaxSRVBindPoint = std::max(Resources.m_MaxSRVBindPoint, static_cast(TexAttribs.BindPoint + TexAttribs.BindCount - 1)); - } - - ~NewResourceHandler() - { - } - - private: - RenderDeviceD3D11Impl* const pDeviceD3D11Impl; - const ShaderDesc& ShdrDesc; - const char* CombinedSamplerSuffix; - ShaderResourcesD3D11& Resources; - }; - - Initialize( - pShaderBytecode, - NewResourceHandler{pDeviceD3D11Impl, ShdrDesc, CombinedSamplerSuffix, *this}, - ShdrDesc.Name, - CombinedSamplerSuffix); -} - - -ShaderResourcesD3D11::~ShaderResourcesD3D11() -{ -} - - -#ifdef DILIGENT_DEVELOPMENT -static String DbgMakeResourceName(const D3DShaderResourceAttribs& Attr, Uint32 BindPoint) -{ - VERIFY(BindPoint >= Uint32{Attr.BindPoint} && BindPoint < Uint32{Attr.BindPoint} + Attr.BindCount, "Bind point is out of allowed range"); - if (Attr.BindCount == 1) - return Attr.Name; - else - return String(Attr.Name) + '[' + std::to_string(BindPoint - Attr.BindPoint) + ']'; -} - -void ShaderResourcesD3D11::dvpVerifyCommittedResources(ID3D11Buffer* CommittedD3D11CBs[], - ID3D11ShaderResourceView* CommittedD3D11SRVs[], - ID3D11Resource* CommittedD3D11SRVResources[], - ID3D11SamplerState* CommittedD3D11Samplers[], - ID3D11UnorderedAccessView* CommittedD3D11UAVs[], - ID3D11Resource* CommittedD3D11UAVResources[], - ShaderResourceCacheD3D11& ResourceCache) const -{ - ShaderResourceCacheD3D11::CachedCB* CachedCBs = nullptr; - ID3D11Buffer** d3d11CBs = nullptr; - ShaderResourceCacheD3D11::CachedResource* CachedSRVResources = nullptr; - ID3D11ShaderResourceView** d3d11SRVs = nullptr; - ShaderResourceCacheD3D11::CachedSampler* CachedSamplers = nullptr; - ID3D11SamplerState** d3d11Samplers = nullptr; - ShaderResourceCacheD3D11::CachedResource* CachedUAVResources = nullptr; - ID3D11UnorderedAccessView** d3d11UAVs = nullptr; - // clang-format off - ResourceCache.GetCBArrays (CachedCBs, d3d11CBs); - ResourceCache.GetSRVArrays (CachedSRVResources, d3d11SRVs); - ResourceCache.GetSamplerArrays(CachedSamplers, d3d11Samplers); - ResourceCache.GetUAVArrays (CachedUAVResources, d3d11UAVs); - // clang-format on - - ProcessResources( - [&](const D3DShaderResourceAttribs& cb, Uint32) // - { - for (auto BindPoint = cb.BindPoint; BindPoint < cb.BindPoint + cb.BindCount; ++BindPoint) - { - if (BindPoint >= ResourceCache.GetCBCount()) - { - LOG_ERROR_MESSAGE("Unable to find constant buffer '", DbgMakeResourceName(cb, BindPoint), "' (slot ", - BindPoint, ") in the resource cache: the cache reserves ", ResourceCache.GetCBCount(), - " CB slots only. This should never happen and may be the result of using wrong resource cache."); - continue; - } - auto& CB = CachedCBs[BindPoint]; - if (CB.pBuff == nullptr) - { - LOG_ERROR_MESSAGE("Constant buffer '", DbgMakeResourceName(cb, BindPoint), "' (slot ", - BindPoint, ") is not initialized in the resource cache."); - continue; - } - - if (!(CB.pBuff->GetDesc().BindFlags & BIND_UNIFORM_BUFFER)) - { - LOG_ERROR_MESSAGE("Buffer '", CB.pBuff->GetDesc().Name, - "' committed in the device context as constant buffer to variable '", - DbgMakeResourceName(cb, BindPoint), "' (slot ", BindPoint, - ") in shader '", GetShaderName(), "' was not created with BIND_UNIFORM_BUFFER flag"); - continue; - } - - VERIFY_EXPR(d3d11CBs[BindPoint] == CB.pBuff->GetD3D11Buffer()); - - if (CommittedD3D11CBs[BindPoint] == nullptr) - { - LOG_ERROR_MESSAGE("No D3D11 resource committed to constant buffer '", DbgMakeResourceName(cb, BindPoint), - "' (slot ", BindPoint, ") in shader '", GetShaderName(), "'"); - continue; - } - - if (CommittedD3D11CBs[BindPoint] != d3d11CBs[BindPoint]) - { - LOG_ERROR_MESSAGE("D3D11 resource committed to constant buffer '", DbgMakeResourceName(cb, BindPoint), - "' (slot ", BindPoint, ") in shader '", GetShaderName(), "' does not match the resource in the resource cache"); - continue; - } - } - }, - - [&](const D3DShaderResourceAttribs& sam, Uint32) // - { - for (auto BindPoint = sam.BindPoint; BindPoint < sam.BindPoint + sam.BindCount; ++BindPoint) - { - if (BindPoint >= ResourceCache.GetSamplerCount()) - { - LOG_ERROR_MESSAGE("Unable to find sampler '", DbgMakeResourceName(sam, BindPoint), "' (slot ", BindPoint, - ") in the resource cache: the cache reserves ", ResourceCache.GetSamplerCount(), - " Sampler slots only. This should never happen and may be the result of using wrong resource cache."); - continue; - } - auto& Sam = CachedSamplers[BindPoint]; - if (Sam.pSampler == nullptr) - { - LOG_ERROR_MESSAGE("Sampler '", DbgMakeResourceName(sam, BindPoint), "' (slot ", BindPoint, - ") is not initialized in the resource cache."); - continue; - } - VERIFY_EXPR(d3d11Samplers[BindPoint] == Sam.pSampler->GetD3D11SamplerState()); - - if (CommittedD3D11Samplers[BindPoint] == nullptr) - { - LOG_ERROR_MESSAGE("No D3D11 sampler committed to variable '", DbgMakeResourceName(sam, BindPoint), - "' (slot ", BindPoint, ") in shader '", GetShaderName(), "'"); - continue; - } - - if (CommittedD3D11Samplers[BindPoint] != d3d11Samplers[BindPoint]) - { - LOG_ERROR_MESSAGE("D3D11 sampler committed to variable '", DbgMakeResourceName(sam, BindPoint), - "' (slot ", BindPoint, ") in shader '", GetShaderName(), "' does not match the resource in the resource cache"); - continue; - } - } - }, - - [&](const D3DShaderResourceAttribs& tex, Uint32) // - { - for (auto BindPoint = tex.BindPoint; BindPoint < tex.BindPoint + tex.BindCount; ++BindPoint) - { - if (BindPoint >= ResourceCache.GetSRVCount()) - { - LOG_ERROR_MESSAGE("Unable to find texture SRV '", DbgMakeResourceName(tex, BindPoint), "' (slot ", - BindPoint, ") in the resource cache: the cache reserves ", ResourceCache.GetSRVCount(), - " SRV slots only. This should never happen and may be the result of using wrong resource cache."); - continue; - } - auto& SRVRes = CachedSRVResources[BindPoint]; - if (SRVRes.pBuffer != nullptr) - { - LOG_ERROR_MESSAGE("Unexpected buffer bound to variable '", DbgMakeResourceName(tex, BindPoint), "' (slot ", - BindPoint, "). Texture is expected."); - continue; - } - if (SRVRes.pTexture == nullptr) - { - LOG_ERROR_MESSAGE("Texture '", DbgMakeResourceName(tex, BindPoint), "' (slot ", BindPoint, - ") is not initialized in the resource cache."); - continue; - } - - if (!(SRVRes.pTexture->GetDesc().BindFlags & BIND_SHADER_RESOURCE)) - { - LOG_ERROR_MESSAGE("Texture '", SRVRes.pTexture->GetDesc().Name, - "' committed in the device context as SRV to variable '", DbgMakeResourceName(tex, BindPoint), - "' (slot ", BindPoint, ") in shader '", GetShaderName(), "' was not created with BIND_SHADER_RESOURCE flag"); - } - - if (CommittedD3D11SRVs[BindPoint] == nullptr) - { - LOG_ERROR_MESSAGE("No D3D11 resource committed to texture SRV '", DbgMakeResourceName(tex, BindPoint), - "' (slot ", BindPoint, ") in shader '", GetShaderName(), "'"); - continue; - } - - if (CommittedD3D11SRVs[BindPoint] != d3d11SRVs[BindPoint]) - { - LOG_ERROR_MESSAGE("D3D11 resource committed to texture SRV '", DbgMakeResourceName(tex, BindPoint), - "' (slot ", BindPoint, ") in shader '", GetShaderName(), - "' does not match the resource in the resource cache"); - continue; - } - } - - if (tex.IsCombinedWithSampler()) - { - const auto& SamAttribs = GetCombinedSampler(tex); - VERIFY_EXPR(SamAttribs.IsValidBindPoint()); - VERIFY_EXPR(SamAttribs.BindCount == 1 || SamAttribs.BindCount == tex.BindCount); - } - }, - - [&](const D3DShaderResourceAttribs& uav, Uint32) // - { - for (auto BindPoint = uav.BindPoint; BindPoint < uav.BindPoint + uav.BindCount; ++BindPoint) - { - if (BindPoint >= ResourceCache.GetUAVCount()) - { - LOG_ERROR_MESSAGE("Unable to find texture UAV '", DbgMakeResourceName(uav, BindPoint), "' (slot ", - BindPoint, ") in the resource cache: the cache reserves ", ResourceCache.GetUAVCount(), - " UAV slots only. This should never happen and may be the result of using wrong resource cache."); - continue; - } - auto& UAVRes = CachedUAVResources[BindPoint]; - if (UAVRes.pBuffer != nullptr) - { - LOG_ERROR_MESSAGE("Unexpected buffer bound to variable '", DbgMakeResourceName(uav, BindPoint), - "' (slot ", BindPoint, "). Texture is expected."); - continue; - } - if (UAVRes.pTexture == nullptr) - { - LOG_ERROR_MESSAGE("Texture '", DbgMakeResourceName(uav, BindPoint), "' (slot ", BindPoint, - ") is not initialized in the resource cache."); - continue; - } - - if (!(UAVRes.pTexture->GetDesc().BindFlags & BIND_UNORDERED_ACCESS)) - { - LOG_ERROR_MESSAGE("Texture '", UAVRes.pTexture->GetDesc().Name, - "' committed in the device context as UAV to variable '", DbgMakeResourceName(uav, BindPoint), "' (slot ", BindPoint, ") in shader '", GetShaderName(), "' was not created with BIND_UNORDERED_ACCESS flag"); - } - - if (CommittedD3D11UAVs[BindPoint] == nullptr) - { - LOG_ERROR_MESSAGE("No D3D11 resource committed to texture UAV '", DbgMakeResourceName(uav, BindPoint), - "' (slot ", BindPoint, ") in shader '", GetShaderName(), "'"); - continue; - } - - if (CommittedD3D11UAVs[BindPoint] != d3d11UAVs[BindPoint]) - { - LOG_ERROR_MESSAGE("D3D11 resource committed to texture UAV '", DbgMakeResourceName(uav, BindPoint), - "' (slot ", BindPoint, ") in shader '", GetShaderName(), "' does not match the resource in the resource cache"); - continue; - } - } - }, - - - [&](const D3DShaderResourceAttribs& buf, Uint32) // - { - for (auto BindPoint = buf.BindPoint; BindPoint < buf.BindPoint + buf.BindCount; ++BindPoint) - { - if (BindPoint >= ResourceCache.GetSRVCount()) - { - LOG_ERROR_MESSAGE("Unable to find buffer SRV '", DbgMakeResourceName(buf, BindPoint), "' (slot ", BindPoint, - ") in the resource cache: the cache reserves ", ResourceCache.GetSRVCount(), - " SRV slots only. This should never happen and may be the result of using wrong resource cache."); - continue; - } - auto& SRVRes = CachedSRVResources[BindPoint]; - if (SRVRes.pTexture != nullptr) - { - LOG_ERROR_MESSAGE("Unexpected texture bound to variable '", DbgMakeResourceName(buf, BindPoint), - "' (slot ", BindPoint, "). Buffer is expected."); - continue; - } - if (SRVRes.pBuffer == nullptr) - { - LOG_ERROR_MESSAGE("Buffer '", DbgMakeResourceName(buf, BindPoint), "' (slot ", BindPoint, - ") is not initialized in the resource cache."); - continue; - } - - if (!(SRVRes.pBuffer->GetDesc().BindFlags & BIND_SHADER_RESOURCE)) - { - LOG_ERROR_MESSAGE("Buffer '", SRVRes.pBuffer->GetDesc().Name, - "' committed in the device context as SRV to variable '", DbgMakeResourceName(buf, BindPoint), - "' (slot ", BindPoint, ") in shader '", GetShaderName(), - "' was not created with BIND_SHADER_RESOURCE flag"); - } - - if (CommittedD3D11SRVs[BindPoint] == nullptr) - { - LOG_ERROR_MESSAGE("No D3D11 resource committed to buffer SRV '", DbgMakeResourceName(buf, BindPoint), - "' (slot ", BindPoint, ") in shader '", GetShaderName(), "'"); - continue; - } - - if (CommittedD3D11SRVs[BindPoint] != d3d11SRVs[BindPoint]) - { - LOG_ERROR_MESSAGE("D3D11 resource committed to buffer SRV '", DbgMakeResourceName(buf, BindPoint), - "' (slot ", BindPoint, ") in shader '", GetShaderName(), - "' does not match the resource in the resource cache"); - continue; - } - } - }, - - [&](const D3DShaderResourceAttribs& uav, Uint32) // - { - for (auto BindPoint = uav.BindPoint; BindPoint < uav.BindPoint + uav.BindCount; ++BindPoint) - { - if (BindPoint >= ResourceCache.GetUAVCount()) - { - LOG_ERROR_MESSAGE("Unable to find buffer UAV '", DbgMakeResourceName(uav, BindPoint), "' (slot ", BindPoint, - ") in the resource cache: the cache reserves ", ResourceCache.GetUAVCount(), - " UAV slots only. This should never happen and may be the result of using wrong resource cache."); - continue; - } - auto& UAVRes = CachedUAVResources[BindPoint]; - if (UAVRes.pTexture != nullptr) - { - LOG_ERROR_MESSAGE("Unexpected texture bound to variable '", DbgMakeResourceName(uav, BindPoint), - "' (slot ", BindPoint, "). Buffer is expected."); - return; - } - if (UAVRes.pBuffer == nullptr) - { - LOG_ERROR_MESSAGE("Buffer UAV '", DbgMakeResourceName(uav, BindPoint), "' (slot ", BindPoint, - ") is not initialized in the resource cache."); - return; - } - - if (!(UAVRes.pBuffer->GetDesc().BindFlags & BIND_UNORDERED_ACCESS)) - { - LOG_ERROR_MESSAGE("Buffer '", UAVRes.pBuffer->GetDesc().Name, - "' committed in the device context as UAV to variable '", DbgMakeResourceName(uav, BindPoint), "' (slot ", BindPoint, ") in shader '", GetShaderName(), "' was not created with BIND_UNORDERED_ACCESS flag"); - } - - if (CommittedD3D11UAVs[BindPoint] == nullptr) - { - LOG_ERROR_MESSAGE("No D3D11 resource committed to buffer UAV '", DbgMakeResourceName(uav, BindPoint), - "' (slot ", BindPoint, ") in shader '", GetShaderName(), "'"); - return; - } - - if (CommittedD3D11UAVs[BindPoint] != d3d11UAVs[BindPoint]) - { - LOG_ERROR_MESSAGE("D3D11 resource committed to buffer UAV '", DbgMakeResourceName(uav, BindPoint), - "' (slot ", BindPoint, ") in shader '", GetShaderName(), - "' does not match the resource in the resource cache"); - return; - } - } - } // clang-format off - ); // clang-format on -} -#endif - -} // namespace Diligent +/* + * 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 +#include "ShaderResourcesD3D11.hpp" +#include "ShaderBase.hpp" +#include "ShaderResourceCacheD3D11.hpp" +#include "RenderDeviceD3D11Impl.hpp" + +namespace Diligent +{ + + +ShaderResourcesD3D11::ShaderResourcesD3D11(RenderDeviceD3D11Impl* pDeviceD3D11Impl, + ID3DBlob* pShaderBytecode, + const ShaderDesc& ShdrDesc, + const char* CombinedSamplerSuffix) : + ShaderResources{ShdrDesc.ShaderType} +{ + class NewResourceHandler + { + public: + NewResourceHandler(RenderDeviceD3D11Impl* const _pDeviceD3D11Impl, + const ShaderDesc& _ShdrDesc, + const char* _CombinedSamplerSuffix, + ShaderResourcesD3D11& _Resources) : + // clang-format off + pDeviceD3D11Impl {_pDeviceD3D11Impl }, + ShdrDesc {_ShdrDesc }, + CombinedSamplerSuffix{_CombinedSamplerSuffix}, + Resources {_Resources } + // clang-format on + {} + + void OnNewCB(const D3DShaderResourceAttribs& CBAttribs) + { + VERIFY(CBAttribs.BindPoint + CBAttribs.BindCount - 1 <= MaxAllowedBindPoint, "CB bind point exceeds supported range"); + Resources.m_MaxCBBindPoint = std::max(Resources.m_MaxCBBindPoint, static_cast(CBAttribs.BindPoint + CBAttribs.BindCount - 1)); + } + + void OnNewTexUAV(const D3DShaderResourceAttribs& TexUAV) + { + VERIFY(TexUAV.BindPoint + TexUAV.BindCount - 1 <= MaxAllowedBindPoint, "Tex UAV bind point exceeds supported range"); + Resources.m_MaxUAVBindPoint = std::max(Resources.m_MaxUAVBindPoint, static_cast(TexUAV.BindPoint + TexUAV.BindCount - 1)); + } + + void OnNewBuffUAV(const D3DShaderResourceAttribs& BuffUAV) + { + VERIFY(BuffUAV.BindPoint + BuffUAV.BindCount - 1 <= MaxAllowedBindPoint, "Buff UAV bind point exceeds supported range"); + Resources.m_MaxUAVBindPoint = std::max(Resources.m_MaxUAVBindPoint, static_cast(BuffUAV.BindPoint + BuffUAV.BindCount - 1)); + } + + void OnNewBuffSRV(const D3DShaderResourceAttribs& BuffSRV) + { + VERIFY(BuffSRV.BindPoint + BuffSRV.BindCount - 1 <= MaxAllowedBindPoint, "Buff SRV bind point exceeds supported range"); + Resources.m_MaxSRVBindPoint = std::max(Resources.m_MaxSRVBindPoint, static_cast(BuffSRV.BindPoint + BuffSRV.BindCount - 1)); + } + + void OnNewSampler(const D3DShaderResourceAttribs& SamplerAttribs) + { + VERIFY(SamplerAttribs.BindPoint + SamplerAttribs.BindCount - 1 <= MaxAllowedBindPoint, "Sampler bind point exceeds supported range"); + Resources.m_MaxSamplerBindPoint = std::max(Resources.m_MaxSamplerBindPoint, static_cast(SamplerAttribs.BindPoint + SamplerAttribs.BindCount - 1)); + } + + void OnNewTexSRV(const D3DShaderResourceAttribs& TexAttribs) + { + VERIFY(TexAttribs.BindPoint + TexAttribs.BindCount - 1 <= MaxAllowedBindPoint, "Tex SRV bind point exceeds supported range"); + Resources.m_MaxSRVBindPoint = std::max(Resources.m_MaxSRVBindPoint, static_cast(TexAttribs.BindPoint + TexAttribs.BindCount - 1)); + } + + ~NewResourceHandler() + { + } + + private: + RenderDeviceD3D11Impl* const pDeviceD3D11Impl; + const ShaderDesc& ShdrDesc; + const char* CombinedSamplerSuffix; + ShaderResourcesD3D11& Resources; + }; + + CComPtr pShaderReflection; + HRESULT hr = D3DReflect(pShaderBytecode->GetBufferPointer(), pShaderBytecode->GetBufferSize(), __uuidof(pShaderReflection), reinterpret_cast(&pShaderReflection)); + CHECK_D3D_RESULT_THROW(hr, "Failed to get the shader reflection"); + + + Initialize( + static_cast(pShaderReflection), + NewResourceHandler{pDeviceD3D11Impl, ShdrDesc, CombinedSamplerSuffix, *this}, + ShdrDesc.Name, + CombinedSamplerSuffix); +} + + +ShaderResourcesD3D11::~ShaderResourcesD3D11() +{ +} + + +#ifdef DILIGENT_DEVELOPMENT +static String DbgMakeResourceName(const D3DShaderResourceAttribs& Attr, Uint32 BindPoint) +{ + VERIFY(BindPoint >= Uint32{Attr.BindPoint} && BindPoint < Uint32{Attr.BindPoint} + Attr.BindCount, "Bind point is out of allowed range"); + if (Attr.BindCount == 1) + return Attr.Name; + else + return String(Attr.Name) + '[' + std::to_string(BindPoint - Attr.BindPoint) + ']'; +} + +void ShaderResourcesD3D11::dvpVerifyCommittedResources(ID3D11Buffer* CommittedD3D11CBs[], + ID3D11ShaderResourceView* CommittedD3D11SRVs[], + ID3D11Resource* CommittedD3D11SRVResources[], + ID3D11SamplerState* CommittedD3D11Samplers[], + ID3D11UnorderedAccessView* CommittedD3D11UAVs[], + ID3D11Resource* CommittedD3D11UAVResources[], + ShaderResourceCacheD3D11& ResourceCache) const +{ + ShaderResourceCacheD3D11::CachedCB* CachedCBs = nullptr; + ID3D11Buffer** d3d11CBs = nullptr; + ShaderResourceCacheD3D11::CachedResource* CachedSRVResources = nullptr; + ID3D11ShaderResourceView** d3d11SRVs = nullptr; + ShaderResourceCacheD3D11::CachedSampler* CachedSamplers = nullptr; + ID3D11SamplerState** d3d11Samplers = nullptr; + ShaderResourceCacheD3D11::CachedResource* CachedUAVResources = nullptr; + ID3D11UnorderedAccessView** d3d11UAVs = nullptr; + // clang-format off + ResourceCache.GetCBArrays (CachedCBs, d3d11CBs); + ResourceCache.GetSRVArrays (CachedSRVResources, d3d11SRVs); + ResourceCache.GetSamplerArrays(CachedSamplers, d3d11Samplers); + ResourceCache.GetUAVArrays (CachedUAVResources, d3d11UAVs); + // clang-format on + + ProcessResources( + [&](const D3DShaderResourceAttribs& cb, Uint32) // + { + for (auto BindPoint = cb.BindPoint; BindPoint < cb.BindPoint + cb.BindCount; ++BindPoint) + { + if (BindPoint >= ResourceCache.GetCBCount()) + { + LOG_ERROR_MESSAGE("Unable to find constant buffer '", DbgMakeResourceName(cb, BindPoint), "' (slot ", + BindPoint, ") in the resource cache: the cache reserves ", ResourceCache.GetCBCount(), + " CB slots only. This should never happen and may be the result of using wrong resource cache."); + continue; + } + auto& CB = CachedCBs[BindPoint]; + if (CB.pBuff == nullptr) + { + LOG_ERROR_MESSAGE("Constant buffer '", DbgMakeResourceName(cb, BindPoint), "' (slot ", + BindPoint, ") is not initialized in the resource cache."); + continue; + } + + if (!(CB.pBuff->GetDesc().BindFlags & BIND_UNIFORM_BUFFER)) + { + LOG_ERROR_MESSAGE("Buffer '", CB.pBuff->GetDesc().Name, + "' committed in the device context as constant buffer to variable '", + DbgMakeResourceName(cb, BindPoint), "' (slot ", BindPoint, + ") in shader '", GetShaderName(), "' was not created with BIND_UNIFORM_BUFFER flag"); + continue; + } + + VERIFY_EXPR(d3d11CBs[BindPoint] == CB.pBuff->GetD3D11Buffer()); + + if (CommittedD3D11CBs[BindPoint] == nullptr) + { + LOG_ERROR_MESSAGE("No D3D11 resource committed to constant buffer '", DbgMakeResourceName(cb, BindPoint), + "' (slot ", BindPoint, ") in shader '", GetShaderName(), "'"); + continue; + } + + if (CommittedD3D11CBs[BindPoint] != d3d11CBs[BindPoint]) + { + LOG_ERROR_MESSAGE("D3D11 resource committed to constant buffer '", DbgMakeResourceName(cb, BindPoint), + "' (slot ", BindPoint, ") in shader '", GetShaderName(), "' does not match the resource in the resource cache"); + continue; + } + } + }, + + [&](const D3DShaderResourceAttribs& sam, Uint32) // + { + for (auto BindPoint = sam.BindPoint; BindPoint < sam.BindPoint + sam.BindCount; ++BindPoint) + { + if (BindPoint >= ResourceCache.GetSamplerCount()) + { + LOG_ERROR_MESSAGE("Unable to find sampler '", DbgMakeResourceName(sam, BindPoint), "' (slot ", BindPoint, + ") in the resource cache: the cache reserves ", ResourceCache.GetSamplerCount(), + " Sampler slots only. This should never happen and may be the result of using wrong resource cache."); + continue; + } + auto& Sam = CachedSamplers[BindPoint]; + if (Sam.pSampler == nullptr) + { + LOG_ERROR_MESSAGE("Sampler '", DbgMakeResourceName(sam, BindPoint), "' (slot ", BindPoint, + ") is not initialized in the resource cache."); + continue; + } + VERIFY_EXPR(d3d11Samplers[BindPoint] == Sam.pSampler->GetD3D11SamplerState()); + + if (CommittedD3D11Samplers[BindPoint] == nullptr) + { + LOG_ERROR_MESSAGE("No D3D11 sampler committed to variable '", DbgMakeResourceName(sam, BindPoint), + "' (slot ", BindPoint, ") in shader '", GetShaderName(), "'"); + continue; + } + + if (CommittedD3D11Samplers[BindPoint] != d3d11Samplers[BindPoint]) + { + LOG_ERROR_MESSAGE("D3D11 sampler committed to variable '", DbgMakeResourceName(sam, BindPoint), + "' (slot ", BindPoint, ") in shader '", GetShaderName(), "' does not match the resource in the resource cache"); + continue; + } + } + }, + + [&](const D3DShaderResourceAttribs& tex, Uint32) // + { + for (auto BindPoint = tex.BindPoint; BindPoint < tex.BindPoint + tex.BindCount; ++BindPoint) + { + if (BindPoint >= ResourceCache.GetSRVCount()) + { + LOG_ERROR_MESSAGE("Unable to find texture SRV '", DbgMakeResourceName(tex, BindPoint), "' (slot ", + BindPoint, ") in the resource cache: the cache reserves ", ResourceCache.GetSRVCount(), + " SRV slots only. This should never happen and may be the result of using wrong resource cache."); + continue; + } + auto& SRVRes = CachedSRVResources[BindPoint]; + if (SRVRes.pBuffer != nullptr) + { + LOG_ERROR_MESSAGE("Unexpected buffer bound to variable '", DbgMakeResourceName(tex, BindPoint), "' (slot ", + BindPoint, "). Texture is expected."); + continue; + } + if (SRVRes.pTexture == nullptr) + { + LOG_ERROR_MESSAGE("Texture '", DbgMakeResourceName(tex, BindPoint), "' (slot ", BindPoint, + ") is not initialized in the resource cache."); + continue; + } + + if (!(SRVRes.pTexture->GetDesc().BindFlags & BIND_SHADER_RESOURCE)) + { + LOG_ERROR_MESSAGE("Texture '", SRVRes.pTexture->GetDesc().Name, + "' committed in the device context as SRV to variable '", DbgMakeResourceName(tex, BindPoint), + "' (slot ", BindPoint, ") in shader '", GetShaderName(), "' was not created with BIND_SHADER_RESOURCE flag"); + } + + if (CommittedD3D11SRVs[BindPoint] == nullptr) + { + LOG_ERROR_MESSAGE("No D3D11 resource committed to texture SRV '", DbgMakeResourceName(tex, BindPoint), + "' (slot ", BindPoint, ") in shader '", GetShaderName(), "'"); + continue; + } + + if (CommittedD3D11SRVs[BindPoint] != d3d11SRVs[BindPoint]) + { + LOG_ERROR_MESSAGE("D3D11 resource committed to texture SRV '", DbgMakeResourceName(tex, BindPoint), + "' (slot ", BindPoint, ") in shader '", GetShaderName(), + "' does not match the resource in the resource cache"); + continue; + } + } + + if (tex.IsCombinedWithSampler()) + { + const auto& SamAttribs = GetCombinedSampler(tex); + VERIFY_EXPR(SamAttribs.IsValidBindPoint()); + VERIFY_EXPR(SamAttribs.BindCount == 1 || SamAttribs.BindCount == tex.BindCount); + } + }, + + [&](const D3DShaderResourceAttribs& uav, Uint32) // + { + for (auto BindPoint = uav.BindPoint; BindPoint < uav.BindPoint + uav.BindCount; ++BindPoint) + { + if (BindPoint >= ResourceCache.GetUAVCount()) + { + LOG_ERROR_MESSAGE("Unable to find texture UAV '", DbgMakeResourceName(uav, BindPoint), "' (slot ", + BindPoint, ") in the resource cache: the cache reserves ", ResourceCache.GetUAVCount(), + " UAV slots only. This should never happen and may be the result of using wrong resource cache."); + continue; + } + auto& UAVRes = CachedUAVResources[BindPoint]; + if (UAVRes.pBuffer != nullptr) + { + LOG_ERROR_MESSAGE("Unexpected buffer bound to variable '", DbgMakeResourceName(uav, BindPoint), + "' (slot ", BindPoint, "). Texture is expected."); + continue; + } + if (UAVRes.pTexture == nullptr) + { + LOG_ERROR_MESSAGE("Texture '", DbgMakeResourceName(uav, BindPoint), "' (slot ", BindPoint, + ") is not initialized in the resource cache."); + continue; + } + + if (!(UAVRes.pTexture->GetDesc().BindFlags & BIND_UNORDERED_ACCESS)) + { + LOG_ERROR_MESSAGE("Texture '", UAVRes.pTexture->GetDesc().Name, + "' committed in the device context as UAV to variable '", DbgMakeResourceName(uav, BindPoint), "' (slot ", BindPoint, ") in shader '", GetShaderName(), "' was not created with BIND_UNORDERED_ACCESS flag"); + } + + if (CommittedD3D11UAVs[BindPoint] == nullptr) + { + LOG_ERROR_MESSAGE("No D3D11 resource committed to texture UAV '", DbgMakeResourceName(uav, BindPoint), + "' (slot ", BindPoint, ") in shader '", GetShaderName(), "'"); + continue; + } + + if (CommittedD3D11UAVs[BindPoint] != d3d11UAVs[BindPoint]) + { + LOG_ERROR_MESSAGE("D3D11 resource committed to texture UAV '", DbgMakeResourceName(uav, BindPoint), + "' (slot ", BindPoint, ") in shader '", GetShaderName(), "' does not match the resource in the resource cache"); + continue; + } + } + }, + + + [&](const D3DShaderResourceAttribs& buf, Uint32) // + { + for (auto BindPoint = buf.BindPoint; BindPoint < buf.BindPoint + buf.BindCount; ++BindPoint) + { + if (BindPoint >= ResourceCache.GetSRVCount()) + { + LOG_ERROR_MESSAGE("Unable to find buffer SRV '", DbgMakeResourceName(buf, BindPoint), "' (slot ", BindPoint, + ") in the resource cache: the cache reserves ", ResourceCache.GetSRVCount(), + " SRV slots only. This should never happen and may be the result of using wrong resource cache."); + continue; + } + auto& SRVRes = CachedSRVResources[BindPoint]; + if (SRVRes.pTexture != nullptr) + { + LOG_ERROR_MESSAGE("Unexpected texture bound to variable '", DbgMakeResourceName(buf, BindPoint), + "' (slot ", BindPoint, "). Buffer is expected."); + continue; + } + if (SRVRes.pBuffer == nullptr) + { + LOG_ERROR_MESSAGE("Buffer '", DbgMakeResourceName(buf, BindPoint), "' (slot ", BindPoint, + ") is not initialized in the resource cache."); + continue; + } + + if (!(SRVRes.pBuffer->GetDesc().BindFlags & BIND_SHADER_RESOURCE)) + { + LOG_ERROR_MESSAGE("Buffer '", SRVRes.pBuffer->GetDesc().Name, + "' committed in the device context as SRV to variable '", DbgMakeResourceName(buf, BindPoint), + "' (slot ", BindPoint, ") in shader '", GetShaderName(), + "' was not created with BIND_SHADER_RESOURCE flag"); + } + + if (CommittedD3D11SRVs[BindPoint] == nullptr) + { + LOG_ERROR_MESSAGE("No D3D11 resource committed to buffer SRV '", DbgMakeResourceName(buf, BindPoint), + "' (slot ", BindPoint, ") in shader '", GetShaderName(), "'"); + continue; + } + + if (CommittedD3D11SRVs[BindPoint] != d3d11SRVs[BindPoint]) + { + LOG_ERROR_MESSAGE("D3D11 resource committed to buffer SRV '", DbgMakeResourceName(buf, BindPoint), + "' (slot ", BindPoint, ") in shader '", GetShaderName(), + "' does not match the resource in the resource cache"); + continue; + } + } + }, + + [&](const D3DShaderResourceAttribs& uav, Uint32) // + { + for (auto BindPoint = uav.BindPoint; BindPoint < uav.BindPoint + uav.BindCount; ++BindPoint) + { + if (BindPoint >= ResourceCache.GetUAVCount()) + { + LOG_ERROR_MESSAGE("Unable to find buffer UAV '", DbgMakeResourceName(uav, BindPoint), "' (slot ", BindPoint, + ") in the resource cache: the cache reserves ", ResourceCache.GetUAVCount(), + " UAV slots only. This should never happen and may be the result of using wrong resource cache."); + continue; + } + auto& UAVRes = CachedUAVResources[BindPoint]; + if (UAVRes.pTexture != nullptr) + { + LOG_ERROR_MESSAGE("Unexpected texture bound to variable '", DbgMakeResourceName(uav, BindPoint), + "' (slot ", BindPoint, "). Buffer is expected."); + return; + } + if (UAVRes.pBuffer == nullptr) + { + LOG_ERROR_MESSAGE("Buffer UAV '", DbgMakeResourceName(uav, BindPoint), "' (slot ", BindPoint, + ") is not initialized in the resource cache."); + return; + } + + if (!(UAVRes.pBuffer->GetDesc().BindFlags & BIND_UNORDERED_ACCESS)) + { + LOG_ERROR_MESSAGE("Buffer '", UAVRes.pBuffer->GetDesc().Name, + "' committed in the device context as UAV to variable '", DbgMakeResourceName(uav, BindPoint), "' (slot ", BindPoint, ") in shader '", GetShaderName(), "' was not created with BIND_UNORDERED_ACCESS flag"); + } + + if (CommittedD3D11UAVs[BindPoint] == nullptr) + { + LOG_ERROR_MESSAGE("No D3D11 resource committed to buffer UAV '", DbgMakeResourceName(uav, BindPoint), + "' (slot ", BindPoint, ") in shader '", GetShaderName(), "'"); + return; + } + + if (CommittedD3D11UAVs[BindPoint] != d3d11UAVs[BindPoint]) + { + LOG_ERROR_MESSAGE("D3D11 resource committed to buffer UAV '", DbgMakeResourceName(uav, BindPoint), + "' (slot ", BindPoint, ") in shader '", GetShaderName(), + "' does not match the resource in the resource cache"); + return; + } + } + } // clang-format off + ); // clang-format on +} +#endif + +} // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/CMakeLists.txt b/Graphics/GraphicsEngineD3D12/CMakeLists.txt index 6ea2fc22..4fe2a6c3 100644 --- a/Graphics/GraphicsEngineD3D12/CMakeLists.txt +++ b/Graphics/GraphicsEngineD3D12/CMakeLists.txt @@ -171,6 +171,14 @@ PUBLIC ) target_compile_definitions(Diligent-GraphicsEngineD3D12-shared PUBLIC ENGINE_DLL=1) +if(${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION} STRGREATER_EQUAL "10.0.19041.0") + target_compile_definitions(Diligent-GraphicsEngineD3D12-static PRIVATE D12_H_HAS_MESH_SHADER) +endif() +if(${HAS_DXIL_COMPILER}) + target_compile_definitions(Diligent-GraphicsEngineD3D12-static PRIVATE HAS_DXIL_COMPILER) + target_link_libraries(Diligent-GraphicsEngineD3D12-static PRIVATE dxcompiler.lib) +endif() + # Set output name to GraphicsEngineD3D12_{32|64}{r|d} set_dll_output_name(Diligent-GraphicsEngineD3D12-shared GraphicsEngineD3D12) diff --git a/Graphics/GraphicsEngineD3D12/include/CommandContext.hpp b/Graphics/GraphicsEngineD3D12/include/CommandContext.hpp index a8211db6..f5e3e681 100644 --- a/Graphics/GraphicsEngineD3D12/include/CommandContext.hpp +++ b/Graphics/GraphicsEngineD3D12/include/CommandContext.hpp @@ -339,6 +339,18 @@ public: FlushResourceBarriers(); m_pCommandList->DrawIndexedInstanced(IndexCountPerInstance, InstanceCount, StartIndexLocation, BaseVertexLocation, StartInstanceLocation); } + + void DrawMesh(UINT ThreadGroupCountX, UINT ThreadGroupCountY, UINT ThreadGroupCountZ) + { +#ifdef D12_H_HAS_MESH_SHADER + FlushResourceBarriers(); + CComPtr CmdList; + if (SUCCEEDED(m_pCommandList->QueryInterface(__uuidof(CmdList), reinterpret_cast(&CmdList)))) + CmdList->DispatchMesh(ThreadGroupCountX, ThreadGroupCountY, ThreadGroupCountZ); +#else + UNSUPPORTED("DrawMesh is not supported in current D3D12 header"); +#endif + } }; class ComputeContext : public CommandContext diff --git a/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.hpp index 5c6912b6..f7359ec8 100644 --- a/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.hpp +++ b/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.hpp @@ -131,6 +131,10 @@ public: virtual void DILIGENT_CALL_TYPE DrawIndirect (const DrawIndirectAttribs& Attribs, IBuffer* pAttribsBuffer) override final; /// Implementation of IDeviceContext::DrawIndexedIndirect() in Direct3D12 backend. virtual void DILIGENT_CALL_TYPE DrawIndexedIndirect(const DrawIndexedIndirectAttribs& Attribs, IBuffer* pAttribsBuffer) override final; + /// Implementation of IDeviceContext::DrawMesh() in Direct3D12 backend. + virtual void DILIGENT_CALL_TYPE DrawMesh (const DrawMeshAttribs& Attribs) override final; + /// Implementation of IDeviceContext::DrawMeshIndirect() in Direct3D12 backend. + virtual void DILIGENT_CALL_TYPE DrawMeshIndirect (const DrawMeshIndirectAttribs& Attribs, IBuffer* pAttribsBuffer) override final; /// Implementation of IDeviceContext::DispatchCompute() in Direct3D12 backend. @@ -382,6 +386,7 @@ private: CComPtr m_pDrawIndirectSignature; CComPtr m_pDrawIndexedIndirectSignature; CComPtr m_pDispatchIndirectSignature; + CComPtr m_pDrawMeshIndirectSignature; D3D12DynamicHeap m_DynamicHeap; diff --git a/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.hpp index 303f8bfb..7f4446ac 100644 --- a/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.hpp +++ b/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.hpp @@ -143,6 +143,7 @@ public: const GenerateMipsHelper& GetMipsGenerator() const { return m_MipsGenerator; } QueryManagerD3D12& GetQueryManager() { return m_QueryMgr; } + D3D_SHADER_MODEL GetShaderModel() const; D3D_FEATURE_LEVEL GetD3DFeatureLevel() const; private: diff --git a/Graphics/GraphicsEngineD3D12/include/ShaderResourcesD3D12.hpp b/Graphics/GraphicsEngineD3D12/include/ShaderResourcesD3D12.hpp index 23f9882b..88c1cdc5 100644 --- a/Graphics/GraphicsEngineD3D12/include/ShaderResourcesD3D12.hpp +++ b/Graphics/GraphicsEngineD3D12/include/ShaderResourcesD3D12.hpp @@ -92,7 +92,7 @@ class ShaderResourcesD3D12 final : public ShaderResources { public: // Loads shader resources from the compiled shader bytecode - ShaderResourcesD3D12(ID3DBlob* pShaderBytecode, const ShaderDesc& ShdrDesc, const char* CombinedSamplerSuffix); + ShaderResourcesD3D12(ID3DBlob* pShaderBytecode, bool isDXIL, const ShaderDesc& ShdrDesc, const char* CombinedSamplerSuffix); // clang-format off ShaderResourcesD3D12 (const ShaderResourcesD3D12&) = delete; diff --git a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp index 5fa7f8e1..b351713c 100644 --- a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp @@ -204,7 +204,7 @@ void DeviceContextD3D12Impl::SetPipelineState(IPipelineState* pPipelineState) // This is necessary because if the command list had been flushed // and the first PSO set on the command list was a compute pipeline, // the states would otherwise never be committed (since m_pPipelineState != nullptr) - CommitStates = OldPSODesc.IsComputePipeline; + CommitStates = OldPSODesc.IsComputePipeline(); // We also need to update scissor rect if ScissorEnable state has changed CommitScissor = OldPSODesc.GraphicsPipeline.RasterizerDesc.ScissorEnable != PSODesc.GraphicsPipeline.RasterizerDesc.ScissorEnable; } @@ -214,7 +214,7 @@ void DeviceContextD3D12Impl::SetPipelineState(IPipelineState* pPipelineState) auto& CmdCtx = GetCmdContext(); auto* pd3d12PSO = pPipelineStateD3D12->GetD3D12PipelineState(); - if (PSODesc.IsComputePipeline) + if (PSODesc.IsComputePipeline()) { CmdCtx.AsComputeContext().SetPipelineState(pd3d12PSO); } @@ -541,6 +541,34 @@ void DeviceContextD3D12Impl::DrawIndexedIndirect(const DrawIndexedIndirectAttrib ++m_State.NumCommands; } +void DeviceContextD3D12Impl::DrawMesh(const DrawMeshAttribs& Attribs) +{ + if (!DvpVerifyDrawMeshArguments(Attribs)) + return; + + auto& GraphCtx = GetCmdContext().AsGraphicsContext(); + PrepareForDraw(GraphCtx, Attribs.Flags); + + GraphCtx.DrawMesh(Attribs.ThreadGroupCount, 1, 1); + ++m_State.NumCommands; +} + +void DeviceContextD3D12Impl::DrawMeshIndirect(const DrawMeshIndirectAttribs& Attribs, IBuffer* pAttribsBuffer) +{ + if (!DvpVerifyDrawMeshIndirectArguments(Attribs, pAttribsBuffer)) + return; + + auto& GraphCtx = GetCmdContext().AsGraphicsContext(); + PrepareForDraw(GraphCtx, Attribs.Flags); + + ID3D12Resource* pd3d12ArgsBuff; + Uint64 BuffDataStartByteOffset; + PrepareDrawIndirectBuffer(GraphCtx, pAttribsBuffer, Attribs.IndirectAttribsBufferStateTransitionMode, pd3d12ArgsBuff, BuffDataStartByteOffset); + + GraphCtx.ExecuteIndirect(m_pDrawMeshIndirectSignature, pd3d12ArgsBuff, Attribs.IndirectDrawArgsOffset + BuffDataStartByteOffset); + ++m_State.NumCommands; +} + void DeviceContextD3D12Impl::PrepareForDispatchCompute(ComputeContext& ComputeCtx) { ComputeCtx.SetRootSignature(m_pPipelineState->GetD3D12RootSignature()); @@ -894,7 +922,7 @@ void DeviceContextD3D12Impl::SetScissorRects(Uint32 NumRects, const Rect* pRects if (m_pPipelineState) { const auto& PSODesc = m_pPipelineState->GetDesc(); - if (!PSODesc.IsComputePipeline && PSODesc.GraphicsPipeline.RasterizerDesc.ScissorEnable) + if (PSODesc.IsAnyGraphicsPipeline() && PSODesc.GraphicsPipeline.RasterizerDesc.ScissorEnable) { VERIFY(NumRects == m_NumScissorRects, "Unexpected number of scissor rects"); auto& Ctx = GetCmdContext().AsGraphicsContext(); diff --git a/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp index 168736a0..bf6c3ae5 100644 --- a/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/PipelineStateD3D12Impl.cpp @@ -40,6 +40,33 @@ namespace Diligent { +namespace +{ +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4324) +#endif + + template + struct alignas(void*) PSS_SubObject + { + const D3D12_PIPELINE_STATE_SUBOBJECT_TYPE Type {SubObjType}; + InnerStructType Obj {}; + + PSS_SubObject() {} + + PSS_SubObject& operator= (const InnerStructType &obj) { Obj = obj; return *this; } + + InnerStructType* operator-> () { return &Obj; } + InnerStructType* operator& () { return &Obj; } + InnerStructType& operator* () { return Obj; } + }; + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +} // namespace class PrimitiveTopology_To_D3D12_PRIMITIVE_TOPOLOGY_TYPE { @@ -158,121 +185,221 @@ PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* pR } m_RootSig.Finalize(pd3d12Device); - if (m_Desc.IsComputePipeline) + switch (m_Desc.PipelineType) { - auto& ComputePipeline = m_Desc.ComputePipeline; + case COMPUTE_PIPELINE: + { + auto& ComputePipeline = m_Desc.ComputePipeline; - if (ComputePipeline.pCS == nullptr) - LOG_ERROR_AND_THROW("Compute shader is not set in the pipeline desc"); + if (ComputePipeline.pCS == nullptr) + LOG_ERROR_AND_THROW("Compute shader is not set in the pipeline desc"); - D3D12_COMPUTE_PIPELINE_STATE_DESC d3d12PSODesc = {}; + D3D12_COMPUTE_PIPELINE_STATE_DESC d3d12PSODesc = {}; - d3d12PSODesc.pRootSignature = nullptr; + d3d12PSODesc.pRootSignature = nullptr; - auto* pByteCode = ValidatedCast(ComputePipeline.pCS)->GetShaderByteCode(); - d3d12PSODesc.CS.pShaderBytecode = pByteCode->GetBufferPointer(); - d3d12PSODesc.CS.BytecodeLength = pByteCode->GetBufferSize(); + auto* pByteCode = ValidatedCast(ComputePipeline.pCS)->GetShaderByteCode(); + d3d12PSODesc.CS.pShaderBytecode = pByteCode->GetBufferPointer(); + d3d12PSODesc.CS.BytecodeLength = pByteCode->GetBufferSize(); - // For single GPU operation, set this to zero. If there are multiple GPU nodes, - // set bits to identify the nodes (the device's physical adapters) for which the - // graphics pipeline state is to apply. Each bit in the mask corresponds to a single node. - d3d12PSODesc.NodeMask = 0; + // For single GPU operation, set this to zero. If there are multiple GPU nodes, + // set bits to identify the nodes (the device's physical adapters) for which the + // graphics pipeline state is to apply. Each bit in the mask corresponds to a single node. + d3d12PSODesc.NodeMask = 0; - d3d12PSODesc.CachedPSO.pCachedBlob = nullptr; - d3d12PSODesc.CachedPSO.CachedBlobSizeInBytes = 0; + d3d12PSODesc.CachedPSO.pCachedBlob = nullptr; + d3d12PSODesc.CachedPSO.CachedBlobSizeInBytes = 0; - // 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; + // 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; - d3d12PSODesc.pRootSignature = m_RootSig.GetD3D12RootSignature(); + d3d12PSODesc.pRootSignature = m_RootSig.GetD3D12RootSignature(); - HRESULT hr = pd3d12Device->CreateComputePipelineState(&d3d12PSODesc, __uuidof(ID3D12PipelineState), reinterpret_cast(static_cast(&m_pd3d12PSO))); - if (FAILED(hr)) - LOG_ERROR_AND_THROW("Failed to create pipeline state"); - } - else - { - const auto& GraphicsPipeline = m_Desc.GraphicsPipeline; - - D3D12_GRAPHICS_PIPELINE_STATE_DESC d3d12PSODesc = {}; + HRESULT hr = pd3d12Device->CreateComputePipelineState(&d3d12PSODesc, __uuidof(ID3D12PipelineState), reinterpret_cast(static_cast(&m_pd3d12PSO))); + if (FAILED(hr)) + LOG_ERROR_AND_THROW("Failed to create pipeline state"); + break; + } - for (Uint32 s = 0; s < m_NumShaders; ++s) + case GRAPHICS_PIPELINE: { - auto* pShaderD3D12 = GetShader(s); - auto ShaderType = pShaderD3D12->GetDesc().ShaderType; + const auto& GraphicsPipeline = m_Desc.GraphicsPipeline; + + D3D12_GRAPHICS_PIPELINE_STATE_DESC d3d12PSODesc = {}; - D3D12_SHADER_BYTECODE* pd3d12ShaderBytecode = nullptr; - switch (ShaderType) + for (Uint32 s = 0; s < m_NumShaders; ++s) { - // 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"); + auto* pShaderD3D12 = GetShader(s); + auto ShaderType = pShaderD3D12->GetDesc().ShaderType; + + 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 on + default: UNEXPECTED("Unexpected shader type"); + } + auto* pByteCode = pShaderD3D12->GetShaderByteCode(); + + pd3d12ShaderBytecode->pShaderBytecode = pByteCode->GetBufferPointer(); + pd3d12ShaderBytecode->BytecodeLength = pByteCode->GetBufferSize(); } - auto* pByteCode = pShaderD3D12->GetShaderByteCode(); - pd3d12ShaderBytecode->pShaderBytecode = pByteCode->GetBufferPointer(); - pd3d12ShaderBytecode->BytecodeLength = pByteCode->GetBufferSize(); - } + d3d12PSODesc.pRootSignature = m_RootSig.GetD3D12RootSignature(); - d3d12PSODesc.pRootSignature = m_RootSig.GetD3D12RootSignature(); + memset(&d3d12PSODesc.StreamOutput, 0, sizeof(d3d12PSODesc.StreamOutput)); - memset(&d3d12PSODesc.StreamOutput, 0, sizeof(d3d12PSODesc.StreamOutput)); + BlendStateDesc_To_D3D12_BLEND_DESC(GraphicsPipeline.BlendDesc, d3d12PSODesc.BlendState); + // The sample mask for the blend state. + d3d12PSODesc.SampleMask = GraphicsPipeline.SampleMask; - BlendStateDesc_To_D3D12_BLEND_DESC(GraphicsPipeline.BlendDesc, d3d12PSODesc.BlendState); - // The sample mask for the blend state. - d3d12PSODesc.SampleMask = GraphicsPipeline.SampleMask; + RasterizerStateDesc_To_D3D12_RASTERIZER_DESC(GraphicsPipeline.RasterizerDesc, d3d12PSODesc.RasterizerState); + DepthStencilStateDesc_To_D3D12_DEPTH_STENCIL_DESC(GraphicsPipeline.DepthStencilDesc, d3d12PSODesc.DepthStencilState); - RasterizerStateDesc_To_D3D12_RASTERIZER_DESC(GraphicsPipeline.RasterizerDesc, d3d12PSODesc.RasterizerState); - DepthStencilStateDesc_To_D3D12_DEPTH_STENCIL_DESC(GraphicsPipeline.DepthStencilDesc, d3d12PSODesc.DepthStencilState); + std::vector> d312InputElements(STD_ALLOCATOR_RAW_MEM(D3D12_INPUT_ELEMENT_DESC, GetRawAllocator(), "Allocator for vector")); - std::vector> d312InputElements(STD_ALLOCATOR_RAW_MEM(D3D12_INPUT_ELEMENT_DESC, GetRawAllocator(), "Allocator for vector")); + const auto& InputLayout = m_Desc.GraphicsPipeline.InputLayout; + if (InputLayout.NumElements > 0) + { + LayoutElements_To_D3D12_INPUT_ELEMENT_DESCs(InputLayout, d312InputElements); + d3d12PSODesc.InputLayout.NumElements = static_cast(d312InputElements.size()); + d3d12PSODesc.InputLayout.pInputElementDescs = d312InputElements.data(); + } + else + { + d3d12PSODesc.InputLayout.NumElements = 0; + d3d12PSODesc.InputLayout.pInputElementDescs = nullptr; + } - const auto& InputLayout = m_Desc.GraphicsPipeline.InputLayout; - if (InputLayout.NumElements > 0) - { - LayoutElements_To_D3D12_INPUT_ELEMENT_DESCs(InputLayout, d312InputElements); - d3d12PSODesc.InputLayout.NumElements = static_cast(d312InputElements.size()); - d3d12PSODesc.InputLayout.pInputElementDescs = d312InputElements.data(); - } - else - { - d3d12PSODesc.InputLayout.NumElements = 0; - d3d12PSODesc.InputLayout.pInputElementDescs = nullptr; - } + d3d12PSODesc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED; + static const PrimitiveTopology_To_D3D12_PRIMITIVE_TOPOLOGY_TYPE PrimTopologyToD3D12TopologyType; + d3d12PSODesc.PrimitiveTopologyType = PrimTopologyToD3D12TopologyType[GraphicsPipeline.PrimitiveTopology]; - d3d12PSODesc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED; - static const PrimitiveTopology_To_D3D12_PRIMITIVE_TOPOLOGY_TYPE PrimTopologyToD3D12TopologyType; - d3d12PSODesc.PrimitiveTopologyType = PrimTopologyToD3D12TopologyType[GraphicsPipeline.PrimitiveTopology]; + d3d12PSODesc.NumRenderTargets = GraphicsPipeline.NumRenderTargets; + for (Uint32 rt = 0; rt < GraphicsPipeline.NumRenderTargets; ++rt) + d3d12PSODesc.RTVFormats[rt] = TexFormatToDXGI_Format(GraphicsPipeline.RTVFormats[rt]); + for (Uint32 rt = GraphicsPipeline.NumRenderTargets; rt < 8; ++rt) + d3d12PSODesc.RTVFormats[rt] = TexFormatToDXGI_Format(GraphicsPipeline.RTVFormats[rt]); + d3d12PSODesc.DSVFormat = TexFormatToDXGI_Format(GraphicsPipeline.DSVFormat); - d3d12PSODesc.NumRenderTargets = GraphicsPipeline.NumRenderTargets; - for (Uint32 rt = 0; rt < GraphicsPipeline.NumRenderTargets; ++rt) - d3d12PSODesc.RTVFormats[rt] = TexFormatToDXGI_Format(GraphicsPipeline.RTVFormats[rt]); - for (Uint32 rt = GraphicsPipeline.NumRenderTargets; rt < 8; ++rt) - d3d12PSODesc.RTVFormats[rt] = TexFormatToDXGI_Format(GraphicsPipeline.RTVFormats[rt]); - d3d12PSODesc.DSVFormat = TexFormatToDXGI_Format(GraphicsPipeline.DSVFormat); + d3d12PSODesc.SampleDesc.Count = GraphicsPipeline.SmplDesc.Count; + d3d12PSODesc.SampleDesc.Quality = GraphicsPipeline.SmplDesc.Quality; - d3d12PSODesc.SampleDesc.Count = GraphicsPipeline.SmplDesc.Count; - d3d12PSODesc.SampleDesc.Quality = GraphicsPipeline.SmplDesc.Quality; + // For single GPU operation, set this to zero. If there are multiple GPU nodes, + // set bits to identify the nodes (the device's physical adapters) for which the + // graphics pipeline state is to apply. Each bit in the mask corresponds to a single node. + d3d12PSODesc.NodeMask = 0; - // For single GPU operation, set this to zero. If there are multiple GPU nodes, - // set bits to identify the nodes (the device's physical adapters) for which the - // graphics pipeline state is to apply. Each bit in the mask corresponds to a single node. - d3d12PSODesc.NodeMask = 0; + d3d12PSODesc.CachedPSO.pCachedBlob = nullptr; + d3d12PSODesc.CachedPSO.CachedBlobSizeInBytes = 0; - d3d12PSODesc.CachedPSO.pCachedBlob = nullptr; - d3d12PSODesc.CachedPSO.CachedBlobSizeInBytes = 0; + // 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; - // 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(static_cast(&m_pd3d12PSO))); + if (FAILED(hr)) + LOG_ERROR_AND_THROW("Failed to create pipeline state"); + break; + } + +#ifdef D12_H_HAS_MESH_SHADER + case MESH_PIPELINE: + { + const auto& GraphicsPipeline = m_Desc.GraphicsPipeline; + + struct MESH_SHADER_PIPELINE_STATE_DESC + { + PSS_SubObject Flags; + PSS_SubObject NodeMask; + PSS_SubObject pRootSignature; + PSS_SubObject PS; + PSS_SubObject AS; + PSS_SubObject MS; + PSS_SubObject BlendState; + PSS_SubObject DepthStencilState; + PSS_SubObject RasterizerState; + PSS_SubObject SampleDesc; + PSS_SubObject SampleMask; + PSS_SubObject DSVFormat; + PSS_SubObject RTVFormatArray; + PSS_SubObject CachedPSO; + }; + MESH_SHADER_PIPELINE_STATE_DESC d3d12PSODesc = {}; + + for (Uint32 s = 0; s < m_NumShaders; ++s) + { + auto* pShaderD3D12 = GetShader(s); + auto ShaderType = pShaderD3D12->GetDesc().ShaderType; + + 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 on + default: UNEXPECTED("Unexpected shader type"); + } + auto* pByteCode = pShaderD3D12->GetShaderByteCode(); + + pd3d12ShaderBytecode->pShaderBytecode = pByteCode->GetBufferPointer(); + pd3d12ShaderBytecode->BytecodeLength = pByteCode->GetBufferSize(); + } + + d3d12PSODesc.pRootSignature = m_RootSig.GetD3D12RootSignature(); + + BlendStateDesc_To_D3D12_BLEND_DESC(GraphicsPipeline.BlendDesc, *d3d12PSODesc.BlendState); + // The sample mask for the blend state. + d3d12PSODesc.SampleMask = GraphicsPipeline.SampleMask; + + RasterizerStateDesc_To_D3D12_RASTERIZER_DESC(GraphicsPipeline.RasterizerDesc, *d3d12PSODesc.RasterizerState); + DepthStencilStateDesc_To_D3D12_DEPTH_STENCIL_DESC(GraphicsPipeline.DepthStencilDesc, *d3d12PSODesc.DepthStencilState); + + d3d12PSODesc.RTVFormatArray->NumRenderTargets = GraphicsPipeline.NumRenderTargets; + for (Uint32 rt = 0; rt < GraphicsPipeline.NumRenderTargets; ++rt) + d3d12PSODesc.RTVFormatArray->RTFormats[rt] = TexFormatToDXGI_Format(GraphicsPipeline.RTVFormats[rt]); + for (Uint32 rt = GraphicsPipeline.NumRenderTargets; rt < 8; ++rt) + d3d12PSODesc.RTVFormatArray->RTFormats[rt] = TexFormatToDXGI_Format(GraphicsPipeline.RTVFormats[rt]); + d3d12PSODesc.DSVFormat = TexFormatToDXGI_Format(GraphicsPipeline.DSVFormat); + + d3d12PSODesc.SampleDesc->Count = GraphicsPipeline.SmplDesc.Count; + d3d12PSODesc.SampleDesc->Quality = GraphicsPipeline.SmplDesc.Quality; + + // For single GPU operation, set this to zero. If there are multiple GPU nodes, + // set bits to identify the nodes (the device's physical adapters) for which the + // graphics pipeline state is to apply. Each bit in the mask corresponds to a single node. + d3d12PSODesc.NodeMask = 0; + + d3d12PSODesc.CachedPSO->pCachedBlob = nullptr; + d3d12PSODesc.CachedPSO->CachedBlobSizeInBytes = 0; + + // 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; + + D3D12_PIPELINE_STATE_STREAM_DESC streamDesc; + streamDesc.SizeInBytes = sizeof(d3d12PSODesc); + streamDesc.pPipelineStateSubobjectStream = &d3d12PSODesc; + + CComPtr device2; + HRESULT hr = pd3d12Device->QueryInterface(IID_PPV_ARGS(&device2)); + if (FAILED(hr)) + LOG_ERROR_AND_THROW("Failed to get ID3D12Device2"); + + hr = device2->CreatePipelineState(&streamDesc, IID_PPV_ARGS(&m_pd3d12PSO)); + if (FAILED(hr)) + LOG_ERROR_AND_THROW("Failed to create pipeline state"); + break; + } +#endif // D12_H_HAS_MESH_SHADER - HRESULT hr = pd3d12Device->CreateGraphicsPipelineState(&d3d12PSODesc, __uuidof(ID3D12PipelineState), reinterpret_cast(static_cast(&m_pd3d12PSO))); - if (FAILED(hr)) - LOG_ERROR_AND_THROW("Failed to create pipeline state"); + default: + LOG_ERROR_AND_THROW("Unknown shader type"); } if (*m_Desc.Name != 0) @@ -402,7 +529,7 @@ ShaderResourceCacheD3D12* PipelineStateD3D12Impl::CommitAndTransitionShaderResou { if (Attrib.CommitResources) { - if (m_Desc.IsComputePipeline) + if (m_Desc.IsComputePipeline()) CmdCtx.AsComputeContext().SetRootSignature(GetD3D12RootSignature()); else CmdCtx.AsGraphicsContext().SetRootSignature(GetD3D12RootSignature()); @@ -431,18 +558,18 @@ ShaderResourceCacheD3D12* PipelineStateD3D12Impl::CommitAndTransitionShaderResou auto& ResourceCache = pResBindingD3D12Impl->GetResourceCache(); if (Attrib.CommitResources) { - if (m_Desc.IsComputePipeline) + if (m_Desc.IsComputePipeline()) CmdCtx.AsComputeContext().SetRootSignature(GetD3D12RootSignature()); else CmdCtx.AsGraphicsContext().SetRootSignature(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.IsComputePipeline(), 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.IsComputePipeline(), Attrib.ValidateStates); } } else @@ -454,7 +581,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.IsComputePipeline(), Attrib.CtxId, pDeviceCtx, Attrib.CommitResources, // CommitViews diff --git a/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp index 0315f7f0..2f061df3 100644 --- a/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp @@ -63,6 +63,34 @@ static CComPtr DXGIAdapterFromD3D12Device(ID3D12Device* pd3d12Dev return nullptr; } +D3D_SHADER_MODEL RenderDeviceD3D12Impl::GetShaderModel() const +{ +#ifdef HAS_DXIL_COMPILER + // Header may not have constants for D3D_SHADER_MODEL_6_5 and above. + const D3D_SHADER_MODEL Models[] = { + D3D_SHADER_MODEL(0x65), // for mesh shader + D3D_SHADER_MODEL(0x64), + D3D_SHADER_MODEL(0x60) + }; + + // Get maximum supported shader model + D3D12_FEATURE_DATA_SHADER_MODEL ShaderModel = {}; + if (m_pd3d12Device) + { + for (auto Model : Models) + { + ShaderModel.HighestShaderModel = Model; + if (SUCCEEDED(m_pd3d12Device->CheckFeatureSupport(D3D12_FEATURE_SHADER_MODEL, &ShaderModel, sizeof(ShaderModel)))) + return ShaderModel.HighestShaderModel; + } + } +#endif + + // 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 + return D3D_SHADER_MODEL_5_1; +} + D3D_FEATURE_LEVEL RenderDeviceD3D12Impl::GetD3DFeatureLevel() const { D3D_FEATURE_LEVEL FeatureLevels[] = @@ -180,6 +208,19 @@ RenderDeviceD3D12Impl::RenderDeviceD3D12Impl(IReferenceCounters* pRefCo m_DeviceCaps.Features.BindlessResources = True; m_DeviceCaps.Features.VertexPipelineUAVWritesAndAtomics = True; + + const D3D_SHADER_MODEL ShaderModel = GetShaderModel(); + + // Check if mesh shader is supported. +#ifdef D12_H_HAS_MESH_SHADER + { + D3D12_FEATURE_DATA_D3D12_OPTIONS7 FeatureData = {}; + bool SupportsMeshShader = SUCCEEDED(m_pd3d12Device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS7, &FeatureData, sizeof(FeatureData))) && + FeatureData.MeshShaderTier != D3D12_MESH_SHADER_TIER_NOT_SUPPORTED; + + m_DeviceCaps.Features.MeshShaders = (ShaderModel >= D3D_SHADER_MODEL_6_5 && SupportsMeshShader); + } +#endif auto& TexCaps = m_DeviceCaps.TexCaps; diff --git a/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp b/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp index 958df523..f5eeceb1 100644 --- a/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp +++ b/Graphics/GraphicsEngineD3D12/src/RootSignature.cpp @@ -177,12 +177,16 @@ RootSignature::RootSignature() : // clang-format off static 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 + 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 D12_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) @@ -193,12 +197,16 @@ D3D12_SHADER_VISIBILITY GetShaderVisibility(SHADER_TYPE ShaderType) 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; + 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 D12_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; } @@ -209,29 +217,35 @@ D3D12_SHADER_VISIBILITY GetShaderVisibility(SHADER_TYPE ShaderType) // 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_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(ShaderVisibility >= D3D12_SHADER_VISIBILITY_ALL && ShaderVisibility <= D3D12_SHADER_VISIBILITY_PIXEL); + VERIFY_EXPR(uint32_t(ShaderVisibility) < std::size(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; + 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 D12_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; } diff --git a/Graphics/GraphicsEngineD3D12/src/ShaderD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/ShaderD3D12Impl.cpp index 859a1a3d..dc723614 100644 --- a/Graphics/GraphicsEngineD3D12/src/ShaderD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/ShaderD3D12Impl.cpp @@ -36,19 +36,16 @@ namespace Diligent { -static const std::string GetD3D12ShaderModel(RenderDeviceD3D12Impl* /*pDevice*/, const ShaderVersion& HLSLVersion) +static const Uint8 GetD3D12ShaderModel(RenderDeviceD3D12Impl* pDevice, const ShaderVersion& HLSLVersion) { if (HLSLVersion.Major == 0 && HLSLVersion.Minor == 0) { - //auto d3dDeviceFeatureLevel = pDevice->GetD3DFeatureLevel(); - - // 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 - return "5_1"; + D3D_SHADER_MODEL ver = pDevice->GetShaderModel(); + return Uint8((ver & 0xF0) | (ver & 0x0F)); } else { - return std::to_string(Uint32{HLSLVersion.Major}) + '_' + std::to_string(Uint32{HLSLVersion.Minor}); + return Uint8(((HLSLVersion.Major & 0xF) << 4) | (HLSLVersion.Minor & 0xF)); } } @@ -62,13 +59,13 @@ ShaderD3D12Impl::ShaderD3D12Impl(IReferenceCounters* pRefCounters, pRenderDeviceD3D12, ShaderCI.Desc }, - ShaderD3DBase{ShaderCI, GetD3D12ShaderModel(pRenderDeviceD3D12, ShaderCI.HLSLVersion).c_str()} + ShaderD3DBase{ShaderCI, GetD3D12ShaderModel(pRenderDeviceD3D12, ShaderCI.HLSLVersion)} // clang-format on { // Load shader resources auto& Allocator = GetRawAllocator(); auto* pRawMem = ALLOCATE(Allocator, "Allocator for ShaderResources", ShaderResourcesD3D12, 1); - auto* pResources = new (pRawMem) ShaderResourcesD3D12(m_pShaderByteCode, m_Desc, ShaderCI.UseCombinedTextureSamplers ? ShaderCI.CombinedSamplerSuffix : nullptr); + auto* pResources = new (pRawMem) ShaderResourcesD3D12(m_pShaderByteCode, m_isDXIL, m_Desc, ShaderCI.UseCombinedTextureSamplers ? ShaderCI.CombinedSamplerSuffix : nullptr); m_pShaderResources.reset(pResources, STDDeleterRawMem(Allocator)); } diff --git a/Graphics/GraphicsEngineD3D12/src/ShaderResourcesD3D12.cpp b/Graphics/GraphicsEngineD3D12/src/ShaderResourcesD3D12.cpp index edf818cc..8c7d554c 100644 --- a/Graphics/GraphicsEngineD3D12/src/ShaderResourcesD3D12.cpp +++ b/Graphics/GraphicsEngineD3D12/src/ShaderResourcesD3D12.cpp @@ -32,11 +32,15 @@ #include "ShaderD3DBase.hpp" #include "ShaderBase.hpp" +#ifdef HAS_DXIL_COMPILER +#include "dxcapi.h" +#endif + namespace Diligent { -ShaderResourcesD3D12::ShaderResourcesD3D12(ID3DBlob* pShaderBytecode, const ShaderDesc& ShdrDesc, const char* CombinedSamplerSuffix) : +ShaderResourcesD3D12::ShaderResourcesD3D12(ID3DBlob* pShaderBytecode, bool isDXIL, const ShaderDesc& ShdrDesc, const char* CombinedSamplerSuffix) : ShaderResources{ShdrDesc.ShaderType} { class NewResourceHandler @@ -51,8 +55,36 @@ ShaderResourcesD3D12::ShaderResourcesD3D12(ID3DBlob* pShaderBytecode, const Shad void OnNewTexSRV (const D3DShaderResourceAttribs& TexAttribs) {} // clang-format on }; + + CComPtr pShaderReflection; + + HRESULT hr; + + if (isDXIL) + { +#ifdef HAS_DXIL_COMPILER + const uint32_t DFCC_DXIL = uint32_t('D') | (uint32_t('X') << 8) | (uint32_t('I') << 16) | (uint32_t('L') << 24); + CComPtr pReflection; + UINT32 shaderIdx; + DxcCreateInstance(CLSID_DxcContainerReflection, IID_PPV_ARGS(&pReflection)); + hr = pReflection->Load(reinterpret_cast(pShaderBytecode)); + CHECK_D3D_RESULT_THROW(hr, "Failed to create shader reflection instance"); + hr = pReflection->FindFirstPartKind(DFCC_DXIL, &shaderIdx); + CHECK_D3D_RESULT_THROW(hr, "Failed to find DXIL part"); + hr = pReflection->GetPartReflection(shaderIdx, __uuidof(pShaderReflection), reinterpret_cast(&pShaderReflection)); + CHECK_D3D_RESULT_THROW(hr, "Failed to get the shader reflection"); +#else + LOG_ERROR_AND_THROW("DXIL compiler is not supported"); +#endif + } + else + { + hr = D3DReflect(pShaderBytecode->GetBufferPointer(), pShaderBytecode->GetBufferSize(), __uuidof(pShaderReflection), reinterpret_cast(&pShaderReflection)); + CHECK_D3D_RESULT_THROW(hr, "Failed to get the shader reflection"); + } + Initialize( - pShaderBytecode, + static_cast(pShaderReflection), NewResourceHandler{}, ShdrDesc.Name, CombinedSamplerSuffix); diff --git a/Graphics/GraphicsEngineD3DBase/CMakeLists.txt b/Graphics/GraphicsEngineD3DBase/CMakeLists.txt index 4b8f046f..f95d6f39 100644 --- a/Graphics/GraphicsEngineD3DBase/CMakeLists.txt +++ b/Graphics/GraphicsEngineD3DBase/CMakeLists.txt @@ -69,6 +69,14 @@ PUBLIC set_common_target_properties(Diligent-GraphicsEngineD3DBase) +if(${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION} STRGREATER_EQUAL "10.0.17763.0") + set(HAS_DXIL_COMPILER TRUE CACHE INTERNAL "" FORCE) + target_compile_definitions(Diligent-GraphicsEngineD3DBase PRIVATE HAS_DXIL_COMPILER) + target_link_libraries(Diligent-GraphicsEngineD3DBase PRIVATE dxcompiler.lib) +else() + set(HAS_DXIL_COMPILER FALSE CACHE INTERNAL "" FORCE) +endif() + source_group("src" FILES ${SOURCE}) source_group("include" FILES ${INCLUDE}) source_group("interface" FILES ${INTERFACE}) diff --git a/Graphics/GraphicsEngineD3DBase/include/D3DShaderResourceLoader.hpp b/Graphics/GraphicsEngineD3DBase/include/D3DShaderResourceLoader.hpp index ea3a9f3e..f63aa8ad 100644 --- a/Graphics/GraphicsEngineD3DBase/include/D3DShaderResourceLoader.hpp +++ b/Graphics/GraphicsEngineD3DBase/include/D3DShaderResourceLoader.hpp @@ -52,8 +52,8 @@ struct D3DShaderResourceCounters template -void LoadD3DShaderResources(ID3DBlob* pShaderByteCode, +void LoadD3DShaderResources(TShaderReflection* pShaderReflection, THandleShaderDesc HandleShaderDesc, TOnResourcesCounted OnResourcesCounted, TOnNewCB OnNewCB, @@ -72,11 +72,6 @@ void LoadD3DShaderResources(ID3DBlob* pShaderByteCode, TOnNewSampler OnNewSampler, TOnNewTexSRV OnNewTexSRV) { - CComPtr pShaderReflection; - - auto hr = D3DReflect(pShaderByteCode->GetBufferPointer(), pShaderByteCode->GetBufferSize(), __uuidof(pShaderReflection), reinterpret_cast(static_cast(&pShaderReflection))); - CHECK_D3D_RESULT_THROW(hr, "Failed to get the shader reflection"); - D3D_SHADER_DESC shaderDesc = {}; pShaderReflection->GetDesc(&shaderDesc); diff --git a/Graphics/GraphicsEngineD3DBase/include/ShaderD3DBase.hpp b/Graphics/GraphicsEngineD3DBase/include/ShaderD3DBase.hpp index e7b61f59..5dac32d4 100644 --- a/Graphics/GraphicsEngineD3DBase/include/ShaderD3DBase.hpp +++ b/Graphics/GraphicsEngineD3DBase/include/ShaderD3DBase.hpp @@ -41,10 +41,11 @@ namespace Diligent class ShaderD3DBase { public: - ShaderD3DBase(const ShaderCreateInfo& ShaderCI, const char* ShaderModel); + ShaderD3DBase(const ShaderCreateInfo& ShaderCI, Uint8 ShaderModel); protected: CComPtr m_pShaderByteCode; + bool m_isDXIL; }; } // namespace Diligent diff --git a/Graphics/GraphicsEngineD3DBase/include/ShaderResources.hpp b/Graphics/GraphicsEngineD3DBase/include/ShaderResources.hpp index 5765e20a..49976ba8 100644 --- a/Graphics/GraphicsEngineD3DBase/include/ShaderResources.hpp +++ b/Graphics/GraphicsEngineD3DBase/include/ShaderResources.hpp @@ -395,7 +395,7 @@ protected: typename D3D_SHADER_INPUT_BIND_DESC, typename TShaderReflection, typename TNewResourceHandler> - void Initialize(ID3DBlob* pShaderByteCode, + void Initialize(TShaderReflection* pShaderReflection, TNewResourceHandler NewResHandler, const Char* ShaderName, const Char* SamplerSuffix); @@ -460,14 +460,14 @@ template -void ShaderResources::Initialize(ID3DBlob* pShaderByteCode, +void ShaderResources::Initialize(TShaderReflection* pShaderReflection, TNewResourceHandler NewResHandler, const Char* ShaderName, const Char* CombinedSamplerSuffix) { Uint32 CurrCB = 0, CurrTexSRV = 0, CurrTexUAV = 0, CurrBufSRV = 0, CurrBufUAV = 0, CurrSampler = 0; - LoadD3DShaderResources( - pShaderByteCode, + LoadD3DShaderResources( + pShaderReflection, [&](const D3D_SHADER_DESC& d3dShaderDesc) // { diff --git a/Graphics/GraphicsEngineD3DBase/src/ShaderD3DBase.cpp b/Graphics/GraphicsEngineD3DBase/src/ShaderD3DBase.cpp index 3962a8e4..d9a8fdc0 100644 --- a/Graphics/GraphicsEngineD3DBase/src/ShaderD3DBase.cpp +++ b/Graphics/GraphicsEngineD3DBase/src/ShaderD3DBase.cpp @@ -33,6 +33,12 @@ #include "RefCntAutoPtr.hpp" #include #include "ShaderD3DBase.hpp" +#include +#include + +#ifdef HAS_DXIL_COMPILER +#include "dxcapi.h" +#endif namespace Diligent { @@ -42,6 +48,220 @@ static const Char* g_HLSLDefinitions = #include "HLSLDefinitions_inc.fxh" }; + +#ifdef HAS_DXIL_COMPILER +class DxcIncludeHandlerImpl final : public IDxcIncludeHandler +{ +public: + explicit DxcIncludeHandlerImpl(IShaderSourceInputStreamFactory* pStreamFactory, CComPtr pLibrary) : + m_pLibrary{pLibrary}, + m_pStreamFactory{pStreamFactory}, + m_RefCount{1} + { + } + + HRESULT STDMETHODCALLTYPE LoadSource(_In_ LPCWSTR pFilename, _COM_Outptr_result_maybenull_ IDxcBlob **ppIncludeSource) override + { + String fileName = std::wstring_convert, wchar_t>{}.to_bytes(pFilename); + if (fileName.empty()) + { + LOG_ERROR("Failed to convert shader include file name ", fileName, ". File name must be ANSI string"); + return E_FAIL; + } + + RefCntAutoPtr pSourceStream; + m_pStreamFactory->CreateInputStream(fileName.c_str(), &pSourceStream); + if (pSourceStream == nullptr) + { + LOG_ERROR("Failed to open shader include file ", fileName, ". Check that the file exists"); + return E_FAIL; + } + + RefCntAutoPtr pFileData(MakeNewRCObj()(0)); + pSourceStream->ReadBlob(pFileData); + + CComPtr sourceBlob; + HRESULT hr = m_pLibrary->CreateBlobWithEncodingFromPinned(pFileData->GetDataPtr(), UINT32(pFileData->GetSize()), CP_UTF8, &sourceBlob); + if (FAILED(hr)) + { + LOG_ERROR("Failed to allocate space for shader include file ", fileName, "."); + return E_FAIL; + } + + m_FileDataCache.push_back(pFileData); + + sourceBlob->QueryInterface(__uuidof(*ppIncludeSource), reinterpret_cast(ppIncludeSource)); + return S_OK; + } + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, _COM_Outptr_ void __RPC_FAR *__RPC_FAR *ppvObject) override + { + return E_FAIL; + } + + ULONG STDMETHODCALLTYPE AddRef(void) override + { + return m_RefCount++; + } + + ULONG STDMETHODCALLTYPE Release(void) override + { + --m_RefCount; + VERIFY(m_RefCount > 0, "Inconsistent call to Release()"); + return m_RefCount; + } + +private: + CComPtr m_pLibrary; + IShaderSourceInputStreamFactory* m_pStreamFactory; + ULONG m_RefCount; + std::vector> m_FileDataCache; +}; +#endif + +static HRESULT CompileDxilShader(const char* Source, + const ShaderCreateInfo& ShaderCI, + LPCSTR profile, + ID3DBlob** ppBlobOut, + ID3DBlob** ppCompilerOutput) +{ +#ifdef HAS_DXIL_COMPILER + std::vector unicodeBuffer; unicodeBuffer.resize(1u << 15); + size_t unicodeBufferOffset = 0; + + const auto ToUnicode = [&unicodeBuffer, &unicodeBufferOffset](const char* str) { + auto len = strlen(str) + 1; + auto pos = unicodeBufferOffset; + unicodeBufferOffset += len; + VERIFY(unicodeBufferOffset < unicodeBuffer.size(), "buffer overflow"); + for (size_t i = 0; i < len; ++i) { + unicodeBuffer[pos + i] = str[i]; + } + return &unicodeBuffer[pos]; + }; + + std::vector D3DMacros; + switch (ShaderCI.Desc.ShaderType) + { + case SHADER_TYPE_VERTEX: + D3DMacros.push_back({L"VERTEX_SHADER", L"1"}); + break; + + case SHADER_TYPE_PIXEL: + D3DMacros.push_back({L"FRAGMENT_SHADER", L"1"}); + D3DMacros.push_back({L"PIXEL_SHADER", L"1"}); + break; + + case SHADER_TYPE_GEOMETRY: + D3DMacros.push_back({L"GEOMETRY_SHADER", L"1"}); + break; + + case SHADER_TYPE_HULL: + D3DMacros.push_back({L"TESS_CONTROL_SHADER", L"1"}); + D3DMacros.push_back({L"HULL_SHADER", L"1"}); + break; + + case SHADER_TYPE_DOMAIN: + D3DMacros.push_back({L"TESS_EVALUATION_SHADER", L"1"}); + D3DMacros.push_back({L"DOMAIN_SHADER", L"1"}); + break; + + case SHADER_TYPE_COMPUTE: + D3DMacros.push_back({L"COMPUTE_SHADER", L"1"}); + break; + + case SHADER_TYPE_AMPLIFICATION: + D3DMacros.push_back({L"TASK_SHADER", L"1"}); + D3DMacros.push_back({L"AMPLIFICATION_SHADER", L"1"}); + break; + + case SHADER_TYPE_MESH: + D3DMacros.push_back({L"MESH_SHADER", L"1"}); + break; + + default: UNEXPECTED("Unexpected shader type"); + } + + if (ShaderCI.Macros) + { + for (auto* pCurrMacro = ShaderCI.Macros; pCurrMacro->Name && pCurrMacro->Definition; ++pCurrMacro) + { + D3DMacros.push_back({ToUnicode(pCurrMacro->Name), ToUnicode(pCurrMacro->Definition)}); + } + } + + HRESULT hr; + + CComPtr library; + hr = DxcCreateInstance(CLSID_DxcLibrary, IID_PPV_ARGS(&library)); + if (FAILED(hr)) + return hr; + + CComPtr compiler; + hr = DxcCreateInstance(CLSID_DxcCompiler, IID_PPV_ARGS(&compiler)); + if (FAILED(hr)) + return hr; + + CComPtr sourceBlob; + hr = library->CreateBlobWithEncodingFromPinned(Source, UINT32(strlen(Source)), CP_UTF8, &sourceBlob); + if (FAILED(hr)) + return hr; + + const wchar_t* pArgs[] = + { + L"-Zpc", // Matrices in column-major order + L"-WX", // Warnings as errors +# ifdef DILIGENT_DEBUG + L"-Zi", // Debug info + //L"-Qembed_debug", // Embed debug info into the shader (some compilers do not recognize this flag) + L"-Od", // Disable optimization +# else + L"-O3", // Optimization level 3 +# endif + }; + + DxcIncludeHandlerImpl IncludeHandler{ShaderCI.pShaderSourceStreamFactory, library}; + + CComPtr result; + hr = compiler->Compile( + sourceBlob, + L"", + ToUnicode(ShaderCI.EntryPoint), + ToUnicode(profile), + pArgs, UINT32(std::size(pArgs)), + D3DMacros.data(), UINT32(D3DMacros.size()), + &IncludeHandler, + &result); + + if (SUCCEEDED(hr)) + { + HRESULT status; + if (SUCCEEDED(result->GetStatus(&status))) + hr = status; + } + + if (FAILED(hr)) + { + if (result) + { + CComPtr errorsBlob; + if (SUCCEEDED(result->GetErrorBuffer(&errorsBlob)) && errorsBlob) + { + errorsBlob->QueryInterface(__uuidof(*ppCompilerOutput), reinterpret_cast(ppCompilerOutput)); + } + } + return hr; + } + + hr = result->GetResult(reinterpret_cast(ppBlobOut)); + return hr; +#else + UNSUPPORTED("Shader model 6 and above requires DXIL compiler"); + return E_FAIL; +#endif +} + + class D3DIncludeImpl : public ID3DInclude { public: @@ -83,14 +303,55 @@ private: std::unordered_map> m_DataBlobs; }; -static HRESULT CompileShader(const char* Source, - LPCSTR strFunctionName, - const D3D_SHADER_MACRO* pDefines, - IShaderSourceInputStreamFactory* pIncludeStreamFactory, - LPCSTR profile, - ID3DBlob** ppBlobOut, - ID3DBlob** ppCompilerOutput) +static HRESULT CompileShader(const char* Source, + const ShaderCreateInfo& ShaderCI, + LPCSTR profile, + ID3DBlob** ppBlobOut, + ID3DBlob** ppCompilerOutput) { + std::vector D3DMacros; + switch (ShaderCI.Desc.ShaderType) + { + case SHADER_TYPE_VERTEX: + D3DMacros.push_back({"VERTEX_SHADER", "1"}); + break; + + case SHADER_TYPE_PIXEL: + D3DMacros.push_back({"FRAGMENT_SHADER", "1"}); + D3DMacros.push_back({"PIXEL_SHADER", "1"}); + break; + + case SHADER_TYPE_GEOMETRY: + D3DMacros.push_back({"GEOMETRY_SHADER", "1"}); + break; + + case SHADER_TYPE_HULL: + D3DMacros.push_back({"TESS_CONTROL_SHADER", "1"}); + D3DMacros.push_back({"HULL_SHADER", "1"}); + break; + + case SHADER_TYPE_DOMAIN: + D3DMacros.push_back({"TESS_EVALUATION_SHADER", "1"}); + D3DMacros.push_back({"DOMAIN_SHADER", "1"}); + break; + + case SHADER_TYPE_COMPUTE: + D3DMacros.push_back({"COMPUTE_SHADER", "1"}); + break; + + default: UNEXPECTED("Unexpected shader type"); + } + + if (ShaderCI.Macros) + { + for (auto* pCurrMacro = ShaderCI.Macros; pCurrMacro->Name && pCurrMacro->Definition; ++pCurrMacro) + { + D3DMacros.push_back({pCurrMacro->Name, pCurrMacro->Definition}); + } + } + + D3DMacros.push_back({nullptr, nullptr}); + DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS; #if defined(DILIGENT_DEBUG) // Set the D3D10_SHADER_DEBUG flag to embed debug information in the shaders. @@ -103,13 +364,13 @@ static HRESULT CompileShader(const char* Source, // report strange errors: // dwShaderFlags |= D3D10_SHADER_OPTIMIZATION_LEVEL3; #endif - HRESULT hr; + // do // { - auto SourceLen = strlen(Source); - D3DIncludeImpl IncludeImpl(pIncludeStreamFactory); - hr = D3DCompile(Source, SourceLen, NULL, pDefines, &IncludeImpl, strFunctionName, profile, dwShaderFlags, 0, ppBlobOut, ppCompilerOutput); + D3DIncludeImpl IncludeImpl(ShaderCI.pShaderSourceStreamFactory); + auto SourceLen = strlen(Source); + auto hr = D3DCompile(Source, SourceLen, NULL, D3DMacros.data(), &IncludeImpl, ShaderCI.EntryPoint, profile, dwShaderFlags, 0, ppBlobOut, ppCompilerOutput); // if( FAILED(hr) || errors ) // { @@ -126,7 +387,8 @@ static HRESULT CompileShader(const char* Source, return hr; } -ShaderD3DBase::ShaderD3DBase(const ShaderCreateInfo& ShaderCI, const char* ShaderModel) +ShaderD3DBase::ShaderD3DBase(const ShaderCreateInfo& ShaderCI, Uint8 ShaderModel) : + m_isDXIL{false} { if (ShaderCI.Source || ShaderCI.FilePath) { @@ -137,18 +399,24 @@ ShaderD3DBase::ShaderD3DBase(const ShaderCreateInfo& ShaderCI, const char* Shade switch (ShaderCI.Desc.ShaderType) { // clang-format off - case SHADER_TYPE_VERTEX: strShaderProfile="vs"; break; - case SHADER_TYPE_PIXEL: strShaderProfile="ps"; break; - case SHADER_TYPE_GEOMETRY:strShaderProfile="gs"; break; - case SHADER_TYPE_HULL: strShaderProfile="hs"; break; - case SHADER_TYPE_DOMAIN: strShaderProfile="ds"; break; - case SHADER_TYPE_COMPUTE: strShaderProfile="cs"; break; + case SHADER_TYPE_VERTEX: strShaderProfile="vs"; break; + case SHADER_TYPE_PIXEL: strShaderProfile="ps"; break; + case SHADER_TYPE_GEOMETRY: strShaderProfile="gs"; break; + case SHADER_TYPE_HULL: strShaderProfile="hs"; break; + case SHADER_TYPE_DOMAIN: strShaderProfile="ds"; break; + case SHADER_TYPE_COMPUTE: strShaderProfile="cs"; break; + case SHADER_TYPE_AMPLIFICATION: strShaderProfile="as"; break; + case SHADER_TYPE_MESH: strShaderProfile="ms"; break; // clang-format on default: UNEXPECTED("Unknown shader type"); } strShaderProfile += "_"; - strShaderProfile += ShaderModel; + strShaderProfile += '0' + ((ShaderModel >> 4) & 0xF); + strShaderProfile += "_"; + strShaderProfile += ((ShaderModel & 0xF) == 0xF) ? 'x' : ('0' + (ShaderModel & 0xF)); + + m_isDXIL = (ShaderModel >= 0x60); String ShaderSource(g_HLSLDefinitions); if (ShaderCI.Source) @@ -171,56 +439,17 @@ ShaderD3DBase::ShaderD3DBase(const ShaderCreateInfo& ShaderCI, const char* Shade ShaderSource.append(FileDataPtr, FileDataPtr + Size / sizeof(*FileDataPtr)); } - const D3D_SHADER_MACRO* pDefines = nullptr; - std::vector D3DMacros; - switch (ShaderCI.Desc.ShaderType) - { - case SHADER_TYPE_VERTEX: - D3DMacros.push_back({"VERTEX_SHADER", "1"}); - break; - - case SHADER_TYPE_PIXEL: - D3DMacros.push_back({"FRAGMENT_SHADER", "1"}); - D3DMacros.push_back({"PIXEL_SHADER", "1"}); - break; - - case SHADER_TYPE_GEOMETRY: - D3DMacros.push_back({"GEOMETRY_SHADER", "1"}); - break; - - case SHADER_TYPE_HULL: - D3DMacros.push_back({"TESS_CONTROL_SHADER", "1"}); - D3DMacros.push_back({"HULL_SHADER", "1"}); - break; - - case SHADER_TYPE_DOMAIN: - D3DMacros.push_back({"TESS_EVALUATION_SHADER", "1"}); - D3DMacros.push_back({"DOMAIN_SHADER", "1"}); - break; - - case SHADER_TYPE_COMPUTE: - D3DMacros.push_back({"COMPUTE_SHADER", "1"}); - break; - - default: UNEXPECTED("Unexpected shader type"); - } - - if (ShaderCI.Macros) - { - for (auto* pCurrMacro = ShaderCI.Macros; pCurrMacro->Name && pCurrMacro->Definition; ++pCurrMacro) - { - D3DMacros.push_back({pCurrMacro->Name, pCurrMacro->Definition}); - } - } - - D3DMacros.push_back({nullptr, nullptr}); - pDefines = D3DMacros.data(); - DEV_CHECK_ERR(ShaderCI.EntryPoint != nullptr, "Entry point must not be null"); + CComPtr errors; - auto hr = CompileShader(ShaderSource.c_str(), ShaderCI.EntryPoint, pDefines, ShaderCI.pShaderSourceStreamFactory, strShaderProfile.c_str(), &m_pShaderByteCode, &errors); + HRESULT hr; + + if (m_isDXIL) + hr = CompileDxilShader(ShaderSource.c_str(), ShaderCI, strShaderProfile.c_str(), &m_pShaderByteCode, &errors); + else + hr = CompileShader(ShaderSource.c_str(), ShaderCI, strShaderProfile.c_str(), &m_pShaderByteCode, &errors); - const char* CompilerMsg = errors ? reinterpret_cast(errors->GetBufferPointer()) : nullptr; + const char* CompilerMsg = errors ? static_cast(errors->GetBufferPointer()) : nullptr; if (CompilerMsg != nullptr && ShaderCI.ppCompilerOutput != nullptr) { auto ErrorMsgLen = strlen(CompilerMsg); diff --git a/Graphics/GraphicsEngineOpenGL/include/DeviceContextGLImpl.hpp b/Graphics/GraphicsEngineOpenGL/include/DeviceContextGLImpl.hpp index e80e0d04..54eff631 100644 --- a/Graphics/GraphicsEngineOpenGL/include/DeviceContextGLImpl.hpp +++ b/Graphics/GraphicsEngineOpenGL/include/DeviceContextGLImpl.hpp @@ -120,6 +120,10 @@ public: virtual void DILIGENT_CALL_TYPE DrawIndirect (const DrawIndirectAttribs& Attribs, IBuffer* pAttribsBuffer) override final; /// Implementation of IDeviceContext::DrawIndexedIndirect() in OpenGL backend. virtual void DILIGENT_CALL_TYPE DrawIndexedIndirect(const DrawIndexedIndirectAttribs& Attribs, IBuffer* pAttribsBuffer) override final; + /// Implementation of IDeviceContext::DrawMesh() in OpenGL backend. + virtual void DILIGENT_CALL_TYPE DrawMesh (const DrawMeshAttribs& Attribs) override final; + /// Implementation of IDeviceContext::DrawMeshIndirect() in OpenGL backend. + virtual void DILIGENT_CALL_TYPE DrawMeshIndirect (const DrawMeshIndirectAttribs& Attribs, IBuffer* pAttribsBuffer) override final; /// Implementation of IDeviceContext::DispatchCompute() in OpenGL backend. virtual void DILIGENT_CALL_TYPE DispatchCompute (const DispatchComputeAttribs& Attribs) override final; diff --git a/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp b/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp index f6308229..7728de7b 100644 --- a/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp @@ -84,7 +84,7 @@ void DeviceContextGLImpl::SetPipelineState(IPipelineState* pPipelineState) TDeviceContextBase::SetPipelineState(pPipelineStateGLImpl, 0 /*Dummy*/); const auto& Desc = pPipelineStateGLImpl->GetDesc(); - if (Desc.IsComputePipeline) + if (Desc.IsComputePipeline()) { } else @@ -874,6 +874,16 @@ void DeviceContextGLImpl::DrawIndexedIndirect(const DrawIndexedIndirectAttribs& #endif } +void DeviceContextGLImpl::DrawMesh(const DrawMeshAttribs& Attribs) +{ + UNSUPPORTED("DrawMesh is not supported in OpenGL"); +} + +void DeviceContextGLImpl::DrawMeshIndirect(const DrawMeshIndirectAttribs& Attribs, IBuffer* pAttribsBuffer) +{ + UNSUPPORTED("DrawMeshIndirect is not supported in OpenGL"); +} + void DeviceContextGLImpl::DispatchCompute(const DispatchComputeAttribs& Attribs) { diff --git a/Graphics/GraphicsEngineOpenGL/src/PipelineStateGLImpl.cpp b/Graphics/GraphicsEngineOpenGL/src/PipelineStateGLImpl.cpp index 72d504be..bb2201d1 100644 --- a/Graphics/GraphicsEngineOpenGL/src/PipelineStateGLImpl.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/PipelineStateGLImpl.cpp @@ -52,7 +52,7 @@ PipelineStateGLImpl::PipelineStateGLImpl(IReferenceCounters* pRefCoun m_StaticResourceLayout{*this} // clang-format on { - if (!m_Desc.IsComputePipeline && m_pPS == nullptr) + if (m_Desc.IsAnyGraphicsPipeline() && m_pPS == nullptr) { // Some OpenGL implementations fail if fragment shader is not present, so // create a dummy one. diff --git a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp index 83e2c077..4dd6ae1e 100644 --- a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp @@ -142,6 +142,10 @@ public: virtual void DILIGENT_CALL_TYPE DrawIndirect (const DrawIndirectAttribs& Attribs, IBuffer* pAttribsBuffer) override final; /// Implementation of IDeviceContext::DrawIndexedIndirect() in Vulkan backend. virtual void DILIGENT_CALL_TYPE DrawIndexedIndirect(const DrawIndexedIndirectAttribs& Attribs, IBuffer* pAttribsBuffer) override final; + /// Implementation of IDeviceContext::DrawMesh() in Vulkan backend. + virtual void DILIGENT_CALL_TYPE DrawMesh (const DrawMeshAttribs& Attribs) override final; + /// Implementation of IDeviceContext::DrawMeshIndirect() in Vulkan backend. + virtual void DILIGENT_CALL_TYPE DrawMeshIndirect (const DrawMeshIndirectAttribs& Attribs, IBuffer* pAttribsBuffer) override final; /// Implementation of IDeviceContext::DispatchCompute() in Vulkan backend. virtual void DILIGENT_CALL_TYPE DispatchCompute (const DispatchComputeAttribs& Attribs) override final; diff --git a/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp index aca69cac..01f37a76 100644 --- a/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp @@ -156,7 +156,7 @@ private: VulkanUtilities::PipelineWrapper m_Pipeline; PipelineLayout m_PipelineLayout; - Int8 m_ResourceLayoutIndex[6] = {-1, -1, -1, -1, -1, -1}; + std::array m_ResourceLayoutIndex; bool m_HasStaticResources = false; bool m_HasNonStaticResources = false; }; diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.hpp b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.hpp index 1465024b..5e4f5062 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.hpp +++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.hpp @@ -138,6 +138,32 @@ public: vkCmdDrawIndexedIndirect(m_VkCmdBuffer, Buffer, Offset, DrawCount, Stride); } + __forceinline void DrawMesh(uint32_t TaskCount, uint32_t FirstTask) + { +#ifdef VK_NV_mesh_shader + VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE); + VERIFY(m_State.RenderPass != VK_NULL_HANDLE, "vkCmdDrawMeshTasksNV() must be called inside render pass (19.3)"); + VERIFY(m_State.GraphicsPipeline != VK_NULL_HANDLE, "No graphics pipeline bound"); + + vkCmdDrawMeshTasksNV(m_VkCmdBuffer, TaskCount, FirstTask); +#else + UNSUPPORTED("DrawMesh is not supported in current Vulkan headers"); +#endif + } + + __forceinline void DrawMeshIndirect(VkBuffer Buffer, VkDeviceSize Offset, uint32_t DrawCount, uint32_t Stride) + { +#ifdef VK_NV_mesh_shader + VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE); + VERIFY(m_State.RenderPass != VK_NULL_HANDLE, "vkCmdDrawMeshTasksNV() must be called inside render pass (19.3)"); + VERIFY(m_State.GraphicsPipeline != VK_NULL_HANDLE, "No graphics pipeline bound"); + + vkCmdDrawMeshTasksIndirectNV(m_VkCmdBuffer, Buffer, Offset, DrawCount, Stride); +#else + UNSUPPORTED("DrawMeshIndirect is not supported in current Vulkan headers"); +#endif + } + __forceinline void Dispatch(uint32_t GroupCountX, uint32_t GroupCountY, uint32_t GroupCountZ) { VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE); diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanInstance.hpp b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanInstance.hpp index 3fcb736d..0ca092c6 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanInstance.hpp +++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanInstance.hpp @@ -63,6 +63,7 @@ public: // clang-format off bool IsLayerAvailable (const char* LayerName) const; bool IsExtensionAvailable(const char* ExtensionName)const; + bool IsExtensionEnabled (const char* ExtensionName)const; VkPhysicalDevice SelectPhysicalDevice()const; @@ -82,6 +83,7 @@ private: std::vector m_Layers; std::vector m_Extensions; + std::vector m_EnabledExtensions; std::vector m_PhysicalDevices; }; diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanPhysicalDevice.hpp b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanPhysicalDevice.hpp index 24212950..17bc2e4a 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanPhysicalDevice.hpp +++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanPhysicalDevice.hpp @@ -29,13 +29,25 @@ #include #include -#include "VulkanHeaders.h" +#include "VulkanInstance.hpp" namespace VulkanUtilities { class VulkanPhysicalDevice { +public: + struct ExtensionFeatures + { +#ifdef VK_NV_mesh_shader + VkPhysicalDeviceMeshShaderFeaturesNV MeshShader; +#endif + }; + + struct ExtensionProperties + { + }; + public: // clang-format off VulkanPhysicalDevice (const VulkanPhysicalDevice&) = delete; @@ -44,7 +56,8 @@ public: VulkanPhysicalDevice& operator = (VulkanPhysicalDevice&&) = delete; // clang-format on - static std::unique_ptr Create(VkPhysicalDevice vkDevice); + static std::unique_ptr Create(VkPhysicalDevice vkDevice, + std::shared_ptr Instance); // clang-format off uint32_t FindQueueFamily (VkQueueFlags QueueFlags) const; @@ -59,15 +72,20 @@ public: const VkPhysicalDeviceProperties& GetProperties() const { return m_Properties; } const VkPhysicalDeviceFeatures& GetFeatures() const { return m_Features; } + const ExtensionProperties& GetExtProperties() const { return m_ExtProperties; } + const ExtensionFeatures& GetExtFeatures() const { return m_ExtFeatures; } VkFormatProperties GetPhysicalDeviceFormatProperties(VkFormat imageFormat) const; private: - VulkanPhysicalDevice(VkPhysicalDevice vkDevice); + VulkanPhysicalDevice(VkPhysicalDevice vkDevice, + std::shared_ptr Instance); const VkPhysicalDevice m_VkDevice; VkPhysicalDeviceProperties m_Properties = {}; VkPhysicalDeviceFeatures m_Features = {}; VkPhysicalDeviceMemoryProperties m_MemoryProperties = {}; + ExtensionProperties m_ExtProperties = {}; + ExtensionFeatures m_ExtFeatures = {}; std::vector m_QueueFamilyProperties; std::vector m_SupportedExtensions; }; diff --git a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp index d61ddc97..a8ec8364 100644 --- a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp @@ -256,7 +256,7 @@ void DeviceContextVkImpl::SetPipelineState(IPipelineState* pPipelineState) // This is necessary because if the command list had been flushed // and the first PSO set on the command list was a compute pipeline, // the states would otherwise never be committed (since m_pPipelineState != nullptr) - CommitStates = OldPSODesc.IsComputePipeline; + CommitStates = OldPSODesc.IsComputePipeline(); // We also need to update scissor rect if ScissorEnable state was disabled in previous pipeline CommitScissor = !OldPSODesc.GraphicsPipeline.RasterizerDesc.ScissorEnable; } @@ -264,7 +264,7 @@ void DeviceContextVkImpl::SetPipelineState(IPipelineState* pPipelineState) TDeviceContextBase::SetPipelineState(pPipelineStateVk, 0 /*Dummy*/); EnsureVkCmdBuffer(); - if (PSODesc.IsComputePipeline) + if (PSODesc.IsComputePipeline()) { auto vkPipeline = pPipelineStateVk->GetVkPipeline(); m_CommandBuffer.BindComputePipeline(vkPipeline); @@ -553,6 +553,31 @@ void DeviceContextVkImpl::DrawIndexedIndirect(const DrawIndexedIndirectAttribs& ++m_State.NumCommands; } +void DeviceContextVkImpl::DrawMesh(const DrawMeshAttribs& Attribs) +{ + if (!DvpVerifyDrawMeshArguments(Attribs)) + return; + + PrepareForDraw(Attribs.Flags); + + m_CommandBuffer.DrawMesh(Attribs.ThreadGroupCount, 0); + ++m_State.NumCommands; +} + +void DeviceContextVkImpl::DrawMeshIndirect(const DrawMeshIndirectAttribs& Attribs, IBuffer* pAttribsBuffer) +{ + if (!DvpVerifyDrawMeshIndirectArguments(Attribs, pAttribsBuffer)) + return; + + // We must prepare indirect draw attribs buffer first because state transitions must + // be performed outside of render pass, and PrepareForDraw commits render pass + BufferVkImpl* pIndirectDrawAttribsVk = PrepareIndirectDrawAttribsBuffer(pAttribsBuffer, Attribs.IndirectAttribsBufferStateTransitionMode); + + PrepareForDraw(Attribs.Flags); + + m_CommandBuffer.DrawMeshIndirect(pIndirectDrawAttribsVk->GetVkBuffer(), pIndirectDrawAttribsVk->GetDynamicOffset(m_ContextId, this) + Attribs.IndirectDrawArgsOffset, 1, 0); + ++m_State.NumCommands; +} void DeviceContextVkImpl::PrepareForDispatchCompute() { @@ -1067,7 +1092,7 @@ void DeviceContextVkImpl::SetScissorRects(Uint32 NumRects, const Rect* pRects, U if (m_pPipelineState) { const auto& PSODesc = m_pPipelineState->GetDesc(); - if (!PSODesc.IsComputePipeline && PSODesc.GraphicsPipeline.RasterizerDesc.ScissorEnable) + if (PSODesc.IsAnyGraphicsPipeline() && PSODesc.GraphicsPipeline.RasterizerDesc.ScissorEnable) { VERIFY(NumRects == m_NumScissorRects, "Unexpected number of scissor rects"); CommitScissorRects(); diff --git a/Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp b/Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp index 8d72a0b5..58aea393 100644 --- a/Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp +++ b/Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp @@ -144,7 +144,7 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E reinterpret_cast(EngineCI.pVkAllocator)); auto vkDevice = Instance->SelectPhysicalDevice(); - auto PhysicalDevice = VulkanUtilities::VulkanPhysicalDevice::Create(vkDevice); + auto PhysicalDevice = VulkanUtilities::VulkanPhysicalDevice::Create(vkDevice, Instance); const auto& PhysicalDeviceFeatures = PhysicalDevice->GetFeatures(); // If an implementation exposes any queue family that supports graphics operations, @@ -155,7 +155,7 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E QueueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; QueueInfo.flags = 0; // reserved for future use // All commands that are allowed on a queue that supports transfer operations are also allowed on a - // queue that supports either graphics or compute operations.Thus, if the capabilities of a queue family + // queue that supports either graphics or compute operations. Thus, if the capabilities of a queue family // include VK_QUEUE_GRAPHICS_BIT or VK_QUEUE_COMPUTE_BIT, then reporting the VK_QUEUE_TRANSFER_BIT // capability separately for that queue family is optional (4.1). QueueInfo.queueFamilyIndex = PhysicalDevice->FindQueueFamily(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT); @@ -200,6 +200,24 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E VK_KHR_SWAPCHAIN_EXTENSION_NAME, VK_KHR_MAINTENANCE1_EXTENSION_NAME // To allow negative viewport height }; + + // To enable some device extensions you must enable instance extension VK_KHR_get_physical_device_properties2 + // and add feature description to DeviceCreateInfo.pNext. + bool SupportsFeatures2 = Instance->IsExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + void** NextExt = const_cast(&DeviceCreateInfo.pNext); + + // Enable mesh shader extension. +#ifdef VK_NV_mesh_shader + VkPhysicalDeviceMeshShaderFeaturesNV MeshShaderFeats = PhysicalDevice->GetExtFeatures().MeshShader; + + if (SupportsFeatures2 && PhysicalDevice->IsExtensionSupported(VK_NV_MESH_SHADER_EXTENSION_NAME)) + { + DeviceExtensions.push_back(VK_NV_MESH_SHADER_EXTENSION_NAME); + *NextExt = &MeshShaderFeats; + NextExt = &MeshShaderFeats.pNext; + } +#endif + DeviceCreateInfo.ppEnabledExtensionNames = DeviceExtensions.empty() ? nullptr : DeviceExtensions.data(); DeviceCreateInfo.enabledExtensionCount = static_cast(DeviceExtensions.size()); diff --git a/Graphics/GraphicsEngineVulkan/src/GenerateMipsVkHelper.cpp b/Graphics/GraphicsEngineVulkan/src/GenerateMipsVkHelper.cpp index 7742cd63..be1bf51d 100644 --- a/Graphics/GraphicsEngineVulkan/src/GenerateMipsVkHelper.cpp +++ b/Graphics/GraphicsEngineVulkan/src/GenerateMipsVkHelper.cpp @@ -157,7 +157,7 @@ std::array, 4> GenerateMipsVkHelper::CreatePSOs(TE PipelineStateCreateInfo PSOCreateInfo; PipelineStateDesc& PSODesc = PSOCreateInfo.PSODesc; - PSODesc.IsComputePipeline = true; + PSODesc.PipelineType = COMPUTE_PIPELINE; PSODesc.Name = name.c_str(); PSODesc.ComputePipeline.pCS = pCS; diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp index 32a68780..8fa63070 100644 --- a/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp +++ b/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp @@ -46,12 +46,16 @@ static VkShaderStageFlagBits ShaderTypeToVkShaderStageFlagBit(SHADER_TYPE Shader switch (ShaderType) { // clang-format off - case SHADER_TYPE_VERTEX: return VK_SHADER_STAGE_VERTEX_BIT; - case SHADER_TYPE_HULL: return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; - case SHADER_TYPE_DOMAIN: return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; - case SHADER_TYPE_GEOMETRY: return VK_SHADER_STAGE_GEOMETRY_BIT; - case SHADER_TYPE_PIXEL: return VK_SHADER_STAGE_FRAGMENT_BIT; - case SHADER_TYPE_COMPUTE: return VK_SHADER_STAGE_COMPUTE_BIT; + case SHADER_TYPE_VERTEX: return VK_SHADER_STAGE_VERTEX_BIT; + case SHADER_TYPE_HULL: return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; + case SHADER_TYPE_DOMAIN: return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; + case SHADER_TYPE_GEOMETRY: return VK_SHADER_STAGE_GEOMETRY_BIT; + case SHADER_TYPE_PIXEL: return VK_SHADER_STAGE_FRAGMENT_BIT; + case SHADER_TYPE_COMPUTE: return VK_SHADER_STAGE_COMPUTE_BIT; +#ifdef VK_NV_mesh_shader + case SHADER_TYPE_AMPLIFICATION: return VK_SHADER_STAGE_TASK_BIT_NV; + case SHADER_TYPE_MESH: return VK_SHADER_STAGE_MESH_BIT_NV; +#endif // clang-format on default: UNEXPECTED("Unknown shader type"); diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp index 99b27d2c..063978f9 100644 --- a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp @@ -173,6 +173,8 @@ PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* pRefCoun m_ShaderResourceLayouts = ALLOCATE(ShaderResLayoutAllocator, "Raw memory for ShaderResourceLayoutVk", ShaderResourceLayoutVk, m_NumShaders * 2); m_StaticResCaches = ALLOCATE(GetRawAllocator(), "Raw memory for ShaderResourceCacheVk", ShaderResourceCacheVk, m_NumShaders); m_StaticVarsMgrs = ALLOCATE(GetRawAllocator(), "Raw memory for ShaderVariableManagerVk", ShaderVariableManagerVk, m_NumShaders); + m_ResourceLayoutIndex.fill(-1); + for (Uint32 s = 0; s < m_NumShaders; ++s) { new (m_ShaderResourceLayouts + s) ShaderResourceLayoutVk(LogicalDevice); @@ -228,12 +230,16 @@ PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* pRefCoun switch (ShaderType) { // clang-format off - case SHADER_TYPE_VERTEX: StageCI.stage = VK_SHADER_STAGE_VERTEX_BIT; break; - case SHADER_TYPE_HULL: StageCI.stage = VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; break; - case SHADER_TYPE_DOMAIN: StageCI.stage = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; break; - case SHADER_TYPE_GEOMETRY: StageCI.stage = VK_SHADER_STAGE_GEOMETRY_BIT; break; - case SHADER_TYPE_PIXEL: StageCI.stage = VK_SHADER_STAGE_FRAGMENT_BIT; break; - case SHADER_TYPE_COMPUTE: StageCI.stage = VK_SHADER_STAGE_COMPUTE_BIT; break; + case SHADER_TYPE_VERTEX: StageCI.stage = VK_SHADER_STAGE_VERTEX_BIT; break; + case SHADER_TYPE_HULL: StageCI.stage = VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; break; + case SHADER_TYPE_DOMAIN: StageCI.stage = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; break; + case SHADER_TYPE_GEOMETRY: StageCI.stage = VK_SHADER_STAGE_GEOMETRY_BIT; break; + case SHADER_TYPE_PIXEL: StageCI.stage = VK_SHADER_STAGE_FRAGMENT_BIT; break; + case SHADER_TYPE_COMPUTE: StageCI.stage = VK_SHADER_STAGE_COMPUTE_BIT; break; +#ifdef VK_NV_mesh_shader + case SHADER_TYPE_AMPLIFICATION: StageCI.stage = VK_SHADER_STAGE_TASK_BIT_NV; break; + case SHADER_TYPE_MESH: StageCI.stage = VK_SHADER_STAGE_MESH_BIT_NV; break; +#endif default: UNEXPECTED("Unknown shader type"); // clang-format on } @@ -269,7 +275,7 @@ PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* pRefCoun } // Create pipeline - if (m_Desc.IsComputePipeline) + if (m_Desc.IsComputePipeline()) { auto& ComputePipeline = m_Desc.ComputePipeline; @@ -642,7 +648,7 @@ void PipelineStateVkImpl::CommitAndTransitionShaderResources(IShaderResourceBind } // Prepare descriptor sets, and also bind them if there are no dynamic descriptors VERIFY_EXPR(pDescrSetBindInfo != nullptr); - m_PipelineLayout.PrepareDescriptorSets(pCtxVkImpl, m_Desc.IsComputePipeline, ResourceCache, *pDescrSetBindInfo, DynamicDescrSet); + m_PipelineLayout.PrepareDescriptorSets(pCtxVkImpl, m_Desc.IsComputePipeline(), ResourceCache, *pDescrSetBindInfo, DynamicDescrSet); // Dynamic descriptor sets are not released individually. Instead, all dynamic descriptor pools // are released at the end of the frame by DeviceContextVkImpl::FinishFrame(). } diff --git a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp index 4e6049b0..66ea8716 100644 --- a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp @@ -156,6 +156,7 @@ RenderDeviceVkImpl::RenderDeviceVkImpl(IReferenceCounters* auto& Features = m_DeviceCaps.Features; const auto& vkDeviceFeatures = m_PhysicalDevice->GetFeatures(); + const auto& vkExtFeatures = m_PhysicalDevice->GetExtFeatures(); Features.SeparablePrograms = True; Features.IndirectRendering = True; @@ -179,6 +180,9 @@ RenderDeviceVkImpl::RenderDeviceVkImpl(IReferenceCounters* Features.PixelUAVWritesAndAtomics = vkDeviceFeatures.fragmentStoresAndAtomics != VK_FALSE; Features.TextureUAVExtendedFormats = vkDeviceFeatures.shaderStorageImageExtendedFormats != VK_FALSE; + // All devices that supports mesh shader also supports task shader, so it is not necessary to use two separate features. + Features.MeshShaders = vkExtFeatures.MeshShader.meshShader != VK_FALSE && vkExtFeatures.MeshShader.taskShader != VK_FALSE; + const auto& vkDeviceLimits = m_PhysicalDevice->GetProperties().limits; auto& TexCaps = m_DeviceCaps.TexCaps; diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanInstance.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanInstance.cpp index aa6235f3..603da02a 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanInstance.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanInstance.cpp @@ -27,6 +27,7 @@ #include #include +#include "VulkanUtilities/VulkanInstance.hpp" #if DILIGENT_USE_VOLK # define VOLK_IMPLEMENTATION @@ -34,7 +35,6 @@ #endif #include "VulkanErrors.hpp" -#include "VulkanUtilities/VulkanInstance.hpp" #include "VulkanUtilities/VulkanDebug.hpp" #if !DILIGENT_NO_GLSLANG @@ -64,6 +64,15 @@ bool VulkanInstance::IsExtensionAvailable(const char* ExtensionName) const return false; } +bool VulkanInstance::IsExtensionEnabled(const char* ExtensionName) const +{ + for (const auto& Extension : m_EnabledExtensions) + if (strcmp(Extension, ExtensionName) == 0) + return true; + + return false; +} + std::shared_ptr VulkanInstance::Create(bool EnableValidation, uint32_t GlobalExtensionCount, const char* const* ppGlobalExtensionNames, @@ -138,6 +147,14 @@ VulkanInstance::VulkanInstance(bool EnableValidation, #endif }; + // This extension added to core in 1.1, but current version is 1.0 +#ifdef VK_KHR_get_physical_device_properties2 + if (IsExtensionAvailable(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) + { + GlobalExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + } +#endif + if (ppGlobalExtensionNames != nullptr) { for (uint32_t ext = 0; ext < GlobalExtensionCount; ++ext) @@ -213,6 +230,8 @@ VulkanInstance::VulkanInstance(bool EnableValidation, volkLoadInstance(m_VkInstance); #endif + m_EnabledExtensions = std::move(GlobalExtensions); + // If requested, we enable the default validation layers for debugging if (m_DebugUtilsEnabled) { diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp index 22eee45e..f18d6872 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp @@ -33,13 +33,15 @@ namespace VulkanUtilities { -std::unique_ptr VulkanPhysicalDevice::Create(VkPhysicalDevice vkDevice) +std::unique_ptr VulkanPhysicalDevice::Create(VkPhysicalDevice vkDevice, + std::shared_ptr Instance) { - auto* PhysicalDevice = new VulkanPhysicalDevice{vkDevice}; + auto* PhysicalDevice = new VulkanPhysicalDevice{vkDevice, Instance}; return std::unique_ptr{PhysicalDevice}; } -VulkanPhysicalDevice::VulkanPhysicalDevice(VkPhysicalDevice vkDevice) : +VulkanPhysicalDevice::VulkanPhysicalDevice(VkPhysicalDevice vkDevice, + std::shared_ptr Instance) : m_VkDevice{vkDevice} { VERIFY_EXPR(m_VkDevice != VK_NULL_HANDLE); @@ -65,6 +67,29 @@ VulkanPhysicalDevice::VulkanPhysicalDevice(VkPhysicalDevice vkDevice) : (void)res; VERIFY_EXPR(ExtensionCount == m_SupportedExtensions.size()); } + + if (Instance->IsExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) + { + VkPhysicalDeviceFeatures2 Feats2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2}; + VkPhysicalDeviceProperties2 Props2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; + void** NextFeat = &Feats2.pNext; + //void** NextProp = &Props2.pNext; + + // Enable mesh shader extension. +#ifdef VK_NV_mesh_shader + if (IsExtensionSupported(VK_NV_MESH_SHADER_EXTENSION_NAME)) + { + *NextFeat = &m_ExtFeatures.MeshShader; + NextFeat = &m_ExtFeatures.MeshShader.pNext; + m_ExtFeatures.MeshShader.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_NV; + } +#endif + + // Initialize device extension features by current physical device features. + // Some flags may not be supported by hardware. + vkGetPhysicalDeviceFeatures2KHR(m_VkDevice, &Feats2); + vkGetPhysicalDeviceProperties2KHR(m_VkDevice, &Props2); + } } uint32_t VulkanPhysicalDevice::FindQueueFamily(VkQueueFlags QueueFlags) const -- cgit v1.2.3