summaryrefslogtreecommitdiffstats
path: root/Graphics/GraphicsEngineVulkan
diff options
context:
space:
mode:
authorazhirnov <zh1dron@gmail.com>2021-01-15 23:56:25 +0000
committerazhirnov <zh1dron@gmail.com>2021-01-15 23:56:25 +0000
commit8a3b697948704337d08af7bea93627f5e647899e (patch)
tree852d3b0f7ea9fa9fa0ffcf2df81a5a5472371183 /Graphics/GraphicsEngineVulkan
parentIBufferSuballocation: added SetUserData()/GetUserData() methods (diff)
downloadDiligentCore-8a3b697948704337d08af7bea93627f5e647899e.tar.gz
DiligentCore-8a3b697948704337d08af7bea93627f5e647899e.zip
added pipeline resource signature (wip)
Diffstat (limited to 'Graphics/GraphicsEngineVulkan')
-rw-r--r--Graphics/GraphicsEngineVulkan/CMakeLists.txt10
-rw-r--r--Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp13
-rw-r--r--Graphics/GraphicsEngineVulkan/include/PipelineLayout.hpp271
-rw-r--r--Graphics/GraphicsEngineVulkan/include/PipelineLayoutCacheVk.hpp82
-rw-r--r--Graphics/GraphicsEngineVulkan/include/PipelineLayoutVk.hpp174
-rw-r--r--Graphics/GraphicsEngineVulkan/include/PipelineResourceSignatureVkImpl.hpp178
-rw-r--r--Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp105
-rw-r--r--Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp12
-rw-r--r--Graphics/GraphicsEngineVulkan/include/ShaderResourceBindingVkImpl.hpp24
-rw-r--r--Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.hpp65
-rw-r--r--Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.hpp478
-rw-r--r--Graphics/GraphicsEngineVulkan/include/ShaderVariableVk.hpp142
-rw-r--r--Graphics/GraphicsEngineVulkan/include/ShaderVkImpl.hpp5
-rw-r--r--Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.hpp1
-rw-r--r--Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp146
-rw-r--r--Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp505
-rw-r--r--Graphics/GraphicsEngineVulkan/src/PipelineLayoutCacheVk.cpp80
-rw-r--r--Graphics/GraphicsEngineVulkan/src/PipelineLayoutVk.cpp170
-rw-r--r--Graphics/GraphicsEngineVulkan/src/PipelineResourceSignatureVkImpl.cpp465
-rw-r--r--Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp474
-rw-r--r--Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp26
-rw-r--r--Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp101
-rw-r--r--Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp92
-rw-r--r--Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp1598
-rw-r--r--Graphics/GraphicsEngineVulkan/src/ShaderVariableVk.cpp640
-rw-r--r--Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp14
26 files changed, 2364 insertions, 3507 deletions
diff --git a/Graphics/GraphicsEngineVulkan/CMakeLists.txt b/Graphics/GraphicsEngineVulkan/CMakeLists.txt
index e5cd319c..40a0dd49 100644
--- a/Graphics/GraphicsEngineVulkan/CMakeLists.txt
+++ b/Graphics/GraphicsEngineVulkan/CMakeLists.txt
@@ -16,7 +16,8 @@ set(INCLUDE
include/FramebufferCache.hpp
include/GenerateMipsVkHelper.hpp
include/pch.h
- include/PipelineLayout.hpp
+ include/PipelineLayoutVk.hpp
+ include/PipelineLayoutCacheVk.hpp
include/PipelineStateVkImpl.hpp
include/QueryManagerVk.hpp
include/QueryVkImpl.hpp
@@ -28,7 +29,6 @@ set(INCLUDE
include/ManagedVulkanObject.hpp
include/ShaderResourceBindingVkImpl.hpp
include/ShaderResourceCacheVk.hpp
- include/ShaderResourceLayoutVk.hpp
include/ShaderVariableVk.hpp
include/SwapChainVkImpl.hpp
include/TextureVkImpl.hpp
@@ -39,6 +39,7 @@ set(INCLUDE
include/BottomLevelASVkImpl.hpp
include/TopLevelASVkImpl.hpp
include/ShaderBindingTableVkImpl.hpp
+ include/PipelineResourceSignatureVkImpl.hpp
)
set(VULKAN_UTILS_INCLUDE
@@ -92,7 +93,8 @@ set(SRC
src/VulkanDynamicHeap.cpp
src/FramebufferCache.cpp
src/GenerateMipsVkHelper.cpp
- src/PipelineLayout.cpp
+ src/PipelineLayoutCacheVk.cpp
+ src/PipelineLayoutVk.cpp
src/PipelineStateVkImpl.cpp
src/QueryManagerVk.cpp
src/QueryVkImpl.cpp
@@ -103,7 +105,6 @@ set(SRC
src/ShaderVkImpl.cpp
src/ShaderResourceBindingVkImpl.cpp
src/ShaderResourceCacheVk.cpp
- src/ShaderResourceLayoutVk.cpp
src/ShaderVariableVk.cpp
src/SwapChainVkImpl.cpp
src/TextureVkImpl.cpp
@@ -113,6 +114,7 @@ set(SRC
src/BottomLevelASVkImpl.cpp
src/TopLevelASVkImpl.cpp
src/ShaderBindingTableVkImpl.cpp
+ src/PipelineResourceSignatureVkImpl.cpp
)
set(VULKAN_UTILS_SRC
diff --git a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp
index d9a2c2f2..d91feae3 100644
--- a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp
+++ b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp
@@ -39,7 +39,7 @@
#include "VulkanDynamicHeap.hpp"
#include "ResourceReleaseQueue.hpp"
#include "DescriptorPoolManager.hpp"
-#include "PipelineLayout.hpp"
+#include "PipelineLayoutVk.hpp"
#include "GenerateMipsVkHelper.hpp"
#include "BufferVkImpl.hpp"
#include "TextureVkImpl.hpp"
@@ -53,6 +53,7 @@
#include "BottomLevelASVkImpl.hpp"
#include "TopLevelASVkImpl.hpp"
#include "ShaderBindingTableVkImpl.hpp"
+#include "ShaderResourceBindingVkImpl.hpp"
namespace Diligent
@@ -396,6 +397,7 @@ private:
void CommitVkVertexBuffers();
void CommitViewports();
void CommitScissorRects();
+ void BindShaderResources(PipelineStateVkImpl* pPipelineStateVk);
__forceinline void TransitionOrVerifyBufferState(BufferVkImpl& Buffer,
RESOURCE_STATE_TRANSITION_MODE TransitionMode,
@@ -476,6 +478,14 @@ private:
} m_State;
+ /// AZ TODO: comment
+ using DescSetBindingInfoArray = std::array<PipelineLayoutVk::DescriptorSetBindInfo, 3>;
+ DescSetBindingInfoArray m_DescrSetBindInfo;
+
+ /// AZ TODO: comment
+ using ShaderResourcePerPipelineType = std::array<std::array<RefCntAutoPtr<ShaderResourceBindingVkImpl>, MAX_RESOURCE_SIGNATURES>, 3>;
+ ShaderResourcePerPipelineType m_ShaderResources;
+
/// Render pass that matches currently bound render targets.
/// This render pass may or may not be currently set in the command buffer
VkRenderPass m_vkRenderPass = VK_NULL_HANDLE;
@@ -531,7 +541,6 @@ private:
VulkanDynamicHeap m_DynamicHeap;
DynamicDescriptorSetAllocator m_DynamicDescrSetAllocator;
- PipelineLayout::DescriptorSetBindInfo m_DescrSetBindInfo;
std::shared_ptr<GenerateMipsVkHelper> m_GenerateMipsHelper;
RefCntAutoPtr<IShaderResourceBinding> m_GenerateMipsSRB;
diff --git a/Graphics/GraphicsEngineVulkan/include/PipelineLayout.hpp b/Graphics/GraphicsEngineVulkan/include/PipelineLayout.hpp
deleted file mode 100644
index 4cb99d61..00000000
--- a/Graphics/GraphicsEngineVulkan/include/PipelineLayout.hpp
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- * Copyright 2019-2021 Diligent Graphics LLC
- * Copyright 2015-2019 Egor Yusov
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * In no event and under no legal theory, whether in tort (including negligence),
- * contract, or otherwise, unless required by applicable law (such as deliberate
- * and grossly negligent acts) or agreed to in writing, shall any Contributor be
- * liable for any damages, including any direct, indirect, special, incidental,
- * or consequential damages of any character arising as a result of this License or
- * out of the use or inability to use the software (including but not limited to damages
- * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
- * all other commercial damages or losses), even if such Contributor has been advised
- * of the possibility of such damages.
- */
-
-#pragma once
-
-/// \file
-/// Declaration of Diligent::PipelineLayout class
-#include <array>
-
-#include "ShaderBase.hpp"
-#include "ShaderResourceLayoutVk.hpp"
-#include "VulkanUtilities/VulkanObjectWrappers.hpp"
-#include "VulkanUtilities/VulkanLogicalDevice.hpp"
-#include "VulkanUtilities/VulkanCommandBuffer.hpp"
-
-namespace Diligent
-{
-
-class RenderDeviceVkImpl;
-class DeviceContextVkImpl;
-class ShaderResourceCacheVk;
-
-/// Implementation of the Diligent::PipelineLayout class
-class PipelineLayout
-{
-public:
- static VkDescriptorType GetVkDescriptorType(SPIRVShaderResourceAttribs::ResourceType Type);
-
- PipelineLayout();
- void Release(RenderDeviceVkImpl* pDeviceVkImpl, Uint64 CommandQueueMask);
- void Finalize(const VulkanUtilities::VulkanLogicalDevice& LogicalDevice);
-
- VkPipelineLayout GetVkPipelineLayout() const { return m_LayoutMgr.GetVkPipelineLayout(); }
-
- std::array<Uint32, 2> GetDescriptorSetSizes(Uint32& NumSets) const;
-
- void InitResourceCache(RenderDeviceVkImpl* pDeviceVkImpl,
- ShaderResourceCacheVk& ResourceCache,
- IMemoryAllocator& CacheMemAllocator,
- const char* DbgPipelineName) const;
-
- void AllocateResourceSlot(const SPIRVShaderResourceAttribs& ResAttribs,
- SHADER_RESOURCE_VARIABLE_TYPE VariableType,
- VkSampler vkImmutableSampler,
- SHADER_TYPE ShaderType,
- Uint32& DescriptorSet,
- Uint32& Binding,
- Uint32& OffsetInCache);
-
- Uint32 GetTotalDescriptors(SHADER_RESOURCE_VARIABLE_TYPE VarType) const
- {
- VERIFY_EXPR(VarType >= 0 && VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES);
- return m_LayoutMgr.GetDescriptorSet(VarType).TotalDescriptors;
- }
-
- bool IsSameAs(const PipelineLayout& RS) const
- {
- return m_LayoutMgr == RS.m_LayoutMgr;
- }
- size_t GetHash() const
- {
- return m_LayoutMgr.GetHash();
- }
-
- VkDescriptorSetLayout GetDynamicDescriptorSetVkLayout() const
- {
- return m_LayoutMgr.GetDescriptorSet(SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC).VkLayout;
- }
-
- struct DescriptorSetBindInfo
- {
- std::vector<VkDescriptorSet> vkSets;
- std::vector<uint32_t> DynamicOffsets;
- const ShaderResourceCacheVk* pResourceCache = nullptr;
- VkPipelineBindPoint BindPoint = VK_PIPELINE_BIND_POINT_MAX_ENUM;
- Uint32 SetCout = 0;
- Uint32 DynamicOffsetCount = 0;
- bool DynamicBuffersPresent = false;
- bool DynamicDescriptorsBound = false;
-#ifdef DILIGENT_DEBUG
- const PipelineLayout* pDbgPipelineLayout = nullptr;
-#endif
- DescriptorSetBindInfo() :
- // clang-format off
- vkSets (2),
- DynamicOffsets(64)
- // clang-format on
- {
- }
-
- void Reset()
- {
- pResourceCache = nullptr;
- BindPoint = VK_PIPELINE_BIND_POINT_MAX_ENUM;
- SetCout = 0;
- DynamicOffsetCount = 0;
- DynamicBuffersPresent = false;
- DynamicDescriptorsBound = false;
-
-#ifdef DILIGENT_DEBUG
- // In release mode, do not clear vectors as this causes unnecessary work
- vkSets.clear();
- DynamicOffsets.clear();
-
- pDbgPipelineLayout = nullptr;
-#endif
- }
- };
-
- // Prepares Vulkan descriptor sets for binding. Actual binding
- // may not be possible until draw command time because dynamic offsets are
- // set by the same Vulkan command. If there are no dynamic descriptors, this
- // function also binds descriptor sets rightaway.
- void PrepareDescriptorSets(DeviceContextVkImpl* pCtxVkImpl,
- VkPipelineBindPoint BindPoint,
- const ShaderResourceCacheVk& ResourceCache,
- DescriptorSetBindInfo& BindInfo,
- VkDescriptorSet VkDynamicDescrSet) const;
-
- // Computes dynamic offsets and binds descriptor sets
- __forceinline void BindDescriptorSetsWithDynamicOffsets(VulkanUtilities::VulkanCommandBuffer& CmdBuffer,
- Uint32 CtxId,
- DeviceContextVkImpl* pCtxVkImpl,
- DescriptorSetBindInfo& BindInfo) const;
-
-private:
- class DescriptorSetLayoutManager
- {
- public:
- struct DescriptorSetLayout
- {
- DescriptorSetLayout() noexcept {}
- // clang-format off
- DescriptorSetLayout (DescriptorSetLayout&&) = default;
- DescriptorSetLayout (const DescriptorSetLayout&) = delete;
- DescriptorSetLayout& operator = (const DescriptorSetLayout&) = delete;
- DescriptorSetLayout& operator = (DescriptorSetLayout&&) = delete;
- // clang-format on
-
- uint32_t TotalDescriptors = 0;
- int8_t SetIndex = -1;
- uint8_t NumDynamicDescriptors = 0; // Total number of uniform and storage buffers, counting all array elements
- uint16_t NumLayoutBindings = 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, IMemoryAllocator& MemAllocator, Uint64 CommandQueueMask);
-
- bool operator==(const DescriptorSetLayout& rhs) const;
- bool operator!=(const DescriptorSetLayout& rhs) const { return !(*this == rhs); }
- size_t GetHash() const;
-
- private:
- void ReserveMemory(Uint32 NumBindings, IMemoryAllocator& MemAllocator);
- static size_t GetMemorySize(Uint32 NumBindings);
- };
-
- DescriptorSetLayoutManager(IMemoryAllocator& MemAllocator);
- ~DescriptorSetLayoutManager();
-
- // clang-format off
- DescriptorSetLayoutManager (const DescriptorSetLayoutManager&) = delete;
- DescriptorSetLayoutManager& operator= (const DescriptorSetLayoutManager&) = delete;
- DescriptorSetLayoutManager (DescriptorSetLayoutManager&&) = delete;
- DescriptorSetLayoutManager& operator= (DescriptorSetLayoutManager&&) = delete;
- // clang-format on
-
- void Finalize(const VulkanUtilities::VulkanLogicalDevice& LogicalDevice);
- void Release(RenderDeviceVkImpl* pRenderDeviceVk, Uint64 CommandQueueMask);
-
- DescriptorSetLayout& GetDescriptorSet(SHADER_RESOURCE_VARIABLE_TYPE VarType) { return m_DescriptorSetLayouts[VarType == SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC ? 1 : 0]; }
- const DescriptorSetLayout& GetDescriptorSet(SHADER_RESOURCE_VARIABLE_TYPE VarType) const { return m_DescriptorSetLayouts[VarType == SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC ? 1 : 0]; }
-
- bool operator==(const DescriptorSetLayoutManager& rhs) const;
- bool operator!=(const DescriptorSetLayoutManager& rhs) const { return !(*this == rhs); }
- size_t GetHash() const;
- VkPipelineLayout GetVkPipelineLayout() const { return m_VkPipelineLayout; }
-
- void AllocateResourceSlot(const SPIRVShaderResourceAttribs& ResAttribs,
- SHADER_RESOURCE_VARIABLE_TYPE VariableType,
- VkSampler vkImmutableSampler,
- SHADER_TYPE ShaderType,
- Uint32& DescriptorSet,
- Uint32& Binding,
- Uint32& OffsetInCache);
-
- private:
- IMemoryAllocator& m_MemAllocator;
- VulkanUtilities::PipelineLayoutWrapper m_VkPipelineLayout;
- std::array<DescriptorSetLayout, 2> m_DescriptorSetLayouts;
- std::vector<VkDescriptorSetLayoutBinding, STDAllocatorRawMem<VkDescriptorSetLayoutBinding>> m_LayoutBindings;
- uint8_t m_ActiveSets = 0;
- };
-
- IMemoryAllocator& m_MemAllocator;
- DescriptorSetLayoutManager m_LayoutMgr;
-};
-
-
-__forceinline void PipelineLayout::BindDescriptorSetsWithDynamicOffsets(VulkanUtilities::VulkanCommandBuffer& CmdBuffer,
- Uint32 CtxId,
- DeviceContextVkImpl* pCtxVkImpl,
- DescriptorSetBindInfo& BindInfo) const
-{
- VERIFY(BindInfo.pDbgPipelineLayout != nullptr, "Pipeline layout is not initialized, which most likely means that CommitShaderResources() has never been called");
- VERIFY(BindInfo.pDbgPipelineLayout->IsSameAs(*this), "Inconsistent pipeline layout");
- VERIFY(BindInfo.DynamicOffsetCount > 0, "This function should only be called for pipelines that contain dynamic descriptors");
-
- VERIFY_EXPR(BindInfo.pResourceCache != nullptr);
-#ifdef DILIGENT_DEBUG
- Uint32 TotalDynamicDescriptors = 0;
- for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE; VarType <= SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC; VarType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(VarType + 1))
- {
- const auto& Set = m_LayoutMgr.GetDescriptorSet(VarType);
- TotalDynamicDescriptors += Set.NumDynamicDescriptors;
- }
- VERIFY(BindInfo.DynamicOffsetCount == TotalDynamicDescriptors, "Incosistent dynamic buffer size");
- VERIFY_EXPR(BindInfo.DynamicOffsets.size() >= BindInfo.DynamicOffsetCount);
-#endif
-
- auto NumOffsetsWritten = BindInfo.pResourceCache->GetDynamicBufferOffsets(CtxId, pCtxVkImpl, BindInfo.DynamicOffsets);
- VERIFY_EXPR(NumOffsetsWritten == BindInfo.DynamicOffsetCount);
- (void)NumOffsetsWritten;
-
- // Note that there is one global dynamic buffer from which all dynamic resources are suballocated in Vulkan back-end,
- // and this buffer is not resizable, so the buffer handle can never change.
-
- // vkCmdBindDescriptorSets causes the sets numbered [firstSet .. firstSet+descriptorSetCount-1] to use the
- // bindings stored in pDescriptorSets[0 .. descriptorSetCount-1] for subsequent rendering commands
- // (either compute or graphics, according to the pipelineBindPoint). Any bindings that were previously
- // applied via these sets are no longer valid (13.2.5)
- CmdBuffer.BindDescriptorSets(BindInfo.BindPoint,
- m_LayoutMgr.GetVkPipelineLayout(),
- 0, // First set
- BindInfo.SetCout,
- BindInfo.vkSets.data(), // BindInfo.vkSets is never empty
- // dynamicOffsetCount must equal the total number of dynamic descriptors in the sets being bound (13.2.5)
- BindInfo.DynamicOffsetCount,
- BindInfo.DynamicOffsets.data());
-
- BindInfo.DynamicDescriptorsBound = true;
-}
-
-} // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/include/PipelineLayoutCacheVk.hpp b/Graphics/GraphicsEngineVulkan/include/PipelineLayoutCacheVk.hpp
new file mode 100644
index 00000000..f34110f7
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/include/PipelineLayoutCacheVk.hpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2019-2021 Diligent Graphics LLC
+ * Copyright 2015-2019 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Declaration of Diligent::PipelineLayoutCacheVk class
+
+#include <unordered_set>
+#include <mutex>
+#include "VulkanUtilities/VulkanObjectWrappers.hpp"
+#include "PipelineLayoutVk.hpp"
+
+namespace Diligent
+{
+
+class PipelineLayoutCacheVk
+{
+public:
+ PipelineLayoutCacheVk(RenderDeviceVkImpl& DeviceVKImpl) :
+ m_DeviceVk{DeviceVKImpl}
+ {}
+
+ // clang-format off
+ PipelineLayoutCacheVk (const PipelineLayoutCacheVk&) = delete;
+ PipelineLayoutCacheVk (PipelineLayoutCacheVk&&) = delete;
+ PipelineLayoutCacheVk& operator = (const PipelineLayoutCacheVk&) = delete;
+ PipelineLayoutCacheVk& operator = (PipelineLayoutCacheVk&&) = delete;
+ // clang-format on
+
+ ~PipelineLayoutCacheVk();
+
+ RefCntAutoPtr<PipelineLayoutVk> GetLayout(IPipelineResourceSignature** ppSignatures, Uint32 SignatureCount);
+
+ void OnDestroyLayout(PipelineLayoutVk* pLayout);
+
+private:
+ struct PipelineLayoutHash
+ {
+ std::size_t operator()(const PipelineLayoutVk* Key) const noexcept
+ {
+ return Key->GetHash();
+ }
+ };
+
+ struct PipelineLayoutCompare
+ {
+ bool operator()(const PipelineLayoutVk* lhs, const PipelineLayoutVk* rhs) const noexcept;
+ };
+
+ RenderDeviceVkImpl& m_DeviceVk;
+
+ std::mutex m_Mutex;
+
+ std::unordered_set<PipelineLayoutVk*, PipelineLayoutHash, PipelineLayoutCompare> m_Cache;
+};
+
+} // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/include/PipelineLayoutVk.hpp b/Graphics/GraphicsEngineVulkan/include/PipelineLayoutVk.hpp
new file mode 100644
index 00000000..fd27d0a3
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/include/PipelineLayoutVk.hpp
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2019-2021 Diligent Graphics LLC
+ * Copyright 2015-2019 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Declaration of Diligent::PipelineLayoutVk class
+#include <array>
+
+#include "PipelineResourceSignatureVkImpl.hpp"
+#include "VulkanUtilities/VulkanObjectWrappers.hpp"
+#include "VulkanUtilities/VulkanLogicalDevice.hpp"
+#include "VulkanUtilities/VulkanCommandBuffer.hpp"
+
+namespace Diligent
+{
+
+class DeviceContextVkImpl;
+class ShaderResourceCacheVk;
+
+/// Implementation of the Diligent::PipelineLayoutVk class
+class PipelineLayoutVk final : public ObjectBase<IObject>
+{
+public:
+ PipelineLayoutVk(IReferenceCounters* pRefCounters, RenderDeviceVkImpl* pDeviceVk, IPipelineResourceSignature** ppSignatures, Uint32 SignatureCount);
+ ~PipelineLayoutVk();
+
+ using ObjectBase<IObject>::Release;
+
+ void Finalize();
+
+ size_t GetHash() const;
+
+ VkPipelineLayout GetVkPipelineLayout() const { return m_VkPipelineLayout; }
+ PIPELINE_TYPE GetPipelineType() const { return m_PipelineType; }
+ Uint32 GetSignatureCount() const { return m_SignatureCount; }
+ Uint32 GetDescriptorSetCount() const { return m_DescrSetCount; }
+ Uint32 GetDynamicOffsetCount() const { return m_DynamicOffsetCount; }
+
+ IPipelineResourceSignature* GetSignature(Uint32 index) const
+ {
+ VERIFY_EXPR(index < m_SignatureCount);
+ return m_Signatures[index].RawPtr<IPipelineResourceSignature>();
+ }
+
+ bool HasSignature(IPipelineResourceSignature* pPRS) const
+ {
+ Uint32 Index = pPRS->GetDesc().BindingIndex;
+ return Index < m_SignatureCount && m_Signatures[Index].RawPtr() == pPRS;
+ }
+
+ Uint32 GetDescrSetIndex(IPipelineResourceSignature* pPRS) const
+ {
+ Uint32 Index = pPRS->GetDesc().BindingIndex;
+ return Index < m_SignatureCount ? m_DescSetOffset[Index] : ~0u;
+ }
+
+ Uint32 GetDynamicBufferOffset(IPipelineResourceSignature* pPRS) const
+ {
+ Uint32 Index = pPRS->GetDesc().BindingIndex;
+ return Index < m_SignatureCount ? m_DynBufOffset[Index] : 0;
+ }
+
+ struct ResourceInfo
+ {
+ SHADER_RESOURCE_TYPE Type = SHADER_RESOURCE_TYPE_UNKNOWN;
+ Uint16 DescrSetIndex = 0;
+ Uint16 BindingIndex = 0;
+ };
+ bool GetResourceInfo(const char* Name, SHADER_TYPE Stage, ResourceInfo& Info) const;
+
+ using DescriptorSetBindInfo = PipelineResourceSignatureVkImpl::DescriptorSetBindInfo;
+
+ // Computes dynamic offsets and binds descriptor sets
+ __forceinline void BindDescriptorSetsWithDynamicOffsets(VulkanUtilities::VulkanCommandBuffer& CmdBuffer,
+ Uint32 CtxId,
+ DeviceContextVkImpl* pCtxVkImpl,
+ DescriptorSetBindInfo& BindInfo) const;
+
+private:
+ VulkanUtilities::PipelineLayoutWrapper m_VkPipelineLayout;
+
+ RenderDeviceVkImpl* m_pDeviceVk;
+
+ // AZ TODO: pack bits
+ Uint16 m_DynamicOffsetCount = 0;
+ Uint8 m_SignatureCount = 0;
+ Uint8 m_DescrSetCount = 0;
+
+ PIPELINE_TYPE m_PipelineType = PIPELINE_TYPE(0xFF);
+
+ using SignatureArray = std::array<RefCntAutoPtr<PipelineResourceSignatureVkImpl>, MAX_RESOURCE_SIGNATURES>;
+ using DescSetOffsetArray = std::array<Uint8, MAX_RESOURCE_SIGNATURES>;
+ using DynBufOffsetArray = std::array<Uint16, MAX_RESOURCE_SIGNATURES>;
+
+ SignatureArray m_Signatures;
+ DescSetOffsetArray m_DescSetOffset = {};
+ DynBufOffsetArray m_DynBufOffset = {};
+};
+
+
+__forceinline void PipelineLayoutVk::BindDescriptorSetsWithDynamicOffsets(VulkanUtilities::VulkanCommandBuffer& CmdBuffer,
+ Uint32 CtxId,
+ DeviceContextVkImpl* pCtxVkImpl,
+ DescriptorSetBindInfo& BindInfo) const
+{
+ /*
+ VERIFY(BindInfo.pDbgPipelineLayout != nullptr, "Pipeline layout is not initialized, which most likely means that CommitShaderResources() has never been called");
+ VERIFY(BindInfo.pDbgPipelineLayout->IsSameAs(*this), "Inconsistent pipeline layout");
+ VERIFY(BindInfo.DynamicOffsetCount > 0, "This function should only be called for pipelines that contain dynamic descriptors");
+ VERIFY_EXPR(BindInfo.pResourceCache != nullptr);
+
+#ifdef DILIGENT_DEBUG
+ Uint32 TotalDynamicDescriptors = 0;
+ for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE;
+ VarType <= SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC;
+ VarType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(VarType + 1))
+ {
+ const auto& Set = m_LayoutMgr.GetDescriptorSet(VarType);
+ TotalDynamicDescriptors += Set.NumDynamicDescriptors;
+ }
+ VERIFY(BindInfo.DynamicOffsetCount == TotalDynamicDescriptors, "Incosistent dynamic buffer size");
+ VERIFY_EXPR(BindInfo.DynamicOffsets.size() >= BindInfo.DynamicOffsetCount);
+#endif
+
+ auto NumOffsetsWritten = BindInfo.pResourceCache->GetDynamicBufferOffsets(CtxId, pCtxVkImpl, BindInfo.DynamicOffsets);
+ VERIFY_EXPR(NumOffsetsWritten == BindInfo.DynamicOffsetCount);
+ (void)NumOffsetsWritten;
+
+ // Note that there is one global dynamic buffer from which all dynamic resources are suballocated in Vulkan back-end,
+ // and this buffer is not resizable, so the buffer handle can never change.
+
+ // vkCmdBindDescriptorSets causes the sets numbered [firstSet .. firstSet+descriptorSetCount-1] to use the
+ // bindings stored in pDescriptorSets[0 .. descriptorSetCount-1] for subsequent rendering commands
+ // (either compute or graphics, according to the pipelineBindPoint). Any bindings that were previously
+ // applied via these sets are no longer valid (13.2.5)
+ CmdBuffer.BindDescriptorSets(BindInfo.BindPoint,
+ m_LayoutMgr.GetVkPipelineLayout(),
+ 0, // First set
+ BindInfo.SetCout,
+ BindInfo.vkSets.data(), // BindInfo.vkSets is never empty
+ // dynamicOffsetCount must equal the total number of dynamic descriptors in the sets being bound (13.2.5)
+ BindInfo.DynamicOffsetCount,
+ BindInfo.DynamicOffsets.data());
+
+ BindInfo.DynamicDescriptorsBound = true;
+*/
+}
+
+} // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/include/PipelineResourceSignatureVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/PipelineResourceSignatureVkImpl.hpp
new file mode 100644
index 00000000..6b01b4cd
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/include/PipelineResourceSignatureVkImpl.hpp
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2019-2021 Diligent Graphics LLC
+ * Copyright 2015-2019 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Declaration of Diligent::PipelineResourceSignatureVkImpl class
+#include <array>
+
+#include "PipelineResourceSignatureBase.hpp"
+#include "VulkanUtilities/VulkanObjectWrappers.hpp"
+#include "VulkanUtilities/VulkanLogicalDevice.hpp"
+#include "VulkanUtilities/VulkanCommandBuffer.hpp"
+#include "SRBMemoryAllocator.hpp"
+
+namespace Diligent
+{
+class RenderDeviceVkImpl;
+class ShaderResourceCacheVk;
+class ShaderVariableManagerVk;
+class DeviceContextVkImpl;
+
+/// Implementation of the Diligent::PipelineResourceSignatureVkImpl class
+class PipelineResourceSignatureVkImpl final : public PipelineResourceSignatureBase<IPipelineResourceSignature, RenderDeviceVkImpl>
+{
+public:
+ using TPipelineResourceSignatureBase = PipelineResourceSignatureBase<IPipelineResourceSignature, RenderDeviceVkImpl>;
+
+ PipelineResourceSignatureVkImpl(IReferenceCounters* pRefCounters,
+ RenderDeviceVkImpl* pDevice,
+ const PipelineResourceSignatureDesc& Desc,
+ bool bIsDeviceInternal = false);
+ ~PipelineResourceSignatureVkImpl();
+
+ Uint32 GetDynamicBufferCount() const { return m_DynamicBufferCount; }
+ Uint8 GetNumShaderStages() const { return m_NumShaders; }
+ Uint32 GetTotalResourceCount() const { return m_Desc.NumResources; }
+
+ static constexpr Uint8 InvalidSamplerInd = 0xFF;
+
+ struct PackedBindingIndex
+ {
+ Uint16 Binding;
+ Uint8 DescSet : 1; // 0 - static, 1 - dynamic
+ Uint8 SamplerInd = InvalidSamplerInd;
+ };
+
+ const PackedBindingIndex& GetBinding(Uint32 ResIndex) const
+ {
+ VERIFY_EXPR(ResIndex < m_Desc.NumResources);
+ return m_pBindingIndices[ResIndex];
+ }
+
+ const PipelineResourceDesc& GetResource(Uint32 ResIndex) const
+ {
+ VERIFY_EXPR(ResIndex < m_Desc.NumResources);
+ return m_Desc.Resources[ResIndex];
+ }
+
+ VkDescriptorSetLayout GetStaticVkDescriptorSetLayout() const { return m_VkDescSetLayouts[0]; }
+ VkDescriptorSetLayout GetDynamicVkDescriptorSetLayout() const { return m_VkDescSetLayouts[1]; }
+
+ virtual void DILIGENT_CALL_TYPE CreateShaderResourceBinding(IShaderResourceBinding** ppShaderResourceBinding,
+ bool InitStaticResources) override final;
+
+ virtual IShaderResourceVariable* DILIGENT_CALL_TYPE GetStaticVariableByName(SHADER_TYPE ShaderType, const Char* Name) override final;
+
+ virtual IShaderResourceVariable* DILIGENT_CALL_TYPE GetStaticVariableByIndex(SHADER_TYPE ShaderType, Uint32 Index) override final;
+
+ virtual Uint32 DILIGENT_CALL_TYPE GetStaticVariableCount(SHADER_TYPE ShaderType) const override final;
+
+ using VkDescSetArray = std::array<VkDescriptorSet, MAX_RESOURCE_SIGNATURES * 2>;
+
+ struct DescriptorSetBindInfo
+ {
+ VkDescSetArray vkSets;
+ std::vector<uint32_t> DynamicOffsets;
+ const ShaderResourceCacheVk* pResourceCache = nullptr;
+ Uint32 SetCout = 0;
+ Uint32 DynamicOffsetCount = 0;
+ bool DynamicBuffersPresent = false;
+ bool DynamicDescriptorsBound = false;
+#ifdef DILIGENT_DEBUG
+ //const PipelineLayoutVk* pDbgPipelineLayout = nullptr;
+#endif
+ DescriptorSetBindInfo() :
+ DynamicOffsets(64)
+ {
+ }
+
+ void Reset()
+ {
+ pResourceCache = nullptr;
+ SetCout = 0;
+ DynamicOffsetCount = 0;
+ DynamicBuffersPresent = false;
+ DynamicDescriptorsBound = false;
+
+#ifdef DILIGENT_DEBUG
+ // In release mode, do not clear vectors as this causes unnecessary work
+ DynamicOffsets.clear();
+
+ //pDbgPipelineLayout = nullptr;
+#endif
+ }
+ };
+
+ void PrepareDescriptorSets(DeviceContextVkImpl* pCtxVkImpl,
+ VkPipelineBindPoint BindPoint,
+ const ShaderResourceCacheVk& ResourceCache,
+ DescriptorSetBindInfo& BindInfo,
+ VkDescriptorSet VkDynamicDescrSet) const;
+
+ static VkDescriptorType GetVkDescriptorType(const PipelineResourceDesc& Res);
+
+ SHADER_TYPE GetShaderStageType(Uint32 StageIndex) const;
+
+ SRBMemoryAllocator& GetSRBMemoryAllocator()
+ {
+ return m_SRBMemAllocator;
+ }
+
+ void InitResourceCache(ShaderResourceCacheVk& ResourceCache,
+ IMemoryAllocator& CacheMemAllocator,
+ const char* DbgPipelineName) const;
+
+ // Initializes resource slots in the ResourceCache
+ void InitializeResourceMemoryInCache(ShaderResourceCacheVk& ResourceCache) const;
+
+ void InitializeStaticSRBResources(ShaderResourceCacheVk& ResourceCache) const;
+
+private:
+ void Destruct();
+
+ VulkanUtilities::DescriptorSetLayoutWrapper m_VkDescSetLayouts[2];
+
+ PackedBindingIndex* m_pBindingIndices = nullptr; // [m_Desc.NumResources]
+
+ SHADER_TYPE m_ShaderStages = SHADER_TYPE_UNKNOWN;
+
+ Uint16 m_DynamicBufferCount = 0;
+ Uint8 m_NumShaders = 0;
+
+ std::array<Int8, MAX_SHADERS_IN_PIPELINE> m_StaticVarIndex = {-1, -1, -1, -1, -1, -1};
+ static_assert(MAX_SHADERS_IN_PIPELINE == 6, "Please update the initializer list above");
+
+ ShaderResourceCacheVk* m_pResourceCache = nullptr;
+ ShaderVariableManagerVk* m_StaticVarsMgrs = nullptr; // [0..MAX_SHADERS_IN_PIPELINE]
+
+ SRBMemoryAllocator m_SRBMemAllocator;
+};
+
+
+} // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp
index 6a753048..46d0fc93 100644
--- a/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp
+++ b/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp
@@ -35,21 +35,20 @@
#include "RenderDeviceVk.h"
#include "PipelineStateVk.h"
#include "PipelineStateBase.hpp"
-#include "PipelineLayout.hpp"
-#include "ShaderResourceLayoutVk.hpp"
#include "ShaderVariableVk.hpp"
#include "FixedBlockMemoryAllocator.hpp"
#include "SRBMemoryAllocator.hpp"
#include "VulkanUtilities/VulkanObjectWrappers.hpp"
#include "VulkanUtilities/VulkanCommandBuffer.hpp"
-#include "PipelineLayout.hpp"
#include "RenderDeviceVkImpl.hpp"
+#include "PipelineLayoutVk.hpp"
namespace Diligent
{
class FixedBlockMemoryAllocator;
class ShaderVariableManagerVk;
+class ShaderVkImpl;
/// Pipeline state object implementation in Vulkan backend.
class PipelineStateVkImpl final : public PipelineStateBase<IPipelineStateVk, RenderDeviceVkImpl>
@@ -64,9 +63,6 @@ public:
IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_PipelineStateVk, TPipelineStateBase)
- /// Implementation of IPipelineState::CreateShaderResourceBinding() in Vulkan backend.
- virtual void DILIGENT_CALL_TYPE CreateShaderResourceBinding(IShaderResourceBinding** ppShaderResourceBinding, bool InitStaticResources) override final;
-
/// Implementation of IPipelineState::IsCompatibleWith() in Vulkan backend.
virtual bool DILIGENT_CALL_TYPE IsCompatibleWith(const IPipelineState* pPSO) const override final;
@@ -79,41 +75,21 @@ public:
/// Implementation of IPipelineState::BindStaticResources() in Vulkan backend.
virtual void DILIGENT_CALL_TYPE BindStaticResources(Uint32 ShaderFlags, IResourceMapping* pResourceMapping, Uint32 Flags) override final;
- /// Implementation of IPipelineState::GetStaticVariableCount() in Vulkan backend.
- virtual Uint32 DILIGENT_CALL_TYPE GetStaticVariableCount(SHADER_TYPE ShaderType) const override final;
-
- /// Implementation of IPipelineState::GetStaticVariableByName() in Vulkan backend.
- virtual IShaderResourceVariable* DILIGENT_CALL_TYPE GetStaticVariableByName(SHADER_TYPE ShaderType, const Char* Name) override final;
+ /// Implementation of IPipelineState::GetResourceSignatureCount() in Vulkan backend.
+ virtual Uint32 DILIGENT_CALL_TYPE GetResourceSignatureCount() const override final { return m_PipelineLayout->GetSignatureCount(); }
- /// Implementation of IPipelineState::GetStaticVariableByIndex() in Vulkan backend.
- virtual IShaderResourceVariable* DILIGENT_CALL_TYPE GetStaticVariableByIndex(SHADER_TYPE ShaderType, Uint32 Index) override final;
+ /// Implementation of IPipelineState::GetResourceSignature() in Vulkan backend.
+ virtual IPipelineResourceSignature* DILIGENT_CALL_TYPE GetResourceSignature(Uint32 Index) const override final { return m_PipelineLayout->GetSignature(Index); }
- void CommitAndTransitionShaderResources(IShaderResourceBinding* pShaderResourceBinding,
- DeviceContextVkImpl* pCtxVkImpl,
- bool CommitResources,
- RESOURCE_STATE_TRANSITION_MODE StateTransitionMode,
- PipelineLayout::DescriptorSetBindInfo* pDescrSetBindInfo) const;
-
- __forceinline void BindDescriptorSetsWithDynamicOffsets(VulkanUtilities::VulkanCommandBuffer& CmdBuffer,
- Uint32 CtxId,
- DeviceContextVkImpl* pCtxVkImpl,
- PipelineLayout::DescriptorSetBindInfo& BindInfo)
+ __forceinline void BindDescriptorSetsWithDynamicOffsets(VulkanUtilities::VulkanCommandBuffer& CmdBuffer,
+ Uint32 CtxId,
+ DeviceContextVkImpl* pCtxVkImpl,
+ PipelineLayoutVk::DescriptorSetBindInfo& BindInfo)
{
- m_PipelineLayout.BindDescriptorSetsWithDynamicOffsets(CmdBuffer, CtxId, pCtxVkImpl, BindInfo);
+ m_PipelineLayout->BindDescriptorSetsWithDynamicOffsets(CmdBuffer, CtxId, pCtxVkImpl, BindInfo);
}
- const PipelineLayout& GetPipelineLayout() const { return m_PipelineLayout; }
-
- const ShaderResourceLayoutVk& GetShaderResLayout(Uint32 ShaderInd) const
- {
- VERIFY_EXPR(ShaderInd < GetNumShaderStages());
- return m_ShaderResourceLayouts[ShaderInd];
- }
-
- SRBMemoryAllocator& GetSRBMemoryAllocator()
- {
- return m_SRBMemAllocator;
- }
+ const PipelineLayoutVk& GetPipelineLayout() const { return *m_PipelineLayout; }
static RenderPassDesc GetImplicitRenderPassDesc(Uint32 NumRenderTargets,
const TEXTURE_FORMAT RTVFormats[],
@@ -126,50 +102,45 @@ public:
void InitializeStaticSRBResources(ShaderResourceCacheVk& ResourceCache) const;
-private:
- using TShaderStages = ShaderResourceLayoutVk::TShaderStages;
+ bool IsIncompatibleWith(IPipelineResourceSignature* pPRS) const
+ {
+ return !m_PipelineLayout->HasSignature(pPRS);
+ }
+
+ struct ShaderStageInfo
+ {
+ ShaderStageInfo() {}
+ ShaderStageInfo(const ShaderVkImpl* pShader);
+
+ void Append(const ShaderVkImpl* pShader);
+ size_t Count() const;
+ // Shader stage type. All shaders in the stage must have the same type.
+ SHADER_TYPE Type = SHADER_TYPE_UNKNOWN;
+
+ std::vector<const ShaderVkImpl*> Shaders;
+ std::vector<std::vector<uint32_t>> SPIRVs;
+ };
+ using TShaderStages = std::vector<ShaderStageInfo>;
+
+private:
template <typename PSOCreateInfoType>
TShaderStages InitInternalObjects(const PSOCreateInfoType& CreateInfo,
std::vector<VkPipelineShaderStageCreateInfo>& vkShaderStages,
std::vector<VulkanUtilities::ShaderModuleWrapper>& ShaderModules);
+ void InitPipelineLayout(const PipelineStateCreateInfo& CreateInfo,
+ TShaderStages& ShaderStages);
+
void InitResourceLayouts(const PipelineStateCreateInfo& CreateInfo,
TShaderStages& ShaderStages);
void Destruct();
- const ShaderResourceLayoutVk& GetStaticShaderResLayout(Uint32 ShaderInd) const
- {
- VERIFY_EXPR(ShaderInd < GetNumShaderStages());
- return m_ShaderResourceLayouts[GetNumShaderStages() + ShaderInd];
- }
-
- const ShaderResourceCacheVk& GetStaticResCache(Uint32 ShaderInd) const
- {
- VERIFY_EXPR(ShaderInd < GetNumShaderStages());
- return m_StaticResCaches[ShaderInd];
- }
-
- const ShaderVariableManagerVk& GetStaticVarMgr(Uint32 ShaderInd) const
- {
- VERIFY_EXPR(ShaderInd < GetNumShaderStages());
- return m_StaticVarsMgrs[ShaderInd];
- }
-
- ShaderResourceLayoutVk* m_ShaderResourceLayouts = nullptr; // [m_NumShaderStages * 2]
- ShaderResourceCacheVk* m_StaticResCaches = nullptr; // [m_NumShaderStages]
- ShaderVariableManagerVk* m_StaticVarsMgrs = nullptr; // [m_NumShaderStages]
-
- SRBMemoryAllocator m_SRBMemAllocator;
+ void* m_pRawMem = nullptr; // AZ TODO: remove
VulkanUtilities::PipelineWrapper m_Pipeline;
- PipelineLayout m_PipelineLayout;
-
- // Resource layout index in m_ShaderResourceLayouts array for every shader stage,
- // indexed by the shader type pipeline index (returned by GetShaderTypePipelineIndex)
- std::array<Int8, MAX_SHADERS_IN_PIPELINE> m_ResourceLayoutIndex = {-1, -1, -1, -1, -1, -1};
- static_assert(MAX_SHADERS_IN_PIPELINE == 6, "Please update the initializer list above");
+ RefCntAutoPtr<PipelineLayoutVk> m_PipelineLayout;
bool m_HasStaticResources = false;
bool m_HasNonStaticResources = false;
diff --git a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp
index 37052725..2547dbb0 100644
--- a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp
+++ b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp
@@ -47,6 +47,7 @@
#include "VulkanUploadHeap.hpp"
#include "FramebufferCache.hpp"
#include "RenderPassCache.hpp"
+#include "PipelineLayoutCacheVk.hpp"
#include "CommandPoolManager.hpp"
#include "DXCompiler.hpp"
@@ -130,6 +131,10 @@ public:
virtual void DILIGENT_CALL_TYPE CreateSBT(const ShaderBindingTableDesc& Desc,
IShaderBindingTable** ppSBT) override final;
+ /// Implementation of IRenderDevice::CreatePipelineResourceSignature() in Vulkan backend.
+ virtual void DILIGENT_CALL_TYPE CreatePipelineResourceSignature(const PipelineResourceSignatureDesc& Desc,
+ IPipelineResourceSignature** ppSignature) override final;
+
/// Implementation of IRenderDeviceVk::GetVkDevice().
virtual VkDevice DILIGENT_CALL_TYPE GetVkDevice() override final { return m_LogicalVkDevice->GetVkDevice(); }
@@ -190,6 +195,8 @@ public:
FramebufferCache& GetFramebufferCache() { return m_FramebufferCache; }
RenderPassCache& GetImplicitRenderPassCache() { return m_ImplicitRenderPassCache; }
+ PipelineLayoutCacheVk& GetPipelineLayoutCache() { return m_PipelineLayoutCache; }
+
VulkanUtilities::VulkanMemoryAllocation AllocateMemory(const VkMemoryRequirements& MemReqs, VkMemoryPropertyFlags MemoryProperties, VkMemoryAllocateFlags AllocateFlags = 0)
{
return m_MemoryMgr.Allocate(MemReqs, MemoryProperties, AllocateFlags);
@@ -224,6 +231,8 @@ public:
return m_Properties;
}
+ void CreatePipelineLayout(IPipelineResourceSignature** ppSignatures, Uint32 SignatureCount, PipelineLayoutVk** ppPipelineLayout);
+
private:
template <typename PSOCreateInfoType>
void CreatePipelineState(const PSOCreateInfoType& PSOCreateInfo, IPipelineState** ppPipelineState);
@@ -244,6 +253,7 @@ private:
EngineVkCreateInfo m_EngineAttribs;
FramebufferCache m_FramebufferCache;
+ PipelineLayoutCacheVk m_PipelineLayoutCache;
RenderPassCache m_ImplicitRenderPassCache;
DescriptorSetAllocator m_DescriptorSetAllocator;
DescriptorPoolManager m_DynamicDescriptorPool;
@@ -260,6 +270,8 @@ private:
std::unique_ptr<IDXCompiler> m_pDxCompiler;
Properties m_Properties;
+
+ FixedBlockMemoryAllocator m_PipelineLayoutAllocator;
};
} // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderResourceBindingVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/ShaderResourceBindingVkImpl.hpp
index 36613bff..84ce03d9 100644
--- a/Graphics/GraphicsEngineVulkan/include/ShaderResourceBindingVkImpl.hpp
+++ b/Graphics/GraphicsEngineVulkan/include/ShaderResourceBindingVkImpl.hpp
@@ -36,22 +36,23 @@
#include "ShaderBase.hpp"
#include "ShaderResourceCacheVk.hpp"
#include "ShaderVariableVk.hpp"
+#include "PipelineResourceSignatureVkImpl.hpp"
namespace Diligent
{
-class PipelineStateVkImpl;
+class PipelineResourceSignatureVkImpl;
/// Implementation of the Diligent::IShaderResourceBindingVk interface
// sizeof(ShaderResourceBindingVkImpl) == 72 (x64, msvc, Release)
-class ShaderResourceBindingVkImpl final : public ShaderResourceBindingBase<IShaderResourceBindingVk, PipelineStateVkImpl>
+class ShaderResourceBindingVkImpl final : public ShaderResourceBindingBase<IShaderResourceBindingVk, PipelineResourceSignatureVkImpl>
{
public:
- using TBase = ShaderResourceBindingBase<IShaderResourceBindingVk, PipelineStateVkImpl>;
+ using TBase = ShaderResourceBindingBase<IShaderResourceBindingVk, PipelineResourceSignatureVkImpl>;
- ShaderResourceBindingVkImpl(IReferenceCounters* pRefCounters,
- PipelineStateVkImpl* pPSO,
- bool IsPSOInternal);
+ ShaderResourceBindingVkImpl(IReferenceCounters* pRefCounters,
+ PipelineResourceSignatureVkImpl* pPRS,
+ bool IsPSOInternal);
~ShaderResourceBindingVkImpl();
IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_ShaderResourceBindingVk, TBase)
@@ -71,6 +72,9 @@ public:
/// Implementation of IShaderResourceBinding::InitializeStaticResources() in Vulkan backend.
virtual void DILIGENT_CALL_TYPE InitializeStaticResources(const IPipelineState* pPipelineState) override final;
+ /// Implementation of IShaderResourceBinding::InitializeStaticResourcesWithSignature() in Vulkan backend.
+ virtual void DILIGENT_CALL_TYPE InitializeStaticResourcesWithSignature(const IPipelineResourceSignature* pResourceSignature) override final;
+
ShaderResourceCacheVk& GetResourceCache() { return m_ShaderResourceCache; }
bool StaticResourcesInitialized() const { return m_bStaticResourcesInitialized; }
@@ -78,14 +82,12 @@ public:
private:
void Destruct();
+ std::array<Int8, MAX_SHADERS_IN_PIPELINE> m_ShaderVarIndex = {-1, -1, -1, -1, -1, -1};
+ static_assert(MAX_SHADERS_IN_PIPELINE == 6, "Please update the initializer list above");
+
ShaderResourceCacheVk m_ShaderResourceCache;
ShaderVariableManagerVk* m_pShaderVarMgrs = nullptr;
- // Resource layout index in m_ShaderResourceCache array for every shader stage,
- // indexed by the shader type pipeline index (returned by GetShaderTypePipelineIndex)
- std::array<Int8, MAX_SHADERS_IN_PIPELINE> m_ResourceLayoutIndex = {-1, -1, -1, -1, -1, -1};
- static_assert(MAX_SHADERS_IN_PIPELINE == 6, "Please update the initializer list above");
-
bool m_bStaticResourcesInitialized = false;
Uint8 m_NumShaders = 0;
};
diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.hpp b/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.hpp
index 82c10b51..77ce5d8b 100644
--- a/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.hpp
+++ b/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.hpp
@@ -90,16 +90,16 @@ public:
~ShaderResourceCacheVk();
- static size_t GetRequiredMemorySize(Uint32 NumSets, Uint32 SetSizes[]);
+ static size_t GetRequiredMemorySize(Uint32 NumSets, const Uint32* SetSizes);
- void InitializeSets(IMemoryAllocator& MemAllocator, Uint32 NumSets, Uint32 SetSizes[]);
- void InitializeResources(Uint32 Set, Uint32 Offset, Uint32 ArraySize, SPIRVShaderResourceAttribs::ResourceType Type);
+ void InitializeSets(IMemoryAllocator& MemAllocator, Uint32 NumSets, const Uint32* SetSizes);
+ void InitializeResources(Uint32 Set, Uint32 Offset, Uint32 ArraySize, VkDescriptorType Type);
// sizeof(Resource) == 16 (x64, msvc, Release)
struct Resource
{
// clang-format off
- explicit Resource(SPIRVShaderResourceAttribs::ResourceType _Type) noexcept :
+ explicit Resource(VkDescriptorType _Type) noexcept :
Type{_Type}
{}
@@ -108,9 +108,9 @@ public:
Resource& operator = (const Resource&) = delete;
Resource& operator = (Resource&&) = delete;
-/* 0 */ const SPIRVShaderResourceAttribs::ResourceType Type;
-/*1-7*/ // Unused
-/* 8 */ RefCntAutoPtr<IDeviceObject> pObject;
+/* 0 */ const VkDescriptorType Type;
+/*4-7*/ // Unused
+/* 8 */ RefCntAutoPtr<IDeviceObject> pObject;
VkDescriptorBufferInfo GetUniformBufferDescriptorWriteInfo () const;
VkDescriptorBufferInfo GetStorageBufferDescriptorWriteInfo () const;
@@ -213,7 +213,9 @@ private:
IMemoryAllocator* m_pAllocator = nullptr;
void* m_pMemory = nullptr;
Uint16 m_NumSets = 0;
- // Total number of dynamic buffers bound in the resource cache regardless of the variable type
+
+ // Total number of dynamic buffers bound in the resource cache regardless of the variable type.
+ // This variable is not equal to dynamic offsets count, it just a indicator that dynamic descriptor has dynamic buffers.
Uint16 m_NumDynamicBuffers = 0;
Uint32 m_TotalResources = 0;
@@ -243,46 +245,27 @@ __forceinline Uint32 ShaderResourceCacheVk::GetDynamicBufferOffsets(Uint32
{
const auto& DescrSet = GetDescriptorSet(set);
Uint32 res = 0;
- while (res < DescrSet.GetSize())
- {
- const auto& Res = DescrSet.GetResource(res);
- if (Res.Type != SPIRVShaderResourceAttribs::ResourceType::UniformBuffer)
- break;
-
- const auto* pBufferVk = Res.pObject.RawPtr<const BufferVkImpl>();
- auto Offset = pBufferVk != nullptr ? pBufferVk->GetDynamicOffset(CtxId, pCtxVkImpl) : 0;
- Offsets[OffsetInd++] = Offset;
-
- ++res;
- }
+ // AZ TODO: optimize
while (res < DescrSet.GetSize())
{
const auto& Res = DescrSet.GetResource(res);
- if (Res.Type != SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer &&
- Res.Type != SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer)
- break;
-
- const auto* pBufferVkView = Res.pObject.RawPtr<const BufferViewVkImpl>();
- const auto* pBufferVk = pBufferVkView != nullptr ? pBufferVkView->GetBufferVk() : 0;
- auto Offset = pBufferVk != nullptr ? pBufferVk->GetDynamicOffset(CtxId, pCtxVkImpl) : 0;
- Offsets[OffsetInd++] = Offset;
+ if (Res.Type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC)
+ {
+ const auto* pBufferVk = Res.pObject.RawPtr<const BufferVkImpl>();
+ auto Offset = pBufferVk != nullptr ? pBufferVk->GetDynamicOffset(CtxId, pCtxVkImpl) : 0;
+ Offsets[OffsetInd++] = Offset;
+ }
+ if (Res.Type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)
+ {
+ const auto* pBufferVkView = Res.pObject.RawPtr<const BufferViewVkImpl>();
+ const auto* pBufferVk = pBufferVkView != nullptr ? pBufferVkView->GetBufferVk() : 0;
+ auto Offset = pBufferVk != nullptr ? pBufferVk->GetDynamicOffset(CtxId, pCtxVkImpl) : 0;
+ Offsets[OffsetInd++] = Offset;
+ }
++res;
}
-
-#ifdef DILIGENT_DEBUG
- for (; res < DescrSet.GetSize(); ++res)
- {
- const auto& Res = DescrSet.GetResource(res);
- // clang-format off
- VERIFY(Res.Type != SPIRVShaderResourceAttribs::ResourceType::UniformBuffer &&
- Res.Type != SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer &&
- Res.Type != SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer,
- "All uniform and storage buffers are expected to go first in the beginning of each descriptor set");
- // clang-format on
- }
-#endif
}
return OffsetInd;
}
diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.hpp b/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.hpp
deleted file mode 100644
index bf283e1f..00000000
--- a/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.hpp
+++ /dev/null
@@ -1,478 +0,0 @@
-/*
- * Copyright 2019-2021 Diligent Graphics LLC
- * Copyright 2015-2019 Egor Yusov
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * In no event and under no legal theory, whether in tort (including negligence),
- * contract, or otherwise, unless required by applicable law (such as deliberate
- * and grossly negligent acts) or agreed to in writing, shall any Contributor be
- * liable for any damages, including any direct, indirect, special, incidental,
- * or consequential damages of any character arising as a result of this License or
- * out of the use or inability to use the software (including but not limited to damages
- * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
- * all other commercial damages or losses), even if such Contributor has been advised
- * of the possibility of such damages.
- */
-
-#pragma once
-
-/// \file
-/// Declaration of Diligent::ShaderResourceLayoutVk class
-
-// All resources are stored in a single continuous chunk of memory using the following layout:
-//
-// m_ResourceBuffer
-// |
-// || VkResource[0] ... VkResource[s-1] | VkResource[s] ... VkResource[s+m-1] | VkResource[s+m] ... VkResource[s+m+d-1] || ||
-// || | | || ||
-// || VARIABLE_TYPE_STATIC | VARIABLE_TYPE_MUTABLE | VARIABLE_TYPE_DYNAMIC || Immutable Samplers ||
-// || | | || ||
-//
-// s == m_NumResources[SHADER_RESOURCE_VARIABLE_TYPE_STATIC]
-// m == m_NumResources[SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE]
-// d == m_NumResources[SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC]
-//
-//
-// Every ShaderVariableVkImpl variable managed by ShaderVariableManagerVk keeps a reference to corresponding VkResource.
-//
-// ___________________________ ___________________________________________________________________________
-// | | unique_ptr | | | | |
-// | ShaderResourceLayoutVk |--------------->| VkResource[0] | VkResource[1] | ... | VkResource[s+m+d-1] |
-// |___________________________| |___________________|_________________|_______________|_____________________|
-// A A
-// / |
-// Ref Ref
-// / |
-// __________________________ __________________/___________________________|___________________________
-// | | | | | |
-// | ShaderVariableManagerVk |---------------->| ShaderVariableVkImpl[0] | ShaderVariableVkImpl[1] | ... |
-// |__________________________| |___________________________|____________________________|_________________|
-//
-//
-//
-//
-// Resources in the resource cache are identified by the descriptor set index and the offset from the set start
-//
-// ___________________________ ___________________________________________________________________________
-// | | unique_ptr | | | | |
-// | ShaderResourceLayoutVk |--------------->| VkResource[0] | VkResource[1] | ... | VkResource[s+m+d-1] |
-// |___________________________| |___________________|_________________|_______________|_____________________|
-// | |
-// | |
-// | (DescriptorSet, CacheOffset) / (DescriptorSet, CacheOffset)
-// \ /
-// __________________________ ________V_______________________________________________________V_______
-// | | | |
-// | ShaderResourceCacheVk |---------------->| Resources |
-// |__________________________| |________________________________________________________________________|
-//
-//
-//
-// Every pipeline state object (PipelineStateVkImpl) keeps the following layouts:
-// * One layout object per shader stage to facilitate management of static shader resources
-// - Uses artificial layout where resource binding matches the resource type (SPIRVShaderResourceAttribs::ResourceType)
-// * One layout object per shader stage used by SRBs to manage all resource types:
-// - All variable types are preserved
-// - Bindings, descriptor sets and offsets are assigned during the initialization
-
-#include <array>
-#include <memory>
-#include <unordered_map>
-
-#include "PipelineState.h"
-#include "ShaderBase.hpp"
-#include "HashUtils.hpp"
-#include "ShaderResourceCacheVk.hpp"
-#include "VulkanUtilities/VulkanLogicalDevice.hpp"
-#include "StringPool.hpp"
-
-namespace Diligent
-{
-
-class ShaderVkImpl;
-
-/// Diligent::ShaderResourceLayoutVk class
-// sizeof(ShaderResourceLayoutVk)==40 (MS compiler, x64)
-class ShaderResourceLayoutVk
-{
-public:
- struct ShaderStageInfo
- {
- ShaderStageInfo() {}
- ShaderStageInfo(const ShaderVkImpl* pShader);
-
- void Append(const ShaderVkImpl* pShader);
- size_t Count() const;
-
- // Shader stage type. All shaders in the stage must have the same type.
- SHADER_TYPE Type = SHADER_TYPE_UNKNOWN;
-
- std::vector<const ShaderVkImpl*> Shaders;
- std::vector<std::vector<uint32_t>> SPIRVs;
- };
- using TShaderStages = std::vector<ShaderStageInfo>;
-
- ShaderResourceLayoutVk(const VulkanUtilities::VulkanLogicalDevice& LogicalDevice) noexcept :
- m_LogicalDevice{LogicalDevice}
- {
-#if defined(_MSC_VER) && defined(_WIN64)
- static_assert(sizeof(*this) == 40, "Unexpected sizeof(ShaderResourceLayoutVk).");
-#endif
- }
-
- // clang-format off
- ShaderResourceLayoutVk (const ShaderResourceLayoutVk&) = delete;
- ShaderResourceLayoutVk (ShaderResourceLayoutVk&&) = delete;
- ShaderResourceLayoutVk& operator = (const ShaderResourceLayoutVk&) = delete;
- ShaderResourceLayoutVk& operator = (ShaderResourceLayoutVk&&) = delete;
- // clang-format on
-
- ~ShaderResourceLayoutVk();
-
- // This method is called by PipelineStateVkImpl class instance to initialize static
- // shader resource layout and the cache
- void InitializeStaticResourceLayout(const std::vector<const ShaderVkImpl*>& Shaders,
- IMemoryAllocator& LayoutDataAllocator,
- const PipelineResourceLayoutDesc& ResourceLayoutDesc,
- ShaderResourceCacheVk& StaticResourceCache);
-
- // This method is called by PipelineStateVkImpl class instance to initialize resource
- // layouts for all shader stages in the pipeline.
- static void Initialize(IRenderDevice* pRenderDevice,
- TShaderStages& ShaderStages,
- ShaderResourceLayoutVk Layouts[],
- IMemoryAllocator& LayoutDataAllocator,
- const PipelineResourceLayoutDesc& ResourceLayoutDesc,
- class PipelineLayout& PipelineLayout,
- bool VerifyVariables,
- bool VerifyImmutableSamplers);
-
- // sizeof(VkResource) == 32 (x64)
- struct VkResource
- {
- // clang-format off
- VkResource (const VkResource&) = delete;
- VkResource ( VkResource&&) = delete;
- VkResource& operator = (const VkResource&) = delete;
- VkResource& operator = ( VkResource&&) = delete;
-
- static constexpr const Uint32 CacheOffsetBits = 21;
- static constexpr const Uint32 SamplerIndBits = 8;
- static constexpr const Uint32 VariableTypeBits = 2;
- static constexpr const Uint32 ImmutableSamplerFlagBits = 1;
- static_assert(CacheOffsetBits + SamplerIndBits + VariableTypeBits + ImmutableSamplerFlagBits == 32, "Elements are expected to be packed into 32 bits");
- static_assert(SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES <= (1<<VariableTypeBits), "Not enough bits to represent SHADER_RESOURCE_VARIABLE_TYPE");
-
- static constexpr const Uint32 InvalidSamplerInd = (1 << SamplerIndBits)-1;
-
- static constexpr const Uint32 ResourceDimBits = 7;
- static constexpr const Uint32 IsMSFlagBits = 8 - ResourceDimBits;
- static_assert(RESOURCE_DIM_NUM_DIMENSIONS <= (1 << ResourceDimBits), "Not enough bits to represent RESOURCE_DIMENSION");
-
- using ResourceType = SPIRVShaderResourceAttribs::ResourceType;
-
-/* 0 */ const Uint16 Binding;
-/* 2 */ const Uint16 DescriptorSet;
-
-/* 4.0 */ const Uint32 CacheOffset : CacheOffsetBits; // Offset from the beginning of the cached descriptor set
-/* 6.5 */ const Uint32 SamplerInd : SamplerIndBits; // When using combined texture samplers, index of the separate sampler
- // assigned to separate image
-/* 7.5 */ const Uint32 VariableType : VariableTypeBits;
-/* 7.7 */ const Uint32 ImmutableSamplerAssigned : ImmutableSamplerFlagBits;
-
-/* 8 */ const Uint16 ArraySize;
-
-/* 10 */ const ResourceType Type;
-/* 11.0*/ const Uint8 ResourceDim : ResourceDimBits;
-/* 11.7*/ const Uint8 IsMS : IsMSFlagBits;
-
-/* 16 */ const char* const Name;
-/* 24 */ const ShaderResourceLayoutVk& ParentResLayout;
-
-#ifdef DILIGENT_DEVELOPMENT
-/* 32 */ const Uint32 BufferStaticSize;
-/* 36 */ const Uint32 BufferStride;
-#endif
- // clang-format on
-
- VkResource(const ShaderResourceLayoutVk& _ParentLayout,
- const char* _Name,
- const SPIRVShaderResourceAttribs& _Attribs,
- SHADER_RESOURCE_VARIABLE_TYPE _VariableType,
- uint32_t _Binding,
- uint32_t _DescriptorSet,
- Uint32 _CacheOffset,
- Uint32 _SamplerInd,
- bool _ImmutableSamplerAssigned) noexcept :
- // clang-format off
- Binding {static_cast<decltype(Binding)>(_Binding) },
- DescriptorSet {static_cast<decltype(DescriptorSet)>(_DescriptorSet)},
- CacheOffset {_CacheOffset },
- SamplerInd {_SamplerInd },
- VariableType {_VariableType},
- ImmutableSamplerAssigned {_ImmutableSamplerAssigned ? 1U : 0U},
- ArraySize {_Attribs.ArraySize },
- Type {_Attribs.Type },
- ResourceDim {_Attribs.ResourceDim},
- IsMS {_Attribs.IsMS },
-#ifdef DILIGENT_DEVELOPMENT
- BufferStaticSize {_Attribs.BufferStaticSize},
- BufferStride {_Attribs.BufferStride },
-#endif
- Name {_Name },
- ParentResLayout {_ParentLayout}
- // clang-format on
- {
-#if defined(_MSC_VER) && defined(_WIN64) && !defined(DILIGENT_DEVELOPMENT)
- static_assert(sizeof(*this) == 32, "Unexpected sizeof(VkResource)");
-#endif
- // clang-format off
- VERIFY(_CacheOffset < (1 << CacheOffsetBits), "Cache offset (", _CacheOffset, ") exceeds max representable value ", (1 << CacheOffsetBits) );
- VERIFY(_SamplerInd < (1 << SamplerIndBits), "Sampler index (", _SamplerInd, ") exceeds max representable value ", (1 << SamplerIndBits) );
- VERIFY(_Binding <= std::numeric_limits<decltype(Binding)>::max(), "Binding (", _Binding, ") exceeds max representable value ", std::numeric_limits<decltype(Binding)>::max() );
- VERIFY(_DescriptorSet <= std::numeric_limits<decltype(DescriptorSet)>::max(), "Descriptor set (", _DescriptorSet, ") exceeds max representable value ", std::numeric_limits<decltype(DescriptorSet)>::max());
- VERIFY(_VariableType < (1 << VariableTypeBits), "Variable type (", Uint32{_VariableType}, ") exceeds max representable value ", (1 << VariableTypeBits) );
- VERIFY(_Attribs.ResourceDim < (1 << ResourceDimBits), "Resource dimension (", Uint32{_Attribs.ResourceDim}, ") exceeds max representable value ", (1 << ResourceDimBits) );
- // clang-format on
- }
-
-
- // Checks if a resource is bound in ResourceCache at the given ArrayIndex
- bool IsBound(Uint32 ArrayIndex, const ShaderResourceCacheVk& ResourceCache) const;
-
- // Binds a resource pObject in the ResourceCache
- void BindResource(IDeviceObject* pObject, Uint32 ArrayIndex, ShaderResourceCacheVk& ResourceCache) const;
-
- // Updates resource descriptor in the descriptor set
- inline void UpdateDescriptorHandle(VkDescriptorSet vkDescrSet,
- uint32_t ArrayElement,
- const VkDescriptorImageInfo* pImageInfo,
- const VkDescriptorBufferInfo* pBufferInfo,
- const VkBufferView* pTexelBufferView,
- const VkWriteDescriptorSetAccelerationStructureKHR* pAccelStructInfo = nullptr) const;
-
- bool IsImmutableSamplerAssigned() const
- {
- VERIFY(ImmutableSamplerAssigned == 0 ||
- Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage ||
- Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler,
- "Immutable sampler can only be assigned to a sampled image or separate sampler");
- return ImmutableSamplerAssigned != 0;
- }
-
- SHADER_RESOURCE_VARIABLE_TYPE GetVariableType() const
- {
- return static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(VariableType);
- }
-
- String GetPrintName(Uint32 ArrayInd) const
- {
- VERIFY_EXPR(ArrayInd < ArraySize);
- if (ArraySize > 1)
- {
- std::stringstream ss;
- ss << Name << '[' << ArrayInd << ']';
- return ss.str();
- }
- else
- return Name;
- }
-
- ShaderResourceDesc GetResourceDesc() const
- {
- return ShaderResourceDesc{Name, SPIRVShaderResourceAttribs::GetShaderResourceType(Type), ArraySize};
- }
-
- RESOURCE_DIMENSION GetResourceDimension() const
- {
- return static_cast<RESOURCE_DIMENSION>(ResourceDim);
- }
-
- bool IsMultisample() const
- {
- return IsMS != 0;
- }
-
- bool IsCompatibleWith(const VkResource& rhs) const
- {
- // clang-format off
- return Binding == rhs.Binding &&
- DescriptorSet == rhs.DescriptorSet &&
- ArraySize == rhs.ArraySize &&
- Type == rhs.Type;
- // clang-format on
- }
-
- private:
- void CacheUniformBuffer(IDeviceObject* pBuffer,
- ShaderResourceCacheVk::Resource& DstRes,
- VkDescriptorSet vkDescrSet,
- Uint32 ArrayInd,
- Uint16& DynamicBuffersCounter) const;
-
- void CacheStorageBuffer(IDeviceObject* pBufferView,
- ShaderResourceCacheVk::Resource& DstRes,
- VkDescriptorSet vkDescrSet,
- Uint32 ArrayInd,
- Uint16& DynamicBuffersCounter) const;
-
- void CacheTexelBuffer(IDeviceObject* pBufferView,
- ShaderResourceCacheVk::Resource& DstRes,
- VkDescriptorSet vkDescrSet,
- Uint32 ArrayInd,
- Uint16& DynamicBuffersCounter) const;
-
- template <typename TCacheSampler>
- void CacheImage(IDeviceObject* pTexView,
- ShaderResourceCacheVk::Resource& DstRes,
- VkDescriptorSet vkDescrSet,
- Uint32 ArrayInd,
- TCacheSampler CacheSampler) const;
-
- void CacheSeparateSampler(IDeviceObject* pSampler,
- ShaderResourceCacheVk::Resource& DstRes,
- VkDescriptorSet vkDescrSet,
- Uint32 ArrayInd) const;
-
- void CacheInputAttachment(IDeviceObject* pTexView,
- ShaderResourceCacheVk::Resource& DstRes,
- VkDescriptorSet vkDescrSet,
- Uint32 ArrayInd) const;
-
- void CacheAccelerationStructure(IDeviceObject* pTLAS,
- ShaderResourceCacheVk::Resource& DstRes,
- VkDescriptorSet vkDescrSet,
- Uint32 ArrayInd) const;
-
- template <typename ObjectType, typename TPreUpdateObject>
- bool UpdateCachedResource(ShaderResourceCacheVk::Resource& DstRes,
- RefCntAutoPtr<ObjectType>&& pObject,
- TPreUpdateObject PreUpdateObject) const;
- };
-
- // Copies static resources from SrcResourceCache defined by SrcLayout
- // to DstResourceCache defined by this layout
- void InitializeStaticResources(const ShaderResourceLayoutVk& SrcLayout,
- const ShaderResourceCacheVk& SrcResourceCache,
- ShaderResourceCacheVk& DstResourceCache) const;
-
-#ifdef DILIGENT_DEVELOPMENT
- bool dvpVerifyBindings(const ShaderResourceCacheVk& ResourceCache) const;
- static void dvpVerifyResourceLayoutDesc(const TShaderStages& ShaderStages,
- const PipelineResourceLayoutDesc& ResourceLayoutDesc,
- bool VerifyVariables,
- bool VerifyImmutableSamplers);
-#endif
-
- Uint32 GetResourceCount(SHADER_RESOURCE_VARIABLE_TYPE VarType) const
- {
- return m_NumResources[VarType];
- }
-
- // Initializes resource slots in the ResourceCache
- void InitializeResourceMemoryInCache(ShaderResourceCacheVk& ResourceCache) const;
-
- // Writes dynamic resource descriptors from ResourceCache to vkDynamicDescriptorSet
- void CommitDynamicResources(const ShaderResourceCacheVk& ResourceCache,
- VkDescriptorSet vkDynamicDescriptorSet) const;
-
- const Char* GetShaderName() const
- {
- return GetStringPoolData();
- }
-
- SHADER_TYPE GetShaderType() const { return m_ShaderType; }
-
- const VkResource& GetResource(SHADER_RESOURCE_VARIABLE_TYPE VarType, Uint32 r) const
- {
- VERIFY_EXPR(r < m_NumResources[VarType]);
- auto* Resources = reinterpret_cast<const VkResource*>(m_ResourceBuffer.get());
- return Resources[GetResourceOffset(VarType, r)];
- }
-
- bool IsUsingSeparateSamplers() const { return m_IsUsingSeparateSamplers; }
-
- bool IsCompatibleWith(const ShaderResourceLayoutVk& ResLayout) const;
-
-private:
- Uint32 GetResourceOffset(SHADER_RESOURCE_VARIABLE_TYPE VarType, Uint32 r) const
- {
- VERIFY_EXPR(r < m_NumResources[VarType]);
- static_assert(SHADER_RESOURCE_VARIABLE_TYPE_STATIC == 0, "SHADER_RESOURCE_VARIABLE_TYPE_STATIC == 0 expected");
- r += (VarType > SHADER_RESOURCE_VARIABLE_TYPE_STATIC) ? m_NumResources[SHADER_RESOURCE_VARIABLE_TYPE_STATIC] : 0;
- static_assert(SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE == 1, "SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE == 1 expected");
- r += (VarType > SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE) ? m_NumResources[SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE] : 0;
- return r;
- }
- VkResource& GetResource(SHADER_RESOURCE_VARIABLE_TYPE VarType, Uint32 r)
- {
- VERIFY_EXPR(r < m_NumResources[VarType]);
- auto* Resources = reinterpret_cast<VkResource*>(m_ResourceBuffer.get());
- return Resources[GetResourceOffset(VarType, r)];
- }
-
- const VkResource& GetResource(Uint32 r) const
- {
- VERIFY_EXPR(r < GetTotalResourceCount());
- const auto* Resources = reinterpret_cast<const VkResource*>(m_ResourceBuffer.get());
- return Resources[r];
- }
-
- Uint32 GetTotalResourceCount() const
- {
- return m_NumResources[SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES];
- }
-
- const char* GetStringPoolData() const
- {
- const auto* ResourceDataEnd = reinterpret_cast<const VkResource*>(m_ResourceBuffer.get()) + GetTotalResourceCount();
- const auto* SamplerDataEnd = reinterpret_cast<const ImmutableSamplerPtrType*>(ResourceDataEnd) + m_NumImmutableSamplers;
- return reinterpret_cast<const char*>(SamplerDataEnd);
- }
-
- static constexpr const Uint32 InvalidResourceIndex = ~0u;
-
- // Maps resource name to its index in m_ResourceBuffer
- using ResourceNameToIndex_t = std::unordered_map<HashMapStringKey, Uint32, HashMapStringKey::Hasher>;
- StringPool AllocateMemory(const std::vector<const ShaderVkImpl*>& Shaders,
- IMemoryAllocator& Allocator,
- const PipelineResourceLayoutDesc& ResourceLayoutDesc,
- const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes,
- Uint32 NumAllowedTypes,
- ResourceNameToIndex_t& UniqueNames,
- bool AllocateImmutableSamplers);
-
- using ImmutableSamplerPtrType = RefCntAutoPtr<ISampler>;
- ImmutableSamplerPtrType& GetImmutableSampler(Uint32 n) noexcept
- {
- VERIFY(n < m_NumImmutableSamplers, "Immutable sampler index (", n, ") is out of range. Total immutable sampler count: ", m_NumImmutableSamplers);
- auto* ResourceMemoryEnd = reinterpret_cast<VkResource*>(m_ResourceBuffer.get()) + GetTotalResourceCount();
- return reinterpret_cast<ImmutableSamplerPtrType*>(ResourceMemoryEnd)[n];
- }
-
- // clang-format off
-/* 0 */ const VulkanUtilities::VulkanLogicalDevice& m_LogicalDevice;
-/* 8 */ std::unique_ptr<void, STDDeleterRawMem<void>> m_ResourceBuffer;
-
-/*24 */ std::array<Uint16, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES+1> m_NumResources = {};
-
-/*32 */ Uint16 m_NumImmutableSamplers = 0;
-/*34 */ bool m_IsUsingSeparateSamplers = false;
-/*36 */ SHADER_TYPE m_ShaderType = SHADER_TYPE_UNKNOWN;
-
-/*40 */ // End of class
- // clang-format on
-};
-
-} // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderVariableVk.hpp b/Graphics/GraphicsEngineVulkan/include/ShaderVariableVk.hpp
index cebe33c3..6eaaf35c 100644
--- a/Graphics/GraphicsEngineVulkan/include/ShaderVariableVk.hpp
+++ b/Graphics/GraphicsEngineVulkan/include/ShaderVariableVk.hpp
@@ -61,13 +61,14 @@
#include <memory>
-#include "ShaderResourceLayoutVk.hpp"
#include "ShaderResourceVariableBase.hpp"
+#include "ShaderResourceCacheVk.hpp"
namespace Diligent
{
class ShaderVariableVkImpl;
+class PipelineResourceSignatureVkImpl;
// sizeof(ShaderVariableManagerVk) == 32 (x64, msvc, Release)
class ShaderVariableManagerVk
@@ -79,10 +80,10 @@ public:
m_ResourceCache{ResourceCache}
{}
- void Initialize(const ShaderResourceLayoutVk& SrcLayout,
- IMemoryAllocator& Allocator,
- const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes,
- Uint32 NumAllowedTypes);
+ void Initialize(const PipelineResourceSignatureVkImpl& SrcLayout,
+ IMemoryAllocator& Allocator,
+ const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes,
+ Uint32 NumAllowedTypes);
~ShaderVariableManagerVk();
@@ -93,19 +94,35 @@ public:
void BindResources(IResourceMapping* pResourceMapping, Uint32 Flags) const;
- static size_t GetRequiredMemorySize(const ShaderResourceLayoutVk& Layout,
- const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes,
- Uint32 NumAllowedTypes,
- Uint32& NumVariables);
+ static size_t GetRequiredMemorySize(const PipelineResourceSignatureVkImpl& Layout,
+ const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes,
+ Uint32 NumAllowedTypes,
+ Uint32& NumVariables);
Uint32 GetVariableCount() const { return m_NumVariables; }
private:
friend ShaderVariableVkImpl;
+ using PackedBindingIndex = PipelineResourceSignatureVkImpl::PackedBindingIndex;
Uint32 GetVariableIndex(const ShaderVariableVkImpl& Variable);
+ const PipelineResourceDesc& GetResource(Uint32 Index) const
+ {
+ VERIFY_EXPR(m_pSignature);
+ return m_pSignature->GetResource(Index);
+ }
+ const PackedBindingIndex& GetBinding(Uint32 Index) const
+ {
+ VERIFY_EXPR(m_pSignature);
+ return m_pSignature->GetBinding(Index);
+ }
+
+private:
+ PipelineResourceSignatureVkImpl const* m_pSignature = nullptr;
+
IObject& m_Owner;
+
// Variable mgr is owned by either Pipeline state object (in which case m_ResourceCache references
// static resource cache owned by the same PSO object), or by SRB object (in which case
// m_ResourceCache references the cache in the SRB). Thus the cache and the resource layout
@@ -123,14 +140,12 @@ private:
#endif
};
-// sizeof(ShaderVariableVkImpl) == 24 (x64)
+// sizeof(ShaderVariableVkImpl) == 16 (x64)
class ShaderVariableVkImpl final : public IShaderResourceVariable
{
public:
- ShaderVariableVkImpl(ShaderVariableManagerVk& ParentManager,
- const ShaderResourceLayoutVk::VkResource& Resource) :
- m_ParentManager{ParentManager},
- m_Resource{Resource}
+ explicit ShaderVariableVkImpl(ShaderVariableManagerVk& ParentManager) :
+ m_ParentManager{ParentManager}
{}
// clang-format off
@@ -171,48 +186,101 @@ public:
virtual SHADER_RESOURCE_VARIABLE_TYPE DILIGENT_CALL_TYPE GetType() const override final
{
- return m_Resource.GetVariableType();
+ return GetDesc().VarType;
}
- virtual void DILIGENT_CALL_TYPE Set(IDeviceObject* pObject) override final
- {
- m_Resource.BindResource(pObject, 0, m_ParentManager.m_ResourceCache);
- }
+ virtual void DILIGENT_CALL_TYPE Set(IDeviceObject* pObject) override final;
virtual void DILIGENT_CALL_TYPE SetArray(IDeviceObject* const* ppObjects,
Uint32 FirstElement,
- Uint32 NumElements) override final
- {
- VerifyAndCorrectSetArrayArguments(m_Resource.Name, m_Resource.ArraySize, FirstElement, NumElements);
- for (Uint32 Elem = 0; Elem < NumElements; ++Elem)
- m_Resource.BindResource(ppObjects[Elem], FirstElement + Elem, m_ParentManager.m_ResourceCache);
- }
+ Uint32 NumElements) override final;
virtual void DILIGENT_CALL_TYPE GetResourceDesc(ShaderResourceDesc& ResourceDesc) const override final
{
- ResourceDesc = m_Resource.GetResourceDesc();
+ const auto& Desc = GetDesc();
+ ResourceDesc.Name = Desc.Name;
+ ResourceDesc.Type = Desc.ResourceType;
+ ResourceDesc.ArraySize = Desc.ArraySize;
}
virtual Uint32 DILIGENT_CALL_TYPE GetIndex() const override final
{
- return m_ParentManager.GetVariableIndex(*this);
+ VERIFY_EXPR(m_ParentManager.m_pVariables);
+ return Uint32(size_t(this - m_ParentManager.m_pVariables));
}
- virtual bool DILIGENT_CALL_TYPE IsBound(Uint32 ArrayIndex) const override final
- {
- return m_Resource.IsBound(ArrayIndex, m_ParentManager.m_ResourceCache);
- }
+ virtual bool DILIGENT_CALL_TYPE IsBound(Uint32 ArrayIndex) const override final;
- const ShaderResourceLayoutVk::VkResource& GetResource() const
- {
- return m_Resource;
- }
+ String GetPrintName(Uint32 ArrayInd) const;
+
+ RESOURCE_DIMENSION GetResourceDimension() const;
+
+ bool IsMultisample() const;
private:
friend ShaderVariableManagerVk;
+ using PackedBindingIndex = PipelineResourceSignatureVkImpl::PackedBindingIndex;
+
+ const PipelineResourceDesc& GetDesc() const { return m_ParentManager.GetResource(GetIndex()); }
+ const PackedBindingIndex& GetBinding() const { return m_ParentManager.GetBinding(GetIndex()); }
+
+ void BindResource(IDeviceObject* pObj, Uint32 ArrayIndex) const;
+
+ struct UpdateInfo
+ {
+ ShaderResourceCacheVk::Resource& DstRes;
+ const VkDescriptorSet vkDescrSet;
+ const Uint32 ArrayIndex;
+ const SHADER_RESOURCE_VARIABLE_TYPE VarType;
+ const Uint16 Binding;
+ const Uint8 SamplerInd;
+ char const* const Name;
+ };
+
+ void CacheUniformBuffer(IDeviceObject* pBuffer,
+ UpdateInfo& Info,
+ Uint16& DynamicBuffersCounter) const;
+
+ void CacheStorageBuffer(IDeviceObject* pBufferView,
+ UpdateInfo& Info,
+ Uint16& DynamicBuffersCounter) const;
+
+ void CacheTexelBuffer(IDeviceObject* pBufferView,
+ UpdateInfo& Info,
+ Uint16& DynamicBuffersCounter) const;
+
+ template <typename TCacheSampler>
+ void CacheImage(IDeviceObject* pTexView,
+ UpdateInfo& Info,
+ TCacheSampler CacheSampler) const;
- ShaderVariableManagerVk& m_ParentManager;
- const ShaderResourceLayoutVk::VkResource& m_Resource;
+ void CacheSeparateSampler(IDeviceObject* pSampler,
+ UpdateInfo& Info) const;
+
+ void CacheInputAttachment(IDeviceObject* pTexView,
+ UpdateInfo& Info) const;
+
+ void CacheAccelerationStructure(IDeviceObject* pTLAS,
+ UpdateInfo& Info) const;
+
+ template <typename ObjectType, typename TPreUpdateObject>
+ bool UpdateCachedResource(UpdateInfo& Info,
+ RefCntAutoPtr<ObjectType>&& pObject,
+ TPreUpdateObject PreUpdateObject) const;
+
+ bool IsImmutableSamplerAssigned() const;
+
+ // Updates resource descriptor in the descriptor set
+ inline void UpdateDescriptorHandle(UpdateInfo& Info,
+ const VkDescriptorImageInfo* pImageInfo,
+ const VkDescriptorBufferInfo* pBufferInfo,
+ const VkBufferView* pTexelBufferView,
+ const VkWriteDescriptorSetAccelerationStructureKHR* pAccelStructInfo = nullptr) const;
+
+ static constexpr Uint8 InvalidSamplerInd = PipelineResourceSignatureVkImpl::InvalidSamplerInd;
+
+private:
+ ShaderVariableManagerVk& m_ParentManager;
};
} // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/ShaderVkImpl.hpp
index 112a5664..e3bb52f6 100644
--- a/Graphics/GraphicsEngineVulkan/include/ShaderVkImpl.hpp
+++ b/Graphics/GraphicsEngineVulkan/include/ShaderVkImpl.hpp
@@ -68,15 +68,14 @@ public:
return m_SPIRV;
}
- const std::shared_ptr<const SPIRVShaderResources>& GetShaderResources() const { return m_pShaderResources; }
+ const SPIRVShaderResources& GetShaderResources() const { return *m_pShaderResources; }
const char* GetEntryPoint() const { return m_EntryPoint.c_str(); }
private:
void MapHLSLVertexShaderInputs();
- // SPIRVShaderResources class instance must be referenced through the shared pointer, because
- // it is referenced by ShaderResourceLayoutVk class instances
+ // AZ TODO: remove shared pointer
std::shared_ptr<const SPIRVShaderResources> m_pShaderResources;
std::string m_EntryPoint;
diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.hpp b/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.hpp
index 5200d792..6e79a300 100644
--- a/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.hpp
+++ b/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.hpp
@@ -87,6 +87,7 @@ VkAccessFlags AccessFlagsToVkAccessFlags(ACCESS_FLAGS AccessFlags);
VkShaderStageFlagBits ShaderTypeToVkShaderStageFlagBit(SHADER_TYPE ShaderType);
+VkShaderStageFlags ShaderTypesToVkShaderStageFlags(SHADER_TYPE ShaderTypes);
VkBuildAccelerationStructureFlagsKHR BuildASFlagsToVkBuildAccelerationStructureFlags(RAYTRACING_BUILD_AS_FLAGS Flags);
VkGeometryFlagsKHR GeometryFlagsToVkGeometryFlags(RAYTRACING_GEOMETRY_FLAGS Flags);
diff --git a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp
index 8516a174..bea9f29b 100644
--- a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp
@@ -231,6 +231,8 @@ inline void DeviceContextVkImpl::DisposeCurrentCmdBuffer(Uint32 CmdQueue, Uint64
void DeviceContextVkImpl::SetPipelineState(IPipelineState* pPipelineState)
{
auto* pPipelineStateVk = ValidatedCast<PipelineStateVkImpl>(pPipelineState);
+ BindShaderResources(pPipelineStateVk);
+
if (PipelineStateVkImpl::IsSameObject(m_pPipelineState, pPipelineStateVk))
return;
@@ -306,21 +308,84 @@ void DeviceContextVkImpl::SetPipelineState(IPipelineState* pPipelineState)
default:
UNEXPECTED("unknown pipeline type");
}
+}
+
+static Uint32 PipelineTypeToBindPointIndex(PIPELINE_TYPE Type)
+{
+ const Uint8 Indices[] = {
+ 0, // PIPELINE_TYPE_GRAPHICS
+ 1, // PIPELINE_TYPE_COMPUTE
+ 0, // PIPELINE_TYPE_MESH
+ 2 // PIPELINE_TYPE_RAY_TRACING
+ };
+ static_assert(_countof(Indices) == Uint32{PIPELINE_TYPE_LAST} + 1, "AZ TODO");
+ return Indices[Uint32{Type}];
+}
+
+static VkPipelineBindPoint PipelineTypeToBindPoint(PIPELINE_TYPE Type)
+{
+ const VkPipelineBindPoint BindPoints[] = {
+ VK_PIPELINE_BIND_POINT_GRAPHICS, // PIPELINE_TYPE_GRAPHICS
+ VK_PIPELINE_BIND_POINT_COMPUTE, // PIPELINE_TYPE_COMPUTE
+ VK_PIPELINE_BIND_POINT_GRAPHICS, // PIPELINE_TYPE_MESH
+ VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR // PIPELINE_TYPE_RAY_TRACING
+ };
+ static_assert(_countof(BindPoints) == Uint32{PIPELINE_TYPE_LAST} + 1, "AZ TODO");
+ return BindPoints[Uint32{Type}];
+}
+
+void DeviceContextVkImpl::BindShaderResources(PipelineStateVkImpl* pPipelineStateVk)
+{
+ VERIFY_EXPR(pPipelineStateVk != nullptr);
+
+ const auto& Layout = pPipelineStateVk->GetPipelineLayout();
+ auto& Resources = m_ShaderResources[PipelineTypeToBindPointIndex(Layout.GetPipelineType())];
+ auto& DescrSetBindInfo = m_DescrSetBindInfo[PipelineTypeToBindPointIndex(Layout.GetPipelineType())];
+
+#ifdef DILIGENT_DEVELOPMENT
+ for (Uint32 i = 0, Count = Layout.GetSignatureCount(); i < Count; ++i)
+ {
+ auto* LayoutSign = Layout.GetSignature(i);
+ auto* ResSign = Resources[i] ? Resources[i]->GetPipelineResourceSignature() : nullptr;
+
+ if (LayoutSign != ResSign)
+ {
+ LOG_ERROR_MESSAGE("Shader resource binding '", (ResSign ? ResSign->GetDesc().Name : ""),
+ "' is not compatible with pipeline layout in current pipeline '", pPipelineStateVk->GetDesc().Name, "'.");
+ Resources[i] = nullptr;
+ }
+ }
+#endif
+
+ // the number of bound descriptor sets and dynamic offsets may be greater then actually used in pipeline layout,
+ // see https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#descriptorsets-compatibility
+ VERIFY_EXPR(Layout.GetDescriptorSetCount() <= DescrSetBindInfo.SetCout);
+ VERIFY_EXPR(Layout.GetDynamicOffsetCount() <= DescrSetBindInfo.DynamicOffsetCount);
- m_DescrSetBindInfo.Reset();
+ // AZ TODO: optimize - bind DS that was changed
+ GetCommandBuffer().BindDescriptorSets(PipelineTypeToBindPoint(Layout.GetPipelineType()), Layout.GetVkPipelineLayout(), 0, Layout.GetDescriptorSetCount(), DescrSetBindInfo.vkSets.data(), Layout.GetDynamicOffsetCount(), DescrSetBindInfo.DynamicOffsets.data());
}
-void DeviceContextVkImpl::TransitionShaderResources(IPipelineState* pPipelineState, IShaderResourceBinding* pShaderResourceBinding)
+void DeviceContextVkImpl::TransitionShaderResources(IPipelineState*, IShaderResourceBinding* pShaderResourceBinding)
{
- DEV_CHECK_ERR(pPipelineState != nullptr, "Pipeline state must mot be null");
+#ifdef DILIGENT_DEVELOPMENT
if (m_pActiveRenderPass)
{
LOG_ERROR_MESSAGE("State transitions are not allowed inside a render pass.");
return;
}
- auto* pPipelineStateVk = ValidatedCast<PipelineStateVkImpl>(pPipelineState);
- pPipelineStateVk->CommitAndTransitionShaderResources(pShaderResourceBinding, this, false, RESOURCE_STATE_TRANSITION_MODE_TRANSITION, nullptr);
+ if (pShaderResourceBinding == nullptr)
+ {
+ LOG_ERROR_MESSAGE("TODO");
+ return;
+ }
+#endif
+
+ auto* pResBindingVkImpl = ValidatedCast<ShaderResourceBindingVkImpl>(pShaderResourceBinding);
+ auto& ResourceCache = pResBindingVkImpl->GetResourceCache();
+
+ ResourceCache.TransitionResources<false>(this);
}
void DeviceContextVkImpl::CommitShaderResources(IShaderResourceBinding* pShaderResourceBinding, RESOURCE_STATE_TRANSITION_MODE StateTransitionMode)
@@ -328,7 +393,32 @@ void DeviceContextVkImpl::CommitShaderResources(IShaderResourceBinding* pShaderR
if (!DeviceContextBase::CommitShaderResources(pShaderResourceBinding, StateTransitionMode, 0 /*Dummy*/))
return;
- m_pPipelineState->CommitAndTransitionShaderResources(pShaderResourceBinding, this, true, StateTransitionMode, &m_DescrSetBindInfo);
+ auto* pResBindingVkImpl = ValidatedCast<ShaderResourceBindingVkImpl>(pShaderResourceBinding);
+ auto& ResourceCache = pResBindingVkImpl->GetResourceCache();
+
+#ifdef DILIGENT_DEBUG
+ ResourceCache.DbgVerifyDynamicBuffersCounter();
+#endif
+
+ if (StateTransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION)
+ {
+ ResourceCache.TransitionResources<false>(this);
+ }
+#ifdef DILIGENT_DEVELOPMENT
+ else if (StateTransitionMode == RESOURCE_STATE_TRANSITION_MODE_VERIFY)
+ {
+ ResourceCache.TransitionResources<true>(this);
+ }
+#endif
+
+ Uint32 Index = PipelineTypeToBindPointIndex(pResBindingVkImpl->GetPipelineType());
+ auto& DescrSetBindInfo = m_DescrSetBindInfo[Index];
+ auto& ResourceBinding = m_ShaderResources[Index];
+
+ // AZ TODO: create dynamic descriptor set
+ (void)(DescrSetBindInfo);
+
+ ResourceBinding[pResBindingVkImpl->GetBindingIndex()] = pResBindingVkImpl;
}
void DeviceContextVkImpl::SetStencilRef(Uint32 StencilRef)
@@ -468,15 +558,17 @@ void DeviceContextVkImpl::PrepareForDraw(DRAW_FLAGS Flags)
}
#endif
- if (m_DescrSetBindInfo.DynamicOffsetCount != 0)
+ auto& DescrSetBindInfo = m_DescrSetBindInfo[0];
+
+ if (DescrSetBindInfo.DynamicOffsetCount != 0)
{
// First time we must always bind descriptor sets with dynamic offsets.
// If there are no dynamic buffers bound in the resource cache, for all subsequent
// cals we do not need to bind the sets again.
- if (!m_DescrSetBindInfo.DynamicDescriptorsBound ||
- (m_DescrSetBindInfo.DynamicBuffersPresent && (Flags & DRAW_FLAG_DYNAMIC_RESOURCE_BUFFERS_INTACT) == 0))
+ if (!DescrSetBindInfo.DynamicDescriptorsBound ||
+ (DescrSetBindInfo.DynamicBuffersPresent && (Flags & DRAW_FLAG_DYNAMIC_RESOURCE_BUFFERS_INTACT) == 0))
{
- m_pPipelineState->BindDescriptorSetsWithDynamicOffsets(GetCommandBuffer(), m_ContextId, this, m_DescrSetBindInfo);
+ m_pPipelineState->BindDescriptorSetsWithDynamicOffsets(GetCommandBuffer(), m_ContextId, this, DescrSetBindInfo);
}
}
#if 0
@@ -621,11 +713,13 @@ void DeviceContextVkImpl::PrepareForDispatchCompute()
if (m_CommandBuffer.GetState().RenderPass != VK_NULL_HANDLE)
m_CommandBuffer.EndRenderPass();
- if (m_DescrSetBindInfo.DynamicOffsetCount != 0)
+ auto& DescrSetBindInfo = m_DescrSetBindInfo[1];
+
+ if (DescrSetBindInfo.DynamicOffsetCount != 0)
{
- if (!m_DescrSetBindInfo.DynamicDescriptorsBound || m_DescrSetBindInfo.DynamicBuffersPresent)
+ if (!DescrSetBindInfo.DynamicDescriptorsBound || DescrSetBindInfo.DynamicBuffersPresent)
{
- m_pPipelineState->BindDescriptorSetsWithDynamicOffsets(GetCommandBuffer(), m_ContextId, this, m_DescrSetBindInfo);
+ m_pPipelineState->BindDescriptorSetsWithDynamicOffsets(GetCommandBuffer(), m_ContextId, this, DescrSetBindInfo);
}
}
#if 0
@@ -643,11 +737,13 @@ void DeviceContextVkImpl::PrepareForRayTracing()
{
EnsureVkCmdBuffer();
- if (m_DescrSetBindInfo.DynamicOffsetCount != 0)
+ auto& DescrSetBindInfo = m_DescrSetBindInfo[2];
+
+ if (DescrSetBindInfo.DynamicOffsetCount != 0)
{
- if (!m_DescrSetBindInfo.DynamicDescriptorsBound || m_DescrSetBindInfo.DynamicBuffersPresent)
+ if (!DescrSetBindInfo.DynamicDescriptorsBound || DescrSetBindInfo.DynamicBuffersPresent)
{
- m_pPipelineState->BindDescriptorSetsWithDynamicOffsets(GetCommandBuffer(), m_ContextId, this, m_DescrSetBindInfo);
+ m_pPipelineState->BindDescriptorSetsWithDynamicOffsets(GetCommandBuffer(), m_ContextId, this, DescrSetBindInfo);
}
}
}
@@ -1030,8 +1126,13 @@ void DeviceContextVkImpl::Flush()
DisposeCurrentCmdBuffer(m_CommandQueueId, SubmittedFenceValue);
}
+ for (auto& BindInfo : m_DescrSetBindInfo)
+ BindInfo.Reset();
+
+ for (auto& ResourcesPerBindPoint : m_ShaderResources)
+ ResourcesPerBindPoint.fill({});
+
m_State = ContextState{};
- m_DescrSetBindInfo.Reset();
m_CommandBuffer.Reset();
m_pPipelineState = nullptr;
m_pActiveRenderPass = nullptr;
@@ -1067,7 +1168,13 @@ void DeviceContextVkImpl::InvalidateState()
m_State = ContextState{};
m_vkRenderPass = VK_NULL_HANDLE;
m_vkFramebuffer = VK_NULL_HANDLE;
- m_DescrSetBindInfo.Reset();
+
+ for (auto& BindInfo : m_DescrSetBindInfo)
+ BindInfo.Reset();
+
+ for (auto& ResourcesPerBindPoint : m_ShaderResources)
+ ResourcesPerBindPoint.fill({});
+
VERIFY(m_CommandBuffer.GetState().RenderPass == VK_NULL_HANDLE, "Invalidating context with unifinished render pass");
m_CommandBuffer.Reset();
}
@@ -2091,8 +2198,7 @@ void DeviceContextVkImpl::FinishCommandList(class ICommandList** ppCommandList)
pCmdListVk->QueryInterface(IID_CommandList, reinterpret_cast<IObject**>(ppCommandList));
m_CommandBuffer.Reset();
- m_State = ContextState{};
- m_DescrSetBindInfo.Reset();
+ m_State = ContextState{};
m_pPipelineState = nullptr;
InvalidateState();
diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp
deleted file mode 100644
index e0196321..00000000
--- a/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp
+++ /dev/null
@@ -1,505 +0,0 @@
-/*
- * Copyright 2019-2021 Diligent Graphics LLC
- * Copyright 2015-2019 Egor Yusov
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * In no event and under no legal theory, whether in tort (including negligence),
- * contract, or otherwise, unless required by applicable law (such as deliberate
- * and grossly negligent acts) or agreed to in writing, shall any Contributor be
- * liable for any damages, including any direct, indirect, special, incidental,
- * or consequential damages of any character arising as a result of this License or
- * out of the use or inability to use the software (including but not limited to damages
- * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
- * all other commercial damages or losses), even if such Contributor has been advised
- * of the possibility of such damages.
- */
-
-#include "pch.h"
-
-#include "PipelineLayout.hpp"
-#include "ShaderResourceLayoutVk.hpp"
-#include "ShaderVkImpl.hpp"
-#include "RenderDeviceVkImpl.hpp"
-#include "DeviceContextVkImpl.hpp"
-#include "TextureVkImpl.hpp"
-#include "BufferVkImpl.hpp"
-#include "VulkanTypeConversions.hpp"
-#include "HashUtils.hpp"
-
-namespace Diligent
-{
-
-class ResourceTypeToVkDescriptorType
-{
-public:
- ResourceTypeToVkDescriptorType()
- {
- static_assert(Uint32{SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes} == 12, "Please add the corresponding decriptor type");
- m_Map[Uint32{SPIRVShaderResourceAttribs::ResourceType::UniformBuffer}] = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
- m_Map[Uint32{SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer}] = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
- m_Map[Uint32{SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer}] = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
- m_Map[Uint32{SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer}] = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
- m_Map[Uint32{SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer}] = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
- m_Map[Uint32{SPIRVShaderResourceAttribs::ResourceType::StorageImage}] = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
- m_Map[Uint32{SPIRVShaderResourceAttribs::ResourceType::SampledImage}] = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
- m_Map[Uint32{SPIRVShaderResourceAttribs::ResourceType::AtomicCounter}] = VK_DESCRIPTOR_TYPE_MAX_ENUM; // atomic counter doesn't exist in Vulkan
- m_Map[Uint32{SPIRVShaderResourceAttribs::ResourceType::SeparateImage}] = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
- m_Map[Uint32{SPIRVShaderResourceAttribs::ResourceType::SeparateSampler}] = VK_DESCRIPTOR_TYPE_SAMPLER;
- m_Map[Uint32{SPIRVShaderResourceAttribs::ResourceType::InputAttachment}] = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
- m_Map[Uint32{SPIRVShaderResourceAttribs::ResourceType::AccelerationStructure}] = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
- }
-
- VkDescriptorType operator[](SPIRVShaderResourceAttribs::ResourceType ResType) const
- {
- return m_Map[static_cast<int>(ResType)];
- }
-
-private:
- std::array<VkDescriptorType, Uint32{SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes}> m_Map = {};
-};
-
-VkDescriptorType PipelineLayout::GetVkDescriptorType(SPIRVShaderResourceAttribs::ResourceType Type)
-{
- static const ResourceTypeToVkDescriptorType ResTypeToVkDescrType;
- return ResTypeToVkDescrType[Type];
-}
-
-PipelineLayout::DescriptorSetLayoutManager::DescriptorSetLayoutManager(IMemoryAllocator& MemAllocator) :
- m_MemAllocator{MemAllocator},
- 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(NumLayoutBindings + 1, MemAllocator);
- pBindings[NumLayoutBindings++] = Binding;
- TotalDescriptors += Binding.descriptorCount;
- if (Binding.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ||
- Binding.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)
- {
- VERIFY(NumDynamicDescriptors + Binding.descriptorCount <= std::numeric_limits<decltype(NumDynamicDescriptors)>::max(), "Number of dynamic descriptors exceeds max representable value");
- NumDynamicDescriptors += static_cast<decltype(NumDynamicDescriptors)>(Binding.descriptorCount);
- }
-}
-
-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{2U << PlatformMisc::GetMSB(NumBindings - 1)};
- }
- VERIFY_EXPR(((NumBindings & (NumBindings - 1)) == 0) && NumBindings == MemSize || NumBindings < MemSize);
-
-#ifdef DILIGENT_DEBUG
- static constexpr size_t MinMemSize = 1;
-#else
- static constexpr size_t MinMemSize = 16;
-#endif
- MemSize = std::max(MemSize, MinMemSize);
- return MemSize * sizeof(VkDescriptorSetLayoutBinding);
-}
-
-void PipelineLayout::DescriptorSetLayoutManager::DescriptorSetLayout::ReserveMemory(Uint32 NumBindings, IMemoryAllocator& MemAllocator)
-{
- size_t ReservedMemory = GetMemorySize(NumLayoutBindings);
- size_t RequiredMemory = GetMemorySize(NumBindings);
- if (RequiredMemory > ReservedMemory)
- {
- void* pNewBindings = ALLOCATE_RAW(MemAllocator, "Memory buffer for descriptor set layout bindings", RequiredMemory);
- if (pBindings != nullptr)
- {
- memcpy(pNewBindings, pBindings, sizeof(VkDescriptorSetLayoutBinding) * NumLayoutBindings);
- MemAllocator.Free(pBindings);
- }
- pBindings = reinterpret_cast<VkDescriptorSetLayoutBinding*>(pNewBindings);
- }
-}
-
-void PipelineLayout::DescriptorSetLayoutManager::DescriptorSetLayout::Finalize(const VulkanUtilities::VulkanLogicalDevice& LogicalDevice,
- IMemoryAllocator& MemAllocator,
- VkDescriptorSetLayoutBinding* pNewBindings)
-{
- VERIFY_EXPR(memcmp(pBindings, pNewBindings, sizeof(VkDescriptorSetLayoutBinding) * NumLayoutBindings) == 0);
-
- VkDescriptorSetLayoutCreateInfo SetLayoutCI = {};
-
- SetLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
- SetLayoutCI.pNext = nullptr;
- SetLayoutCI.flags = 0;
- SetLayoutCI.bindingCount = NumLayoutBindings;
- SetLayoutCI.pBindings = pBindings;
- VkLayout = LogicalDevice.CreateDescriptorSetLayout(SetLayoutCI);
-
- MemAllocator.Free(pBindings);
- pBindings = pNewBindings;
-}
-
-void PipelineLayout::DescriptorSetLayoutManager::DescriptorSetLayout::Release(RenderDeviceVkImpl* pRenderDeviceVk, IMemoryAllocator& MemAllocator, Uint64 CommandQueueMask)
-{
- pRenderDeviceVk->SafeReleaseDeviceObject(std::move(VkLayout), CommandQueueMask);
- for (uint32_t b = 0; b < NumLayoutBindings; ++b)
- {
- if (pBindings[b].pImmutableSamplers != nullptr)
- MemAllocator.Free(const_cast<VkSampler*>(pBindings[b].pImmutableSamplers));
- }
- pBindings = nullptr;
- NumLayoutBindings = 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
-{
- // clang-format off
- if (TotalDescriptors != rhs.TotalDescriptors ||
- SetIndex != rhs.SetIndex ||
- NumDynamicDescriptors != rhs.NumDynamicDescriptors ||
- NumLayoutBindings != rhs.NumLayoutBindings)
- return false;
- // clang-format on
-
- for (uint32_t b = 0; b < NumLayoutBindings; ++b)
- {
- const auto& B0 = pBindings[b];
- const auto& B1 = rhs.pBindings[b];
- // clang-format off
- 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;
- // Immutable samplers themselves should not affect compatibility
- // clang-format on
- }
- return true;
-}
-
-size_t PipelineLayout::DescriptorSetLayoutManager::DescriptorSetLayout::GetHash() const
-{
- size_t Hash = ComputeHash(SetIndex, NumLayoutBindings, TotalDescriptors, NumDynamicDescriptors);
- for (uint32_t b = 0; b < NumLayoutBindings; ++b)
- {
- const auto& B = pBindings[b];
- HashCombine(Hash, B.binding, static_cast<size_t>(B.descriptorType), B.descriptorCount, static_cast<size_t>(B.stageFlags), B.pImmutableSamplers != nullptr);
- }
-
- return Hash;
-}
-
-void PipelineLayout::DescriptorSetLayoutManager::Finalize(const VulkanUtilities::VulkanLogicalDevice& LogicalDevice)
-{
- size_t TotalBindings = 0;
- for (const auto& Layout : m_DescriptorSetLayouts)
- {
- TotalBindings += Layout.NumLayoutBindings;
- }
- m_LayoutBindings.resize(TotalBindings);
- size_t BindingOffset = 0;
-
- std::array<VkDescriptorSetLayout, 2> ActiveDescrSetLayouts = {};
- for (auto& Layout : m_DescriptorSetLayouts)
- {
- if (Layout.SetIndex >= 0)
- {
- std::copy(Layout.pBindings, Layout.pBindings + Layout.NumLayoutBindings, m_LayoutBindings.begin() + BindingOffset);
- Layout.Finalize(LogicalDevice, m_MemAllocator, &m_LayoutBindings[BindingOffset]);
- BindingOffset += Layout.NumLayoutBindings;
- ActiveDescrSetLayouts[Layout.SetIndex] = Layout.VkLayout;
- }
- }
- VERIFY_EXPR(BindingOffset == TotalBindings);
- // clang-format off
- VERIFY_EXPR(m_ActiveSets == 0 && ActiveDescrSetLayouts[0] == VK_NULL_HANDLE && ActiveDescrSetLayouts[1] == VK_NULL_HANDLE ||
- m_ActiveSets == 1 && ActiveDescrSetLayouts[0] != VK_NULL_HANDLE && ActiveDescrSetLayouts[1] == VK_NULL_HANDLE ||
- m_ActiveSets == 2 && ActiveDescrSetLayouts[0] != VK_NULL_HANDLE && ActiveDescrSetLayouts[1] != VK_NULL_HANDLE);
- // clang-format on
-
- VkPipelineLayoutCreateInfo PipelineLayoutCI = {};
-
- PipelineLayoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
- PipelineLayoutCI.pNext = nullptr;
- PipelineLayoutCI.flags = 0; // reserved for future use
- PipelineLayoutCI.setLayoutCount = m_ActiveSets;
- PipelineLayoutCI.pSetLayouts = PipelineLayoutCI.setLayoutCount != 0 ? ActiveDescrSetLayouts.data() : nullptr;
- PipelineLayoutCI.pushConstantRangeCount = 0;
- PipelineLayoutCI.pPushConstantRanges = nullptr;
- m_VkPipelineLayout = LogicalDevice.CreatePipelineLayout(PipelineLayoutCI);
-
- VERIFY_EXPR(BindingOffset == TotalBindings);
-}
-
-void PipelineLayout::DescriptorSetLayoutManager::Release(RenderDeviceVkImpl* pRenderDeviceVk, Uint64 CommandQueueMask)
-{
- for (auto& Layout : m_DescriptorSetLayouts)
- Layout.Release(pRenderDeviceVk, m_MemAllocator, CommandQueueMask);
-
- pRenderDeviceVk->SafeReleaseDeviceObject(std::move(m_VkPipelineLayout), CommandQueueMask);
-}
-
-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
-{
- // Two pipeline layouts are defined to be "compatible for set N" if they were created with identically
- // defined descriptor set layouts for sets zero through N, and if they were created with identical push
- // constant ranges (13.2.2)
-
- if (m_ActiveSets != rhs.m_ActiveSets)
- return false;
-
- for (size_t i = 0; i < m_DescriptorSetLayouts.size(); ++i)
- if (m_DescriptorSetLayouts[i] != rhs.m_DescriptorSetLayouts[i])
- return false;
-
- return true;
-}
-
-size_t PipelineLayout::DescriptorSetLayoutManager::GetHash() const
-{
- size_t Hash = 0;
- for (const auto& SetLayout : m_DescriptorSetLayouts)
- HashCombine(Hash, SetLayout.GetHash());
-
- return Hash;
-}
-
-void PipelineLayout::DescriptorSetLayoutManager::AllocateResourceSlot(const SPIRVShaderResourceAttribs& ResAttribs,
- SHADER_RESOURCE_VARIABLE_TYPE VariableType,
- VkSampler vkImmutableSampler,
- SHADER_TYPE ShaderType,
- Uint32& DescriptorSet,
- Uint32& Binding,
- Uint32& OffsetInCache)
-{
- auto& DescrSet = GetDescriptorSet(VariableType);
- if (DescrSet.SetIndex < 0)
- {
- DescrSet.SetIndex = m_ActiveSets++;
- }
- DescriptorSet = DescrSet.SetIndex;
-
- VkDescriptorSetLayoutBinding VkBinding = {};
-
- Binding = DescrSet.NumLayoutBindings;
-
- VkBinding.binding = Binding;
- VkBinding.descriptorType = GetVkDescriptorType(ResAttribs.Type);
- VkBinding.descriptorCount = ResAttribs.ArraySize;
- // There are no limitations on what combinations of stages can use a descriptor binding (13.2.1)
- VkBinding.stageFlags = ShaderTypeToVkShaderStageFlagBit(ShaderType);
- if (vkImmutableSampler != VK_NULL_HANDLE)
- {
- // 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)
- auto* pImmutableSamplers = ALLOCATE(m_MemAllocator, "Memory buffer for immutable samplers", VkSampler, VkBinding.descriptorCount);
- for (uint32_t s = 0; s < VkBinding.descriptorCount; ++s)
- pImmutableSamplers[s] = vkImmutableSampler;
- VkBinding.pImmutableSamplers = pImmutableSamplers;
- }
- else
- VkBinding.pImmutableSamplers = nullptr;
-
- OffsetInCache = DescrSet.TotalDescriptors;
- DescrSet.AddBinding(VkBinding, m_MemAllocator);
-}
-
-PipelineLayout::PipelineLayout() :
- m_MemAllocator{GetRawAllocator()},
- m_LayoutMgr{m_MemAllocator}
-{
-}
-
-void PipelineLayout::Release(RenderDeviceVkImpl* pDeviceVkImpl, Uint64 CommandQueueMask)
-{
- m_LayoutMgr.Release(pDeviceVkImpl, CommandQueueMask);
-}
-
-void PipelineLayout::AllocateResourceSlot(const SPIRVShaderResourceAttribs& ResAttribs,
- SHADER_RESOURCE_VARIABLE_TYPE VariableType,
- VkSampler vkImmutableSampler,
- SHADER_TYPE ShaderType,
- Uint32& DescriptorSet, // Output parameter
- Uint32& Binding, // Output parameter
- Uint32& OffsetInCache)
-{
- VERIFY((ResAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage ||
- ResAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler) ||
- vkImmutableSampler == VK_NULL_HANDLE,
- "Immutable sampler should only be specified for combined image samplers or separate samplers");
- m_LayoutMgr.AllocateResourceSlot(ResAttribs, VariableType, vkImmutableSampler, ShaderType, DescriptorSet, Binding, OffsetInCache);
-}
-
-void PipelineLayout::Finalize(const VulkanUtilities::VulkanLogicalDevice& LogicalDevice)
-{
- m_LayoutMgr.Finalize(LogicalDevice);
-}
-
-std::array<Uint32, 2> PipelineLayout::GetDescriptorSetSizes(Uint32& NumSets) const
-{
- NumSets = 0;
- std::array<Uint32, 2> SetSizes = {};
-
- const auto& StaticAndMutSet = m_LayoutMgr.GetDescriptorSet(SHADER_RESOURCE_VARIABLE_TYPE_STATIC);
- if (StaticAndMutSet.SetIndex >= 0)
- {
- NumSets = std::max(NumSets, static_cast<Uint32>(StaticAndMutSet.SetIndex + 1));
- SetSizes[StaticAndMutSet.SetIndex] = StaticAndMutSet.TotalDescriptors;
- }
-
- const auto& DynamicSet = m_LayoutMgr.GetDescriptorSet(SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC);
- if (DynamicSet.SetIndex >= 0)
- {
- NumSets = std::max(NumSets, static_cast<Uint32>(DynamicSet.SetIndex + 1));
- SetSizes[DynamicSet.SetIndex] = DynamicSet.TotalDescriptors;
- }
-
- return SetSizes;
-}
-
-void PipelineLayout::InitResourceCache(RenderDeviceVkImpl* pDeviceVkImpl,
- ShaderResourceCacheVk& ResourceCache,
- IMemoryAllocator& CacheMemAllocator,
- const char* DbgPipelineName) const
-{
- Uint32 NumSets = 0;
- auto SetSizes = GetDescriptorSetSizes(NumSets);
-
- // This call only initializes descriptor sets (ShaderResourceCacheVk::DescriptorSet) in the resource cache
- // Resources are initialized by source layout when shader resource binding objects are created
- ResourceCache.InitializeSets(CacheMemAllocator, NumSets, SetSizes.data());
-
- const auto& StaticAndMutSet = m_LayoutMgr.GetDescriptorSet(SHADER_RESOURCE_VARIABLE_TYPE_STATIC);
- if (StaticAndMutSet.SetIndex >= 0)
- {
- const char* DescrSetName = "Static/Mutable Descriptor Set";
-#ifdef DILIGENT_DEVELOPMENT
- std::string _DescrSetName(DbgPipelineName);
- _DescrSetName.append(" - static/mutable set");
- DescrSetName = _DescrSetName.c_str();
-#endif
- DescriptorSetAllocation SetAllocation = pDeviceVkImpl->AllocateDescriptorSet(~Uint64{0}, StaticAndMutSet.VkLayout, DescrSetName);
- ResourceCache.GetDescriptorSet(StaticAndMutSet.SetIndex).AssignDescriptorSetAllocation(std::move(SetAllocation));
- }
-}
-
-void PipelineLayout::PrepareDescriptorSets(DeviceContextVkImpl* pCtxVkImpl,
- VkPipelineBindPoint BindPoint,
- const ShaderResourceCacheVk& ResourceCache,
- DescriptorSetBindInfo& BindInfo,
- VkDescriptorSet VkDynamicDescrSet) const
-{
-#ifdef DILIGENT_DEBUG
- BindInfo.vkSets.clear();
-#endif
-
- // Do not use vector::resize for BindInfo.vkSets and BindInfo.DynamicOffsets as this
- // causes unnecessary work to zero-initialize new elements
-
- VERIFY(m_LayoutMgr.GetDescriptorSet(SHADER_RESOURCE_VARIABLE_TYPE_STATIC).SetIndex == m_LayoutMgr.GetDescriptorSet(SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE).SetIndex,
- "Static and mutable variables are expected to share the same descriptor set");
- Uint32 TotalDynamicDescriptors = 0;
-
- BindInfo.SetCout = 0;
- for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE; VarType <= SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC; VarType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(VarType + 1))
- {
- const auto& Set = m_LayoutMgr.GetDescriptorSet(VarType);
- if (Set.SetIndex >= 0)
- {
- BindInfo.SetCout = std::max(BindInfo.SetCout, static_cast<Uint32>(Set.SetIndex + 1));
- if (BindInfo.SetCout > BindInfo.vkSets.size())
- BindInfo.vkSets.resize(BindInfo.SetCout);
- VERIFY_EXPR(BindInfo.vkSets[Set.SetIndex] == VK_NULL_HANDLE);
- if (VarType == SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE)
- BindInfo.vkSets[Set.SetIndex] = ResourceCache.GetDescriptorSet(Set.SetIndex).GetVkDescriptorSet();
- else
- {
- VERIFY_EXPR(ResourceCache.GetDescriptorSet(Set.SetIndex).GetVkDescriptorSet() == VK_NULL_HANDLE);
- BindInfo.vkSets[Set.SetIndex] = VkDynamicDescrSet;
- }
- VERIFY(BindInfo.vkSets[Set.SetIndex] != VK_NULL_HANDLE, "Descriptor set must not be null");
- }
- TotalDynamicDescriptors += Set.NumDynamicDescriptors;
- }
-
-#ifdef DILIGENT_DEBUG
- for (const auto& set : BindInfo.vkSets)
- VERIFY(set != VK_NULL_HANDLE, "Descriptor set must not be null");
-#endif
-
- BindInfo.DynamicOffsetCount = TotalDynamicDescriptors;
- if (TotalDynamicDescriptors > BindInfo.DynamicOffsets.size())
- BindInfo.DynamicOffsets.resize(TotalDynamicDescriptors);
- BindInfo.BindPoint = BindPoint;
- BindInfo.pResourceCache = &ResourceCache;
-#ifdef DILIGENT_DEBUG
- BindInfo.pDbgPipelineLayout = this;
-#endif
- BindInfo.DynamicBuffersPresent = ResourceCache.GetNumDynamicBuffers() > 0;
-
- if (TotalDynamicDescriptors == 0)
- {
- // There are no dynamic descriptors, so we can bind descriptor sets right now
- auto& CmdBuffer = pCtxVkImpl->GetCommandBuffer();
- CmdBuffer.BindDescriptorSets(BindInfo.BindPoint,
- m_LayoutMgr.GetVkPipelineLayout(),
- 0, // First set
- BindInfo.SetCout,
- BindInfo.vkSets.data(), // BindInfo.vkSets is never empty
- 0,
- nullptr);
- }
-
- BindInfo.DynamicDescriptorsBound = false;
-}
-
-} // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineLayoutCacheVk.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineLayoutCacheVk.cpp
new file mode 100644
index 00000000..6ca53a44
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/src/PipelineLayoutCacheVk.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2019-2021 Diligent Graphics LLC
+ * Copyright 2015-2019 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#include "PipelineLayoutCacheVk.hpp"
+#include "RenderDeviceVkImpl.hpp"
+
+namespace Diligent
+{
+
+bool PipelineLayoutCacheVk::PipelineLayoutCompare::operator()(const PipelineLayoutVk* lhs, const PipelineLayoutVk* rhs) const noexcept
+{
+ if (lhs->GetSignatureCount() != rhs->GetSignatureCount())
+ return false;
+
+ for (Uint32 i = 0, Cnt = lhs->GetSignatureCount(); i < Cnt; ++i)
+ {
+ if (lhs->GetSignature(i) != rhs->GetSignature(i))
+ return false;
+ }
+ return true;
+}
+
+PipelineLayoutCacheVk::~PipelineLayoutCacheVk()
+{
+ std::lock_guard<std::mutex> Lock{m_Mutex};
+ VERIFY(m_Cache.empty(), "All pipeline layouts must be released");
+}
+
+RefCntAutoPtr<PipelineLayoutVk> PipelineLayoutCacheVk::GetLayout(IPipelineResourceSignature** ppSignatures, Uint32 SignatureCount)
+{
+ RefCntAutoPtr<PipelineLayoutVk> pNewLayout;
+ m_DeviceVk.CreatePipelineLayout(ppSignatures, SignatureCount, &pNewLayout);
+
+ if (pNewLayout == nullptr)
+ return {};
+
+ std::lock_guard<std::mutex> Lock{m_Mutex};
+
+ PipelineLayoutVk* pResult = *m_Cache.insert(pNewLayout).first;
+
+ if (pNewLayout == pResult)
+ {
+ pNewLayout->Finalize();
+ void(pNewLayout.Detach());
+ }
+ return RefCntAutoPtr<PipelineLayoutVk>{pResult};
+}
+
+void PipelineLayoutCacheVk::OnDestroyLayout(PipelineLayoutVk* pLayout)
+{
+ std::lock_guard<std::mutex> Lock{m_Mutex};
+
+ m_Cache.erase(pLayout);
+}
+
+} // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineLayoutVk.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineLayoutVk.cpp
new file mode 100644
index 00000000..446c41bb
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/src/PipelineLayoutVk.cpp
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2019-2021 Diligent Graphics LLC
+ * Copyright 2015-2019 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#include "pch.h"
+
+#include "PipelineLayoutVk.hpp"
+#include "ShaderVkImpl.hpp"
+#include "RenderDeviceVkImpl.hpp"
+#include "DeviceContextVkImpl.hpp"
+#include "TextureVkImpl.hpp"
+#include "BufferVkImpl.hpp"
+#include "VulkanTypeConversions.hpp"
+#include "HashUtils.hpp"
+
+namespace Diligent
+{
+
+PipelineLayoutVk::PipelineLayoutVk(IReferenceCounters* pRefCounters, RenderDeviceVkImpl* pDeviceVk, IPipelineResourceSignature** ppSignatures, Uint32 SignatureCount) :
+ ObjectBase<IObject>{pRefCounters},
+ m_pDeviceVk{pDeviceVk},
+ m_SignatureCount{0}
+{
+ for (Uint32 i = 0; i < SignatureCount; ++i)
+ {
+ auto* pSign = ValidatedCast<PipelineResourceSignatureVkImpl>(ppSignatures[i]);
+ if (pSign)
+ {
+ const Uint8 Index = pSign->GetDesc().BindingIndex;
+
+ if (Index >= m_Signatures.size())
+ LOG_ERROR_AND_THROW("Pipeline resource signature '", pSign->GetDesc().Name, "' index (", Uint32{Index}, ") must be less than (", m_Signatures.size(), ").");
+
+ if (m_Signatures[Index] != nullptr)
+ LOG_ERROR_AND_THROW("Pipeline resource signature '", pSign->GetDesc().Name, "' with index (", Uint32{Index}, ") overrides another resource signature '", m_Signatures[Index]->GetDesc().Name, "'.");
+
+ m_SignatureCount = std::max(m_SignatureCount, Uint8(Index + 1));
+ m_Signatures[Index] = pSign;
+
+ if (m_PipelineType <= PIPELINE_TYPE_LAST)
+ {
+ if (m_PipelineType != pSign->GetPipelineType())
+ {
+ LOG_ERROR_AND_THROW("Pipeline resource signature '", pSign->GetDesc().Name, "' with index (", Uint32{Index}, ") has different pipeline type (",
+ GetPipelineTypeString(pSign->GetPipelineType()), ") than other (", GetPipelineTypeString(m_PipelineType), ").");
+ }
+ }
+ else
+ m_PipelineType = pSign->GetPipelineType();
+ }
+ }
+}
+
+PipelineLayoutVk::~PipelineLayoutVk()
+{
+ m_pDeviceVk->GetPipelineLayoutCache().OnDestroyLayout(this);
+ m_pDeviceVk->SafeReleaseDeviceObject(std::move(m_VkPipelineLayout), ~0ull);
+}
+
+void PipelineLayoutVk::Finalize()
+{
+ std::array<VkDescriptorSetLayout, MAX_RESOURCE_SIGNATURES * 2> DescSetLayouts;
+
+ Uint32 DescSetLayoutCount = 0;
+ Uint32 DynamicBufferCount = 0;
+
+ for (Uint32 i = 0; i < m_SignatureCount; ++i)
+ {
+ if (m_Signatures[i] == nullptr)
+ continue;
+
+ m_DescSetOffset[i] = static_cast<Uint8>(DescSetLayoutCount);
+ m_DynBufOffset[i] = static_cast<Uint16>(DynamicBufferCount);
+
+ auto StaticDSLayout = m_Signatures[i]->GetStaticVkDescriptorSetLayout();
+ auto DynamicDSLayout = m_Signatures[i]->GetDynamicVkDescriptorSetLayout();
+
+ if (StaticDSLayout) DescSetLayouts[DescSetLayoutCount++] = StaticDSLayout;
+ if (DynamicDSLayout) DescSetLayouts[DescSetLayoutCount++] = DynamicDSLayout;
+
+ DynamicBufferCount += m_Signatures[i]->GetDynamicBufferCount();
+ }
+
+ VkPipelineLayoutCreateInfo PipelineLayoutCI = {};
+
+ PipelineLayoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+ PipelineLayoutCI.pNext = nullptr;
+ PipelineLayoutCI.flags = 0; // reserved for future use
+ PipelineLayoutCI.setLayoutCount = DescSetLayoutCount;
+ PipelineLayoutCI.pSetLayouts = DescSetLayoutCount ? DescSetLayouts.data() : nullptr;
+ PipelineLayoutCI.pushConstantRangeCount = 0;
+ PipelineLayoutCI.pPushConstantRanges = nullptr;
+ m_VkPipelineLayout = m_pDeviceVk->GetLogicalDevice().CreatePipelineLayout(PipelineLayoutCI);
+
+ const auto& Limits = m_pDeviceVk->GetPhysicalDevice().GetProperties().limits;
+ VERIFY_EXPR(DescSetLayoutCount <= Limits.maxBoundDescriptorSets);
+ VERIFY_EXPR(DynamicBufferCount <= (Limits.maxDescriptorSetUniformBuffersDynamic + Limits.maxDescriptorSetStorageBuffersDynamic)); // AZ TODO
+
+ m_DescrSetCount = static_cast<Uint8>(DescSetLayoutCount);
+ m_DynamicOffsetCount = static_cast<Uint16>(DynamicBufferCount);
+}
+
+size_t PipelineLayoutVk::GetHash() const
+{
+ size_t hash = 0;
+ HashCombine(hash, m_SignatureCount);
+ for (Uint32 i = 0; i < m_SignatureCount; ++i)
+ {
+ if (m_Signatures[i] != nullptr)
+ HashCombine(hash, m_Signatures[i]->GetHash());
+ else
+ HashCombine(hash, 0);
+ }
+ return hash;
+}
+
+bool PipelineLayoutVk::GetResourceInfo(const char* Name, SHADER_TYPE Stage, ResourceInfo& Info) const
+{
+ // AZ TODO: optimize
+ for (Uint32 i = 0, Count = GetSignatureCount(); i < Count; ++i)
+ {
+ auto* pSign = GetSignature(i);
+ if (pSign)
+ {
+ auto& Desc = pSign->GetDesc();
+ Uint32 BindingCount[2] = {};
+
+ for (Uint32 j = 0; j < Desc.NumResources; ++j)
+ {
+ auto& Res = Desc.Resources[j];
+ Uint16 DSIndex = (Res.VarType == SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC ? 1 : 0);
+
+ if ((Res.ShaderStages & Stage) && strcmp(Res.Name, Name) == 0)
+ {
+ Info.Type = Res.ResourceType;
+ Info.BindingIndex = static_cast<Uint16>(BindingCount[DSIndex]);
+ Info.DescrSetIndex = m_DescSetOffset[i] + DSIndex;
+ return true;
+ }
+ BindingCount[DSIndex] += Res.ArraySize;
+ }
+ }
+ }
+ return false;
+}
+
+} // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineResourceSignatureVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineResourceSignatureVkImpl.cpp
new file mode 100644
index 00000000..da646a96
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/src/PipelineResourceSignatureVkImpl.cpp
@@ -0,0 +1,465 @@
+/*
+ * Copyright 2019-2021 Diligent Graphics LLC
+ * Copyright 2015-2019 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#include "pch.h"
+#include "PipelineResourceSignatureVkImpl.hpp"
+#include "ShaderResourceBindingVkImpl.hpp"
+#include "RenderDeviceVkImpl.hpp"
+#include "VulkanTypeConversions.hpp"
+
+namespace Diligent
+{
+
+VkDescriptorType PipelineResourceSignatureVkImpl::GetVkDescriptorType(const PipelineResourceDesc& Res)
+{
+ const bool WithDynamicOffset = !(Res.Flags & PIPELINE_RESOURCE_FLAG_NO_DYNAMIC_OFFSETS);
+ const bool CombinedSampler = (Res.Flags & PIPELINE_RESOURCE_FLAG_COMBINED_IMAGE);
+ const bool UseTexelBuffer = (Res.Flags & PIPELINE_RESOURCE_FLAG_TEXEL_BUFFER);
+
+ VERIFY_EXPR(WithDynamicOffset ^ UseTexelBuffer);
+ VERIFY_EXPR(CombinedSampler ? !(WithDynamicOffset | UseTexelBuffer) : true);
+
+ static_assert(SHADER_RESOURCE_TYPE_LAST == SHADER_RESOURCE_TYPE_ACCEL_STRUCT, "Please update the switch below to handle the new shader resource type");
+ switch (Res.ResourceType)
+ {
+ // clang-format off
+ case SHADER_RESOURCE_TYPE_CONSTANT_BUFFER: return WithDynamicOffset ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ case SHADER_RESOURCE_TYPE_BUFFER_UAV: return UseTexelBuffer ? VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER : (WithDynamicOffset ? VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC : VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
+ case SHADER_RESOURCE_TYPE_TEXTURE_SRV: return CombinedSampler ? VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER : VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
+ case SHADER_RESOURCE_TYPE_BUFFER_SRV: return UseTexelBuffer ? VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER : (WithDynamicOffset ? VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC : VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
+ case SHADER_RESOURCE_TYPE_TEXTURE_UAV: return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
+ case SHADER_RESOURCE_TYPE_SAMPLER: return VK_DESCRIPTOR_TYPE_SAMPLER;
+ case SHADER_RESOURCE_TYPE_INPUT_ATTACHMENT: return VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
+ case SHADER_RESOURCE_TYPE_ACCEL_STRUCT: return VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
+ default: UNEXPECTED("unknown resource type");
+ // clang-format on
+ }
+ return VK_DESCRIPTOR_TYPE_MAX_ENUM;
+}
+
+PipelineResourceSignatureVkImpl::PipelineResourceSignatureVkImpl(IReferenceCounters* pRefCounters,
+ RenderDeviceVkImpl* pDevice,
+ const PipelineResourceSignatureDesc& Desc,
+ bool bIsDeviceInternal) :
+ TPipelineResourceSignatureBase{pRefCounters, pDevice, Desc, bIsDeviceInternal},
+ m_SRBMemAllocator{GetRawAllocator()}
+{
+#define LOG_PRS_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Description of a pipeline resource signature '", (Desc.Name ? Desc.Name : ""), "' is invalid: ", ##__VA_ARGS__)
+
+ try
+ {
+ FixedLinearAllocator MemPool{GetRawAllocator()};
+
+ MemPool.AddSpace<PackedBindingIndex>(Desc.NumResources);
+
+ ReserveSpaceForDescription(MemPool, Desc);
+
+ Int8 StaticVarStageCount = 0;
+ Uint32 StaticVarCount = 0;
+ {
+ // get active shader stages
+ SHADER_TYPE Stages = SHADER_TYPE_UNKNOWN;
+ SHADER_TYPE StaticResStages = SHADER_TYPE_UNKNOWN;
+
+ for (Uint32 i = 0; i < Desc.NumResources; ++i)
+ {
+ const auto& Res = Desc.Resources[i];
+ Stages |= Res.ShaderStages;
+
+ if (Res.VarType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC)
+ {
+ StaticResStages |= Res.ShaderStages;
+ StaticVarCount += Res.ArraySize;
+ }
+ }
+
+ m_ShaderStages = Stages;
+ m_NumShaders = static_cast<Uint8>(PlatformMisc::CountOneBits(static_cast<Uint32>(Stages)));
+
+ if (Stages == SHADER_TYPE_COMPUTE)
+ {
+ m_PipelineType = PIPELINE_TYPE_COMPUTE;
+ }
+ else if (Stages & (SHADER_TYPE_AMPLIFICATION | SHADER_TYPE_MESH))
+ {
+ m_PipelineType = PIPELINE_TYPE_MESH;
+ }
+ else if (Stages < SHADER_TYPE_COMPUTE)
+ {
+ m_PipelineType = PIPELINE_TYPE_GRAPHICS;
+ }
+ else if (Stages >= SHADER_TYPE_RAY_GEN)
+ {
+ m_PipelineType = PIPELINE_TYPE_RAY_TRACING;
+ }
+ else
+ {
+ LOG_PRS_ERROR_AND_THROW("can not deduce pipeline type - used incompatible shader stages");
+ }
+
+ m_StaticVarIndex.fill(-1);
+
+ for (; StaticResStages != SHADER_TYPE_UNKNOWN; ++StaticVarStageCount)
+ {
+ auto StageBit = static_cast<SHADER_TYPE>(1 << PlatformMisc::GetLSB(Uint32{StaticResStages}));
+ StaticResStages = StaticResStages & ~StageBit;
+
+ const auto ShaderTypeInd = GetShaderTypePipelineIndex(StageBit, m_PipelineType);
+ m_StaticVarIndex[ShaderTypeInd] = StaticVarStageCount;
+ }
+
+ if (StaticVarStageCount > 0)
+ {
+ MemPool.AddSpace<ShaderResourceCacheVk>(1);
+ MemPool.AddSpace<ShaderVariableManagerVk>(StaticVarStageCount);
+ }
+ }
+
+
+ MemPool.Reserve();
+
+
+ m_pBindingIndices = MemPool.Allocate<PackedBindingIndex>(m_Desc.NumResources);
+
+ // The memory is now owned by PipelineResourceSignatureVkImpl and will be freed by Destruct().
+ auto* Ptr = MemPool.ReleaseOwnership();
+ VERIFY_EXPR(Ptr == m_pBindingIndices);
+ (void)Ptr;
+
+ CopyDescription(MemPool, Desc);
+
+ if (StaticVarStageCount > 0)
+ {
+ m_pResourceCache = MemPool.Construct<ShaderResourceCacheVk>(ShaderResourceCacheVk::StaticShaderResources);
+ m_StaticVarsMgrs = MemPool.Allocate<ShaderVariableManagerVk>(StaticVarStageCount);
+
+ m_pResourceCache->InitializeSets(GetRawAllocator(), 1, &StaticVarCount);
+
+ const SHADER_RESOURCE_VARIABLE_TYPE AllowedVarTypes[] = {SHADER_RESOURCE_VARIABLE_TYPE_STATIC};
+
+ for (Int8 i = 0; i < StaticVarStageCount; ++i)
+ {
+ new (m_StaticVarsMgrs + i) ShaderVariableManagerVk{*this, *m_pResourceCache};
+ m_StaticVarsMgrs[i].Initialize(*this, GetRawAllocator(), AllowedVarTypes, _countof(AllowedVarTypes));
+ }
+ }
+
+ std::vector<VkDescriptorSetLayoutBinding> LayoutBindings[2];
+
+ for (Uint32 i = 0; i < m_Desc.NumResources; ++i)
+ {
+ const auto& Res = m_Desc.Resources[i];
+ auto& Binding = m_pBindingIndices[i];
+
+ Binding.DescSet = (Res.VarType == SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC ? 1 : 0);
+ Binding.Binding = static_cast<Uint16>(LayoutBindings[Binding.DescSet].size());
+ Binding.SamplerInd = 0; // AZ TODO
+
+ LayoutBindings[Binding.DescSet].emplace_back();
+ auto& LayoutBinding = LayoutBindings[Binding.DescSet].back();
+
+ LayoutBinding.binding = Binding.Binding;
+ LayoutBinding.descriptorCount = Res.ArraySize;
+ LayoutBinding.stageFlags = ShaderTypesToVkShaderStageFlags(Res.ShaderStages);
+ LayoutBinding.pImmutableSamplers = nullptr;
+ LayoutBinding.descriptorType = GetVkDescriptorType(Res);
+
+ if (!(Res.Flags & PIPELINE_RESOURCE_FLAG_NO_DYNAMIC_OFFSETS))
+ m_DynamicBufferCount += static_cast<Uint16>(Res.ArraySize);
+
+ if (m_pResourceCache && Res.VarType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC)
+ m_pResourceCache->InitializeResources(0, Binding.Binding, Res.ArraySize, LayoutBinding.descriptorType);
+ }
+
+ if (m_Desc.SRBAllocationGranularity > 1)
+ {
+ const SHADER_RESOURCE_VARIABLE_TYPE AllowedVarTypes[] = {SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE, SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC};
+
+ Uint32 UnusedNumVars = 0;
+ const size_t ShaderVariableDataSize = ShaderVariableManagerVk::GetRequiredMemorySize(*this, AllowedVarTypes, _countof(AllowedVarTypes), UnusedNumVars);
+
+ const Uint32 NumSets = !LayoutBindings[0].empty() + !LayoutBindings[1].empty();
+ const Uint32 DescriptorSetSizes[] = {static_cast<Uint32>(LayoutBindings[0].size()), static_cast<Uint32>(LayoutBindings[1].size())};
+ const size_t CacheMemorySize = ShaderResourceCacheVk::GetRequiredMemorySize(NumSets, DescriptorSetSizes);
+
+ m_SRBMemAllocator.Initialize(m_Desc.SRBAllocationGranularity, 1, &ShaderVariableDataSize, 1, &CacheMemorySize);
+ }
+
+ VkDescriptorSetLayoutCreateInfo SetLayoutCI = {};
+
+ SetLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
+ SetLayoutCI.pNext = nullptr;
+ SetLayoutCI.flags = 0;
+
+ const auto& LogicalDevice = pDevice->GetLogicalDevice();
+
+ for (Uint32 i = 0; i < _countof(LayoutBindings); ++i)
+ {
+ auto& LayoutBinding = LayoutBindings[i];
+ if (LayoutBinding.empty())
+ continue;
+
+ SetLayoutCI.bindingCount = static_cast<Uint32>(LayoutBinding.size());
+ SetLayoutCI.pBindings = LayoutBinding.data();
+ m_VkDescSetLayouts[i] = LogicalDevice.CreateDescriptorSetLayout(SetLayoutCI);
+ }
+ }
+ catch (...)
+ {
+ Destruct();
+ throw;
+ }
+#undef LOG_PRS_ERROR_AND_THROW
+}
+
+PipelineResourceSignatureVkImpl::~PipelineResourceSignatureVkImpl()
+{
+ Destruct();
+}
+
+void PipelineResourceSignatureVkImpl::Destruct()
+{
+ TPipelineResourceSignatureBase::Destruct();
+
+ for (auto& Layout : m_VkDescSetLayouts)
+ {
+ if (Layout)
+ m_pDevice->SafeReleaseDeviceObject(std::move(Layout), ~0ull);
+ }
+
+ if (m_pBindingIndices == nullptr)
+ return; // memory is not allocated
+
+ auto& RawAllocator = GetRawAllocator();
+
+ for (size_t i = 0; m_StaticVarsMgrs && i < m_StaticVarIndex.size(); ++i)
+ {
+ Int8 Idx = m_StaticVarIndex[i];
+ if (Idx >= 0)
+ {
+ m_StaticVarsMgrs[Idx].DestroyVariables(RawAllocator);
+ m_StaticVarsMgrs[Idx].~ShaderVariableManagerVk();
+ }
+ }
+ m_StaticVarsMgrs = nullptr;
+
+ if (m_pResourceCache != nullptr)
+ {
+ m_pResourceCache->~ShaderResourceCacheVk();
+ m_pResourceCache = nullptr;
+ }
+
+ if (void* pRawMem = m_pBindingIndices)
+ {
+ RawAllocator.Free(pRawMem);
+ m_pBindingIndices = nullptr;
+ }
+}
+
+void PipelineResourceSignatureVkImpl::CreateShaderResourceBinding(IShaderResourceBinding** ppShaderResourceBinding,
+ bool InitStaticResources)
+{
+ auto& SRBAllocator = m_pDevice->GetSRBAllocator();
+ auto pResBindingVk = NEW_RC_OBJ(SRBAllocator, "ShaderResourceBindingVkImpl instance", ShaderResourceBindingVkImpl)(this, false);
+ if (InitStaticResources)
+ pResBindingVk->InitializeStaticResources(nullptr);
+ pResBindingVk->QueryInterface(IID_ShaderResourceBinding, reinterpret_cast<IObject**>(ppShaderResourceBinding));
+}
+
+void PipelineResourceSignatureVkImpl::PrepareDescriptorSets(DeviceContextVkImpl* pCtxVkImpl,
+ VkPipelineBindPoint BindPoint,
+ const ShaderResourceCacheVk& ResourceCache,
+ DescriptorSetBindInfo& BindInfo,
+ VkDescriptorSet VkDynamicDescrSet) const
+{
+ /*
+#ifdef DILIGENT_DEBUG
+ BindInfo.vkSets.clear();
+#endif
+
+ // Do not use vector::resize for BindInfo.vkSets and BindInfo.DynamicOffsets as this
+ // causes unnecessary work to zero-initialize new elements
+
+ VERIFY(m_LayoutMgr.GetDescriptorSet(SHADER_RESOURCE_VARIABLE_TYPE_STATIC).SetIndex == m_LayoutMgr.GetDescriptorSet(SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE).SetIndex,
+ "Static and mutable variables are expected to share the same descriptor set");
+ Uint32 TotalDynamicDescriptors = 0;
+
+ BindInfo.SetCout = 0;
+ for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE; VarType <= SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC; VarType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(VarType + 1))
+ {
+ const auto& Set = m_LayoutMgr.GetDescriptorSet(VarType);
+ if (Set.SetIndex >= 0)
+ {
+ BindInfo.SetCout = std::max(BindInfo.SetCout, static_cast<Uint32>(Set.SetIndex + 1));
+ if (BindInfo.SetCout > BindInfo.vkSets.size())
+ BindInfo.vkSets.resize(BindInfo.SetCout);
+ VERIFY_EXPR(BindInfo.vkSets[Set.SetIndex] == VK_NULL_HANDLE);
+ if (VarType == SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE)
+ BindInfo.vkSets[Set.SetIndex] = ResourceCache.GetDescriptorSet(Set.SetIndex).GetVkDescriptorSet();
+ else
+ {
+ VERIFY_EXPR(ResourceCache.GetDescriptorSet(Set.SetIndex).GetVkDescriptorSet() == VK_NULL_HANDLE);
+ BindInfo.vkSets[Set.SetIndex] = VkDynamicDescrSet;
+ }
+ VERIFY(BindInfo.vkSets[Set.SetIndex] != VK_NULL_HANDLE, "Descriptor set must not be null");
+ }
+ TotalDynamicDescriptors += Set.NumDynamicDescriptors;
+ }
+
+#ifdef DILIGENT_DEBUG
+ for (const auto& set : BindInfo.vkSets)
+ VERIFY(set != VK_NULL_HANDLE, "Descriptor set must not be null");
+#endif
+
+ BindInfo.DynamicOffsetCount = TotalDynamicDescriptors;
+ if (TotalDynamicDescriptors > BindInfo.DynamicOffsets.size())
+ BindInfo.DynamicOffsets.resize(TotalDynamicDescriptors);
+ BindInfo.BindPoint = BindPoint;
+ BindInfo.pResourceCache = &ResourceCache;
+#ifdef DILIGENT_DEBUG
+ BindInfo.pDbgPipelineLayout = this;
+#endif
+ BindInfo.DynamicBuffersPresent = ResourceCache.GetNumDynamicBuffers() > 0;
+
+ if (TotalDynamicDescriptors == 0)
+ {
+ // There are no dynamic descriptors, so we can bind descriptor sets right now
+ auto& CmdBuffer = pCtxVkImpl->GetCommandBuffer();
+ CmdBuffer.BindDescriptorSets(BindInfo.BindPoint,
+ m_LayoutMgr.GetVkPipelineLayout(),
+ 0, // First set
+ BindInfo.SetCout,
+ BindInfo.vkSets.data(), // BindInfo.vkSets is never empty
+ 0,
+ nullptr);
+ }
+
+ BindInfo.DynamicDescriptorsBound = false;
+ */
+}
+
+Uint32 PipelineResourceSignatureVkImpl::GetStaticVariableCount(SHADER_TYPE ShaderType) const
+{
+ const auto VarMngrInd = GetStaticVariableCountHelper(ShaderType, m_StaticVarIndex);
+ if (VarMngrInd < 0)
+ return 0;
+
+ auto& StaticVarMgr = m_StaticVarsMgrs[VarMngrInd];
+ return StaticVarMgr.GetVariableCount();
+}
+
+IShaderResourceVariable* PipelineResourceSignatureVkImpl::GetStaticVariableByName(SHADER_TYPE ShaderType, const Char* Name)
+{
+ const auto VarMngrInd = GetStaticVariableByNameHelper(ShaderType, Name, m_StaticVarIndex);
+ if (VarMngrInd < 0)
+ return nullptr;
+
+ auto& StaticVarMgr = m_StaticVarsMgrs[VarMngrInd];
+ return StaticVarMgr.GetVariable(Name);
+}
+
+IShaderResourceVariable* PipelineResourceSignatureVkImpl::GetStaticVariableByIndex(SHADER_TYPE ShaderType, Uint32 Index)
+{
+ const auto VarMngrInd = GetStaticVariableByIndexHelper(ShaderType, Index, m_StaticVarIndex);
+ if (VarMngrInd < 0)
+ return nullptr;
+
+ const auto& StaticVarMgr = m_StaticVarsMgrs[VarMngrInd];
+ return StaticVarMgr.GetVariable(Index);
+}
+
+void PipelineResourceSignatureVkImpl::InitResourceCache(ShaderResourceCacheVk& ResourceCache,
+ IMemoryAllocator& CacheMemAllocator,
+ const char* DbgPipelineName) const
+{
+ std::array<Uint32, 2> VarCount = {};
+ for (Uint32 r = 0; r < m_Desc.NumResources; ++r)
+ {
+ const auto& Res = GetResource(r);
+ const auto& Bind = GetBinding(r);
+ VarCount[Bind.DescSet] += Res.ArraySize;
+ }
+
+ // This call only initializes descriptor sets (ShaderResourceCacheVk::DescriptorSet) in the resource cache
+ // Resources are initialized by source layout when shader resource binding objects are created
+ ResourceCache.InitializeSets(CacheMemAllocator, static_cast<Uint32>(VarCount.size()), VarCount.data());
+
+ if (auto VkLayout = GetStaticVkDescriptorSetLayout())
+ {
+ const char* DescrSetName = "Static/Mutable Descriptor Set";
+#ifdef DILIGENT_DEVELOPMENT
+ std::string _DescrSetName(DbgPipelineName);
+ _DescrSetName.append(" - static/mutable set");
+ DescrSetName = _DescrSetName.c_str();
+#endif
+ DescriptorSetAllocation SetAllocation = GetDevice()->AllocateDescriptorSet(~Uint64{0}, VkLayout, DescrSetName);
+ ResourceCache.GetDescriptorSet(0).AssignDescriptorSetAllocation(std::move(SetAllocation));
+ }
+}
+
+SHADER_TYPE PipelineResourceSignatureVkImpl::GetShaderStageType(Uint32 StageIndex) const
+{
+ SHADER_TYPE Stages = m_ShaderStages;
+ for (Uint32 Index = 0; Stages != SHADER_TYPE_UNKNOWN; ++Index)
+ {
+ auto StageBit = static_cast<SHADER_TYPE>(1 << PlatformMisc::GetLSB(Uint32{Stages}));
+ Stages = Stages & ~StageBit;
+
+ if (Index == StageIndex)
+ return StageBit;
+ }
+
+ UNEXPECTED("index is out of range");
+ return SHADER_TYPE_UNKNOWN;
+}
+
+void PipelineResourceSignatureVkImpl::InitializeResourceMemoryInCache(ShaderResourceCacheVk& ResourceCache) const
+{
+ auto TotalResources = GetTotalResourceCount();
+ for (Uint32 r = 0; r < TotalResources; ++r)
+ {
+ const auto& Res = GetResource(r);
+ const auto& Bind = GetBinding(r);
+ ResourceCache.InitializeResources(Bind.DescSet, Bind.Binding, Res.ArraySize, GetVkDescriptorType(Res));
+ }
+}
+
+void PipelineResourceSignatureVkImpl::InitializeStaticSRBResources(ShaderResourceCacheVk& DstResourceCache) const
+{
+ const auto& SrcResourceCache = *m_pResourceCache;
+ (void)(SrcResourceCache);
+
+ for (Uint32 s = 0; s < GetNumShaderStages(); ++s)
+ {
+ // AZ TODO
+ }
+#ifdef DILIGENT_DEBUG
+ DstResourceCache.DbgVerifyDynamicBuffersCounter();
+#endif
+}
+
+} // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp
index 338f0f50..225e3f82 100644
--- a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp
@@ -76,7 +76,7 @@ bool StripReflection(const VulkanUtilities::VulkanLogicalDevice& LogicalDevice,
}
void InitPipelineShaderStages(const VulkanUtilities::VulkanLogicalDevice& LogicalDevice,
- ShaderResourceLayoutVk::TShaderStages& ShaderStages,
+ PipelineStateVkImpl::TShaderStages& ShaderStages,
std::vector<VulkanUtilities::ShaderModuleWrapper>& ShaderModules,
std::vector<VkPipelineShaderStageCreateInfo>& Stages)
{
@@ -131,7 +131,7 @@ void InitPipelineShaderStages(const VulkanUtilities::VulkanLogicalDevice&
void CreateComputePipeline(RenderDeviceVkImpl* pDeviceVk,
std::vector<VkPipelineShaderStageCreateInfo>& Stages,
- const PipelineLayout& Layout,
+ const PipelineLayoutVk& Layout,
const PipelineStateDesc& PSODesc,
VulkanUtilities::PipelineWrapper& Pipeline)
{
@@ -156,7 +156,7 @@ void CreateComputePipeline(RenderDeviceVkImpl* pDevice
void CreateGraphicsPipeline(RenderDeviceVkImpl* pDeviceVk,
std::vector<VkPipelineShaderStageCreateInfo>& Stages,
- const PipelineLayout& Layout,
+ const PipelineLayoutVk& Layout,
const PipelineStateDesc& PSODesc,
const GraphicsPipelineDesc& GraphicsPipeline,
VulkanUtilities::PipelineWrapper& Pipeline,
@@ -341,7 +341,7 @@ void CreateGraphicsPipeline(RenderDeviceVkImpl* pDevic
void CreateRayTracingPipeline(RenderDeviceVkImpl* pDeviceVk,
const std::vector<VkPipelineShaderStageCreateInfo>& vkStages,
const std::vector<VkRayTracingShaderGroupCreateInfoKHR>& vkShaderGroups,
- const PipelineLayout& Layout,
+ const PipelineLayoutVk& Layout,
const PipelineStateDesc& PSODesc,
const RayTracingPipelineDesc& RayTracingPipeline,
VulkanUtilities::PipelineWrapper& Pipeline)
@@ -375,7 +375,7 @@ void CreateRayTracingPipeline(RenderDeviceVkImpl*
std::vector<VkRayTracingShaderGroupCreateInfoKHR> BuildRTShaderGroupDescription(
const RayTracingPipelineStateCreateInfo& CreateInfo,
const std::unordered_map<HashMapStringKey, Uint32, HashMapStringKey::Hasher>& NameToGroupIndex,
- const ShaderResourceLayoutVk::TShaderStages& ShaderStages)
+ const PipelineStateVkImpl::TShaderStages& ShaderStages)
{
// Returns the shader module index in the PSO create info
auto GetShaderModuleIndex = [&ShaderStages](const IShader* pShader) {
@@ -505,6 +505,42 @@ std::vector<VkRayTracingShaderGroupCreateInfoKHR> BuildRTShaderGroupDescription(
} // namespace
+PipelineStateVkImpl::ShaderStageInfo::ShaderStageInfo(const ShaderVkImpl* pShader) :
+ Type{pShader->GetDesc().ShaderType},
+ Shaders{pShader},
+ SPIRVs{pShader->GetSPIRV()}
+{
+}
+
+void PipelineStateVkImpl::ShaderStageInfo::Append(const ShaderVkImpl* pShader)
+{
+ VERIFY_EXPR(pShader != nullptr);
+ VERIFY(std::find(Shaders.begin(), Shaders.end(), pShader) == Shaders.end(),
+ "Shader '", pShader->GetDesc().Name, "' already exists in the stage. Shaders must be deduplicated.");
+
+ const auto NewShaderType = pShader->GetDesc().ShaderType;
+ if (Type == SHADER_TYPE_UNKNOWN)
+ {
+ VERIFY_EXPR(Shaders.empty() && SPIRVs.empty());
+ Type = NewShaderType;
+ }
+ else
+ {
+ VERIFY(Type == NewShaderType, "The type (", GetShaderTypeLiteralName(NewShaderType),
+ ") of shader '", pShader->GetDesc().Name, "' being added to the stage is incosistent with the stage type (",
+ GetShaderTypeLiteralName(Type), ").");
+ }
+ Shaders.push_back(pShader);
+ SPIRVs.push_back(pShader->GetSPIRV());
+}
+
+size_t PipelineStateVkImpl::ShaderStageInfo::Count() const
+{
+ VERIFY_EXPR(Shaders.size() == SPIRVs.size());
+ return Shaders.size();
+}
+
+
RenderPassDesc PipelineStateVkImpl::GetImplicitRenderPassDesc(
Uint32 NumRenderTargets,
const TEXTURE_FORMAT RTVFormats[],
@@ -589,65 +625,102 @@ RenderPassDesc PipelineStateVkImpl::GetImplicitRenderPassDesc(
return RPDesc;
}
-void PipelineStateVkImpl::InitResourceLayouts(const PipelineStateCreateInfo& CreateInfo,
- TShaderStages& ShaderStages)
+void PipelineStateVkImpl::InitPipelineLayout(const PipelineStateCreateInfo& CreateInfo,
+ TShaderStages& ShaderStages)
{
- auto* const pDeviceVk = GetDevice();
- const auto& LogicalDevice = pDeviceVk->GetLogicalDevice();
-
- for (size_t s = 0; s < ShaderStages.size(); ++s)
- {
- auto& StageInfo = ShaderStages[s];
- const auto ShaderType = StageInfo.Type;
- const auto ShaderTypeInd = GetShaderTypePipelineIndex(ShaderType, m_Desc.PipelineType);
-
- m_ResourceLayoutIndex[ShaderTypeInd] = static_cast<Int8>(s);
+ std::array<IPipelineResourceSignature*, MAX_RESOURCE_SIGNATURES> Signatures;
+ RefCntAutoPtr<IPipelineResourceSignature> TempSignature;
- auto& StaticResLayout = m_ShaderResourceLayouts[GetNumShaderStages() + s];
- StaticResLayout.InitializeStaticResourceLayout(StageInfo.Shaders, GetRawAllocator(), m_Desc.ResourceLayout, m_StaticResCaches[s]);
+ Uint32 SignatureCount = CreateInfo.ResourceSignaturesCount;
- m_StaticVarsMgrs[s].Initialize(StaticResLayout, GetRawAllocator(), nullptr, 0);
+ for (Uint32 i = 0; i < SignatureCount; ++i)
+ {
+ Signatures[i] = CreateInfo.ppResourceSignatures[i];
}
- // Initialize shader resource layouts and assign bindings and descriptor sets in shader SPIRVs
- ShaderResourceLayoutVk::Initialize(pDeviceVk, ShaderStages, m_ShaderResourceLayouts, GetRawAllocator(),
- m_Desc.ResourceLayout, m_PipelineLayout,
- (CreateInfo.Flags & PSO_CREATE_FLAG_IGNORE_MISSING_VARIABLES) == 0,
- (CreateInfo.Flags & PSO_CREATE_FLAG_IGNORE_MISSING_IMMUTABLE_SAMPLERS) == 0);
- m_PipelineLayout.Finalize(LogicalDevice);
-
- if (m_Desc.SRBAllocationGranularity > 1)
+ if (SignatureCount == 0 || CreateInfo.ppResourceSignatures == nullptr)
{
- std::array<size_t, MAX_SHADERS_IN_PIPELINE> ShaderVariableDataSizes = {};
- for (Uint32 s = 0; s < GetNumShaderStages(); ++s)
- {
- const SHADER_RESOURCE_VARIABLE_TYPE AllowedVarTypes[] = {SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE, SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC};
+ using ResourceNameToIndex_t = std::unordered_map<HashMapStringKey, Uint32, HashMapStringKey::Hasher>;
- Uint32 UnusedNumVars = 0;
- ShaderVariableDataSizes[s] = ShaderVariableManagerVk::GetRequiredMemorySize(m_ShaderResourceLayouts[s], AllowedVarTypes, _countof(AllowedVarTypes), UnusedNumVars);
+ std::vector<PipelineResourceDesc> Resources;
+ ResourceNameToIndex_t UniqueNames;
+ const PipelineResourceLayoutDesc& LayoutDesc = CreateInfo.PSODesc.ResourceLayout;
+
+ for (auto& Stage : ShaderStages)
+ {
+ UniqueNames.clear();
+ for (auto* pShader : Stage.Shaders)
+ {
+ pShader->GetShaderResources().ProcessResources(
+ [&](const SPIRVShaderResourceAttribs& Res, Uint32) //
+ {
+ bool IsNewResource = UniqueNames.emplace(HashMapStringKey{Res.Name}, static_cast<Uint32>(Resources.size())).second;
+ if (IsNewResource)
+ {
+ Resources.emplace_back(Res.Name, Res.ArraySize, Res.GetShaderResourceType(Res.Type), Stage.Type, CreateInfo.PSODesc.ResourceLayout.DefaultVariableType);
+ }
+ });
+
+ for (Uint32 i = 0; i < LayoutDesc.NumVariables; ++i)
+ {
+ const auto& Var = LayoutDesc.Variables[i];
+ if (Var.ShaderStages & Stage.Type)
+ {
+ auto Iter = UniqueNames.find(HashMapStringKey{Var.Name});
+ if (Iter != UniqueNames.end() && Iter->second < Resources.size())
+ Resources[Iter->second].VarType = Var.Type;
+ }
+ }
+ }
}
- Uint32 NumSets = 0;
- auto DescriptorSetSizes = m_PipelineLayout.GetDescriptorSetSizes(NumSets);
- auto CacheMemorySize = ShaderResourceCacheVk::GetRequiredMemorySize(NumSets, DescriptorSetSizes.data());
+ PipelineResourceSignatureDesc ResSignDesc;
+ ResSignDesc.Resources = Resources.data();
+ ResSignDesc.NumResources = static_cast<Uint32>(Resources.size());
+ ResSignDesc.ImmutableSamplers = LayoutDesc.ImmutableSamplers;
+ ResSignDesc.NumImmutableSamplers = LayoutDesc.NumImmutableSamplers;
+ ResSignDesc.BindingIndex = 0;
- m_SRBMemAllocator.Initialize(m_Desc.SRBAllocationGranularity, GetNumShaderStages(), ShaderVariableDataSizes.data(), 1, &CacheMemorySize);
+ GetDevice()->CreatePipelineResourceSignature(ResSignDesc, &TempSignature);
+ if (TempSignature == nullptr)
+ LOG_ERROR_AND_THROW("");
+
+ Signatures[0] = TempSignature;
+ SignatureCount = 1;
}
- m_HasStaticResources = false;
- m_HasNonStaticResources = false;
- for (Uint32 s = 0; s < GetNumShaderStages(); ++s)
+ m_PipelineLayout = GetDevice()->GetPipelineLayoutCache().GetLayout(Signatures.data(), SignatureCount);
+
+ // verify that pipeline layout is compatible with shader resources and
+ // remap resource bindings
+ for (size_t s = 0; s < ShaderStages.size(); ++s)
{
- const auto& Layout = m_ShaderResourceLayouts[s];
- if (Layout.GetResourceCount(SHADER_RESOURCE_VARIABLE_TYPE_STATIC) != 0)
- m_HasStaticResources = true;
+ const auto& Shaders = ShaderStages[s].Shaders;
+ auto& SPIRVs = ShaderStages[s].SPIRVs;
+ const auto ShaderType = ShaderStages[s].Type;
- if (Layout.GetResourceCount(SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE) != 0 ||
- Layout.GetResourceCount(SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC) != 0)
- m_HasNonStaticResources = true;
- }
+ VERIFY_EXPR(Shaders.size() == SPIRVs.size());
- m_ShaderResourceLayoutHash = m_PipelineLayout.GetHash();
+ for (size_t i = 0; i < Shaders.size(); ++i)
+ {
+ auto* pShader = Shaders[i];
+ auto& SPIRV = SPIRVs[i];
+
+ pShader->GetShaderResources().ProcessResources(
+ [&](const SPIRVShaderResourceAttribs& Res, Uint32) //
+ {
+ PipelineLayoutVk::ResourceInfo Info;
+ if (!m_PipelineLayout->GetResourceInfo(Res.Name, ShaderType, Info))
+ {
+ LOG_ERROR_AND_THROW("Shader '", pShader->GetDesc().Name, "' contains resource with name '", Res.Name,
+ "' that is not presented in any pipeline resource signature that used to create pipeline state '",
+ m_Desc.Name, "'.");
+ }
+ SPIRV[Res.BindingDecorationOffset] = Info.BindingIndex;
+ SPIRV[Res.DescriptorSetDecorationOffset] = Info.DescrSetIndex;
+ });
+ }
+ }
}
template <typename PSOCreateInfoType>
@@ -656,19 +729,12 @@ PipelineStateVkImpl::TShaderStages PipelineStateVkImpl::InitInternalObjects(
std::vector<VkPipelineShaderStageCreateInfo>& vkShaderStages,
std::vector<VulkanUtilities::ShaderModuleWrapper>& ShaderModules)
{
- m_ResourceLayoutIndex.fill(-1);
-
TShaderStages ShaderStages;
ExtractShaders<ShaderVkImpl>(CreateInfo, ShaderStages);
- FixedLinearAllocator MemPool{GetRawAllocator()};
-
- const auto NumShaderStages = GetNumShaderStages();
- VERIFY_EXPR(NumShaderStages > 0 && NumShaderStages == ShaderStages.size());
+ InitPipelineLayout(CreateInfo, ShaderStages);
- MemPool.AddSpace<ShaderResourceCacheVk>(NumShaderStages);
- MemPool.AddSpace<ShaderResourceLayoutVk>(NumShaderStages * 2);
- MemPool.AddSpace<ShaderVariableManagerVk>(NumShaderStages);
+ FixedLinearAllocator MemPool{GetRawAllocator()};
ReserveSpaceForPipelineDesc(CreateInfo, MemPool);
@@ -676,38 +742,23 @@ PipelineStateVkImpl::TShaderStages PipelineStateVkImpl::InitInternalObjects(
const auto& LogicalDevice = GetDevice()->GetLogicalDevice();
- m_StaticResCaches = MemPool.ConstructArray<ShaderResourceCacheVk>(NumShaderStages, ShaderResourceCacheVk::DbgCacheContentType::StaticShaderResources);
-
- // The memory is now owned by PipelineStateVkImpl and will be freed by Destruct().
- auto* Ptr = MemPool.ReleaseOwnership();
- VERIFY_EXPR(Ptr == m_StaticResCaches);
- (void)Ptr;
-
- m_ShaderResourceLayouts = MemPool.ConstructArray<ShaderResourceLayoutVk>(NumShaderStages * 2, LogicalDevice);
-
- m_StaticVarsMgrs = MemPool.Allocate<ShaderVariableManagerVk>(NumShaderStages);
- for (Uint32 s = 0; s < NumShaderStages; ++s)
- new (m_StaticVarsMgrs + s) ShaderVariableManagerVk{*this, m_StaticResCaches[s]};
-
InitializePipelineDesc(CreateInfo, MemPool);
// It is important to construct all objects before initializing them because if an exception is thrown,
// destructors will be called for all objects
- InitResourceLayouts(CreateInfo, ShaderStages);
+ //InitResourceLayouts(CreateInfo, ShaderStages);
// Create shader modules and initialize shader stages
InitPipelineShaderStages(LogicalDevice, ShaderStages, ShaderModules, vkShaderStages);
+ m_pRawMem = MemPool.ReleaseOwnership();
+
return ShaderStages;
}
-
-PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* pRefCounters,
- RenderDeviceVkImpl* pDeviceVk,
- const GraphicsPipelineStateCreateInfo& CreateInfo) :
- TPipelineStateBase{pRefCounters, pDeviceVk, CreateInfo},
- m_SRBMemAllocator{GetRawAllocator()}
+PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* pRefCounters, RenderDeviceVkImpl* pDeviceVk, const GraphicsPipelineStateCreateInfo& CreateInfo) :
+ TPipelineStateBase{pRefCounters, pDeviceVk, CreateInfo}
{
try
{
@@ -716,7 +767,7 @@ PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters*
InitInternalObjects(CreateInfo, vkShaderStages, ShaderModules);
- CreateGraphicsPipeline(pDeviceVk, vkShaderStages, m_PipelineLayout, m_Desc, GetGraphicsPipelineDesc(), m_Pipeline, m_pRenderPass);
+ CreateGraphicsPipeline(pDeviceVk, vkShaderStages, *m_PipelineLayout, m_Desc, GetGraphicsPipelineDesc(), m_Pipeline, m_pRenderPass);
}
catch (...)
{
@@ -725,12 +776,8 @@ PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters*
}
}
-
-PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* pRefCounters,
- RenderDeviceVkImpl* pDeviceVk,
- const ComputePipelineStateCreateInfo& CreateInfo) :
- TPipelineStateBase{pRefCounters, pDeviceVk, CreateInfo},
- m_SRBMemAllocator{GetRawAllocator()}
+PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* pRefCounters, RenderDeviceVkImpl* pDeviceVk, const ComputePipelineStateCreateInfo& CreateInfo) :
+ TPipelineStateBase{pRefCounters, pDeviceVk, CreateInfo}
{
try
{
@@ -739,7 +786,7 @@ PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* p
InitInternalObjects(CreateInfo, vkShaderStages, ShaderModules);
- CreateComputePipeline(pDeviceVk, vkShaderStages, m_PipelineLayout, m_Desc, m_Pipeline);
+ CreateComputePipeline(pDeviceVk, vkShaderStages, *m_PipelineLayout, m_Desc, m_Pipeline);
}
catch (...)
{
@@ -748,11 +795,8 @@ PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* p
}
}
-PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* pRefCounters,
- RenderDeviceVkImpl* pDeviceVk,
- const RayTracingPipelineStateCreateInfo& CreateInfo) :
- TPipelineStateBase{pRefCounters, pDeviceVk, CreateInfo},
- m_SRBMemAllocator{GetRawAllocator()}
+PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* pRefCounters, RenderDeviceVkImpl* pDeviceVk, const RayTracingPipelineStateCreateInfo& CreateInfo) :
+ TPipelineStateBase{pRefCounters, pDeviceVk, CreateInfo}
{
try
{
@@ -765,7 +809,7 @@ PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters*
const auto vkShaderGroups = BuildRTShaderGroupDescription(CreateInfo, m_pRayTracingPipelineData->NameToGroupIndex, ShaderStages);
- CreateRayTracingPipeline(pDeviceVk, vkShaderStages, vkShaderGroups, m_PipelineLayout, m_Desc, GetRayTracingPipelineDesc(), m_Pipeline);
+ CreateRayTracingPipeline(pDeviceVk, vkShaderStages, vkShaderGroups, *m_PipelineLayout, m_Desc, GetRayTracingPipelineDesc(), m_Pipeline);
VERIFY(m_pRayTracingPipelineData->NameToGroupIndex.size() == vkShaderGroups.size(),
"The size of NameToGroupIndex map does not match the actual number of groups in the pipeline. This is a bug.");
@@ -791,9 +835,16 @@ void PipelineStateVkImpl::Destruct()
TPipelineStateBase::Destruct();
m_pDevice->SafeReleaseDeviceObject(std::move(m_Pipeline), m_Desc.CommandQueueMask);
- m_PipelineLayout.Release(m_pDevice, m_Desc.CommandQueueMask);
auto& RawAllocator = GetRawAllocator();
+ if (m_pRawMem)
+ {
+ RawAllocator.Free(m_pRawMem);
+ m_pRawMem = nullptr;
+ }
+
+ // AZ TODO:
+ /*
for (Uint32 s = 0; s < GetNumShaderStages(); ++s)
{
if (m_StaticVarsMgrs != nullptr)
@@ -802,253 +853,22 @@ void PipelineStateVkImpl::Destruct()
m_StaticVarsMgrs[s].~ShaderVariableManagerVk();
}
- if (m_ShaderResourceLayouts != nullptr)
- {
- m_ShaderResourceLayouts[s].~ShaderResourceLayoutVk();
- m_ShaderResourceLayouts[GetNumShaderStages() + s].~ShaderResourceLayoutVk();
- }
-
if (m_StaticResCaches != nullptr)
{
m_StaticResCaches[s].~ShaderResourceCacheVk();
}
}
-
- // All internal objects are allocted in contiguous chunks of memory.
- if (void* pRawMem = m_StaticResCaches)
- {
- RawAllocator.Free(pRawMem);
- }
-}
-
-void PipelineStateVkImpl::CreateShaderResourceBinding(IShaderResourceBinding** ppShaderResourceBinding, bool InitStaticResources)
-{
- auto& SRBAllocator = m_pDevice->GetSRBAllocator();
- auto pResBindingVk = NEW_RC_OBJ(SRBAllocator, "ShaderResourceBindingVkImpl instance", ShaderResourceBindingVkImpl)(this, false);
- if (InitStaticResources)
- pResBindingVk->InitializeStaticResources(nullptr);
- pResBindingVk->QueryInterface(IID_ShaderResourceBinding, reinterpret_cast<IObject**>(ppShaderResourceBinding));
+ */
}
bool PipelineStateVkImpl::IsCompatibleWith(const IPipelineState* pPSO) const
{
- VERIFY_EXPR(pPSO != nullptr);
-
- if (pPSO == this)
- return true;
-
- const PipelineStateVkImpl* pPSOVk = ValidatedCast<const PipelineStateVkImpl>(pPSO);
- if (m_ShaderResourceLayoutHash != pPSOVk->m_ShaderResourceLayoutHash)
- return false;
-
- auto IsSamePipelineLayout = m_PipelineLayout.IsSameAs(pPSOVk->m_PipelineLayout);
-#ifdef DILIGENT_DEBUG
- {
- bool IsCompatibleShaders = true;
- if (GetNumShaderStages() != pPSOVk->GetNumShaderStages())
- IsCompatibleShaders = false;
-
- if (IsCompatibleShaders)
- {
- for (Uint32 s = 0; s < GetNumShaderStages(); ++s)
- {
- if (GetShaderStageType(s) != pPSOVk->GetShaderStageType(s))
- {
- IsCompatibleShaders = false;
- break;
- }
-
- const auto& Res0 = GetShaderResLayout(s);
- const auto& Res1 = pPSOVk->GetShaderResLayout(s);
- if (!Res0.IsCompatibleWith(Res1))
- {
- IsCompatibleShaders = false;
- break;
- }
- }
- }
-
- if (IsCompatibleShaders)
- VERIFY(IsSamePipelineLayout, "Compatible shaders must have same pipeline layouts");
- }
-#endif
-
- return IsSamePipelineLayout;
-}
-
-
-void PipelineStateVkImpl::CommitAndTransitionShaderResources(IShaderResourceBinding* pShaderResourceBinding,
- DeviceContextVkImpl* pCtxVkImpl,
- bool CommitResources,
- RESOURCE_STATE_TRANSITION_MODE StateTransitionMode,
- PipelineLayout::DescriptorSetBindInfo* pDescrSetBindInfo) const
-{
- VERIFY(CommitResources || StateTransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION, "Resources should be transitioned or committed or both");
-
- if (!m_HasStaticResources && !m_HasNonStaticResources)
- return;
-
-#ifdef DILIGENT_DEVELOPMENT
- if (pShaderResourceBinding == nullptr)
- {
- LOG_ERROR_MESSAGE("Pipeline state '", m_Desc.Name, "' requires shader resource binding object to ",
- (CommitResources ? "commit" : "transition"), " resources, but none is provided.");
- return;
- }
-#endif
-
- auto* pResBindingVkImpl = ValidatedCast<ShaderResourceBindingVkImpl>(pShaderResourceBinding);
- auto& ResourceCache = pResBindingVkImpl->GetResourceCache();
-
-#ifdef DILIGENT_DEVELOPMENT
- {
- auto* pRefPSO = pResBindingVkImpl->GetPipelineState();
- if (IsIncompatibleWith(pRefPSO))
- {
- LOG_ERROR_MESSAGE("Shader resource binding is incompatible with the pipeline state '", m_Desc.Name, "'. Operation will be ignored.");
- return;
- }
- }
-
- if (CommitResources)
- {
- if (m_HasStaticResources && !pResBindingVkImpl->StaticResourcesInitialized())
- {
- LOG_ERROR_MESSAGE("Static resources have not been initialized in the shader resource binding object being committed for PSO '", m_Desc.Name, "'. Please call IShaderResourceBinding::InitializeStaticResources().");
- }
-
- for (Uint32 s = 0; s < GetNumShaderStages(); ++s)
- {
- m_ShaderResourceLayouts[s].dvpVerifyBindings(ResourceCache);
- }
- }
-#endif
-#ifdef DILIGENT_DEBUG
- ResourceCache.DbgVerifyDynamicBuffersCounter();
-#endif
-
- if (StateTransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION)
- {
- ResourceCache.TransitionResources<false>(pCtxVkImpl);
- }
-#ifdef DILIGENT_DEVELOPMENT
- else if (StateTransitionMode == RESOURCE_STATE_TRANSITION_MODE_VERIFY)
- {
- ResourceCache.TransitionResources<true>(pCtxVkImpl);
- }
-#endif
-
- if (CommitResources)
- {
- VkDescriptorSet DynamicDescrSet = VK_NULL_HANDLE;
- auto DynamicDescriptorSetVkLayout = m_PipelineLayout.GetDynamicDescriptorSetVkLayout();
- if (DynamicDescriptorSetVkLayout != VK_NULL_HANDLE)
- {
- const char* DynamicDescrSetName = "Dynamic Descriptor Set";
-#ifdef DILIGENT_DEVELOPMENT
- std::string _DynamicDescrSetName(m_Desc.Name);
- _DynamicDescrSetName.append(" - dynamic set");
- DynamicDescrSetName = _DynamicDescrSetName.c_str();
-#endif
- // Allocate vulkan descriptor set for dynamic resources
- DynamicDescrSet = pCtxVkImpl->AllocateDynamicDescriptorSet(DynamicDescriptorSetVkLayout, DynamicDescrSetName);
- // Commit all dynamic resource descriptors
- for (Uint32 s = 0; s < GetNumShaderStages(); ++s)
- {
- const auto& Layout = m_ShaderResourceLayouts[s];
- if (Layout.GetResourceCount(SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC) != 0)
- Layout.CommitDynamicResources(ResourceCache, DynamicDescrSet);
- }
- }
-
-
- VkPipelineBindPoint BindPoint = VK_PIPELINE_BIND_POINT_MAX_ENUM;
- switch (m_Desc.PipelineType)
- {
- // clang-format off
- case PIPELINE_TYPE_GRAPHICS:
- case PIPELINE_TYPE_MESH: BindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; break;
- case PIPELINE_TYPE_COMPUTE: BindPoint = VK_PIPELINE_BIND_POINT_COMPUTE; break;
- case PIPELINE_TYPE_RAY_TRACING: BindPoint = VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR; break;
- // clang-format on
- default: UNEXPECTED("Unknown pipeline type");
- }
-
- VERIFY_EXPR(pDescrSetBindInfo != nullptr);
- // Prepare descriptor sets, and also bind them if there are no dynamic descriptors
- m_PipelineLayout.PrepareDescriptorSets(pCtxVkImpl, BindPoint, ResourceCache, *pDescrSetBindInfo, DynamicDescrSet);
- // Dynamic descriptor sets are not released individually. Instead, all dynamic descriptor pools
- // are released at the end of the frame by DeviceContextVkImpl::FinishFrame().
- }
+ return m_PipelineLayout == ValidatedCast<const PipelineStateVkImpl>(pPSO)->m_PipelineLayout;
}
void PipelineStateVkImpl::BindStaticResources(Uint32 ShaderFlags, IResourceMapping* pResourceMapping, Uint32 Flags)
{
- for (Uint32 s = 0; s < GetNumShaderStages(); ++s)
- {
- auto ShaderType = GetStaticShaderResLayout(s).GetShaderType();
- if ((ShaderType & ShaderFlags) != 0)
- {
- auto& StaticVarMgr = GetStaticVarMgr(s);
- StaticVarMgr.BindResources(pResourceMapping, Flags);
- }
- }
-}
-
-Uint32 PipelineStateVkImpl::GetStaticVariableCount(SHADER_TYPE ShaderType) const
-{
- const auto LayoutInd = GetStaticVariableCountHelper(ShaderType, m_ResourceLayoutIndex);
- if (LayoutInd < 0)
- return 0;
-
- auto& StaticVarMgr = GetStaticVarMgr(LayoutInd);
- return StaticVarMgr.GetVariableCount();
-}
-
-IShaderResourceVariable* PipelineStateVkImpl::GetStaticVariableByName(SHADER_TYPE ShaderType, const Char* Name)
-{
- const auto LayoutInd = GetStaticVariableByNameHelper(ShaderType, Name, m_ResourceLayoutIndex);
- if (LayoutInd < 0)
- return nullptr;
-
- auto& StaticVarMgr = GetStaticVarMgr(LayoutInd);
- return StaticVarMgr.GetVariable(Name);
-}
-
-IShaderResourceVariable* PipelineStateVkImpl::GetStaticVariableByIndex(SHADER_TYPE ShaderType, Uint32 Index)
-{
- const auto LayoutInd = GetStaticVariableByIndexHelper(ShaderType, Index, m_ResourceLayoutIndex);
- if (LayoutInd < 0)
- return nullptr;
-
- const auto& StaticVarMgr = GetStaticVarMgr(LayoutInd);
- return StaticVarMgr.GetVariable(Index);
-}
-
-
-void PipelineStateVkImpl::InitializeStaticSRBResources(ShaderResourceCacheVk& ResourceCache) const
-{
- for (Uint32 s = 0; s < GetNumShaderStages(); ++s)
- {
- const auto& StaticResLayout = GetStaticShaderResLayout(s);
- const auto& StaticResCache = GetStaticResCache(s);
-
-#ifdef DILIGENT_DEVELOPMENT
- if (!StaticResLayout.dvpVerifyBindings(StaticResCache))
- {
- LOG_ERROR_MESSAGE("Static resources in SRB of PSO '", GetDesc().Name,
- "' will not be successfully initialized because not all static resource bindings in shader '",
- GetShaderTypeLiteralName(GetShaderStageType(s)),
- "' are valid. Please make sure you bind all static resources to PSO before calling InitializeStaticResources() "
- "directly or indirectly by passing InitStaticResources=true to CreateShaderResourceBinding() method.");
- }
-#endif
- const auto& ShaderResourceLayouts = GetShaderResLayout(s);
- ShaderResourceLayouts.InitializeStaticResources(StaticResLayout, StaticResCache, ResourceCache);
- }
-#ifdef DILIGENT_DEBUG
- ResourceCache.DbgVerifyDynamicBuffersCounter();
-#endif
+ //m_StaticVarsMgr.BindResources(ShaderFlags, pResourceMapping, Flags);
}
} // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp
index 90c1a88e..cc1a444c 100644
--- a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp
@@ -42,6 +42,7 @@
#include "BottomLevelASVkImpl.hpp"
#include "TopLevelASVkImpl.hpp"
#include "ShaderBindingTableVkImpl.hpp"
+#include "PipelineResourceSignatureVkImpl.hpp"
#include "EngineMemory.h"
namespace Diligent
@@ -82,6 +83,7 @@ RenderDeviceVkImpl::RenderDeviceVkImpl(IReferenceCounters*
sizeof(BottomLevelASVkImpl),
sizeof(TopLevelASVkImpl),
sizeof(ShaderBindingTableVkImpl),
+ sizeof(PipelineResourceSignatureVkImpl),
}
},
m_VulkanInstance {Instance },
@@ -89,6 +91,7 @@ RenderDeviceVkImpl::RenderDeviceVkImpl(IReferenceCounters*
m_LogicalVkDevice {std::move(LogicalDevice) },
m_EngineAttribs {EngineCI },
m_FramebufferCache {*this },
+ m_PipelineLayoutCache {*this },
m_ImplicitRenderPassCache{*this },
m_DescriptorSetAllocator
{
@@ -168,11 +171,12 @@ RenderDeviceVkImpl::RenderDeviceVkImpl(IReferenceCounters*
m_PhysicalDevice->GetExtProperties().MeshShader.maxDrawMeshTasksCount,
m_PhysicalDevice->GetExtProperties().RayTracingPipeline.maxRayRecursionDepth,
m_PhysicalDevice->GetExtProperties().RayTracingPipeline.maxRayDispatchInvocationCount
- }
+ },
+ m_PipelineLayoutAllocator{GetRawAllocator(), sizeof(PipelineLayoutVk), 128}
// clang-format on
{
static_assert(sizeof(VulkanDescriptorPoolSize) == sizeof(Uint32) * 11, "Please add new descriptors to m_DescriptorSetAllocator and m_DynamicDescriptorPool constructors");
- static_assert(sizeof(DeviceObjectSizes) == sizeof(size_t) * 15, "Please add new objects to DeviceObjectSizes constructor");
+ static_assert(sizeof(DeviceObjectSizes) == sizeof(size_t) * 16, "Please add new objects to DeviceObjectSizes constructor");
// set device properties
{
@@ -827,4 +831,22 @@ void RenderDeviceVkImpl::CreateSBT(const ShaderBindingTableDesc& Desc,
});
}
+void RenderDeviceVkImpl::CreatePipelineResourceSignature(const PipelineResourceSignatureDesc& Desc,
+ IPipelineResourceSignature** ppSignature)
+{
+ CreateDeviceObject("PipelineResourceSignature", Desc, ppSignature,
+ [&]() //
+ {
+ PipelineResourceSignatureVkImpl* pPRSVk(NEW_RC_OBJ(m_PipeResSignAllocator, "PipelineResourceSignatureVkImpl instance", PipelineResourceSignatureVkImpl)(this, Desc));
+ pPRSVk->QueryInterface(IID_PipelineResourceSignature, reinterpret_cast<IObject**>(ppSignature));
+ OnCreateDeviceObject(pPRSVk);
+ });
+}
+
+void RenderDeviceVkImpl::CreatePipelineLayout(IPipelineResourceSignature** ppSignatures, Uint32 SignatureCount, PipelineLayoutVk** ppPipelineLayout)
+{
+ PipelineLayoutVk* pPLVk(NEW_RC_OBJ(m_PipelineLayoutAllocator, "PipelineLayoutVk instance", PipelineLayoutVk)(this, ppSignatures, SignatureCount));
+ *ppPipelineLayout = pPLVk;
+}
+
} // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp
index 289ca960..3672853f 100644
--- a/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp
@@ -35,14 +35,14 @@
namespace Diligent
{
-ShaderResourceBindingVkImpl::ShaderResourceBindingVkImpl(IReferenceCounters* pRefCounters,
- PipelineStateVkImpl* pPSO,
- bool IsPSOInternal) :
+ShaderResourceBindingVkImpl::ShaderResourceBindingVkImpl(IReferenceCounters* pRefCounters,
+ PipelineResourceSignatureVkImpl* pPRS,
+ bool IsPSOInternal) :
// clang-format off
TBase
{
pRefCounters,
- pPSO,
+ pPRS,
IsPSOInternal
},
m_ShaderResourceCache{ShaderResourceCacheVk::DbgCacheContentType::SRBResources}
@@ -50,9 +50,9 @@ ShaderResourceBindingVkImpl::ShaderResourceBindingVkImpl(IReferenceCounters* pR
{
try
{
- m_ResourceLayoutIndex.fill(-1);
+ m_ShaderVarIndex.fill(-1);
- m_NumShaders = static_cast<decltype(m_NumShaders)>(pPSO->GetNumShaderStages());
+ m_NumShaders = static_cast<decltype(m_NumShaders)>(pPRS->GetNumShaderStages());
FixedLinearAllocator MemPool{GetRawAllocator()};
MemPool.AddSpace<ShaderVariableManagerVk>(m_NumShaders);
@@ -67,29 +67,28 @@ ShaderResourceBindingVkImpl::ShaderResourceBindingVkImpl(IReferenceCounters* pR
// It is important to construct all objects before initializing them because if an exception is thrown,
// destructors will be called for all objects
- auto* pRenderDeviceVkImpl = pPSO->GetDevice();
// This will only allocate memory and initialize descriptor sets in the resource cache
// Resources will be initialized by InitializeResourceMemoryInCache()
- auto& ResourceCacheDataAllocator = pPSO->GetSRBMemoryAllocator().GetResourceCacheDataAllocator(0);
- pPSO->GetPipelineLayout().InitResourceCache(pRenderDeviceVkImpl, m_ShaderResourceCache, ResourceCacheDataAllocator, pPSO->GetDesc().Name);
+ auto& SRBMemAllocator = pPRS->GetSRBMemoryAllocator();
+ auto& ResourceCacheDataAllocator = SRBMemAllocator.GetResourceCacheDataAllocator(0);
+ pPRS->InitResourceCache(m_ShaderResourceCache, ResourceCacheDataAllocator, pPRS->GetDesc().Name);
for (Uint32 s = 0; s < m_NumShaders; ++s)
{
- auto ShaderInd = GetShaderTypePipelineIndex(pPSO->GetShaderStageType(s), pPSO->GetDesc().PipelineType);
+ auto ShaderInd = GetShaderTypePipelineIndex(pPRS->GetShaderStageType(s), pPRS->GetPipelineType());
- m_ResourceLayoutIndex[ShaderInd] = static_cast<Int8>(s);
+ m_ShaderVarIndex[ShaderInd] = static_cast<Int8>(s);
- auto& VarDataAllocator = pPSO->GetSRBMemoryAllocator().GetShaderVariableDataAllocator(s);
+ auto& VarDataAllocator = SRBMemAllocator.GetShaderVariableDataAllocator(s);
- const auto& SrcLayout = pPSO->GetShaderResLayout(s);
// Use source layout to initialize resource memory in the cache
- SrcLayout.InitializeResourceMemoryInCache(m_ShaderResourceCache);
+ pPRS->InitializeResourceMemoryInCache(m_ShaderResourceCache);
// Create shader variable manager in place
// Initialize vars manager to reference mutable and dynamic variables
// Note that the cache has space for all variable types
const SHADER_RESOURCE_VARIABLE_TYPE VarTypes[] = {SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE, SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC};
- m_pShaderVarMgrs[s].Initialize(SrcLayout, VarDataAllocator, VarTypes, _countof(VarTypes));
+ m_pShaderVarMgrs[s].Initialize(*pPRS, VarDataAllocator, VarTypes, _countof(VarTypes));
}
#ifdef DILIGENT_DEBUG
m_ShaderResourceCache.DbgVerifyResourceInitialization();
@@ -111,7 +110,7 @@ void ShaderResourceBindingVkImpl::Destruct()
{
if (m_pShaderVarMgrs != nullptr)
{
- auto& SRBMemAllocator = m_pPSO->GetSRBMemoryAllocator();
+ auto& SRBMemAllocator = GetSignature()->GetSRBMemoryAllocator();
for (Uint32 s = 0; s < m_NumShaders; ++s)
{
auto& VarDataAllocator = SRBMemAllocator.GetShaderVariableDataAllocator(s);
@@ -125,50 +124,37 @@ void ShaderResourceBindingVkImpl::Destruct()
void ShaderResourceBindingVkImpl::BindResources(Uint32 ShaderFlags, IResourceMapping* pResMapping, Uint32 Flags)
{
- const auto PipelineType = m_pPSO->GetDesc().PipelineType;
- for (Int32 ShaderInd = 0; ShaderInd < static_cast<Int32>(m_ResourceLayoutIndex.size()); ++ShaderInd)
- {
- auto ResLayoutInd = m_ResourceLayoutIndex[ShaderInd];
- if (ResLayoutInd >= 0)
- {
- // ShaderInd is the shader type pipeline index here
- const auto ShaderType = GetShaderTypeFromPipelineIndex(ShaderInd, PipelineType);
- if (ShaderFlags & ShaderType)
- {
- m_pShaderVarMgrs[ResLayoutInd].BindResources(pResMapping, Flags);
- }
- }
- }
+ // AZ TODO
}
-IShaderResourceVariable* ShaderResourceBindingVkImpl::GetVariableByName(SHADER_TYPE ShaderType, const char* Name)
+Uint32 ShaderResourceBindingVkImpl::GetVariableCount(SHADER_TYPE ShaderType) const
{
- auto ResLayoutInd = GetVariableByNameHelper(ShaderType, Name, m_ResourceLayoutIndex);
- if (ResLayoutInd < 0)
- return nullptr;
+ const auto VarMngrInd = GetVariableCountHelper(ShaderType, m_ShaderVarIndex);
+ if (VarMngrInd < 0)
+ return 0;
- VERIFY_EXPR(static_cast<Uint32>(ResLayoutInd) < Uint32{m_NumShaders});
- return m_pShaderVarMgrs[ResLayoutInd].GetVariable(Name);
+ auto& ShaderVarMgr = m_pShaderVarMgrs[VarMngrInd];
+ return ShaderVarMgr.GetVariableCount();
}
-Uint32 ShaderResourceBindingVkImpl::GetVariableCount(SHADER_TYPE ShaderType) const
+IShaderResourceVariable* ShaderResourceBindingVkImpl::GetVariableByName(SHADER_TYPE ShaderType, const Char* Name)
{
- auto ResLayoutInd = GetVariableCountHelper(ShaderType, m_ResourceLayoutIndex);
- if (ResLayoutInd < 0)
- return 0;
+ const auto VarMngrInd = GetVariableByNameHelper(ShaderType, Name, m_ShaderVarIndex);
+ if (VarMngrInd < 0)
+ return nullptr;
- VERIFY_EXPR(static_cast<Uint32>(ResLayoutInd) < Uint32{m_NumShaders});
- return m_pShaderVarMgrs[ResLayoutInd].GetVariableCount();
+ auto& ShaderVarMgr = m_pShaderVarMgrs[VarMngrInd];
+ return ShaderVarMgr.GetVariable(Name);
}
IShaderResourceVariable* ShaderResourceBindingVkImpl::GetVariableByIndex(SHADER_TYPE ShaderType, Uint32 Index)
{
- auto ResLayoutInd = GetVariableByIndexHelper(ShaderType, Index, m_ResourceLayoutIndex);
- if (ResLayoutInd < 0)
+ const auto VarMngrInd = GetVariableByIndexHelper(ShaderType, Index, m_ShaderVarIndex);
+ if (VarMngrInd < 0)
return nullptr;
- VERIFY_EXPR(static_cast<Uint32>(ResLayoutInd) < Uint32{m_NumShaders});
- return m_pShaderVarMgrs[ResLayoutInd].GetVariable(Index);
+ const auto& ShaderVarMgr = m_pShaderVarMgrs[VarMngrInd];
+ return ShaderVarMgr.GetVariable(Index);
}
void ShaderResourceBindingVkImpl::InitializeStaticResources(const IPipelineState* pPipelineState)
@@ -181,17 +167,28 @@ void ShaderResourceBindingVkImpl::InitializeStaticResources(const IPipelineState
if (pPipelineState == nullptr)
{
- pPipelineState = GetPipelineState();
+ InitializeStaticResourcesWithSignature(nullptr);
}
else
{
- DEV_CHECK_ERR(pPipelineState->IsCompatibleWith(GetPipelineState()), "The pipeline state '", pPipelineState->GetDesc().Name,
- "' is not compatible with the pipeline state '", m_pPSO->GetDesc().Name,
- "' this SRB was created from and cannot be used to initialize static resources.");
+ auto* pSign = pPipelineState->GetResourceSignature(GetBindingIndex());
+ if (pSign == nullptr)
+ {
+ LOG_ERROR_MESSAGE("Shader resource binding is not compatible with pipeline state.");
+ return;
+ }
+
+ InitializeStaticResourcesWithSignature(pSign);
}
+}
+
+void ShaderResourceBindingVkImpl::InitializeStaticResourcesWithSignature(const IPipelineResourceSignature* pResourceSignature)
+{
+ if (pResourceSignature == nullptr)
+ pResourceSignature = GetPipelineResourceSignature();
- auto* pPSOVK = ValidatedCast<const PipelineStateVkImpl>(pPipelineState);
- pPSOVK->InitializeStaticSRBResources(m_ShaderResourceCache);
+ auto* pPRSVk = ValidatedCast<const PipelineResourceSignatureVkImpl>(pResourceSignature);
+ pPRSVk->InitializeStaticSRBResources(m_ShaderResourceCache);
m_bStaticResourcesInitialized = true;
}
diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp
index f7da5b14..820d1e9a 100644
--- a/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp
@@ -39,7 +39,7 @@
namespace Diligent
{
-size_t ShaderResourceCacheVk::GetRequiredMemorySize(Uint32 NumSets, Uint32 SetSizes[])
+size_t ShaderResourceCacheVk::GetRequiredMemorySize(Uint32 NumSets, const Uint32* SetSizes)
{
Uint32 TotalResources = 0;
for (Uint32 t = 0; t < NumSets; ++t)
@@ -48,7 +48,7 @@ size_t ShaderResourceCacheVk::GetRequiredMemorySize(Uint32 NumSets, Uint32 SetSi
return MemorySize;
}
-void ShaderResourceCacheVk::InitializeSets(IMemoryAllocator& MemAllocator, Uint32 NumSets, Uint32 SetSizes[])
+void ShaderResourceCacheVk::InitializeSets(IMemoryAllocator& MemAllocator, Uint32 NumSets, const Uint32* SetSizes)
{
// Memory layout:
//
@@ -89,7 +89,7 @@ void ShaderResourceCacheVk::InitializeSets(IMemoryAllocator& MemAllocator, Uint3
}
}
-void ShaderResourceCacheVk::InitializeResources(Uint32 Set, Uint32 Offset, Uint32 ArraySize, SPIRVShaderResourceAttribs::ResourceType Type)
+void ShaderResourceCacheVk::InitializeResources(Uint32 Set, Uint32 Offset, Uint32 ArraySize, VkDescriptorType Type)
{
auto& DescrSet = GetDescriptorSet(Set);
for (Uint32 res = 0; res < ArraySize; ++res)
@@ -117,15 +117,16 @@ void ShaderResourceCacheVk::DbgVerifyDynamicBuffersCounter() const
for (Uint32 res = 0; res < m_TotalResources; ++res)
{
const auto& Res = pResources[res];
- if (Res.Type == SPIRVShaderResourceAttribs::ResourceType::UniformBuffer)
+ if (Res.Type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ||
+ Res.Type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC)
{
if (Res.pObject && Res.pObject.RawPtr<const BufferVkImpl>()->GetDesc().Usage == USAGE_DYNAMIC)
++NumDynamicBuffers;
}
- else if (Res.Type == SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer ||
- Res.Type == SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer ||
- Res.Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer ||
- Res.Type == SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer)
+ else if (Res.Type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ||
+ Res.Type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC ||
+ Res.Type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER ||
+ Res.Type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)
{
if (Res.pObject && Res.pObject.RawPtr<const BufferViewVkImpl>()->GetBuffer<const BufferVkImpl>()->GetDesc().Usage == USAGE_DYNAMIC)
++NumDynamicBuffers;
@@ -156,10 +157,10 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl)
for (Uint32 res = 0; res < m_TotalResources; ++res)
{
auto& Res = pResources[res];
- static_assert(Uint32{SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes} == 12, "Please handle the new resource type below");
switch (Res.Type)
{
- case SPIRVShaderResourceAttribs::ResourceType::UniformBuffer:
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
{
auto* pBufferVk = Res.pObject.RawPtr<BufferVkImpl>();
if (pBufferVk != nullptr && pBufferVk->IsInKnownState())
@@ -191,18 +192,17 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl)
}
break;
- case SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer:
- case SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer:
- case SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer:
- case SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer:
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
+ case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
+ case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
{
auto* pBuffViewVk = Res.pObject.RawPtr<BufferViewVkImpl>();
auto* pBufferVk = pBuffViewVk != nullptr ? ValidatedCast<BufferVkImpl>(pBuffViewVk->GetBuffer()) : nullptr;
if (pBufferVk != nullptr && pBufferVk->IsInKnownState())
{
const RESOURCE_STATE RequiredState =
- (Res.Type == SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer ||
- Res.Type == SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer) ?
+ Res.Type != VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER ? // AZ TODO: read-only buffer ???
RESOURCE_STATE_UNORDERED_ACCESS :
RESOURCE_STATE_SHADER_RESOURCE;
#ifdef DILIGENT_DEBUG
@@ -239,9 +239,9 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl)
}
break;
- case SPIRVShaderResourceAttribs::ResourceType::SeparateImage:
- case SPIRVShaderResourceAttribs::ResourceType::SampledImage:
- case SPIRVShaderResourceAttribs::ResourceType::StorageImage:
+ case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
+ case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
+ case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
{
auto* pTextureViewVk = Res.pObject.RawPtr<TextureViewVkImpl>();
auto* pTextureVk = pTextureViewVk != nullptr ? ValidatedCast<TextureVkImpl>(pTextureViewVk->GetTexture()) : nullptr;
@@ -253,7 +253,7 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl)
// VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
// or VK_IMAGE_LAYOUT_GENERAL layout in order to access its data in a shader (13.1.3, 13.1.4).
RESOURCE_STATE RequiredState;
- if (Res.Type == SPIRVShaderResourceAttribs::ResourceType::StorageImage)
+ if (Res.Type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
{
RequiredState = RESOURCE_STATE_UNORDERED_ACCESS;
VERIFY_EXPR(ResourceStateToVkImageLayout(RequiredState) == VK_IMAGE_LAYOUT_GENERAL);
@@ -302,19 +302,13 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl)
}
break;
- case SPIRVShaderResourceAttribs::ResourceType::AtomicCounter:
- {
- // Nothing to do with atomic counters
- }
- break;
-
- case SPIRVShaderResourceAttribs::ResourceType::SeparateSampler:
+ case VK_DESCRIPTOR_TYPE_SAMPLER:
{
// Nothing to do with samplers
}
break;
- case SPIRVShaderResourceAttribs::ResourceType::InputAttachment:
+ case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
{
// Nothing to do with input attachments - they are transitioned by the render pass.
// There is nothing we can validate here - a texture may be in different state at
@@ -322,7 +316,7 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl)
}
break;
- case SPIRVShaderResourceAttribs::ResourceType::AccelerationStructure:
+ case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:
{
auto* pTLASVk = Res.pObject.RawPtr<TopLevelASVkImpl>();
if (pTLASVk != nullptr && pTLASVk->IsInKnownState())
@@ -367,7 +361,11 @@ template void ShaderResourceCacheVk::TransitionResources<true>(DeviceContextVkIm
VkDescriptorBufferInfo ShaderResourceCacheVk::Resource::GetUniformBufferDescriptorWriteInfo() const
{
- VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::UniformBuffer, "Uniform buffer resource is expected");
+ // clang-format off
+ VERIFY(Type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ||
+ Type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
+ "Uniform buffer resource is expected");
+ // clang-format on
DEV_CHECK_ERR(pObject != nullptr, "Unable to get uniform buffer write info: cached object is null");
auto* pBuffVk = pObject.RawPtr<const BufferVkImpl>();
@@ -387,8 +385,10 @@ VkDescriptorBufferInfo ShaderResourceCacheVk::Resource::GetUniformBufferDescript
VkDescriptorBufferInfo ShaderResourceCacheVk::Resource::GetStorageBufferDescriptorWriteInfo() const
{
// clang-format off
- VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer ||
- Type == SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer,
+ VERIFY(Type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER ||
+ Type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER ||
+ Type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ||
+ Type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,
"Storage buffer resource is expected");
// clang-format on
DEV_CHECK_ERR(pObject != nullptr, "Unable to get storage buffer write info: cached object is null");
@@ -399,7 +399,7 @@ VkDescriptorBufferInfo ShaderResourceCacheVk::Resource::GetStorageBufferDescript
// VK_DESCRIPTOR_TYPE_STORAGE_BUFFER or VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC descriptor type
// require buffer to be created with VK_BUFFER_USAGE_STORAGE_BUFFER_BIT (13.2.4)
- if (Type == SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer)
+ /*if (Type == SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer) // AZ TODO
{
// HLSL buffer SRVs are mapped to read-only storge buffers in SPIR-V
VERIFY(ViewDesc.ViewType == BUFFER_VIEW_SHADER_RESOURCE, "Attempting to bind buffer view '", ViewDesc.Name,
@@ -407,7 +407,7 @@ VkDescriptorBufferInfo ShaderResourceCacheVk::Resource::GetStorageBufferDescript
GetBufferViewTypeLiteralName(ViewDesc.ViewType));
VERIFY((pBuffVk->GetDesc().BindFlags & BIND_SHADER_RESOURCE) != 0, "Buffer '", pBuffVk->GetDesc().Name, "' being set as read-only storage buffer was not created with BIND_SHADER_RESOURCE flag");
}
- else if (Type == SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer)
+ else if (Type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER || Type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)
{
VERIFY(ViewDesc.ViewType == BUFFER_VIEW_UNORDERED_ACCESS, "Attempting to bind buffer view '", ViewDesc.Name,
"' as writable storage buffer. Expected view type is BUFFER_VIEW_UNORDERED_ACCESS. Actual type: ",
@@ -417,7 +417,7 @@ VkDescriptorBufferInfo ShaderResourceCacheVk::Resource::GetStorageBufferDescript
else
{
UNEXPECTED("Unexpected resource type");
- }
+ }*/
VkDescriptorBufferInfo DescrBuffInfo;
DescrBuffInfo.buffer = pBuffVk->GetVkBuffer();
@@ -431,23 +431,23 @@ VkDescriptorBufferInfo ShaderResourceCacheVk::Resource::GetStorageBufferDescript
VkDescriptorImageInfo ShaderResourceCacheVk::Resource::GetImageDescriptorWriteInfo(bool IsImmutableSampler) const
{
// clang-format off
- VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::StorageImage ||
- Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage ||
- Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage,
+ VERIFY(Type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE ||
+ Type == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE ||
+ Type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
"Storage image, separate image or sampled image resource is expected");
// clang-format on
DEV_CHECK_ERR(pObject != nullptr, "Unable to get image descriptor write info: cached object is null");
- bool IsStorageImage = Type == SPIRVShaderResourceAttribs::ResourceType::StorageImage;
+ bool IsStorageImage = Type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
auto* pTexViewVk = pObject.RawPtr<const TextureViewVkImpl>();
VERIFY_EXPR(pTexViewVk->GetDesc().ViewType == (IsStorageImage ? TEXTURE_VIEW_UNORDERED_ACCESS : TEXTURE_VIEW_SHADER_RESOURCE));
VkDescriptorImageInfo DescrImgInfo;
DescrImgInfo.sampler = VK_NULL_HANDLE;
- VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage || !IsImmutableSampler,
+ VERIFY(Type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER || !IsImmutableSampler,
"Immutable sampler can't be assigned to separarate image or storage image");
- if (Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage && !IsImmutableSampler)
+ if (Type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER && !IsImmutableSampler)
{
// Immutable samplers are permanently bound into the set layout; later binding a sampler
// into an immutable sampler slot in a descriptor set is not allowed (13.2.1)
@@ -488,8 +488,8 @@ VkDescriptorImageInfo ShaderResourceCacheVk::Resource::GetImageDescriptorWriteIn
VkBufferView ShaderResourceCacheVk::Resource::GetBufferViewWriteInfo() const
{
// clang-format off
- VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer ||
- Type == SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer,
+ VERIFY(Type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER ||
+ Type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
"Uniform or storage buffer resource is expected");
// clang-format on
DEV_CHECK_ERR(pObject != nullptr, "Unable to get buffer view write info: cached object is null");
@@ -503,7 +503,7 @@ VkBufferView ShaderResourceCacheVk::Resource::GetBufferViewWriteInfo() const
VkDescriptorImageInfo ShaderResourceCacheVk::Resource::GetSamplerDescriptorWriteInfo() const
{
- VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler, "Separate sampler resource is expected");
+ VERIFY(Type == VK_DESCRIPTOR_TYPE_SAMPLER, "Separate sampler resource is expected");
DEV_CHECK_ERR(pObject != nullptr, "Unable to get separate sampler descriptor write info: cached object is null");
auto* pSamplerVk = pObject.RawPtr<const SamplerVkImpl>();
@@ -518,7 +518,7 @@ VkDescriptorImageInfo ShaderResourceCacheVk::Resource::GetSamplerDescriptorWrite
VkDescriptorImageInfo ShaderResourceCacheVk::Resource::GetInputAttachmentDescriptorWriteInfo() const
{
- VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::InputAttachment, "Input attachment resource is expected");
+ VERIFY(Type == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, "Input attachment resource is expected");
DEV_CHECK_ERR(pObject != nullptr, "Unable to get input attachment write info: cached object is null");
auto* pTexViewVk = pObject.RawPtr<const TextureViewVkImpl>();
@@ -534,7 +534,7 @@ VkDescriptorImageInfo ShaderResourceCacheVk::Resource::GetInputAttachmentDescrip
VkWriteDescriptorSetAccelerationStructureKHR ShaderResourceCacheVk::Resource::GetAccelerationStructureWriteInfo() const
{
- VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::AccelerationStructure, "Acceleration structure resource is expected");
+ VERIFY(Type == VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, "Acceleration structure resource is expected");
DEV_CHECK_ERR(pObject != nullptr, "Unable to get acceleration structure write info: cached object is null");
auto* pTLASVk = pObject.RawPtr<const TopLevelASVkImpl>();
diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp
deleted file mode 100644
index 1c6d5f24..00000000
--- a/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp
+++ /dev/null
@@ -1,1598 +0,0 @@
-/*
- * Copyright 2019-2021 Diligent Graphics LLC
- * Copyright 2015-2019 Egor Yusov
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * In no event and under no legal theory, whether in tort (including negligence),
- * contract, or otherwise, unless required by applicable law (such as deliberate
- * and grossly negligent acts) or agreed to in writing, shall any Contributor be
- * liable for any damages, including any direct, indirect, special, incidental,
- * or consequential damages of any character arising as a result of this License or
- * out of the use or inability to use the software (including but not limited to damages
- * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
- * all other commercial damages or losses), even if such Contributor has been advised
- * of the possibility of such damages.
- */
-
-#include "pch.h"
-
-#include "ShaderResourceLayoutVk.hpp"
-#include "ShaderResourceCacheVk.hpp"
-#include "BufferVkImpl.hpp"
-#include "BufferViewVk.h"
-#include "TextureVkImpl.hpp"
-#include "TextureViewVkImpl.hpp"
-#include "SamplerVkImpl.hpp"
-#include "ShaderVkImpl.hpp"
-#include "PipelineLayout.hpp"
-#include "ShaderResourceVariableBase.hpp"
-#include "StringTools.hpp"
-#include "PipelineStateVkImpl.hpp"
-#include "TopLevelASVkImpl.hpp"
-
-namespace Diligent
-{
-
-static constexpr auto RAY_TRACING_SHADER_TYPES =
- SHADER_TYPE_RAY_GEN |
- SHADER_TYPE_RAY_MISS |
- SHADER_TYPE_RAY_CLOSEST_HIT |
- SHADER_TYPE_RAY_ANY_HIT |
- SHADER_TYPE_RAY_INTERSECTION |
- SHADER_TYPE_CALLABLE;
-
-static Int32 FindImmutableSampler(SHADER_TYPE ShaderType,
- const PipelineResourceLayoutDesc& ResourceLayoutDesc,
- const SPIRVShaderResourceAttribs& Attribs,
- const char* SamplerSuffix)
-{
- if (Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage)
- {
- SamplerSuffix = nullptr;
- }
- else if (Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler)
- {
- // Use SamplerSuffix. If HLSL-style combined images samplers are not used,
- // SamplerSuffix will be null and we will be looking for the sampler itself.
- }
- else
- {
- UNEXPECTED("Immutable sampler can only be assigned to a sampled image or separate sampler");
- return -1;
- }
-
- for (Uint32 s = 0; s < ResourceLayoutDesc.NumImmutableSamplers; ++s)
- {
- const auto& ImtblSam = ResourceLayoutDesc.ImmutableSamplers[s];
- if (((ImtblSam.ShaderStages & ShaderType) != 0) && StreqSuff(Attribs.Name, ImtblSam.SamplerOrTextureName, SamplerSuffix))
- return s;
- }
-
- return -1;
-}
-
-static SHADER_RESOURCE_VARIABLE_TYPE FindShaderVariableType(SHADER_TYPE ShaderType,
- const SPIRVShaderResourceAttribs& Attribs,
- const PipelineResourceLayoutDesc& ResourceLayoutDesc,
- const char* CombinedSamplerSuffix)
-{
- if (Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler)
- {
- // Use texture or sampler name to derive separate sampler type
- // When HLSL-style combined image samplers are not used, CombinedSamplerSuffix is null
- return GetShaderVariableType(ShaderType, ResourceLayoutDesc.DefaultVariableType, ResourceLayoutDesc.Variables, ResourceLayoutDesc.NumVariables,
- [&](const char* VarName) {
- return StreqSuff(Attribs.Name, VarName, CombinedSamplerSuffix);
- });
- }
- else
- {
- return GetShaderVariableType(ShaderType, Attribs.Name, ResourceLayoutDesc);
- }
-}
-
-
-ShaderResourceLayoutVk::ShaderStageInfo::ShaderStageInfo(const ShaderVkImpl* pShader) :
- Type{pShader->GetDesc().ShaderType},
- Shaders{pShader},
- SPIRVs{pShader->GetSPIRV()}
-{
-}
-
-void ShaderResourceLayoutVk::ShaderStageInfo::Append(const ShaderVkImpl* pShader)
-{
- VERIFY_EXPR(pShader != nullptr);
- VERIFY(std::find(Shaders.begin(), Shaders.end(), pShader) == Shaders.end(),
- "Shader '", pShader->GetDesc().Name, "' already exists in the stage. Shaders must be deduplicated.");
-
- const auto NewShaderType = pShader->GetDesc().ShaderType;
- if (Type == SHADER_TYPE_UNKNOWN)
- {
- VERIFY_EXPR(Shaders.empty() && SPIRVs.empty());
- Type = NewShaderType;
- }
- else
- {
- VERIFY(Type == NewShaderType, "The type (", GetShaderTypeLiteralName(NewShaderType),
- ") of shader '", pShader->GetDesc().Name, "' being added to the stage is incosistent with the stage type (",
- GetShaderTypeLiteralName(Type), ").");
- }
- Shaders.push_back(pShader);
- SPIRVs.push_back(pShader->GetSPIRV());
-}
-
-size_t ShaderResourceLayoutVk::ShaderStageInfo::Count() const
-{
- VERIFY_EXPR(Shaders.size() == SPIRVs.size());
- return Shaders.size();
-}
-
-
-ShaderResourceLayoutVk::~ShaderResourceLayoutVk()
-{
- for (Uint32 r = 0; r < GetTotalResourceCount(); ++r)
- GetResource(r).~VkResource();
-
- for (Uint32 s = 0; s < m_NumImmutableSamplers; ++s)
- GetImmutableSampler(s).~ImmutableSamplerPtrType();
-}
-
-StringPool ShaderResourceLayoutVk::AllocateMemory(const std::vector<const ShaderVkImpl*>& Shaders,
- IMemoryAllocator& Allocator,
- const PipelineResourceLayoutDesc& ResourceLayoutDesc,
- const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes,
- Uint32 NumAllowedTypes,
- ResourceNameToIndex_t& UniqueNames,
- bool AllocateImmutableSamplers)
-{
- VERIFY(!m_ResourceBuffer, "Memory has already been initialized");
- VERIFY_EXPR(Shaders.size() > 0);
- VERIFY_EXPR(m_ShaderType == SHADER_TYPE_UNKNOWN);
-
- m_ShaderType = Shaders[0]->GetDesc().ShaderType;
- m_IsUsingSeparateSamplers = !Shaders[0]->GetShaderResources()->IsUsingCombinedSamplers();
- const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes);
-
- // Construct shader or shader group name
- const auto ShaderName = GetShaderGroupName(Shaders);
-
- size_t StringPoolSize = StringPool::GetRequiredReserveSize(ShaderName);
-
- // Count the number of resources to allocate all needed memory
- for (size_t s = 0; s < Shaders.size(); ++s)
- {
- const auto& Resources = *Shaders[s]->GetShaderResources();
- const auto* CombinedSamplerSuffix = Resources.GetCombinedSamplerSuffix();
- VERIFY(Resources.GetShaderType() == m_ShaderType, "Unexpected shader type");
- VERIFY(m_IsUsingSeparateSamplers == !Resources.IsUsingCombinedSamplers(), "All shaders in the stage must either use or not use combined image samplers");
-
- Resources.ProcessResources(
- [&](const SPIRVShaderResourceAttribs& ResAttribs, Uint32) //
- {
- auto VarType = FindShaderVariableType(m_ShaderType, ResAttribs, ResourceLayoutDesc, CombinedSamplerSuffix);
- if (IsAllowedType(VarType, AllowedTypeBits))
- {
- bool IsNewResource = UniqueNames.emplace(HashMapStringKey{ResAttribs.Name}, Uint32{InvalidResourceIndex}).second;
- if (IsNewResource)
- {
- StringPoolSize += StringPool::GetRequiredReserveSize(ResAttribs.Name);
-
- // For immutable separate samplers we still allocate VkResource instances, but they are never exposed to the app
-
- VERIFY(Uint32{m_NumResources[VarType]} + 1 <= Uint32{std::numeric_limits<Uint16>::max()}, "Number of resources exceeds Uint16 maximum representable value");
- ++m_NumResources[VarType];
- }
- }
- } //
- );
- }
-
- Uint32 TotalResources = 0;
- for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(VarType + 1))
- {
- TotalResources += m_NumResources[VarType];
- }
- VERIFY(TotalResources <= Uint32{std::numeric_limits<Uint16>::max()}, "Total number of resources exceeds Uint16 maximum representable value");
- m_NumResources[SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES] = static_cast<Uint16>(TotalResources);
-
- m_NumImmutableSamplers = 0;
- if (AllocateImmutableSamplers)
- {
- // Reserve space for all immutable samplers that may potentially be used in this
- // shader stage. Note that not all samplers may actually be used/initialized.
- for (Uint32 s = 0; s < ResourceLayoutDesc.NumImmutableSamplers; ++s)
- {
- const auto& ImtblSamDesc = ResourceLayoutDesc.ImmutableSamplers[s];
- if ((ImtblSamDesc.ShaderStages & m_ShaderType) != 0)
- ++m_NumImmutableSamplers;
- }
- }
-
- FixedLinearAllocator MemPool{Allocator};
-
- MemPool.AddSpace<VkResource>(TotalResources);
- MemPool.AddSpace<ImmutableSamplerPtrType>(m_NumImmutableSamplers);
- MemPool.AddSpace<char>(StringPoolSize);
-
- MemPool.Reserve();
-
- auto* pResources = MemPool.Allocate<VkResource>(TotalResources);
- auto* pImtblSamplers = MemPool.ConstructArray<ImmutableSamplerPtrType>(m_NumImmutableSamplers);
- auto* pStringData = MemPool.ConstructArray<char>(StringPoolSize);
-
- m_ResourceBuffer = std::unique_ptr<void, STDDeleterRawMem<void>>(MemPool.Release(), Allocator);
-
- VERIFY_EXPR(pResources == nullptr || m_ResourceBuffer.get() == pResources);
- VERIFY_EXPR(pImtblSamplers == nullptr || pImtblSamplers == std::addressof(GetImmutableSampler(0)));
- VERIFY_EXPR(pStringData == GetStringPoolData());
-
- StringPool stringPool;
- stringPool.AssignMemory(pStringData, StringPoolSize);
- stringPool.CopyString(ShaderName);
- return stringPool;
-}
-
-
-static Uint32 FindAssignedSampler(const ShaderResourceLayoutVk& Layout,
- const SPIRVShaderResources& Resources,
- const SPIRVShaderResourceAttribs& SepImg,
- Uint32 CurrResourceCount,
- SHADER_RESOURCE_VARIABLE_TYPE ImgVarType)
-{
- using VkResource = ShaderResourceLayoutVk::VkResource;
- VERIFY_EXPR(SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage);
-
- Uint32 SamplerInd = VkResource::InvalidSamplerInd;
- if (Resources.IsUsingCombinedSamplers() && SepImg.IsValidSepSamplerAssigned())
- {
- const auto& SepSampler = Resources.GetAssignedSepSampler(SepImg);
- for (SamplerInd = 0; SamplerInd < CurrResourceCount; ++SamplerInd)
- {
- const auto& Res = Layout.GetResource(ImgVarType, SamplerInd);
- if (Res.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler &&
- strcmp(Res.Name, SepSampler.Name) == 0)
- {
- VERIFY(ImgVarType == Res.GetVariableType(),
- "The type (", GetShaderVariableTypeLiteralName(ImgVarType), ") of separate image variable '", SepImg.Name,
- "' is not consistent with the type (", GetShaderVariableTypeLiteralName(Res.GetVariableType()),
- ") of the separate sampler '", SepSampler.Name,
- "' that is assigned to it. "
- "This should never happen as when HLSL-style combined texture samplers are used, the type of the sampler "
- "is derived from the type of the corresponding separate image.");
- break;
- }
- }
- if (SamplerInd == CurrResourceCount)
- {
- LOG_ERROR("Unable to find separate sampler '", SepSampler.Name, "' assigned to separate image '",
- SepImg.Name, "' in the list of already created resources. This seems to be a bug.");
- SamplerInd = VkResource::InvalidSamplerInd;
- }
- }
- return SamplerInd;
-}
-
-static void VerifyResourceMerge(const ShaderResourceLayoutVk::VkResource& ExistingRes,
- const SPIRVShaderResourceAttribs& NewResAttribs,
- SHADER_RESOURCE_VARIABLE_TYPE VarType)
-{
- VERIFY(ExistingRes.VariableType == VarType,
- "The type of variable '", NewResAttribs.Name, "' does not match the type determined for previous shaders. This appears to be a bug.");
-
- DEV_CHECK_ERR(ExistingRes.Type == NewResAttribs.Type,
- "Shader variable '", NewResAttribs.Name,
- "' exists in multiple shaders from the same shader stage, but its type is not consistent between "
- "shaders. All variables with the same name from the same shader stage must have the same type.");
-
- DEV_CHECK_ERR(ExistingRes.ResourceDim == NewResAttribs.ResourceDim,
- "Shader variable '", NewResAttribs.Name,
- "' exists in multiple shaders from the same shader stage, but its resource dimension is not consistent between "
- "shaders. All variables with the same name from the same shader stage must have the same resource dimension.");
-
- DEV_CHECK_ERR(ExistingRes.ArraySize == NewResAttribs.ArraySize,
- "Shader variable '", NewResAttribs.Name,
- "' exists in multiple shaders from the same shader stage, but its array size is not consistent between "
- "shaders. All variables with the same name from the same shader stage must have the same array size.");
-
- DEV_CHECK_ERR(ExistingRes.IsMS == NewResAttribs.IsMS,
- "Shader variable '", NewResAttribs.Name,
- "' exists in multiple shaders from the same shader stage, but its multisample flag is not consistent between "
- "shaders. All variables with the same name from the same shader stage must either be multisample or non-multisample.");
-}
-
-void ShaderResourceLayoutVk::InitializeStaticResourceLayout(const std::vector<const ShaderVkImpl*>& Shaders,
- IMemoryAllocator& LayoutDataAllocator,
- const PipelineResourceLayoutDesc& ResourceLayoutDesc,
- ShaderResourceCacheVk& StaticResourceCache)
-{
- const auto AllowedVarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC;
- const Uint32 AllowedTypeBits = GetAllowedTypeBits(&AllowedVarType, 1);
-
- // A mapping from the resource name to its index in m_ResourceBuffer that is used
- // to de-duplicate shader resources.
- ResourceNameToIndex_t ResourceNameToIndex;
-
- // We do not need immutable samplers in static shader resource layout as they
- // are relevant only when the main layout is initialized
- constexpr bool AllocateImmutableSamplers = false;
-
- auto stringPool = AllocateMemory(Shaders, LayoutDataAllocator, ResourceLayoutDesc, &AllowedVarType, 1, ResourceNameToIndex, AllocateImmutableSamplers);
-
- std::array<Uint32, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES> CurrResInd = {};
-
- Uint32 StaticResCacheSize = 0;
- for (const auto* pShader : Shaders)
- {
- const auto& Resources = *pShader->GetShaderResources();
- const auto* CombinedSamplerSuffix = Resources.GetCombinedSamplerSuffix();
- Resources.ProcessResources(
- [&](const SPIRVShaderResourceAttribs& Attribs, Uint32) //
- {
- auto VarType = FindShaderVariableType(m_ShaderType, Attribs, ResourceLayoutDesc, CombinedSamplerSuffix);
- if (!IsAllowedType(VarType, AllowedTypeBits))
- return;
-
- auto ResIter = ResourceNameToIndex.find(HashMapStringKey{Attribs.Name});
- VERIFY_EXPR(ResIter != ResourceNameToIndex.end());
-
- if (ResIter->second == InvalidResourceIndex)
- {
- Int32 SrcImmutableSamplerInd = -1;
- if (Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage ||
- Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler)
- {
- // Only search for the immutable sampler for combined image samplers and separate samplers
- SrcImmutableSamplerInd = FindImmutableSampler(m_ShaderType, ResourceLayoutDesc, Attribs, CombinedSamplerSuffix);
- // NB: for immutable separate samplers we still allocate VkResource instances to be compliant with the main
- // layout, but they are never initialized or exposed to the app.
- }
-
- Uint32 Binding = Uint32{Attribs.Type};
- Uint32 DescriptorSet = 0;
- Uint32 CacheOffset = StaticResCacheSize;
- StaticResCacheSize += Attribs.ArraySize;
-
- Uint32 SamplerInd = VkResource::InvalidSamplerInd;
- if (Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage)
- {
- // Separate samplers are enumerated before separate images, so the sampler
- // assigned to this separate image must have already been created.
- SamplerInd = FindAssignedSampler(*this, Resources, Attribs, CurrResInd[VarType], VarType);
- }
-
- // add new resource
- ResIter->second = CurrResInd[VarType];
- ::new (&GetResource(VarType, CurrResInd[VarType]++)) VkResource //
- {
- *this,
- stringPool.CopyString(Attribs.Name),
- Attribs,
- VarType,
- Binding,
- DescriptorSet,
- CacheOffset,
- SamplerInd,
- SrcImmutableSamplerInd >= 0 //
- };
- }
- else
- {
- // Merge with existing
- VerifyResourceMerge(GetResource(VarType, ResIter->second), Attribs, VarType);
- }
- } //
- );
- }
-
-#ifdef DILIGENT_DEBUG
- for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(VarType + 1))
- {
- VERIFY(CurrResInd[VarType] == m_NumResources[VarType], "Not all resources have been initialized, which will cause a crash when dtor is called");
- }
-
- VERIFY_EXPR(stringPool.GetRemainingSize() == 0);
-#endif
-
- StaticResourceCache.InitializeSets(GetRawAllocator(), 1, &StaticResCacheSize);
- InitializeResourceMemoryInCache(StaticResourceCache);
-#ifdef DILIGENT_DEBUG
- StaticResourceCache.DbgVerifyResourceInitialization();
-#endif
-}
-
-#ifdef DILIGENT_DEVELOPMENT
-void ShaderResourceLayoutVk::dvpVerifyResourceLayoutDesc(const TShaderStages& ShaderStages,
- const PipelineResourceLayoutDesc& ResourceLayoutDesc,
- bool VerifyVariables,
- bool VerifyImmutableSamplers)
-{
- auto GetAllowedShadersString = [&](SHADER_TYPE Stages) //
- {
- std::string ShadersStr;
- while (Stages != SHADER_TYPE_UNKNOWN)
- {
- const auto ShaderType = Stages & static_cast<SHADER_TYPE>(~(static_cast<Uint32>(Stages) - 1));
- String ShaderName;
-
- for (const auto& StageInfo : ShaderStages)
- {
- if ((Stages & StageInfo.Type) != 0)
- {
- ShaderName = GetShaderGroupName(StageInfo.Shaders);
- break;
- }
- }
-
- if (!ShadersStr.empty())
- ShadersStr.append(", ");
- ShadersStr.append(GetShaderTypeLiteralName(ShaderType));
- ShadersStr.append(" (");
- if (ShaderName.size())
- {
- ShadersStr.push_back('\'');
- ShadersStr.append(ShaderName);
- ShadersStr.push_back('\'');
- }
- else
- {
- ShadersStr.append("Not enabled in PSO");
- }
- ShadersStr.append(")");
-
- Stages &= ~ShaderType;
- }
- return ShadersStr;
- };
-
- if (VerifyVariables)
- {
- for (Uint32 v = 0; v < ResourceLayoutDesc.NumVariables; ++v)
- {
- const auto& VarDesc = ResourceLayoutDesc.Variables[v];
- if (VarDesc.ShaderStages == SHADER_TYPE_UNKNOWN)
- {
- LOG_WARNING_MESSAGE("No allowed shader stages are specified for ", GetShaderVariableTypeLiteralName(VarDesc.Type), " variable '", VarDesc.Name, "'.");
- continue;
- }
-
- bool VariableFound = false;
- for (size_t s = 0; s < ShaderStages.size() && !VariableFound; ++s)
- {
- const auto& Stage = ShaderStages[s];
- if ((Stage.Type & VarDesc.ShaderStages) == 0)
- continue;
-
- for (size_t i = 0; i < Stage.Shaders.size() && !VariableFound; ++i)
- {
- const auto& Resources = *Stage.Shaders[i]->GetShaderResources();
- VERIFY_EXPR(Resources.GetShaderType() == Stage.Type);
-
- for (Uint32 res = 0; res < Resources.GetTotalResources() && !VariableFound; ++res)
- {
- const auto& ResAttribs = Resources.GetResource(res);
- VariableFound = (strcmp(ResAttribs.Name, VarDesc.Name) == 0);
- }
- }
- }
- if (!VariableFound)
- {
- LOG_WARNING_MESSAGE(GetShaderVariableTypeLiteralName(VarDesc.Type), " variable '", VarDesc.Name,
- "' is not found in any of the designated shader stages: ",
- GetAllowedShadersString(VarDesc.ShaderStages));
- }
- }
- }
-
- if (VerifyImmutableSamplers)
- {
- for (Uint32 sam = 0; sam < ResourceLayoutDesc.NumImmutableSamplers; ++sam)
- {
- const auto& ImtblSamDesc = ResourceLayoutDesc.ImmutableSamplers[sam];
- if (ImtblSamDesc.ShaderStages == SHADER_TYPE_UNKNOWN)
- {
- LOG_WARNING_MESSAGE("No allowed shader stages are specified for immutable sampler '", ImtblSamDesc.SamplerOrTextureName, "'.");
- continue;
- }
-
- bool SamplerFound = false;
- for (size_t s = 0; s < ShaderStages.size() && !SamplerFound; ++s)
- {
- const auto& Stage = ShaderStages[s];
- if ((Stage.Type & ImtblSamDesc.ShaderStages) == 0)
- continue;
-
- for (size_t j = 0; j < Stage.Shaders.size() && !SamplerFound; ++j)
- {
- const auto& Resources = *Stage.Shaders[j]->GetShaderResources();
- VERIFY_EXPR(Resources.GetShaderType() == Stage.Type);
-
- // Irrespective of whether HLSL-style combined image samplers are used,
- // an immutable sampler can be assigned to GLSL sampled image (i.e. sampler2D g_tex)
- for (Uint32 i = 0; i < Resources.GetNumSmpldImgs() && !SamplerFound; ++i)
- {
- const auto& SmplImg = Resources.GetSmpldImg(i);
- SamplerFound = (strcmp(SmplImg.Name, ImtblSamDesc.SamplerOrTextureName) == 0);
- }
-
- if (!SamplerFound)
- {
- // Check if immutable is assigned to a separate sampler.
- // In case HLSL-style combined image samplers are used, the condition is SepSmpl.Name == "g_Texture" + "_sampler".
- // Otherwise the condition is SepSmpl.Name == "g_Texture_sampler" + "".
- const auto* CombinedSamplerSuffix = Resources.GetCombinedSamplerSuffix();
- for (Uint32 i = 0; i < Resources.GetNumSepSmplrs() && !SamplerFound; ++i)
- {
- const auto& SepSmpl = Resources.GetSepSmplr(i);
- SamplerFound = StreqSuff(SepSmpl.Name, ImtblSamDesc.SamplerOrTextureName, CombinedSamplerSuffix);
- }
- }
- }
- }
-
- if (!SamplerFound)
- {
- LOG_WARNING_MESSAGE("Immutable sampler '", ImtblSamDesc.SamplerOrTextureName,
- "' is not found in any of the designated shader stages: ",
- GetAllowedShadersString(ImtblSamDesc.ShaderStages));
- }
- }
- }
-}
-#endif
-
-void ShaderResourceLayoutVk::Initialize(IRenderDevice* pRenderDevice,
- TShaderStages& ShaderStages,
- ShaderResourceLayoutVk Layouts[],
- IMemoryAllocator& LayoutDataAllocator,
- const PipelineResourceLayoutDesc& ResourceLayoutDesc,
- class PipelineLayout& PipelineLayout,
- bool VerifyVariables,
- bool VerifyImmutableSamplers)
-{
-#ifdef DILIGENT_DEVELOPMENT
- dvpVerifyResourceLayoutDesc(ShaderStages, ResourceLayoutDesc, VerifyVariables, VerifyImmutableSamplers);
-#endif
-
- // Mappings from resource name to its index, for every shader stage
- std::array<ResourceNameToIndex_t, MAX_SHADERS_IN_PIPELINE> ResourceNameToIndexArray;
-
- constexpr bool AllocateImmutableSamplers = true;
-
- std::vector<StringPool> stringPools;
- stringPools.reserve(ShaderStages.size());
- for (size_t s = 0; s < ShaderStages.size(); ++s)
- {
- stringPools.emplace_back(
- Layouts[s].AllocateMemory(ShaderStages[s].Shaders, LayoutDataAllocator, ResourceLayoutDesc,
- nullptr, 0, ResourceNameToIndexArray[s], AllocateImmutableSamplers));
- }
-
- // Current resource index, for every variable type in every shader stage
- std::array<std::array<Uint32, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES>, MAX_SHADERS_IN_PIPELINE> CurrResInd = {};
- // Current immutable sampler index, for every shader stage
- std::array<Uint32, MAX_SHADERS_IN_PIPELINE> CurrImmutableSamplerInd = {};
-
-#ifdef DILIGENT_DEBUG
- std::unordered_map<Uint32, std::pair<Uint32, Uint32>> dbgBindings_CacheOffsets;
-#endif
-
- auto AddResource = [&](const Uint32 ShaderStageInd,
- const SPIRVShaderResources& Resources,
- const SPIRVShaderResourceAttribs& Attribs,
- std::vector<uint32_t>& SPIRV) //
- {
- auto& ResourceNameToIndex = ResourceNameToIndexArray[ShaderStageInd];
-
- auto ResIter = ResourceNameToIndex.find(HashMapStringKey{Attribs.Name});
- VERIFY(ResIter != ResourceNameToIndex.end(), "Resource '", Attribs.Name,
- "' is not found in ResourceNameToIndex map. This is a bug as the resource must have been processed by AllocateMemory and added to the map.");
-
- const auto ShaderType = Resources.GetShaderType();
- const auto VarType = FindShaderVariableType(ShaderType, Attribs, ResourceLayoutDesc, Resources.GetCombinedSamplerSuffix());
-
- auto& ResLayout = Layouts[ShaderStageInd];
-
- const VkResource* pResource = nullptr;
- if (ResIter->second == InvalidResourceIndex)
- {
- // add new resource
- Uint32 Binding = 0;
- Uint32 DescriptorSet = 0;
- Uint32 CacheOffset = 0;
- Uint32 SamplerInd = VkResource::InvalidSamplerInd;
-
- if (Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage)
- {
- // Separate samplers are enumerated before separate images, so the sampler
- // assigned to this separate image must have already been created.
- SamplerInd = FindAssignedSampler(ResLayout, Resources, Attribs, CurrResInd[ShaderStageInd][VarType], VarType);
- }
-
- VkSampler vkImmutableSampler = VK_NULL_HANDLE;
- if (Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage ||
- Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler)
- {
- // Only search for the immutable sampler for combined image samplers and separate samplers
- Int32 SrcImmutableSamplerInd = FindImmutableSampler(ShaderType, ResourceLayoutDesc, Attribs, Resources.GetCombinedSamplerSuffix());
- if (SrcImmutableSamplerInd >= 0)
- {
- // NB: for immutable separate samplers we still allocate VkResource instances, but they are never exposed to the app
-
- // We reserve enough space for the maximum number of immutable samplers that may be used in the stage,
- // but not all of them will necessarily be initialized.
- auto& ImmutableSampler = ResLayout.GetImmutableSampler(CurrImmutableSamplerInd[ShaderStageInd]++);
- VERIFY(!ImmutableSampler, "Immutable sampler has already been initialized. This is unexpected "
- "as all resources are deduplicated and should only be initialized once.");
- const auto& ImmutableSamplerDesc = ResourceLayoutDesc.ImmutableSamplers[SrcImmutableSamplerInd].Desc;
- pRenderDevice->CreateSampler(ImmutableSamplerDesc, &ImmutableSampler);
- vkImmutableSampler = ImmutableSampler.RawPtr<SamplerVkImpl>()->GetVkSampler();
- }
- }
-
- PipelineLayout.AllocateResourceSlot(Attribs, VarType, vkImmutableSampler, Resources.GetShaderType(), DescriptorSet, Binding, CacheOffset);
- VERIFY(DescriptorSet <= std::numeric_limits<decltype(VkResource::DescriptorSet)>::max(), "Descriptor set (", DescriptorSet, ") excceeds maximum representable value");
- VERIFY(Binding <= std::numeric_limits<decltype(VkResource::Binding)>::max(), "Binding (", Binding, ") excceeds maximum representable value");
-
-#ifdef DILIGENT_DEBUG
- // Verify that bindings and cache offsets monotonically increase in every descriptor set
- auto Binding_OffsetIt = dbgBindings_CacheOffsets.find(DescriptorSet);
- if (Binding_OffsetIt != dbgBindings_CacheOffsets.end())
- {
- VERIFY(Binding > Binding_OffsetIt->second.first, "Binding for descriptor set ", DescriptorSet, " is not strictly monotonic");
- VERIFY(CacheOffset > Binding_OffsetIt->second.second, "Cache offset for descriptor set ", DescriptorSet, " is not strictly monotonic");
- }
- dbgBindings_CacheOffsets[DescriptorSet] = std::make_pair(Binding, CacheOffset);
-#endif
-
- auto& ResInd = CurrResInd[ShaderStageInd][VarType];
- ResIter->second = ResInd;
-
- pResource = ::new (&ResLayout.GetResource(VarType, ResInd++)) VkResource //
- {
- ResLayout,
- stringPools[ShaderStageInd].CopyString(Attribs.Name),
- Attribs,
- VarType,
- Binding,
- DescriptorSet,
- CacheOffset,
- SamplerInd,
- vkImmutableSampler != VK_NULL_HANDLE //
- };
- }
- else
- {
- // merge with existing
- pResource = &ResLayout.GetResource(VarType, ResIter->second);
- VerifyResourceMerge(*pResource, Attribs, VarType);
- }
- VERIFY_EXPR(pResource != nullptr);
- SPIRV[Attribs.BindingDecorationOffset] = pResource->Binding;
- SPIRV[Attribs.DescriptorSetDecorationOffset] = pResource->DescriptorSet;
- };
-
- // First process uniform buffers for ALL shader stages to make sure all UBs go first in every descriptor set
- for (size_t s = 0; s < ShaderStages.size(); ++s)
- {
- auto& Shaders = ShaderStages[s].Shaders;
- for (size_t i = 0; i < Shaders.size(); ++i)
- {
- auto& SPIRV = ShaderStages[s].SPIRVs[i];
- auto& Resources = *Shaders[i]->GetShaderResources();
- for (Uint32 n = 0; n < Resources.GetNumUBs(); ++n)
- {
- const auto& UB = Resources.GetUB(n);
- AddResource(static_cast<Uint32>(s), Resources, UB, SPIRV);
- }
- }
- }
-
- // Second, process all storage buffers in all shader stages
- for (size_t s = 0; s < ShaderStages.size(); ++s)
- {
- auto& Shaders = ShaderStages[s].Shaders;
- for (size_t i = 0; i < Shaders.size(); ++i)
- {
- auto& Resources = *Shaders[i]->GetShaderResources();
- auto& SPIRV = ShaderStages[s].SPIRVs[i];
- for (Uint32 n = 0; n < Resources.GetNumSBs(); ++n)
- {
- const auto& SB = Resources.GetSB(n);
- AddResource(static_cast<Uint32>(s), Resources, SB, SPIRV);
- }
- }
- }
-
- // Finally, process all other resource types
- for (size_t s = 0; s < ShaderStages.size(); ++s)
- {
- auto& Shaders = ShaderStages[s].Shaders;
- for (size_t i = 0; i < Shaders.size(); ++i)
- {
- auto& Resources = *Shaders[i]->GetShaderResources();
- auto& SPIRV = ShaderStages[s].SPIRVs[i];
- // clang-format off
- Resources.ProcessResources(
- [&](const SPIRVShaderResourceAttribs& UB, Uint32)
- {
- VERIFY_EXPR(UB.Type == SPIRVShaderResourceAttribs::ResourceType::UniformBuffer);
- // Skip
- },
- [&](const SPIRVShaderResourceAttribs& SB, Uint32)
- {
- VERIFY_EXPR(SB.Type == SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer || SB.Type == SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer);
- // Skip
- },
- [&](const SPIRVShaderResourceAttribs& Img, Uint32)
- {
- VERIFY_EXPR(Img.Type == SPIRVShaderResourceAttribs::ResourceType::StorageImage || Img.Type == SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer);
- AddResource(static_cast<Uint32>(s), Resources, Img, SPIRV);
- },
- [&](const SPIRVShaderResourceAttribs& SmplImg, Uint32)
- {
- VERIFY_EXPR(SmplImg.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage || SmplImg.Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer);
- AddResource(static_cast<Uint32>(s), Resources, SmplImg, SPIRV);
- },
- [&](const SPIRVShaderResourceAttribs& AC, Uint32)
- {
- VERIFY_EXPR(AC.Type == SPIRVShaderResourceAttribs::ResourceType::AtomicCounter);
- AddResource(static_cast<Uint32>(s), Resources, AC, SPIRV);
- },
- [&](const SPIRVShaderResourceAttribs& SepSmpl, Uint32)
- {
- VERIFY_EXPR(SepSmpl.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler);
- AddResource(static_cast<Uint32>(s), Resources, SepSmpl, SPIRV);
- },
- [&](const SPIRVShaderResourceAttribs& SepImg, Uint32)
- {
- VERIFY_EXPR(SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage || SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer);
- AddResource(static_cast<Uint32>(s), Resources, SepImg, SPIRV);
- },
- [&](const SPIRVShaderResourceAttribs& InputAtt, Uint32)
- {
- VERIFY_EXPR(InputAtt.Type == SPIRVShaderResourceAttribs::ResourceType::InputAttachment);
- AddResource(static_cast<Uint32>(s), Resources, InputAtt, SPIRV);
- },
- [&](const SPIRVShaderResourceAttribs& AccelStruct, Uint32)
- {
- VERIFY_EXPR(AccelStruct.Type == SPIRVShaderResourceAttribs::ResourceType::AccelerationStructure);
- AddResource(static_cast<Uint32>(s), Resources, AccelStruct, SPIRV);
- }
- );
- // clang-format on
- }
- }
-
-#ifdef DILIGENT_DEBUG
- for (size_t s = 0; s < ShaderStages.size(); ++s)
- {
- auto& Layout = Layouts[s];
- for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(VarType + 1))
- {
- VERIFY(CurrResInd[s][VarType] == Layout.m_NumResources[VarType], "Not all resources have been initialized, which will cause a crash when dtor is called. This is a bug.");
- }
- // Some immutable samplers may never be initialized if they are not present in shaders
- VERIFY_EXPR(CurrImmutableSamplerInd[s] <= Layout.m_NumImmutableSamplers);
-
- VERIFY_EXPR(stringPools[s].GetRemainingSize() == 0);
- }
-#endif
-}
-
-
-void ShaderResourceLayoutVk::VkResource::UpdateDescriptorHandle(VkDescriptorSet vkDescrSet,
- uint32_t ArrayElement,
- const VkDescriptorImageInfo* pImageInfo,
- const VkDescriptorBufferInfo* pBufferInfo,
- const VkBufferView* pTexelBufferView,
- const VkWriteDescriptorSetAccelerationStructureKHR* pAccelStructInfo) const
-{
- VERIFY_EXPR(vkDescrSet != VK_NULL_HANDLE);
-
- VkWriteDescriptorSet WriteDescrSet;
- WriteDescrSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- WriteDescrSet.pNext = pAccelStructInfo;
- WriteDescrSet.dstSet = vkDescrSet;
- WriteDescrSet.dstBinding = Binding;
- WriteDescrSet.dstArrayElement = ArrayElement;
- WriteDescrSet.descriptorCount = 1;
- // descriptorType must be the same type as that specified in VkDescriptorSetLayoutBinding for dstSet at dstBinding.
- // The type of the descriptor also controls which array the descriptors are taken from. (13.2.4)
- WriteDescrSet.descriptorType = PipelineLayout::GetVkDescriptorType(Type);
- WriteDescrSet.pImageInfo = pImageInfo;
- WriteDescrSet.pBufferInfo = pBufferInfo;
- WriteDescrSet.pTexelBufferView = pTexelBufferView;
-
- ParentResLayout.m_LogicalDevice.UpdateDescriptorSets(1, &WriteDescrSet, 0, nullptr);
-}
-
-template <typename ObjectType, typename TPreUpdateObject>
-bool ShaderResourceLayoutVk::VkResource::UpdateCachedResource(ShaderResourceCacheVk::Resource& DstRes,
- RefCntAutoPtr<ObjectType>&& pObject,
- TPreUpdateObject PreUpdateObject) const
-{
- // We cannot use ValidatedCast<> here as the resource retrieved from the
- // resource mapping can be of wrong type
- if (pObject)
- {
- if (GetVariableType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC && DstRes.pObject != nullptr)
- {
- // Do not update resource if one is already bound unless it is dynamic. This may be
- // dangerous as writing descriptors while they are used by the GPU is an undefined behavior
- return false;
- }
-
- PreUpdateObject(DstRes.pObject.template RawPtr<const ObjectType>(), pObject.template RawPtr<const ObjectType>());
- DstRes.pObject.Attach(pObject.Detach());
- return true;
- }
- else
- {
- return false;
- }
-}
-
-void ShaderResourceLayoutVk::VkResource::CacheUniformBuffer(IDeviceObject* pBuffer,
- ShaderResourceCacheVk::Resource& DstRes,
- VkDescriptorSet vkDescrSet,
- Uint32 ArrayInd,
- Uint16& DynamicBuffersCounter) const
-{
- VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::UniformBuffer, "Uniform buffer resource is expected");
- RefCntAutoPtr<BufferVkImpl> pBufferVk{pBuffer, IID_BufferVk};
-#ifdef DILIGENT_DEVELOPMENT
- VerifyConstantBufferBinding(*this, GetVariableType(), ArrayInd, pBuffer, pBufferVk.RawPtr(), DstRes.pObject.RawPtr(), ParentResLayout.GetShaderName());
-
- if (pBufferVk->GetDesc().uiSizeInBytes < BufferStaticSize)
- {
- // It is OK if robustBufferAccess feature is enabled, otherwise access outside of buffer range may lead to crash or undefined behavior.
- LOG_WARNING_MESSAGE("Error binding uniform buffer '", pBufferVk->GetDesc().Name, "' to shader variable '",
- Name, "' in shader '", ParentResLayout.GetShaderName(), "': buffer size in the shader (",
- BufferStaticSize, ") is incompatible with the actual buffer size (", pBufferVk->GetDesc().uiSizeInBytes, ").");
- }
-#endif
-
- auto UpdateDynamicBuffersCounter = [&DynamicBuffersCounter](const BufferVkImpl* pOldBuffer, const BufferVkImpl* pNewBuffer) {
- if (pOldBuffer != nullptr && pOldBuffer->GetDesc().Usage == USAGE_DYNAMIC)
- {
- VERIFY(DynamicBuffersCounter > 0, "Dynamic buffers counter must be greater than zero when there is at least one dynamic buffer bound in the resource cache");
- --DynamicBuffersCounter;
- }
- if (pNewBuffer != nullptr && pNewBuffer->GetDesc().Usage == USAGE_DYNAMIC)
- ++DynamicBuffersCounter;
- };
- if (UpdateCachedResource(DstRes, std::move(pBufferVk), UpdateDynamicBuffersCounter))
- {
- // VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER or VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC descriptor type require
- // buffer to be created with VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT
-
- // Do not update descriptor for a dynamic uniform buffer. All dynamic resource
- // descriptors are updated at once by CommitDynamicResources() when SRB is committed.
- if (vkDescrSet != VK_NULL_HANDLE && GetVariableType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
- {
- VkDescriptorBufferInfo DescrBuffInfo = DstRes.GetUniformBufferDescriptorWriteInfo();
- UpdateDescriptorHandle(vkDescrSet, ArrayInd, nullptr, &DescrBuffInfo, nullptr);
- }
- }
-}
-
-void ShaderResourceLayoutVk::VkResource::CacheStorageBuffer(IDeviceObject* pBufferView,
- ShaderResourceCacheVk::Resource& DstRes,
- VkDescriptorSet vkDescrSet,
- Uint32 ArrayInd,
- Uint16& DynamicBuffersCounter) const
-{
- // clang-format off
- VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer ||
- Type == SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer,
- "Storage buffer resource is expected");
- // clang-format on
-
- RefCntAutoPtr<BufferViewVkImpl> pBufferViewVk{pBufferView, IID_BufferViewVk};
-#ifdef DILIGENT_DEVELOPMENT
- {
- // HLSL buffer SRVs are mapped to storge buffers in GLSL
- auto RequiredViewType = Type == SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer ? BUFFER_VIEW_SHADER_RESOURCE : BUFFER_VIEW_UNORDERED_ACCESS;
- VerifyResourceViewBinding(*this, GetVariableType(), ArrayInd, pBufferView, pBufferViewVk.RawPtr(), {RequiredViewType}, DstRes.pObject.RawPtr(), ParentResLayout.GetShaderName());
- if (pBufferViewVk != nullptr)
- {
- const auto& ViewDesc = pBufferViewVk->GetDesc();
- const auto& BuffDesc = pBufferViewVk->GetBuffer()->GetDesc();
- if (BuffDesc.Mode != BUFFER_MODE_STRUCTURED && BuffDesc.Mode != BUFFER_MODE_RAW)
- {
- LOG_ERROR_MESSAGE("Error binding buffer view '", ViewDesc.Name, "' of buffer '", BuffDesc.Name, "' to shader variable '",
- Name, "' in shader '", ParentResLayout.GetShaderName(), "': structured buffer view is expected.");
- }
-
- if (BufferStride == 0 && ViewDesc.ByteWidth < BufferStaticSize)
- {
- // It is OK if robustBufferAccess feature is enabled, otherwise access outside of buffer range may lead to crash or undefined behavior.
- LOG_WARNING_MESSAGE("Error binding buffer view '", ViewDesc.Name, "' of buffer '", BuffDesc.Name, "' to shader variable '",
- Name, "' in shader '", ParentResLayout.GetShaderName(), "': buffer size in the shader (",
- BufferStaticSize, ") is incompatible with the actual buffer view size (", ViewDesc.ByteWidth, ").");
- }
-
- if (BufferStride > 0 && (ViewDesc.ByteWidth < BufferStaticSize || (ViewDesc.ByteWidth - BufferStaticSize) % BufferStride != 0))
- {
- // For buffers with dynamic arrays we know only static part size and array element stride.
- // Element stride in the shader may be differ than in the code. Here we check that the buffer size is exactly the same as the array with N elements.
- LOG_WARNING_MESSAGE("Error binding buffer view '", ViewDesc.Name, "' of buffer '", BuffDesc.Name, "' to shader variable '",
- Name, "' in shader '", ParentResLayout.GetShaderName(), "': static buffer size in the shader (",
- BufferStaticSize, ") and array element stride (", BufferStride, ") are incompatible with the actual buffer view size (", ViewDesc.ByteWidth, "),",
- " this may be the result of the array element size mismatch.");
- }
- }
- }
-#endif
-
- auto UpdateDynamicBuffersCounter = [&DynamicBuffersCounter](const BufferViewVkImpl* pOldBufferView, const BufferViewVkImpl* pNewBufferView) {
- if (pOldBufferView != nullptr && pOldBufferView->GetBuffer<const BufferVkImpl>()->GetDesc().Usage == USAGE_DYNAMIC)
- {
- VERIFY(DynamicBuffersCounter > 0, "Dynamic buffers counter must be greater than zero when there is at least one dynamic buffer bound in the resource cache");
- --DynamicBuffersCounter;
- }
- if (pNewBufferView != nullptr && pNewBufferView->GetBuffer<const BufferVkImpl>()->GetDesc().Usage == USAGE_DYNAMIC)
- ++DynamicBuffersCounter;
- };
-
- if (UpdateCachedResource(DstRes, std::move(pBufferViewVk), UpdateDynamicBuffersCounter))
- {
- // VK_DESCRIPTOR_TYPE_STORAGE_BUFFER or VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC descriptor type
- // require buffer to be created with VK_BUFFER_USAGE_STORAGE_BUFFER_BIT (13.2.4)
-
- // Do not update descriptor for a dynamic storage buffer. All dynamic resource
- // descriptors are updated at once by CommitDynamicResources() when SRB is committed.
- if (vkDescrSet != VK_NULL_HANDLE && GetVariableType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
- {
- VkDescriptorBufferInfo DescrBuffInfo = DstRes.GetStorageBufferDescriptorWriteInfo();
- UpdateDescriptorHandle(vkDescrSet, ArrayInd, nullptr, &DescrBuffInfo, nullptr);
- }
- }
-}
-
-void ShaderResourceLayoutVk::VkResource::CacheTexelBuffer(IDeviceObject* pBufferView,
- ShaderResourceCacheVk::Resource& DstRes,
- VkDescriptorSet vkDescrSet,
- Uint32 ArrayInd,
- Uint16& DynamicBuffersCounter) const
-{
- // clang-format off
- VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer ||
- Type == SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer,
- "Uniform or storage buffer resource is expected");
- // clang-format on
-
- RefCntAutoPtr<BufferViewVkImpl> pBufferViewVk{pBufferView, IID_BufferViewVk};
-#ifdef DILIGENT_DEVELOPMENT
- {
- // HLSL buffer SRVs are mapped to storge buffers in GLSL
- auto RequiredViewType = Type == SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer ? BUFFER_VIEW_UNORDERED_ACCESS : BUFFER_VIEW_SHADER_RESOURCE;
- VerifyResourceViewBinding(*this, GetVariableType(), ArrayInd, pBufferView, pBufferViewVk.RawPtr(), {RequiredViewType}, DstRes.pObject.RawPtr(), ParentResLayout.GetShaderName());
- if (pBufferViewVk != nullptr)
- {
- const auto& ViewDesc = pBufferViewVk->GetDesc();
- const auto& BuffDesc = pBufferViewVk->GetBuffer()->GetDesc();
- if (!((BuffDesc.Mode == BUFFER_MODE_FORMATTED && ViewDesc.Format.ValueType != VT_UNDEFINED) || BuffDesc.Mode == BUFFER_MODE_RAW))
- {
- LOG_ERROR_MESSAGE("Error binding buffer view '", ViewDesc.Name, "' of buffer '", BuffDesc.Name, "' to shader variable '",
- Name, "' in shader '", ParentResLayout.GetShaderName(), "': formatted buffer view is expected.");
- }
- }
- }
-#endif
-
- auto UpdateDynamicBuffersCounter = [&DynamicBuffersCounter](const BufferViewVkImpl* pOldBufferView, const BufferViewVkImpl* pNewBufferView) {
- if (pOldBufferView != nullptr && pOldBufferView->GetBuffer<const BufferVkImpl>()->GetDesc().Usage == USAGE_DYNAMIC)
- {
- VERIFY(DynamicBuffersCounter > 0, "Dynamic buffers counter must be greater than zero when there is at least one dynamic buffer bound in the resource cache");
- --DynamicBuffersCounter;
- }
- if (pNewBufferView != nullptr && pNewBufferView->GetBuffer<const BufferVkImpl>()->GetDesc().Usage == USAGE_DYNAMIC)
- ++DynamicBuffersCounter;
- };
-
- if (UpdateCachedResource(DstRes, std::move(pBufferViewVk), UpdateDynamicBuffersCounter))
- {
- // The following bits must have been set at buffer creation time:
- // * VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER -> VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT
- // * VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER -> VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT
-
- // Do not update descriptor for a dynamic texel buffer. All dynamic resource descriptors
- // are updated at once by CommitDynamicResources() when SRB is committed.
- if (vkDescrSet != VK_NULL_HANDLE && GetVariableType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
- {
- VkBufferView BuffView = DstRes.pObject.RawPtr<BufferViewVkImpl>()->GetVkBufferView();
- UpdateDescriptorHandle(vkDescrSet, ArrayInd, nullptr, nullptr, &BuffView);
- }
- }
-}
-
-template <typename TCacheSampler>
-void ShaderResourceLayoutVk::VkResource::CacheImage(IDeviceObject* pTexView,
- ShaderResourceCacheVk::Resource& DstRes,
- VkDescriptorSet vkDescrSet,
- Uint32 ArrayInd,
- TCacheSampler CacheSampler) const
-{
- // clang-format off
- VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::StorageImage ||
- Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage ||
- Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage,
- "Storage image, separate image or sampled image resource is expected");
- // clang-format on
-
- RefCntAutoPtr<TextureViewVkImpl> pTexViewVk0{pTexView, IID_TextureViewVk};
-#ifdef DILIGENT_DEVELOPMENT
- {
- // HLSL buffer SRVs are mapped to storge buffers in GLSL
- auto RequiredViewType = Type == SPIRVShaderResourceAttribs::ResourceType::StorageImage ? TEXTURE_VIEW_UNORDERED_ACCESS : TEXTURE_VIEW_SHADER_RESOURCE;
- VerifyResourceViewBinding(*this, GetVariableType(), ArrayInd, pTexView, pTexViewVk0.RawPtr(), {RequiredViewType}, DstRes.pObject.RawPtr(), ParentResLayout.GetShaderName());
- }
-#endif
- if (UpdateCachedResource(DstRes, std::move(pTexViewVk0), [](const TextureViewVkImpl*, const TextureViewVkImpl*) {}))
- {
- // We can do RawPtr here safely since UpdateCachedResource() returned true
- auto* pTexViewVk = DstRes.pObject.RawPtr<TextureViewVkImpl>();
-#ifdef DILIGENT_DEVELOPMENT
- if (Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage && !IsImmutableSamplerAssigned())
- {
- if (pTexViewVk->GetSampler() == nullptr)
- {
- LOG_ERROR_MESSAGE("Error binding texture view '", pTexViewVk->GetDesc().Name, "' to variable '", GetPrintName(ArrayInd),
- "' in shader '", ParentResLayout.GetShaderName(), "'. No sampler is assigned to the view");
- }
- }
-#endif
-
- // Do not update descriptor for a dynamic image. All dynamic resource descriptors
- // are updated at once by CommitDynamicResources() when SRB is committed.
- if (vkDescrSet != VK_NULL_HANDLE && GetVariableType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
- {
- VkDescriptorImageInfo DescrImgInfo = DstRes.GetImageDescriptorWriteInfo(IsImmutableSamplerAssigned());
- UpdateDescriptorHandle(vkDescrSet, ArrayInd, &DescrImgInfo, nullptr, nullptr);
- }
-
- if (SamplerInd != InvalidSamplerInd)
- {
- VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage,
- "Only separate images can be assigned separate samplers when using HLSL-style combined samplers.");
- VERIFY(!IsImmutableSamplerAssigned(), "Separate image can't be assigned an immutable sampler.");
- const auto& SamplerAttribs = ParentResLayout.GetResource(GetVariableType(), SamplerInd);
- VERIFY_EXPR(SamplerAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler);
- if (!SamplerAttribs.IsImmutableSamplerAssigned())
- {
- auto* pSampler = pTexViewVk->GetSampler();
- if (pSampler != nullptr)
- {
- CacheSampler(SamplerAttribs, pSampler);
- }
- else
- {
- LOG_ERROR_MESSAGE("Failed to bind sampler to sampler variable '", SamplerAttribs.Name,
- "' assigned to separate image '", GetPrintName(ArrayInd), "' in shader '",
- ParentResLayout.GetShaderName(), "': no sampler is set in texture view '", pTexViewVk->GetDesc().Name, '\'');
- }
- }
- }
- }
-}
-
-void ShaderResourceLayoutVk::VkResource::CacheSeparateSampler(IDeviceObject* pSampler,
- ShaderResourceCacheVk::Resource& DstRes,
- VkDescriptorSet vkDescrSet,
- Uint32 ArrayInd) const
-{
- VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler, "Separate sampler resource is expected");
- VERIFY(!IsImmutableSamplerAssigned(), "This separate sampler is assigned an immutable sampler");
-
- RefCntAutoPtr<SamplerVkImpl> pSamplerVk{pSampler, IID_Sampler};
-#ifdef DILIGENT_DEVELOPMENT
- if (pSampler != nullptr && pSamplerVk == nullptr)
- {
- LOG_ERROR_MESSAGE("Failed to bind object '", pSampler->GetDesc().Name, "' to variable '", GetPrintName(ArrayInd),
- "' in shader '", ParentResLayout.GetShaderName(), "'. Unexpected object type: sampler is expected");
- }
- if (GetVariableType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC && DstRes.pObject != nullptr && DstRes.pObject != pSamplerVk)
- {
- auto VarTypeStr = GetShaderVariableTypeLiteralName(GetVariableType());
- LOG_ERROR_MESSAGE("Non-null sampler is already bound to ", VarTypeStr, " shader variable '", GetPrintName(ArrayInd),
- "' in shader '", ParentResLayout.GetShaderName(),
- "'. Attempting to bind another sampler or null is an error and may "
- "cause unpredicted behavior. Use another shader resource binding instance or label the variable as dynamic.");
- }
-#endif
- if (UpdateCachedResource(DstRes, std::move(pSamplerVk), [](const SamplerVkImpl*, const SamplerVkImpl*) {}))
- {
- // Do not update descriptor for a dynamic sampler. All dynamic resource descriptors
- // are updated at once by CommitDynamicResources() when SRB is committed.
- if (vkDescrSet != VK_NULL_HANDLE && GetVariableType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
- {
- VkDescriptorImageInfo DescrImgInfo = DstRes.GetSamplerDescriptorWriteInfo();
- UpdateDescriptorHandle(vkDescrSet, ArrayInd, &DescrImgInfo, nullptr, nullptr);
- }
- }
-}
-
-void ShaderResourceLayoutVk::VkResource::CacheInputAttachment(IDeviceObject* pTexView,
- ShaderResourceCacheVk::Resource& DstRes,
- VkDescriptorSet vkDescrSet,
- Uint32 ArrayInd) const
-{
- VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::InputAttachment, "Input attachment resource is expected");
- RefCntAutoPtr<TextureViewVkImpl> pTexViewVk0{pTexView, IID_TextureViewVk};
-#ifdef DILIGENT_DEVELOPMENT
- VerifyResourceViewBinding(*this, GetVariableType(), ArrayInd, pTexView, pTexViewVk0.RawPtr(), {TEXTURE_VIEW_SHADER_RESOURCE}, DstRes.pObject.RawPtr(), ParentResLayout.GetShaderName());
-#endif
- if (UpdateCachedResource(DstRes, std::move(pTexViewVk0), [](const TextureViewVkImpl*, const TextureViewVkImpl*) {}))
- {
- // Do not update descriptor for a dynamic image. All dynamic resource descriptors
- // are updated at once by CommitDynamicResources() when SRB is committed.
- if (vkDescrSet != VK_NULL_HANDLE && GetVariableType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
- {
- VkDescriptorImageInfo DescrImgInfo = DstRes.GetInputAttachmentDescriptorWriteInfo();
- UpdateDescriptorHandle(vkDescrSet, ArrayInd, &DescrImgInfo, nullptr, nullptr);
- }
- //
- }
-}
-
-void ShaderResourceLayoutVk::VkResource::CacheAccelerationStructure(IDeviceObject* pTLAS,
- ShaderResourceCacheVk::Resource& DstRes,
- VkDescriptorSet vkDescrSet,
- Uint32 ArrayInd) const
-{
- VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::AccelerationStructure, "Acceleration Structure resource is expected");
- RefCntAutoPtr<TopLevelASVkImpl> pTLASVk{pTLAS, IID_TopLevelASVk};
-#ifdef DILIGENT_DEVELOPMENT
- VerifyTLASResourceBinding(*this, GetVariableType(), ArrayInd, pTLASVk.RawPtr(), DstRes.pObject.RawPtr(), ParentResLayout.GetShaderName());
-#endif
- if (UpdateCachedResource(DstRes, std::move(pTLASVk), [](const TopLevelASVkImpl*, const TopLevelASVkImpl*) {}))
- {
- // Do not update descriptor for a dynamic TLAS. All dynamic resource descriptors
- // are updated at once by CommitDynamicResources() when SRB is committed.
- if (vkDescrSet != VK_NULL_HANDLE && GetVariableType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
- {
- VkWriteDescriptorSetAccelerationStructureKHR DescrASInfo = DstRes.GetAccelerationStructureWriteInfo();
- UpdateDescriptorHandle(vkDescrSet, ArrayInd, nullptr, nullptr, nullptr, &DescrASInfo);
- }
- //
- }
-}
-
-void ShaderResourceLayoutVk::VkResource::BindResource(IDeviceObject* pObj, Uint32 ArrayIndex, ShaderResourceCacheVk& ResourceCache) const
-{
- VERIFY_EXPR(ArrayIndex < ArraySize);
-
- auto& DstDescrSet = ResourceCache.GetDescriptorSet(DescriptorSet);
- auto vkDescrSet = DstDescrSet.GetVkDescriptorSet();
-#ifdef DILIGENT_DEBUG
- if (ResourceCache.DbgGetContentType() == ShaderResourceCacheVk::DbgCacheContentType::SRBResources)
- {
- if (VariableType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC || VariableType == SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE)
- {
- VERIFY(vkDescrSet != VK_NULL_HANDLE, "Static and mutable variables must have valid vulkan descriptor set assigned");
- // Dynamic variables do not have vulkan descriptor set only until they are assigned one the first time
- }
- }
- else if (ResourceCache.DbgGetContentType() == ShaderResourceCacheVk::DbgCacheContentType::StaticShaderResources)
- {
- VERIFY(vkDescrSet == VK_NULL_HANDLE, "Static shader resource cache should not have vulkan descriptor set allocation");
- }
- else
- {
- UNEXPECTED("Unexpected shader resource cache content type");
- }
-#endif
- auto& DstRes = DstDescrSet.GetResource(CacheOffset + ArrayIndex);
- VERIFY(DstRes.Type == Type, "Inconsistent types");
-
- if (pObj)
- {
- static_assert(Uint32{SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes} == 12, "Please handle the new resource type below");
- switch (Type)
- {
- case SPIRVShaderResourceAttribs::ResourceType::UniformBuffer:
- CacheUniformBuffer(pObj, DstRes, vkDescrSet, ArrayIndex, ResourceCache.GetDynamicBuffersCounter());
- break;
-
- case SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer:
- case SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer:
- CacheStorageBuffer(pObj, DstRes, vkDescrSet, ArrayIndex, ResourceCache.GetDynamicBuffersCounter());
- break;
-
- case SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer:
- case SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer:
- CacheTexelBuffer(pObj, DstRes, vkDescrSet, ArrayIndex, ResourceCache.GetDynamicBuffersCounter());
- break;
-
- case SPIRVShaderResourceAttribs::ResourceType::StorageImage:
- case SPIRVShaderResourceAttribs::ResourceType::SeparateImage:
- case SPIRVShaderResourceAttribs::ResourceType::SampledImage:
- CacheImage(pObj, DstRes, vkDescrSet, ArrayIndex,
- [&](const VkResource& SeparateSampler, ISampler* pSampler) {
- VERIFY(!SeparateSampler.IsImmutableSamplerAssigned(), "Separate sampler '", SeparateSampler.Name, "' is assigned an immutable sampler");
- VERIFY_EXPR(Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage);
- DEV_CHECK_ERR(SeparateSampler.ArraySize == 1 || SeparateSampler.ArraySize == ArraySize,
- "Array size (", SeparateSampler.ArraySize,
- ") of separate sampler variable '",
- SeparateSampler.Name,
- "' must be one or the same as the array size (", ArraySize,
- ") of separate image variable '", Name, "' it is assigned to");
- Uint32 SamplerArrInd = SeparateSampler.ArraySize == 1 ? 0 : ArrayIndex;
- SeparateSampler.BindResource(pSampler, SamplerArrInd, ResourceCache);
- });
- break;
-
- case SPIRVShaderResourceAttribs::ResourceType::SeparateSampler:
- if (!IsImmutableSamplerAssigned())
- {
- CacheSeparateSampler(pObj, DstRes, vkDescrSet, ArrayIndex);
- }
- else
- {
- // Immutable samplers are permanently bound into the set layout; later binding a sampler
- // into an immutable sampler slot in a descriptor set is not allowed (13.2.1)
- LOG_ERROR_MESSAGE("Attempting to assign a sampler to an immutable sampler '", Name, '\'');
- }
- break;
-
- case SPIRVShaderResourceAttribs::ResourceType::InputAttachment:
- CacheInputAttachment(pObj, DstRes, vkDescrSet, ArrayIndex);
- break;
-
- case SPIRVShaderResourceAttribs::ResourceType::AccelerationStructure:
- CacheAccelerationStructure(pObj, DstRes, vkDescrSet, ArrayIndex);
- break;
-
- default: UNEXPECTED("Unknown resource type ", static_cast<Int32>(Type));
- }
- }
- else
- {
- if (DstRes.pObject && GetVariableType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
- {
- LOG_ERROR_MESSAGE("Shader variable '", Name, "' in shader '", ParentResLayout.GetShaderName(),
- "' is not dynamic but being unbound. This is an error and may cause unpredicted behavior. "
- "Use another shader resource binding instance or label shader variable as dynamic if you need to bind another resource.");
- }
-
- DstRes.pObject.Release();
- }
-}
-
-bool ShaderResourceLayoutVk::VkResource::IsBound(Uint32 ArrayIndex, const ShaderResourceCacheVk& ResourceCache) const
-{
- VERIFY_EXPR(ArrayIndex < ArraySize);
-
- if (DescriptorSet < ResourceCache.GetNumDescriptorSets())
- {
- const auto& Set = ResourceCache.GetDescriptorSet(DescriptorSet);
- if (CacheOffset + ArrayIndex < Set.GetSize())
- {
- const auto& CachedRes = Set.GetResource(CacheOffset + ArrayIndex);
- return CachedRes.pObject != nullptr;
- }
- }
-
- return false;
-}
-
-
-void ShaderResourceLayoutVk::InitializeStaticResources(const ShaderResourceLayoutVk& SrcLayout,
- const ShaderResourceCacheVk& SrcResourceCache,
- ShaderResourceCacheVk& DstResourceCache) const
-{
- auto NumStaticResources = m_NumResources[SHADER_RESOURCE_VARIABLE_TYPE_STATIC];
- VERIFY(NumStaticResources == SrcLayout.m_NumResources[SHADER_RESOURCE_VARIABLE_TYPE_STATIC], "Inconsistent number of static resources");
- VERIFY(SrcLayout.GetShaderType() == GetShaderType(), "Incosistent shader types");
-
- // Static shader resources are stored in one large continuous descriptor set
- for (Uint32 r = 0; r < NumStaticResources; ++r)
- {
- // Get resource attributes. Resources have the same index in both layouts.
- const auto& DstRes = GetResource(SHADER_RESOURCE_VARIABLE_TYPE_STATIC, r);
- const auto& SrcRes = SrcLayout.GetResource(SHADER_RESOURCE_VARIABLE_TYPE_STATIC, r);
- VERIFY(strcmp(SrcRes.Name, DstRes.Name) == 0, "Src resource name ('", SrcRes.Name, "') does match the dst resource name '(", DstRes.Name, "'). This is a bug.");
- VERIFY(SrcRes.Type == DstRes.Type, "Src and dst resource types are incompatible. This is a bug.");
- VERIFY(SrcRes.ResourceDim == DstRes.ResourceDim, "Src and dst resource dimensions are incompatible. This is a bug.");
- VERIFY(SrcRes.Binding == Uint32{SrcRes.Type}, "Unexpected binding");
- VERIFY(SrcRes.ArraySize == DstRes.ArraySize, "Src and dst resource array sizes are not identical. This is a bug.");
- VERIFY(SrcRes.IsImmutableSamplerAssigned() == DstRes.IsImmutableSamplerAssigned(), "Src and dst resource immutable sampler flags are not identical. This is a bug.");
-
- if (DstRes.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler &&
- DstRes.IsImmutableSamplerAssigned())
- continue; // Skip immutable separate samplers
-
- for (Uint32 ArrInd = 0; ArrInd < DstRes.ArraySize; ++ArrInd)
- {
- auto SrcOffset = SrcRes.CacheOffset + ArrInd;
- const auto& SrcCachedSet = SrcResourceCache.GetDescriptorSet(SrcRes.DescriptorSet);
- const auto& SrcCachedRes = SrcCachedSet.GetResource(SrcOffset);
- IDeviceObject* pObject = SrcCachedRes.pObject.RawPtr<IDeviceObject>();
- if (!pObject)
- LOG_ERROR_MESSAGE("No resource is assigned to static shader variable '", SrcRes.GetPrintName(ArrInd), "' in shader '", GetShaderName(), "'.");
-
- auto DstOffset = DstRes.CacheOffset + ArrInd;
- IDeviceObject* pCachedResource = DstResourceCache.GetDescriptorSet(DstRes.DescriptorSet).GetResource(DstOffset).pObject;
- if (pCachedResource != pObject)
- {
- VERIFY(pCachedResource == nullptr, "Static resource has already been initialized, and the resource to be assigned from the shader does not match previously assigned resource");
- DstRes.BindResource(pObject, ArrInd, DstResourceCache);
- }
- }
- }
-}
-
-
-#ifdef DILIGENT_DEVELOPMENT
-bool ShaderResourceLayoutVk::dvpVerifyBindings(const ShaderResourceCacheVk& ResourceCache) const
-{
- bool BindingsOK = true;
- for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(VarType + 1))
- {
- for (Uint32 r = 0; r < m_NumResources[VarType]; ++r)
- {
- const auto& Res = GetResource(VarType, r);
- VERIFY(Res.GetVariableType() == VarType, "Unexpected variable type");
- for (Uint32 ArrInd = 0; ArrInd < Res.ArraySize; ++ArrInd)
- {
- const auto& CachedDescrSet = ResourceCache.GetDescriptorSet(Res.DescriptorSet);
- const auto& CachedRes = CachedDescrSet.GetResource(Res.CacheOffset + ArrInd);
- VERIFY(CachedRes.Type == Res.Type, "Inconsistent types");
- if (CachedRes.pObject == nullptr &&
- !(Res.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler && Res.IsImmutableSamplerAssigned()))
- {
- LOG_ERROR_MESSAGE("No resource is bound to ", GetShaderVariableTypeLiteralName(Res.GetVariableType()), " variable '", Res.GetPrintName(ArrInd), "' in shader '", GetShaderName(), "'");
- BindingsOK = false;
- }
-# ifdef DILIGENT_DEBUG
- auto vkDescSet = CachedDescrSet.GetVkDescriptorSet();
- auto dbgCacheContentType = ResourceCache.DbgGetContentType();
- if (dbgCacheContentType == ShaderResourceCacheVk::DbgCacheContentType::StaticShaderResources)
- VERIFY(vkDescSet == VK_NULL_HANDLE, "Static resource cache should never have vulkan descriptor set");
- else if (dbgCacheContentType == ShaderResourceCacheVk::DbgCacheContentType::SRBResources)
- {
- if (VarType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC || VarType == SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE)
- {
- VERIFY(vkDescSet != VK_NULL_HANDLE, "Static and mutable variables must have valid vulkan descriptor set assigned");
- }
- else if (VarType == SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
- {
- VERIFY(vkDescSet == VK_NULL_HANDLE, "Dynamic variables must not be assigned a vulkan descriptor set");
- }
- }
- else
- UNEXPECTED("Unexpected cache content type");
-# endif
- }
- }
- }
- return BindingsOK;
-}
-#endif
-
-void ShaderResourceLayoutVk::InitializeResourceMemoryInCache(ShaderResourceCacheVk& ResourceCache) const
-{
- auto TotalResources = GetTotalResourceCount();
- for (Uint32 r = 0; r < TotalResources; ++r)
- {
- const auto& Res = GetResource(r);
- ResourceCache.InitializeResources(Res.DescriptorSet, Res.CacheOffset, Res.ArraySize, Res.Type);
- }
-}
-
-void ShaderResourceLayoutVk::CommitDynamicResources(const ShaderResourceCacheVk& ResourceCache,
- VkDescriptorSet vkDynamicDescriptorSet) const
-{
- Uint32 NumDynamicResources = m_NumResources[SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC];
- VERIFY(NumDynamicResources != 0, "This shader resource layout does not contain dynamic resources");
- VERIFY_EXPR(vkDynamicDescriptorSet != VK_NULL_HANDLE);
-
-#ifdef DILIGENT_DEBUG
- static constexpr size_t ImgUpdateBatchSize = 4;
- static constexpr size_t BuffUpdateBatchSize = 2;
- static constexpr size_t TexelBuffUpdateBatchSize = 2;
- static constexpr size_t AccelStructBatchSize = 2;
- static constexpr size_t WriteDescriptorSetBatchSize = 2;
-#else
- static constexpr size_t ImgUpdateBatchSize = 128;
- static constexpr size_t BuffUpdateBatchSize = 64;
- static constexpr size_t TexelBuffUpdateBatchSize = 32;
- static constexpr size_t AccelStructBatchSize = 32;
- static constexpr size_t WriteDescriptorSetBatchSize = 32;
-#endif
-
- // Do not zero-initiaize arrays!
- std::array<VkDescriptorImageInfo, ImgUpdateBatchSize> DescrImgInfoArr;
- std::array<VkDescriptorBufferInfo, BuffUpdateBatchSize> DescrBuffInfoArr;
- std::array<VkBufferView, TexelBuffUpdateBatchSize> DescrBuffViewArr;
- std::array<VkWriteDescriptorSetAccelerationStructureKHR, AccelStructBatchSize> DescrAccelStructArr;
- std::array<VkWriteDescriptorSet, WriteDescriptorSetBatchSize> WriteDescrSetArr;
-
- Uint32 ResNum = 0, ArrElem = 0;
- auto DescrImgIt = DescrImgInfoArr.begin();
- auto DescrBuffIt = DescrBuffInfoArr.begin();
- auto BuffViewIt = DescrBuffViewArr.begin();
- auto AccelStructIt = DescrAccelStructArr.begin();
- auto WriteDescrSetIt = WriteDescrSetArr.begin();
-
-#ifdef DILIGENT_DEBUG
- Int32 DynamicDescrSetIndex = -1;
-#endif
-
- while (ResNum < NumDynamicResources)
- {
- const auto& Res = GetResource(SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC, ResNum);
- VERIFY_EXPR(Res.GetVariableType() == SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC);
-#ifdef DILIGENT_DEBUG
- if (DynamicDescrSetIndex < 0)
- DynamicDescrSetIndex = Res.DescriptorSet;
- else
- VERIFY(DynamicDescrSetIndex == Res.DescriptorSet, "Inconsistent dynamic resource desriptor set index");
-#endif
- const auto& SetResources = ResourceCache.GetDescriptorSet(Res.DescriptorSet);
- WriteDescrSetIt->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- WriteDescrSetIt->pNext = nullptr;
- VERIFY(SetResources.GetVkDescriptorSet() == VK_NULL_HANDLE, "Dynamic descriptor set must not be assigned to the resource cache");
- WriteDescrSetIt->dstSet = vkDynamicDescriptorSet;
- VERIFY(WriteDescrSetIt->dstSet != VK_NULL_HANDLE, "Vulkan descriptor set must not be null");
- WriteDescrSetIt->dstBinding = Res.Binding;
- WriteDescrSetIt->dstArrayElement = ArrElem;
- // descriptorType must be the same type as that specified in VkDescriptorSetLayoutBinding for dstSet at dstBinding.
- // The type of the descriptor also controls which array the descriptors are taken from. (13.2.4)
- WriteDescrSetIt->descriptorType = PipelineLayout::GetVkDescriptorType(Res.Type);
-
- // For every resource type, try to batch as many descriptor updates as we can
- static_assert(Uint32{SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes} == 12, "Please handle the new resource type below");
- switch (Res.Type)
- {
- case SPIRVShaderResourceAttribs::ResourceType::UniformBuffer:
- WriteDescrSetIt->pBufferInfo = &(*DescrBuffIt);
- while (ArrElem < Res.ArraySize && DescrBuffIt != DescrBuffInfoArr.end())
- {
- const auto& CachedRes = SetResources.GetResource(Res.CacheOffset + ArrElem);
- *DescrBuffIt = CachedRes.GetUniformBufferDescriptorWriteInfo();
- ++DescrBuffIt;
- ++ArrElem;
- }
- break;
-
- case SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer:
- case SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer:
- WriteDescrSetIt->pBufferInfo = &(*DescrBuffIt);
- while (ArrElem < Res.ArraySize && DescrBuffIt != DescrBuffInfoArr.end())
- {
- const auto& CachedRes = SetResources.GetResource(Res.CacheOffset + ArrElem);
- *DescrBuffIt = CachedRes.GetStorageBufferDescriptorWriteInfo();
- ++DescrBuffIt;
- ++ArrElem;
- }
- break;
-
- case SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer:
- case SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer:
- WriteDescrSetIt->pTexelBufferView = &(*BuffViewIt);
- while (ArrElem < Res.ArraySize && BuffViewIt != DescrBuffViewArr.end())
- {
- const auto& CachedRes = SetResources.GetResource(Res.CacheOffset + ArrElem);
- *BuffViewIt = CachedRes.GetBufferViewWriteInfo();
- ++BuffViewIt;
- ++ArrElem;
- }
- break;
-
- case SPIRVShaderResourceAttribs::ResourceType::SeparateImage:
- case SPIRVShaderResourceAttribs::ResourceType::StorageImage:
- case SPIRVShaderResourceAttribs::ResourceType::SampledImage:
- WriteDescrSetIt->pImageInfo = &(*DescrImgIt);
- while (ArrElem < Res.ArraySize && DescrImgIt != DescrImgInfoArr.end())
- {
- const auto& CachedRes = SetResources.GetResource(Res.CacheOffset + ArrElem);
- *DescrImgIt = CachedRes.GetImageDescriptorWriteInfo(Res.IsImmutableSamplerAssigned());
- ++DescrImgIt;
- ++ArrElem;
- }
- break;
-
- case SPIRVShaderResourceAttribs::ResourceType::AtomicCounter:
- // Do nothing
- break;
-
-
- case SPIRVShaderResourceAttribs::ResourceType::SeparateSampler:
- // Immutable samplers are permanently bound into the set layout; later binding a sampler
- // into an immutable sampler slot in a descriptor set is not allowed (13.2.1)
- if (!Res.IsImmutableSamplerAssigned())
- {
- WriteDescrSetIt->pImageInfo = &(*DescrImgIt);
- while (ArrElem < Res.ArraySize && DescrImgIt != DescrImgInfoArr.end())
- {
- const auto& CachedRes = SetResources.GetResource(Res.CacheOffset + ArrElem);
- *DescrImgIt = CachedRes.GetSamplerDescriptorWriteInfo();
- ++DescrImgIt;
- ++ArrElem;
- }
- }
- else
- {
- ArrElem = Res.ArraySize;
- WriteDescrSetIt->dstArrayElement = Res.ArraySize;
- }
- break;
-
- case SPIRVShaderResourceAttribs::ResourceType::AccelerationStructure:
- WriteDescrSetIt->pNext = &(*AccelStructIt);
- while (ArrElem < Res.ArraySize && AccelStructIt != DescrAccelStructArr.end())
- {
- const auto& CachedRes = SetResources.GetResource(Res.CacheOffset + ArrElem);
- *AccelStructIt = CachedRes.GetAccelerationStructureWriteInfo();
- ++AccelStructIt;
- ++ArrElem;
- }
- break;
-
- default:
- UNEXPECTED("Unexpected resource type");
- }
-
- WriteDescrSetIt->descriptorCount = ArrElem - WriteDescrSetIt->dstArrayElement;
- if (ArrElem == Res.ArraySize)
- {
- ArrElem = 0;
- ++ResNum;
- }
- // descriptorCount == 0 for immutable separate samplers
- if (WriteDescrSetIt->descriptorCount > 0)
- ++WriteDescrSetIt;
-
- // If we ran out of space in any of the arrays or if we processed all resources,
- // flush pending updates and reset iterators
- if (ResNum == NumDynamicResources ||
- DescrImgIt == DescrImgInfoArr.end() ||
- DescrBuffIt == DescrBuffInfoArr.end() ||
- BuffViewIt == DescrBuffViewArr.end() ||
- AccelStructIt == DescrAccelStructArr.end() ||
- WriteDescrSetIt == WriteDescrSetArr.end())
- {
- auto DescrWriteCount = static_cast<Uint32>(std::distance(WriteDescrSetArr.begin(), WriteDescrSetIt));
- if (DescrWriteCount > 0)
- m_LogicalDevice.UpdateDescriptorSets(DescrWriteCount, WriteDescrSetArr.data(), 0, nullptr);
-
- DescrImgIt = DescrImgInfoArr.begin();
- DescrBuffIt = DescrBuffInfoArr.begin();
- BuffViewIt = DescrBuffViewArr.begin();
- AccelStructIt = DescrAccelStructArr.begin();
- WriteDescrSetIt = WriteDescrSetArr.begin();
- }
- }
-}
-
-bool ShaderResourceLayoutVk::IsCompatibleWith(const ShaderResourceLayoutVk& ResLayout) const
-{
- if (m_NumResources != ResLayout.m_NumResources)
- return false;
-
- for (Uint32 i = 0, Cnt = GetTotalResourceCount(); i < Cnt; ++i)
- {
- const auto& lhs = this->GetResource(i);
- const auto& rhs = ResLayout.GetResource(i);
-
- if (!lhs.IsCompatibleWith(rhs))
- return false;
- }
-
- return true;
-}
-
-} // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderVariableVk.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderVariableVk.cpp
index 24f9342f..a93c4482 100644
--- a/Graphics/GraphicsEngineVulkan/src/ShaderVariableVk.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/ShaderVariableVk.cpp
@@ -29,51 +29,57 @@
#include "ShaderVariableVk.hpp"
#include "ShaderResourceVariableBase.hpp"
+#include "PipelineResourceSignatureVkImpl.hpp"
+#include "SamplerVkImpl.hpp"
+#include "TextureViewVkImpl.hpp"
+#include "TopLevelASVkImpl.hpp"
namespace Diligent
{
-size_t ShaderVariableManagerVk::GetRequiredMemorySize(const ShaderResourceLayoutVk& Layout,
- const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes,
- Uint32 NumAllowedTypes,
- Uint32& NumVariables)
+size_t ShaderVariableManagerVk::GetRequiredMemorySize(const PipelineResourceSignatureVkImpl& Layout,
+ const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes,
+ Uint32 NumAllowedTypes,
+ Uint32& NumVariables)
{
NumVariables = 0;
const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes);
- const bool UsingSeparateSamplers = Layout.IsUsingSeparateSamplers();
- for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(VarType + 1))
+ const bool UsingSeparateSamplers = true; //Layout.IsUsingSeparateSamplers();
+ const auto& Desc = Layout.GetDesc();
+
+ for (Uint32 r = 0; r < Desc.NumResources; ++r)
{
- if (IsAllowedType(VarType, AllowedTypeBits))
- {
- auto NumResources = Layout.GetResourceCount(VarType);
- for (Uint32 r = 0; r < NumResources; ++r)
- {
- const auto& SrcRes = Layout.GetResource(VarType, r);
+ const auto& SrcRes = Desc.Resources[r];
- // When using HLSL-style combined image samplers, we need to skip separate samplers.
- // Also always skip immutable separate samplers.
- if (SrcRes.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler &&
- (!UsingSeparateSamplers || SrcRes.IsImmutableSamplerAssigned()))
- continue;
+ if (!IsAllowedType(SrcRes.VarType, AllowedTypeBits))
+ continue;
- ++NumVariables;
- }
- }
+ // AZ TODO
+ /*
+ // When using HLSL-style combined image samplers, we need to skip separate samplers.
+ // Also always skip immutable separate samplers.
+ if (SrcRes.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler && // AZ TODO
+ (!UsingSeparateSamplers || SrcRes.IsImmutableSamplerAssigned()))
+ continue;
+ */
+ ++NumVariables;
}
return NumVariables * sizeof(ShaderVariableVkImpl);
}
// Creates shader variable for every resource from SrcLayout whose type is one AllowedVarTypes
-void ShaderVariableManagerVk::Initialize(const ShaderResourceLayoutVk& SrcLayout,
- IMemoryAllocator& Allocator,
- const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes,
- Uint32 NumAllowedTypes)
+void ShaderVariableManagerVk::Initialize(const PipelineResourceSignatureVkImpl& SrcLayout,
+ IMemoryAllocator& Allocator,
+ const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes,
+ Uint32 NumAllowedTypes)
{
#ifdef DILIGENT_DEBUG
m_pDbgAllocator = &Allocator;
#endif
+ VERIFY_EXPR(m_pSignature == nullptr);
+
const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes);
VERIFY_EXPR(m_NumVariables == 0);
auto MemSize = GetRequiredMemorySize(SrcLayout, AllowedVarTypes, NumAllowedTypes, m_NumVariables);
@@ -84,27 +90,30 @@ void ShaderVariableManagerVk::Initialize(const ShaderResourceLayoutVk& Sr
auto* pRawMem = ALLOCATE_RAW(Allocator, "Raw memory buffer for shader variables", MemSize);
m_pVariables = reinterpret_cast<ShaderVariableVkImpl*>(pRawMem);
- Uint32 VarInd = 0;
- const bool UsingSeparateSamplers = SrcLayout.IsUsingSeparateSamplers();
- for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(VarType + 1))
+ Uint32 VarInd = 0;
+ const bool UsingSeparateSamplers = false; //SrcLayout.IsUsingSeparateSamplers();
+ const auto& Desc = SrcLayout.GetDesc();
+
+ for (Uint32 r = 0; r < Desc.NumResources; ++r)
{
- if (!IsAllowedType(VarType, AllowedTypeBits))
- continue;
+ const auto& SrcRes = Desc.Resources[r];
- Uint32 NumResources = SrcLayout.GetResourceCount(VarType);
- for (Uint32 r = 0; r < NumResources; ++r)
- {
- const auto& SrcRes = SrcLayout.GetResource(VarType, r);
- // Skip separate samplers when using combined HLSL-style image samplers. Also always skip immutable separate samplers.
- if (SrcRes.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler &&
- (!UsingSeparateSamplers || SrcRes.IsImmutableSamplerAssigned()))
- continue;
+ if (!IsAllowedType(SrcRes.VarType, AllowedTypeBits))
+ continue;
- ::new (m_pVariables + VarInd) ShaderVariableVkImpl(*this, SrcRes);
- ++VarInd;
- }
+ // AZ TODO
+ /*
+ // Skip separate samplers when using combined HLSL-style image samplers. Also always skip immutable separate samplers.
+ if (SrcRes.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler &&
+ (!UsingSeparateSamplers || SrcRes.IsImmutableSamplerAssigned()))
+ continue;
+ */
+ ::new (m_pVariables + VarInd) ShaderVariableVkImpl(*this);
+ ++VarInd;
}
VERIFY_EXPR(VarInd == m_NumVariables);
+
+ m_pSignature = &SrcLayout;
}
ShaderVariableManagerVk::~ShaderVariableManagerVk()
@@ -131,7 +140,7 @@ ShaderVariableVkImpl* ShaderVariableManagerVk::GetVariable(const Char* Name) con
for (Uint32 v = 0; v < m_NumVariables; ++v)
{
auto& Var = m_pVariables[v];
- const auto& Res = Var.m_Resource;
+ const auto& Res = Var.GetDesc();
if (strcmp(Res.Name, Name) == 0)
{
pVar = &Var;
@@ -183,7 +192,7 @@ void ShaderVariableManagerVk::BindResources(IResourceMapping* pResourceMapping,
if ((Flags & BIND_SHADER_RESOURCES_UPDATE_ALL) == 0)
Flags |= BIND_SHADER_RESOURCES_UPDATE_ALL;
-
+ /*
for (Uint32 v = 0; v < m_NumVariables; ++v)
{
auto& Var = m_pVariables[v];
@@ -218,7 +227,554 @@ void ShaderVariableManagerVk::BindResources(IResourceMapping* pResourceMapping,
}
}
}
+ }*/
+}
+
+void ShaderVariableVkImpl::Set(IDeviceObject* pObject)
+{
+ BindResource(pObject, 0);
+}
+
+void ShaderVariableVkImpl::SetArray(IDeviceObject* const* ppObjects,
+ Uint32 FirstElement,
+ Uint32 NumElements)
+{
+ const auto& ResDesc = GetDesc();
+ VerifyAndCorrectSetArrayArguments(ResDesc.Name, ResDesc.ArraySize, FirstElement, NumElements);
+
+ for (Uint32 Elem = 0; Elem < NumElements; ++Elem)
+ BindResource(ppObjects[Elem], FirstElement + Elem);
+}
+
+bool ShaderVariableVkImpl::IsBound(Uint32 ArrayIndex) const
+{
+ auto& ResourceCache = m_ParentManager.m_ResourceCache;
+ const auto& ResDesc = GetDesc();
+ const auto& Binding = GetBinding();
+ Uint32 CacheOffset = GetIndex();
+
+ VERIFY_EXPR(ArrayIndex < ResDesc.ArraySize);
+
+ if (Binding.DescSet < ResourceCache.GetNumDescriptorSets())
+ {
+ const auto& Set = ResourceCache.GetDescriptorSet(Binding.DescSet);
+ if (CacheOffset + ArrayIndex < Set.GetSize())
+ {
+ const auto& CachedRes = Set.GetResource(CacheOffset + ArrayIndex);
+ return CachedRes.pObject != nullptr;
+ }
+ }
+
+ return false;
+}
+
+void ShaderVariableVkImpl::BindResource(IDeviceObject* pObj, Uint32 ArrayIndex) const
+{
+ auto CacheOffset = GetIndex();
+ auto& ResDesc = GetDesc();
+ auto& Bindings = GetBinding();
+ auto& ResourceCache = m_ParentManager.m_ResourceCache;
+ auto& DstDescrSet = ResourceCache.GetDescriptorSet(Bindings.DescSet);
+
+ VERIFY_EXPR(ArrayIndex < ResDesc.ArraySize);
+
+ UpdateInfo Info{
+ DstDescrSet.GetResource(CacheOffset + ArrayIndex),
+ DstDescrSet.GetVkDescriptorSet(),
+ ArrayIndex,
+ ResDesc.VarType,
+ Bindings.Binding,
+ Bindings.SamplerInd,
+ ResDesc.Name};
+
+#ifdef DILIGENT_DEBUG
+ if (ResourceCache.DbgGetContentType() == ShaderResourceCacheVk::DbgCacheContentType::SRBResources)
+ {
+ if (Info.VarType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC || Info.VarType == SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE)
+ {
+ VERIFY(Info.vkDescrSet != VK_NULL_HANDLE, "Static and mutable variables must have valid vulkan descriptor set assigned");
+ // Dynamic variables do not have vulkan descriptor set only until they are assigned one the first time
+ }
+ }
+ else if (ResourceCache.DbgGetContentType() == ShaderResourceCacheVk::DbgCacheContentType::StaticShaderResources)
+ {
+ VERIFY(Info.vkDescrSet == VK_NULL_HANDLE, "Static shader resource cache should not have vulkan descriptor set allocation");
+ }
+ else
+ {
+ UNEXPECTED("Unexpected shader resource cache content type");
+ }
+#endif
+
+ VERIFY(Info.DstRes.Type == PipelineResourceSignatureVkImpl::GetVkDescriptorType(ResDesc), "Inconsistent types");
+
+ if (pObj)
+ {
+ switch (Info.DstRes.Type)
+ {
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
+ CacheUniformBuffer(pObj, Info, ResourceCache.GetDynamicBuffersCounter());
+ break;
+
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
+ CacheStorageBuffer(pObj, Info, ResourceCache.GetDynamicBuffersCounter());
+ break;
+
+ case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
+ case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
+ CacheTexelBuffer(pObj, Info, ResourceCache.GetDynamicBuffersCounter());
+ break;
+
+ case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
+ case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
+ case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
+ CacheImage(pObj, Info,
+ [&](const ShaderVariableVkImpl& SeparateSampler, ISampler* pSampler) {
+ VERIFY(!SeparateSampler.IsImmutableSamplerAssigned(), "Separate sampler '", SeparateSampler.GetDesc().Name, "' is assigned an immutable sampler");
+ VERIFY_EXPR(Info.DstRes.Type == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
+ DEV_CHECK_ERR(SeparateSampler.GetDesc().ArraySize == 1 || SeparateSampler.GetDesc().ArraySize == ResDesc.ArraySize,
+ "Array size (", SeparateSampler.GetDesc().ArraySize,
+ ") of separate sampler variable '",
+ SeparateSampler.GetDesc().Name,
+ "' must be one or the same as the array size (", ResDesc.ArraySize,
+ ") of separate image variable '", ResDesc.Name, "' it is assigned to");
+ Uint32 SamplerArrInd = SeparateSampler.GetDesc().ArraySize == 1 ? 0 : ArrayIndex;
+ SeparateSampler.BindResource(pSampler, SamplerArrInd);
+ });
+ break;
+
+ case VK_DESCRIPTOR_TYPE_SAMPLER:
+ if (!IsImmutableSamplerAssigned())
+ {
+ CacheSeparateSampler(pObj, Info);
+ }
+ else
+ {
+ // Immutable samplers are permanently bound into the set layout; later binding a sampler
+ // into an immutable sampler slot in a descriptor set is not allowed (13.2.1)
+ LOG_ERROR_MESSAGE("Attempting to assign a sampler to an immutable sampler '", ResDesc.Name, '\'');
+ }
+ break;
+
+ case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
+ CacheInputAttachment(pObj, Info);
+ break;
+
+ case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:
+ CacheAccelerationStructure(pObj, Info);
+ break;
+
+ default: UNEXPECTED("Unknown resource type ", static_cast<Int32>(Info.DstRes.Type));
+ }
+ }
+ else
+ {
+ if (Info.DstRes.pObject && Info.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
+ {
+ LOG_ERROR_MESSAGE("Shader variable '", ResDesc.Name, "' is not dynamic but being unbound. This is an error and may cause unpredicted behavior. "
+ "Use another shader resource binding instance or label shader variable as dynamic if you need to bind another resource.");
+ }
+
+ Info.DstRes.pObject.Release();
+ }
+}
+
+template <typename ObjectType, typename TPreUpdateObject>
+bool ShaderVariableVkImpl::UpdateCachedResource(UpdateInfo& Info,
+ RefCntAutoPtr<ObjectType>&& pObject,
+ TPreUpdateObject PreUpdateObject) const
+{
+ // We cannot use ValidatedCast<> here as the resource retrieved from the
+ // resource mapping can be of wrong type
+ if (pObject)
+ {
+ if (Info.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC && Info.DstRes.pObject != nullptr)
+ {
+ // Do not update resource if one is already bound unless it is dynamic. This may be
+ // dangerous as writing descriptors while they are used by the GPU is an undefined behavior
+ return false;
+ }
+
+ PreUpdateObject(Info.DstRes.pObject.template RawPtr<const ObjectType>(), pObject.template RawPtr<const ObjectType>());
+ Info.DstRes.pObject.Attach(pObject.Detach());
+ return true;
}
+ else
+ {
+ return false;
+ }
+}
+
+void ShaderVariableVkImpl::CacheUniformBuffer(IDeviceObject* pBuffer,
+ UpdateInfo& Info,
+ Uint16& DynamicBuffersCounter) const
+{
+ // clang-format off
+ VERIFY(Info.DstRes.Type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ||
+ Info.DstRes.Type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
+ "Uniform buffer resource is expected");
+ // clang-format on
+ RefCntAutoPtr<BufferVkImpl> pBufferVk{pBuffer, IID_BufferVk};
+#ifdef DILIGENT_DEVELOPMENT
+ VerifyConstantBufferBinding(*this, Info.VarType, Info.ArrayIndex, pBuffer, pBufferVk.RawPtr(), Info.DstRes.pObject.RawPtr());
+
+ /*if (pBufferVk->GetDesc().uiSizeInBytes < BufferStaticSize)
+ {
+ // It is OK if robustBufferAccess feature is enabled, otherwise access outside of buffer range may lead to crash or undefined behavior.
+ LOG_WARNING_MESSAGE("Error binding uniform buffer '", pBufferVk->GetDesc().Name, "' to shader variable '",
+ GetDesc().Name, "': buffer size in the shader (",
+ BufferStaticSize, ") is incompatible with the actual buffer size (", pBufferVk->GetDesc().uiSizeInBytes, ").");
+ }*/
+#endif
+
+ auto UpdateDynamicBuffersCounter = [&DynamicBuffersCounter](const BufferVkImpl* pOldBuffer, const BufferVkImpl* pNewBuffer) {
+ if (pOldBuffer != nullptr && pOldBuffer->GetDesc().Usage == USAGE_DYNAMIC)
+ {
+ VERIFY(DynamicBuffersCounter > 0, "Dynamic buffers counter must be greater than zero when there is at least one dynamic buffer bound in the resource cache");
+ --DynamicBuffersCounter;
+ }
+ if (pNewBuffer != nullptr && pNewBuffer->GetDesc().Usage == USAGE_DYNAMIC)
+ ++DynamicBuffersCounter;
+ };
+ if (UpdateCachedResource(Info, std::move(pBufferVk), UpdateDynamicBuffersCounter))
+ {
+ // VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER or VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC descriptor type require
+ // buffer to be created with VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT
+
+ // Do not update descriptor for a dynamic uniform buffer. All dynamic resource
+ // descriptors are updated at once by CommitDynamicResources() when SRB is committed.
+ if (Info.vkDescrSet != VK_NULL_HANDLE && Info.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
+ {
+ VkDescriptorBufferInfo DescrBuffInfo = Info.DstRes.GetUniformBufferDescriptorWriteInfo();
+ UpdateDescriptorHandle(Info, nullptr, &DescrBuffInfo, nullptr);
+ }
+ }
+}
+
+void ShaderVariableVkImpl::CacheStorageBuffer(IDeviceObject* pBufferView,
+ UpdateInfo& Info,
+ Uint16& DynamicBuffersCounter) const
+{
+ // clang-format off
+ VERIFY(Info.DstRes.Type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ||
+ Info.DstRes.Type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,
+ "Storage buffer resource is expected");
+ // clang-format on
+
+ RefCntAutoPtr<BufferViewVkImpl> pBufferViewVk{pBufferView, IID_BufferViewVk};
+#ifdef DILIGENT_DEVELOPMENT
+ {
+ // HLSL buffer SRVs are mapped to storge buffers in GLSL
+ auto RequiredViewType = BUFFER_VIEW_UNORDERED_ACCESS; // AZ TODO
+ VerifyResourceViewBinding(*this, Info.VarType, Info.ArrayIndex, pBufferView, pBufferViewVk.RawPtr(), {RequiredViewType}, Info.DstRes.pObject.RawPtr());
+ if (pBufferViewVk != nullptr)
+ {
+ const auto& ViewDesc = pBufferViewVk->GetDesc();
+ const auto& BuffDesc = pBufferViewVk->GetBuffer()->GetDesc();
+ if (BuffDesc.Mode != BUFFER_MODE_STRUCTURED && BuffDesc.Mode != BUFFER_MODE_RAW)
+ {
+ LOG_ERROR_MESSAGE("Error binding buffer view '", ViewDesc.Name, "' of buffer '", BuffDesc.Name, "' to shader variable '",
+ GetDesc().Name, "': structured buffer view is expected.");
+ }
+
+ /*if (BufferStride == 0 && ViewDesc.ByteWidth < BufferStaticSize)
+ {
+ // It is OK if robustBufferAccess feature is enabled, otherwise access outside of buffer range may lead to crash or undefined behavior.
+ LOG_WARNING_MESSAGE("Error binding buffer view '", ViewDesc.Name, "' of buffer '", BuffDesc.Name, "' to shader variable '",
+ Name, "': buffer size in the shader (",
+ BufferStaticSize, ") is incompatible with the actual buffer view size (", ViewDesc.ByteWidth, ").");
+ }
+
+ if (BufferStride > 0 && (ViewDesc.ByteWidth < BufferStaticSize || (ViewDesc.ByteWidth - BufferStaticSize) % BufferStride != 0))
+ {
+ // For buffers with dynamic arrays we know only static part size and array element stride.
+ // Element stride in the shader may be differ than in the code. Here we check that the buffer size is exactly the same as the array with N elements.
+ LOG_WARNING_MESSAGE("Error binding buffer view '", ViewDesc.Name, "' of buffer '", BuffDesc.Name, "' to shader variable '",
+ Name, "': static buffer size in the shader (",
+ BufferStaticSize, ") and array element stride (", BufferStride, ") are incompatible with the actual buffer view size (", ViewDesc.ByteWidth, "),",
+ " this may be the result of the array element size mismatch.");
+ }*/
+ }
+ }
+#endif
+
+ auto UpdateDynamicBuffersCounter = [&DynamicBuffersCounter](const BufferViewVkImpl* pOldBufferView, const BufferViewVkImpl* pNewBufferView) {
+ if (pOldBufferView != nullptr && pOldBufferView->GetBuffer<const BufferVkImpl>()->GetDesc().Usage == USAGE_DYNAMIC)
+ {
+ VERIFY(DynamicBuffersCounter > 0, "Dynamic buffers counter must be greater than zero when there is at least one dynamic buffer bound in the resource cache");
+ --DynamicBuffersCounter;
+ }
+ if (pNewBufferView != nullptr && pNewBufferView->GetBuffer<const BufferVkImpl>()->GetDesc().Usage == USAGE_DYNAMIC)
+ ++DynamicBuffersCounter;
+ };
+
+ if (UpdateCachedResource(Info, std::move(pBufferViewVk), UpdateDynamicBuffersCounter))
+ {
+ // VK_DESCRIPTOR_TYPE_STORAGE_BUFFER or VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC descriptor type
+ // require buffer to be created with VK_BUFFER_USAGE_STORAGE_BUFFER_BIT (13.2.4)
+
+ // Do not update descriptor for a dynamic storage buffer. All dynamic resource
+ // descriptors are updated at once by CommitDynamicResources() when SRB is committed.
+ if (Info.vkDescrSet != VK_NULL_HANDLE && Info.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
+ {
+ VkDescriptorBufferInfo DescrBuffInfo = Info.DstRes.GetStorageBufferDescriptorWriteInfo();
+ UpdateDescriptorHandle(Info, nullptr, &DescrBuffInfo, nullptr);
+ }
+ }
+}
+
+void ShaderVariableVkImpl::CacheTexelBuffer(IDeviceObject* pBufferView,
+ UpdateInfo& Info,
+ Uint16& DynamicBuffersCounter) const
+{
+ // clang-format off
+ VERIFY(Info.DstRes.Type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER ||
+ Info.DstRes.Type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
+ "Uniform or storage buffer resource is expected");
+ // clang-format on
+
+ RefCntAutoPtr<BufferViewVkImpl> pBufferViewVk{pBufferView, IID_BufferViewVk};
+#ifdef DILIGENT_DEVELOPMENT
+ {
+ // HLSL buffer SRVs are mapped to storge buffers in GLSL
+ auto RequiredViewType = BUFFER_VIEW_UNORDERED_ACCESS; // AZ TODO
+ VerifyResourceViewBinding(*this, Info.VarType, Info.ArrayIndex, pBufferView, pBufferViewVk.RawPtr(), {RequiredViewType}, Info.DstRes.pObject.RawPtr());
+ if (pBufferViewVk != nullptr)
+ {
+ const auto& ViewDesc = pBufferViewVk->GetDesc();
+ const auto& BuffDesc = pBufferViewVk->GetBuffer()->GetDesc();
+ if (!((BuffDesc.Mode == BUFFER_MODE_FORMATTED && ViewDesc.Format.ValueType != VT_UNDEFINED) || BuffDesc.Mode == BUFFER_MODE_RAW))
+ {
+ LOG_ERROR_MESSAGE("Error binding buffer view '", ViewDesc.Name, "' of buffer '", BuffDesc.Name, "' to shader variable '",
+ GetDesc().Name, "': formatted buffer view is expected.");
+ }
+ }
+ }
+#endif
+
+ auto UpdateDynamicBuffersCounter = [&DynamicBuffersCounter](const BufferViewVkImpl* pOldBufferView, const BufferViewVkImpl* pNewBufferView) {
+ if (pOldBufferView != nullptr && pOldBufferView->GetBuffer<const BufferVkImpl>()->GetDesc().Usage == USAGE_DYNAMIC)
+ {
+ VERIFY(DynamicBuffersCounter > 0, "Dynamic buffers counter must be greater than zero when there is at least one dynamic buffer bound in the resource cache");
+ --DynamicBuffersCounter;
+ }
+ if (pNewBufferView != nullptr && pNewBufferView->GetBuffer<const BufferVkImpl>()->GetDesc().Usage == USAGE_DYNAMIC)
+ ++DynamicBuffersCounter;
+ };
+
+ if (UpdateCachedResource(Info, std::move(pBufferViewVk), UpdateDynamicBuffersCounter))
+ {
+ // The following bits must have been set at buffer creation time:
+ // * VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER -> VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT
+ // * VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER -> VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT
+
+ // Do not update descriptor for a dynamic texel buffer. All dynamic resource descriptors
+ // are updated at once by CommitDynamicResources() when SRB is committed.
+ if (Info.vkDescrSet != VK_NULL_HANDLE && Info.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
+ {
+ VkBufferView BuffView = Info.DstRes.pObject.RawPtr<BufferViewVkImpl>()->GetVkBufferView();
+ UpdateDescriptorHandle(Info, nullptr, nullptr, &BuffView);
+ }
+ }
+}
+
+template <typename TCacheSampler>
+void ShaderVariableVkImpl::CacheImage(IDeviceObject* pTexView,
+ UpdateInfo& Info,
+ TCacheSampler CacheSampler) const
+{
+ // clang-format off
+ VERIFY(Info.DstRes.Type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE ||
+ Info.DstRes.Type == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE ||
+ Info.DstRes.Type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+ "Storage image, separate image or sampled image resource is expected");
+ // clang-format on
+ RefCntAutoPtr<TextureViewVkImpl> pTexViewVk0{pTexView, IID_TextureViewVk};
+#ifdef DILIGENT_DEVELOPMENT
+ {
+ // HLSL buffer SRVs are mapped to storge buffers in GLSL
+ auto RequiredViewType = TEXTURE_VIEW_UNORDERED_ACCESS; // AZ TODO: read only
+ VerifyResourceViewBinding(*this, Info.VarType, Info.ArrayIndex, pTexView, pTexViewVk0.RawPtr(), {RequiredViewType}, Info.DstRes.pObject.RawPtr());
+ }
+#endif
+ if (UpdateCachedResource(Info, std::move(pTexViewVk0), [](const TextureViewVkImpl*, const TextureViewVkImpl*) {}))
+ {
+ // We can do RawPtr here safely since UpdateCachedResource() returned true
+ auto* pTexViewVk = Info.DstRes.pObject.RawPtr<TextureViewVkImpl>();
+#ifdef DILIGENT_DEVELOPMENT
+ if (Info.DstRes.Type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER && !IsImmutableSamplerAssigned())
+ {
+ if (pTexViewVk->GetSampler() == nullptr)
+ {
+ LOG_ERROR_MESSAGE("Error binding texture view '", pTexViewVk->GetDesc().Name, "' to variable '", GetPrintName(Info.ArrayIndex),
+ "'. No sampler is assigned to the view");
+ }
+ }
+#endif
+
+ // Do not update descriptor for a dynamic image. All dynamic resource descriptors
+ // are updated at once by CommitDynamicResources() when SRB is committed.
+ if (Info.vkDescrSet != VK_NULL_HANDLE && Info.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
+ {
+ VkDescriptorImageInfo DescrImgInfo = Info.DstRes.GetImageDescriptorWriteInfo(IsImmutableSamplerAssigned());
+ UpdateDescriptorHandle(Info, &DescrImgInfo, nullptr, nullptr);
+ }
+
+ if (Info.SamplerInd != InvalidSamplerInd)
+ {
+ VERIFY(Info.DstRes.Type == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
+ "Only separate images can be assigned separate samplers when using HLSL-style combined samplers.");
+ VERIFY(!IsImmutableSamplerAssigned(), "Separate image can't be assigned an immutable sampler.");
+ const auto& SamplerAttribs = *m_ParentManager.GetVariable(Info.SamplerInd);
+ VERIFY_EXPR(SamplerAttribs.GetDesc().ResourceType == SHADER_RESOURCE_TYPE_SAMPLER);
+ if (!SamplerAttribs.IsImmutableSamplerAssigned())
+ {
+ auto* pSampler = pTexViewVk->GetSampler();
+ if (pSampler != nullptr)
+ {
+ CacheSampler(SamplerAttribs, pSampler);
+ }
+ else
+ {
+ LOG_ERROR_MESSAGE("Failed to bind sampler to sampler variable '", SamplerAttribs.GetDesc().Name,
+ "' assigned to separate image '", GetPrintName(Info.ArrayIndex),
+ "': no sampler is set in texture view '", pTexViewVk->GetDesc().Name, '\'');
+ }
+ }
+ }
+ }
+}
+
+void ShaderVariableVkImpl::CacheSeparateSampler(IDeviceObject* pSampler,
+ UpdateInfo& Info) const
+{
+ VERIFY(Info.DstRes.Type == VK_DESCRIPTOR_TYPE_SAMPLER, "Separate sampler resource is expected");
+ VERIFY(!IsImmutableSamplerAssigned(), "This separate sampler is assigned an immutable sampler");
+
+ RefCntAutoPtr<SamplerVkImpl> pSamplerVk{pSampler, IID_Sampler};
+#ifdef DILIGENT_DEVELOPMENT
+ if (pSampler != nullptr && pSamplerVk == nullptr)
+ {
+ LOG_ERROR_MESSAGE("Failed to bind object '", pSampler->GetDesc().Name, "' to variable '", GetPrintName(Info.ArrayIndex),
+ "'. Unexpected object type: sampler is expected");
+ }
+ if (Info.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC && Info.DstRes.pObject != nullptr && Info.DstRes.pObject != pSamplerVk)
+ {
+ auto VarTypeStr = GetShaderVariableTypeLiteralName(Info.VarType);
+ LOG_ERROR_MESSAGE("Non-null sampler is already bound to ", VarTypeStr, " shader variable '", GetPrintName(Info.ArrayIndex),
+ "'. Attempting to bind another sampler or null is an error and may "
+ "cause unpredicted behavior. Use another shader resource binding instance or label the variable as dynamic.");
+ }
+#endif
+ if (UpdateCachedResource(Info, std::move(pSamplerVk), [](const SamplerVkImpl*, const SamplerVkImpl*) {}))
+ {
+ // Do not update descriptor for a dynamic sampler. All dynamic resource descriptors
+ // are updated at once by CommitDynamicResources() when SRB is committed.
+ if (Info.vkDescrSet != VK_NULL_HANDLE && Info.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
+ {
+ VkDescriptorImageInfo DescrImgInfo = Info.DstRes.GetSamplerDescriptorWriteInfo();
+ UpdateDescriptorHandle(Info, &DescrImgInfo, nullptr, nullptr);
+ }
+ }
+}
+
+void ShaderVariableVkImpl::CacheInputAttachment(IDeviceObject* pTexView,
+ UpdateInfo& Info) const
+{
+ VERIFY(Info.DstRes.Type == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, "Input attachment resource is expected");
+ RefCntAutoPtr<TextureViewVkImpl> pTexViewVk0{pTexView, IID_TextureViewVk};
+#ifdef DILIGENT_DEVELOPMENT
+ VerifyResourceViewBinding(*this, Info.VarType, Info.ArrayIndex, pTexView, pTexViewVk0.RawPtr(), {TEXTURE_VIEW_SHADER_RESOURCE}, Info.DstRes.pObject.RawPtr());
+#endif
+ if (UpdateCachedResource(Info, std::move(pTexViewVk0), [](const TextureViewVkImpl*, const TextureViewVkImpl*) {}))
+ {
+ // Do not update descriptor for a dynamic image. All dynamic resource descriptors
+ // are updated at once by CommitDynamicResources() when SRB is committed.
+ if (Info.vkDescrSet != VK_NULL_HANDLE && Info.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
+ {
+ VkDescriptorImageInfo DescrImgInfo = Info.DstRes.GetInputAttachmentDescriptorWriteInfo();
+ UpdateDescriptorHandle(Info, &DescrImgInfo, nullptr, nullptr);
+ }
+ //
+ }
+}
+
+void ShaderVariableVkImpl::CacheAccelerationStructure(IDeviceObject* pTLAS,
+ UpdateInfo& Info) const
+{
+ //VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::AccelerationStructure, "Acceleration Structure resource is expected");
+ RefCntAutoPtr<TopLevelASVkImpl> pTLASVk{pTLAS, IID_TopLevelASVk};
+#ifdef DILIGENT_DEVELOPMENT
+ VerifyTLASResourceBinding(*this, Info.VarType, Info.ArrayIndex, pTLASVk.RawPtr(), Info.DstRes.pObject.RawPtr());
+#endif
+ if (UpdateCachedResource(Info, std::move(pTLASVk), [](const TopLevelASVkImpl*, const TopLevelASVkImpl*) {}))
+ {
+ // Do not update descriptor for a dynamic TLAS. All dynamic resource descriptors
+ // are updated at once by CommitDynamicResources() when SRB is committed.
+ if (Info.vkDescrSet != VK_NULL_HANDLE && Info.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
+ {
+ VkWriteDescriptorSetAccelerationStructureKHR DescrASInfo = Info.DstRes.GetAccelerationStructureWriteInfo();
+ UpdateDescriptorHandle(Info, nullptr, nullptr, nullptr, &DescrASInfo);
+ }
+ //
+ }
+}
+
+bool ShaderVariableVkImpl::IsImmutableSamplerAssigned() const
+{
+ return true; // AZ TODO
+}
+
+void ShaderVariableVkImpl::UpdateDescriptorHandle(UpdateInfo& Info,
+ const VkDescriptorImageInfo* pImageInfo,
+ const VkDescriptorBufferInfo* pBufferInfo,
+ const VkBufferView* pTexelBufferView,
+ const VkWriteDescriptorSetAccelerationStructureKHR* pAccelStructInfo) const
+{
+ VERIFY_EXPR(Info.vkDescrSet != VK_NULL_HANDLE);
+
+ VkWriteDescriptorSet WriteDescrSet;
+ WriteDescrSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ WriteDescrSet.pNext = pAccelStructInfo;
+ WriteDescrSet.dstSet = Info.vkDescrSet;
+ WriteDescrSet.dstBinding = GetBinding().Binding;
+ WriteDescrSet.dstArrayElement = Info.ArrayIndex;
+ WriteDescrSet.descriptorCount = 1;
+ // descriptorType must be the same type as that specified in VkDescriptorSetLayoutBinding for dstSet at dstBinding.
+ // The type of the descriptor also controls which array the descriptors are taken from. (13.2.4)
+ WriteDescrSet.descriptorType = PipelineResourceSignatureVkImpl::GetVkDescriptorType(GetDesc());
+ WriteDescrSet.pImageInfo = pImageInfo;
+ WriteDescrSet.pBufferInfo = pBufferInfo;
+ WriteDescrSet.pTexelBufferView = pTexelBufferView;
+
+ m_ParentManager.m_pSignature->GetDevice()->GetLogicalDevice().UpdateDescriptorSets(1, &WriteDescrSet, 0, nullptr);
+}
+
+String ShaderVariableVkImpl::GetPrintName(Uint32 ArrayInd) const
+{
+ auto& ResDesc = GetDesc();
+ VERIFY_EXPR(ArrayInd < ResDesc.ArraySize);
+
+ if (ResDesc.ArraySize > 1)
+ {
+ std::stringstream ss;
+ ss << ResDesc.Name << '[' << ArrayInd << ']';
+ return ss.str();
+ }
+ else
+ return ResDesc.Name;
+}
+
+RESOURCE_DIMENSION ShaderVariableVkImpl::GetResourceDimension() const
+{
+ return GetDesc().ResourceDim;
+}
+
+bool ShaderVariableVkImpl::IsMultisample() const
+{
+ return false; // AZ TODO
}
} // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp
index 38320b47..264d49a5 100644
--- a/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp
@@ -1632,6 +1632,18 @@ VkShaderStageFlagBits ShaderTypeToVkShaderStageFlagBit(SHADER_TYPE ShaderType)
}
}
+VkShaderStageFlags ShaderTypesToVkShaderStageFlags(SHADER_TYPE ShaderTypes)
+{
+ VkShaderStageFlags Result = 0;
+ while (ShaderTypes != SHADER_TYPE_UNKNOWN)
+ {
+ auto Type = static_cast<SHADER_TYPE>(1u << PlatformMisc::GetLSB(Uint32{ShaderTypes}));
+ Result |= ShaderTypeToVkShaderStageFlagBit(Type);
+ ShaderTypes = ShaderTypes & ~Type;
+ }
+ return Result;
+}
+
VkBuildAccelerationStructureFlagsKHR BuildASFlagsToVkBuildAccelerationStructureFlags(RAYTRACING_BUILD_AS_FLAGS Flags)
{
static_assert(RAYTRACING_BUILD_AS_FLAGS_LAST == RAYTRACING_BUILD_AS_LOW_MEMORY,
@@ -1640,7 +1652,7 @@ VkBuildAccelerationStructureFlagsKHR BuildASFlagsToVkBuildAccelerationStructureF
VkBuildAccelerationStructureFlagsKHR Result = 0;
while (Flags != RAYTRACING_BUILD_AS_NONE)
{
- auto FlagBit = static_cast<RAYTRACING_BUILD_AS_FLAGS>(1 << PlatformMisc::GetLSB(Uint32{Flags}));
+ auto FlagBit = static_cast<RAYTRACING_BUILD_AS_FLAGS>(1u << PlatformMisc::GetLSB(Uint32{Flags}));
switch (FlagBit)
{
// clang-format off