From 7f26e40e0898391a32e6a05d91ef1a217d885668 Mon Sep 17 00:00:00 2001 From: azhirnov Date: Sun, 25 Oct 2020 15:53:05 +0300 Subject: PSO refactoring for ray tracing --- .../include/PipelineLayout.hpp | 6 +- .../include/PipelineStateVkImpl.hpp | 3 +- .../include/RenderDeviceVkImpl.hpp | 3 + .../include/ShaderResourceBindingVkImpl.hpp | 2 +- .../include/ShaderResourceCacheVk.hpp | 13 +- .../include/ShaderResourceLayoutVk.hpp | 162 +++-- .../include/ShaderVariableVk.hpp | 4 +- .../include/VulkanUtilities/VulkanInstance.hpp | 8 +- .../VulkanUtilities/VulkanLogicalDevice.hpp | 12 +- .../VulkanUtilities/VulkanObjectWrappers.hpp | 5 + .../VulkanUtilities/VulkanPhysicalDevice.hpp | 2 + .../src/DeviceContextVkImpl.cpp | 10 +- .../GraphicsEngineVulkan/src/EngineFactoryVk.cpp | 129 ++-- .../GraphicsEngineVulkan/src/PipelineLayout.cpp | 38 +- .../src/PipelineStateVkImpl.cpp | 499 ++++++++++---- .../src/RenderDeviceVkImpl.cpp | 53 +- .../src/ShaderResourceCacheVk.cpp | 48 +- .../src/ShaderResourceLayoutVk.cpp | 758 ++++++++++++++------- .../GraphicsEngineVulkan/src/ShaderVariableVk.cpp | 14 +- Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp | 8 + .../src/VulkanUtilities/VulkanInstance.cpp | 21 +- .../src/VulkanUtilities/VulkanLogicalDevice.cpp | 41 +- .../src/VulkanUtilities/VulkanPhysicalDevice.cpp | 14 +- 23 files changed, 1269 insertions(+), 584 deletions(-) (limited to 'Graphics/GraphicsEngineVulkan') diff --git a/Graphics/GraphicsEngineVulkan/include/PipelineLayout.hpp b/Graphics/GraphicsEngineVulkan/include/PipelineLayout.hpp index 73fced1f..8a0fab15 100644 --- a/Graphics/GraphicsEngineVulkan/include/PipelineLayout.hpp +++ b/Graphics/GraphicsEngineVulkan/include/PipelineLayout.hpp @@ -48,7 +48,7 @@ class ShaderResourceCacheVk; class PipelineLayout { public: - static VkDescriptorType GetVkDescriptorType(const SPIRVShaderResourceAttribs& Res); + static VkDescriptorType GetVkDescriptorType(SPIRVShaderResourceAttribs::ResourceType Type); PipelineLayout(); void Release(RenderDeviceVkImpl* pDeviceVkImpl, Uint64 CommandQueueMask); @@ -69,8 +69,7 @@ public: SHADER_TYPE ShaderType, Uint32& DescriptorSet, Uint32& Binding, - Uint32& OffsetInCache, - std::vector& SPIRV); + Uint32& OffsetInCache); Uint32 GetTotalDescriptors(SHADER_RESOURCE_VARIABLE_TYPE VarType) const { @@ -137,7 +136,6 @@ public: // set by the same Vulkan command. If there are no dynamic descriptors, this // function also binds descriptor sets rightaway. void PrepareDescriptorSets(DeviceContextVkImpl* pCtxVkImpl, - bool IsCompute, const ShaderResourceCacheVk& ResourceCache, DescriptorSetBindInfo& BindInfo, VkDescriptorSet VkDynamicDescrSet) const; diff --git a/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp index d4f2fc36..a02c8d74 100644 --- a/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp @@ -59,6 +59,7 @@ public: PipelineStateVkImpl(IReferenceCounters* pRefCounters, RenderDeviceVkImpl* pDeviceVk, const GraphicsPipelineStateCreateInfo& CreateInfo); PipelineStateVkImpl(IReferenceCounters* pRefCounters, RenderDeviceVkImpl* pDeviceVk, const ComputePipelineStateCreateInfo& CreateInfo); + PipelineStateVkImpl(IReferenceCounters* pRefCounters, RenderDeviceVkImpl* pDeviceVk, const RayTracingPipelineStateCreateInfo& CreateInfo); ~PipelineStateVkImpl(); virtual void DILIGENT_CALL_TYPE QueryInterface(const INTERFACE_ID& IID, IObject** ppInterface) override final; @@ -168,7 +169,7 @@ private: // Resource layout index in m_ShaderResourceLayouts array for every shader stage, // indexed by the shader type pipeline index (returned by GetShaderTypePipelineIndex) - std::array m_ResourceLayoutIndex = {-1, -1, -1, -1, -1}; + std::array m_ResourceLayoutIndex = {-1, -1, -1, -1, -1, -1}; bool m_HasStaticResources = false; bool m_HasNonStaticResources = false; diff --git a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp index d85e9ff3..9ceed3e4 100644 --- a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp @@ -78,6 +78,9 @@ public: /// Implementation of IRenderDevice::CreateComputePipelineState() in Vulkan backend. virtual void DILIGENT_CALL_TYPE CreateComputePipelineState(const ComputePipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState) override final; + /// Implementation of IRenderDevice::CreateRayTracingPipelineState() in Vulkan backend. + virtual void DILIGENT_CALL_TYPE CreateRayTracingPipelineState(const RayTracingPipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState) override final; + /// Implementation of IRenderDevice::CreateBuffer() in Vulkan backend. virtual void DILIGENT_CALL_TYPE CreateBuffer(const BufferDesc& BuffDesc, const BufferData* pBuffData, diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderResourceBindingVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/ShaderResourceBindingVkImpl.hpp index 00f2c33a..68401f52 100644 --- a/Graphics/GraphicsEngineVulkan/include/ShaderResourceBindingVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/ShaderResourceBindingVkImpl.hpp @@ -83,7 +83,7 @@ private: // Resource layout index in m_ShaderResourceCache array for every shader stage, // indexed by the shader type pipeline index (returned by GetShaderTypePipelineIndex) - std::array m_ResourceLayoutIndex = {-1, -1, -1, -1, -1}; + std::array m_ResourceLayoutIndex = {-1, -1, -1, -1, -1, -1}; bool m_bStaticResourcesInitialized = false; Uint8 m_NumShaders = 0; diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.hpp b/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.hpp index 7d77ff48..0bcf79a0 100644 --- a/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.hpp +++ b/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.hpp @@ -112,12 +112,13 @@ public: /*1-7*/ // Unused /* 8 */ RefCntAutoPtr pObject; - VkDescriptorBufferInfo GetUniformBufferDescriptorWriteInfo () const; - VkDescriptorBufferInfo GetStorageBufferDescriptorWriteInfo () const; - VkDescriptorImageInfo GetImageDescriptorWriteInfo (bool IsImmutableSampler)const; - VkBufferView GetBufferViewWriteInfo () const; - VkDescriptorImageInfo GetSamplerDescriptorWriteInfo() const; - VkDescriptorImageInfo GetInputAttachmentDescriptorWriteInfo() const; + VkDescriptorBufferInfo GetUniformBufferDescriptorWriteInfo () const; + VkDescriptorBufferInfo GetStorageBufferDescriptorWriteInfo () const; + VkDescriptorImageInfo GetImageDescriptorWriteInfo (bool IsImmutableSampler) const; + VkBufferView GetBufferViewWriteInfo () const; + VkDescriptorImageInfo GetSamplerDescriptorWriteInfo() const; + VkDescriptorImageInfo GetInputAttachmentDescriptorWriteInfo() const; + VkWriteDescriptorSetAccelerationStructureKHR GetAccelerationStructureWriteInfo() const; // clang-format on }; diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.hpp b/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.hpp index 9452a390..e5cddb0c 100644 --- a/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.hpp +++ b/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.hpp @@ -113,18 +113,21 @@ namespace Diligent class ShaderVkImpl; /// Diligent::ShaderResourceLayoutVk class -// sizeof(ShaderResourceLayoutVk)==56 (MS compiler, x64) +// sizeof(ShaderResourceLayoutVk)==72 (MS compiler, x64) class ShaderResourceLayoutVk { public: struct ShaderStageInfo { - ShaderStageInfo(SHADER_TYPE _Type, - const ShaderVkImpl* _pShader); + ShaderStageInfo() {} + ShaderStageInfo(SHADER_TYPE Stage, const ShaderVkImpl* pShader); - const SHADER_TYPE Type; - const ShaderVkImpl* const pShader; - std::vector SPIRV; + void Append(const ShaderVkImpl* pShader); + size_t Count() const; + + SHADER_TYPE Type = SHADER_TYPE_UNKNOWN; + std::vector Shaders; + std::vector> SPIRVs; }; using TShaderStages = std::vector; @@ -144,10 +147,10 @@ public: // This method is called by PipelineStateVkImpl class instance to initialize static // shader resource layout and the cache - void InitializeStaticResourceLayout(const ShaderVkImpl* pShader, - IMemoryAllocator& LayoutDataAllocator, - const PipelineResourceLayoutDesc& ResourceLayoutDesc, - ShaderResourceCacheVk& StaticResourceCache); + void InitializeStaticResourceLayout(const std::vector& Shaders, + IMemoryAllocator& LayoutDataAllocator, + const PipelineResourceLayoutDesc& ResourceLayoutDesc, + ShaderResourceCacheVk& StaticResourceCache); // This method is called by PipelineStateVkImpl class instance to initialize resource // layouts for all shader stages in the pipeline. @@ -160,7 +163,7 @@ public: bool VerifyVariables, bool VerifyImmutableSamplers); - // sizeof(VkResource) == 24 (x64) + // sizeof(VkResource) == 32 (x64) struct VkResource { // clang-format off @@ -178,40 +181,56 @@ public: static constexpr const Uint32 InvalidSamplerInd = (1 << SamplerIndBits)-1; + using ResourceType = SPIRVShaderResourceAttribs::ResourceType; + /* 0 */ const Uint16 Binding; -/* 2 */ const Uint16 DescriptorSet; +/* 2 */ const Uint16 ArraySize; /* 4.0 */ const Uint32 CacheOffset : CacheOffsetBits; // Offset from the beginning of the cached descriptor set /* 6.5 */ const Uint32 SamplerInd : SamplerIndBits; // When using combined texture samplers, index of the separate sampler // assigned to separate image /* 7.5 */ const Uint32 VariableType : VariableTypeBits; /* 7.7 */ const Uint32 ImmutableSamplerAssigned : ImmutableSamplerFlagBits; +/* 8 */ const Uint8 DescriptorSet; + +/* 9 */ const ResourceType Type; +/* 10.0*/ const Uint8 ResourceDim : 7; +/* 10.7*/ const Uint8 IsMS : 1; +/* 16 */ const char* const Name; +/* 24 */ const ShaderResourceLayoutVk& ParentResLayout; + // clang-format on -/* 8 */ const SPIRVShaderResourceAttribs& SpirvAttribs; -/* 16 */ const ShaderResourceLayoutVk& ParentResLayout; - - VkResource(const ShaderResourceLayoutVk& _ParentLayout, - const SPIRVShaderResourceAttribs& _SpirvAttribs, - SHADER_RESOURCE_VARIABLE_TYPE _VariableType, - uint32_t _Binding, - uint32_t _DescriptorSet, - Uint32 _CacheOffset, - Uint32 _SamplerInd, - bool _ImmutableSamplerAssigned = false)noexcept : + VkResource(const ShaderResourceLayoutVk& _ParentLayout, + const char* _Name, + Uint16 _ArraySize, + ResourceType _Type, + Uint8 _ResourceDim, + Uint8 _IsMS, + SHADER_RESOURCE_VARIABLE_TYPE _VariableType, + uint32_t _Binding, + uint32_t _DescriptorSet, + Uint32 _CacheOffset, + Uint32 _SamplerInd, + bool _ImmutableSamplerAssigned = false) noexcept : + // clang-format off Binding {static_cast(_Binding) }, DescriptorSet {static_cast(_DescriptorSet)}, CacheOffset {_CacheOffset }, SamplerInd {_SamplerInd }, VariableType {_VariableType }, ImmutableSamplerAssigned {_ImmutableSamplerAssigned ? 1U : 0U}, - SpirvAttribs {_SpirvAttribs }, + Name {_Name }, + ArraySize {_ArraySize }, + Type {_Type }, + ResourceDim {_ResourceDim }, + IsMS {_IsMS }, ParentResLayout {_ParentLayout } + // clang-format on { - VERIFY(_CacheOffset < (1 << CacheOffsetBits), "Cache offset (", _CacheOffset, ") exceeds max representable value ", (1 << CacheOffsetBits) ); - VERIFY(_SamplerInd < (1 << SamplerIndBits), "Sampler index (", _SamplerInd, ") exceeds max representable value ", (1 << SamplerIndBits) ); - VERIFY(_Binding <= std::numeric_limits::max(), "Binding (", _Binding, ") exceeds max representable value ", std::numeric_limits::max() ); + VERIFY(_CacheOffset < (1 << CacheOffsetBits), "Cache offset (", _CacheOffset, ") exceeds max representable value ", (1 << CacheOffsetBits)); + VERIFY(_SamplerInd < (1 << SamplerIndBits), "Sampler index (", _SamplerInd, ") exceeds max representable value ", (1 << SamplerIndBits)); + VERIFY(_Binding <= std::numeric_limits::max(), "Binding (", _Binding, ") exceeds max representable value ", std::numeric_limits::max()); VERIFY(_DescriptorSet <= std::numeric_limits::max(), "Descriptor set (", _DescriptorSet, ") exceeds max representable value ", std::numeric_limits::max()); } - // clang-format on // Checks if a resource is bound in ResourceCache at the given ArrayIndex bool IsBound(Uint32 ArrayIndex, const ShaderResourceCacheVk& ResourceCache) const; @@ -220,17 +239,18 @@ public: void BindResource(IDeviceObject* pObject, Uint32 ArrayIndex, ShaderResourceCacheVk& ResourceCache) const; // Updates resource descriptor in the descriptor set - inline void UpdateDescriptorHandle(VkDescriptorSet vkDescrSet, - uint32_t ArrayElement, - const VkDescriptorImageInfo* pImageInfo, - const VkDescriptorBufferInfo* pBufferInfo, - const VkBufferView* pTexelBufferView) const; + inline void UpdateDescriptorHandle(VkDescriptorSet vkDescrSet, + uint32_t ArrayElement, + const VkDescriptorImageInfo* pImageInfo, + const VkDescriptorBufferInfo* pBufferInfo, + const VkBufferView* pTexelBufferView, + const VkWriteDescriptorSetAccelerationStructureKHR* pAccelStructInfo = nullptr) const; bool IsImmutableSamplerAssigned() const { VERIFY(ImmutableSamplerAssigned == 0 || - SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage || - SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler, + Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage || + Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler, "Immutable sampler can only be assigned to a sampled image or separate sampler"); return ImmutableSamplerAssigned != 0; } @@ -240,6 +260,31 @@ public: return static_cast(VariableType); } + String GetPrintName(Uint32 ArrayInd) const + { + VERIFY_EXPR(ArrayInd < ArraySize); + if (ArraySize > 1) + { + std::stringstream ss; + ss << Name << '[' << ArrayInd << ']'; + return ss.str(); + } + else + return Name; + } + + ShaderResourceDesc GetResourceDesc() const; + + RESOURCE_DIMENSION GetResourceDimension() const + { + return static_cast(ResourceDim); + } + + bool IsMultisample() const + { + return IsMS != 0; + } + private: void CacheUniformBuffer(IDeviceObject* pBuffer, ShaderResourceCacheVk::Resource& DstRes, @@ -276,6 +321,11 @@ public: VkDescriptorSet vkDescrSet, Uint32 ArrayInd) const; + void CacheAccelerationStructure(IDeviceObject* pTLAS, + ShaderResourceCacheVk::Resource& DstRes, + VkDescriptorSet vkDescrSet, + Uint32 ArrayInd) const; + template bool UpdateCachedResource(ShaderResourceCacheVk::Resource& DstRes, RefCntAutoPtr&& pObject, @@ -310,15 +360,10 @@ public: const Char* GetShaderName() const { - return m_pResources->GetShaderName(); + return ""; // AZ TODO } - SHADER_TYPE GetShaderType() const - { - return m_pResources->GetShaderType(); - } - - const SPIRVShaderResources& GetResources() const { return *m_pResources; } + SHADER_TYPE GetShaderType() const { return m_ShaderType; } const VkResource& GetResource(SHADER_RESOURCE_VARIABLE_TYPE VarType, Uint32 r) const { @@ -327,7 +372,7 @@ public: return Resources[GetResourceOffset(VarType, r)]; } - bool IsUsingSeparateSamplers() const { return !m_pResources->IsUsingCombinedSamplers(); } + bool IsUsingSeparateSamplers() const { return m_IsUsingSeparateSamplers; } private: Uint32 GetResourceOffset(SHADER_RESOURCE_VARIABLE_TYPE VarType, Uint32 r) const @@ -358,12 +403,14 @@ private: return m_NumResources[SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES]; } - void AllocateMemory(const ShaderVkImpl* pShader, - IMemoryAllocator& Allocator, - const PipelineResourceLayoutDesc& ResourceLayoutDesc, - const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, - Uint32 NumAllowedTypes, - bool AllocateImmutableSamplers); + using ResourceNameToIndex_t = std::unordered_map; + void AllocateMemory(const std::vector& Shaders, + IMemoryAllocator& Allocator, + const PipelineResourceLayoutDesc& ResourceLayoutDesc, + const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, + Uint32 NumAllowedTypes, + ResourceNameToIndex_t& UniqueNames, + bool AllocateImmutableSamplers); using ImmutableSamplerPtrType = RefCntAutoPtr; ImmutableSamplerPtrType& GetImmutableSampler(Uint32 n) noexcept @@ -374,16 +421,17 @@ private: } // clang-format off -/* 0 */ const VulkanUtilities::VulkanLogicalDevice& m_LogicalDevice; -/* 8 */ std::unique_ptr > m_ResourceBuffer; +/* 0 */ const VulkanUtilities::VulkanLogicalDevice& m_LogicalDevice; +/* 8 */ std::unique_ptr > m_ResourceBuffer; // AZ TODO: use linear allocator +/*24 */ StringPool m_StringPool; + +/*48 */ std::array m_NumResources = {}; - // We must use shared_ptr to reference ShaderResources instance, because - // there may be multiple objects referencing the same set of resources -/*24 */ std::shared_ptr m_pResources; +/*56 */ Uint32 m_NumImmutableSamplers = 0; +/*60 */ SHADER_TYPE m_ShaderType = SHADER_TYPE_UNKNOWN; +/*64 */ bool m_IsUsingSeparateSamplers = false; -/*40 */ std::array m_NumResources = {}; -/*48 */ Uint32 m_NumImmutableSamplers = 0; -/*56*/ // End of class +/*72 */ // End of class // clang-format on }; diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderVariableVk.hpp b/Graphics/GraphicsEngineVulkan/include/ShaderVariableVk.hpp index 27689c1e..6c88bf56 100644 --- a/Graphics/GraphicsEngineVulkan/include/ShaderVariableVk.hpp +++ b/Graphics/GraphicsEngineVulkan/include/ShaderVariableVk.hpp @@ -183,14 +183,14 @@ public: Uint32 FirstElement, Uint32 NumElements) override final { - VerifyAndCorrectSetArrayArguments(m_Resource.SpirvAttribs.Name, m_Resource.SpirvAttribs.ArraySize, FirstElement, NumElements); + VerifyAndCorrectSetArrayArguments(m_Resource.Name, m_Resource.ArraySize, FirstElement, NumElements); for (Uint32 Elem = 0; Elem < NumElements; ++Elem) m_Resource.BindResource(ppObjects[Elem], FirstElement + Elem, m_ParentManager.m_ResourceCache); } virtual void DILIGENT_CALL_TYPE GetResourceDesc(ShaderResourceDesc& ResourceDesc) const override final { - ResourceDesc = m_Resource.SpirvAttribs.GetResourceDesc(); + ResourceDesc = m_Resource.GetResourceDesc(); } virtual Uint32 DILIGENT_CALL_TYPE GetIndex() const override final diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanInstance.hpp b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanInstance.hpp index f5b921a6..c28be56c 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanInstance.hpp +++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanInstance.hpp @@ -44,7 +44,8 @@ public: VulkanInstance& operator = ( VulkanInstance&&) = delete; // clang-format on - static std::shared_ptr Create(bool EnableValidation, + static std::shared_ptr Create(uint32_t ApiVersion, + bool EnableValidation, uint32_t GlobalExtensionCount, const char* const* ppGlobalExtensionNames, VkAllocationCallbacks* pVkAllocator); @@ -69,10 +70,12 @@ public: VkAllocationCallbacks* GetVkAllocator()const{return m_pVkAllocator;} VkInstance GetVkInstance() const{return m_VkInstance; } + uint32_t GetVkVersion() const{return m_VkVersion; } // clang-format on private: - VulkanInstance(bool EnableValidation, + VulkanInstance(uint32_t ApiVersion, + bool EnableValidation, uint32_t GlobalExtensionCount, const char* const* ppGlobalExtensionNames, VkAllocationCallbacks* pVkAllocator); @@ -80,6 +83,7 @@ private: bool m_DebugUtilsEnabled = false; VkAllocationCallbacks* const m_pVkAllocator; VkInstance m_VkInstance = VK_NULL_HANDLE; + uint32_t m_VkVersion = VK_API_VERSION_1_0; std::vector m_Layers; std::vector m_Extensions; diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanLogicalDevice.hpp b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanLogicalDevice.hpp index a8366551..5e60a343 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanLogicalDevice.hpp +++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanLogicalDevice.hpp @@ -88,8 +88,11 @@ using AccelStructWrapper = DEFINE_VULKAN_OBJECT_WRAPPER(AccelerationStru class VulkanLogicalDevice : public std::enable_shared_from_this { public: + using ExtensionFeatures = VulkanPhysicalDevice::ExtensionFeatures; + static std::shared_ptr Create(const VulkanPhysicalDevice& PhysicalDevice, const VkDeviceCreateInfo& DeviceCI, + const ExtensionFeatures& EnabledExtFeatures, const VkAllocationCallbacks* vkAllocator); // clang-format off @@ -131,8 +134,9 @@ public: RenderPassWrapper CreateRenderPass (const VkRenderPassCreateInfo& RenderPassCI,const char* DebugName = "") const; DeviceMemoryWrapper AllocateDeviceMemory(const VkMemoryAllocateInfo & AllocInfo, const char* DebugName = "") const; - PipelineWrapper CreateComputePipeline (const VkComputePipelineCreateInfo& PipelineCI, VkPipelineCache cache, const char* DebugName = "") const; - PipelineWrapper CreateGraphicsPipeline(const VkGraphicsPipelineCreateInfo& PipelineCI, VkPipelineCache cache, const char* DebugName = "") const; + PipelineWrapper CreateComputePipeline (const VkComputePipelineCreateInfo& PipelineCI, VkPipelineCache cache, const char* DebugName = "") const; + PipelineWrapper CreateGraphicsPipeline (const VkGraphicsPipelineCreateInfo& PipelineCI, VkPipelineCache cache, const char* DebugName = "") const; + PipelineWrapper CreateRayTracingPipeline(const VkRayTracingPipelineCreateInfoKHR& PipelineCI, VkPipelineCache cache, const char* DebugName = "") const; ShaderModuleWrapper CreateShaderModule (const VkShaderModuleCreateInfo& ShaderModuleCI, const char* DebugName = "") const; PipelineLayoutWrapper CreatePipelineLayout (const VkPipelineLayoutCreateInfo& LayoutCI, const char* DebugName = "") const; @@ -216,12 +220,15 @@ public: } VkPipelineStageFlags GetEnabledGraphicsShaderStages() const { return m_EnabledGraphicsShaderStages; } + VkResult GetRayTracingShaderGroupHandles(VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void* pData) const; const VkPhysicalDeviceFeatures& GetEnabledFeatures() const { return m_EnabledFeatures; } + const ExtensionFeatures& GetEnabledExtFeatures() const { return m_EnabledExtFeatures; } private: VulkanLogicalDevice(const VulkanPhysicalDevice& PhysicalDevice, const VkDeviceCreateInfo& DeviceCI, + const ExtensionFeatures& EnabledExtFeatures, const VkAllocationCallbacks* vkAllocator); template GetPhysicalDevice(); - const auto& MeshShaderFeats = PhysicalDevice.GetExtFeatures().MeshShader; + const auto& LogicalDevice = m_pDevice->GetLogicalDevice(); + const auto& MeshShaderFeats = LogicalDevice.GetEnabledExtFeatures().MeshShader; VERIFY_EXPR(MeshShaderFeats.meshShader != VK_FALSE && MeshShaderFeats.taskShader != VK_FALSE); VERIFY_EXPR(Attribs.ThreadGroupCount <= PhysicalDevice.GetExtProperties().MeshShader.maxDrawMeshTasksCount); } @@ -612,7 +618,7 @@ void DeviceContextVkImpl::DrawMeshIndirect(const DrawMeshIndirectAttribs& Attrib #ifdef DILIGENT_DEBUG { - const auto& MeshShaderFeats = m_pDevice->GetPhysicalDevice().GetExtFeatures().MeshShader; + const auto& MeshShaderFeats = m_pDevice->GetLogicalDevice().GetEnabledExtFeatures().MeshShader; VERIFY_EXPR(MeshShaderFeats.meshShader != VK_FALSE && MeshShaderFeats.taskShader != VK_FALSE); } #endif diff --git a/Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp b/Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp index d37655a5..fcb64973 100644 --- a/Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp +++ b/Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp @@ -138,6 +138,7 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E try { auto Instance = VulkanUtilities::VulkanInstance::Create( + VK_API_VERSION_1_2, // AZ TODO: use 1.2 only for ray tracing, wave ops extensions EngineCI.EnableValidation, EngineCI.GlobalExtensionCount, EngineCI.ppGlobalExtensionNames, @@ -238,7 +239,11 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E VK_KHR_MAINTENANCE1_EXTENSION_NAME // To allow negative viewport height }; - const auto& DeviceExtFeatures = PhysicalDevice->GetExtFeatures(); + const VulkanUtilities::VulkanPhysicalDevice::ExtensionFeatures& DeviceExtFeatures = PhysicalDevice->GetExtFeatures(); + VulkanUtilities::VulkanPhysicalDevice::ExtensionFeatures EnabledExtFeats = {}; + + // SPIRV 1.5 is in Vulkan 1.2 core + EnabledExtFeats.Spirv15 = DeviceExtFeatures.Spirv15; #define ENABLE_FEATURE(IsFeatureSupported, Feature, FeatureName) \ do \ @@ -247,33 +252,25 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E GetFeatureState(EngineCI.Features.Feature, IsFeatureSupported, FeatureName); \ } while (false) + ENABLE_FEATURE(DeviceExtFeatures.MeshShader.taskShader != VK_FALSE && DeviceExtFeatures.MeshShader.meshShader != VK_FALSE, MeshShaders, "Mesh shaders are"); - auto MeshShaderFeats = DeviceExtFeatures.MeshShader; - ENABLE_FEATURE(MeshShaderFeats.taskShader != VK_FALSE && MeshShaderFeats.meshShader != VK_FALSE, MeshShaders, "Mesh shaders are"); - - auto ShaderFloat16Int8 = DeviceExtFeatures.ShaderFloat16Int8; // clang-format off - ENABLE_FEATURE(ShaderFloat16Int8.shaderFloat16 != VK_FALSE, ShaderFloat16, "16-bit float shader operations are"); - ENABLE_FEATURE(ShaderFloat16Int8.shaderInt8 != VK_FALSE, ShaderInt8, "8-bit int shader operations are"); + ENABLE_FEATURE(DeviceExtFeatures.ShaderFloat16Int8.shaderFloat16 != VK_FALSE, ShaderFloat16, "16-bit float shader operations are"); + ENABLE_FEATURE(DeviceExtFeatures.ShaderFloat16Int8.shaderInt8 != VK_FALSE, ShaderInt8, "8-bit int shader operations are"); // clang-format on - auto Storage16BitFeats = DeviceExtFeatures.Storage16Bit; // clang-format off - ENABLE_FEATURE(Storage16BitFeats.storageBuffer16BitAccess != VK_FALSE, ResourceBuffer16BitAccess, "16-bit resoure buffer access is"); - ENABLE_FEATURE(Storage16BitFeats.uniformAndStorageBuffer16BitAccess != VK_FALSE, UniformBuffer16BitAccess, "16-bit uniform buffer access is"); - ENABLE_FEATURE(Storage16BitFeats.storageInputOutput16 != VK_FALSE, ShaderInputOutput16, "16-bit shader inputs/outputs are"); + ENABLE_FEATURE(DeviceExtFeatures.Storage16Bit.storageBuffer16BitAccess != VK_FALSE, ResourceBuffer16BitAccess, "16-bit resoure buffer access is"); + ENABLE_FEATURE(DeviceExtFeatures.Storage16Bit.uniformAndStorageBuffer16BitAccess != VK_FALSE, UniformBuffer16BitAccess, "16-bit uniform buffer access is"); + ENABLE_FEATURE(DeviceExtFeatures.Storage16Bit.storageInputOutput16 != VK_FALSE, ShaderInputOutput16, "16-bit shader inputs/outputs are"); // clang-format on - auto Storage8BitFeats = DeviceExtFeatures.Storage8Bit; // clang-format off - ENABLE_FEATURE(Storage8BitFeats.storageBuffer8BitAccess != VK_FALSE, ResourceBuffer8BitAccess, "8-bit resoure buffer access is"); - ENABLE_FEATURE(Storage8BitFeats.uniformAndStorageBuffer8BitAccess != VK_FALSE, UniformBuffer8BitAccess, "8-bit uniform buffer access is"); + ENABLE_FEATURE(DeviceExtFeatures.Storage8Bit.storageBuffer8BitAccess != VK_FALSE, ResourceBuffer8BitAccess, "8-bit resoure buffer access is"); + ENABLE_FEATURE(DeviceExtFeatures.Storage8Bit.uniformAndStorageBuffer8BitAccess != VK_FALSE, UniformBuffer8BitAccess, "8-bit uniform buffer access is"); // clang-format on - auto RayTracingFeats = DeviceExtFeatures.RayTracing; - auto BufferDeviceAddressFeats = DeviceExtFeatures.BufferDeviceAddress; - auto DescriptorIndexingFeats = DeviceExtFeatures.DescriptorIndexing; - ENABLE_FEATURE(RayTracingFeats.rayTracing != VK_FALSE || DeviceExtFeatures.RayTracingNV, RayTracing, "Ray tracing is"); + ENABLE_FEATURE((DeviceExtFeatures.RayTracing.rayTracing != VK_FALSE && DeviceExtFeatures.Spirv14) || DeviceExtFeatures.RayTracingNV, RayTracing, "Ray tracing is"); #undef FeatureSupport @@ -289,31 +286,33 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E // Mesh shader if (EngineCI.Features.MeshShaders != DEVICE_FEATURE_STATE_DISABLED) { - VERIFY_EXPR(MeshShaderFeats.taskShader != VK_FALSE && MeshShaderFeats.meshShader != VK_FALSE); + EnabledExtFeats.MeshShader = DeviceExtFeatures.MeshShader; + VERIFY_EXPR(EnabledExtFeats.MeshShader.taskShader != VK_FALSE && EnabledExtFeats.MeshShader.meshShader != VK_FALSE); VERIFY(PhysicalDevice->IsExtensionSupported(VK_NV_MESH_SHADER_EXTENSION_NAME), "VK_NV_mesh_shader extension must be supported as it has already been checked by VulkanPhysicalDevice and " "both taskShader and meshShader features are TRUE"); DeviceExtensions.push_back(VK_NV_MESH_SHADER_EXTENSION_NAME); - *NextExt = &MeshShaderFeats; - NextExt = &MeshShaderFeats.pNext; + *NextExt = &EnabledExtFeats.MeshShader; + NextExt = &EnabledExtFeats.MeshShader.pNext; } if (EngineCI.Features.ShaderFloat16 != DEVICE_FEATURE_STATE_DISABLED || EngineCI.Features.ShaderInt8 != DEVICE_FEATURE_STATE_DISABLED) { - VERIFY_EXPR(ShaderFloat16Int8.shaderFloat16 != VK_FALSE || ShaderFloat16Int8.shaderInt8 != VK_FALSE); + EnabledExtFeats.ShaderFloat16Int8 = DeviceExtFeatures.ShaderFloat16Int8; + VERIFY_EXPR(EnabledExtFeats.ShaderFloat16Int8.shaderFloat16 != VK_FALSE || EnabledExtFeats.ShaderFloat16Int8.shaderInt8 != VK_FALSE); VERIFY(PhysicalDevice->IsExtensionSupported(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME), "VK_KHR_shader_float16_int8 extension must be supported as it has already been checked by VulkanPhysicalDevice " "and at least one of shaderFloat16 or shaderInt8 features is TRUE"); DeviceExtensions.push_back(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME); if (EngineCI.Features.ShaderFloat16 == DEVICE_FEATURE_STATE_DISABLED) - ShaderFloat16Int8.shaderFloat16 = VK_FALSE; + EnabledExtFeats.ShaderFloat16Int8.shaderFloat16 = VK_FALSE; if (EngineCI.Features.ShaderInt8 == DEVICE_FEATURE_STATE_DISABLED) - ShaderFloat16Int8.shaderInt8 = VK_FALSE; + EnabledExtFeats.ShaderFloat16Int8.shaderInt8 = VK_FALSE; - *NextExt = &ShaderFloat16Int8; - NextExt = &ShaderFloat16Int8.pNext; + *NextExt = &EnabledExtFeats.ShaderFloat16Int8; + NextExt = &EnabledExtFeats.ShaderFloat16Int8.pNext; } bool StorageBufferStorageClassExtensionRequired = false; @@ -325,9 +324,10 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E // clang-format on { // clang-format off - VERIFY_EXPR(EngineCI.Features.ResourceBuffer16BitAccess == DEVICE_FEATURE_STATE_DISABLED || Storage16BitFeats.storageBuffer16BitAccess != VK_FALSE); - VERIFY_EXPR(EngineCI.Features.UniformBuffer16BitAccess == DEVICE_FEATURE_STATE_DISABLED || Storage16BitFeats.uniformAndStorageBuffer16BitAccess != VK_FALSE); - VERIFY_EXPR(EngineCI.Features.ShaderInputOutput16 == DEVICE_FEATURE_STATE_DISABLED || Storage16BitFeats.storageInputOutput16 != VK_FALSE); + EnabledExtFeats.Storage16Bit = DeviceExtFeatures.Storage16Bit; + VERIFY_EXPR(EngineCI.Features.ResourceBuffer16BitAccess == DEVICE_FEATURE_STATE_DISABLED || EnabledExtFeats.Storage16Bit.storageBuffer16BitAccess != VK_FALSE); + VERIFY_EXPR(EngineCI.Features.UniformBuffer16BitAccess == DEVICE_FEATURE_STATE_DISABLED || EnabledExtFeats.Storage16Bit.uniformAndStorageBuffer16BitAccess != VK_FALSE); + VERIFY_EXPR(EngineCI.Features.ShaderInputOutput16 == DEVICE_FEATURE_STATE_DISABLED || EnabledExtFeats.Storage16Bit.storageInputOutput16 != VK_FALSE); // clang-format on VERIFY(PhysicalDevice->IsExtensionSupported(VK_KHR_16BIT_STORAGE_EXTENSION_NAME), @@ -344,14 +344,14 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E StorageBufferStorageClassExtensionRequired = true; if (EngineCI.Features.ResourceBuffer16BitAccess == DEVICE_FEATURE_STATE_DISABLED) - Storage16BitFeats.storageBuffer16BitAccess = VK_FALSE; + EnabledExtFeats.Storage16Bit.storageBuffer16BitAccess = VK_FALSE; if (EngineCI.Features.UniformBuffer16BitAccess == DEVICE_FEATURE_STATE_DISABLED) - Storage16BitFeats.uniformAndStorageBuffer16BitAccess = VK_FALSE; + EnabledExtFeats.Storage16Bit.uniformAndStorageBuffer16BitAccess = VK_FALSE; if (EngineCI.Features.ShaderInputOutput16 == DEVICE_FEATURE_STATE_DISABLED) - Storage16BitFeats.storageInputOutput16 = VK_FALSE; + EnabledExtFeats.Storage16Bit.storageInputOutput16 = VK_FALSE; - *NextExt = &Storage16BitFeats; - NextExt = &Storage16BitFeats.pNext; + *NextExt = &EnabledExtFeats.Storage16Bit; + NextExt = &EnabledExtFeats.Storage16Bit.pNext; } // clang-format off @@ -360,8 +360,9 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E // clang-format on { // clang-format off - VERIFY_EXPR(EngineCI.Features.ResourceBuffer8BitAccess == DEVICE_FEATURE_STATE_DISABLED || Storage8BitFeats.storageBuffer8BitAccess != VK_FALSE); - VERIFY_EXPR(EngineCI.Features.UniformBuffer8BitAccess == DEVICE_FEATURE_STATE_DISABLED || Storage8BitFeats.uniformAndStorageBuffer8BitAccess != VK_FALSE); + EnabledExtFeats.Storage8Bit = DeviceExtFeatures.Storage8Bit; + VERIFY_EXPR(EngineCI.Features.ResourceBuffer8BitAccess == DEVICE_FEATURE_STATE_DISABLED || EnabledExtFeats.Storage8Bit.storageBuffer8BitAccess != VK_FALSE); + VERIFY_EXPR(EngineCI.Features.UniformBuffer8BitAccess == DEVICE_FEATURE_STATE_DISABLED || EnabledExtFeats.Storage8Bit.uniformAndStorageBuffer8BitAccess != VK_FALSE); // clang-format on VERIFY(PhysicalDevice->IsExtensionSupported(VK_KHR_8BIT_STORAGE_EXTENSION_NAME), @@ -378,12 +379,12 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E StorageBufferStorageClassExtensionRequired = true; if (EngineCI.Features.ResourceBuffer8BitAccess == DEVICE_FEATURE_STATE_DISABLED) - Storage8BitFeats.storageBuffer8BitAccess = VK_FALSE; + EnabledExtFeats.Storage8Bit.storageBuffer8BitAccess = VK_FALSE; if (EngineCI.Features.UniformBuffer8BitAccess == DEVICE_FEATURE_STATE_DISABLED) - Storage8BitFeats.uniformAndStorageBuffer8BitAccess = VK_FALSE; + EnabledExtFeats.Storage8Bit.uniformAndStorageBuffer8BitAccess = VK_FALSE; - *NextExt = &Storage8BitFeats; - NextExt = &Storage8BitFeats.pNext; + *NextExt = &EnabledExtFeats.Storage8Bit; + NextExt = &EnabledExtFeats.Storage8Bit.pNext; } if (StorageBufferStorageClassExtensionRequired) @@ -398,29 +399,37 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E { if (DeviceExtFeatures.RayTracingNV) { + EnabledExtFeats.RayTracingNV = DeviceExtFeatures.RayTracingNV; DeviceExtensions.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); DeviceExtensions.push_back(VK_NV_RAY_TRACING_EXTENSION_NAME); } - else if (RayTracingFeats.rayTracing != VK_FALSE) - { - // required extensions - DeviceExtensions.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); - DeviceExtensions.push_back(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); - DeviceExtensions.push_back(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); - DeviceExtensions.push_back(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); - DeviceExtensions.push_back(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); - DeviceExtensions.push_back(VK_KHR_RAY_TRACING_EXTENSION_NAME); - - *NextExt = &RayTracingFeats; - NextExt = &RayTracingFeats.pNext; - *NextExt = &DescriptorIndexingFeats; - NextExt = &DescriptorIndexingFeats.pNext; - *NextExt = &BufferDeviceAddressFeats; - NextExt = &BufferDeviceAddressFeats.pNext; - } - else + else if (DeviceExtFeatures.RayTracing.rayTracing != VK_FALSE) { - UNEXPECTED("Either KHR or NV extension must be enabled"); + DeviceExtensions.push_back(VK_KHR_MAINTENANCE3_EXTENSION_NAME); // required for VK_EXT_descriptor_indexing + DeviceExtensions.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); // required for VK_KHR_ray_tracing + DeviceExtensions.push_back(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); // required for VK_KHR_ray_tracing + DeviceExtensions.push_back(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); // required for VK_KHR_ray_tracing + DeviceExtensions.push_back(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); // required for VK_KHR_ray_tracing + DeviceExtensions.push_back(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); // required for VK_KHR_ray_tracing + DeviceExtensions.push_back(VK_KHR_RAY_TRACING_EXTENSION_NAME); // required for VK_KHR_ray_tracing + + EnabledExtFeats.RayTracing = DeviceExtFeatures.RayTracing; + EnabledExtFeats.BufferDeviceAddress = DeviceExtFeatures.BufferDeviceAddress; + EnabledExtFeats.DescriptorIndexing = DeviceExtFeatures.DescriptorIndexing; + + if (!DeviceExtFeatures.Spirv15) + { + DeviceExtensions.push_back(VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME); // required for VK_KHR_spirv_1_4 + DeviceExtensions.push_back(VK_KHR_SPIRV_1_4_EXTENSION_NAME); // required for ray tracing shaders + EnabledExtFeats.Spirv14 = DeviceExtFeatures.Spirv14; + } + + *NextExt = &EnabledExtFeats.RayTracing; + NextExt = &EnabledExtFeats.RayTracing.pNext; + *NextExt = &EnabledExtFeats.DescriptorIndexing; + NextExt = &EnabledExtFeats.DescriptorIndexing.pNext; + *NextExt = &EnabledExtFeats.BufferDeviceAddress; + NextExt = &EnabledExtFeats.BufferDeviceAddress.pNext; } } @@ -436,7 +445,7 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E DeviceCreateInfo.enabledExtensionCount = static_cast(DeviceExtensions.size()); auto vkAllocator = Instance->GetVkAllocator(); - auto LogicalDevice = VulkanUtilities::VulkanLogicalDevice::Create(*PhysicalDevice, DeviceCreateInfo, vkAllocator); + auto LogicalDevice = VulkanUtilities::VulkanLogicalDevice::Create(*PhysicalDevice, DeviceCreateInfo, EnabledExtFeats, vkAllocator); auto& RawMemAllocator = GetRawAllocator(); diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp index b221659a..d0e37670 100644 --- a/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp +++ b/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp @@ -45,18 +45,19 @@ class ResourceTypeToVkDescriptorType public: ResourceTypeToVkDescriptorType() { - static_assert(SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes == 11, "Please add the corresponding decriptor type"); - m_Map[SPIRVShaderResourceAttribs::ResourceType::UniformBuffer] = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; - m_Map[SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer] = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC; - m_Map[SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer] = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC; - m_Map[SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer] = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; - m_Map[SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer] = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; - m_Map[SPIRVShaderResourceAttribs::ResourceType::StorageImage] = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - m_Map[SPIRVShaderResourceAttribs::ResourceType::SampledImage] = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - m_Map[SPIRVShaderResourceAttribs::ResourceType::AtomicCounter] = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - m_Map[SPIRVShaderResourceAttribs::ResourceType::SeparateImage] = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; - m_Map[SPIRVShaderResourceAttribs::ResourceType::SeparateSampler] = VK_DESCRIPTOR_TYPE_SAMPLER; - m_Map[SPIRVShaderResourceAttribs::ResourceType::InputAttachment] = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT; + static_assert(SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes == 12, "Please add the corresponding decriptor type"); + m_Map[SPIRVShaderResourceAttribs::ResourceType::UniformBuffer] = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; + m_Map[SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer] = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC; + m_Map[SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer] = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC; + m_Map[SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer] = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; + m_Map[SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer] = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; + m_Map[SPIRVShaderResourceAttribs::ResourceType::StorageImage] = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + m_Map[SPIRVShaderResourceAttribs::ResourceType::SampledImage] = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + m_Map[SPIRVShaderResourceAttribs::ResourceType::AtomicCounter] = VK_DESCRIPTOR_TYPE_MAX_ENUM; // atomic counter doesn't exist in Vulkan + m_Map[SPIRVShaderResourceAttribs::ResourceType::SeparateImage] = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + m_Map[SPIRVShaderResourceAttribs::ResourceType::SeparateSampler] = VK_DESCRIPTOR_TYPE_SAMPLER; + m_Map[SPIRVShaderResourceAttribs::ResourceType::InputAttachment] = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT; + m_Map[SPIRVShaderResourceAttribs::ResourceType::AccelerationStructure] = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR; } VkDescriptorType operator[](SPIRVShaderResourceAttribs::ResourceType ResType) const @@ -68,10 +69,10 @@ private: std::array m_Map = {}; }; -VkDescriptorType PipelineLayout::GetVkDescriptorType(const SPIRVShaderResourceAttribs& Res) +VkDescriptorType PipelineLayout::GetVkDescriptorType(SPIRVShaderResourceAttribs::ResourceType Type) { static const ResourceTypeToVkDescriptorType ResTypeToVkDescrType; - return ResTypeToVkDescrType[Res.Type]; + return ResTypeToVkDescrType[Type]; } PipelineLayout::DescriptorSetLayoutManager::DescriptorSetLayoutManager(IMemoryAllocator& MemAllocator) : @@ -331,7 +332,7 @@ void PipelineLayout::DescriptorSetLayoutManager::AllocateResourceSlot(const SPIR Binding = DescrSet.NumLayoutBindings; VkBinding.binding = Binding; - VkBinding.descriptorType = GetVkDescriptorType(ResAttribs); + VkBinding.descriptorType = GetVkDescriptorType(ResAttribs.Type); VkBinding.descriptorCount = ResAttribs.ArraySize; // There are no limitations on what combinations of stages can use a descriptor binding (13.2.1) VkBinding.stageFlags = ShaderTypeToVkShaderStageFlagBit(ShaderType); @@ -369,16 +370,13 @@ void PipelineLayout::AllocateResourceSlot(const SPIRVShaderResourceAttribs& ResA SHADER_TYPE ShaderType, Uint32& DescriptorSet, // Output parameter Uint32& Binding, // Output parameter - Uint32& OffsetInCache, - std::vector& SPIRV) + Uint32& OffsetInCache) { VERIFY((ResAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage || ResAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler) || vkImmutableSampler == VK_NULL_HANDLE, "Immutable sampler should only be specified for combined image samplers or separate samplers"); m_LayoutMgr.AllocateResourceSlot(ResAttribs, VariableType, vkImmutableSampler, ShaderType, DescriptorSet, Binding, OffsetInCache); - SPIRV[ResAttribs.BindingDecorationOffset] = Binding; - SPIRV[ResAttribs.DescriptorSetDecorationOffset] = DescriptorSet; } void PipelineLayout::Finalize(const VulkanUtilities::VulkanLogicalDevice& LogicalDevice) @@ -435,7 +433,6 @@ void PipelineLayout::InitResourceCache(RenderDeviceVkImpl* pDeviceVkImpl, } void PipelineLayout::PrepareDescriptorSets(DeviceContextVkImpl* pCtxVkImpl, - bool IsCompute, const ShaderResourceCacheVk& ResourceCache, DescriptorSetBindInfo& BindInfo, VkDescriptorSet VkDynamicDescrSet) const @@ -481,7 +478,6 @@ void PipelineLayout::PrepareDescriptorSets(DeviceContextVkImpl* pCtxVkIm BindInfo.DynamicOffsetCount = TotalDynamicDescriptors; if (TotalDynamicDescriptors > BindInfo.DynamicOffsets.size()) BindInfo.DynamicOffsets.resize(TotalDynamicDescriptors); - BindInfo.BindPoint = IsCompute ? VK_PIPELINE_BIND_POINT_COMPUTE : VK_PIPELINE_BIND_POINT_GRAPHICS; BindInfo.pResourceCache = &ResourceCache; #ifdef DILIGENT_DEBUG BindInfo.pDbgPipelineLayout = this; diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp index 83512870..c7b9e05f 100644 --- a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp @@ -44,98 +44,24 @@ namespace Diligent { - -RenderPassDesc PipelineStateVkImpl::GetImplicitRenderPassDesc( - Uint32 NumRenderTargets, - const TEXTURE_FORMAT RTVFormats[], - TEXTURE_FORMAT DSVFormat, - Uint8 SampleCount, - std::array& Attachments, - std::array& AttachmentReferences, - SubpassDesc& SubpassDesc) +namespace { - VERIFY_EXPR(NumRenderTargets <= MAX_RENDER_TARGETS); - - RenderPassDesc RPDesc; - - RPDesc.AttachmentCount = (DSVFormat != TEX_FORMAT_UNKNOWN ? 1 : 0) + NumRenderTargets; - uint32_t AttachmentInd = 0; - AttachmentReference* pDepthAttachmentReference = nullptr; - if (DSVFormat != TEX_FORMAT_UNKNOWN) - { - auto& DepthAttachment = Attachments[AttachmentInd]; - - DepthAttachment.Format = DSVFormat; - DepthAttachment.SampleCount = SampleCount; - DepthAttachment.LoadOp = ATTACHMENT_LOAD_OP_LOAD; // previous contents of the image within the render area - // will be preserved. For attachments with a depth/stencil format, - // this uses the access type VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT. - DepthAttachment.StoreOp = ATTACHMENT_STORE_OP_STORE; // the contents generated during the render pass and within the render - // area are written to memory. For attachments with a depth/stencil format, - // this uses the access type VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT. - DepthAttachment.StencilLoadOp = ATTACHMENT_LOAD_OP_LOAD; - DepthAttachment.StencilStoreOp = ATTACHMENT_STORE_OP_STORE; - DepthAttachment.InitialState = RESOURCE_STATE_DEPTH_WRITE; - DepthAttachment.FinalState = RESOURCE_STATE_DEPTH_WRITE; - - pDepthAttachmentReference = &AttachmentReferences[AttachmentInd]; - pDepthAttachmentReference->AttachmentIndex = AttachmentInd; - pDepthAttachmentReference->State = RESOURCE_STATE_DEPTH_WRITE; - - ++AttachmentInd; - } - - AttachmentReference* pColorAttachmentsReference = NumRenderTargets > 0 ? &AttachmentReferences[AttachmentInd] : nullptr; - for (Uint32 rt = 0; rt < NumRenderTargets; ++rt, ++AttachmentInd) - { - auto& ColorAttachment = Attachments[AttachmentInd]; - - ColorAttachment.Format = RTVFormats[rt]; - ColorAttachment.SampleCount = SampleCount; - ColorAttachment.LoadOp = ATTACHMENT_LOAD_OP_LOAD; // previous contents of the image within the render area - // will be preserved. For attachments with a depth/stencil format, - // this uses the access type VK_ACCESS_COLOR_ATTACHMENT_READ_BIT. - ColorAttachment.StoreOp = ATTACHMENT_STORE_OP_STORE; // the contents generated during the render pass and within the render - // area are written to memory. For attachments with a color format, - // this uses the access type VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT. - ColorAttachment.StencilLoadOp = ATTACHMENT_LOAD_OP_DISCARD; - ColorAttachment.StencilStoreOp = ATTACHMENT_STORE_OP_DISCARD; - ColorAttachment.InitialState = RESOURCE_STATE_RENDER_TARGET; - ColorAttachment.FinalState = RESOURCE_STATE_RENDER_TARGET; - - auto& ColorAttachmentRef = AttachmentReferences[AttachmentInd]; - ColorAttachmentRef.AttachmentIndex = AttachmentInd; - ColorAttachmentRef.State = RESOURCE_STATE_RENDER_TARGET; - } - - RPDesc.pAttachments = Attachments.data(); - RPDesc.SubpassCount = 1; - RPDesc.pSubpasses = &SubpassDesc; - RPDesc.DependencyCount = 0; // the number of dependencies between pairs of subpasses, or zero indicating no dependencies. - RPDesc.pDependencies = nullptr; // an array of dependencyCount number of VkSubpassDependency structures describing - // dependencies between pairs of subpasses, or NULL if dependencyCount is zero. - - - SubpassDesc.InputAttachmentCount = 0; - SubpassDesc.pInputAttachments = nullptr; - SubpassDesc.RenderTargetAttachmentCount = NumRenderTargets; - SubpassDesc.pRenderTargetAttachments = pColorAttachmentsReference; - SubpassDesc.pResolveAttachments = nullptr; - SubpassDesc.pDepthStencilAttachment = pDepthAttachmentReference; - SubpassDesc.PreserveAttachmentCount = 0; - SubpassDesc.pPreserveAttachments = nullptr; - - return RPDesc; -} - -static bool StripReflection(std::vector& SPIRV) +bool StripReflection(const VulkanUtilities::VulkanLogicalDevice& LogicalDevice, std::vector& SPIRV) { #if DILIGENT_NO_HLSL - return false; + return true; #else std::vector StrippedSPIRV; - spvtools::Optimizer SpirvOptimizer(SPV_ENV_VULKAN_1_0); + spv_target_env Target = SPV_ENV_VULKAN_1_0; + const auto& ExtFeats = LogicalDevice.GetEnabledExtFeatures(); + + if (ExtFeats.Spirv15) + Target = SPV_ENV_VULKAN_1_2; + else if (ExtFeats.Spirv14) + Target = SPV_ENV_VULKAN_1_1_SPIRV_1_4; + + spvtools::Optimizer SpirvOptimizer(Target); // Decorations defined in SPV_GOOGLE_hlsl_functionality1 are the only instructions // removed by strip-reflect-info pass. SPIRV offsets become INVALID after this operation. SpirvOptimizer.RegisterPass(spvtools::CreateStripReflectInfoPass()); @@ -149,21 +75,25 @@ static bool StripReflection(std::vector& SPIRV) #endif } -static void InitPipelineShaderStages(const VulkanUtilities::VulkanLogicalDevice& LogicalDevice, - ShaderResourceLayoutVk::TShaderStages& ShaderStages, - std::vector& vkShaderModules, - std::vector& vkPipelineShaderStages) +void InitPipelineShaderStages(const VulkanUtilities::VulkanLogicalDevice& LogicalDevice, + ShaderResourceLayoutVk::TShaderStages& ShaderStages, + std::vector& ShaderModules, + std::vector& Stages) { for (size_t s = 0; s < ShaderStages.size(); ++s) { - auto& StageInfo = ShaderStages[s]; + const auto& Shaders = ShaderStages[s].Shaders; + auto& SPIRVs = ShaderStages[s].SPIRVs; + const auto ShaderType = ShaderStages[s].Type; + + VERIFY_EXPR(Shaders.size() == SPIRVs.size()); VkPipelineShaderStageCreateInfo StageCI = {}; StageCI.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; StageCI.pNext = nullptr; StageCI.flags = 0; // reserved for future use - StageCI.stage = ShaderTypeToVkShaderStageFlagBit(StageInfo.Type); + StageCI.stage = ShaderTypeToVkShaderStageFlagBit(ShaderType); VkShaderModuleCreateInfo ShaderModuleCI = {}; @@ -171,33 +101,39 @@ static void InitPipelineShaderStages(const VulkanUtilities::VulkanLogicalDevice& ShaderModuleCI.pNext = nullptr; ShaderModuleCI.flags = 0; - // We have to strip reflection instructions to fix the follownig validation error: - // SPIR-V module not valid: DecorateStringGOOGLE requires one of the following extensions: SPV_GOOGLE_decorate_string - // Optimizer also performs validation and may catch problems with the byte code. - if (!StripReflection(StageInfo.SPIRV)) - LOG_ERROR("Failed to strip reflection information from shader '", StageInfo.pShader->GetDesc().Name, "'. This may indicate a problem with the byte code."); + for (size_t i = 0; i < Shaders.size(); ++i) + { + auto* pShader = Shaders[i]; + auto& SPIRV = SPIRVs[i]; + + // We have to strip reflection instructions to fix the follownig validation error: + // SPIR-V module not valid: DecorateStringGOOGLE requires one of the following extensions: SPV_GOOGLE_decorate_string + // Optimizer also performs validation and may catch problems with the byte code. + if (!StripReflection(LogicalDevice, SPIRV)) + LOG_ERROR("Failed to strip reflection information from shader '", pShader->GetDesc().Name, "'. This may indicate a problem with the byte code."); - ShaderModuleCI.codeSize = StageInfo.SPIRV.size() * sizeof(uint32_t); - ShaderModuleCI.pCode = StageInfo.SPIRV.data(); + ShaderModuleCI.codeSize = SPIRV.size() * sizeof(uint32_t); + ShaderModuleCI.pCode = SPIRV.data(); - vkShaderModules.push_back(LogicalDevice.CreateShaderModule(ShaderModuleCI, StageInfo.pShader->GetDesc().Name)); + ShaderModules.push_back(LogicalDevice.CreateShaderModule(ShaderModuleCI, pShader->GetDesc().Name)); - StageCI.module = vkShaderModules.back(); - StageCI.pName = StageInfo.pShader->GetEntryPoint(); - StageCI.pSpecializationInfo = nullptr; + StageCI.module = ShaderModules.back(); + StageCI.pName = pShader->GetEntryPoint(); + StageCI.pSpecializationInfo = nullptr; - vkPipelineShaderStages.push_back(StageCI); + Stages.push_back(StageCI); + } } - VERIFY_EXPR(vkShaderModules.size() == vkPipelineShaderStages.size()); + VERIFY_EXPR(ShaderModules.size() == Stages.size()); } -static void CreateComputePipeline(RenderDeviceVkImpl* pDeviceVk, - std::vector& Stages, - const PipelineLayout& Layout, - const PipelineStateDesc& PSODesc, - VulkanUtilities::PipelineWrapper& Pipeline) +void CreateComputePipeline(RenderDeviceVkImpl* pDeviceVk, + std::vector& Stages, + const PipelineLayout& Layout, + const PipelineStateDesc& PSODesc, + VulkanUtilities::PipelineWrapper& Pipeline) { const auto& LogicalDevice = pDeviceVk->GetLogicalDevice(); @@ -218,13 +154,13 @@ static void CreateComputePipeline(RenderDeviceVkImpl* } -static void CreateGraphicsPipeline(RenderDeviceVkImpl* pDeviceVk, - std::vector& Stages, - const PipelineLayout& Layout, - const PipelineStateDesc& PSODesc, - const GraphicsPipelineDesc& GraphicsPipeline, - VulkanUtilities::PipelineWrapper& Pipeline, - RefCntAutoPtr& pRenderPass) +void CreateGraphicsPipeline(RenderDeviceVkImpl* pDeviceVk, + std::vector& Stages, + const PipelineLayout& Layout, + const PipelineStateDesc& PSODesc, + const GraphicsPipelineDesc& GraphicsPipeline, + VulkanUtilities::PipelineWrapper& Pipeline, + RefCntAutoPtr& pRenderPass) { const auto& LogicalDevice = pDeviceVk->GetLogicalDevice(); const auto& PhysicalDevice = pDeviceVk->GetPhysicalDevice(); @@ -401,6 +337,240 @@ static void CreateGraphicsPipeline(RenderDeviceVkImpl* Pipeline = LogicalDevice.CreateGraphicsPipeline(PipelineCI, VK_NULL_HANDLE, PSODesc.Name); } + +void CreateRayTracingPipeline(RenderDeviceVkImpl* pDeviceVk, + std::vector& Stages, + const std::vector& ShaderGroups, + const PipelineLayout& Layout, + const PipelineStateDesc& PSODesc, + const RayTracingPipelineDesc& RayTracingPipeline, + VulkanUtilities::PipelineWrapper& Pipeline) +{ + const auto& LogicalDevice = pDeviceVk->GetLogicalDevice(); + const auto& PhysicalDevice = pDeviceVk->GetPhysicalDevice(); + const auto& RTLimits = PhysicalDevice.GetExtProperties().RayTracing; + + DEV_CHECK_ERR(RayTracingPipeline.MaxRecursionDepth <= RTLimits.maxRecursionDepth, + "RayTracingPipeline.MaxRecursionDepth must not exceed ", RTLimits.maxRecursionDepth); + + VkRayTracingPipelineCreateInfoKHR PipelineCI = {}; + + PipelineCI.sType = VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR; + PipelineCI.pNext = nullptr; +#ifdef DILIGENT_DEBUG + PipelineCI.flags = VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT; +#endif + + PipelineCI.stageCount = static_cast(Stages.size()); + PipelineCI.pStages = Stages.data(); + PipelineCI.layout = Layout.GetVkPipelineLayout(); + + PipelineCI.groupCount = static_cast(ShaderGroups.size()); + PipelineCI.pGroups = ShaderGroups.data(); + PipelineCI.maxRecursionDepth = RayTracingPipeline.MaxRecursionDepth; + PipelineCI.libraries.sType = VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR; + PipelineCI.libraries.pNext = nullptr; + PipelineCI.libraries.libraryCount = 0; + PipelineCI.libraries.pLibraries = nullptr; + PipelineCI.pLibraryInterface = nullptr; + PipelineCI.basePipelineHandle = VK_NULL_HANDLE; // a pipeline to derive from + PipelineCI.basePipelineIndex = -1; // an index into the pCreateInfos parameter to use as a pipeline to derive from + + Pipeline = LogicalDevice.CreateRayTracingPipeline(PipelineCI, VK_NULL_HANDLE, PSODesc.Name); +} + + +template +void BuildRTPipelineDescription(const RayTracingPipelineStateCreateInfo& CreateInfo, + TNameToGroupIndexMap& NameToGroupIndex, + std::vector& ShaderGroups, + const ShaderResourceLayoutVk::TShaderStages& ShaderStages, + LinearAllocator& MemPool) +{ +#define LOG_PSO_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Description of ray tracing PSO '", CreateInfo.PSODesc.Name, "' is invalid: ", ##__VA_ARGS__) + ShaderGroups.reserve(CreateInfo.GeneralShaderCount + CreateInfo.TriangleHitShaderCount + CreateInfo.ProceduralHitShaderCount); + + Uint32 GroupIndex = 0; + Uint32 ShaderIndex = 0; + + std::unordered_map UniqueShaders; + + const auto ShaderToIndex = [&ShaderIndex, &UniqueShaders](const IShader* pShader) -> Uint32 { + if (pShader != nullptr) + { + auto Result = UniqueShaders.emplace(pShader, ShaderIndex); + if (Result.second) + { + ++ShaderIndex; + } + return Result.first->second; + } + return VK_SHADER_UNUSED_KHR; + }; + + for (Uint32 i = 0; i < CreateInfo.GeneralShaderCount; ++i) + { + VkRayTracingShaderGroupCreateInfoKHR Group = {}; + + Group.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR; + Group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + Group.generalShader = ShaderToIndex(CreateInfo.pGeneralShaders[i].pShader); + Group.closestHitShader = VK_SHADER_UNUSED_KHR; + Group.anyHitShader = VK_SHADER_UNUSED_KHR; + Group.intersectionShader = VK_SHADER_UNUSED_KHR; + + bool IsUniqueName = NameToGroupIndex.emplace(HashMapStringKey{MemPool.CopyString(CreateInfo.pGeneralShaders[i].Name)}, GroupIndex++).second; + if (!IsUniqueName) + LOG_PSO_ERROR_AND_THROW("pGeneralShaders[", i, "].Name must be unique"); + + ShaderGroups.push_back(Group); + } + + for (Uint32 i = 0; i < CreateInfo.TriangleHitShaderCount; ++i) + { + VkRayTracingShaderGroupCreateInfoKHR Group = {}; + + Group.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR; + Group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; + Group.generalShader = VK_SHADER_UNUSED_KHR; + Group.closestHitShader = ShaderToIndex(CreateInfo.pTriangleHitShaders[i].pClosestHitShader); + Group.anyHitShader = ShaderToIndex(CreateInfo.pTriangleHitShaders[i].pAnyHitShader); + Group.intersectionShader = VK_SHADER_UNUSED_KHR; + + bool IsUniqueName = NameToGroupIndex.emplace(HashMapStringKey{MemPool.CopyString(CreateInfo.pTriangleHitShaders[i].Name)}, GroupIndex++).second; + if (!IsUniqueName) + LOG_PSO_ERROR_AND_THROW("pTriangleHitShaders[", i, "].Name must be unique"); + + ShaderGroups.push_back(Group); + } + + for (Uint32 i = 0; i < CreateInfo.ProceduralHitShaderCount; ++i) + { + VkRayTracingShaderGroupCreateInfoKHR Group = {}; + + Group.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR; + Group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR; + Group.generalShader = VK_SHADER_UNUSED_KHR; + Group.intersectionShader = ShaderToIndex(CreateInfo.pProceduralHitShaders[i].pIntersectionShader); + Group.closestHitShader = ShaderToIndex(CreateInfo.pProceduralHitShaders[i].pClosestHitShader); + Group.anyHitShader = ShaderToIndex(CreateInfo.pProceduralHitShaders[i].pAnyHitShader); + + bool IsUniqueName = NameToGroupIndex.emplace(HashMapStringKey{MemPool.CopyString(CreateInfo.pProceduralHitShaders[i].Name)}, GroupIndex++).second; + if (!IsUniqueName) + LOG_PSO_ERROR_AND_THROW("pProceduralHitShaders[", i, "].Name must be unique"); + + ShaderGroups.push_back(Group); + } + + VERIFY_EXPR(Uint32(CreateInfo.GeneralShaderCount + CreateInfo.TriangleHitShaderCount + CreateInfo.ProceduralHitShaderCount) == GroupIndex); + +#ifdef DILIGENT_DEVELOPMENT + Uint32 ShaderIndex2 = 0; + for (auto& Stage : ShaderStages) + { + for (auto* pShader : Stage.Shaders) + { + auto iter = UniqueShaders.find(static_cast(pShader)); + if (iter != UniqueShaders.end()) + VERIFY_EXPR(iter->second == ShaderIndex2); + else + UNEXPECTED("shader is not used in ray tracing shader groups"); + + ++ShaderIndex2; + } + } + VERIFY_EXPR(ShaderIndex == ShaderIndex2); +#endif +#undef LOG_PSO_ERROR_AND_THROW +} + +} // namespace + + +RenderPassDesc PipelineStateVkImpl::GetImplicitRenderPassDesc( + Uint32 NumRenderTargets, + const TEXTURE_FORMAT RTVFormats[], + TEXTURE_FORMAT DSVFormat, + Uint8 SampleCount, + std::array& Attachments, + std::array& AttachmentReferences, + SubpassDesc& SubpassDesc) +{ + VERIFY_EXPR(NumRenderTargets <= MAX_RENDER_TARGETS); + + RenderPassDesc RPDesc; + + RPDesc.AttachmentCount = (DSVFormat != TEX_FORMAT_UNKNOWN ? 1 : 0) + NumRenderTargets; + + uint32_t AttachmentInd = 0; + AttachmentReference* pDepthAttachmentReference = nullptr; + if (DSVFormat != TEX_FORMAT_UNKNOWN) + { + auto& DepthAttachment = Attachments[AttachmentInd]; + + DepthAttachment.Format = DSVFormat; + DepthAttachment.SampleCount = SampleCount; + DepthAttachment.LoadOp = ATTACHMENT_LOAD_OP_LOAD; // previous contents of the image within the render area + // will be preserved. For attachments with a depth/stencil format, + // this uses the access type VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT. + DepthAttachment.StoreOp = ATTACHMENT_STORE_OP_STORE; // the contents generated during the render pass and within the render + // area are written to memory. For attachments with a depth/stencil format, + // this uses the access type VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT. + DepthAttachment.StencilLoadOp = ATTACHMENT_LOAD_OP_LOAD; + DepthAttachment.StencilStoreOp = ATTACHMENT_STORE_OP_STORE; + DepthAttachment.InitialState = RESOURCE_STATE_DEPTH_WRITE; + DepthAttachment.FinalState = RESOURCE_STATE_DEPTH_WRITE; + + pDepthAttachmentReference = &AttachmentReferences[AttachmentInd]; + pDepthAttachmentReference->AttachmentIndex = AttachmentInd; + pDepthAttachmentReference->State = RESOURCE_STATE_DEPTH_WRITE; + + ++AttachmentInd; + } + + AttachmentReference* pColorAttachmentsReference = NumRenderTargets > 0 ? &AttachmentReferences[AttachmentInd] : nullptr; + for (Uint32 rt = 0; rt < NumRenderTargets; ++rt, ++AttachmentInd) + { + auto& ColorAttachment = Attachments[AttachmentInd]; + + ColorAttachment.Format = RTVFormats[rt]; + ColorAttachment.SampleCount = SampleCount; + ColorAttachment.LoadOp = ATTACHMENT_LOAD_OP_LOAD; // previous contents of the image within the render area + // will be preserved. For attachments with a depth/stencil format, + // this uses the access type VK_ACCESS_COLOR_ATTACHMENT_READ_BIT. + ColorAttachment.StoreOp = ATTACHMENT_STORE_OP_STORE; // the contents generated during the render pass and within the render + // area are written to memory. For attachments with a color format, + // this uses the access type VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT. + ColorAttachment.StencilLoadOp = ATTACHMENT_LOAD_OP_DISCARD; + ColorAttachment.StencilStoreOp = ATTACHMENT_STORE_OP_DISCARD; + ColorAttachment.InitialState = RESOURCE_STATE_RENDER_TARGET; + ColorAttachment.FinalState = RESOURCE_STATE_RENDER_TARGET; + + auto& ColorAttachmentRef = AttachmentReferences[AttachmentInd]; + ColorAttachmentRef.AttachmentIndex = AttachmentInd; + ColorAttachmentRef.State = RESOURCE_STATE_RENDER_TARGET; + } + + RPDesc.pAttachments = Attachments.data(); + RPDesc.SubpassCount = 1; + RPDesc.pSubpasses = &SubpassDesc; + RPDesc.DependencyCount = 0; // the number of dependencies between pairs of subpasses, or zero indicating no dependencies. + RPDesc.pDependencies = nullptr; // an array of dependencyCount number of VkSubpassDependency structures describing + // dependencies between pairs of subpasses, or NULL if dependencyCount is zero. + + + SubpassDesc.InputAttachmentCount = 0; + SubpassDesc.pInputAttachments = nullptr; + SubpassDesc.RenderTargetAttachmentCount = NumRenderTargets; + SubpassDesc.pRenderTargetAttachments = pColorAttachmentsReference; + SubpassDesc.pResolveAttachments = nullptr; + SubpassDesc.pDepthStencilAttachment = pDepthAttachmentReference; + SubpassDesc.PreserveAttachmentCount = 0; + SubpassDesc.pPreserveAttachments = nullptr; + + return RPDesc; +} + void PipelineStateVkImpl::InitResourceLayouts(const PipelineStateCreateInfo& CreateInfo, TShaderStages& ShaderStages) { @@ -416,7 +586,7 @@ void PipelineStateVkImpl::InitResourceLayouts(const PipelineStateCreateInfo& Cre m_ResourceLayoutIndex[ShaderTypeInd] = static_cast(s); auto& StaticResLayout = m_ShaderResourceLayouts[GetNumShaderStages() + s]; - StaticResLayout.InitializeStaticResourceLayout(StageInfo.pShader, GetRawAllocator(), m_Desc.ResourceLayout, m_StaticResCaches[s]); + StaticResLayout.InitializeStaticResourceLayout(StageInfo.Shaders, GetRawAllocator(), m_Desc.ResourceLayout, m_StaticResCaches[s]); m_StaticVarsMgrs[s].Initialize(StaticResLayout, GetRawAllocator(), nullptr, 0); } @@ -509,6 +679,7 @@ void PipelineStateVkImpl::InitInternalObjects(const PSOCreateInfoType& InitPipelineShaderStages(GetDevice()->GetLogicalDevice(), ShaderStages, ShaderModules, vkShaderStages); } + PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* pRefCounters, RenderDeviceVkImpl* pDeviceVk, const GraphicsPipelineStateCreateInfo& CreateInfo) : @@ -554,6 +725,75 @@ PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* p } } +PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* pRefCounters, + RenderDeviceVkImpl* pDeviceVk, + const RayTracingPipelineStateCreateInfo& CreateInfo) : + TPipelineStateBase{pRefCounters, pDeviceVk, CreateInfo.PSODesc}, + m_SRBMemAllocator{GetRawAllocator()} +{ + try + { + m_ResourceLayoutIndex.fill(-1); + + TShaderStages ShaderStages; + ExtractShaders(CreateInfo, ShaderStages); + + const auto ShaderGroupHandleSize = pDeviceVk->GetPhysicalDevice().GetExtProperties().RayTracing.shaderGroupHandleSize; + TNameToGroupIndexMap NameToGroupIndex; + LinearAllocator MemPool{GetRawAllocator()}; + + const auto NumShaderStages = GetNumShaderStages(); + VERIFY_EXPR(NumShaderStages > 0 && NumShaderStages == ShaderStages.size()); + + MemPool.AddSpace(NumShaderStages); + MemPool.AddSpace(NumShaderStages * 2); + MemPool.AddSpace(NumShaderStages); + + ReserveSpaceForPipelineDesc(CreateInfo, ShaderGroupHandleSize, MemPool); + + MemPool.Reserve(); + + const auto& LogicalDevice = GetDevice()->GetLogicalDevice(); + + m_StaticResCaches = MemPool.ConstructArray(NumShaderStages, ShaderResourceCacheVk::DbgCacheContentType::StaticShaderResources); + + // The memory is now owned by PipelineStateVkImpl and will be freed by Destruct(). + auto* Ptr = MemPool.ReleaseOwnership(); + VERIFY_EXPR(Ptr == m_StaticResCaches); + (void)Ptr; + + m_ShaderResourceLayouts = MemPool.ConstructArray(NumShaderStages * 2, LogicalDevice); + + m_StaticVarsMgrs = MemPool.Allocate(NumShaderStages); + for (Uint32 s = 0; s < NumShaderStages; ++s) + new (m_StaticVarsMgrs + s) ShaderVariableManagerVk{*this, m_StaticResCaches[s]}; + + std::vector ShaderGroups; + BuildRTPipelineDescription(CreateInfo, NameToGroupIndex, ShaderGroups, ShaderStages, MemPool); + InitializePipelineDesc(CreateInfo, ShaderGroupHandleSize, std::move(NameToGroupIndex), MemPool); + + // It is important to construct all objects before initializing them because if an exception is thrown, + // destructors will be called for all objects + + InitResourceLayouts(CreateInfo, ShaderStages); + + // Create shader modules and initialize shader stages + std::vector vkShaderStages; + std::vector ShaderModules; + InitPipelineShaderStages(GetDevice()->GetLogicalDevice(), ShaderStages, ShaderModules, vkShaderStages); + + CreateRayTracingPipeline(pDeviceVk, vkShaderStages, ShaderGroups, m_PipelineLayout, m_Desc, GetRayTracingPipelineDesc(), m_Pipeline); + + auto err = LogicalDevice.GetRayTracingShaderGroupHandles(m_Pipeline, 0, static_cast(ShaderGroups.size()), ShaderGroupHandleSize, &m_pRayTracingPipelineData->Shaders[0]); + VERIFY(err == VK_SUCCESS, "Failed to get shader group handles"); + (void)err; + } + catch (...) + { + Destruct(); + throw; + } +} PipelineStateVkImpl::~PipelineStateVkImpl() { @@ -562,6 +802,8 @@ PipelineStateVkImpl::~PipelineStateVkImpl() void PipelineStateVkImpl::Destruct() { + TPipelineStateBase::Destruct(); + m_pDevice->SafeReleaseDeviceObject(std::move(m_Pipeline), m_Desc.CommandQueueMask); m_PipelineLayout.Release(m_pDevice, m_Desc.CommandQueueMask); @@ -617,8 +859,7 @@ bool PipelineStateVkImpl::IsCompatibleWith(const IPipelineState* pPSO) const return false; auto IsSamePipelineLayout = m_PipelineLayout.IsSameAs(pPSOVk->m_PipelineLayout); - -#ifdef DILIGENT_DEBUG +#if 0 //def DILIGENT_DEBUG // AZ TODO { bool IsCompatibleShaders = true; if (GetNumShaderStages() != pPSOVk->GetNumShaderStages()) @@ -736,9 +977,21 @@ void PipelineStateVkImpl::CommitAndTransitionShaderResources(IShaderResourceBind Layout.CommitDynamicResources(ResourceCache, DynamicDescrSet); } } - // 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); + switch (m_Desc.PipelineType) + { + // clang-format off + case PIPELINE_TYPE_GRAPHICS: + case PIPELINE_TYPE_MESH: pDescrSetBindInfo->BindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; break; + case PIPELINE_TYPE_COMPUTE: pDescrSetBindInfo->BindPoint = VK_PIPELINE_BIND_POINT_COMPUTE; break; + case PIPELINE_TYPE_RAY_TRACING: pDescrSetBindInfo->BindPoint = VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR; break; + default: UNEXPECTED("unknown pipeline type"); + // clang-format on + } + + // Prepare descriptor sets, and also bind them if there are no dynamic descriptors + m_PipelineLayout.PrepareDescriptorSets(pCtxVkImpl, 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(). } @@ -783,7 +1036,7 @@ IShaderResourceVariable* PipelineStateVkImpl::GetStaticVariableByIndex(SHADER_TY if (LayoutInd < 0) return nullptr; - const auto& StaticVarMgr = GetStaticVarMgr(LayoutInd); + auto& StaticVarMgr = GetStaticVarMgr(LayoutInd); return StaticVarMgr.GetVariable(Index); } diff --git a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp index cdcac036..3199a014 100644 --- a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp @@ -96,17 +96,18 @@ RenderDeviceVkImpl::RenderDeviceVkImpl(IReferenceCounters* "Main descriptor pool", std::vector { - {VK_DESCRIPTOR_TYPE_SAMPLER, EngineCI.MainDescriptorPoolSize.NumSeparateSamplerDescriptors}, - {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, EngineCI.MainDescriptorPoolSize.NumCombinedSamplerDescriptors}, - {VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, EngineCI.MainDescriptorPoolSize.NumSampledImageDescriptors}, - {VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, EngineCI.MainDescriptorPoolSize.NumStorageImageDescriptors}, - {VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, EngineCI.MainDescriptorPoolSize.NumUniformTexelBufferDescriptors}, - {VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, EngineCI.MainDescriptorPoolSize.NumStorageTexelBufferDescriptors}, - //{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, EngineCI.MainDescriptorPoolSize.NumUniformBufferDescriptors}, - //{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, EngineCI.MainDescriptorPoolSize.NumStorageBufferDescriptors}, - {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, EngineCI.MainDescriptorPoolSize.NumUniformBufferDescriptors}, - {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, EngineCI.MainDescriptorPoolSize.NumStorageBufferDescriptors}, - {VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, EngineCI.MainDescriptorPoolSize.NumInputAttachmentDescriptors}, + {VK_DESCRIPTOR_TYPE_SAMPLER, EngineCI.MainDescriptorPoolSize.NumSeparateSamplerDescriptors}, + {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, EngineCI.MainDescriptorPoolSize.NumCombinedSamplerDescriptors}, + {VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, EngineCI.MainDescriptorPoolSize.NumSampledImageDescriptors}, + {VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, EngineCI.MainDescriptorPoolSize.NumStorageImageDescriptors}, + {VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, EngineCI.MainDescriptorPoolSize.NumUniformTexelBufferDescriptors}, + {VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, EngineCI.MainDescriptorPoolSize.NumStorageTexelBufferDescriptors}, + //{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, EngineCI.MainDescriptorPoolSize.NumUniformBufferDescriptors}, + //{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, EngineCI.MainDescriptorPoolSize.NumStorageBufferDescriptors}, + {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, EngineCI.MainDescriptorPoolSize.NumUniformBufferDescriptors}, + {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, EngineCI.MainDescriptorPoolSize.NumStorageBufferDescriptors}, + {VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, EngineCI.MainDescriptorPoolSize.NumInputAttachmentDescriptors}, + {VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, EngineCI.MainDescriptorPoolSize.NumAccelStructDescriptors} }, EngineCI.MainDescriptorPoolSize.MaxDescriptorSets, true @@ -117,17 +118,18 @@ RenderDeviceVkImpl::RenderDeviceVkImpl(IReferenceCounters* "Dynamic descriptor pool", std::vector { - {VK_DESCRIPTOR_TYPE_SAMPLER, EngineCI.DynamicDescriptorPoolSize.NumSeparateSamplerDescriptors}, - {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, EngineCI.DynamicDescriptorPoolSize.NumCombinedSamplerDescriptors}, - {VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, EngineCI.DynamicDescriptorPoolSize.NumSampledImageDescriptors}, - {VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, EngineCI.DynamicDescriptorPoolSize.NumStorageImageDescriptors}, - {VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, EngineCI.DynamicDescriptorPoolSize.NumUniformTexelBufferDescriptors}, - {VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, EngineCI.DynamicDescriptorPoolSize.NumStorageTexelBufferDescriptors}, - //{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, EngineCI.DynamicDescriptorPoolSize.NumUniformBufferDescriptors}, - //{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, EngineCI.DynamicDescriptorPoolSize.NumStorageBufferDescriptors}, - {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, EngineCI.DynamicDescriptorPoolSize.NumUniformBufferDescriptors}, - {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, EngineCI.DynamicDescriptorPoolSize.NumStorageBufferDescriptors}, - {VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, EngineCI.MainDescriptorPoolSize.NumInputAttachmentDescriptors}, + {VK_DESCRIPTOR_TYPE_SAMPLER, EngineCI.DynamicDescriptorPoolSize.NumSeparateSamplerDescriptors}, + {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, EngineCI.DynamicDescriptorPoolSize.NumCombinedSamplerDescriptors}, + {VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, EngineCI.DynamicDescriptorPoolSize.NumSampledImageDescriptors}, + {VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, EngineCI.DynamicDescriptorPoolSize.NumStorageImageDescriptors}, + {VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, EngineCI.DynamicDescriptorPoolSize.NumUniformTexelBufferDescriptors}, + {VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, EngineCI.DynamicDescriptorPoolSize.NumStorageTexelBufferDescriptors}, + //{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, EngineCI.DynamicDescriptorPoolSize.NumUniformBufferDescriptors}, + //{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, EngineCI.DynamicDescriptorPoolSize.NumStorageBufferDescriptors}, + {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, EngineCI.DynamicDescriptorPoolSize.NumUniformBufferDescriptors}, + {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, EngineCI.DynamicDescriptorPoolSize.NumStorageBufferDescriptors}, + {VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, EngineCI.MainDescriptorPoolSize.NumInputAttachmentDescriptors}, + {VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, EngineCI.MainDescriptorPoolSize.NumAccelStructDescriptors} }, EngineCI.DynamicDescriptorPoolSize.MaxDescriptorSets, false // Pools can only be reset @@ -160,6 +162,9 @@ RenderDeviceVkImpl::RenderDeviceVkImpl(IReferenceCounters* m_pDxCompiler{CreateDXCompiler(DXCompilerTarget::Vulkan, EngineCI.pDxCompilerPath)} // clang-format on { + static_assert(sizeof(VulkanDescriptorPoolSize) == sizeof(Uint32) * 11, "Please add new descriptors to m_DescriptorSetAllocator and m_DynamicDescriptorPool constructors"); + static_assert(sizeof(DeviceObjectSizes) == sizeof(size_t) * 15, "Please add new objects to DeviceObjectSizes constructor"); + m_DeviceCaps.DevType = RENDER_DEVICE_TYPE_VULKAN; m_DeviceCaps.MajorVersion = 1; m_DeviceCaps.MinorVersion = 0; @@ -573,6 +578,10 @@ void RenderDeviceVkImpl::CreateComputePipelineState(const ComputePipelineStateCr CreatePipelineState(PSOCreateInfo, ppPipelineState); } +void RenderDeviceVkImpl::CreateRayTracingPipelineState(const RayTracingPipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState) +{ + CreatePipelineState(PSOCreateInfo, ppPipelineState); +} void RenderDeviceVkImpl::CreateBufferFromVulkanResource(VkBuffer vkBuffer, const BufferDesc& BuffDesc, RESOURCE_STATE InitialState, IBuffer** ppBuffer) { diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp index caf8ffd2..8a9da14e 100644 --- a/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp +++ b/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp @@ -155,7 +155,7 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl) for (Uint32 res = 0; res < m_TotalResources; ++res) { auto& Res = pResources[res]; - static_assert(SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes == 11, "Please handle the new resource type below"); + static_assert(SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes == 12, "Please handle the new resource type below"); switch (Res.Type) { case SPIRVShaderResourceAttribs::ResourceType::UniformBuffer: @@ -321,6 +321,36 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl) } break; + case SPIRVShaderResourceAttribs::ResourceType::AccelerationStructure: + { + //auto* pTLASVk = Res.pObject.RawPtr(); + //if (pTLASVk != nullptr && pTLASVk->IsInKnownState()) + //{ + // constexpr RESOURCE_STATE RequiredState = RESOURCE_STATE_RAY_TRACING; + // const bool IsInRequiredState = pTLASVk->CheckState(RequiredState); + // if (VerifyOnly) + // { + // if (!IsInRequiredState) + // { + // LOG_ERROR_MESSAGE("State of TLAS '", pTLASVk->GetDesc().Name, "' is incorrect. Required state: ", + // GetResourceStateString(RequiredState), ". Actual state: ", + // GetResourceStateString(pTLASVk->GetState()), + // ". Call IDeviceContext::TransitionShaderResources(), use RESOURCE_STATE_TRANSITION_MODE_TRANSITION " + // "when calling IDeviceContext::CommitShaderResources() or explicitly transition the TLAS state " + // "with IDeviceContext::TransitionResourceStates()."); + // } + // } + // else + // { + // if (!IsInRequiredState) + // { + // pCtxVkImpl->TransitionTLASState(*pTLASVk, RESOURCE_STATE_UNKNOWN, RequiredState, true); + // } + // } + //} + } + break; + default: UNEXPECTED("Unexpected resource type"); } } @@ -497,4 +527,20 @@ VkDescriptorImageInfo ShaderResourceCacheVk::Resource::GetInputAttachmentDescrip return DescrImgInfo; } +VkWriteDescriptorSetAccelerationStructureKHR ShaderResourceCacheVk::Resource::GetAccelerationStructureWriteInfo() const +{ + VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::AccelerationStructure, "Acceleration structure resource is expected"); + DEV_CHECK_ERR(pObject != nullptr, "Unable to get acceleration structure write info: cached object is null"); + + //auto* pTLASVk = pObject.RawPtr(); + + VkWriteDescriptorSetAccelerationStructureKHR DescrAS = {}; + //DescrAS.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR; + //DescrAS.pNext = nullptr; + //DescrAS.accelerationStructureCount = 1; + //DescrAS.pAccelerationStructures = pTLASVk->GetVkTLASPtr(); + + return DescrAS; +} + } // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp index e73ee9aa..16b6bee3 100644 --- a/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp +++ b/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp @@ -93,12 +93,24 @@ static SHADER_RESOURCE_VARIABLE_TYPE FindShaderVariableType(SHADER_TYPE } } -ShaderResourceLayoutVk::ShaderStageInfo::ShaderStageInfo(SHADER_TYPE _Type, - const ShaderVkImpl* _pShader) : - Type{_Type}, - pShader{_pShader}, - SPIRV{pShader->GetSPIRV()} + +ShaderResourceLayoutVk::ShaderStageInfo::ShaderStageInfo(SHADER_TYPE Stage, const ShaderVkImpl* pShader) : + Type{Stage} +{ + Shaders.push_back(pShader); + SPIRVs.push_back(pShader->GetSPIRV()); +} + +void ShaderResourceLayoutVk::ShaderStageInfo::Append(const ShaderVkImpl* pShader) { + Shaders.push_back(pShader); + SPIRVs.push_back(pShader->GetSPIRV()); +} + +size_t ShaderResourceLayoutVk::ShaderStageInfo::Count() const +{ + VERIFY_EXPR(Shaders.size() == SPIRVs.size()); + return Shaders.size(); } @@ -111,38 +123,53 @@ ShaderResourceLayoutVk::~ShaderResourceLayoutVk() GetImmutableSampler(s).~ImmutableSamplerPtrType(); } -void ShaderResourceLayoutVk::AllocateMemory(const ShaderVkImpl* pShader, - IMemoryAllocator& Allocator, - const PipelineResourceLayoutDesc& ResourceLayoutDesc, - const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, - Uint32 NumAllowedTypes, - bool AllocateImmutableSamplers) +void ShaderResourceLayoutVk::AllocateMemory(const std::vector& Shaders, + IMemoryAllocator& Allocator, + const PipelineResourceLayoutDesc& ResourceLayoutDesc, + const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes, + Uint32 NumAllowedTypes, + ResourceNameToIndex_t& UniqueNames, + bool AllocateImmutableSamplers) { VERIFY(!m_ResourceBuffer, "Memory has already been initialized"); - VERIFY_EXPR(!m_pResources); - m_pResources = pShader->GetShaderResources(); + VERIFY_EXPR(Shaders.size() > 0); + VERIFY_EXPR(m_ShaderType == SHADER_TYPE_UNKNOWN); + + size_t StringPoolSize = 0; + m_ShaderType = Shaders[0]->GetDesc().ShaderType; + m_IsUsingSeparateSamplers = !Shaders[0]->GetShaderResources()->IsUsingCombinedSamplers(); + const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes); - const auto ShaderType = pShader->GetDesc().ShaderType; - VERIFY_EXPR(m_pResources->GetShaderType() == ShaderType); // Count the number of resources to allocate all needed memory + for (size_t s = 0; s < Shaders.size(); ++s) { - const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes); - const auto* CombinedSamplerSuffix = m_pResources->GetCombinedSamplerSuffix(); - m_pResources->ProcessResources( + auto pResources = Shaders[s]->GetShaderResources(); + const auto* CombinedSamplerSuffix = pResources->GetCombinedSamplerSuffix(); + VERIFY_EXPR(pResources->GetShaderType() == m_ShaderType); + pResources->ProcessResources( [&](const SPIRVShaderResourceAttribs& ResAttribs, Uint32) // { - auto VarType = FindShaderVariableType(ShaderType, ResAttribs, ResourceLayoutDesc, CombinedSamplerSuffix); + auto VarType = FindShaderVariableType(m_ShaderType, ResAttribs, ResourceLayoutDesc, CombinedSamplerSuffix); if (IsAllowedType(VarType, AllowedTypeBits)) { - // For immutable separate samplers we still allocate VkResource instances, but they are never exposed to the app + bool IsUniqueName = UniqueNames.emplace(HashMapStringKey{ResAttribs.Name}, ~0u).second; + if (IsUniqueName) + { + StringPoolSize += strlen(ResAttribs.Name) + 1; + + // For immutable separate samplers we still allocate VkResource instances, but they are never exposed to the app - VERIFY(Uint32{m_NumResources[VarType]} + 1 <= Uint32{std::numeric_limits::max()}, "Number of resources exceeds Uint16 maximum representable value"); - ++m_NumResources[VarType]; + VERIFY(Uint32{m_NumResources[VarType]} + 1 <= Uint32{std::numeric_limits::max()}, "Number of resources exceeds Uint16 maximum representable value"); + ++m_NumResources[VarType]; + } } } // ); + VERIFY_EXPR(m_IsUsingSeparateSamplers == !pResources->IsUsingCombinedSamplers()); } + m_StringPool.Reserve(StringPoolSize, GetRawAllocator()); + Uint32 TotalResources = 0; for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast(VarType + 1)) { @@ -157,7 +184,7 @@ void ShaderResourceLayoutVk::AllocateMemory(const ShaderVkImpl* for (Uint32 s = 0; s < ResourceLayoutDesc.NumImmutableSamplers; ++s) { const auto& ImtblSamDesc = ResourceLayoutDesc.ImmutableSamplers[s]; - if ((ImtblSamDesc.ShaderStages & ShaderType) != 0) + if ((ImtblSamDesc.ShaderStages & m_ShaderType) != 0) ++m_NumImmutableSamplers; } } @@ -194,8 +221,8 @@ static Uint32 FindAssignedSampler(const ShaderResourceLayoutVk& Layout, for (SamplerInd = 0; SamplerInd < CurrResourceCount; ++SamplerInd) { const auto& Res = Layout.GetResource(ImgVarType, SamplerInd); - if (Res.SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler && - strcmp(Res.SpirvAttribs.Name, SepSampler.Name) == 0) + if (Res.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler && + strcmp(Res.Name, SepSampler.Name) == 0) { VERIFY(ImgVarType == Res.GetVariableType(), "The type (", GetShaderVariableTypeLiteralName(ImgVarType), ") of separate image variable '", SepImg.Name, @@ -217,62 +244,88 @@ static Uint32 FindAssignedSampler(const ShaderResourceLayoutVk& Layout, } -void ShaderResourceLayoutVk::InitializeStaticResourceLayout(const ShaderVkImpl* pShader, - IMemoryAllocator& LayoutDataAllocator, - const PipelineResourceLayoutDesc& ResourceLayoutDesc, - ShaderResourceCacheVk& StaticResourceCache) +void ShaderResourceLayoutVk::InitializeStaticResourceLayout(const std::vector& Shaders, + IMemoryAllocator& LayoutDataAllocator, + const PipelineResourceLayoutDesc& ResourceLayoutDesc, + ShaderResourceCacheVk& StaticResourceCache) { const auto AllowedVarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; // We do not need immutable samplers in static shader resource layout as they // are relevant only when the main layout is initialized - constexpr bool AllocateImmutableSamplers = false; - AllocateMemory(pShader, LayoutDataAllocator, ResourceLayoutDesc, &AllowedVarType, 1, AllocateImmutableSamplers); + ResourceNameToIndex_t ResourceNameToIndex; + constexpr bool AllocateImmutableSamplers = false; + AllocateMemory(Shaders, LayoutDataAllocator, ResourceLayoutDesc, &AllowedVarType, 1, ResourceNameToIndex, AllocateImmutableSamplers); std::array CurrResInd = {}; - Uint32 StaticResCacheSize = 0; + Uint32 StaticResCacheSize = 0; + const Uint32 AllowedTypeBits = GetAllowedTypeBits(&AllowedVarType, 1); - const Uint32 AllowedTypeBits = GetAllowedTypeBits(&AllowedVarType, 1); - const auto* CombinedSamplerSuffix = m_pResources->GetCombinedSamplerSuffix(); - const auto ShaderType = pShader->GetDesc().ShaderType; + for (auto* pShader : Shaders) + { + auto pResources = pShader->GetShaderResources(); + const auto* CombinedSamplerSuffix = pResources->GetCombinedSamplerSuffix(); + pResources->ProcessResources( + [&](const SPIRVShaderResourceAttribs& Attribs, Uint32) // + { + auto VarType = FindShaderVariableType(m_ShaderType, Attribs, ResourceLayoutDesc, CombinedSamplerSuffix); + if (!IsAllowedType(VarType, AllowedTypeBits)) + return; - m_pResources->ProcessResources( - [&](const SPIRVShaderResourceAttribs& Attribs, Uint32) // - { - auto VarType = FindShaderVariableType(ShaderType, Attribs, ResourceLayoutDesc, CombinedSamplerSuffix); - if (!IsAllowedType(VarType, AllowedTypeBits)) - return; + auto ResIter = ResourceNameToIndex.find(HashMapStringKey{Attribs.Name}); + VERIFY_EXPR(ResIter != ResourceNameToIndex.end()); - Int32 SrcImmutableSamplerInd = -1; - if (Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage || - Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler) - { - // Only search for the immutable sampler for combined image samplers and separate samplers - SrcImmutableSamplerInd = FindImmutableSampler(ShaderType, ResourceLayoutDesc, Attribs, CombinedSamplerSuffix); - // For immutable separate samplers we allocate VkResource instances, but they are never exposed to the app - } + if (ResIter->second == ~0u) + { + Int32 SrcImmutableSamplerInd = -1; + if (Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage || + Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler) + { + // Only search for the immutable sampler for combined image samplers and separate samplers + SrcImmutableSamplerInd = FindImmutableSampler(m_ShaderType, ResourceLayoutDesc, Attribs, CombinedSamplerSuffix); + // For immutable separate samplers we allocate VkResource instances, but they are never exposed to the app + } - Uint32 Binding = Attribs.Type; - Uint32 DescriptorSet = 0; - Uint32 CacheOffset = StaticResCacheSize; - StaticResCacheSize += Attribs.ArraySize; + Uint32 Binding = Attribs.Type; + Uint32 DescriptorSet = 0; + Uint32 CacheOffset = StaticResCacheSize; + StaticResCacheSize += Attribs.ArraySize; - Uint32 SamplerInd = VkResource::InvalidSamplerInd; - if (Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage) - { - // Separate samplers are enumerated before separate images, so the sampler - // assigned to this separate image must have already been created. - SamplerInd = FindAssignedSampler(*this, *m_pResources, Attribs, CurrResInd[VarType], VarType); - } - ::new (&GetResource(VarType, CurrResInd[VarType]++)) VkResource(*this, Attribs, VarType, Binding, DescriptorSet, CacheOffset, SamplerInd, SrcImmutableSamplerInd >= 0); - } // - ); + Uint32 SamplerInd = VkResource::InvalidSamplerInd; + if (Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage) + { + // Separate samplers are enumerated before separate images, so the sampler + // assigned to this separate image must have already been created. + SamplerInd = FindAssignedSampler(*this, *pResources, Attribs, CurrResInd[VarType], VarType); + } + + // add new resource + ResIter->second = CurrResInd[VarType]; + ::new (&GetResource(VarType, CurrResInd[VarType]++)) VkResource(*this, m_StringPool.CopyString(Attribs.Name), Attribs.ArraySize, + Attribs.Type, Attribs.ResourceDim, Attribs.IsMS, VarType, + Binding, DescriptorSet, CacheOffset, SamplerInd, SrcImmutableSamplerInd >= 0); + } + else + { + // merge with existing + auto& ExistingRes = GetResource(VarType, ResIter->second); + VERIFY_EXPR(ExistingRes.VariableType == VarType); + VERIFY_EXPR(ExistingRes.Type == Attribs.Type); + VERIFY_EXPR(ExistingRes.ResourceDim == Attribs.ResourceDim); + VERIFY_EXPR(ExistingRes.IsMS == Attribs.IsMS); + VERIFY_EXPR(ExistingRes.ArraySize == Attribs.ArraySize); + } + } // + ); + } #ifdef DILIGENT_DEBUG for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast(VarType + 1)) { VERIFY(CurrResInd[VarType] == m_NumResources[VarType], "Not all resources have been initialized, which will cause a crash when dtor is called"); } + + VERIFY_EXPR(m_StringPool.GetRemainingSize() == 0); #endif StaticResourceCache.InitializeSets(GetRawAllocator(), 1, &StaticResCacheSize); @@ -296,14 +349,15 @@ void ShaderResourceLayoutVk::dvpVerifyResourceLayoutDesc(const TShaderStages& const auto ShaderType = Stages & static_cast(~(static_cast(Stages) - 1)); const char* ShaderName = nullptr; - for (const auto& StageInfo : ShaderStages) + // AZ TODO + /*for (const auto& StageInfo : ShaderStages) { if ((Stages & StageInfo.Type) != 0) { ShaderName = StageInfo.pShader->GetDesc().Name; break; } - } + }*/ if (!ShadersStr.empty()) ShadersStr.append(", "); @@ -340,13 +394,17 @@ void ShaderResourceLayoutVk::dvpVerifyResourceLayoutDesc(const TShaderStages& bool VariableFound = false; for (size_t s = 0; s < ShaderStages.size() && !VariableFound; ++s) { - const auto& Resources = *ShaderStages[s].pShader->GetShaderResources(); - if ((VarDesc.ShaderStages & Resources.GetShaderType()) != 0) + auto& Shaders = ShaderStages[s].Shaders; + for (size_t i = 0; i < Shaders.size() && !VariableFound; ++i) { - for (Uint32 res = 0; res < Resources.GetTotalResources() && !VariableFound; ++res) + const auto& Resources = *Shaders[i]->GetShaderResources(); + if ((VarDesc.ShaderStages & Resources.GetShaderType()) != 0) { - const auto& ResAttribs = Resources.GetResource(res); - VariableFound = (strcmp(ResAttribs.Name, VarDesc.Name) == 0); + for (Uint32 res = 0; res < Resources.GetTotalResources() && !VariableFound; ++res) + { + const auto& ResAttribs = Resources.GetResource(res); + VariableFound = (strcmp(ResAttribs.Name, VarDesc.Name) == 0); + } } } } @@ -373,28 +431,32 @@ void ShaderResourceLayoutVk::dvpVerifyResourceLayoutDesc(const TShaderStages& bool SamplerFound = false; for (size_t s = 0; s < ShaderStages.size() && !SamplerFound; ++s) { - const auto& Resources = *ShaderStages[s].pShader->GetShaderResources(); - if ((ImtblSamDesc.ShaderStages & Resources.GetShaderType()) == 0) - continue; - - // Irrespective of whether HLSL-style combined image samplers are used, - // an immutable sampler can be assigned to a GLSL sampled image (i.e. sampler2D g_tex) - for (Uint32 i = 0; i < Resources.GetNumSmpldImgs() && !SamplerFound; ++i) + auto& Shaders = ShaderStages[s].Shaders; + for (size_t j = 0; j < Shaders.size() && !SamplerFound; ++j) { - const auto& SmplImg = Resources.GetSmpldImg(i); - SamplerFound = (strcmp(SmplImg.Name, ImtblSamDesc.SamplerOrTextureName) == 0); - } + const auto& Resources = *Shaders[j]->GetShaderResources(); + if ((ImtblSamDesc.ShaderStages & Resources.GetShaderType()) == 0) + continue; - if (!SamplerFound) - { - // Check if an immutable sampler is assigned to a separate sampler. - // In case HLSL-style combined image samplers are used, the condition is SepSmpl.Name == "g_Texture" + "_sampler". - // Otherwise the condition is SepSmpl.Name == "g_Texture_sampler" + "". - const auto* CombinedSamplerSuffix = Resources.GetCombinedSamplerSuffix(); - for (Uint32 i = 0; i < Resources.GetNumSepSmplrs() && !SamplerFound; ++i) + // Irrespective of whether HLSL-style combined image samplers are used, + // a static sampler can be assigned to GLSL sampled image (i.e. sampler2D g_tex) + for (Uint32 i = 0; i < Resources.GetNumSmpldImgs() && !SamplerFound; ++i) + { + const auto& SmplImg = Resources.GetSmpldImg(i); + SamplerFound = (strcmp(SmplImg.Name, ImtblSamDesc.SamplerOrTextureName) == 0); + } + + if (!SamplerFound) { - const auto& SepSmpl = Resources.GetSepSmplr(i); - SamplerFound = StreqSuff(SepSmpl.Name, ImtblSamDesc.SamplerOrTextureName, CombinedSamplerSuffix); + // Check if static sampler is assigned to a separate sampler. + // In case HLSL-style combined image samplers are used, the condition is SepSmpl.Name == "g_Texture" + "_sampler". + // Otherwise the condition is SepSmpl.Name == "g_Texture_sampler" + "". + const auto* CombinedSamplerSuffix = Resources.GetCombinedSamplerSuffix(); + for (Uint32 i = 0; i < Resources.GetNumSepSmplrs() && !SamplerFound; ++i) + { + const auto& SepSmpl = Resources.GetSepSmplr(i); + SamplerFound = StreqSuff(SepSmpl.Name, ImtblSamDesc.SamplerOrTextureName, CombinedSamplerSuffix); + } } } } @@ -423,15 +485,16 @@ void ShaderResourceLayoutVk::Initialize(IRenderDevice* pRende dvpVerifyResourceLayoutDesc(ShaderStages, ResourceLayoutDesc, VerifyVariables, VerifyImmutableSamplers); #endif - const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes = nullptr; - const Uint32 NumAllowedTypes = 0; - const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes); - constexpr bool AllocateImmutableSamplers = true; + std::array ResourceNameToIndexArray; + const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes = nullptr; + const Uint32 NumAllowedTypes = 0; + const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes); + constexpr bool AllocateImmutableSamplers = true; for (size_t s = 0; s < ShaderStages.size(); ++s) { - Layouts[s].AllocateMemory(ShaderStages[s].pShader, LayoutDataAllocator, ResourceLayoutDesc, - AllowedVarTypes, NumAllowedTypes, AllocateImmutableSamplers); + Layouts[s].AllocateMemory(ShaderStages[s].Shaders, LayoutDataAllocator, ResourceLayoutDesc, + AllowedVarTypes, NumAllowedTypes, ResourceNameToIndexArray[s], AllocateImmutableSamplers); } //VERIFY_EXPR(NumShaders <= MAX_SHADERS_IN_PIPELINE); @@ -444,74 +507,107 @@ void ShaderResourceLayoutVk::Initialize(IRenderDevice* pRende auto AddResource = [&](Uint32 ShaderInd, ShaderResourceLayoutVk& ResLayout, const SPIRVShaderResources& Resources, - const SPIRVShaderResourceAttribs& Attribs) // + const SPIRVShaderResourceAttribs& Attribs, + ResourceNameToIndex_t& ResourceNameToIndex, + std::vector& SPIRV) // { const auto ShaderType = Resources.GetShaderType(); const SHADER_RESOURCE_VARIABLE_TYPE VarType = FindShaderVariableType(ShaderType, Attribs, ResourceLayoutDesc, Resources.GetCombinedSamplerSuffix()); if (!IsAllowedType(VarType, AllowedTypeBits)) return; - Uint32 Binding = 0; - Uint32 DescriptorSet = 0; - Uint32 CacheOffset = 0; - Uint32 SamplerInd = VkResource::InvalidSamplerInd; + auto ResIter = ResourceNameToIndex.find(HashMapStringKey{Attribs.Name}); + VERIFY_EXPR(ResIter != ResourceNameToIndex.end()); - if (Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage) + if (ResIter->second == ~0u) { - // Separate samplers are enumerated before separate images, so the sampler - // assigned to this separate image must have already been created. - SamplerInd = FindAssignedSampler(ResLayout, Resources, Attribs, CurrResInd[ShaderInd][VarType], VarType); - } + // add new resource + Uint32 Binding = 0; + Uint32 DescriptorSet = 0; + Uint32 CacheOffset = 0; + Uint32 SamplerInd = VkResource::InvalidSamplerInd; - VkSampler vkImmutableSampler = VK_NULL_HANDLE; - if (Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage || - Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler) - { - // Only search for the immutable sampler for combined image samplers and separate samplers - Int32 SrcImmutableSamplerInd = FindImmutableSampler(ShaderType, ResourceLayoutDesc, Attribs, Resources.GetCombinedSamplerSuffix()); - if (SrcImmutableSamplerInd >= 0) + if (Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage) { - auto& ImmutableSampler = ResLayout.GetImmutableSampler(CurrImmutableSamplerInd[ShaderInd]++); - VERIFY(!ImmutableSampler, "Immutable sampler has already been initialized!"); - const auto& ImmutableSamplerDesc = ResourceLayoutDesc.ImmutableSamplers[SrcImmutableSamplerInd].Desc; - pRenderDevice->CreateSampler(ImmutableSamplerDesc, &ImmutableSampler); - vkImmutableSampler = ImmutableSampler.RawPtr()->GetVkSampler(); + // Separate samplers are enumerated before separate images, so the sampler + // assigned to this separate image must have already been created. + SamplerInd = FindAssignedSampler(ResLayout, Resources, Attribs, CurrResInd[ShaderInd][VarType], VarType); } - } - auto& ShaderSPIRV = ShaderStages[ShaderInd].SPIRV; - PipelineLayout.AllocateResourceSlot(Attribs, VarType, vkImmutableSampler, Resources.GetShaderType(), DescriptorSet, Binding, CacheOffset, ShaderSPIRV); - VERIFY(DescriptorSet <= std::numeric_limits::max(), "Descriptor set (", DescriptorSet, ") excceeds maximum representable value"); - VERIFY(Binding <= std::numeric_limits::max(), "Binding (", Binding, ") excceeds maximum representable value"); + VkSampler vkImmutableSampler = VK_NULL_HANDLE; + if (Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage || + Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler) + { + // Only search for the immutable sampler for combined image samplers and separate samplers + Int32 SrcImmutableSamplerInd = FindImmutableSampler(ShaderType, ResourceLayoutDesc, Attribs, Resources.GetCombinedSamplerSuffix()); + if (SrcImmutableSamplerInd >= 0) + { + auto& ImmutableSampler = ResLayout.GetImmutableSampler(CurrImmutableSamplerInd[ShaderInd]++); + VERIFY(!ImmutableSampler, "Immutable sampler has already been initialized!"); + const auto& ImmutableSamplerDesc = ResourceLayoutDesc.ImmutableSamplers[SrcImmutableSamplerInd].Desc; + pRenderDevice->CreateSampler(ImmutableSamplerDesc, &ImmutableSampler); + vkImmutableSampler = ImmutableSampler.RawPtr()->GetVkSampler(); + } + } + + PipelineLayout.AllocateResourceSlot(Attribs, VarType, vkImmutableSampler, Resources.GetShaderType(), DescriptorSet, Binding, CacheOffset); + VERIFY(DescriptorSet <= std::numeric_limits::max(), "Descriptor set (", DescriptorSet, ") excceeds maximum representable value"); + VERIFY(Binding <= std::numeric_limits::max(), "Binding (", Binding, ") excceeds maximum representable value"); + + SPIRV[Attribs.BindingDecorationOffset] = Binding; + SPIRV[Attribs.DescriptorSetDecorationOffset] = DescriptorSet; #ifdef DILIGENT_DEBUG - // Verify that bindings and cache offsets monotonically increase in every descriptor set - auto Binding_OffsetIt = dbgBindings_CacheOffsets.find(DescriptorSet); - if (Binding_OffsetIt != dbgBindings_CacheOffsets.end()) - { - VERIFY(Binding > Binding_OffsetIt->second.first, "Binding for descriptor set ", DescriptorSet, " is not strictly monotonic"); - VERIFY(CacheOffset > Binding_OffsetIt->second.second, "Cache offset for descriptor set ", DescriptorSet, " is not strictly monotonic"); - } - dbgBindings_CacheOffsets[DescriptorSet] = std::make_pair(Binding, CacheOffset); + // Verify that bindings and cache offsets monotonically increase in every descriptor set + auto Binding_OffsetIt = dbgBindings_CacheOffsets.find(DescriptorSet); + if (Binding_OffsetIt != dbgBindings_CacheOffsets.end()) + { + VERIFY(Binding > Binding_OffsetIt->second.first, "Binding for descriptor set ", DescriptorSet, " is not strictly monotonic"); + VERIFY(CacheOffset > Binding_OffsetIt->second.second, "Cache offset for descriptor set ", DescriptorSet, " is not strictly monotonic"); + } + dbgBindings_CacheOffsets[DescriptorSet] = std::make_pair(Binding, CacheOffset); #endif - auto& ResInd = CurrResInd[ShaderInd][VarType]; - ::new (&ResLayout.GetResource(VarType, ResInd++)) VkResource(ResLayout, Attribs, VarType, Binding, DescriptorSet, CacheOffset, SamplerInd, vkImmutableSampler != VK_NULL_HANDLE ? 1 : 0); + auto& ResInd = CurrResInd[ShaderInd][VarType]; + ResIter->second = ResInd; + ::new (&ResLayout.GetResource(VarType, ResInd++)) VkResource(ResLayout, ResLayout.m_StringPool.CopyString(Attribs.Name), Attribs.ArraySize, + Attribs.Type, Attribs.ResourceDim, Attribs.IsMS, VarType, + Binding, DescriptorSet, CacheOffset, SamplerInd, vkImmutableSampler != VK_NULL_HANDLE ? 1 : 0); + } + else + { + // merge with existing + auto& ExistingRes = ResLayout.GetResource(VarType, ResIter->second); + + VERIFY_EXPR(ExistingRes.VariableType == VarType); + VERIFY_EXPR(ExistingRes.Type == Attribs.Type); + VERIFY_EXPR(ExistingRes.ResourceDim == Attribs.ResourceDim); + VERIFY_EXPR(ExistingRes.IsMS == Attribs.IsMS); + VERIFY_EXPR(ExistingRes.ArraySize == Attribs.ArraySize); + + SPIRV[Attribs.BindingDecorationOffset] = ExistingRes.Binding; + SPIRV[Attribs.DescriptorSetDecorationOffset] = ExistingRes.DescriptorSet; + } }; // First process uniform buffers for all shader stages to make sure all UBs go first in every descriptor set for (size_t s = 0; s < ShaderStages.size(); ++s) { + auto& Shaders = ShaderStages[s].Shaders; auto& Layout = Layouts[s]; - auto* pShaderVk = ShaderStages[s].pShader; - auto& Resources = *pShaderVk->GetShaderResources(); - for (Uint32 n = 0; n < Resources.GetNumUBs(); ++n) + auto& NameToIdx = ResourceNameToIndexArray[s]; + for (size_t i = 0; i < Shaders.size(); ++i) { - const auto& UB = Resources.GetUB(n); - auto VarType = GetShaderVariableType(Resources.GetShaderType(), UB.Name, ResourceLayoutDesc); - if (IsAllowedType(VarType, AllowedTypeBits)) + auto& SPIRV = ShaderStages[s].SPIRVs[i]; + auto& Resources = *Shaders[i]->GetShaderResources(); + for (Uint32 n = 0; n < Resources.GetNumUBs(); ++n) { - AddResource(static_cast(s), Layout, Resources, UB); + const auto& UB = Resources.GetUB(n); + auto VarType = GetShaderVariableType(Resources.GetShaderType(), UB.Name, ResourceLayoutDesc); + if (IsAllowedType(VarType, AllowedTypeBits)) + { + AddResource(static_cast(s), Layout, Resources, UB, NameToIdx, SPIRV); + } } } } @@ -519,15 +615,21 @@ void ShaderResourceLayoutVk::Initialize(IRenderDevice* pRende // Second, process all storage buffers for (size_t s = 0; s < ShaderStages.size(); ++s) { + auto& Shaders = ShaderStages[s].Shaders; auto& Layout = Layouts[s]; - auto& Resources = *ShaderStages[s].pShader->GetShaderResources(); - for (Uint32 n = 0; n < Resources.GetNumSBs(); ++n) + auto& NameToIdx = ResourceNameToIndexArray[s]; + for (size_t i = 0; i < Shaders.size(); ++i) { - const auto& SB = Resources.GetSB(n); - auto VarType = GetShaderVariableType(Resources.GetShaderType(), SB.Name, ResourceLayoutDesc); - if (IsAllowedType(VarType, AllowedTypeBits)) + auto& Resources = *Shaders[i]->GetShaderResources(); + auto& SPIRV = ShaderStages[s].SPIRVs[i]; + for (Uint32 n = 0; n < Resources.GetNumSBs(); ++n) { - AddResource(static_cast(s), Layout, Resources, SB); + const auto& SB = Resources.GetSB(n); + auto VarType = GetShaderVariableType(Resources.GetShaderType(), SB.Name, ResourceLayoutDesc); + if (IsAllowedType(VarType, AllowedTypeBits)) + { + AddResource(static_cast(s), Layout, Resources, SB, NameToIdx, SPIRV); + } } } } @@ -536,51 +638,62 @@ void ShaderResourceLayoutVk::Initialize(IRenderDevice* pRende for (size_t s = 0; s < ShaderStages.size(); ++s) { auto& Layout = Layouts[s]; - auto& Resources = *ShaderStages[s].pShader->GetShaderResources(); - // clang-format off - Resources.ProcessResources( - [&](const SPIRVShaderResourceAttribs& UB, Uint32) - { - VERIFY_EXPR(UB.Type == SPIRVShaderResourceAttribs::ResourceType::UniformBuffer); - // Skip - }, - [&](const SPIRVShaderResourceAttribs& SB, Uint32) - { - VERIFY_EXPR(SB.Type == SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer || SB.Type == SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer); - // Skip - }, - [&](const SPIRVShaderResourceAttribs& Img, Uint32) - { - VERIFY_EXPR(Img.Type == SPIRVShaderResourceAttribs::ResourceType::StorageImage || Img.Type == SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer); - AddResource(static_cast(s), Layout, Resources, Img); - }, - [&](const SPIRVShaderResourceAttribs& SmplImg, Uint32) - { - VERIFY_EXPR(SmplImg.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage || SmplImg.Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer); - AddResource(static_cast(s), Layout, Resources, SmplImg); - }, - [&](const SPIRVShaderResourceAttribs& AC, Uint32) - { - VERIFY_EXPR(AC.Type == SPIRVShaderResourceAttribs::ResourceType::AtomicCounter); - AddResource(static_cast(s), Layout, Resources, AC); - }, - [&](const SPIRVShaderResourceAttribs& SepSmpl, Uint32) - { - VERIFY_EXPR(SepSmpl.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler); - AddResource(static_cast(s), Layout, Resources, SepSmpl); - }, - [&](const SPIRVShaderResourceAttribs& SepImg, Uint32) - { - VERIFY_EXPR(SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage || SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer); - AddResource(static_cast(s), Layout, Resources, SepImg); - }, - [&](const SPIRVShaderResourceAttribs& InputAtt, Uint32) - { - VERIFY_EXPR(InputAtt.Type == SPIRVShaderResourceAttribs::ResourceType::InputAttachment); - AddResource(static_cast(s), Layout, Resources, InputAtt); - } - ); - // clang-format on + auto& Shaders = ShaderStages[s].Shaders; + auto& NameToIdx = ResourceNameToIndexArray[s]; + for (size_t i = 0; i < Shaders.size(); ++i) + { + auto& Resources = *Shaders[i]->GetShaderResources(); + auto& SPIRV = ShaderStages[s].SPIRVs[i]; + // clang-format off + Resources.ProcessResources( + [&](const SPIRVShaderResourceAttribs& UB, Uint32) + { + VERIFY_EXPR(UB.Type == SPIRVShaderResourceAttribs::ResourceType::UniformBuffer); + // Skip + }, + [&](const SPIRVShaderResourceAttribs& SB, Uint32) + { + VERIFY_EXPR(SB.Type == SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer || SB.Type == SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer); + // Skip + }, + [&](const SPIRVShaderResourceAttribs& Img, Uint32) + { + VERIFY_EXPR(Img.Type == SPIRVShaderResourceAttribs::ResourceType::StorageImage || Img.Type == SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer); + AddResource(static_cast(s), Layout, Resources, Img, NameToIdx, SPIRV); + }, + [&](const SPIRVShaderResourceAttribs& SmplImg, Uint32) + { + VERIFY_EXPR(SmplImg.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage || SmplImg.Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer); + AddResource(static_cast(s), Layout, Resources, SmplImg, NameToIdx, SPIRV); + }, + [&](const SPIRVShaderResourceAttribs& AC, Uint32) + { + VERIFY_EXPR(AC.Type == SPIRVShaderResourceAttribs::ResourceType::AtomicCounter); + AddResource(static_cast(s), Layout, Resources, AC, NameToIdx, SPIRV); + }, + [&](const SPIRVShaderResourceAttribs& SepSmpl, Uint32) + { + VERIFY_EXPR(SepSmpl.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler); + AddResource(static_cast(s), Layout, Resources, SepSmpl, NameToIdx, SPIRV); + }, + [&](const SPIRVShaderResourceAttribs& SepImg, Uint32) + { + VERIFY_EXPR(SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage || SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer); + AddResource(static_cast(s), Layout, Resources, SepImg, NameToIdx, SPIRV); + }, + [&](const SPIRVShaderResourceAttribs& InputAtt, Uint32) + { + VERIFY_EXPR(InputAtt.Type == SPIRVShaderResourceAttribs::ResourceType::InputAttachment); + AddResource(static_cast(s), Layout, Resources, InputAtt, NameToIdx, SPIRV); + }, + [&](const SPIRVShaderResourceAttribs& AccelStruct, Uint32) + { + VERIFY_EXPR(AccelStruct.Type == SPIRVShaderResourceAttribs::ResourceType::AccelerationStructure); + AddResource(static_cast(s), Layout, Resources, AccelStruct, NameToIdx, SPIRV); + } + ); + // clang-format on + } } #ifdef DILIGENT_DEBUG @@ -593,28 +706,32 @@ void ShaderResourceLayoutVk::Initialize(IRenderDevice* pRende } // Some immutable samplers may never be initialized if they are not present in shaders VERIFY_EXPR(CurrImmutableSamplerInd[s] <= Layout.m_NumImmutableSamplers); + + VERIFY_EXPR(Layout.m_StringPool.GetRemainingSize() == 0); } #endif } -void ShaderResourceLayoutVk::VkResource::UpdateDescriptorHandle(VkDescriptorSet vkDescrSet, - uint32_t ArrayElement, - const VkDescriptorImageInfo* pImageInfo, - const VkDescriptorBufferInfo* pBufferInfo, - const VkBufferView* pTexelBufferView) const + +void ShaderResourceLayoutVk::VkResource::UpdateDescriptorHandle(VkDescriptorSet vkDescrSet, + uint32_t ArrayElement, + const VkDescriptorImageInfo* pImageInfo, + const VkDescriptorBufferInfo* pBufferInfo, + const VkBufferView* pTexelBufferView, + const VkWriteDescriptorSetAccelerationStructureKHR* pAccelStructInfo) const { VERIFY_EXPR(vkDescrSet != VK_NULL_HANDLE); VkWriteDescriptorSet WriteDescrSet; WriteDescrSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - WriteDescrSet.pNext = nullptr; + WriteDescrSet.pNext = pAccelStructInfo; WriteDescrSet.dstSet = vkDescrSet; WriteDescrSet.dstBinding = Binding; WriteDescrSet.dstArrayElement = ArrayElement; WriteDescrSet.descriptorCount = 1; // descriptorType must be the same type as that specified in VkDescriptorSetLayoutBinding for dstSet at dstBinding. // The type of the descriptor also controls which array the descriptors are taken from. (13.2.4) - WriteDescrSet.descriptorType = PipelineLayout::GetVkDescriptorType(SpirvAttribs); + WriteDescrSet.descriptorType = PipelineLayout::GetVkDescriptorType(Type); WriteDescrSet.pImageInfo = pImageInfo; WriteDescrSet.pBufferInfo = pBufferInfo; WriteDescrSet.pTexelBufferView = pTexelBufferView; @@ -654,10 +771,10 @@ void ShaderResourceLayoutVk::VkResource::CacheUniformBuffer(IDeviceObject* Uint32 ArrayInd, Uint16& DynamicBuffersCounter) const { - VERIFY(SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::UniformBuffer, "Uniform buffer resource is expected"); + VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::UniformBuffer, "Uniform buffer resource is expected"); RefCntAutoPtr pBufferVk{pBuffer, IID_BufferVk}; #ifdef DILIGENT_DEVELOPMENT - VerifyConstantBufferBinding(SpirvAttribs, GetVariableType(), ArrayInd, pBuffer, pBufferVk.RawPtr(), DstRes.pObject.RawPtr(), ParentResLayout.GetShaderName()); + VerifyConstantBufferBinding(*this, GetVariableType(), ArrayInd, pBuffer, pBufferVk.RawPtr(), DstRes.pObject.RawPtr(), ParentResLayout.GetShaderName()); #endif auto UpdateDynamicBuffersCounter = [&DynamicBuffersCounter](const BufferVkImpl* pOldBuffer, const BufferVkImpl* pNewBuffer) { @@ -691,8 +808,8 @@ void ShaderResourceLayoutVk::VkResource::CacheStorageBuffer(IDeviceObject* Uint16& DynamicBuffersCounter) const { // clang-format off - VERIFY(SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer || - SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer, + VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer || + Type == SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer, "Storage buffer resource is expected"); // clang-format on @@ -700,8 +817,8 @@ void ShaderResourceLayoutVk::VkResource::CacheStorageBuffer(IDeviceObject* #ifdef DILIGENT_DEVELOPMENT { // HLSL buffer SRVs are mapped to storge buffers in GLSL - auto RequiredViewType = SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer ? BUFFER_VIEW_SHADER_RESOURCE : BUFFER_VIEW_UNORDERED_ACCESS; - VerifyResourceViewBinding(SpirvAttribs, GetVariableType(), ArrayInd, pBufferView, pBufferViewVk.RawPtr(), {RequiredViewType}, DstRes.pObject.RawPtr(), ParentResLayout.GetShaderName()); + auto RequiredViewType = Type == SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer ? BUFFER_VIEW_SHADER_RESOURCE : BUFFER_VIEW_UNORDERED_ACCESS; + VerifyResourceViewBinding(*this, GetVariableType(), ArrayInd, pBufferView, pBufferViewVk.RawPtr(), {RequiredViewType}, DstRes.pObject.RawPtr(), ParentResLayout.GetShaderName()); if (pBufferViewVk != nullptr) { const auto& ViewDesc = pBufferViewVk->GetDesc(); @@ -709,7 +826,7 @@ void ShaderResourceLayoutVk::VkResource::CacheStorageBuffer(IDeviceObject* if (BuffDesc.Mode != BUFFER_MODE_STRUCTURED && BuffDesc.Mode != BUFFER_MODE_RAW) { LOG_ERROR_MESSAGE("Error binding buffer view '", ViewDesc.Name, "' of buffer '", BuffDesc.Name, "' to shader variable '", - SpirvAttribs.Name, "' in shader '", ParentResLayout.GetShaderName(), "': structured buffer view is expected."); + Name, "' in shader '", ParentResLayout.GetShaderName(), "': structured buffer view is expected."); } } } @@ -747,8 +864,8 @@ void ShaderResourceLayoutVk::VkResource::CacheTexelBuffer(IDeviceObject* Uint16& DynamicBuffersCounter) const { // clang-format off - VERIFY(SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer || - SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer, + VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer || + Type == SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer, "Uniform or storage buffer resource is expected"); // clang-format on @@ -756,8 +873,8 @@ void ShaderResourceLayoutVk::VkResource::CacheTexelBuffer(IDeviceObject* #ifdef DILIGENT_DEVELOPMENT { // HLSL buffer SRVs are mapped to storge buffers in GLSL - auto RequiredViewType = SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer ? BUFFER_VIEW_UNORDERED_ACCESS : BUFFER_VIEW_SHADER_RESOURCE; - VerifyResourceViewBinding(SpirvAttribs, GetVariableType(), ArrayInd, pBufferView, pBufferViewVk.RawPtr(), {RequiredViewType}, DstRes.pObject.RawPtr(), ParentResLayout.GetShaderName()); + auto RequiredViewType = Type == SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer ? BUFFER_VIEW_UNORDERED_ACCESS : BUFFER_VIEW_SHADER_RESOURCE; + VerifyResourceViewBinding(*this, GetVariableType(), ArrayInd, pBufferView, pBufferViewVk.RawPtr(), {RequiredViewType}, DstRes.pObject.RawPtr(), ParentResLayout.GetShaderName()); if (pBufferViewVk != nullptr) { const auto& ViewDesc = pBufferViewVk->GetDesc(); @@ -765,7 +882,7 @@ void ShaderResourceLayoutVk::VkResource::CacheTexelBuffer(IDeviceObject* if (!((BuffDesc.Mode == BUFFER_MODE_FORMATTED && ViewDesc.Format.ValueType != VT_UNDEFINED) || BuffDesc.Mode == BUFFER_MODE_RAW)) { LOG_ERROR_MESSAGE("Error binding buffer view '", ViewDesc.Name, "' of buffer '", BuffDesc.Name, "' to shader variable '", - SpirvAttribs.Name, "' in shader '", ParentResLayout.GetShaderName(), "': formatted buffer view is expected."); + Name, "' in shader '", ParentResLayout.GetShaderName(), "': formatted buffer view is expected."); } } } @@ -805,9 +922,9 @@ void ShaderResourceLayoutVk::VkResource::CacheImage(IDeviceObject* TCacheSampler CacheSampler) const { // clang-format off - VERIFY(SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::StorageImage || - SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage || - SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage, + VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::StorageImage || + Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage || + Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage, "Storage image, separate image or sampled image resource is expected"); // clang-format on @@ -815,8 +932,8 @@ void ShaderResourceLayoutVk::VkResource::CacheImage(IDeviceObject* #ifdef DILIGENT_DEVELOPMENT { // HLSL buffer SRVs are mapped to storge buffers in GLSL - auto RequiredViewType = SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::StorageImage ? TEXTURE_VIEW_UNORDERED_ACCESS : TEXTURE_VIEW_SHADER_RESOURCE; - VerifyResourceViewBinding(SpirvAttribs, GetVariableType(), ArrayInd, pTexView, pTexViewVk0.RawPtr(), {RequiredViewType}, DstRes.pObject.RawPtr(), ParentResLayout.GetShaderName()); + auto RequiredViewType = Type == SPIRVShaderResourceAttribs::ResourceType::StorageImage ? TEXTURE_VIEW_UNORDERED_ACCESS : TEXTURE_VIEW_SHADER_RESOURCE; + VerifyResourceViewBinding(*this, GetVariableType(), ArrayInd, pTexView, pTexViewVk0.RawPtr(), {RequiredViewType}, DstRes.pObject.RawPtr(), ParentResLayout.GetShaderName()); } #endif if (UpdateCachedResource(DstRes, std::move(pTexViewVk0), [](const TextureViewVkImpl*, const TextureViewVkImpl*) {})) @@ -824,11 +941,11 @@ void ShaderResourceLayoutVk::VkResource::CacheImage(IDeviceObject* // We can do RawPtr here safely since UpdateCachedResource() returned true auto* pTexViewVk = DstRes.pObject.RawPtr(); #ifdef DILIGENT_DEVELOPMENT - if (SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage && !IsImmutableSamplerAssigned()) + if (Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage && !IsImmutableSamplerAssigned()) { if (pTexViewVk->GetSampler() == nullptr) { - LOG_ERROR_MESSAGE("Error binding texture view '", pTexViewVk->GetDesc().Name, "' to variable '", SpirvAttribs.GetPrintName(ArrayInd), + LOG_ERROR_MESSAGE("Error binding texture view '", pTexViewVk->GetDesc().Name, "' to variable '", GetPrintName(ArrayInd), "' in shader '", ParentResLayout.GetShaderName(), "'. No sampler is assigned to the view"); } } @@ -844,11 +961,11 @@ void ShaderResourceLayoutVk::VkResource::CacheImage(IDeviceObject* if (SamplerInd != InvalidSamplerInd) { - VERIFY(SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage, + VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage, "Only separate images can be assigned separate samplers when using HLSL-style combined samplers."); VERIFY(!IsImmutableSamplerAssigned(), "Separate image can't be assigned an immutable sampler."); const auto& SamplerAttribs = ParentResLayout.GetResource(GetVariableType(), SamplerInd); - VERIFY_EXPR(SamplerAttribs.SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler); + VERIFY_EXPR(SamplerAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler); if (!SamplerAttribs.IsImmutableSamplerAssigned()) { auto* pSampler = pTexViewVk->GetSampler(); @@ -858,8 +975,8 @@ void ShaderResourceLayoutVk::VkResource::CacheImage(IDeviceObject* } else { - LOG_ERROR_MESSAGE("Failed to bind sampler to sampler variable '", SamplerAttribs.SpirvAttribs.Name, - "' assigned to separate image '", SpirvAttribs.GetPrintName(ArrayInd), "' in shader '", + LOG_ERROR_MESSAGE("Failed to bind sampler to sampler variable '", SamplerAttribs.Name, + "' assigned to separate image '", GetPrintName(ArrayInd), "' in shader '", ParentResLayout.GetShaderName(), "': no sampler is set in texture view '", pTexViewVk->GetDesc().Name, '\''); } } @@ -872,20 +989,20 @@ void ShaderResourceLayoutVk::VkResource::CacheSeparateSampler(IDeviceObject* VkDescriptorSet vkDescrSet, Uint32 ArrayInd) const { - VERIFY(SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler, "Separate sampler resource is expected"); + VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler, "Separate sampler resource is expected"); VERIFY(!IsImmutableSamplerAssigned(), "This separate sampler is assigned an immutable sampler"); RefCntAutoPtr pSamplerVk{pSampler, IID_Sampler}; #ifdef DILIGENT_DEVELOPMENT if (pSampler != nullptr && pSamplerVk == nullptr) { - LOG_ERROR_MESSAGE("Failed to bind object '", pSampler->GetDesc().Name, "' to variable '", SpirvAttribs.GetPrintName(ArrayInd), + LOG_ERROR_MESSAGE("Failed to bind object '", pSampler->GetDesc().Name, "' to variable '", GetPrintName(ArrayInd), "' in shader '", ParentResLayout.GetShaderName(), "'. Unexpected object type: sampler is expected"); } if (GetVariableType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC && DstRes.pObject != nullptr && DstRes.pObject != pSamplerVk) { auto VarTypeStr = GetShaderVariableTypeLiteralName(GetVariableType()); - LOG_ERROR_MESSAGE("Non-null sampler is already bound to ", VarTypeStr, " shader variable '", SpirvAttribs.GetPrintName(ArrayInd), + LOG_ERROR_MESSAGE("Non-null sampler is already bound to ", VarTypeStr, " shader variable '", GetPrintName(ArrayInd), "' in shader '", ParentResLayout.GetShaderName(), "'. Attempting to bind another sampler or null is an error and may " "cause unpredicted behavior. Use another shader resource binding instance or label the variable as dynamic."); @@ -908,10 +1025,10 @@ void ShaderResourceLayoutVk::VkResource::CacheInputAttachment(IDeviceObject* VkDescriptorSet vkDescrSet, Uint32 ArrayInd) const { - VERIFY(SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::InputAttachment, "Input attachment resource is expected"); + VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::InputAttachment, "Input attachment resource is expected"); RefCntAutoPtr pTexViewVk0{pTexView, IID_TextureViewVk}; #ifdef DILIGENT_DEVELOPMENT - VerifyResourceViewBinding(SpirvAttribs, GetVariableType(), ArrayInd, pTexView, pTexViewVk0.RawPtr(), {TEXTURE_VIEW_SHADER_RESOURCE}, DstRes.pObject.RawPtr(), ParentResLayout.GetShaderName()); + VerifyResourceViewBinding(*this, GetVariableType(), ArrayInd, pTexView, pTexViewVk0.RawPtr(), {TEXTURE_VIEW_SHADER_RESOURCE}, DstRes.pObject.RawPtr(), ParentResLayout.GetShaderName()); #endif if (UpdateCachedResource(DstRes, std::move(pTexViewVk0), [](const TextureViewVkImpl*, const TextureViewVkImpl*) {})) { @@ -926,9 +1043,32 @@ void ShaderResourceLayoutVk::VkResource::CacheInputAttachment(IDeviceObject* } } +void ShaderResourceLayoutVk::VkResource::CacheAccelerationStructure(IDeviceObject* pTLAS, + ShaderResourceCacheVk::Resource& DstRes, + VkDescriptorSet vkDescrSet, + Uint32 ArrayInd) const +{ + // VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::AccelerationStructure, "Acceleration Structure resource is expected"); + // RefCntAutoPtr pTLASVk{pTLAS, IID_TopLevelASVk}; + //#ifdef DILIGENT_DEVELOPMENT + // // AZ TODO + //#endif + // if (UpdateCachedResource(DstRes, std::move(pTLASVk), [](const TopLevelASVkImpl*, const TopLevelASVkImpl*) {})) + // { + // // Do not update descriptor for a dynamic TLAS. All dynamic resource descriptors + // // are updated at once by CommitDynamicResources() when SRB is committed. + // if (vkDescrSet != VK_NULL_HANDLE && GetVariableType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC) + // { + // VkWriteDescriptorSetAccelerationStructureKHR DescrASInfo = DstRes.GetAccelerationStructureWriteInfo(); + // UpdateDescriptorHandle(vkDescrSet, ArrayInd, nullptr, nullptr, nullptr, &DescrASInfo); + // } + // // + // } +} + void ShaderResourceLayoutVk::VkResource::BindResource(IDeviceObject* pObj, Uint32 ArrayIndex, ShaderResourceCacheVk& ResourceCache) const { - VERIFY_EXPR(ArrayIndex < SpirvAttribs.ArraySize); + VERIFY_EXPR(ArrayIndex < ArraySize); auto& DstDescrSet = ResourceCache.GetDescriptorSet(DescriptorSet); auto vkDescrSet = DstDescrSet.GetVkDescriptorSet(); @@ -951,12 +1091,12 @@ void ShaderResourceLayoutVk::VkResource::BindResource(IDeviceObject* pObj, Uint3 } #endif auto& DstRes = DstDescrSet.GetResource(CacheOffset + ArrayIndex); - VERIFY(DstRes.Type == SpirvAttribs.Type, "Inconsistent types"); + VERIFY(DstRes.Type == Type, "Inconsistent types"); if (pObj) { - static_assert(SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes == 11, "Please handle the new resource type below"); - switch (SpirvAttribs.Type) + static_assert(SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes == 12, "Please handle the new resource type below"); + switch (Type) { case SPIRVShaderResourceAttribs::ResourceType::UniformBuffer: CacheUniformBuffer(pObj, DstRes, vkDescrSet, ArrayIndex, ResourceCache.GetDynamicBuffersCounter()); @@ -977,15 +1117,15 @@ void ShaderResourceLayoutVk::VkResource::BindResource(IDeviceObject* pObj, Uint3 case SPIRVShaderResourceAttribs::ResourceType::SampledImage: CacheImage(pObj, DstRes, vkDescrSet, ArrayIndex, [&](const VkResource& SeparateSampler, ISampler* pSampler) { - VERIFY(!SeparateSampler.IsImmutableSamplerAssigned(), "Separate sampler '", SeparateSampler.SpirvAttribs.Name, "' is assigned an immutable sampler"); - VERIFY_EXPR(SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage); - DEV_CHECK_ERR(SeparateSampler.SpirvAttribs.ArraySize == 1 || SeparateSampler.SpirvAttribs.ArraySize == SpirvAttribs.ArraySize, - "Array size (", SeparateSampler.SpirvAttribs.ArraySize, + VERIFY(!SeparateSampler.IsImmutableSamplerAssigned(), "Separate sampler '", SeparateSampler.Name, "' is assigned an immutable sampler"); + VERIFY_EXPR(Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage); + DEV_CHECK_ERR(SeparateSampler.ArraySize == 1 || SeparateSampler.ArraySize == ArraySize, + "Array size (", SeparateSampler.ArraySize, ") of separate sampler variable '", - SeparateSampler.SpirvAttribs.Name, - "' must be one or the same as the array size (", SpirvAttribs.ArraySize, - ") of separate image variable '", SpirvAttribs.Name, "' it is assigned to"); - Uint32 SamplerArrInd = SeparateSampler.SpirvAttribs.ArraySize == 1 ? 0 : ArrayIndex; + SeparateSampler.Name, + "' must be one or the same as the array size (", ArraySize, + ") of separate image variable '", Name, "' it is assigned to"); + Uint32 SamplerArrInd = SeparateSampler.ArraySize == 1 ? 0 : ArrayIndex; SeparateSampler.BindResource(pSampler, SamplerArrInd, ResourceCache); }); break; @@ -999,7 +1139,7 @@ void ShaderResourceLayoutVk::VkResource::BindResource(IDeviceObject* pObj, Uint3 { // Immutable samplers are permanently bound into the set layout; later binding a sampler // into an immutable sampler slot in a descriptor set is not allowed (13.2.1) - LOG_ERROR_MESSAGE("Attempting to assign a sampler to an immutable sampler '", SpirvAttribs.Name, '\''); + LOG_ERROR_MESSAGE("Attempting to assign a sampler to an immutable sampler '", Name, '\''); } break; @@ -1007,14 +1147,18 @@ void ShaderResourceLayoutVk::VkResource::BindResource(IDeviceObject* pObj, Uint3 CacheInputAttachment(pObj, DstRes, vkDescrSet, ArrayIndex); break; - default: UNEXPECTED("Unknown resource type ", static_cast(SpirvAttribs.Type)); + case SPIRVShaderResourceAttribs::ResourceType::AccelerationStructure: + CacheAccelerationStructure(pObj, DstRes, vkDescrSet, ArrayIndex); + break; + + default: UNEXPECTED("Unknown resource type ", static_cast(Type)); } } else { if (DstRes.pObject && GetVariableType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC) { - LOG_ERROR_MESSAGE("Shader variable '", SpirvAttribs.Name, "' in shader '", ParentResLayout.GetShaderName(), + LOG_ERROR_MESSAGE("Shader variable '", Name, "' in shader '", ParentResLayout.GetShaderName(), "' is not dynamic but being unbound. This is an error and may cause unpredicted behavior. " "Use another shader resource binding instance or label shader variable as dynamic if you need to bind another resource."); } @@ -1025,7 +1169,7 @@ void ShaderResourceLayoutVk::VkResource::BindResource(IDeviceObject* pObj, Uint3 bool ShaderResourceLayoutVk::VkResource::IsBound(Uint32 ArrayIndex, const ShaderResourceCacheVk& ResourceCache) const { - VERIFY_EXPR(ArrayIndex < SpirvAttribs.ArraySize); + VERIFY_EXPR(ArrayIndex < ArraySize); if (DescriptorSet < ResourceCache.GetNumDescriptorSets()) { @@ -1040,6 +1184,72 @@ bool ShaderResourceLayoutVk::VkResource::IsBound(Uint32 ArrayIndex, const Shader return false; } +ShaderResourceDesc ShaderResourceLayoutVk::VkResource::GetResourceDesc() const +{ + ShaderResourceDesc ResourceDesc; + ResourceDesc.Name = Name; + ResourceDesc.ArraySize = ArraySize; + + static_assert(SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes == 12, "Please handle the new resource type below"); + switch (Type) + { + case SPIRVShaderResourceAttribs::ResourceType::UniformBuffer: + ResourceDesc.Type = SHADER_RESOURCE_TYPE_CONSTANT_BUFFER; + break; + + case SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer: + // Read-only storage buffers map to buffer SRV + // https://github.com/KhronosGroup/SPIRV-Cross/wiki/Reflection-API-user-guide#read-write-vs-read-only-resources-for-hlsl + ResourceDesc.Type = SHADER_RESOURCE_TYPE_BUFFER_SRV; + break; + + case SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer: + ResourceDesc.Type = SHADER_RESOURCE_TYPE_BUFFER_UAV; + break; + + case SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer: + ResourceDesc.Type = SHADER_RESOURCE_TYPE_BUFFER_SRV; + break; + + case SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer: + ResourceDesc.Type = SHADER_RESOURCE_TYPE_BUFFER_UAV; + break; + + case SPIRVShaderResourceAttribs::ResourceType::StorageImage: + ResourceDesc.Type = SHADER_RESOURCE_TYPE_TEXTURE_UAV; + break; + + case SPIRVShaderResourceAttribs::ResourceType::SampledImage: + ResourceDesc.Type = SHADER_RESOURCE_TYPE_TEXTURE_SRV; + break; + + case SPIRVShaderResourceAttribs::ResourceType::AtomicCounter: + LOG_WARNING_MESSAGE("There is no appropriate shader resource type for atomic counter resource '", Name, "'"); + ResourceDesc.Type = SHADER_RESOURCE_TYPE_BUFFER_UAV; + break; + + case SPIRVShaderResourceAttribs::ResourceType::SeparateImage: + ResourceDesc.Type = SHADER_RESOURCE_TYPE_TEXTURE_SRV; + break; + + case SPIRVShaderResourceAttribs::ResourceType::SeparateSampler: + ResourceDesc.Type = SHADER_RESOURCE_TYPE_SAMPLER; + break; + + case SPIRVShaderResourceAttribs::ResourceType::InputAttachment: + ResourceDesc.Type = SHADER_RESOURCE_TYPE_INPUT_ATTACHMENT; + break; + + case SPIRVShaderResourceAttribs::ResourceType::AccelerationStructure: + ResourceDesc.Type = SHADER_RESOURCE_TYPE_ACCEL_STRUCT; + break; + + default: + UNEXPECTED("Unknown SPIRV resource type"); + } + return ResourceDesc; +} + void ShaderResourceLayoutVk::InitializeStaticResources(const ShaderResourceLayoutVk& SrcLayout, const ShaderResourceCacheVk& SrcResourceCache, @@ -1055,21 +1265,21 @@ void ShaderResourceLayoutVk::InitializeStaticResources(const ShaderResourceLayou // Get resource attributes const auto& DstRes = GetResource(SHADER_RESOURCE_VARIABLE_TYPE_STATIC, r); const auto& SrcRes = SrcLayout.GetResource(SHADER_RESOURCE_VARIABLE_TYPE_STATIC, r); - VERIFY(SrcRes.Binding == SrcRes.SpirvAttribs.Type, "Unexpected binding"); - VERIFY(SrcRes.SpirvAttribs.ArraySize == DstRes.SpirvAttribs.ArraySize, "Inconsistent array size"); + VERIFY(SrcRes.Binding == SrcRes.Type, "Unexpected binding"); + VERIFY(SrcRes.ArraySize == DstRes.ArraySize, "Inconsistent array size"); - if (DstRes.SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler && + if (DstRes.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler && DstRes.IsImmutableSamplerAssigned()) continue; // Skip immutable samplers - for (Uint32 ArrInd = 0; ArrInd < DstRes.SpirvAttribs.ArraySize; ++ArrInd) + for (Uint32 ArrInd = 0; ArrInd < DstRes.ArraySize; ++ArrInd) { auto SrcOffset = SrcRes.CacheOffset + ArrInd; const auto& SrcCachedSet = SrcResourceCache.GetDescriptorSet(SrcRes.DescriptorSet); const auto& SrcCachedRes = SrcCachedSet.GetResource(SrcOffset); IDeviceObject* pObject = SrcCachedRes.pObject.RawPtr(); if (!pObject) - LOG_ERROR_MESSAGE("No resource is assigned to static shader variable '", SrcRes.SpirvAttribs.GetPrintName(ArrInd), "' in shader '", GetShaderName(), "'."); + LOG_ERROR_MESSAGE("No resource is assigned to static shader variable '", SrcRes.GetPrintName(ArrInd), "' in shader '", GetShaderName(), "'."); auto DstOffset = DstRes.CacheOffset + ArrInd; IDeviceObject* pCachedResource = DstResourceCache.GetDescriptorSet(DstRes.DescriptorSet).GetResource(DstOffset).pObject; @@ -1093,15 +1303,15 @@ bool ShaderResourceLayoutVk::dvpVerifyBindings(const ShaderResourceCacheVk& Reso { const auto& Res = GetResource(VarType, r); VERIFY(Res.GetVariableType() == VarType, "Unexpected variable type"); - for (Uint32 ArrInd = 0; ArrInd < Res.SpirvAttribs.ArraySize; ++ArrInd) + for (Uint32 ArrInd = 0; ArrInd < Res.ArraySize; ++ArrInd) { const auto& CachedDescrSet = ResourceCache.GetDescriptorSet(Res.DescriptorSet); const auto& CachedRes = CachedDescrSet.GetResource(Res.CacheOffset + ArrInd); - VERIFY(CachedRes.Type == Res.SpirvAttribs.Type, "Inconsistent types"); + VERIFY(CachedRes.Type == Res.Type, "Inconsistent types"); if (CachedRes.pObject == nullptr && - !(Res.SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler && Res.IsImmutableSamplerAssigned())) + !(Res.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler && Res.IsImmutableSamplerAssigned())) { - LOG_ERROR_MESSAGE("No resource is bound to ", GetShaderVariableTypeLiteralName(Res.GetVariableType()), " variable '", Res.SpirvAttribs.GetPrintName(ArrInd), "' in shader '", GetShaderName(), "'"); + LOG_ERROR_MESSAGE("No resource is bound to ", GetShaderVariableTypeLiteralName(Res.GetVariableType()), " variable '", Res.GetPrintName(ArrInd), "' in shader '", GetShaderName(), "'"); BindingsOK = false; } # ifdef DILIGENT_DEBUG @@ -1136,7 +1346,7 @@ void ShaderResourceLayoutVk::InitializeResourceMemoryInCache(ShaderResourceCache for (Uint32 r = 0; r < TotalResources; ++r) { const auto& Res = GetResource(r); - ResourceCache.InitializeResources(Res.DescriptorSet, Res.CacheOffset, Res.SpirvAttribs.ArraySize, Res.SpirvAttribs.Type); + ResourceCache.InitializeResources(Res.DescriptorSet, Res.CacheOffset, Res.ArraySize, Res.Type); } } @@ -1151,24 +1361,28 @@ void ShaderResourceLayoutVk::CommitDynamicResources(const ShaderResourceCacheVk& static constexpr size_t ImgUpdateBatchSize = 4; static constexpr size_t BuffUpdateBatchSize = 2; static constexpr size_t TexelBuffUpdateBatchSize = 2; + static constexpr size_t AccelStructBatchSize = 2; static constexpr size_t WriteDescriptorSetBatchSize = 2; #else static constexpr size_t ImgUpdateBatchSize = 128; static constexpr size_t BuffUpdateBatchSize = 64; static constexpr size_t TexelBuffUpdateBatchSize = 32; + static constexpr size_t AccelStructBatchSize = 32; static constexpr size_t WriteDescriptorSetBatchSize = 32; #endif // Do not zero-initiaize arrays! - std::array DescrImgInfoArr; - std::array DescrBuffInfoArr; - std::array DescrBuffViewArr; - std::array WriteDescrSetArr; + std::array DescrImgInfoArr; + std::array DescrBuffInfoArr; + std::array DescrBuffViewArr; + std::array DescrAccelStructArr; + std::array WriteDescrSetArr; Uint32 ResNum = 0, ArrElem = 0; auto DescrImgIt = DescrImgInfoArr.begin(); auto DescrBuffIt = DescrBuffInfoArr.begin(); auto BuffViewIt = DescrBuffViewArr.begin(); + auto AccelStructIt = DescrAccelStructArr.begin(); auto WriteDescrSetIt = WriteDescrSetArr.begin(); #ifdef DILIGENT_DEBUG @@ -1195,14 +1409,15 @@ void ShaderResourceLayoutVk::CommitDynamicResources(const ShaderResourceCacheVk& WriteDescrSetIt->dstArrayElement = ArrElem; // descriptorType must be the same type as that specified in VkDescriptorSetLayoutBinding for dstSet at dstBinding. // The type of the descriptor also controls which array the descriptors are taken from. (13.2.4) - WriteDescrSetIt->descriptorType = PipelineLayout::GetVkDescriptorType(Res.SpirvAttribs); + WriteDescrSetIt->descriptorType = PipelineLayout::GetVkDescriptorType(Res.Type); // For every resource type, try to batch as many descriptor updates as we can - switch (Res.SpirvAttribs.Type) + static_assert(SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes == 12, "Please handle the new resource type below"); + switch (Res.Type) { case SPIRVShaderResourceAttribs::ResourceType::UniformBuffer: WriteDescrSetIt->pBufferInfo = &(*DescrBuffIt); - while (ArrElem < Res.SpirvAttribs.ArraySize && DescrBuffIt != DescrBuffInfoArr.end()) + while (ArrElem < Res.ArraySize && DescrBuffIt != DescrBuffInfoArr.end()) { const auto& CachedRes = SetResources.GetResource(Res.CacheOffset + ArrElem); *DescrBuffIt = CachedRes.GetUniformBufferDescriptorWriteInfo(); @@ -1214,7 +1429,7 @@ void ShaderResourceLayoutVk::CommitDynamicResources(const ShaderResourceCacheVk& case SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer: case SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer: WriteDescrSetIt->pBufferInfo = &(*DescrBuffIt); - while (ArrElem < Res.SpirvAttribs.ArraySize && DescrBuffIt != DescrBuffInfoArr.end()) + while (ArrElem < Res.ArraySize && DescrBuffIt != DescrBuffInfoArr.end()) { const auto& CachedRes = SetResources.GetResource(Res.CacheOffset + ArrElem); *DescrBuffIt = CachedRes.GetStorageBufferDescriptorWriteInfo(); @@ -1226,7 +1441,7 @@ void ShaderResourceLayoutVk::CommitDynamicResources(const ShaderResourceCacheVk& case SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer: case SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer: WriteDescrSetIt->pTexelBufferView = &(*BuffViewIt); - while (ArrElem < Res.SpirvAttribs.ArraySize && BuffViewIt != DescrBuffViewArr.end()) + while (ArrElem < Res.ArraySize && BuffViewIt != DescrBuffViewArr.end()) { const auto& CachedRes = SetResources.GetResource(Res.CacheOffset + ArrElem); *BuffViewIt = CachedRes.GetBufferViewWriteInfo(); @@ -1239,7 +1454,7 @@ void ShaderResourceLayoutVk::CommitDynamicResources(const ShaderResourceCacheVk& case SPIRVShaderResourceAttribs::ResourceType::StorageImage: case SPIRVShaderResourceAttribs::ResourceType::SampledImage: WriteDescrSetIt->pImageInfo = &(*DescrImgIt); - while (ArrElem < Res.SpirvAttribs.ArraySize && DescrImgIt != DescrImgInfoArr.end()) + while (ArrElem < Res.ArraySize && DescrImgIt != DescrImgInfoArr.end()) { const auto& CachedRes = SetResources.GetResource(Res.CacheOffset + ArrElem); *DescrImgIt = CachedRes.GetImageDescriptorWriteInfo(Res.IsImmutableSamplerAssigned()); @@ -1259,7 +1474,7 @@ void ShaderResourceLayoutVk::CommitDynamicResources(const ShaderResourceCacheVk& if (!Res.IsImmutableSamplerAssigned()) { WriteDescrSetIt->pImageInfo = &(*DescrImgIt); - while (ArrElem < Res.SpirvAttribs.ArraySize && DescrImgIt != DescrImgInfoArr.end()) + while (ArrElem < Res.ArraySize && DescrImgIt != DescrImgInfoArr.end()) { const auto& CachedRes = SetResources.GetResource(Res.CacheOffset + ArrElem); *DescrImgIt = CachedRes.GetSamplerDescriptorWriteInfo(); @@ -1269,8 +1484,19 @@ void ShaderResourceLayoutVk::CommitDynamicResources(const ShaderResourceCacheVk& } else { - ArrElem = Res.SpirvAttribs.ArraySize; - WriteDescrSetIt->dstArrayElement = Res.SpirvAttribs.ArraySize; + ArrElem = Res.ArraySize; + WriteDescrSetIt->dstArrayElement = Res.ArraySize; + } + break; + + case SPIRVShaderResourceAttribs::ResourceType::AccelerationStructure: + WriteDescrSetIt->pNext = &(*AccelStructIt); + while (ArrElem < Res.ArraySize && AccelStructIt != DescrAccelStructArr.end()) + { + const auto& CachedRes = SetResources.GetResource(Res.CacheOffset + ArrElem); + *AccelStructIt = CachedRes.GetAccelerationStructureWriteInfo(); + ++AccelStructIt; + ++ArrElem; } break; @@ -1279,7 +1505,7 @@ void ShaderResourceLayoutVk::CommitDynamicResources(const ShaderResourceCacheVk& } WriteDescrSetIt->descriptorCount = ArrElem - WriteDescrSetIt->dstArrayElement; - if (ArrElem == Res.SpirvAttribs.ArraySize) + if (ArrElem == Res.ArraySize) { ArrElem = 0; ++ResNum; @@ -1294,6 +1520,7 @@ void ShaderResourceLayoutVk::CommitDynamicResources(const ShaderResourceCacheVk& DescrImgIt == DescrImgInfoArr.end() || DescrBuffIt == DescrBuffInfoArr.end() || BuffViewIt == DescrBuffViewArr.end() || + AccelStructIt == DescrAccelStructArr.end() || WriteDescrSetIt == WriteDescrSetArr.end()) { auto DescrWriteCount = static_cast(std::distance(WriteDescrSetArr.begin(), WriteDescrSetIt)); @@ -1303,6 +1530,7 @@ void ShaderResourceLayoutVk::CommitDynamicResources(const ShaderResourceCacheVk& DescrImgIt = DescrImgInfoArr.begin(); DescrBuffIt = DescrBuffInfoArr.begin(); BuffViewIt = DescrBuffViewArr.begin(); + AccelStructIt = DescrAccelStructArr.begin(); WriteDescrSetIt = WriteDescrSetArr.begin(); } } diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderVariableVk.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderVariableVk.cpp index 7e06bd69..062a5725 100644 --- a/Graphics/GraphicsEngineVulkan/src/ShaderVariableVk.cpp +++ b/Graphics/GraphicsEngineVulkan/src/ShaderVariableVk.cpp @@ -52,7 +52,7 @@ size_t ShaderVariableManagerVk::GetRequiredMemorySize(const ShaderResourceLayout // When using HLSL-style combined image samplers, we need to skip separate samplers. // Also always skip immutable separate samplers. - if (SrcRes.SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler && + if (SrcRes.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler && (!UsingSeparateSamplers || SrcRes.IsImmutableSamplerAssigned())) continue; @@ -96,7 +96,7 @@ void ShaderVariableManagerVk::Initialize(const ShaderResourceLayoutVk& Sr { const auto& SrcRes = SrcLayout.GetResource(VarType, r); // Skip separate samplers when using combined HLSL-style image samplers. Also always skip immutable separate samplers. - if (SrcRes.SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler && + if (SrcRes.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler && (!UsingSeparateSamplers || SrcRes.IsImmutableSamplerAssigned())) continue; @@ -132,7 +132,7 @@ ShaderVariableVkImpl* ShaderVariableManagerVk::GetVariable(const Char* Name) con { auto& Var = m_pVariables[v]; const auto& Res = Var.m_Resource; - if (strcmp(Res.SpirvAttribs.Name, Name) == 0) + if (strcmp(Res.Name, Name) == 0) { pVar = &Var; break; @@ -190,18 +190,18 @@ void ShaderVariableManagerVk::BindResources(IResourceMapping* pResourceMapping, const auto& Res = Var.m_Resource; // There should be no immutable separate samplers - VERIFY(Res.SpirvAttribs.Type != SPIRVShaderResourceAttribs::ResourceType::SeparateSampler || !Res.IsImmutableSamplerAssigned(), + VERIFY(Res.Type != SPIRVShaderResourceAttribs::ResourceType::SeparateSampler || !Res.IsImmutableSamplerAssigned(), "There must be no shader resource variables for immutable separate samplers"); if ((Flags & (1 << Res.GetVariableType())) == 0) continue; - for (Uint32 ArrInd = 0; ArrInd < Res.SpirvAttribs.ArraySize; ++ArrInd) + for (Uint32 ArrInd = 0; ArrInd < Res.ArraySize; ++ArrInd) { if ((Flags & BIND_SHADER_RESOURCES_KEEP_EXISTING) && Res.IsBound(ArrInd, m_ResourceCache)) continue; - const auto* VarName = Res.SpirvAttribs.Name; + const auto* VarName = Res.Name; RefCntAutoPtr pObj; pResourceMapping->GetResource(VarName, &pObj, ArrInd); if (pObj) @@ -212,7 +212,7 @@ void ShaderVariableManagerVk::BindResources(IResourceMapping* pResourceMapping, { if ((Flags & BIND_SHADER_RESOURCES_VERIFY_ALL_RESOLVED) && !Res.IsBound(ArrInd, m_ResourceCache)) { - LOG_ERROR_MESSAGE("Unable to bind resource to shader variable '", Res.SpirvAttribs.GetPrintName(ArrInd), + LOG_ERROR_MESSAGE("Unable to bind resource to shader variable '", Res.GetPrintName(ArrInd), "': resource is not found in the resource mapping. " "Do not use BIND_SHADER_RESOURCES_VERIFY_ALL_RESOLVED flag to suppress the message if this is not an issue."); } diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp index 65505ad3..66393e9b 100644 --- a/Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp @@ -122,9 +122,17 @@ ShaderVkImpl::ShaderVkImpl(IReferenceCounters* pRefCounters, SourceLength = GLSLSourceString.length(); } + GLSLangUtils::SpirvVersion spvVersion = GLSLangUtils::SpirvVersion::Vk100; + const auto& ExtFeats = GetDevice()->GetLogicalDevice().GetEnabledExtFeatures(); + if (ExtFeats.Spirv15) + spvVersion = GLSLangUtils::SpirvVersion::Vk120; + else if (ExtFeats.Spirv14) + spvVersion = GLSLangUtils::SpirvVersion::Vk110_Spirv14; + m_SPIRV = GLSLangUtils::GLSLtoSPIRV(m_Desc.ShaderType, ShaderSource, static_cast(SourceLength), Macros, ShaderCI.pShaderSourceStreamFactory, + spvVersion, ShaderCI.ppCompilerOutput); } #endif diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanInstance.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanInstance.cpp index a03102d0..825bf872 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanInstance.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanInstance.cpp @@ -73,16 +73,18 @@ bool VulkanInstance::IsExtensionEnabled(const char* ExtensionName) const return false; } -std::shared_ptr VulkanInstance::Create(bool EnableValidation, +std::shared_ptr VulkanInstance::Create(uint32_t ApiVersion, + bool EnableValidation, uint32_t GlobalExtensionCount, const char* const* ppGlobalExtensionNames, VkAllocationCallbacks* pVkAllocator) { - auto Instance = new VulkanInstance{EnableValidation, GlobalExtensionCount, ppGlobalExtensionNames, pVkAllocator}; + auto Instance = new VulkanInstance{ApiVersion, EnableValidation, GlobalExtensionCount, ppGlobalExtensionNames, pVkAllocator}; return std::shared_ptr{Instance}; } -VulkanInstance::VulkanInstance(bool EnableValidation, +VulkanInstance::VulkanInstance(uint32_t ApiVersion, + bool EnableValidation, uint32_t GlobalExtensionCount, const char* const* ppGlobalExtensionNames, VkAllocationCallbacks* pVkAllocator) : @@ -184,6 +186,16 @@ VulkanInstance::VulkanInstance(bool EnableValidation, } } +#if DILIGENT_USE_VOLK + if (vkEnumerateInstanceVersion != nullptr && ApiVersion > VK_API_VERSION_1_0) + { + uint32_t MaxApiVersion = 0; + vkEnumerateInstanceVersion(&MaxApiVersion); + ApiVersion = std::min(ApiVersion, MaxApiVersion); + LOG_INFO_MESSAGE("Used Vulkan API version ", VK_VERSION_MAJOR(ApiVersion), ".", VK_VERSION_MINOR(ApiVersion)); + } +#endif + VkApplicationInfo appInfo = {}; appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; @@ -192,7 +204,7 @@ VulkanInstance::VulkanInstance(bool EnableValidation, appInfo.applicationVersion = 0; // Developer-supplied version number of the application appInfo.pEngineName = "Diligent Engine"; appInfo.engineVersion = 0; // Developer-supplied version number of the engine used to create the application. - appInfo.apiVersion = VK_API_VERSION_1_0; + appInfo.apiVersion = ApiVersion; VkInstanceCreateInfo InstanceCreateInfo = {}; @@ -229,6 +241,7 @@ VulkanInstance::VulkanInstance(bool EnableValidation, #endif m_EnabledExtensions = std::move(GlobalExtensions); + m_VkVersion = ApiVersion; // If requested, we enable the default validation layers for debugging if (m_DebugUtilsEnabled) diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanLogicalDevice.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanLogicalDevice.cpp index f9e190d8..358bdec5 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanLogicalDevice.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanLogicalDevice.cpp @@ -36,9 +36,10 @@ namespace VulkanUtilities std::shared_ptr VulkanLogicalDevice::Create(const VulkanPhysicalDevice& PhysicalDevice, const VkDeviceCreateInfo& DeviceCI, + const ExtensionFeatures& EnabledExtFeatures, const VkAllocationCallbacks* vkAllocator) { - auto* LogicalDevice = new VulkanLogicalDevice{PhysicalDevice, DeviceCI, vkAllocator}; + auto* LogicalDevice = new VulkanLogicalDevice{PhysicalDevice, DeviceCI, EnabledExtFeatures, vkAllocator}; return std::shared_ptr{LogicalDevice}; } @@ -49,9 +50,11 @@ VulkanLogicalDevice::~VulkanLogicalDevice() VulkanLogicalDevice::VulkanLogicalDevice(const VulkanPhysicalDevice& PhysicalDevice, const VkDeviceCreateInfo& DeviceCI, + const ExtensionFeatures& EnabledExtFeatures, const VkAllocationCallbacks* vkAllocator) : m_VkAllocator{vkAllocator}, - m_EnabledFeatures{*DeviceCI.pEnabledFeatures} + m_EnabledFeatures{*DeviceCI.pEnabledFeatures}, + m_EnabledExtFeatures{EnabledExtFeatures} { auto res = vkCreateDevice(PhysicalDevice.GetVkDeviceHandle(), &DeviceCI, vkAllocator, &m_VkDevice); CHECK_VK_ERROR_AND_THROW(res, "Failed to create logical device"); @@ -225,6 +228,29 @@ PipelineWrapper VulkanLogicalDevice::CreateGraphicsPipeline(const VkGraphicsPipe return PipelineWrapper{GetSharedPtr(), std::move(vkPipeline)}; } +PipelineWrapper VulkanLogicalDevice::CreateRayTracingPipeline(const VkRayTracingPipelineCreateInfoKHR& PipelineCI, VkPipelineCache cache, const char* DebugName) const +{ +#if DILIGENT_USE_VOLK + VERIFY_EXPR(PipelineCI.sType == VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR); + + if (DebugName == nullptr) + DebugName = ""; + + VkPipeline vkPipeline = VK_NULL_HANDLE; + + auto err = vkCreateRayTracingPipelinesKHR(m_VkDevice, cache, 1, &PipelineCI, m_VkAllocator, &vkPipeline); + CHECK_VK_ERROR_AND_THROW(err, "Failed to create ray tracing pipeline '", DebugName, '\''); + + if (*DebugName != 0) + SetPipelineName(m_VkDevice, vkPipeline, DebugName); + + return PipelineWrapper{GetSharedPtr(), std::move(vkPipeline)}; +#else + UNSUPPORTED("vkCreateRayTracingPipelinesKHR is only available through Volk"); + return PipelineWrapper{}; +#endif +} + ShaderModuleWrapper VulkanLogicalDevice::CreateShaderModule(const VkShaderModuleCreateInfo& ShaderModuleCI, const char* DebugName) const { VERIFY_EXPR(ShaderModuleCI.sType == VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO); @@ -455,6 +481,7 @@ VkMemoryRequirements VulkanLogicalDevice::GetImageMemoryRequirements(VkImage vkI VkMemoryRequirements VulkanLogicalDevice::GetASMemoryRequirements(const VkAccelerationStructureMemoryRequirementsInfoKHR& Info) const { VkMemoryRequirements2 MemReqs = {}; + MemReqs.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2; #if DILIGENT_USE_VOLK vkGetAccelerationStructureMemoryRequirementsKHR(m_VkDevice, &Info, &MemReqs); #else @@ -571,4 +598,14 @@ VkResult VulkanLogicalDevice::ResetDescriptorPool(VkDescriptorPool vkD return err; } +VkResult VulkanLogicalDevice::GetRayTracingShaderGroupHandles(VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void* pData) const +{ +#if DILIGENT_USE_VOLK + return vkGetRayTracingShaderGroupHandlesKHR(m_VkDevice, pipeline, firstGroup, groupCount, dataSize, pData); +#else + UNSUPPORTED("vkGetRayTracingShaderGroupHandlesKHR is only available through Volk"); + return VK_ERROR_FEATURE_NOT_PRESENT; +#endif +} + } // namespace VulkanUtilities diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp index 3e5f28d4..b66ac8af 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp @@ -166,6 +166,17 @@ VulkanPhysicalDevice::VulkanPhysicalDevice(VkPhysicalDevice vkDevice, m_ExtProperties.DescriptorIndexing.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES_EXT; } + // Additional extension that is required for ray tracing shader. + if (IsExtensionSupported(VK_KHR_SPIRV_1_4_EXTENSION_NAME)) + m_ExtFeatures.Spirv14 = true; + + // Some features requires SPIRV 1.4 or 1.5 that added to Vulkan 1.2 core. + if (Instance.GetVkVersion() >= VK_API_VERSION_1_2) + { + m_ExtFeatures.Spirv14 = true; + m_ExtFeatures.Spirv15 = true; + } + // make sure that last pNext is null *NextFeat = nullptr; *NextProp = nullptr; @@ -178,7 +189,6 @@ VulkanPhysicalDevice::VulkanPhysicalDevice(VkPhysicalDevice vkDevice, // Emulate KHR extension if (m_ExtFeatures.RayTracingNV) { - //m_ExtFeatures.RayTracing.sType //m_ExtFeatures.RayTracing.rayTracingPrimitiveCulling = true; // AZ TODO m_ExtFeatures.RayTracing.rayTracing = VK_TRUE; @@ -188,7 +198,7 @@ VulkanPhysicalDevice::VulkanPhysicalDevice(VkPhysicalDevice vkDevice, m_ExtProperties.RayTracing.shaderGroupBaseAlignment = RayTracingNV.shaderGroupBaseAlignment; m_ExtProperties.RayTracing.maxGeometryCount = RayTracingNV.maxGeometryCount; m_ExtProperties.RayTracing.maxInstanceCount = RayTracingNV.maxInstanceCount; - m_ExtProperties.RayTracing.maxPrimitiveCount = RayTracingNV.maxTriangleCount; + m_ExtProperties.RayTracing.maxPrimitiveCount = RayTracingNV.maxTriangleCount / 3; m_ExtProperties.RayTracing.maxDescriptorSetAccelerationStructures = RayTracingNV.maxDescriptorSetAccelerationStructures; m_ExtProperties.RayTracing.shaderGroupHandleCaptureReplaySize = 0; } -- cgit v1.2.3