From 0fcb4700020a59f70bd31fbb1de2220e2a2306a3 Mon Sep 17 00:00:00 2001 From: Egor Yusov Date: Wed, 2 May 2018 23:34:03 -0700 Subject: Working on pipeline layout initialization in Vulkan --- Graphics/GraphicsEngineVulkan/CMakeLists.txt | 4 +- .../GraphicsEngineVulkan/include/PipelineLayout.h | 486 ++++++++ .../include/PipelineStateVkImpl.h | 2 +- .../GraphicsEngineVulkan/include/RootSignature.h | 433 ------- .../GraphicsEngineVulkan/src/PipelineLayout.cpp | 1241 ++++++++++++++++++++ .../src/PipelineStateVkImpl.cpp | 26 +- .../GraphicsEngineVulkan/src/RootSignature.cpp | 1033 ---------------- 7 files changed, 1732 insertions(+), 1493 deletions(-) create mode 100644 Graphics/GraphicsEngineVulkan/include/PipelineLayout.h delete mode 100644 Graphics/GraphicsEngineVulkan/include/RootSignature.h create mode 100644 Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp delete mode 100644 Graphics/GraphicsEngineVulkan/src/RootSignature.cpp (limited to 'Graphics/GraphicsEngineVulkan') diff --git a/Graphics/GraphicsEngineVulkan/CMakeLists.txt b/Graphics/GraphicsEngineVulkan/CMakeLists.txt index a340fedd..b501730a 100644 --- a/Graphics/GraphicsEngineVulkan/CMakeLists.txt +++ b/Graphics/GraphicsEngineVulkan/CMakeLists.txt @@ -16,9 +16,9 @@ set(INCLUDE include/FramebufferCache.h include/GenerateMips.h include/pch.h + include/PipelineLayout.h include/PipelineStateVkImpl.h include/RenderDeviceVkImpl.h - include/RootSignature.h include/SamplerVkImpl.h include/ShaderVkImpl.h include/ShaderResourceBindingVkImpl.h @@ -72,10 +72,10 @@ set(SRC src/DynamicUploadHeap.cpp src/FramebufferCache.cpp src/GenerateMips.cpp + src/PipelineLayout.cpp src/PipelineStateVkImpl.cpp src/RenderDeviceVkImpl.cpp src/RenderDeviceFactoryVk.cpp - src/RootSignature.cpp src/SamplerVkImpl.cpp src/ShaderVkImpl.cpp src/ShaderResourceBindingVkImpl.cpp diff --git a/Graphics/GraphicsEngineVulkan/include/PipelineLayout.h b/Graphics/GraphicsEngineVulkan/include/PipelineLayout.h new file mode 100644 index 00000000..89e9dc5f --- /dev/null +++ b/Graphics/GraphicsEngineVulkan/include/PipelineLayout.h @@ -0,0 +1,486 @@ +/* Copyright 2015-2018 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#pragma once + +/// \file +/// Declaration of Diligent::RootSignature class +#include "ShaderBase.h" +#include "ShaderResourceLayoutVk.h" +#include "VulkanUtilities/VulkanObjectWrappers.h" +#include "VulkanUtilities/VulkanLogicalDevice.h" + +namespace Diligent +{ + +class RenderDeviceVkImpl; + +//SHADER_TYPE ShaderTypeFromShaderVisibility(Vk_SHADER_VISIBILITY ShaderVisibility); +//Vk_SHADER_VISIBILITY GetShaderVisibility(SHADER_TYPE ShaderType); +//Vk_DESCRIPTOR_HEAP_TYPE dbgHeapTypeFromRangeType(Vk_DESCRIPTOR_RANGE_TYPE RangeType); + +#if 0 +class DescriptorSetLayout +{ +public: + + + RootParameter(Vk_ROOT_PARAMETER_TYPE ParameterType, Uint32 RootIndex, UINT Register, UINT RegisterSpace, Vk_SHADER_VISIBILITY Visibility, SHADER_VARIABLE_TYPE VarType) : + m_RootIndex(RootIndex), + m_ShaderVarType(VarType) + { + VERIFY(ParameterType == Vk_ROOT_PARAMETER_TYPE_CBV || ParameterType == Vk_ROOT_PARAMETER_TYPE_SRV || ParameterType == Vk_ROOT_PARAMETER_TYPE_UAV, "Unexpected parameter type - verify argument list"); + m_RootParam.ParameterType = ParameterType; + m_RootParam.ShaderVisibility = Visibility; + m_RootParam.Descriptor.ShaderRegister = Register; + m_RootParam.Descriptor.RegisterSpace = RegisterSpace; + } + + RootParameter(Vk_ROOT_PARAMETER_TYPE ParameterType, Uint32 RootIndex, UINT Register, UINT RegisterSpace, UINT NumDwords, Vk_SHADER_VISIBILITY Visibility, SHADER_VARIABLE_TYPE VarType) : + m_RootIndex(RootIndex), + m_ShaderVarType(VarType) + { + VERIFY(ParameterType == Vk_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS, "Unexpected parameter type - verify argument list"); + m_RootParam.ParameterType = ParameterType; + m_RootParam.ShaderVisibility = Visibility; + m_RootParam.Constants.Num32BitValues = NumDwords; + m_RootParam.Constants.ShaderRegister = Register; + m_RootParam.Constants.RegisterSpace = RegisterSpace; + } + + RootParameter(Vk_ROOT_PARAMETER_TYPE ParameterType, Uint32 RootIndex, UINT NumRanges, Vk_DESCRIPTOR_RANGE *pRanges, Vk_SHADER_VISIBILITY Visibility, SHADER_VARIABLE_TYPE VarType) : + m_RootIndex(RootIndex), + m_ShaderVarType(VarType) + { + VERIFY(ParameterType == Vk_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, "Unexpected parameter type - verify argument list"); + VERIFY_EXPR(pRanges != nullptr); + m_RootParam.ParameterType = ParameterType; + m_RootParam.ShaderVisibility = Visibility; + m_RootParam.DescriptorTable.NumDescriptorRanges = NumRanges; + m_RootParam.DescriptorTable.pDescriptorRanges = pRanges; +#ifdef _DEBUG + for (Uint32 r = 0; r < NumRanges; ++r) + pRanges[r].RangeType = static_cast(-1); +#endif + } + + RootParameter(const RootParameter &RP) : + m_RootParam(RP.m_RootParam), + m_DescriptorTableSize(RP.m_DescriptorTableSize), + m_ShaderVarType(RP.m_ShaderVarType), + m_RootIndex(RP.m_RootIndex) + { + VERIFY(m_RootParam.ParameterType != Vk_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, "Use another constructor to copy descriptor table"); + } + + RootParameter(const RootParameter &RP, UINT NumRanges, Vk_DESCRIPTOR_RANGE *pRanges) : + m_RootParam(RP.m_RootParam), + m_DescriptorTableSize(RP.m_DescriptorTableSize), + m_ShaderVarType(RP.m_ShaderVarType), + m_RootIndex(RP.m_RootIndex) + { + VERIFY(m_RootParam.ParameterType == Vk_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, "Root parameter is expected to be a descriptor table"); + VERIFY(NumRanges >= m_RootParam.DescriptorTable.NumDescriptorRanges, "New table must be larger than source one"); + auto &DstTbl = m_RootParam.DescriptorTable; + DstTbl.NumDescriptorRanges = NumRanges; + DstTbl.pDescriptorRanges = pRanges; + const auto &SrcTbl = RP.m_RootParam.DescriptorTable; + memcpy(pRanges, SrcTbl.pDescriptorRanges, SrcTbl.NumDescriptorRanges * sizeof(Vk_DESCRIPTOR_RANGE)); +#ifdef _DEBUG + { + Uint32 dbgTableSize = 0; + for (Uint32 r = 0; r < SrcTbl.NumDescriptorRanges; ++r) + { + const auto &Range = SrcTbl.pDescriptorRanges[r]; + dbgTableSize = std::max(dbgTableSize, Range.OffsetInDescriptorsFromTableStart + Range.NumDescriptors); + } + VERIFY(dbgTableSize == m_DescriptorTableSize, "Incorrect descriptor table size"); + + for (Uint32 r = SrcTbl.NumDescriptorRanges; r < DstTbl.NumDescriptorRanges; ++r) + pRanges[r].RangeType = static_cast(-1); + } +#endif +} + + RootParameter& operator = (const RootParameter &RP) = delete; + RootParameter& operator = (RootParameter &&RP) = delete; + + void SetDescriptorRange(UINT RangeIndex, Vk_DESCRIPTOR_RANGE_TYPE Type, UINT Register, UINT Count, UINT Space = 0, UINT OffsetFromTableStart = Vk_DESCRIPTOR_RANGE_OFFSET_APPEND) + { + VERIFY(m_RootParam.ParameterType == Vk_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, "Incorrect parameter table: descriptor table is expected"); + auto &Tbl = m_RootParam.DescriptorTable; + VERIFY(RangeIndex < Tbl.NumDescriptorRanges, "Invalid descriptor range index"); + Vk_DESCRIPTOR_RANGE &range = const_cast(Tbl.pDescriptorRanges[RangeIndex]); + VERIFY(range.RangeType == static_cast(-1), "Descriptor range has already been initialized. m_DescriptorTableSize may be updated incorrectly"); + range.RangeType = Type; + range.NumDescriptors = Count; + range.BaseShaderRegister = Register; + range.RegisterSpace = Space; + range.OffsetInDescriptorsFromTableStart = OffsetFromTableStart; + m_DescriptorTableSize = std::max(m_DescriptorTableSize, OffsetFromTableStart + Count); + } + + SHADER_VARIABLE_TYPE GetShaderVariableType()const { return m_ShaderVarType; } + Uint32 GetDescriptorTableSize()const + { + VERIFY(m_RootParam.ParameterType == Vk_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, "Incorrect parameter table: descriptor table is expected"); + return m_DescriptorTableSize; + } + Vk_SHADER_VISIBILITY GetShaderVisibility()const { return m_RootParam.ShaderVisibility; } + Vk_ROOT_PARAMETER_TYPE GetParameterType()const { return m_RootParam.ParameterType; } + + Uint32 GetRootIndex()const { return m_RootIndex; } + + operator const Vk_ROOT_PARAMETER&()const { return m_RootParam; } + + bool operator == (const RootParameter&rhs)const + { + if (m_ShaderVarType != rhs.m_ShaderVarType || + m_DescriptorTableSize != rhs.m_DescriptorTableSize || + m_RootIndex != rhs.m_RootIndex) + return false; + + if (m_RootParam.ParameterType != rhs.m_RootParam.ParameterType || + m_RootParam.ShaderVisibility != rhs.m_RootParam.ShaderVisibility) + return false; + + switch (m_RootParam.ParameterType) + { + case Vk_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE: + { + const auto &tbl0 = m_RootParam.DescriptorTable; + const auto &tbl1 = rhs.m_RootParam.DescriptorTable; + if (tbl0.NumDescriptorRanges != tbl1.NumDescriptorRanges) + return false; + for (UINT r = 0; r < tbl0.NumDescriptorRanges; ++r) + { + const auto &rng0 = tbl0.pDescriptorRanges[r]; + const auto &rng1 = tbl1.pDescriptorRanges[r]; + if (memcmp(&rng0, &rng1, sizeof(rng0)) != 0) + return false; + } + } + break; + + case Vk_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS: + { + const auto &cnst0 = m_RootParam.Constants; + const auto &cnst1 = rhs.m_RootParam.Constants; + if (memcmp(&cnst0, &cnst1, sizeof(cnst0)) != 0) + return false; + } + break; + + case Vk_ROOT_PARAMETER_TYPE_CBV: + case Vk_ROOT_PARAMETER_TYPE_SRV: + case Vk_ROOT_PARAMETER_TYPE_UAV: + { + const auto &dscr0 = m_RootParam.Descriptor; + const auto &dscr1 = rhs.m_RootParam.Descriptor; + if (memcmp(&dscr0, &dscr1, sizeof(dscr0)) != 0) + return false; + } + break; + + default: UNEXPECTED("Unexpected root parameter type"); + } + + return true; + } + + bool operator != (const RootParameter&rhs)const + { + return !(*this == rhs); + } + + size_t GetHash()const + { + size_t hash = ComputeHash(m_ShaderVarType, m_DescriptorTableSize, m_RootIndex); + HashCombine(hash, m_RootParam.ParameterType, m_RootParam.ShaderVisibility); + + switch (m_RootParam.ParameterType) + { + case Vk_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE: + { + const auto &tbl = m_RootParam.DescriptorTable; + HashCombine(hash, tbl.NumDescriptorRanges); + for (UINT r = 0; r < tbl.NumDescriptorRanges; ++r) + { + const auto &rng = tbl.pDescriptorRanges[r]; + HashCombine(hash, rng.BaseShaderRegister, rng.NumDescriptors, rng.OffsetInDescriptorsFromTableStart, rng.RangeType, rng.RegisterSpace); + } + } + break; + + case Vk_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS: + { + const auto &cnst = m_RootParam.Constants; + HashCombine(hash, cnst.Num32BitValues, cnst.RegisterSpace, cnst.ShaderRegister); + } + break; + + case Vk_ROOT_PARAMETER_TYPE_CBV: + case Vk_ROOT_PARAMETER_TYPE_SRV: + case Vk_ROOT_PARAMETER_TYPE_UAV: + { + const auto &dscr = m_RootParam.Descriptor; + HashCombine(hash, dscr.RegisterSpace, dscr.ShaderRegister); + } + break; + + default: UNEXPECTED("Unexpected root parameter type"); + } + + return hash; + } + +private: + + SHADER_VARIABLE_TYPE m_ShaderVarType = static_cast(-1); + Vk_ROOT_PARAMETER m_RootParam = {}; + Uint32 m_DescriptorTableSize = 0; + Uint32 m_RootIndex = static_cast(-1); + + +}; +#endif + + +/// Implementation of the Diligent::RootSignature class +class PipelineLayout +{ +public: +#if 0 + RootSignature(); + + void AllocateStaticSamplers(IShader* const *ppShaders, Uint32 NumShaders); + + void Finalize(IVkDevice *pVkDevice); + + IVkRootSignature* GetVkRootSignature()const{return m_pVkRootSignature;} + void InitResourceCache(RenderDeviceVkImpl *pDeviceVkImpl, class ShaderResourceCacheVk& ResourceCache, IMemoryAllocator &CacheMemAllocator)const; + + void InitStaticSampler(SHADER_TYPE ShaderType, const String &TextureName, const D3DShaderResourceAttribs &ShaderResAttribs); +#endif + + //void AllocateResourceSlot(SHADER_TYPE ShaderType, const D3DShaderResourceAttribs &ShaderResAttribs, Vk_DESCRIPTOR_RANGE_TYPE RangeType, Uint32 &RootIndex, Uint32 &OffsetFromTableStart); + +#if 0 + // This method should be thread-safe as it does not modify any object state + void (RootSignature::*CommitDescriptorHandles)(RenderDeviceVkImpl *pRenderDeviceVk, + ShaderResourceCacheVk& ResourceCache, + class CommandContext &Ctx, + bool IsCompute)const = nullptr; + + void (RootSignature::*TransitionAndCommitDescriptorHandles)(RenderDeviceVkImpl *pRenderDeviceVk, + ShaderResourceCacheVk& ResourceCache, + class CommandContext &Ctx, + bool IsCompute)const = nullptr; + + void TransitionResources(ShaderResourceCacheVk& ResourceCache, + class CommandContext &Ctx)const; + + void CommitRootViews(ShaderResourceCacheVk& ResourceCache, + class CommandContext &Ctx, + bool IsCompute, + Uint32 ContextId)const; + + Uint32 GetTotalSrvCbvUavSlots(SHADER_VARIABLE_TYPE VarType)const + { + VERIFY_EXPR(VarType >= 0 && VarType < SHADER_VARIABLE_TYPE_NUM_TYPES); + return m_TotalSrvCbvUavSlots[VarType]; + } + Uint32 GetTotalSamplerSlots(SHADER_VARIABLE_TYPE VarType)const + { + VERIFY_EXPR(VarType >= 0 && VarType < SHADER_VARIABLE_TYPE_NUM_TYPES); + return m_TotalSamplerSlots[VarType]; + } + + bool IsSameAs(const RootSignature& RS)const + { + return m_RootParams == RS.m_RootParams; + } + size_t GetHash()const + { + return m_RootParams.GetHash(); + } + +private: +#ifdef _DEBUG + void dbgVerifyRootParameters()const; +#endif + + Uint32 m_TotalSrvCbvUavSlots[SHADER_VARIABLE_TYPE_NUM_TYPES]; + Uint32 m_TotalSamplerSlots[SHADER_VARIABLE_TYPE_NUM_TYPES]; + + CComPtr m_pVkRootSignature; +#endif + + class DescriptorSetLayoutManager + { + public: + struct DescriptorSetLayout + { + DescriptorSetLayout(SHADER_VARIABLE_TYPE VarType) : + ShaderVarType(VarType) + {} + DescriptorSetLayout(DescriptorSetLayout&&) = default; + DescriptorSetLayout(const DescriptorSetLayout&) = delete; + DescriptorSetLayout& operator = (const DescriptorSetLayout&) = delete; + DescriptorSetLayout& operator = (DescriptorSetLayout&&) = delete; + + const SHADER_VARIABLE_TYPE ShaderVarType; + uint32_t BindingCount = 0; + VkDescriptorSetLayoutBinding* pBindings = nullptr; + VulkanUtilities::DescriptorSetLayoutWrapper VkLayout; + + ~DescriptorSetLayout(); + void AddBinding(const VkDescriptorSetLayoutBinding &Binding, IMemoryAllocator &MemAllocator); + void Finalize(const VulkanUtilities::VulkanLogicalDevice &LogicalDevice, IMemoryAllocator &MemAllocator, VkDescriptorSetLayoutBinding* pNewBindings); + void Release(RenderDeviceVkImpl *pRenderDeviceVk); + + bool operator == (const DescriptorSetLayout& rhs)const; + bool operator != (const DescriptorSetLayout& rhs)const{return !(*this == rhs);} + + private: + void ReserveMemory(Uint32 NumBindings, IMemoryAllocator &MemAllocator); + static size_t GetMemorySize(Uint32 NumBindings); + }; + + DescriptorSetLayoutManager(IMemoryAllocator &MemAllocator); + ~DescriptorSetLayoutManager(); + + DescriptorSetLayoutManager(const DescriptorSetLayoutManager&) = delete; + DescriptorSetLayoutManager& operator= (const DescriptorSetLayoutManager&) = delete; + DescriptorSetLayoutManager(DescriptorSetLayoutManager&&) = delete; + DescriptorSetLayoutManager& operator= (DescriptorSetLayoutManager&&) = delete; + + void Finalize(const VulkanUtilities::VulkanLogicalDevice &LogicalDevice); + void Release(RenderDeviceVkImpl *pRenderDeviceVk); + + //Uint32 GetNumRootTables()const{return m_NumRootTables;} + //Uint32 GetNumRootViews()const{return m_NumRootViews;} + // + //const RootParameter& GetRootTable(Uint32 TableInd)const + //{ + // VERIFY_EXPR(TableInd < m_NumRootTables); + // return m_pRootTables[TableInd]; + //} + + //RootParameter& GetRootTable(Uint32 TableInd) + //{ + // VERIFY_EXPR(TableInd < m_NumRootTables); + // return m_pRootTables[TableInd]; + //} + + //const RootParameter& GetRootView(Uint32 ViewInd)const + //{ + // VERIFY_EXPR(ViewInd < m_NumRootViews); + // return m_pRootViews[ViewInd]; + //} + + //RootParameter& GetRootView(Uint32 ViewInd) + //{ + // VERIFY_EXPR(ViewInd < m_NumRootViews); + // return m_pRootViews[ViewInd]; + //} + + DescriptorSetLayout& GetDescriptorSet(SHADER_VARIABLE_TYPE VarType); + DescriptorSetLayout& GetDescriptorSetByInd(size_t Ind){return m_DescriptorSetLayouts[Ind];} + const DescriptorSetLayout& GetDescriptorSetByInd(size_t Ind)const { return m_DescriptorSetLayouts[Ind]; } + size_t GetNumDescriptorSetLayouts()const { return m_DescriptorSetLayouts.size(); } + + //void AddDescriptorSet(SHADER_VARIABLE_TYPE VarType); + //void AddRootTable(Uint32 RootIndex, Vk_SHADER_VISIBILITY Visibility, SHADER_VARIABLE_TYPE VarType, Uint32 NumRangesInNewTable = 1); + //void AddDescriptorRanges(Uint32 RootTableInd, Uint32 NumExtraRanges = 1); + + //template + //void ProcessDescriptorSets(TOperation)const; + + bool operator == (const DescriptorSetLayoutManager& rhs)const; + bool operator != (const DescriptorSetLayoutManager& rhs)const {return !(*this == rhs);} + //size_t GetHash()const; + + private: + + IMemoryAllocator &m_MemAllocator; + //std::unique_ptr> m_pMemory; + //Uint32 m_NumRootTables = 0; + //Uint32 m_NumRootViews = 0; + //Uint32 m_TotalDescriptorRanges = 0; + //RootParameter *m_pRootTables = nullptr; + //RootParameter *m_pRootViews = nullptr; + VulkanUtilities::PipelineLayoutWrapper m_VkPipelineLayout; + std::vector> m_DescriptorSetLayouts; + std::vector> m_LayoutBindings; + Int8 m_VarTypeToDescrSetLayout[SHADER_VARIABLE_TYPE_NUM_TYPES] = {-1, -1, -1}; + }; + +#if 0 + static constexpr Uint8 InvalidRootTableIndex = static_cast(-1); + + // The array below contains array index of a CBV/SRV/UAV root table + // in m_RootParams (NOT the Root Index!), for every variable type + // (static, mutable, dynamic) and every shader type, + // or -1, if the table is not yet assigned to the combination + Uint8 m_SrvCbvUavRootTablesMap[SHADER_VARIABLE_TYPE_NUM_TYPES * 6]; + // This array contains the same data for Sampler root table + Uint8 m_SamplerRootTablesMap[SHADER_VARIABLE_TYPE_NUM_TYPES * 6]; + + RootParamsManager m_RootParams; + + struct StaticSamplerAttribs + { + StaticSamplerDesc SamplerDesc; + UINT ShaderRegister = static_cast(-1); + UINT ArraySize = 0; + UINT RegisterSpace = 0; + Vk_SHADER_VISIBILITY ShaderVisibility = static_cast(-1); + + StaticSamplerAttribs(){} + StaticSamplerAttribs(const StaticSamplerDesc& SamDesc, Vk_SHADER_VISIBILITY Visibility) : + SamplerDesc(SamDesc), + ShaderVisibility(Visibility) + {} + }; + // Note: sizeof(m_StaticSamplers) == 56 (MS compiler, release x64) + std::vector > m_StaticSamplers; + + IMemoryAllocator &m_MemAllocator; + + // Commits descriptor handles for static and mutable variables + template + void CommitDescriptorHandlesInternal_SM(RenderDeviceVkImpl *pRenderDeviceVk, + ShaderResourceCacheVk& ResourceCache, + class CommandContext &Ctx, + bool IsCompute)const; + template + // Commits descriptor handles for static, mutable, and dynamic variables + void CommitDescriptorHandlesInternal_SMD(RenderDeviceVkImpl *pRenderDeviceVk, + ShaderResourceCacheVk& ResourceCache, + class CommandContext &Ctx, + bool IsCompute)const; +#endif +}; + +} diff --git a/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.h b/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.h index e90cd69a..0ebfe80c 100644 --- a/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.h +++ b/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.h @@ -29,7 +29,7 @@ #include "RenderDeviceVk.h" #include "PipelineStateVk.h" #include "PipelineStateBase.h" -#include "RootSignature.h" +#include "PipelineLayout.h" #include "ShaderResourceLayoutVk.h" #include "AdaptiveFixedBlockAllocator.h" #include "VulkanUtilities/VulkanObjectWrappers.h" diff --git a/Graphics/GraphicsEngineVulkan/include/RootSignature.h b/Graphics/GraphicsEngineVulkan/include/RootSignature.h deleted file mode 100644 index 7545f54b..00000000 --- a/Graphics/GraphicsEngineVulkan/include/RootSignature.h +++ /dev/null @@ -1,433 +0,0 @@ -/* Copyright 2015-2018 Egor Yusov - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. - * - * In no event and under no legal theory, whether in tort (including negligence), - * contract, or otherwise, unless required by applicable law (such as deliberate - * and grossly negligent acts) or agreed to in writing, shall any Contributor be - * liable for any damages, including any direct, indirect, special, incidental, - * or consequential damages of any character arising as a result of this License or - * out of the use or inability to use the software (including but not limited to damages - * for loss of goodwill, work stoppage, computer failure or malfunction, or any and - * all other commercial damages or losses), even if such Contributor has been advised - * of the possibility of such damages. - */ - -#pragma once - -/// \file -/// Declaration of Diligent::RootSignature class -#include "ShaderBase.h" -#include "ShaderResourceLayoutVk.h" - -namespace Diligent -{ - -#if 0 -SHADER_TYPE ShaderTypeFromShaderVisibility(Vk_SHADER_VISIBILITY ShaderVisibility); -Vk_SHADER_VISIBILITY GetShaderVisibility(SHADER_TYPE ShaderType); -Vk_DESCRIPTOR_HEAP_TYPE dbgHeapTypeFromRangeType(Vk_DESCRIPTOR_RANGE_TYPE RangeType); - -class RootParameter -{ -public: - - RootParameter(Vk_ROOT_PARAMETER_TYPE ParameterType, Uint32 RootIndex, UINT Register, UINT RegisterSpace, Vk_SHADER_VISIBILITY Visibility, SHADER_VARIABLE_TYPE VarType) : - m_RootIndex(RootIndex), - m_ShaderVarType(VarType) - { - VERIFY(ParameterType == Vk_ROOT_PARAMETER_TYPE_CBV || ParameterType == Vk_ROOT_PARAMETER_TYPE_SRV || ParameterType == Vk_ROOT_PARAMETER_TYPE_UAV, "Unexpected parameter type - verify argument list"); - m_RootParam.ParameterType = ParameterType; - m_RootParam.ShaderVisibility = Visibility; - m_RootParam.Descriptor.ShaderRegister = Register; - m_RootParam.Descriptor.RegisterSpace = RegisterSpace; - } - - RootParameter( Vk_ROOT_PARAMETER_TYPE ParameterType, Uint32 RootIndex, UINT Register, UINT RegisterSpace, UINT NumDwords, Vk_SHADER_VISIBILITY Visibility, SHADER_VARIABLE_TYPE VarType) : - m_RootIndex(RootIndex), - m_ShaderVarType(VarType) - { - VERIFY(ParameterType == Vk_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS, "Unexpected parameter type - verify argument list"); - m_RootParam.ParameterType = ParameterType; - m_RootParam.ShaderVisibility = Visibility; - m_RootParam.Constants.Num32BitValues = NumDwords; - m_RootParam.Constants.ShaderRegister = Register; - m_RootParam.Constants.RegisterSpace = RegisterSpace; - } - - RootParameter( Vk_ROOT_PARAMETER_TYPE ParameterType, Uint32 RootIndex, UINT NumRanges, Vk_DESCRIPTOR_RANGE *pRanges, Vk_SHADER_VISIBILITY Visibility, SHADER_VARIABLE_TYPE VarType) : - m_RootIndex(RootIndex), - m_ShaderVarType(VarType) - { - VERIFY(ParameterType == Vk_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, "Unexpected parameter type - verify argument list"); - VERIFY_EXPR(pRanges != nullptr); - m_RootParam.ParameterType = ParameterType; - m_RootParam.ShaderVisibility = Visibility; - m_RootParam.DescriptorTable.NumDescriptorRanges = NumRanges; - m_RootParam.DescriptorTable.pDescriptorRanges = pRanges; -#ifdef _DEBUG - for(Uint32 r=0; r < NumRanges; ++r) - pRanges[r].RangeType = static_cast(-1); -#endif - } - - RootParameter(const RootParameter &RP): - m_RootParam( RP.m_RootParam), - m_DescriptorTableSize(RP.m_DescriptorTableSize), - m_ShaderVarType(RP.m_ShaderVarType), - m_RootIndex(RP.m_RootIndex) - { - VERIFY(m_RootParam.ParameterType != Vk_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, "Use another constructor to copy descriptor table"); - } - - RootParameter(const RootParameter &RP, UINT NumRanges, Vk_DESCRIPTOR_RANGE *pRanges): - m_RootParam( RP.m_RootParam), - m_DescriptorTableSize(RP.m_DescriptorTableSize), - m_ShaderVarType(RP.m_ShaderVarType), - m_RootIndex(RP.m_RootIndex) - { - VERIFY(m_RootParam.ParameterType == Vk_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, "Root parameter is expected to be a descriptor table"); - VERIFY(NumRanges >= m_RootParam.DescriptorTable.NumDescriptorRanges, "New table must be larger than source one"); - auto &DstTbl = m_RootParam.DescriptorTable; - DstTbl.NumDescriptorRanges = NumRanges; - DstTbl.pDescriptorRanges = pRanges; - const auto &SrcTbl = RP.m_RootParam.DescriptorTable; - memcpy(pRanges, SrcTbl.pDescriptorRanges, SrcTbl.NumDescriptorRanges * sizeof(Vk_DESCRIPTOR_RANGE)); -#ifdef _DEBUG - { - Uint32 dbgTableSize = 0; - for (Uint32 r = 0; r < SrcTbl.NumDescriptorRanges; ++r) - { - const auto &Range = SrcTbl.pDescriptorRanges[r]; - dbgTableSize = std::max(dbgTableSize, Range.OffsetInDescriptorsFromTableStart + Range.NumDescriptors); - } - VERIFY(dbgTableSize == m_DescriptorTableSize, "Incorrect descriptor table size"); - - for (Uint32 r = SrcTbl.NumDescriptorRanges; r < DstTbl.NumDescriptorRanges; ++r) - pRanges[r].RangeType = static_cast(-1); - } -#endif - } - - RootParameter& operator = (const RootParameter &RP) = delete; - RootParameter& operator = (RootParameter &&RP) = delete; - - void SetDescriptorRange( UINT RangeIndex, Vk_DESCRIPTOR_RANGE_TYPE Type, UINT Register, UINT Count, UINT Space = 0, UINT OffsetFromTableStart = Vk_DESCRIPTOR_RANGE_OFFSET_APPEND) - { - VERIFY(m_RootParam.ParameterType == Vk_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, "Incorrect parameter table: descriptor table is expected"); - auto &Tbl = m_RootParam.DescriptorTable; - VERIFY(RangeIndex < Tbl.NumDescriptorRanges, "Invalid descriptor range index"); - Vk_DESCRIPTOR_RANGE &range = const_cast(Tbl.pDescriptorRanges[RangeIndex]); - VERIFY(range.RangeType == static_cast(-1), "Descriptor range has already been initialized. m_DescriptorTableSize may be updated incorrectly"); - range.RangeType = Type; - range.NumDescriptors = Count; - range.BaseShaderRegister = Register; - range.RegisterSpace = Space; - range.OffsetInDescriptorsFromTableStart = OffsetFromTableStart; - m_DescriptorTableSize = std::max(m_DescriptorTableSize, OffsetFromTableStart + Count); - } - - SHADER_VARIABLE_TYPE GetShaderVariableType()const{ return m_ShaderVarType; } - Uint32 GetDescriptorTableSize()const - { - VERIFY(m_RootParam.ParameterType == Vk_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, "Incorrect parameter table: descriptor table is expected"); - return m_DescriptorTableSize; - } - Vk_SHADER_VISIBILITY GetShaderVisibility()const{return m_RootParam.ShaderVisibility;} - Vk_ROOT_PARAMETER_TYPE GetParameterType()const{return m_RootParam.ParameterType;} - - Uint32 GetRootIndex()const{return m_RootIndex;} - - operator const Vk_ROOT_PARAMETER&()const{return m_RootParam;} - - bool operator == (const RootParameter&rhs)const - { - if (m_ShaderVarType != rhs.m_ShaderVarType || - m_DescriptorTableSize != rhs.m_DescriptorTableSize || - m_RootIndex != rhs.m_RootIndex) - return false; - - if (m_RootParam.ParameterType != rhs.m_RootParam.ParameterType || - m_RootParam.ShaderVisibility != rhs.m_RootParam.ShaderVisibility) - return false; - - switch(m_RootParam.ParameterType) - { - case Vk_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE: - { - const auto &tbl0 = m_RootParam.DescriptorTable; - const auto &tbl1 = rhs.m_RootParam.DescriptorTable; - if(tbl0.NumDescriptorRanges != tbl1.NumDescriptorRanges) - return false; - for(UINT r=0; r < tbl0.NumDescriptorRanges; ++r) - { - const auto &rng0 = tbl0.pDescriptorRanges[r]; - const auto &rng1 = tbl1.pDescriptorRanges[r]; - if( memcmp(&rng0, &rng1, sizeof(rng0)) != 0) - return false; - } - } - break; - - case Vk_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS: - { - const auto &cnst0 = m_RootParam.Constants; - const auto &cnst1 = rhs.m_RootParam.Constants; - if (memcmp(&cnst0, &cnst1, sizeof(cnst0)) != 0) - return false; - } - break; - - case Vk_ROOT_PARAMETER_TYPE_CBV: - case Vk_ROOT_PARAMETER_TYPE_SRV: - case Vk_ROOT_PARAMETER_TYPE_UAV: - { - const auto &dscr0 = m_RootParam.Descriptor; - const auto &dscr1 = rhs.m_RootParam.Descriptor; - if (memcmp(&dscr0, &dscr1, sizeof(dscr0)) != 0) - return false; - } - break; - - default: UNEXPECTED("Unexpected root parameter type"); - } - - return true; - } - - bool operator != (const RootParameter&rhs)const - { - return !(*this == rhs); - } - - size_t GetHash()const - { - size_t hash = ComputeHash(m_ShaderVarType, m_DescriptorTableSize, m_RootIndex); - HashCombine(hash, m_RootParam.ParameterType, m_RootParam.ShaderVisibility); - - switch (m_RootParam.ParameterType) - { - case Vk_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE: - { - const auto &tbl = m_RootParam.DescriptorTable; - HashCombine(hash, tbl.NumDescriptorRanges); - for (UINT r = 0; r < tbl.NumDescriptorRanges; ++r) - { - const auto &rng = tbl.pDescriptorRanges[r]; - HashCombine(hash, rng.BaseShaderRegister, rng.NumDescriptors, rng.OffsetInDescriptorsFromTableStart, rng.RangeType, rng.RegisterSpace); - } - } - break; - - case Vk_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS: - { - const auto &cnst = m_RootParam.Constants; - HashCombine(hash, cnst.Num32BitValues, cnst.RegisterSpace, cnst.ShaderRegister); - } - break; - - case Vk_ROOT_PARAMETER_TYPE_CBV: - case Vk_ROOT_PARAMETER_TYPE_SRV: - case Vk_ROOT_PARAMETER_TYPE_UAV: - { - const auto &dscr = m_RootParam.Descriptor; - HashCombine(hash, dscr.RegisterSpace, dscr.ShaderRegister); - } - break; - - default: UNEXPECTED("Unexpected root parameter type"); - } - - return hash; - } - -private: - - SHADER_VARIABLE_TYPE m_ShaderVarType = static_cast(-1); - Vk_ROOT_PARAMETER m_RootParam = {}; - Uint32 m_DescriptorTableSize = 0; - Uint32 m_RootIndex = static_cast(-1); -}; - - - -/// Implementation of the Diligent::RootSignature class -class RootSignature -{ -public: - RootSignature(); - - void AllocateStaticSamplers(IShader* const *ppShaders, Uint32 NumShaders); - - void Finalize(IVkDevice *pVkDevice); - - IVkRootSignature* GetVkRootSignature()const{return m_pVkRootSignature;} - void InitResourceCache(class RenderDeviceVkImpl *pDeviceVkImpl, class ShaderResourceCacheVk& ResourceCache, IMemoryAllocator &CacheMemAllocator)const; - - void InitStaticSampler(SHADER_TYPE ShaderType, const String &TextureName, const D3DShaderResourceAttribs &ShaderResAttribs); - - void AllocateResourceSlot(SHADER_TYPE ShaderType, const D3DShaderResourceAttribs &ShaderResAttribs, Vk_DESCRIPTOR_RANGE_TYPE RangeType, Uint32 &RootIndex, Uint32 &OffsetFromTableStart); - - // This method should be thread-safe as it does not modify any object state - void (RootSignature::*CommitDescriptorHandles)(class RenderDeviceVkImpl *pRenderDeviceVk, - ShaderResourceCacheVk& ResourceCache, - class CommandContext &Ctx, - bool IsCompute)const = nullptr; - - void (RootSignature::*TransitionAndCommitDescriptorHandles)(class RenderDeviceVkImpl *pRenderDeviceVk, - ShaderResourceCacheVk& ResourceCache, - class CommandContext &Ctx, - bool IsCompute)const = nullptr; - - void TransitionResources(ShaderResourceCacheVk& ResourceCache, - class CommandContext &Ctx)const; - - void CommitRootViews(ShaderResourceCacheVk& ResourceCache, - class CommandContext &Ctx, - bool IsCompute, - Uint32 ContextId)const; - - Uint32 GetTotalSrvCbvUavSlots(SHADER_VARIABLE_TYPE VarType)const - { - VERIFY_EXPR(VarType >= 0 && VarType < SHADER_VARIABLE_TYPE_NUM_TYPES); - return m_TotalSrvCbvUavSlots[VarType]; - } - Uint32 GetTotalSamplerSlots(SHADER_VARIABLE_TYPE VarType)const - { - VERIFY_EXPR(VarType >= 0 && VarType < SHADER_VARIABLE_TYPE_NUM_TYPES); - return m_TotalSamplerSlots[VarType]; - } - - bool IsSameAs(const RootSignature& RS)const - { - return m_RootParams == RS.m_RootParams; - } - size_t GetHash()const - { - return m_RootParams.GetHash(); - } - -private: -#ifdef _DEBUG - void dbgVerifyRootParameters()const; -#endif - - Uint32 m_TotalSrvCbvUavSlots[SHADER_VARIABLE_TYPE_NUM_TYPES]; - Uint32 m_TotalSamplerSlots[SHADER_VARIABLE_TYPE_NUM_TYPES]; - - CComPtr m_pVkRootSignature; - - class RootParamsManager - { - public: - RootParamsManager(IMemoryAllocator &MemAllocator); - - RootParamsManager(const RootParamsManager&) = delete; - RootParamsManager& operator= (const RootParamsManager&) = delete; - RootParamsManager(RootParamsManager&&) = delete; - RootParamsManager& operator= (RootParamsManager&&) = delete; - - Uint32 GetNumRootTables()const{return m_NumRootTables;} - Uint32 GetNumRootViews()const{return m_NumRootViews;} - - const RootParameter& GetRootTable(Uint32 TableInd)const - { - VERIFY_EXPR(TableInd < m_NumRootTables); - return m_pRootTables[TableInd]; - } - - RootParameter& GetRootTable(Uint32 TableInd) - { - VERIFY_EXPR(TableInd < m_NumRootTables); - return m_pRootTables[TableInd]; - } - - const RootParameter& GetRootView(Uint32 ViewInd)const - { - VERIFY_EXPR(ViewInd < m_NumRootViews); - return m_pRootViews[ViewInd]; - } - - RootParameter& GetRootView(Uint32 ViewInd) - { - VERIFY_EXPR(ViewInd < m_NumRootViews); - return m_pRootViews[ViewInd]; - } - - void AddRootView(Vk_ROOT_PARAMETER_TYPE ParameterType, Uint32 RootIndex, UINT Register, Vk_SHADER_VISIBILITY Visibility, SHADER_VARIABLE_TYPE VarType); - void AddRootTable(Uint32 RootIndex, Vk_SHADER_VISIBILITY Visibility, SHADER_VARIABLE_TYPE VarType, Uint32 NumRangesInNewTable = 1); - void AddDescriptorRanges(Uint32 RootTableInd, Uint32 NumExtraRanges = 1); - - template - void ProcessRootTables(TOperation)const; - - bool operator == (const RootParamsManager& RootParams)const; - size_t GetHash()const; - - private: - size_t GetRequiredMemorySize(Uint32 NumExtraRootTables, Uint32 NumExtraRootViews, Uint32 NumExtraDescriptorRanges)const; - Vk_DESCRIPTOR_RANGE* Extend(Uint32 NumExtraRootTables, Uint32 NumExtraRootViews, Uint32 NumExtraDescriptorRanges, Uint32 RootTableToAddRanges = static_cast(-1)); - - IMemoryAllocator &m_MemAllocator; - std::unique_ptr> m_pMemory; - Uint32 m_NumRootTables = 0; - Uint32 m_NumRootViews = 0; - Uint32 m_TotalDescriptorRanges = 0; - RootParameter *m_pRootTables = nullptr; - RootParameter *m_pRootViews = nullptr; - }; - - static constexpr Uint8 InvalidRootTableIndex = static_cast(-1); - - // The array below contains array index of a CBV/SRV/UAV root table - // in m_RootParams (NOT the Root Index!), for every variable type - // (static, mutable, dynamic) and every shader type, - // or -1, if the table is not yet assigned to the combination - Uint8 m_SrvCbvUavRootTablesMap[SHADER_VARIABLE_TYPE_NUM_TYPES * 6]; - // This array contains the same data for Sampler root table - Uint8 m_SamplerRootTablesMap[SHADER_VARIABLE_TYPE_NUM_TYPES * 6]; - - RootParamsManager m_RootParams; - - struct StaticSamplerAttribs - { - StaticSamplerDesc SamplerDesc; - UINT ShaderRegister = static_cast(-1); - UINT ArraySize = 0; - UINT RegisterSpace = 0; - Vk_SHADER_VISIBILITY ShaderVisibility = static_cast(-1); - - StaticSamplerAttribs(){} - StaticSamplerAttribs(const StaticSamplerDesc& SamDesc, Vk_SHADER_VISIBILITY Visibility) : - SamplerDesc(SamDesc), - ShaderVisibility(Visibility) - {} - }; - // Note: sizeof(m_StaticSamplers) == 56 (MS compiler, release x64) - std::vector > m_StaticSamplers; - - IMemoryAllocator &m_MemAllocator; - - // Commits descriptor handles for static and mutable variables - template - void CommitDescriptorHandlesInternal_SM(class RenderDeviceVkImpl *pRenderDeviceVk, - ShaderResourceCacheVk& ResourceCache, - class CommandContext &Ctx, - bool IsCompute)const; - template - // Commits descriptor handles for static, mutable, and dynamic variables - void CommitDescriptorHandlesInternal_SMD(class RenderDeviceVkImpl *pRenderDeviceVk, - ShaderResourceCacheVk& ResourceCache, - class CommandContext &Ctx, - bool IsCompute)const; -}; -#endif -} diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp new file mode 100644 index 00000000..8c3ec83a --- /dev/null +++ b/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp @@ -0,0 +1,1241 @@ +/* Copyright 2015-2018 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include "pch.h" + +#include "PipelineLayout.h" +#include "ShaderResourceLayoutVk.h" +#include "ShaderVkImpl.h" +#include "CommandContext.h" +#include "RenderDeviceVkImpl.h" +#include "TextureVkImpl.h" +#include "BufferVkImpl.h" +#include "VulkanTypeConversions.h" +#include "HashUtils.h" + +namespace Diligent +{ + + +PipelineLayout::DescriptorSetLayoutManager::DescriptorSetLayoutManager(IMemoryAllocator &MemAllocator): + m_MemAllocator(MemAllocator), + m_DescriptorSetLayouts(STD_ALLOCATOR_RAW_MEM(DescriptorSetLayout, MemAllocator, "Allocator for Decriptor Set Layouts")), + m_LayoutBindings(STD_ALLOCATOR_RAW_MEM(VkDescriptorSetLayoutBinding, MemAllocator, "Allocator for Layout Bindings")) +{} + + +void PipelineLayout::DescriptorSetLayoutManager::DescriptorSetLayout::AddBinding(const VkDescriptorSetLayoutBinding &Binding, IMemoryAllocator &MemAllocator) +{ + VERIFY(VkLayout == VK_NULL_HANDLE, "Descriptor set must not be finalized"); + ReserveMemory(BindingCount + 1, MemAllocator); + pBindings[BindingCount++] = Binding; +} + +size_t PipelineLayout::DescriptorSetLayoutManager::DescriptorSetLayout::GetMemorySize(Uint32 NumBindings) +{ + if(NumBindings == 0) + return 0; + + // Align up to the nearest power of two + size_t MemSize = 0; + if(NumBindings == 1) + MemSize = 1; + else if(NumBindings > 1) + { + // NumBindings = 2^n + // n n-1 2 1 0 + // 2^n = 1 0 ... 0 0 0 + // + // n n-1 2 1 0 + // 2^n-1 = 0 1 ... 1 1 1 + // msb = n-1 + // MemSize = 2^n + + + // NumBindings = 2^n + [1 .. 2^n-1] + // n n-1 + // 2^n = 1 0 ... 1 ... + // + // n n-1 + // 2^n-1 = 1 0 ... + // msb = n + // MemSize = 2^(n+1) + + MemSize = Uint32{1U << PlatformMisc::GetMSB(NumBindings-1)}; + } + VERIFY_EXPR(NumBindings <= MemSize); + +#ifdef _DEBUG + static constexpr size_t MinMemSize = 1; +#else + static constexpr size_t MinMemSize = 16; +#endif + MemSize = std::max(MemSize, MinMemSize); + return MemSize; +} + +void PipelineLayout::DescriptorSetLayoutManager::DescriptorSetLayout::ReserveMemory(Uint32 NumBindings, IMemoryAllocator &MemAllocator) +{ + size_t ReservedMemory = GetMemorySize(BindingCount); + size_t RequiredMemory = GetMemorySize(NumBindings); + if(RequiredMemory > ReservedMemory) + { + void *pNewBindings = ALLOCATE(MemAllocator, "Memory buffer for descriptor set layout bindings", RequiredMemory); + if(pBindings != nullptr) + { + memcpy(pNewBindings, pBindings, sizeof(VkDescriptorSetLayoutBinding) * BindingCount); + MemAllocator.Free(pBindings); + } + pBindings = reinterpret_cast(pNewBindings); + } +} + +void PipelineLayout::DescriptorSetLayoutManager::DescriptorSetLayout::Finalize(const VulkanUtilities::VulkanLogicalDevice &LogicalDevice, + IMemoryAllocator &MemAllocator, + VkDescriptorSetLayoutBinding* pNewBindings) +{ + VERIFY_EXPR( memcmp(pBindings, pNewBindings, sizeof(VkDescriptorSetLayoutBinding)*BindingCount) == 0 ); + + VkDescriptorSetLayoutCreateInfo SetLayoutCI = {}; + SetLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + SetLayoutCI.pNext = nullptr; + SetLayoutCI.flags = 0; + SetLayoutCI.bindingCount = BindingCount; + SetLayoutCI.pBindings = pBindings; + VkLayout = LogicalDevice.CreateDescriptorSetLayout(SetLayoutCI); + + MemAllocator.Free(pBindings); + pBindings = pNewBindings; +} + +void PipelineLayout::DescriptorSetLayoutManager::DescriptorSetLayout::Release(RenderDeviceVkImpl *pRenderDeviceVk) +{ + pRenderDeviceVk->SafeReleaseVkObject(std::move(VkLayout)); + pBindings = nullptr; + BindingCount = 0; +} + +PipelineLayout::DescriptorSetLayoutManager::DescriptorSetLayout::~DescriptorSetLayout() +{ + VERIFY(VkLayout == VK_NULL_HANDLE, "Vulkan descriptor set layout has not been released. Did you forget to call Release()?"); +} + +bool PipelineLayout::DescriptorSetLayoutManager::DescriptorSetLayout::operator == (const DescriptorSetLayout& rhs)const +{ + if(ShaderVarType != rhs.ShaderVarType || + BindingCount != rhs.BindingCount) + return false; + + for(uint32_t b=0; b < BindingCount; ++b) + { + const auto &B0 = pBindings[b]; + const auto &B1 = rhs.pBindings[b]; + if(B0.binding != B1.binding || + B0.descriptorType != B1.descriptorType || + B0.descriptorCount != B1.descriptorCount || + B0.stageFlags != B1.stageFlags) + return false; + + if( B0.pImmutableSamplers != nullptr && B1.pImmutableSamplers == nullptr || + B0.pImmutableSamplers == nullptr && B1.pImmutableSamplers != nullptr) + return false; + if(B0.pImmutableSamplers != nullptr && B1.pImmutableSamplers != nullptr) + { + // If descriptorType is VK_DESCRIPTOR_TYPE_SAMPLER or VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + // and descriptorCount is not 0 and pImmutableSamplers is not NULL, pImmutableSamplers must be a + // valid pointer to an array of descriptorCount valid VkSampler handles (13.2.1) + if(memcmp(B0.pImmutableSamplers, B1.pImmutableSamplers, sizeof(VkSampler) * B0.descriptorCount) != 0) + return false; + } + } + return true; +} + +void PipelineLayout::DescriptorSetLayoutManager::Finalize(const VulkanUtilities::VulkanLogicalDevice &LogicalDevice) +{ + size_t TotalBindings = 0; + for (const auto &Layout : m_DescriptorSetLayouts) + { + TotalBindings += Layout.BindingCount; + } + m_LayoutBindings.resize(TotalBindings); + size_t BindingOffset = 0; + for(size_t i=0; i < m_DescriptorSetLayouts.size(); ++i) + { + auto &Layout = m_DescriptorSetLayouts[i]; + std::copy(Layout.pBindings, Layout.pBindings + Layout.BindingCount, m_LayoutBindings.begin() + BindingOffset); + Layout.Finalize(LogicalDevice, m_MemAllocator, &m_LayoutBindings[BindingOffset]); + BindingOffset += Layout.BindingCount; + } + + VkPipelineLayoutCreateInfo PipelineLayoutCI = {}; + PipelineLayoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + PipelineLayoutCI.pNext = nullptr; + PipelineLayoutCI.flags = 0; // reserved for future use + PipelineLayoutCI.setLayoutCount = static_cast(m_DescriptorSetLayouts.size()); + + std::vector > + VkDescrSetLayout(m_DescriptorSetLayouts.size(), + VK_NULL_HANDLE, + STD_ALLOCATOR_RAW_MEM(VkDescriptorSetLayout, m_MemAllocator, "Allocator for vector")); + for(size_t i=0; i < m_DescriptorSetLayouts.size(); ++i) + VkDescrSetLayout[i] = m_DescriptorSetLayouts[i].VkLayout; + PipelineLayoutCI.pSetLayouts = !VkDescrSetLayout.empty() ? VkDescrSetLayout.data() : nullptr; + PipelineLayoutCI.pushConstantRangeCount = 0; + PipelineLayoutCI.pPushConstantRanges = nullptr; + m_VkPipelineLayout = LogicalDevice.CreatePipelineLayout(PipelineLayoutCI); + + VERIFY_EXPR(BindingOffset == TotalBindings); +} + +void PipelineLayout::DescriptorSetLayoutManager::Release(RenderDeviceVkImpl *pRenderDeviceVk) +{ + for (auto &Layout : m_DescriptorSetLayouts) + Layout.Release(pRenderDeviceVk); + + pRenderDeviceVk->SafeReleaseVkObject(std::move(m_VkPipelineLayout)); +} + +PipelineLayout::DescriptorSetLayoutManager::~DescriptorSetLayoutManager() +{ + VERIFY(m_VkPipelineLayout == VK_NULL_HANDLE, "Vulkan pipeline layout has not been released. Did you forget to call Release()?"); +} + +bool PipelineLayout::DescriptorSetLayoutManager::operator == (const DescriptorSetLayoutManager& rhs)const +{ + if(m_DescriptorSetLayouts.size() != rhs.m_DescriptorSetLayouts.size()) + return false; + + for(size_t i=0; i < m_DescriptorSetLayouts.size(); ++i) + if(m_DescriptorSetLayouts[i] != rhs.m_DescriptorSetLayouts[i]) + return false; + + return m_VarTypeToDescrSetLayout == rhs.m_VarTypeToDescrSetLayout; +} + + +#if 0 +size_t PipelineLayout::DescriptorSetLayoutManager::GetRequiredMemorySize(Uint32 NumExtraRootTables, Uint32 NumExtraRootViews, Uint32 NumExtraDescriptorRanges)const +{ + return sizeof(RootParameter) * (m_NumRootTables + NumExtraRootTables + m_NumRootViews + NumExtraRootViews) + sizeof(Vk_DESCRIPTOR_RANGE) * (m_TotalDescriptorRanges + NumExtraDescriptorRanges); +} + +Vk_DESCRIPTOR_RANGE* PipelineLayout::DescriptorSetLayoutManager::Extend(Uint32 NumExtraRootTables, Uint32 NumExtraRootViews, Uint32 NumExtraDescriptorRanges, Uint32 RootTableToAddRanges) +{ + VERIFY(NumExtraRootTables > 0 || NumExtraRootViews > 0 || NumExtraDescriptorRanges > 0, "At least one root table, root view or descriptor range must be added" ); + auto MemorySize = GetRequiredMemorySize(NumExtraRootTables, NumExtraRootViews, NumExtraDescriptorRanges); + VERIFY_EXPR(MemorySize > 0); + auto *pNewMemory = ALLOCATE(m_MemAllocator, "Memory buffer for root tables, root views & descriptor ranges", MemorySize); + memset(pNewMemory, 0, MemorySize); + + // Note: this order is more efficient than views->tables->ranges + auto *pNewRootTables = reinterpret_cast(pNewMemory); + auto *pNewRootViews = pNewRootTables + (m_NumRootTables + NumExtraRootTables); + auto *pCurrDescriptorRangePtr = reinterpret_cast(pNewRootViews+m_NumRootViews+NumExtraRootViews); + + // Copy existing root tables to new memory + for (Uint32 rt = 0; rt < m_NumRootTables; ++rt) + { + const auto &SrcTbl = GetRootTable(rt); + auto &VkSrcTbl = static_cast(SrcTbl).DescriptorTable; + auto NumRanges = VkSrcTbl.NumDescriptorRanges; + if(rt == RootTableToAddRanges) + { + VERIFY(NumExtraRootTables == 0 || NumExtraRootTables == 1, "Up to one descriptor table can be extended at a time"); + NumRanges += NumExtraDescriptorRanges; + } + new(pNewRootTables + rt) RootParameter(SrcTbl, NumRanges, pCurrDescriptorRangePtr); + pCurrDescriptorRangePtr += NumRanges; + } + + // Copy existing root views to new memory + for (Uint32 rv = 0; rv < m_NumRootViews; ++rv) + { + const auto &SrcView = GetRootView(rv); + new(pNewRootViews + rv) RootParameter(SrcView); + } + + m_pMemory.reset(pNewMemory); + m_NumRootTables += NumExtraRootTables; + m_NumRootViews += NumExtraRootViews; + m_TotalDescriptorRanges += NumExtraDescriptorRanges; + m_pRootTables = m_NumRootTables != 0 ? pNewRootTables : nullptr; + m_pRootViews = m_NumRootViews != 0 ? pNewRootViews : nullptr; + + return pCurrDescriptorRangePtr; +} + +void PipelineLayout::DescriptorSetLayoutManager::AddRootView(Vk_ROOT_PARAMETER_TYPE ParameterType, Uint32 RootIndex, UINT Register, Vk_SHADER_VISIBILITY Visibility, SHADER_VARIABLE_TYPE VarType) +{ + auto *pRangePtr = Extend(0, 1, 0); + VERIFY_EXPR((char*)pRangePtr == (char*)m_pMemory.get() + GetRequiredMemorySize(0, 0, 0)); + new(m_pRootViews + m_NumRootViews-1) RootParameter(ParameterType, RootIndex, Register, 0u, Visibility, VarType); +} +#endif + +PipelineLayout::DescriptorSetLayoutManager::DescriptorSetLayout& PipelineLayout::DescriptorSetLayoutManager::GetDescriptorSet(SHADER_VARIABLE_TYPE VarType) +{ + auto DescrSetLayoutInd = m_VarTypeToDescrSetLayout[VarType]; + if(DescrSetLayoutInd < 0) + { + DescrSetLayoutInd = static_cast(m_DescriptorSetLayouts.size()); + m_DescriptorSetLayouts.emplace_back(VarType); + m_VarTypeToDescrSetLayout[VarType] = DescrSetLayoutInd; + } + + return m_DescriptorSetLayouts[DescrSetLayoutInd]; +} + +#if 0 +void PipelineLayout::DescriptorSetLayoutManager::AddDescriptorSet(SHADER_VARIABLE_TYPE VarType) +{ + VERIFY(m_VkPipelineLayout == VK_NULL_HANDLE, "Pipeline layout must not be finalized to add descriptor set"); + m_DescriptorSetLayouts.emplace_back(VarType); +} + + +void PipelineLayout::DescriptorSetLayoutManager::AddDescriptorRanges(Uint32 RootTableInd, Uint32 NumExtraRanges) +{ + auto *pRangePtr = Extend(0, 0, NumExtraRanges, RootTableInd); + VERIFY_EXPR( (char*)pRangePtr == (char*)m_pMemory.get() + GetRequiredMemorySize(0, 0, 0)); +} + +bool PipelineLayout::DescriptorSetLayoutManager::operator == (const DescriptorSetLayoutManager& RootParams)const +{ + if (m_NumRootTables != RootParams.m_NumRootTables || + m_NumRootViews != RootParams.m_NumRootViews) + return false; + + for (Uint32 rv = 0; rv < m_NumRootViews; ++rv) + { + const auto &RV0 = GetRootView(rv); + const auto &RV1 = RootParams.GetRootView(rv); + if (RV0 != RV1) + return false; + } + + for (Uint32 rv = 0; rv < m_NumRootTables; ++rv) + { + const auto &RT0 = GetRootTable(rv); + const auto &RT1 = RootParams.GetRootTable(rv); + if (RT0 != RT1) + return false; + } + + return true; +} + +size_t PipelineLayout::DescriptorSetLayoutManager::GetHash()const +{ + size_t hash = ComputeHash(m_NumRootTables, m_NumRootViews); + for (Uint32 rv = 0; rv < m_NumRootViews; ++rv) + HashCombine(hash, GetRootView(rv).GetHash()); + + for (Uint32 rv = 0; rv < m_NumRootTables; ++rv) + HashCombine(hash, GetRootTable(rv).GetHash()); + + return hash; +} + +PipelineLayout::PipelineLayout() : + m_RootParams(GetRawAllocator()), + m_MemAllocator(GetRawAllocator()), + m_StaticSamplers( STD_ALLOCATOR_RAW_MEM(StaticSamplerAttribs, GetRawAllocator(), "Allocator for vector") ) +{ + for(size_t s=0; s < SHADER_VARIABLE_TYPE_NUM_TYPES; ++s) + { + m_TotalSrvCbvUavSlots[s] = 0; + m_TotalSamplerSlots[s] = 0; + } + + for(size_t i=0; i < _countof(m_SrvCbvUavRootTablesMap); ++i) + m_SrvCbvUavRootTablesMap[i] = InvalidRootTableIndex; + for(size_t i=0; i < _countof(m_SamplerRootTablesMap); ++i) + m_SamplerRootTablesMap[i] = InvalidRootTableIndex; + +} + +static Vk_SHADER_VISIBILITY ShaderTypeInd2ShaderVisibilityMap[] +{ + Vk_SHADER_VISIBILITY_VERTEX, // 0 + Vk_SHADER_VISIBILITY_PIXEL, // 1 + Vk_SHADER_VISIBILITY_GEOMETRY, // 2 + Vk_SHADER_VISIBILITY_HULL, // 3 + Vk_SHADER_VISIBILITY_DOMAIN, // 4 + Vk_SHADER_VISIBILITY_ALL // 5 +}; +Vk_SHADER_VISIBILITY GetShaderVisibility(SHADER_TYPE ShaderType) +{ + auto ShaderInd = GetShaderTypeIndex(ShaderType); + auto ShaderVisibility = ShaderTypeInd2ShaderVisibilityMap[ShaderInd]; +#ifdef _DEBUG + switch (ShaderType) + { + case SHADER_TYPE_VERTEX: VERIFY_EXPR(ShaderVisibility == Vk_SHADER_VISIBILITY_VERTEX); break; + case SHADER_TYPE_PIXEL: VERIFY_EXPR(ShaderVisibility == Vk_SHADER_VISIBILITY_PIXEL); break; + case SHADER_TYPE_GEOMETRY: VERIFY_EXPR(ShaderVisibility == Vk_SHADER_VISIBILITY_GEOMETRY); break; + case SHADER_TYPE_HULL: VERIFY_EXPR(ShaderVisibility == Vk_SHADER_VISIBILITY_HULL); break; + case SHADER_TYPE_DOMAIN: VERIFY_EXPR(ShaderVisibility == Vk_SHADER_VISIBILITY_DOMAIN); break; + case SHADER_TYPE_COMPUTE: VERIFY_EXPR(ShaderVisibility == Vk_SHADER_VISIBILITY_ALL); break; + default: LOG_ERROR("Unknown shader type (", ShaderType, ")"); break; + } +#endif + return ShaderVisibility; +} + +static SHADER_TYPE ShaderVisibility2ShaderTypeMap[] = +{ + SHADER_TYPE_COMPUTE, // Vk_SHADER_VISIBILITY_ALL = 0 + SHADER_TYPE_VERTEX, // Vk_SHADER_VISIBILITY_VERTEX = 1 + SHADER_TYPE_HULL, // Vk_SHADER_VISIBILITY_HULL = 2 + SHADER_TYPE_DOMAIN, // Vk_SHADER_VISIBILITY_DOMAIN = 3 + SHADER_TYPE_GEOMETRY, // Vk_SHADER_VISIBILITY_GEOMETRY = 4 + SHADER_TYPE_PIXEL // Vk_SHADER_VISIBILITY_PIXEL = 5 +}; +SHADER_TYPE ShaderTypeFromShaderVisibility(Vk_SHADER_VISIBILITY ShaderVisibility) +{ + VERIFY_EXPR(ShaderVisibility >= Vk_SHADER_VISIBILITY_ALL && ShaderVisibility <= Vk_SHADER_VISIBILITY_PIXEL ); + auto ShaderType = ShaderVisibility2ShaderTypeMap[ShaderVisibility]; +#ifdef _DEBUG + switch (ShaderVisibility) + { + case Vk_SHADER_VISIBILITY_VERTEX: VERIFY_EXPR(ShaderType == SHADER_TYPE_VERTEX); break; + case Vk_SHADER_VISIBILITY_PIXEL: VERIFY_EXPR(ShaderType == SHADER_TYPE_PIXEL); break; + case Vk_SHADER_VISIBILITY_GEOMETRY: VERIFY_EXPR(ShaderType == SHADER_TYPE_GEOMETRY); break; + case Vk_SHADER_VISIBILITY_HULL: VERIFY_EXPR(ShaderType == SHADER_TYPE_HULL); break; + case Vk_SHADER_VISIBILITY_DOMAIN: VERIFY_EXPR(ShaderType == SHADER_TYPE_DOMAIN); break; + case Vk_SHADER_VISIBILITY_ALL: VERIFY_EXPR(ShaderType == SHADER_TYPE_COMPUTE); break; + default: LOG_ERROR("Unknown shader visibility (", ShaderVisibility, ")"); break; + } +#endif + return ShaderType; +} + + +static Vk_DESCRIPTOR_HEAP_TYPE RangeType2HeapTypeMap[] +{ + Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, //Vk_DESCRIPTOR_RANGE_TYPE_SRV = 0, + Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, //Vk_DESCRIPTOR_RANGE_TYPE_UAV = ( Vk_DESCRIPTOR_RANGE_TYPE_SRV + 1 ) , + Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, //Vk_DESCRIPTOR_RANGE_TYPE_CBV = ( Vk_DESCRIPTOR_RANGE_TYPE_UAV + 1 ) , + Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER //Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER = ( Vk_DESCRIPTOR_RANGE_TYPE_CBV + 1 ) +}; +Vk_DESCRIPTOR_HEAP_TYPE HeapTypeFromRangeType(Vk_DESCRIPTOR_RANGE_TYPE RangeType) +{ + VERIFY_EXPR(RangeType >= Vk_DESCRIPTOR_RANGE_TYPE_SRV && RangeType <= Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER); + auto HeapType = RangeType2HeapTypeMap[RangeType]; + +#ifdef _DEBUG + switch (RangeType) + { + case Vk_DESCRIPTOR_RANGE_TYPE_CBV: VERIFY_EXPR(HeapType == Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); break; + case Vk_DESCRIPTOR_RANGE_TYPE_SRV: VERIFY_EXPR(HeapType == Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); break; + case Vk_DESCRIPTOR_RANGE_TYPE_UAV: VERIFY_EXPR(HeapType == Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); break; + case Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER: VERIFY_EXPR(HeapType == Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER); break; + default: UNEXPECTED("Unexpected descriptor range type"); break; + } +#endif + return HeapType; +} + + +void PipelineLayout::InitStaticSampler(SHADER_TYPE ShaderType, const String &TextureName, const D3DShaderResourceAttribs &SamplerAttribs) +{ + auto ShaderVisibility = GetShaderVisibility(ShaderType); + auto SamplerFound = false; + for (auto &StSmplr : m_StaticSamplers) + { + if (StSmplr.ShaderVisibility == ShaderVisibility && + TextureName.compare(StSmplr.SamplerDesc.TextureName) == 0) + { + StSmplr.ShaderRegister = SamplerAttribs.BindPoint; + StSmplr.ArraySize = SamplerAttribs.BindCount; + StSmplr.RegisterSpace = 0; + SamplerFound = true; + break; + } + } + + if (!SamplerFound) + { + LOG_ERROR("Failed to find static sampler for variable \"", TextureName, '\"'); + } +} + +// http://diligentgraphics.com/diligent-engine/architecture/Vk/shader-resource-layout#Initializing-Shader-Resource-Layouts-and-Root-Signature-in-a-Pipeline-State-Object +void PipelineLayout::AllocateResourceSlot(SHADER_TYPE ShaderType, + const D3DShaderResourceAttribs &ShaderResAttribs, + Vk_DESCRIPTOR_RANGE_TYPE RangeType, + Uint32 &RootIndex, // Output parameter + Uint32 &OffsetFromTableStart // Output parameter + ) +{ + auto ShaderInd = GetShaderTypeIndex(ShaderType); + auto ShaderVisibility = GetShaderVisibility(ShaderType); + if (RangeType == Vk_DESCRIPTOR_RANGE_TYPE_CBV && ShaderResAttribs.BindCount == 1) + { + // Allocate single CBV directly in the root signature + + // Get the next available root index past all allocated tables and root views + RootIndex = m_RootParams.GetNumRootTables() + m_RootParams.GetNumRootViews(); + OffsetFromTableStart = 0; + + // Add new root view to existing root parameters + m_RootParams.AddRootView(Vk_ROOT_PARAMETER_TYPE_CBV, RootIndex, ShaderResAttribs.BindPoint, ShaderVisibility, ShaderResAttribs.GetVariableType()); + } + else + { + // Use the same table for static and mutable resources. Treat both as static + auto RootTableType = (ShaderResAttribs.GetVariableType() == SHADER_VARIABLE_TYPE_DYNAMIC) ? SHADER_VARIABLE_TYPE_DYNAMIC : SHADER_VARIABLE_TYPE_STATIC; + auto TableIndKey = ShaderInd * SHADER_VARIABLE_TYPE_NUM_TYPES + RootTableType; + // Get the table array index (this is not the root index!) + auto &RootTableArrayInd = (( RangeType == Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER ) ? m_SamplerRootTablesMap : m_SrvCbvUavRootTablesMap)[ TableIndKey ]; + if (RootTableArrayInd == InvalidRootTableIndex) + { + // Root table has not been assigned to this combination yet + + // Get the next available root index past all allocated tables and root views + RootIndex = m_RootParams.GetNumRootTables() + m_RootParams.GetNumRootViews(); + VERIFY_EXPR(m_RootParams.GetNumRootTables() < 255); + RootTableArrayInd = static_cast( m_RootParams.GetNumRootTables() ); + // Add root table with one single-descriptor range + m_RootParams.AddRootTable(RootIndex, ShaderVisibility, RootTableType, 1); + } + else + { + // Add a new single-descriptor range to the existing table at index RootTableArrayInd + m_RootParams.AddDescriptorRanges(RootTableArrayInd, 1); + } + + // Reference to either existing or just added table + auto &CurrParam = m_RootParams.GetRootTable(RootTableArrayInd); + RootIndex = CurrParam.GetRootIndex(); + + const auto& VkRootParam = static_cast(CurrParam); + + VERIFY( VkRootParam.ShaderVisibility == ShaderVisibility, "Shader visibility is not correct" ); + + // Descriptors are tightly packed, so the next descriptor offset is the + // current size of the table + OffsetFromTableStart = CurrParam.GetDescriptorTableSize(); + + // New just added range is the last range in the descriptor table + Uint32 NewDescriptorRangeIndex = VkRootParam.DescriptorTable.NumDescriptorRanges-1; + CurrParam.SetDescriptorRange(NewDescriptorRangeIndex, + RangeType, // Range type (CBV, SRV, UAV or SAMPLER) + ShaderResAttribs.BindPoint, // Shader register + ShaderResAttribs.BindCount, // Number of registers used (1 for non-array resources) + 0, // Register space. Always 0 for now + OffsetFromTableStart // Offset in descriptors from the table start + ); + } +} + + +#ifdef _DEBUG +void PipelineLayout::dbgVerifyRootParameters()const +{ + Uint32 dbgTotalSrvCbvUavSlots = 0; + Uint32 dbgTotalSamplerSlots = 0; + for(Uint32 rt = 0; rt < m_RootParams.GetNumRootTables(); ++rt) + { + auto &RootTable = m_RootParams.GetRootTable(rt); + auto &Param = static_cast( RootTable ); + VERIFY(Param.ParameterType == Vk_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, "Root parameter is expected to be a descriptor table"); + auto &Table = Param.DescriptorTable; + VERIFY(Table.NumDescriptorRanges > 0, "Descriptor table is expected to be non-empty"); + VERIFY(Table.pDescriptorRanges[0].OffsetInDescriptorsFromTableStart == 0, "Descriptor table is expected to start at 0 offset"); + bool IsResourceTable = Table.pDescriptorRanges[0].RangeType != Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER; + for (Uint32 r = 0; r < Table.NumDescriptorRanges; ++r) + { + const auto &range = Table.pDescriptorRanges[r]; + if(IsResourceTable) + { + VERIFY( range.RangeType == Vk_DESCRIPTOR_RANGE_TYPE_SRV || + range.RangeType == Vk_DESCRIPTOR_RANGE_TYPE_CBV || + range.RangeType == Vk_DESCRIPTOR_RANGE_TYPE_UAV, "Resource type is expected to be SRV, CBV or UAV"); + dbgTotalSrvCbvUavSlots += range.NumDescriptors; + } + else + { + VERIFY(range.RangeType == Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER, "Resource type is expected to be sampler"); + dbgTotalSamplerSlots += range.NumDescriptors; + } + + if(r>0) + { + VERIFY(Table.pDescriptorRanges[r].OffsetInDescriptorsFromTableStart == Table.pDescriptorRanges[r-1].OffsetInDescriptorsFromTableStart+Table.pDescriptorRanges[r-1].NumDescriptors, "Ranges in a descriptor table are expected to be consequtive"); + } + } + } + + for(Uint32 rv = 0; rv < m_RootParams.GetNumRootViews(); ++rv) + { + auto &RootView = m_RootParams.GetRootView(rv); + auto &Param = static_cast( RootView ); + VERIFY(Param.ParameterType == Vk_ROOT_PARAMETER_TYPE_CBV, "Root parameter is expected to be a CBV"); + } + + VERIFY(dbgTotalSrvCbvUavSlots == + m_TotalSrvCbvUavSlots[SHADER_VARIABLE_TYPE_STATIC] + + m_TotalSrvCbvUavSlots[SHADER_VARIABLE_TYPE_MUTABLE] + + m_TotalSrvCbvUavSlots[SHADER_VARIABLE_TYPE_DYNAMIC], "Unexpected number of SRV CBV UAV resource slots"); + VERIFY(dbgTotalSamplerSlots == + m_TotalSamplerSlots[SHADER_VARIABLE_TYPE_STATIC] + + m_TotalSamplerSlots[SHADER_VARIABLE_TYPE_MUTABLE] + + m_TotalSamplerSlots[SHADER_VARIABLE_TYPE_DYNAMIC], "Unexpected number of sampler slots"); +} +#endif + +void PipelineLayout::AllocateStaticSamplers(IShader* const*ppShaders, Uint32 NumShaders) +{ + Uint32 TotalSamplers = 0; + for(Uint32 s=0;s < NumShaders; ++s) + TotalSamplers += ppShaders[s]->GetDesc().NumStaticSamplers; + if (TotalSamplers > 0) + { + m_StaticSamplers.reserve(TotalSamplers); + for(Uint32 sh=0;sh < NumShaders; ++sh) + { + const auto &Desc = ppShaders[sh]->GetDesc(); + for(Uint32 sam=0; sam < Desc.NumStaticSamplers; ++sam) + { + m_StaticSamplers.emplace_back(Desc.StaticSamplers[sam], GetShaderVisibility(Desc.ShaderType)); + } + } + VERIFY_EXPR(m_StaticSamplers.size() == TotalSamplers); + } +} + +void PipelineLayout::Finalize(IVkDevice *pVkDevice) +{ + for(Uint32 rt = 0; rt < m_RootParams.GetNumRootTables(); ++rt) + { + auto &RootTbl = m_RootParams.GetRootTable(rt); + auto &VkRootParam = static_cast(RootTbl); + VERIFY_EXPR(VkRootParam.ParameterType == Vk_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE); + + auto TableSize = RootTbl.GetDescriptorTableSize(); + VERIFY(VkRootParam.DescriptorTable.NumDescriptorRanges > 0 && TableSize > 0, "Unexpected empty descriptor table"); + auto IsSamplerTable = VkRootParam.DescriptorTable.pDescriptorRanges[0].RangeType == Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER; + auto VarType = RootTbl.GetShaderVariableType(); + (IsSamplerTable ? m_TotalSamplerSlots : m_TotalSrvCbvUavSlots)[VarType] += TableSize; + } + +#ifdef _DEBUG + dbgVerifyRootParameters(); +#endif + + Vk_ROOT_SIGNATURE_DESC PipelineLayoutDesc; + PipelineLayoutDesc.Flags = Vk_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; + + auto TotalParams = m_RootParams.GetNumRootTables() + m_RootParams.GetNumRootViews(); + std::vector > VkParameters( TotalParams, Vk_ROOT_PARAMETER(), STD_ALLOCATOR_RAW_MEM(Vk_ROOT_PARAMETER, GetRawAllocator(), "Allocator for vector") ); + for(Uint32 rt = 0; rt < m_RootParams.GetNumRootTables(); ++rt) + { + auto &RootTable = m_RootParams.GetRootTable(rt); + const Vk_ROOT_PARAMETER &SrcParam = RootTable; + VERIFY( SrcParam.ParameterType == Vk_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE && SrcParam.DescriptorTable.NumDescriptorRanges > 0, "Non-empty descriptor table is expected" ); + VkParameters[RootTable.GetRootIndex()] = SrcParam; + } + for(Uint32 rv = 0; rv < m_RootParams.GetNumRootViews(); ++rv) + { + auto &RootView = m_RootParams.GetRootView(rv); + const Vk_ROOT_PARAMETER &SrcParam = RootView; + VERIFY( SrcParam.ParameterType == Vk_ROOT_PARAMETER_TYPE_CBV, "Root CBV is expected" ); + VkParameters[RootView.GetRootIndex()] = SrcParam; + } + + + PipelineLayoutDesc.NumParameters = static_cast(VkParameters.size()); + PipelineLayoutDesc.pParameters = VkParameters.size() ? VkParameters.data() : nullptr; + + UINT TotalVkStaticSamplers = 0; + for(const auto &StSam : m_StaticSamplers) + TotalVkStaticSamplers += StSam.ArraySize; + PipelineLayoutDesc.NumStaticSamplers = TotalVkStaticSamplers; + PipelineLayoutDesc.pStaticSamplers = nullptr; + std::vector > VkStaticSamplers( STD_ALLOCATOR_RAW_MEM(Vk_STATIC_SAMPLER_DESC, GetRawAllocator(), "Allocator for vector") ); + VkStaticSamplers.reserve(TotalVkStaticSamplers); + if ( !m_StaticSamplers.empty() ) + { + for(size_t s=0; s < m_StaticSamplers.size(); ++s) + { + const auto &StSmplrDesc = m_StaticSamplers[s]; + const auto &SamDesc = StSmplrDesc.SamplerDesc.Desc; + for(UINT ArrInd = 0; ArrInd < StSmplrDesc.ArraySize; ++ArrInd) + { + VkStaticSamplers.emplace_back( + Vk_STATIC_SAMPLER_DESC{ + FilterTypeToVkFilter(SamDesc.MinFilter, SamDesc.MagFilter, SamDesc.MipFilter), + TexAddressModeToVkAddressMode(SamDesc.AddressU), + TexAddressModeToVkAddressMode(SamDesc.AddressV), + TexAddressModeToVkAddressMode(SamDesc.AddressW), + SamDesc.MipLODBias, + SamDesc.MaxAnisotropy, + ComparisonFuncToVkComparisonFunc(SamDesc.ComparisonFunc), + BorderColorToVkStaticBorderColor(SamDesc.BorderColor), + SamDesc.MinLOD, + SamDesc.MaxLOD, + StSmplrDesc.ShaderRegister + ArrInd, + StSmplrDesc.RegisterSpace, + StSmplrDesc.ShaderVisibility + } + ); + } + } + PipelineLayoutDesc.pStaticSamplers = VkStaticSamplers.data(); + + // Release static samplers array, we no longer need it + std::vector > EmptySamplers( STD_ALLOCATOR_RAW_MEM(StaticSamplerAttribs, GetRawAllocator(), "Allocator for vector") ); + m_StaticSamplers.swap( EmptySamplers ); + + VERIFY_EXPR(VkStaticSamplers.size() == TotalVkStaticSamplers); + } + + + CComPtr signature; + CComPtr error; + HRESULT hr = VkSerializePipelineLayout(&PipelineLayoutDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error); + hr = pVkDevice->CreatePipelineLayout(0, signature->GetBufferPointer(), signature->GetBufferSize(), __uuidof(m_pVkPipelineLayout), reinterpret_cast( static_cast(&m_pVkPipelineLayout))); + CHECK_D3D_RESULT_THROW(hr, "Failed to create root signature"); + + bool bHasDynamicResources = m_TotalSrvCbvUavSlots[SHADER_VARIABLE_TYPE_DYNAMIC]!=0 || m_TotalSamplerSlots[SHADER_VARIABLE_TYPE_DYNAMIC]!=0; + if(bHasDynamicResources) + { + CommitDescriptorHandles = &PipelineLayout::CommitDescriptorHandlesInternal_SMD; + TransitionAndCommitDescriptorHandles = &PipelineLayout::CommitDescriptorHandlesInternal_SMD; + } + else + { + CommitDescriptorHandles = &PipelineLayout::CommitDescriptorHandlesInternal_SM; + TransitionAndCommitDescriptorHandles = &PipelineLayout::CommitDescriptorHandlesInternal_SM; + } +} + +//http://diligentgraphics.com/diligent-engine/architecture/Vk/shader-resource-cache#Initializing-the-Cache-for-Shader-Resource-Binding-Object +void PipelineLayout::InitResourceCache(RenderDeviceVkImpl *pDeviceVkImpl, ShaderResourceCacheVk& ResourceCache, IMemoryAllocator &CacheMemAllocator)const +{ + // Get root table size for every root index + // m_RootParams keeps root tables sorted by the array index, not the root index + // Root views are treated as one-descriptor tables + std::vector > CacheTableSizes(m_RootParams.GetNumRootTables() + m_RootParams.GetNumRootViews(), 0, STD_ALLOCATOR_RAW_MEM(Uint32, GetRawAllocator(), "Allocator for vector") ); + for(Uint32 rt = 0; rt < m_RootParams.GetNumRootTables(); ++rt) + { + auto &RootParam = m_RootParams.GetRootTable(rt); + CacheTableSizes[RootParam.GetRootIndex()] = RootParam.GetDescriptorTableSize(); + } + + for(Uint32 rv = 0; rv < m_RootParams.GetNumRootViews(); ++rv) + { + auto &RootParam = m_RootParams.GetRootView(rv); + CacheTableSizes[RootParam.GetRootIndex()] = 1; + } + // Initialize resource cache to hold root tables + ResourceCache.Initialize(CacheMemAllocator, static_cast(CacheTableSizes.size()), CacheTableSizes.data()); + + // Allocate space in GPU-visible descriptor heap for static and mutable variables only + Uint32 TotalSrvCbvUavDescriptors = + m_TotalSrvCbvUavSlots[SHADER_VARIABLE_TYPE_STATIC] + + m_TotalSrvCbvUavSlots[SHADER_VARIABLE_TYPE_MUTABLE]; + Uint32 TotalSamplerDescriptors = + m_TotalSamplerSlots[SHADER_VARIABLE_TYPE_STATIC] + + m_TotalSamplerSlots[SHADER_VARIABLE_TYPE_MUTABLE]; + + DescriptorHeapAllocation CbcSrvUavHeapSpace, SamplerHeapSpace; + if(TotalSrvCbvUavDescriptors) + CbcSrvUavHeapSpace = pDeviceVkImpl->AllocateGPUDescriptors(Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, TotalSrvCbvUavDescriptors); + VERIFY_EXPR(TotalSrvCbvUavDescriptors == 0 && CbcSrvUavHeapSpace.IsNull() || CbcSrvUavHeapSpace.GetNumHandles() == TotalSrvCbvUavDescriptors); + + if(TotalSamplerDescriptors) + SamplerHeapSpace = pDeviceVkImpl->AllocateGPUDescriptors(Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER, TotalSamplerDescriptors); + VERIFY_EXPR(TotalSamplerDescriptors == 0 && SamplerHeapSpace.IsNull() || SamplerHeapSpace.GetNumHandles() == TotalSamplerDescriptors); + + // Iterate through all root static/mutable tables and assign start offsets. The tables are tightly packed, so + // start offset of table N+1 is start offset of table N plus the size of table N. + // Root tables with dynamic resources as well as root views are not assigned space in GPU-visible allocation + // (root views are simply not processed) + Uint32 SrvCbvUavTblStartOffset = 0; + Uint32 SamplerTblStartOffset = 0; + for(Uint32 rt = 0; rt < m_RootParams.GetNumRootTables(); ++rt) + { + auto &RootParam = m_RootParams.GetRootTable(rt); + const auto& VkRootParam = static_cast(RootParam); + auto &RootTableCache = ResourceCache.GetRootTable(RootParam.GetRootIndex()); + + SHADER_TYPE dbgShaderType = SHADER_TYPE_UNKNOWN; +#ifdef _DEBUG + dbgShaderType = ShaderTypeFromShaderVisibility(VkRootParam.ShaderVisibility); +#endif + VERIFY_EXPR( VkRootParam.ParameterType == Vk_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE ); + + auto TableSize = RootParam.GetDescriptorTableSize(); + VERIFY(TableSize > 0, "Unexpected empty descriptor table"); + + auto HeapType = HeapTypeFromRangeType(VkRootParam.DescriptorTable.pDescriptorRanges[0].RangeType); + +#ifdef _DEBUG + RootTableCache.SetDebugAttribs( TableSize, HeapType, dbgShaderType ); +#endif + + // Space for dynamic variables is allocated at every draw call + if( RootParam.GetShaderVariableType() != SHADER_VARIABLE_TYPE_DYNAMIC ) + { + if( HeapType == Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV ) + { + RootTableCache.m_TableStartOffset = SrvCbvUavTblStartOffset; + SrvCbvUavTblStartOffset += TableSize; + } + else + { + RootTableCache.m_TableStartOffset = SamplerTblStartOffset; + SamplerTblStartOffset += TableSize; + } + } + else + { + VERIFY_EXPR(RootTableCache.m_TableStartOffset == ShaderResourceCacheVk::InvalidDescriptorOffset); + } + } + +#ifdef _DEBUG + for(Uint32 rv = 0; rv < m_RootParams.GetNumRootViews(); ++rv) + { + auto &RootParam = m_RootParams.GetRootView(rv); + const auto& VkRootParam = static_cast(RootParam); + auto &RootTableCache = ResourceCache.GetRootTable(RootParam.GetRootIndex()); + // Root views are not assigned valid table start offset + VERIFY_EXPR(RootTableCache.m_TableStartOffset == ShaderResourceCacheVk::InvalidDescriptorOffset); + + SHADER_TYPE dbgShaderType = ShaderTypeFromShaderVisibility(VkRootParam.ShaderVisibility); + VERIFY_EXPR(VkRootParam.ParameterType == Vk_ROOT_PARAMETER_TYPE_CBV); + RootTableCache.SetDebugAttribs( 1, Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, dbgShaderType ); + } +#endif + + VERIFY_EXPR(SrvCbvUavTblStartOffset == TotalSrvCbvUavDescriptors); + VERIFY_EXPR(SamplerTblStartOffset == TotalSamplerDescriptors); + + ResourceCache.SetDescriptorHeapSpace(std::move(CbcSrvUavHeapSpace), std::move(SamplerHeapSpace)); +} + +const Vk_RESOURCE_STATES Vk_RESOURCE_STATE_SHADER_RESOURCE = Vk_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | Vk_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; + +__forceinline +void TransitionResource(CommandContext &Ctx, + ShaderResourceCacheVk::Resource &Res, + Vk_DESCRIPTOR_RANGE_TYPE RangeType) +{ + switch (Res.Type) + { + case CachedResourceType::CBV: + { + VERIFY(RangeType == Vk_DESCRIPTOR_RANGE_TYPE_CBV, "Unexpected descriptor range type"); + // Not using QueryInterface() for the sake of efficiency + auto *pBuffToTransition = Res.pObject.RawPtr(); + if( !pBuffToTransition->CheckAllStates(Vk_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER) ) + Ctx.TransitionResource(pBuffToTransition, Vk_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER ); + } + break; + + case CachedResourceType::BufSRV: + { + VERIFY(RangeType == Vk_DESCRIPTOR_RANGE_TYPE_SRV, "Unexpected descriptor range type"); + auto *pBuffViewVk = Res.pObject.RawPtr(); + auto *pBuffToTransition = ValidatedCast(pBuffViewVk->GetBuffer()); + if( !pBuffToTransition->CheckAllStates(Vk_RESOURCE_STATE_SHADER_RESOURCE) ) + Ctx.TransitionResource(pBuffToTransition, Vk_RESOURCE_STATE_SHADER_RESOURCE ); + } + break; + + case CachedResourceType::BufUAV: + { + VERIFY(RangeType == Vk_DESCRIPTOR_RANGE_TYPE_UAV, "Unexpected descriptor range type"); + auto *pBuffViewVk = Res.pObject.RawPtr(); + auto *pBuffToTransition = ValidatedCast(pBuffViewVk->GetBuffer()); + if( !pBuffToTransition->CheckAllStates(Vk_RESOURCE_STATE_UNORDERED_ACCESS) ) + Ctx.TransitionResource(pBuffToTransition, Vk_RESOURCE_STATE_UNORDERED_ACCESS ); + } + break; + + case CachedResourceType::TexSRV: + { + VERIFY(RangeType == Vk_DESCRIPTOR_RANGE_TYPE_SRV, "Unexpected descriptor range type"); + auto *pTexViewVk = Res.pObject.RawPtr(); + auto *pTexToTransition = ValidatedCast(pTexViewVk->GetTexture()); + if( !pTexToTransition->CheckAllStates(Vk_RESOURCE_STATE_SHADER_RESOURCE) ) + Ctx.TransitionResource(pTexToTransition, Vk_RESOURCE_STATE_SHADER_RESOURCE ); + } + break; + + case CachedResourceType::TexUAV: + { + VERIFY(RangeType == Vk_DESCRIPTOR_RANGE_TYPE_UAV, "Unexpected descriptor range type"); + auto *pTexViewVk = Res.pObject.RawPtr(); + auto *pTexToTransition = ValidatedCast(pTexViewVk->GetTexture()); + if( !pTexToTransition->CheckAllStates(Vk_RESOURCE_STATE_UNORDERED_ACCESS) ) + Ctx.TransitionResource(pTexToTransition, Vk_RESOURCE_STATE_UNORDERED_ACCESS ); + } + break; + + case CachedResourceType::Sampler: + VERIFY(RangeType == Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER, "Unexpected descriptor range type"); + break; + + default: + // Resource not bound + VERIFY(Res.Type == CachedResourceType::Unknown, "Unexpected resource type"); + VERIFY(Res.pObject == nullptr && Res.CPUDescriptorHandle.ptr == 0, "Bound resource is unexpected"); + } +} + + +#ifdef _DEBUG +void DbgVerifyResourceState(ShaderResourceCacheVk::Resource &Res, + Vk_DESCRIPTOR_RANGE_TYPE RangeType) +{ + switch (Res.Type) + { + case CachedResourceType::CBV: + { + VERIFY(RangeType == Vk_DESCRIPTOR_RANGE_TYPE_CBV, "Unexpected descriptor range type"); + // Not using QueryInterface() for the sake of efficiency + auto *pBuffToTransition = Res.pObject.RawPtr(); + auto State = pBuffToTransition->GetState(); + if( (State & Vk_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER) != Vk_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER ) + LOG_ERROR_MESSAGE("Resource \"", pBuffToTransition->GetDesc().Name, "\" is not in Vk_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER state. Did you forget to call TransitionShaderResources() or specify COMMIT_SHADER_RESOURCES_FLAG_TRANSITION_RESOURCES flag in a call to CommitShaderResources()?" ); + } + break; + + case CachedResourceType::BufSRV: + { + VERIFY(RangeType == Vk_DESCRIPTOR_RANGE_TYPE_SRV, "Unexpected descriptor range type"); + auto *pBuffViewVk = Res.pObject.RawPtr(); + auto *pBuffToTransition = ValidatedCast(pBuffViewVk->GetBuffer()); + auto State = pBuffToTransition->GetState(); + if( (State & Vk_RESOURCE_STATE_SHADER_RESOURCE) != Vk_RESOURCE_STATE_SHADER_RESOURCE ) + LOG_ERROR_MESSAGE("Resource \"", pBuffToTransition->GetDesc().Name, "\" is not in correct state. Did you forget to call TransitionShaderResources() or specify COMMIT_SHADER_RESOURCES_FLAG_TRANSITION_RESOURCES flag in a call to CommitShaderResources()?" ); + } + break; + + case CachedResourceType::BufUAV: + { + VERIFY(RangeType == Vk_DESCRIPTOR_RANGE_TYPE_UAV, "Unexpected descriptor range type"); + auto *pBuffViewVk = Res.pObject.RawPtr(); + auto *pBuffToTransition = ValidatedCast(pBuffViewVk->GetBuffer()); + auto State = pBuffToTransition->GetState(); + if( (State & Vk_RESOURCE_STATE_UNORDERED_ACCESS) != Vk_RESOURCE_STATE_UNORDERED_ACCESS ) + LOG_ERROR_MESSAGE("Resource \"", pBuffToTransition->GetDesc().Name, "\" is not in Vk_RESOURCE_STATE_UNORDERED_ACCESS state. Did you forget to call TransitionShaderResources() or specify COMMIT_SHADER_RESOURCES_FLAG_TRANSITION_RESOURCES flag in a call to CommitShaderResources()?" ); + } + break; + + case CachedResourceType::TexSRV: + { + VERIFY(RangeType == Vk_DESCRIPTOR_RANGE_TYPE_SRV, "Unexpected descriptor range type"); + auto *pTexViewVk = Res.pObject.RawPtr(); + auto *pTexToTransition = ValidatedCast(pTexViewVk->GetTexture()); + auto State = pTexToTransition->GetState(); + if( (State & Vk_RESOURCE_STATE_SHADER_RESOURCE) != Vk_RESOURCE_STATE_SHADER_RESOURCE ) + LOG_ERROR_MESSAGE("Resource \"", pTexToTransition->GetDesc().Name, "\" is not in correct state. Did you forget to call TransitionShaderResources() or specify COMMIT_SHADER_RESOURCES_FLAG_TRANSITION_RESOURCES flag in a call to CommitShaderResources()?" ); + } + break; + + case CachedResourceType::TexUAV: + { + VERIFY(RangeType == Vk_DESCRIPTOR_RANGE_TYPE_UAV, "Unexpected descriptor range type"); + auto *pTexViewVk = Res.pObject.RawPtr(); + auto *pTexToTransition = ValidatedCast(pTexViewVk->GetTexture()); + auto State = pTexToTransition->GetState(); + if( (State & Vk_RESOURCE_STATE_UNORDERED_ACCESS) != Vk_RESOURCE_STATE_UNORDERED_ACCESS ) + LOG_ERROR_MESSAGE("Resource \"", pTexToTransition->GetDesc().Name, "\" is not in Vk_RESOURCE_STATE_UNORDERED_ACCESS state. Did you forget to call TransitionShaderResources() or specify COMMIT_SHADER_RESOURCES_FLAG_TRANSITION_RESOURCES flag in a call to CommitShaderResources()?" ); + } + break; + + case CachedResourceType::Sampler: + VERIFY(RangeType == Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER, "Unexpected descriptor range type"); + break; + + default: + // Resource not bound + VERIFY(Res.Type == CachedResourceType::Unknown, "Unexpected resource type"); + VERIFY(Res.pObject == nullptr && Res.CPUDescriptorHandle.ptr == 0, "Bound resource is unexpected"); + } +} +#endif + +template +__forceinline void PipelineLayout::DescriptorSetLayoutManager::ProcessRootTables(TOperation Operation)const +{ + for(Uint32 rt = 0; rt < m_NumRootTables; ++rt) + { + auto &RootTable = GetRootTable(rt); + auto RootInd = RootTable.GetRootIndex(); + const Vk_ROOT_PARAMETER& VkParam = RootTable; + + VERIFY_EXPR(VkParam.ParameterType == Vk_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE); + + auto &VkTable = VkParam.DescriptorTable; + VERIFY(VkTable.NumDescriptorRanges > 0 && RootTable.GetDescriptorTableSize() > 0, "Unexepected empty descriptor table"); + bool IsResourceTable = VkTable.pDescriptorRanges[0].RangeType != Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER; + Vk_DESCRIPTOR_HEAP_TYPE dbgHeapType = Vk_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; +#ifdef _DEBUG + dbgHeapType = IsResourceTable ? Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV : Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER; +#endif + Operation(RootInd, RootTable, VkParam, IsResourceTable, dbgHeapType); + } +} + +template +__forceinline void ProcessCachedTableResources(Uint32 RootInd, + const Vk_ROOT_PARAMETER& VkParam, + ShaderResourceCacheVk& ResourceCache, + Vk_DESCRIPTOR_HEAP_TYPE dbgHeapType, + TOperation Operation) +{ + for (UINT r = 0; r < VkParam.DescriptorTable.NumDescriptorRanges; ++r) + { + const auto &range = VkParam.DescriptorTable.pDescriptorRanges[r]; + for (UINT d = 0; d < range.NumDescriptors; ++d) + { + SHADER_TYPE dbgShaderType = SHADER_TYPE_UNKNOWN; +#ifdef _DEBUG + dbgShaderType = ShaderTypeFromShaderVisibility(VkParam.ShaderVisibility); + VERIFY(dbgHeapType == HeapTypeFromRangeType(range.RangeType), "Mistmatch between descriptor heap type and descriptor range type"); +#endif + auto OffsetFromTableStart = range.OffsetInDescriptorsFromTableStart + d; + auto& Res = ResourceCache.GetRootTable(RootInd).GetResource(OffsetFromTableStart, dbgHeapType, dbgShaderType); + + Operation(OffsetFromTableStart, range, Res); + } + } +} + + +template +void PipelineLayout::CommitDescriptorHandlesInternal_SMD(RenderDeviceVkImpl *pRenderDeviceVk, + ShaderResourceCacheVk& ResourceCache, + CommandContext &Ctx, + bool IsCompute)const +{ + auto *pVkDevice = pRenderDeviceVk->GetVkDevice(); + + Uint32 NumDynamicCbvSrvUavDescriptors = m_TotalSrvCbvUavSlots[SHADER_VARIABLE_TYPE_DYNAMIC]; + Uint32 NumDynamicSamplerDescriptors = m_TotalSamplerSlots[SHADER_VARIABLE_TYPE_DYNAMIC]; + VERIFY_EXPR(NumDynamicCbvSrvUavDescriptors > 0 || NumDynamicSamplerDescriptors > 0); + + DescriptorHeapAllocation DynamicCbvSrvUavDescriptors, DynamicSamplerDescriptors; + if(NumDynamicCbvSrvUavDescriptors) + DynamicCbvSrvUavDescriptors = Ctx.AllocateDynamicGPUVisibleDescriptor(Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, NumDynamicCbvSrvUavDescriptors); + if(NumDynamicSamplerDescriptors) + DynamicSamplerDescriptors = Ctx.AllocateDynamicGPUVisibleDescriptor(Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER, NumDynamicSamplerDescriptors); + + CommandContext::ShaderDescriptorHeaps Heaps(ResourceCache.GetSrvCbvUavDescriptorHeap(), ResourceCache.GetSamplerDescriptorHeap()); + if(Heaps.pSamplerHeap == nullptr) + Heaps.pSamplerHeap = DynamicSamplerDescriptors.GetDescriptorHeap(); + + if(Heaps.pSrvCbvUavHeap == nullptr) + Heaps.pSrvCbvUavHeap = DynamicCbvSrvUavDescriptors.GetDescriptorHeap(); + + if(NumDynamicCbvSrvUavDescriptors) + VERIFY(DynamicCbvSrvUavDescriptors.GetDescriptorHeap() == Heaps.pSrvCbvUavHeap, "Inconsistent CbvSrvUav descriptor heaps" ); + if(NumDynamicSamplerDescriptors) + VERIFY(DynamicSamplerDescriptors.GetDescriptorHeap() == Heaps.pSamplerHeap, "Inconsistent Sampler descriptor heaps" ); + + if(Heaps) + Ctx.SetDescriptorHeaps(Heaps); + + // Offset to the beginning of the current dynamic CBV_SRV_UAV/SAMPLER table from + // the start of the allocation + Uint32 DynamicCbvSrvUavTblOffset = 0; + Uint32 DynamicSamplerTblOffset = 0; + + m_RootParams.ProcessRootTables( + [&](Uint32 RootInd, const RootParameter &RootTable, const Vk_ROOT_PARAMETER& VkParam, bool IsResourceTable, Vk_DESCRIPTOR_HEAP_TYPE dbgHeapType ) + { + Vk_GPU_DESCRIPTOR_HANDLE RootTableGPUDescriptorHandle; + bool IsDynamicTable = RootTable.GetShaderVariableType() == SHADER_VARIABLE_TYPE_DYNAMIC; + if (IsDynamicTable) + { + if( IsResourceTable ) + RootTableGPUDescriptorHandle = DynamicCbvSrvUavDescriptors.GetGpuHandle(DynamicCbvSrvUavTblOffset); + else + RootTableGPUDescriptorHandle = DynamicSamplerDescriptors.GetGpuHandle(DynamicSamplerTblOffset); + } + else + { + RootTableGPUDescriptorHandle = IsResourceTable ? + ResourceCache.GetShaderVisibleTableGPUDescriptorHandle(RootInd) : + ResourceCache.GetShaderVisibleTableGPUDescriptorHandle(RootInd); + VERIFY(RootTableGPUDescriptorHandle.ptr != 0, "Unexpected null GPU descriptor handle"); + } + + if(IsCompute) + Ctx.GetCommandList()->SetComputeRootDescriptorTable(RootInd, RootTableGPUDescriptorHandle); + else + Ctx.GetCommandList()->SetGraphicsRootDescriptorTable(RootInd, RootTableGPUDescriptorHandle); + + ProcessCachedTableResources(RootInd, VkParam, ResourceCache, dbgHeapType, + [&](UINT OffsetFromTableStart, const Vk_DESCRIPTOR_RANGE &range, ShaderResourceCacheVk::Resource &Res) + { + if(PerformResourceTransitions) + { + TransitionResource(Ctx, Res, range.RangeType); + } +#ifdef _DEBUG + else + { + DbgVerifyResourceState(Res, range.RangeType); + } +#endif + + if(IsDynamicTable) + { + if (IsResourceTable) + { + if( Res.CPUDescriptorHandle.ptr == 0 ) + LOG_ERROR_MESSAGE("No valid CbvSrvUav descriptor handle found for root parameter ", RootInd, ", descriptor slot ", OffsetFromTableStart); + + VERIFY( DynamicCbvSrvUavTblOffset < NumDynamicCbvSrvUavDescriptors, "Not enough space in the descriptor heap allocation"); + + pVkDevice->CopyDescriptorsSimple(1, DynamicCbvSrvUavDescriptors.GetCpuHandle(DynamicCbvSrvUavTblOffset), Res.CPUDescriptorHandle, Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + ++DynamicCbvSrvUavTblOffset; + } + else + { + if( Res.CPUDescriptorHandle.ptr == 0 ) + LOG_ERROR_MESSAGE("No valid sampler descriptor handle found for root parameter ", RootInd, ", descriptor slot ", OffsetFromTableStart); + + VERIFY( DynamicSamplerTblOffset < NumDynamicSamplerDescriptors, "Not enough space in the descriptor heap allocation"); + + pVkDevice->CopyDescriptorsSimple(1, DynamicSamplerDescriptors.GetCpuHandle(DynamicSamplerTblOffset), Res.CPUDescriptorHandle, Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER); + ++DynamicSamplerTblOffset; + } + } + } + ); + } + ); + + VERIFY_EXPR( DynamicCbvSrvUavTblOffset == NumDynamicCbvSrvUavDescriptors ); + VERIFY_EXPR( DynamicSamplerTblOffset == NumDynamicSamplerDescriptors ); +} + +template +void PipelineLayout::CommitDescriptorHandlesInternal_SM(RenderDeviceVkImpl *pRenderDeviceVk, + ShaderResourceCacheVk& ResourceCache, + CommandContext &Ctx, + bool IsCompute)const +{ + VERIFY_EXPR(m_TotalSrvCbvUavSlots[SHADER_VARIABLE_TYPE_DYNAMIC] == 0 && m_TotalSamplerSlots[SHADER_VARIABLE_TYPE_DYNAMIC] == 0); + + CommandContext::ShaderDescriptorHeaps Heaps(ResourceCache.GetSrvCbvUavDescriptorHeap(), ResourceCache.GetSamplerDescriptorHeap()); + if(Heaps) + Ctx.SetDescriptorHeaps(Heaps); + + m_RootParams.ProcessRootTables( + [&](Uint32 RootInd, const RootParameter &RootTable, const Vk_ROOT_PARAMETER& VkParam, bool IsResourceTable, Vk_DESCRIPTOR_HEAP_TYPE dbgHeapType ) + { + VERIFY(RootTable.GetShaderVariableType() != SHADER_VARIABLE_TYPE_DYNAMIC, "Unexpected dynamic resource"); + + Vk_GPU_DESCRIPTOR_HANDLE RootTableGPUDescriptorHandle = IsResourceTable ? + ResourceCache.GetShaderVisibleTableGPUDescriptorHandle(RootInd) : + ResourceCache.GetShaderVisibleTableGPUDescriptorHandle(RootInd); + VERIFY(RootTableGPUDescriptorHandle.ptr != 0, "Unexpected null GPU descriptor handle"); + + if(IsCompute) + Ctx.GetCommandList()->SetComputeRootDescriptorTable(RootInd, RootTableGPUDescriptorHandle); + else + Ctx.GetCommandList()->SetGraphicsRootDescriptorTable(RootInd, RootTableGPUDescriptorHandle); + + if(PerformResourceTransitions) + { + ProcessCachedTableResources(RootInd, VkParam, ResourceCache, dbgHeapType, + [&](UINT OffsetFromTableStart, const Vk_DESCRIPTOR_RANGE &range, ShaderResourceCacheVk::Resource &Res) + { + TransitionResource(Ctx, Res, range.RangeType); + } + ); + } +#ifdef _DEBUG + else + { + ProcessCachedTableResources(RootInd, VkParam, ResourceCache, dbgHeapType, + [&](UINT OffsetFromTableStart, const Vk_DESCRIPTOR_RANGE &range, ShaderResourceCacheVk::Resource &Res) + { + DbgVerifyResourceState(Res, range.RangeType); + } + ); + } +#endif + } + ); +} + + +void PipelineLayout::TransitionResources(ShaderResourceCacheVk& ResourceCache, + class CommandContext &Ctx)const +{ + m_RootParams.ProcessRootTables( + [&](Uint32 RootInd, const RootParameter &RootTable, const Vk_ROOT_PARAMETER& VkParam, bool IsResourceTable, Vk_DESCRIPTOR_HEAP_TYPE dbgHeapType ) + { + ProcessCachedTableResources(RootInd, VkParam, ResourceCache, dbgHeapType, + [&](UINT OffsetFromTableStart, const Vk_DESCRIPTOR_RANGE &range, ShaderResourceCacheVk::Resource &Res) + { + TransitionResource(Ctx, Res, range.RangeType); + } + ); + } + ); +} + + +void PipelineLayout::CommitRootViews(ShaderResourceCacheVk& ResourceCache, + CommandContext &Ctx, + bool IsCompute, + Uint32 ContextId)const +{ + for(Uint32 rv = 0; rv < m_RootParams.GetNumRootViews(); ++rv) + { + auto &RootView = m_RootParams.GetRootView(rv); + auto RootInd = RootView.GetRootIndex(); + + SHADER_TYPE dbgShaderType = SHADER_TYPE_UNKNOWN; +#ifdef _DEBUG + auto &Param = static_cast( RootView ); + VERIFY_EXPR(Param.ParameterType == Vk_ROOT_PARAMETER_TYPE_CBV); + dbgShaderType = ShaderTypeFromShaderVisibility(Param.ShaderVisibility); +#endif + + auto& Res = ResourceCache.GetRootTable(RootInd).GetResource(0, Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, dbgShaderType); + auto *pBuffToTransition = Res.pObject.RawPtr(); + if( !pBuffToTransition->CheckAllStates(Vk_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER) ) + Ctx.TransitionResource(pBuffToTransition, Vk_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER); + + Vk_GPU_VIRTUAL_ADDRESS CBVAddress = pBuffToTransition->GetGPUAddress(ContextId); + if(IsCompute) + Ctx.GetCommandList()->SetComputeRootConstantBufferView(RootInd, CBVAddress); + else + Ctx.GetCommandList()->SetGraphicsRootConstantBufferView(RootInd, CBVAddress); + } +} +#endif +} diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp index 611d814a..8fccd1e8 100644 --- a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp @@ -177,35 +177,13 @@ PipelineStateVkImpl :: PipelineStateVkImpl(IReferenceCounters *pRefCounters, Ren CSStage.pName = "main"; CSStage.pSpecializationInfo = nullptr; - m_Pipeline = LogicalDevice.CreateComputePipeline(PipelineCI, VK_NULL_HANDLE, m_Desc.Name); - #if 0 - Vk_COMPUTE_PIPELINE_STATE_DESC VkPSODesc = {}; - VkPSODesc.pRootSignature = nullptr; - - auto *pByteCode = ValidatedCast(ComputePipeline.pCS)->GetShaderByteCode(); - VkPSODesc.CS.pShaderBytecode = pByteCode->GetBufferPointer(); - VkPSODesc.CS.BytecodeLength = pByteCode->GetBufferSize(); - - // For single GPU operation, set this to zero. If there are multiple GPU nodes, - // set bits to identify the nodes (the device's physical adapters) for which the - // graphics pipeline state is to apply. Each bit in the mask corresponds to a single node. - VkPSODesc.NodeMask = 0; - - VkPSODesc.CachedPSO.pCachedBlob = nullptr; - VkPSODesc.CachedPSO.CachedBlobSizeInBytes = 0; - - // The only valid bit is Vk_PIPELINE_STATE_FLAG_TOOL_DEBUG, which can only be set on WARP devices. - VkPSODesc.Flags = Vk_PIPELINE_STATE_FLAG_NONE; - ParseShaderResourceLayout(ComputePipeline.pCS); m_RootSig.Finalize(pVkDevice); VkPSODesc.pRootSignature = m_RootSig.GetVkRootSignature(); - - HRESULT hr = pVkDevice->CreateComputePipelineState(&VkPSODesc, __uuidof(IVkPipelineState), reinterpret_cast( static_cast(&m_pVkPSO)) ); - if(FAILED(hr)) - LOG_ERROR_AND_THROW("Failed to create pipeline state"); #endif + + m_Pipeline = LogicalDevice.CreateComputePipeline(PipelineCI, VK_NULL_HANDLE, m_Desc.Name); } else { diff --git a/Graphics/GraphicsEngineVulkan/src/RootSignature.cpp b/Graphics/GraphicsEngineVulkan/src/RootSignature.cpp deleted file mode 100644 index f357a860..00000000 --- a/Graphics/GraphicsEngineVulkan/src/RootSignature.cpp +++ /dev/null @@ -1,1033 +0,0 @@ -/* Copyright 2015-2018 Egor Yusov - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. - * - * In no event and under no legal theory, whether in tort (including negligence), - * contract, or otherwise, unless required by applicable law (such as deliberate - * and grossly negligent acts) or agreed to in writing, shall any Contributor be - * liable for any damages, including any direct, indirect, special, incidental, - * or consequential damages of any character arising as a result of this License or - * out of the use or inability to use the software (including but not limited to damages - * for loss of goodwill, work stoppage, computer failure or malfunction, or any and - * all other commercial damages or losses), even if such Contributor has been advised - * of the possibility of such damages. - */ - -#include "pch.h" - -#include "RootSignature.h" -#include "ShaderResourceLayoutVk.h" -#include "ShaderVkImpl.h" -#include "CommandContext.h" -#include "RenderDeviceVkImpl.h" -#include "TextureVkImpl.h" -#include "BufferVkImpl.h" -#include "VulkanTypeConversions.h" -#include "HashUtils.h" - -namespace Diligent -{ - -#if 0 -RootSignature::RootParamsManager::RootParamsManager(IMemoryAllocator &MemAllocator): - m_MemAllocator(MemAllocator), - m_pMemory(nullptr, STDDeleter(MemAllocator)) -{} - -size_t RootSignature::RootParamsManager::GetRequiredMemorySize(Uint32 NumExtraRootTables, Uint32 NumExtraRootViews, Uint32 NumExtraDescriptorRanges)const -{ - return sizeof(RootParameter) * (m_NumRootTables + NumExtraRootTables + m_NumRootViews + NumExtraRootViews) + sizeof(Vk_DESCRIPTOR_RANGE) * (m_TotalDescriptorRanges + NumExtraDescriptorRanges); -} - -Vk_DESCRIPTOR_RANGE* RootSignature::RootParamsManager::Extend(Uint32 NumExtraRootTables, Uint32 NumExtraRootViews, Uint32 NumExtraDescriptorRanges, Uint32 RootTableToAddRanges) -{ - VERIFY(NumExtraRootTables > 0 || NumExtraRootViews > 0 || NumExtraDescriptorRanges > 0, "At least one root table, root view or descriptor range must be added" ); - auto MemorySize = GetRequiredMemorySize(NumExtraRootTables, NumExtraRootViews, NumExtraDescriptorRanges); - VERIFY_EXPR(MemorySize > 0); - auto *pNewMemory = ALLOCATE(m_MemAllocator, "Memory buffer for root tables, root views & descriptor ranges", MemorySize); - memset(pNewMemory, 0, MemorySize); - - // Note: this order is more efficient than views->tables->ranges - auto *pNewRootTables = reinterpret_cast(pNewMemory); - auto *pNewRootViews = pNewRootTables + (m_NumRootTables + NumExtraRootTables); - auto *pCurrDescriptorRangePtr = reinterpret_cast(pNewRootViews+m_NumRootViews+NumExtraRootViews); - - // Copy existing root tables to new memory - for (Uint32 rt = 0; rt < m_NumRootTables; ++rt) - { - const auto &SrcTbl = GetRootTable(rt); - auto &VkSrcTbl = static_cast(SrcTbl).DescriptorTable; - auto NumRanges = VkSrcTbl.NumDescriptorRanges; - if(rt == RootTableToAddRanges) - { - VERIFY(NumExtraRootTables == 0 || NumExtraRootTables == 1, "Up to one descriptor table can be extended at a time"); - NumRanges += NumExtraDescriptorRanges; - } - new(pNewRootTables + rt) RootParameter(SrcTbl, NumRanges, pCurrDescriptorRangePtr); - pCurrDescriptorRangePtr += NumRanges; - } - - // Copy existing root views to new memory - for (Uint32 rv = 0; rv < m_NumRootViews; ++rv) - { - const auto &SrcView = GetRootView(rv); - new(pNewRootViews + rv) RootParameter(SrcView); - } - - m_pMemory.reset(pNewMemory); - m_NumRootTables += NumExtraRootTables; - m_NumRootViews += NumExtraRootViews; - m_TotalDescriptorRanges += NumExtraDescriptorRanges; - m_pRootTables = m_NumRootTables != 0 ? pNewRootTables : nullptr; - m_pRootViews = m_NumRootViews != 0 ? pNewRootViews : nullptr; - - return pCurrDescriptorRangePtr; -} - -void RootSignature::RootParamsManager::AddRootView(Vk_ROOT_PARAMETER_TYPE ParameterType, Uint32 RootIndex, UINT Register, Vk_SHADER_VISIBILITY Visibility, SHADER_VARIABLE_TYPE VarType) -{ - auto *pRangePtr = Extend(0, 1, 0); - VERIFY_EXPR((char*)pRangePtr == (char*)m_pMemory.get() + GetRequiredMemorySize(0, 0, 0)); - new(m_pRootViews + m_NumRootViews-1) RootParameter(ParameterType, RootIndex, Register, 0u, Visibility, VarType); -} - -void RootSignature::RootParamsManager::AddRootTable(Uint32 RootIndex, Vk_SHADER_VISIBILITY Visibility, SHADER_VARIABLE_TYPE VarType, Uint32 NumRangesInNewTable) -{ - auto *pRangePtr = Extend(1, 0, NumRangesInNewTable); - VERIFY_EXPR( (char*)(pRangePtr + NumRangesInNewTable) == (char*)m_pMemory.get() + GetRequiredMemorySize(0, 0, 0)); - new(m_pRootTables + m_NumRootTables-1) RootParameter(Vk_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, RootIndex, NumRangesInNewTable, pRangePtr, Visibility, VarType); -} - -void RootSignature::RootParamsManager::AddDescriptorRanges(Uint32 RootTableInd, Uint32 NumExtraRanges) -{ - auto *pRangePtr = Extend(0, 0, NumExtraRanges, RootTableInd); - VERIFY_EXPR( (char*)pRangePtr == (char*)m_pMemory.get() + GetRequiredMemorySize(0, 0, 0)); -} - -bool RootSignature::RootParamsManager::operator == (const RootParamsManager& RootParams)const -{ - if (m_NumRootTables != RootParams.m_NumRootTables || - m_NumRootViews != RootParams.m_NumRootViews) - return false; - - for (Uint32 rv = 0; rv < m_NumRootViews; ++rv) - { - const auto &RV0 = GetRootView(rv); - const auto &RV1 = RootParams.GetRootView(rv); - if (RV0 != RV1) - return false; - } - - for (Uint32 rv = 0; rv < m_NumRootTables; ++rv) - { - const auto &RT0 = GetRootTable(rv); - const auto &RT1 = RootParams.GetRootTable(rv); - if (RT0 != RT1) - return false; - } - - return true; -} - -size_t RootSignature::RootParamsManager::GetHash()const -{ - size_t hash = ComputeHash(m_NumRootTables, m_NumRootViews); - for (Uint32 rv = 0; rv < m_NumRootViews; ++rv) - HashCombine(hash, GetRootView(rv).GetHash()); - - for (Uint32 rv = 0; rv < m_NumRootTables; ++rv) - HashCombine(hash, GetRootTable(rv).GetHash()); - - return hash; -} - -RootSignature::RootSignature() : - m_RootParams(GetRawAllocator()), - m_MemAllocator(GetRawAllocator()), - m_StaticSamplers( STD_ALLOCATOR_RAW_MEM(StaticSamplerAttribs, GetRawAllocator(), "Allocator for vector") ) -{ - for(size_t s=0; s < SHADER_VARIABLE_TYPE_NUM_TYPES; ++s) - { - m_TotalSrvCbvUavSlots[s] = 0; - m_TotalSamplerSlots[s] = 0; - } - - for(size_t i=0; i < _countof(m_SrvCbvUavRootTablesMap); ++i) - m_SrvCbvUavRootTablesMap[i] = InvalidRootTableIndex; - for(size_t i=0; i < _countof(m_SamplerRootTablesMap); ++i) - m_SamplerRootTablesMap[i] = InvalidRootTableIndex; - -} - -static Vk_SHADER_VISIBILITY ShaderTypeInd2ShaderVisibilityMap[] -{ - Vk_SHADER_VISIBILITY_VERTEX, // 0 - Vk_SHADER_VISIBILITY_PIXEL, // 1 - Vk_SHADER_VISIBILITY_GEOMETRY, // 2 - Vk_SHADER_VISIBILITY_HULL, // 3 - Vk_SHADER_VISIBILITY_DOMAIN, // 4 - Vk_SHADER_VISIBILITY_ALL // 5 -}; -Vk_SHADER_VISIBILITY GetShaderVisibility(SHADER_TYPE ShaderType) -{ - auto ShaderInd = GetShaderTypeIndex(ShaderType); - auto ShaderVisibility = ShaderTypeInd2ShaderVisibilityMap[ShaderInd]; -#ifdef _DEBUG - switch (ShaderType) - { - case SHADER_TYPE_VERTEX: VERIFY_EXPR(ShaderVisibility == Vk_SHADER_VISIBILITY_VERTEX); break; - case SHADER_TYPE_PIXEL: VERIFY_EXPR(ShaderVisibility == Vk_SHADER_VISIBILITY_PIXEL); break; - case SHADER_TYPE_GEOMETRY: VERIFY_EXPR(ShaderVisibility == Vk_SHADER_VISIBILITY_GEOMETRY); break; - case SHADER_TYPE_HULL: VERIFY_EXPR(ShaderVisibility == Vk_SHADER_VISIBILITY_HULL); break; - case SHADER_TYPE_DOMAIN: VERIFY_EXPR(ShaderVisibility == Vk_SHADER_VISIBILITY_DOMAIN); break; - case SHADER_TYPE_COMPUTE: VERIFY_EXPR(ShaderVisibility == Vk_SHADER_VISIBILITY_ALL); break; - default: LOG_ERROR("Unknown shader type (", ShaderType, ")"); break; - } -#endif - return ShaderVisibility; -} - -static SHADER_TYPE ShaderVisibility2ShaderTypeMap[] = -{ - SHADER_TYPE_COMPUTE, // Vk_SHADER_VISIBILITY_ALL = 0 - SHADER_TYPE_VERTEX, // Vk_SHADER_VISIBILITY_VERTEX = 1 - SHADER_TYPE_HULL, // Vk_SHADER_VISIBILITY_HULL = 2 - SHADER_TYPE_DOMAIN, // Vk_SHADER_VISIBILITY_DOMAIN = 3 - SHADER_TYPE_GEOMETRY, // Vk_SHADER_VISIBILITY_GEOMETRY = 4 - SHADER_TYPE_PIXEL // Vk_SHADER_VISIBILITY_PIXEL = 5 -}; -SHADER_TYPE ShaderTypeFromShaderVisibility(Vk_SHADER_VISIBILITY ShaderVisibility) -{ - VERIFY_EXPR(ShaderVisibility >= Vk_SHADER_VISIBILITY_ALL && ShaderVisibility <= Vk_SHADER_VISIBILITY_PIXEL ); - auto ShaderType = ShaderVisibility2ShaderTypeMap[ShaderVisibility]; -#ifdef _DEBUG - switch (ShaderVisibility) - { - case Vk_SHADER_VISIBILITY_VERTEX: VERIFY_EXPR(ShaderType == SHADER_TYPE_VERTEX); break; - case Vk_SHADER_VISIBILITY_PIXEL: VERIFY_EXPR(ShaderType == SHADER_TYPE_PIXEL); break; - case Vk_SHADER_VISIBILITY_GEOMETRY: VERIFY_EXPR(ShaderType == SHADER_TYPE_GEOMETRY); break; - case Vk_SHADER_VISIBILITY_HULL: VERIFY_EXPR(ShaderType == SHADER_TYPE_HULL); break; - case Vk_SHADER_VISIBILITY_DOMAIN: VERIFY_EXPR(ShaderType == SHADER_TYPE_DOMAIN); break; - case Vk_SHADER_VISIBILITY_ALL: VERIFY_EXPR(ShaderType == SHADER_TYPE_COMPUTE); break; - default: LOG_ERROR("Unknown shader visibility (", ShaderVisibility, ")"); break; - } -#endif - return ShaderType; -} - - -static Vk_DESCRIPTOR_HEAP_TYPE RangeType2HeapTypeMap[] -{ - Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, //Vk_DESCRIPTOR_RANGE_TYPE_SRV = 0, - Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, //Vk_DESCRIPTOR_RANGE_TYPE_UAV = ( Vk_DESCRIPTOR_RANGE_TYPE_SRV + 1 ) , - Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, //Vk_DESCRIPTOR_RANGE_TYPE_CBV = ( Vk_DESCRIPTOR_RANGE_TYPE_UAV + 1 ) , - Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER //Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER = ( Vk_DESCRIPTOR_RANGE_TYPE_CBV + 1 ) -}; -Vk_DESCRIPTOR_HEAP_TYPE HeapTypeFromRangeType(Vk_DESCRIPTOR_RANGE_TYPE RangeType) -{ - VERIFY_EXPR(RangeType >= Vk_DESCRIPTOR_RANGE_TYPE_SRV && RangeType <= Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER); - auto HeapType = RangeType2HeapTypeMap[RangeType]; - -#ifdef _DEBUG - switch (RangeType) - { - case Vk_DESCRIPTOR_RANGE_TYPE_CBV: VERIFY_EXPR(HeapType == Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); break; - case Vk_DESCRIPTOR_RANGE_TYPE_SRV: VERIFY_EXPR(HeapType == Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); break; - case Vk_DESCRIPTOR_RANGE_TYPE_UAV: VERIFY_EXPR(HeapType == Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); break; - case Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER: VERIFY_EXPR(HeapType == Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER); break; - default: UNEXPECTED("Unexpected descriptor range type"); break; - } -#endif - return HeapType; -} - - -void RootSignature::InitStaticSampler(SHADER_TYPE ShaderType, const String &TextureName, const D3DShaderResourceAttribs &SamplerAttribs) -{ - auto ShaderVisibility = GetShaderVisibility(ShaderType); - auto SamplerFound = false; - for (auto &StSmplr : m_StaticSamplers) - { - if (StSmplr.ShaderVisibility == ShaderVisibility && - TextureName.compare(StSmplr.SamplerDesc.TextureName) == 0) - { - StSmplr.ShaderRegister = SamplerAttribs.BindPoint; - StSmplr.ArraySize = SamplerAttribs.BindCount; - StSmplr.RegisterSpace = 0; - SamplerFound = true; - break; - } - } - - if (!SamplerFound) - { - LOG_ERROR("Failed to find static sampler for variable \"", TextureName, '\"'); - } -} - -// http://diligentgraphics.com/diligent-engine/architecture/Vk/shader-resource-layout#Initializing-Shader-Resource-Layouts-and-Root-Signature-in-a-Pipeline-State-Object -void RootSignature::AllocateResourceSlot(SHADER_TYPE ShaderType, - const D3DShaderResourceAttribs &ShaderResAttribs, - Vk_DESCRIPTOR_RANGE_TYPE RangeType, - Uint32 &RootIndex, // Output parameter - Uint32 &OffsetFromTableStart // Output parameter - ) -{ - auto ShaderInd = GetShaderTypeIndex(ShaderType); - auto ShaderVisibility = GetShaderVisibility(ShaderType); - if (RangeType == Vk_DESCRIPTOR_RANGE_TYPE_CBV && ShaderResAttribs.BindCount == 1) - { - // Allocate single CBV directly in the root signature - - // Get the next available root index past all allocated tables and root views - RootIndex = m_RootParams.GetNumRootTables() + m_RootParams.GetNumRootViews(); - OffsetFromTableStart = 0; - - // Add new root view to existing root parameters - m_RootParams.AddRootView(Vk_ROOT_PARAMETER_TYPE_CBV, RootIndex, ShaderResAttribs.BindPoint, ShaderVisibility, ShaderResAttribs.GetVariableType()); - } - else - { - // Use the same table for static and mutable resources. Treat both as static - auto RootTableType = (ShaderResAttribs.GetVariableType() == SHADER_VARIABLE_TYPE_DYNAMIC) ? SHADER_VARIABLE_TYPE_DYNAMIC : SHADER_VARIABLE_TYPE_STATIC; - auto TableIndKey = ShaderInd * SHADER_VARIABLE_TYPE_NUM_TYPES + RootTableType; - // Get the table array index (this is not the root index!) - auto &RootTableArrayInd = (( RangeType == Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER ) ? m_SamplerRootTablesMap : m_SrvCbvUavRootTablesMap)[ TableIndKey ]; - if (RootTableArrayInd == InvalidRootTableIndex) - { - // Root table has not been assigned to this combination yet - - // Get the next available root index past all allocated tables and root views - RootIndex = m_RootParams.GetNumRootTables() + m_RootParams.GetNumRootViews(); - VERIFY_EXPR(m_RootParams.GetNumRootTables() < 255); - RootTableArrayInd = static_cast( m_RootParams.GetNumRootTables() ); - // Add root table with one single-descriptor range - m_RootParams.AddRootTable(RootIndex, ShaderVisibility, RootTableType, 1); - } - else - { - // Add a new single-descriptor range to the existing table at index RootTableArrayInd - m_RootParams.AddDescriptorRanges(RootTableArrayInd, 1); - } - - // Reference to either existing or just added table - auto &CurrParam = m_RootParams.GetRootTable(RootTableArrayInd); - RootIndex = CurrParam.GetRootIndex(); - - const auto& VkRootParam = static_cast(CurrParam); - - VERIFY( VkRootParam.ShaderVisibility == ShaderVisibility, "Shader visibility is not correct" ); - - // Descriptors are tightly packed, so the next descriptor offset is the - // current size of the table - OffsetFromTableStart = CurrParam.GetDescriptorTableSize(); - - // New just added range is the last range in the descriptor table - Uint32 NewDescriptorRangeIndex = VkRootParam.DescriptorTable.NumDescriptorRanges-1; - CurrParam.SetDescriptorRange(NewDescriptorRangeIndex, - RangeType, // Range type (CBV, SRV, UAV or SAMPLER) - ShaderResAttribs.BindPoint, // Shader register - ShaderResAttribs.BindCount, // Number of registers used (1 for non-array resources) - 0, // Register space. Always 0 for now - OffsetFromTableStart // Offset in descriptors from the table start - ); - } -} - - -#ifdef _DEBUG -void RootSignature::dbgVerifyRootParameters()const -{ - Uint32 dbgTotalSrvCbvUavSlots = 0; - Uint32 dbgTotalSamplerSlots = 0; - for(Uint32 rt = 0; rt < m_RootParams.GetNumRootTables(); ++rt) - { - auto &RootTable = m_RootParams.GetRootTable(rt); - auto &Param = static_cast( RootTable ); - VERIFY(Param.ParameterType == Vk_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE, "Root parameter is expected to be a descriptor table"); - auto &Table = Param.DescriptorTable; - VERIFY(Table.NumDescriptorRanges > 0, "Descriptor table is expected to be non-empty"); - VERIFY(Table.pDescriptorRanges[0].OffsetInDescriptorsFromTableStart == 0, "Descriptor table is expected to start at 0 offset"); - bool IsResourceTable = Table.pDescriptorRanges[0].RangeType != Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER; - for (Uint32 r = 0; r < Table.NumDescriptorRanges; ++r) - { - const auto &range = Table.pDescriptorRanges[r]; - if(IsResourceTable) - { - VERIFY( range.RangeType == Vk_DESCRIPTOR_RANGE_TYPE_SRV || - range.RangeType == Vk_DESCRIPTOR_RANGE_TYPE_CBV || - range.RangeType == Vk_DESCRIPTOR_RANGE_TYPE_UAV, "Resource type is expected to be SRV, CBV or UAV"); - dbgTotalSrvCbvUavSlots += range.NumDescriptors; - } - else - { - VERIFY(range.RangeType == Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER, "Resource type is expected to be sampler"); - dbgTotalSamplerSlots += range.NumDescriptors; - } - - if(r>0) - { - VERIFY(Table.pDescriptorRanges[r].OffsetInDescriptorsFromTableStart == Table.pDescriptorRanges[r-1].OffsetInDescriptorsFromTableStart+Table.pDescriptorRanges[r-1].NumDescriptors, "Ranges in a descriptor table are expected to be consequtive"); - } - } - } - - for(Uint32 rv = 0; rv < m_RootParams.GetNumRootViews(); ++rv) - { - auto &RootView = m_RootParams.GetRootView(rv); - auto &Param = static_cast( RootView ); - VERIFY(Param.ParameterType == Vk_ROOT_PARAMETER_TYPE_CBV, "Root parameter is expected to be a CBV"); - } - - VERIFY(dbgTotalSrvCbvUavSlots == - m_TotalSrvCbvUavSlots[SHADER_VARIABLE_TYPE_STATIC] + - m_TotalSrvCbvUavSlots[SHADER_VARIABLE_TYPE_MUTABLE] + - m_TotalSrvCbvUavSlots[SHADER_VARIABLE_TYPE_DYNAMIC], "Unexpected number of SRV CBV UAV resource slots"); - VERIFY(dbgTotalSamplerSlots == - m_TotalSamplerSlots[SHADER_VARIABLE_TYPE_STATIC] + - m_TotalSamplerSlots[SHADER_VARIABLE_TYPE_MUTABLE] + - m_TotalSamplerSlots[SHADER_VARIABLE_TYPE_DYNAMIC], "Unexpected number of sampler slots"); -} -#endif - -void RootSignature::AllocateStaticSamplers(IShader* const*ppShaders, Uint32 NumShaders) -{ - Uint32 TotalSamplers = 0; - for(Uint32 s=0;s < NumShaders; ++s) - TotalSamplers += ppShaders[s]->GetDesc().NumStaticSamplers; - if (TotalSamplers > 0) - { - m_StaticSamplers.reserve(TotalSamplers); - for(Uint32 sh=0;sh < NumShaders; ++sh) - { - const auto &Desc = ppShaders[sh]->GetDesc(); - for(Uint32 sam=0; sam < Desc.NumStaticSamplers; ++sam) - { - m_StaticSamplers.emplace_back(Desc.StaticSamplers[sam], GetShaderVisibility(Desc.ShaderType)); - } - } - VERIFY_EXPR(m_StaticSamplers.size() == TotalSamplers); - } -} - -void RootSignature::Finalize(IVkDevice *pVkDevice) -{ - for(Uint32 rt = 0; rt < m_RootParams.GetNumRootTables(); ++rt) - { - auto &RootTbl = m_RootParams.GetRootTable(rt); - auto &VkRootParam = static_cast(RootTbl); - VERIFY_EXPR(VkRootParam.ParameterType == Vk_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE); - - auto TableSize = RootTbl.GetDescriptorTableSize(); - VERIFY(VkRootParam.DescriptorTable.NumDescriptorRanges > 0 && TableSize > 0, "Unexpected empty descriptor table"); - auto IsSamplerTable = VkRootParam.DescriptorTable.pDescriptorRanges[0].RangeType == Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER; - auto VarType = RootTbl.GetShaderVariableType(); - (IsSamplerTable ? m_TotalSamplerSlots : m_TotalSrvCbvUavSlots)[VarType] += TableSize; - } - -#ifdef _DEBUG - dbgVerifyRootParameters(); -#endif - - Vk_ROOT_SIGNATURE_DESC rootSignatureDesc; - rootSignatureDesc.Flags = Vk_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; - - auto TotalParams = m_RootParams.GetNumRootTables() + m_RootParams.GetNumRootViews(); - std::vector > VkParameters( TotalParams, Vk_ROOT_PARAMETER(), STD_ALLOCATOR_RAW_MEM(Vk_ROOT_PARAMETER, GetRawAllocator(), "Allocator for vector") ); - for(Uint32 rt = 0; rt < m_RootParams.GetNumRootTables(); ++rt) - { - auto &RootTable = m_RootParams.GetRootTable(rt); - const Vk_ROOT_PARAMETER &SrcParam = RootTable; - VERIFY( SrcParam.ParameterType == Vk_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE && SrcParam.DescriptorTable.NumDescriptorRanges > 0, "Non-empty descriptor table is expected" ); - VkParameters[RootTable.GetRootIndex()] = SrcParam; - } - for(Uint32 rv = 0; rv < m_RootParams.GetNumRootViews(); ++rv) - { - auto &RootView = m_RootParams.GetRootView(rv); - const Vk_ROOT_PARAMETER &SrcParam = RootView; - VERIFY( SrcParam.ParameterType == Vk_ROOT_PARAMETER_TYPE_CBV, "Root CBV is expected" ); - VkParameters[RootView.GetRootIndex()] = SrcParam; - } - - - rootSignatureDesc.NumParameters = static_cast(VkParameters.size()); - rootSignatureDesc.pParameters = VkParameters.size() ? VkParameters.data() : nullptr; - - UINT TotalVkStaticSamplers = 0; - for(const auto &StSam : m_StaticSamplers) - TotalVkStaticSamplers += StSam.ArraySize; - rootSignatureDesc.NumStaticSamplers = TotalVkStaticSamplers; - rootSignatureDesc.pStaticSamplers = nullptr; - std::vector > VkStaticSamplers( STD_ALLOCATOR_RAW_MEM(Vk_STATIC_SAMPLER_DESC, GetRawAllocator(), "Allocator for vector") ); - VkStaticSamplers.reserve(TotalVkStaticSamplers); - if ( !m_StaticSamplers.empty() ) - { - for(size_t s=0; s < m_StaticSamplers.size(); ++s) - { - const auto &StSmplrDesc = m_StaticSamplers[s]; - const auto &SamDesc = StSmplrDesc.SamplerDesc.Desc; - for(UINT ArrInd = 0; ArrInd < StSmplrDesc.ArraySize; ++ArrInd) - { - VkStaticSamplers.emplace_back( - Vk_STATIC_SAMPLER_DESC{ - FilterTypeToVkFilter(SamDesc.MinFilter, SamDesc.MagFilter, SamDesc.MipFilter), - TexAddressModeToVkAddressMode(SamDesc.AddressU), - TexAddressModeToVkAddressMode(SamDesc.AddressV), - TexAddressModeToVkAddressMode(SamDesc.AddressW), - SamDesc.MipLODBias, - SamDesc.MaxAnisotropy, - ComparisonFuncToVkComparisonFunc(SamDesc.ComparisonFunc), - BorderColorToVkStaticBorderColor(SamDesc.BorderColor), - SamDesc.MinLOD, - SamDesc.MaxLOD, - StSmplrDesc.ShaderRegister + ArrInd, - StSmplrDesc.RegisterSpace, - StSmplrDesc.ShaderVisibility - } - ); - } - } - rootSignatureDesc.pStaticSamplers = VkStaticSamplers.data(); - - // Release static samplers array, we no longer need it - std::vector > EmptySamplers( STD_ALLOCATOR_RAW_MEM(StaticSamplerAttribs, GetRawAllocator(), "Allocator for vector") ); - m_StaticSamplers.swap( EmptySamplers ); - - VERIFY_EXPR(VkStaticSamplers.size() == TotalVkStaticSamplers); - } - - - CComPtr signature; - CComPtr error; - HRESULT hr = VkSerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error); - hr = pVkDevice->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), __uuidof(m_pVkRootSignature), reinterpret_cast( static_cast(&m_pVkRootSignature))); - CHECK_D3D_RESULT_THROW(hr, "Failed to create root signature"); - - bool bHasDynamicResources = m_TotalSrvCbvUavSlots[SHADER_VARIABLE_TYPE_DYNAMIC]!=0 || m_TotalSamplerSlots[SHADER_VARIABLE_TYPE_DYNAMIC]!=0; - if(bHasDynamicResources) - { - CommitDescriptorHandles = &RootSignature::CommitDescriptorHandlesInternal_SMD; - TransitionAndCommitDescriptorHandles = &RootSignature::CommitDescriptorHandlesInternal_SMD; - } - else - { - CommitDescriptorHandles = &RootSignature::CommitDescriptorHandlesInternal_SM; - TransitionAndCommitDescriptorHandles = &RootSignature::CommitDescriptorHandlesInternal_SM; - } -} - -//http://diligentgraphics.com/diligent-engine/architecture/Vk/shader-resource-cache#Initializing-the-Cache-for-Shader-Resource-Binding-Object -void RootSignature::InitResourceCache(RenderDeviceVkImpl *pDeviceVkImpl, ShaderResourceCacheVk& ResourceCache, IMemoryAllocator &CacheMemAllocator)const -{ - // Get root table size for every root index - // m_RootParams keeps root tables sorted by the array index, not the root index - // Root views are treated as one-descriptor tables - std::vector > CacheTableSizes(m_RootParams.GetNumRootTables() + m_RootParams.GetNumRootViews(), 0, STD_ALLOCATOR_RAW_MEM(Uint32, GetRawAllocator(), "Allocator for vector") ); - for(Uint32 rt = 0; rt < m_RootParams.GetNumRootTables(); ++rt) - { - auto &RootParam = m_RootParams.GetRootTable(rt); - CacheTableSizes[RootParam.GetRootIndex()] = RootParam.GetDescriptorTableSize(); - } - - for(Uint32 rv = 0; rv < m_RootParams.GetNumRootViews(); ++rv) - { - auto &RootParam = m_RootParams.GetRootView(rv); - CacheTableSizes[RootParam.GetRootIndex()] = 1; - } - // Initialize resource cache to hold root tables - ResourceCache.Initialize(CacheMemAllocator, static_cast(CacheTableSizes.size()), CacheTableSizes.data()); - - // Allocate space in GPU-visible descriptor heap for static and mutable variables only - Uint32 TotalSrvCbvUavDescriptors = - m_TotalSrvCbvUavSlots[SHADER_VARIABLE_TYPE_STATIC] + - m_TotalSrvCbvUavSlots[SHADER_VARIABLE_TYPE_MUTABLE]; - Uint32 TotalSamplerDescriptors = - m_TotalSamplerSlots[SHADER_VARIABLE_TYPE_STATIC] + - m_TotalSamplerSlots[SHADER_VARIABLE_TYPE_MUTABLE]; - - DescriptorHeapAllocation CbcSrvUavHeapSpace, SamplerHeapSpace; - if(TotalSrvCbvUavDescriptors) - CbcSrvUavHeapSpace = pDeviceVkImpl->AllocateGPUDescriptors(Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, TotalSrvCbvUavDescriptors); - VERIFY_EXPR(TotalSrvCbvUavDescriptors == 0 && CbcSrvUavHeapSpace.IsNull() || CbcSrvUavHeapSpace.GetNumHandles() == TotalSrvCbvUavDescriptors); - - if(TotalSamplerDescriptors) - SamplerHeapSpace = pDeviceVkImpl->AllocateGPUDescriptors(Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER, TotalSamplerDescriptors); - VERIFY_EXPR(TotalSamplerDescriptors == 0 && SamplerHeapSpace.IsNull() || SamplerHeapSpace.GetNumHandles() == TotalSamplerDescriptors); - - // Iterate through all root static/mutable tables and assign start offsets. The tables are tightly packed, so - // start offset of table N+1 is start offset of table N plus the size of table N. - // Root tables with dynamic resources as well as root views are not assigned space in GPU-visible allocation - // (root views are simply not processed) - Uint32 SrvCbvUavTblStartOffset = 0; - Uint32 SamplerTblStartOffset = 0; - for(Uint32 rt = 0; rt < m_RootParams.GetNumRootTables(); ++rt) - { - auto &RootParam = m_RootParams.GetRootTable(rt); - const auto& VkRootParam = static_cast(RootParam); - auto &RootTableCache = ResourceCache.GetRootTable(RootParam.GetRootIndex()); - - SHADER_TYPE dbgShaderType = SHADER_TYPE_UNKNOWN; -#ifdef _DEBUG - dbgShaderType = ShaderTypeFromShaderVisibility(VkRootParam.ShaderVisibility); -#endif - VERIFY_EXPR( VkRootParam.ParameterType == Vk_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE ); - - auto TableSize = RootParam.GetDescriptorTableSize(); - VERIFY(TableSize > 0, "Unexpected empty descriptor table"); - - auto HeapType = HeapTypeFromRangeType(VkRootParam.DescriptorTable.pDescriptorRanges[0].RangeType); - -#ifdef _DEBUG - RootTableCache.SetDebugAttribs( TableSize, HeapType, dbgShaderType ); -#endif - - // Space for dynamic variables is allocated at every draw call - if( RootParam.GetShaderVariableType() != SHADER_VARIABLE_TYPE_DYNAMIC ) - { - if( HeapType == Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV ) - { - RootTableCache.m_TableStartOffset = SrvCbvUavTblStartOffset; - SrvCbvUavTblStartOffset += TableSize; - } - else - { - RootTableCache.m_TableStartOffset = SamplerTblStartOffset; - SamplerTblStartOffset += TableSize; - } - } - else - { - VERIFY_EXPR(RootTableCache.m_TableStartOffset == ShaderResourceCacheVk::InvalidDescriptorOffset); - } - } - -#ifdef _DEBUG - for(Uint32 rv = 0; rv < m_RootParams.GetNumRootViews(); ++rv) - { - auto &RootParam = m_RootParams.GetRootView(rv); - const auto& VkRootParam = static_cast(RootParam); - auto &RootTableCache = ResourceCache.GetRootTable(RootParam.GetRootIndex()); - // Root views are not assigned valid table start offset - VERIFY_EXPR(RootTableCache.m_TableStartOffset == ShaderResourceCacheVk::InvalidDescriptorOffset); - - SHADER_TYPE dbgShaderType = ShaderTypeFromShaderVisibility(VkRootParam.ShaderVisibility); - VERIFY_EXPR(VkRootParam.ParameterType == Vk_ROOT_PARAMETER_TYPE_CBV); - RootTableCache.SetDebugAttribs( 1, Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, dbgShaderType ); - } -#endif - - VERIFY_EXPR(SrvCbvUavTblStartOffset == TotalSrvCbvUavDescriptors); - VERIFY_EXPR(SamplerTblStartOffset == TotalSamplerDescriptors); - - ResourceCache.SetDescriptorHeapSpace(std::move(CbcSrvUavHeapSpace), std::move(SamplerHeapSpace)); -} - -const Vk_RESOURCE_STATES Vk_RESOURCE_STATE_SHADER_RESOURCE = Vk_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | Vk_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; - -__forceinline -void TransitionResource(CommandContext &Ctx, - ShaderResourceCacheVk::Resource &Res, - Vk_DESCRIPTOR_RANGE_TYPE RangeType) -{ - switch (Res.Type) - { - case CachedResourceType::CBV: - { - VERIFY(RangeType == Vk_DESCRIPTOR_RANGE_TYPE_CBV, "Unexpected descriptor range type"); - // Not using QueryInterface() for the sake of efficiency - auto *pBuffToTransition = Res.pObject.RawPtr(); - if( !pBuffToTransition->CheckAllStates(Vk_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER) ) - Ctx.TransitionResource(pBuffToTransition, Vk_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER ); - } - break; - - case CachedResourceType::BufSRV: - { - VERIFY(RangeType == Vk_DESCRIPTOR_RANGE_TYPE_SRV, "Unexpected descriptor range type"); - auto *pBuffViewVk = Res.pObject.RawPtr(); - auto *pBuffToTransition = ValidatedCast(pBuffViewVk->GetBuffer()); - if( !pBuffToTransition->CheckAllStates(Vk_RESOURCE_STATE_SHADER_RESOURCE) ) - Ctx.TransitionResource(pBuffToTransition, Vk_RESOURCE_STATE_SHADER_RESOURCE ); - } - break; - - case CachedResourceType::BufUAV: - { - VERIFY(RangeType == Vk_DESCRIPTOR_RANGE_TYPE_UAV, "Unexpected descriptor range type"); - auto *pBuffViewVk = Res.pObject.RawPtr(); - auto *pBuffToTransition = ValidatedCast(pBuffViewVk->GetBuffer()); - if( !pBuffToTransition->CheckAllStates(Vk_RESOURCE_STATE_UNORDERED_ACCESS) ) - Ctx.TransitionResource(pBuffToTransition, Vk_RESOURCE_STATE_UNORDERED_ACCESS ); - } - break; - - case CachedResourceType::TexSRV: - { - VERIFY(RangeType == Vk_DESCRIPTOR_RANGE_TYPE_SRV, "Unexpected descriptor range type"); - auto *pTexViewVk = Res.pObject.RawPtr(); - auto *pTexToTransition = ValidatedCast(pTexViewVk->GetTexture()); - if( !pTexToTransition->CheckAllStates(Vk_RESOURCE_STATE_SHADER_RESOURCE) ) - Ctx.TransitionResource(pTexToTransition, Vk_RESOURCE_STATE_SHADER_RESOURCE ); - } - break; - - case CachedResourceType::TexUAV: - { - VERIFY(RangeType == Vk_DESCRIPTOR_RANGE_TYPE_UAV, "Unexpected descriptor range type"); - auto *pTexViewVk = Res.pObject.RawPtr(); - auto *pTexToTransition = ValidatedCast(pTexViewVk->GetTexture()); - if( !pTexToTransition->CheckAllStates(Vk_RESOURCE_STATE_UNORDERED_ACCESS) ) - Ctx.TransitionResource(pTexToTransition, Vk_RESOURCE_STATE_UNORDERED_ACCESS ); - } - break; - - case CachedResourceType::Sampler: - VERIFY(RangeType == Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER, "Unexpected descriptor range type"); - break; - - default: - // Resource not bound - VERIFY(Res.Type == CachedResourceType::Unknown, "Unexpected resource type"); - VERIFY(Res.pObject == nullptr && Res.CPUDescriptorHandle.ptr == 0, "Bound resource is unexpected"); - } -} - - -#ifdef _DEBUG -void DbgVerifyResourceState(ShaderResourceCacheVk::Resource &Res, - Vk_DESCRIPTOR_RANGE_TYPE RangeType) -{ - switch (Res.Type) - { - case CachedResourceType::CBV: - { - VERIFY(RangeType == Vk_DESCRIPTOR_RANGE_TYPE_CBV, "Unexpected descriptor range type"); - // Not using QueryInterface() for the sake of efficiency - auto *pBuffToTransition = Res.pObject.RawPtr(); - auto State = pBuffToTransition->GetState(); - if( (State & Vk_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER) != Vk_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER ) - LOG_ERROR_MESSAGE("Resource \"", pBuffToTransition->GetDesc().Name, "\" is not in Vk_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER state. Did you forget to call TransitionShaderResources() or specify COMMIT_SHADER_RESOURCES_FLAG_TRANSITION_RESOURCES flag in a call to CommitShaderResources()?" ); - } - break; - - case CachedResourceType::BufSRV: - { - VERIFY(RangeType == Vk_DESCRIPTOR_RANGE_TYPE_SRV, "Unexpected descriptor range type"); - auto *pBuffViewVk = Res.pObject.RawPtr(); - auto *pBuffToTransition = ValidatedCast(pBuffViewVk->GetBuffer()); - auto State = pBuffToTransition->GetState(); - if( (State & Vk_RESOURCE_STATE_SHADER_RESOURCE) != Vk_RESOURCE_STATE_SHADER_RESOURCE ) - LOG_ERROR_MESSAGE("Resource \"", pBuffToTransition->GetDesc().Name, "\" is not in correct state. Did you forget to call TransitionShaderResources() or specify COMMIT_SHADER_RESOURCES_FLAG_TRANSITION_RESOURCES flag in a call to CommitShaderResources()?" ); - } - break; - - case CachedResourceType::BufUAV: - { - VERIFY(RangeType == Vk_DESCRIPTOR_RANGE_TYPE_UAV, "Unexpected descriptor range type"); - auto *pBuffViewVk = Res.pObject.RawPtr(); - auto *pBuffToTransition = ValidatedCast(pBuffViewVk->GetBuffer()); - auto State = pBuffToTransition->GetState(); - if( (State & Vk_RESOURCE_STATE_UNORDERED_ACCESS) != Vk_RESOURCE_STATE_UNORDERED_ACCESS ) - LOG_ERROR_MESSAGE("Resource \"", pBuffToTransition->GetDesc().Name, "\" is not in Vk_RESOURCE_STATE_UNORDERED_ACCESS state. Did you forget to call TransitionShaderResources() or specify COMMIT_SHADER_RESOURCES_FLAG_TRANSITION_RESOURCES flag in a call to CommitShaderResources()?" ); - } - break; - - case CachedResourceType::TexSRV: - { - VERIFY(RangeType == Vk_DESCRIPTOR_RANGE_TYPE_SRV, "Unexpected descriptor range type"); - auto *pTexViewVk = Res.pObject.RawPtr(); - auto *pTexToTransition = ValidatedCast(pTexViewVk->GetTexture()); - auto State = pTexToTransition->GetState(); - if( (State & Vk_RESOURCE_STATE_SHADER_RESOURCE) != Vk_RESOURCE_STATE_SHADER_RESOURCE ) - LOG_ERROR_MESSAGE("Resource \"", pTexToTransition->GetDesc().Name, "\" is not in correct state. Did you forget to call TransitionShaderResources() or specify COMMIT_SHADER_RESOURCES_FLAG_TRANSITION_RESOURCES flag in a call to CommitShaderResources()?" ); - } - break; - - case CachedResourceType::TexUAV: - { - VERIFY(RangeType == Vk_DESCRIPTOR_RANGE_TYPE_UAV, "Unexpected descriptor range type"); - auto *pTexViewVk = Res.pObject.RawPtr(); - auto *pTexToTransition = ValidatedCast(pTexViewVk->GetTexture()); - auto State = pTexToTransition->GetState(); - if( (State & Vk_RESOURCE_STATE_UNORDERED_ACCESS) != Vk_RESOURCE_STATE_UNORDERED_ACCESS ) - LOG_ERROR_MESSAGE("Resource \"", pTexToTransition->GetDesc().Name, "\" is not in Vk_RESOURCE_STATE_UNORDERED_ACCESS state. Did you forget to call TransitionShaderResources() or specify COMMIT_SHADER_RESOURCES_FLAG_TRANSITION_RESOURCES flag in a call to CommitShaderResources()?" ); - } - break; - - case CachedResourceType::Sampler: - VERIFY(RangeType == Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER, "Unexpected descriptor range type"); - break; - - default: - // Resource not bound - VERIFY(Res.Type == CachedResourceType::Unknown, "Unexpected resource type"); - VERIFY(Res.pObject == nullptr && Res.CPUDescriptorHandle.ptr == 0, "Bound resource is unexpected"); - } -} -#endif - -template -__forceinline void RootSignature::RootParamsManager::ProcessRootTables(TOperation Operation)const -{ - for(Uint32 rt = 0; rt < m_NumRootTables; ++rt) - { - auto &RootTable = GetRootTable(rt); - auto RootInd = RootTable.GetRootIndex(); - const Vk_ROOT_PARAMETER& VkParam = RootTable; - - VERIFY_EXPR(VkParam.ParameterType == Vk_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE); - - auto &VkTable = VkParam.DescriptorTable; - VERIFY(VkTable.NumDescriptorRanges > 0 && RootTable.GetDescriptorTableSize() > 0, "Unexepected empty descriptor table"); - bool IsResourceTable = VkTable.pDescriptorRanges[0].RangeType != Vk_DESCRIPTOR_RANGE_TYPE_SAMPLER; - Vk_DESCRIPTOR_HEAP_TYPE dbgHeapType = Vk_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; -#ifdef _DEBUG - dbgHeapType = IsResourceTable ? Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV : Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER; -#endif - Operation(RootInd, RootTable, VkParam, IsResourceTable, dbgHeapType); - } -} - -template -__forceinline void ProcessCachedTableResources(Uint32 RootInd, - const Vk_ROOT_PARAMETER& VkParam, - ShaderResourceCacheVk& ResourceCache, - Vk_DESCRIPTOR_HEAP_TYPE dbgHeapType, - TOperation Operation) -{ - for (UINT r = 0; r < VkParam.DescriptorTable.NumDescriptorRanges; ++r) - { - const auto &range = VkParam.DescriptorTable.pDescriptorRanges[r]; - for (UINT d = 0; d < range.NumDescriptors; ++d) - { - SHADER_TYPE dbgShaderType = SHADER_TYPE_UNKNOWN; -#ifdef _DEBUG - dbgShaderType = ShaderTypeFromShaderVisibility(VkParam.ShaderVisibility); - VERIFY(dbgHeapType == HeapTypeFromRangeType(range.RangeType), "Mistmatch between descriptor heap type and descriptor range type"); -#endif - auto OffsetFromTableStart = range.OffsetInDescriptorsFromTableStart + d; - auto& Res = ResourceCache.GetRootTable(RootInd).GetResource(OffsetFromTableStart, dbgHeapType, dbgShaderType); - - Operation(OffsetFromTableStart, range, Res); - } - } -} - - -template -void RootSignature::CommitDescriptorHandlesInternal_SMD(RenderDeviceVkImpl *pRenderDeviceVk, - ShaderResourceCacheVk& ResourceCache, - CommandContext &Ctx, - bool IsCompute)const -{ - auto *pVkDevice = pRenderDeviceVk->GetVkDevice(); - - Uint32 NumDynamicCbvSrvUavDescriptors = m_TotalSrvCbvUavSlots[SHADER_VARIABLE_TYPE_DYNAMIC]; - Uint32 NumDynamicSamplerDescriptors = m_TotalSamplerSlots[SHADER_VARIABLE_TYPE_DYNAMIC]; - VERIFY_EXPR(NumDynamicCbvSrvUavDescriptors > 0 || NumDynamicSamplerDescriptors > 0); - - DescriptorHeapAllocation DynamicCbvSrvUavDescriptors, DynamicSamplerDescriptors; - if(NumDynamicCbvSrvUavDescriptors) - DynamicCbvSrvUavDescriptors = Ctx.AllocateDynamicGPUVisibleDescriptor(Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, NumDynamicCbvSrvUavDescriptors); - if(NumDynamicSamplerDescriptors) - DynamicSamplerDescriptors = Ctx.AllocateDynamicGPUVisibleDescriptor(Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER, NumDynamicSamplerDescriptors); - - CommandContext::ShaderDescriptorHeaps Heaps(ResourceCache.GetSrvCbvUavDescriptorHeap(), ResourceCache.GetSamplerDescriptorHeap()); - if(Heaps.pSamplerHeap == nullptr) - Heaps.pSamplerHeap = DynamicSamplerDescriptors.GetDescriptorHeap(); - - if(Heaps.pSrvCbvUavHeap == nullptr) - Heaps.pSrvCbvUavHeap = DynamicCbvSrvUavDescriptors.GetDescriptorHeap(); - - if(NumDynamicCbvSrvUavDescriptors) - VERIFY(DynamicCbvSrvUavDescriptors.GetDescriptorHeap() == Heaps.pSrvCbvUavHeap, "Inconsistent CbvSrvUav descriptor heaps" ); - if(NumDynamicSamplerDescriptors) - VERIFY(DynamicSamplerDescriptors.GetDescriptorHeap() == Heaps.pSamplerHeap, "Inconsistent Sampler descriptor heaps" ); - - if(Heaps) - Ctx.SetDescriptorHeaps(Heaps); - - // Offset to the beginning of the current dynamic CBV_SRV_UAV/SAMPLER table from - // the start of the allocation - Uint32 DynamicCbvSrvUavTblOffset = 0; - Uint32 DynamicSamplerTblOffset = 0; - - m_RootParams.ProcessRootTables( - [&](Uint32 RootInd, const RootParameter &RootTable, const Vk_ROOT_PARAMETER& VkParam, bool IsResourceTable, Vk_DESCRIPTOR_HEAP_TYPE dbgHeapType ) - { - Vk_GPU_DESCRIPTOR_HANDLE RootTableGPUDescriptorHandle; - bool IsDynamicTable = RootTable.GetShaderVariableType() == SHADER_VARIABLE_TYPE_DYNAMIC; - if (IsDynamicTable) - { - if( IsResourceTable ) - RootTableGPUDescriptorHandle = DynamicCbvSrvUavDescriptors.GetGpuHandle(DynamicCbvSrvUavTblOffset); - else - RootTableGPUDescriptorHandle = DynamicSamplerDescriptors.GetGpuHandle(DynamicSamplerTblOffset); - } - else - { - RootTableGPUDescriptorHandle = IsResourceTable ? - ResourceCache.GetShaderVisibleTableGPUDescriptorHandle(RootInd) : - ResourceCache.GetShaderVisibleTableGPUDescriptorHandle(RootInd); - VERIFY(RootTableGPUDescriptorHandle.ptr != 0, "Unexpected null GPU descriptor handle"); - } - - if(IsCompute) - Ctx.GetCommandList()->SetComputeRootDescriptorTable(RootInd, RootTableGPUDescriptorHandle); - else - Ctx.GetCommandList()->SetGraphicsRootDescriptorTable(RootInd, RootTableGPUDescriptorHandle); - - ProcessCachedTableResources(RootInd, VkParam, ResourceCache, dbgHeapType, - [&](UINT OffsetFromTableStart, const Vk_DESCRIPTOR_RANGE &range, ShaderResourceCacheVk::Resource &Res) - { - if(PerformResourceTransitions) - { - TransitionResource(Ctx, Res, range.RangeType); - } -#ifdef _DEBUG - else - { - DbgVerifyResourceState(Res, range.RangeType); - } -#endif - - if(IsDynamicTable) - { - if (IsResourceTable) - { - if( Res.CPUDescriptorHandle.ptr == 0 ) - LOG_ERROR_MESSAGE("No valid CbvSrvUav descriptor handle found for root parameter ", RootInd, ", descriptor slot ", OffsetFromTableStart); - - VERIFY( DynamicCbvSrvUavTblOffset < NumDynamicCbvSrvUavDescriptors, "Not enough space in the descriptor heap allocation"); - - pVkDevice->CopyDescriptorsSimple(1, DynamicCbvSrvUavDescriptors.GetCpuHandle(DynamicCbvSrvUavTblOffset), Res.CPUDescriptorHandle, Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); - ++DynamicCbvSrvUavTblOffset; - } - else - { - if( Res.CPUDescriptorHandle.ptr == 0 ) - LOG_ERROR_MESSAGE("No valid sampler descriptor handle found for root parameter ", RootInd, ", descriptor slot ", OffsetFromTableStart); - - VERIFY( DynamicSamplerTblOffset < NumDynamicSamplerDescriptors, "Not enough space in the descriptor heap allocation"); - - pVkDevice->CopyDescriptorsSimple(1, DynamicSamplerDescriptors.GetCpuHandle(DynamicSamplerTblOffset), Res.CPUDescriptorHandle, Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER); - ++DynamicSamplerTblOffset; - } - } - } - ); - } - ); - - VERIFY_EXPR( DynamicCbvSrvUavTblOffset == NumDynamicCbvSrvUavDescriptors ); - VERIFY_EXPR( DynamicSamplerTblOffset == NumDynamicSamplerDescriptors ); -} - -template -void RootSignature::CommitDescriptorHandlesInternal_SM(RenderDeviceVkImpl *pRenderDeviceVk, - ShaderResourceCacheVk& ResourceCache, - CommandContext &Ctx, - bool IsCompute)const -{ - VERIFY_EXPR(m_TotalSrvCbvUavSlots[SHADER_VARIABLE_TYPE_DYNAMIC] == 0 && m_TotalSamplerSlots[SHADER_VARIABLE_TYPE_DYNAMIC] == 0); - - CommandContext::ShaderDescriptorHeaps Heaps(ResourceCache.GetSrvCbvUavDescriptorHeap(), ResourceCache.GetSamplerDescriptorHeap()); - if(Heaps) - Ctx.SetDescriptorHeaps(Heaps); - - m_RootParams.ProcessRootTables( - [&](Uint32 RootInd, const RootParameter &RootTable, const Vk_ROOT_PARAMETER& VkParam, bool IsResourceTable, Vk_DESCRIPTOR_HEAP_TYPE dbgHeapType ) - { - VERIFY(RootTable.GetShaderVariableType() != SHADER_VARIABLE_TYPE_DYNAMIC, "Unexpected dynamic resource"); - - Vk_GPU_DESCRIPTOR_HANDLE RootTableGPUDescriptorHandle = IsResourceTable ? - ResourceCache.GetShaderVisibleTableGPUDescriptorHandle(RootInd) : - ResourceCache.GetShaderVisibleTableGPUDescriptorHandle(RootInd); - VERIFY(RootTableGPUDescriptorHandle.ptr != 0, "Unexpected null GPU descriptor handle"); - - if(IsCompute) - Ctx.GetCommandList()->SetComputeRootDescriptorTable(RootInd, RootTableGPUDescriptorHandle); - else - Ctx.GetCommandList()->SetGraphicsRootDescriptorTable(RootInd, RootTableGPUDescriptorHandle); - - if(PerformResourceTransitions) - { - ProcessCachedTableResources(RootInd, VkParam, ResourceCache, dbgHeapType, - [&](UINT OffsetFromTableStart, const Vk_DESCRIPTOR_RANGE &range, ShaderResourceCacheVk::Resource &Res) - { - TransitionResource(Ctx, Res, range.RangeType); - } - ); - } -#ifdef _DEBUG - else - { - ProcessCachedTableResources(RootInd, VkParam, ResourceCache, dbgHeapType, - [&](UINT OffsetFromTableStart, const Vk_DESCRIPTOR_RANGE &range, ShaderResourceCacheVk::Resource &Res) - { - DbgVerifyResourceState(Res, range.RangeType); - } - ); - } -#endif - } - ); -} - - -void RootSignature::TransitionResources(ShaderResourceCacheVk& ResourceCache, - class CommandContext &Ctx)const -{ - m_RootParams.ProcessRootTables( - [&](Uint32 RootInd, const RootParameter &RootTable, const Vk_ROOT_PARAMETER& VkParam, bool IsResourceTable, Vk_DESCRIPTOR_HEAP_TYPE dbgHeapType ) - { - ProcessCachedTableResources(RootInd, VkParam, ResourceCache, dbgHeapType, - [&](UINT OffsetFromTableStart, const Vk_DESCRIPTOR_RANGE &range, ShaderResourceCacheVk::Resource &Res) - { - TransitionResource(Ctx, Res, range.RangeType); - } - ); - } - ); -} - - -void RootSignature::CommitRootViews(ShaderResourceCacheVk& ResourceCache, - CommandContext &Ctx, - bool IsCompute, - Uint32 ContextId)const -{ - for(Uint32 rv = 0; rv < m_RootParams.GetNumRootViews(); ++rv) - { - auto &RootView = m_RootParams.GetRootView(rv); - auto RootInd = RootView.GetRootIndex(); - - SHADER_TYPE dbgShaderType = SHADER_TYPE_UNKNOWN; -#ifdef _DEBUG - auto &Param = static_cast( RootView ); - VERIFY_EXPR(Param.ParameterType == Vk_ROOT_PARAMETER_TYPE_CBV); - dbgShaderType = ShaderTypeFromShaderVisibility(Param.ShaderVisibility); -#endif - - auto& Res = ResourceCache.GetRootTable(RootInd).GetResource(0, Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, dbgShaderType); - auto *pBuffToTransition = Res.pObject.RawPtr(); - if( !pBuffToTransition->CheckAllStates(Vk_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER) ) - Ctx.TransitionResource(pBuffToTransition, Vk_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER); - - Vk_GPU_VIRTUAL_ADDRESS CBVAddress = pBuffToTransition->GetGPUAddress(ContextId); - if(IsCompute) - Ctx.GetCommandList()->SetComputeRootConstantBufferView(RootInd, CBVAddress); - else - Ctx.GetCommandList()->SetGraphicsRootConstantBufferView(RootInd, CBVAddress); - } -} -#endif -} -- cgit v1.2.3