summaryrefslogtreecommitdiffstats
path: root/Graphics/GraphicsEngineVulkan
diff options
context:
space:
mode:
authorassiduous <assiduous@diligentgraphics.com>2020-12-15 19:32:55 +0000
committerassiduous <assiduous@diligentgraphics.com>2020-12-15 19:32:55 +0000
commit2cbe12c8541f63719ae3662cda827ed53004c0b2 (patch)
tree6ff68d7ee7d386d1c0e30c00fcd551fcbf819c6c /Graphics/GraphicsEngineVulkan
parentMath Lib: added Matrix4x4 constructor from float4 rows (diff)
parentBasicMath: minor code formatting (diff)
downloadDiligentCore-2cbe12c8541f63719ae3662cda827ed53004c0b2.tar.gz
DiligentCore-2cbe12c8541f63719ae3662cda827ed53004c0b2.zip
Merge branch 'azhirnov-ray_tracing_2'
Diffstat (limited to 'Graphics/GraphicsEngineVulkan')
-rw-r--r--Graphics/GraphicsEngineVulkan/CMakeLists.txt9
-rw-r--r--Graphics/GraphicsEngineVulkan/include/BottomLevelASVkImpl.hpp80
-rw-r--r--Graphics/GraphicsEngineVulkan/include/BufferVkImpl.hpp3
-rw-r--r--Graphics/GraphicsEngineVulkan/include/DescriptorPoolManager.hpp12
-rw-r--r--Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp54
-rw-r--r--Graphics/GraphicsEngineVulkan/include/PipelineLayout.hpp7
-rw-r--r--Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp9
-rw-r--r--Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp52
-rw-r--r--Graphics/GraphicsEngineVulkan/include/ShaderBindingTableVkImpl.hpp58
-rw-r--r--Graphics/GraphicsEngineVulkan/include/ShaderResourceBindingVkImpl.hpp3
-rw-r--r--Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.hpp13
-rw-r--r--Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.hpp229
-rw-r--r--Graphics/GraphicsEngineVulkan/include/ShaderVariableVk.hpp4
-rw-r--r--Graphics/GraphicsEngineVulkan/include/TopLevelASVkImpl.hpp83
-rw-r--r--Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.hpp14
-rw-r--r--Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.hpp125
-rw-r--r--Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanHeaders.h6
-rw-r--r--Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanInstance.hpp10
-rw-r--r--Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanLogicalDevice.hpp36
-rw-r--r--Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanMemoryManager.hpp31
-rw-r--r--Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanObjectWrappers.hpp5
-rw-r--r--Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanPhysicalDevice.hpp24
-rw-r--r--Graphics/GraphicsEngineVulkan/interface/BottomLevelASVk.h69
-rw-r--r--Graphics/GraphicsEngineVulkan/interface/BufferVk.h4
-rw-r--r--Graphics/GraphicsEngineVulkan/interface/RenderDeviceVk.h40
-rw-r--r--Graphics/GraphicsEngineVulkan/interface/ShaderBindingTableVk.h67
-rw-r--r--Graphics/GraphicsEngineVulkan/interface/TopLevelASVk.h68
-rw-r--r--Graphics/GraphicsEngineVulkan/src/BottomLevelASVkImpl.cpp185
-rw-r--r--Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp165
-rw-r--r--Graphics/GraphicsEngineVulkan/src/CommandPoolManager.cpp7
-rw-r--r--Graphics/GraphicsEngineVulkan/src/DescriptorPoolManager.cpp38
-rw-r--r--Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp667
-rw-r--r--Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp136
-rw-r--r--Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp42
-rw-r--r--Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp479
-rw-r--r--Graphics/GraphicsEngineVulkan/src/QueryManagerVk.cpp2
-rw-r--r--Graphics/GraphicsEngineVulkan/src/QueryVkImpl.cpp2
-rw-r--r--Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp148
-rw-r--r--Graphics/GraphicsEngineVulkan/src/ShaderBindingTableVkImpl.cpp48
-rw-r--r--Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp4
-rw-r--r--Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp53
-rw-r--r--Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp807
-rw-r--r--Graphics/GraphicsEngineVulkan/src/ShaderVariableVk.cpp14
-rw-r--r--Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp8
-rw-r--r--Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp8
-rw-r--r--Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp18
-rw-r--r--Graphics/GraphicsEngineVulkan/src/TopLevelASVkImpl.cpp136
-rw-r--r--Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp214
-rw-r--r--Graphics/GraphicsEngineVulkan/src/VulkanUploadHeap.cpp2
-rw-r--r--Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBuffer.cpp87
-rw-r--r--Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanDebug.cpp26
-rw-r--r--Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanInstance.cpp44
-rw-r--r--Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanLogicalDevice.cpp102
-rw-r--r--Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanMemoryManager.cpp30
-rw-r--r--Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp76
55 files changed, 3878 insertions, 785 deletions
diff --git a/Graphics/GraphicsEngineVulkan/CMakeLists.txt b/Graphics/GraphicsEngineVulkan/CMakeLists.txt
index 1701c341..e5cd319c 100644
--- a/Graphics/GraphicsEngineVulkan/CMakeLists.txt
+++ b/Graphics/GraphicsEngineVulkan/CMakeLists.txt
@@ -36,6 +36,9 @@ set(INCLUDE
include/VulkanErrors.hpp
include/VulkanTypeConversions.hpp
include/VulkanUploadHeap.hpp
+ include/BottomLevelASVkImpl.hpp
+ include/TopLevelASVkImpl.hpp
+ include/ShaderBindingTableVkImpl.hpp
)
set(VULKAN_UTILS_INCLUDE
@@ -70,6 +73,9 @@ set(INTERFACE
interface/SwapChainVk.h
interface/TextureVk.h
interface/TextureViewVk.h
+ interface/BottomLevelASVk.h
+ interface/TopLevelASVk.h
+ interface/ShaderBindingTableVk.h
)
@@ -104,6 +110,9 @@ set(SRC
src/TextureViewVkImpl.cpp
src/VulkanTypeConversions.cpp
src/VulkanUploadHeap.cpp
+ src/BottomLevelASVkImpl.cpp
+ src/TopLevelASVkImpl.cpp
+ src/ShaderBindingTableVkImpl.cpp
)
set(VULKAN_UTILS_SRC
diff --git a/Graphics/GraphicsEngineVulkan/include/BottomLevelASVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/BottomLevelASVkImpl.hpp
new file mode 100644
index 00000000..d67fe937
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/include/BottomLevelASVkImpl.hpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2019-2020 Diligent Graphics LLC
+ * Copyright 2015-2019 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Definition of the Diligent::BottomLevelASVkImpl class
+
+#include "RenderDeviceVk.h"
+#include "RenderDeviceVkImpl.hpp"
+#include "BottomLevelASVk.h"
+#include "BottomLevelASBase.hpp"
+#include "VulkanUtilities/VulkanObjectWrappers.hpp"
+
+namespace Diligent
+{
+
+class BottomLevelASVkImpl final : public BottomLevelASBase<IBottomLevelASVk, RenderDeviceVkImpl>
+{
+public:
+ using TBottomLevelASBase = BottomLevelASBase<IBottomLevelASVk, RenderDeviceVkImpl>;
+
+ BottomLevelASVkImpl(IReferenceCounters* pRefCounters,
+ RenderDeviceVkImpl* pRenderDeviceVk,
+ const BottomLevelASDesc& Desc);
+ BottomLevelASVkImpl(IReferenceCounters* pRefCounters,
+ RenderDeviceVkImpl* pRenderDeviceVk,
+ const BottomLevelASDesc& Desc,
+ RESOURCE_STATE InitialState,
+ VkAccelerationStructureKHR vkBLAS);
+ ~BottomLevelASVkImpl();
+
+ /// Implementation of IBottomLevelAS::GetNativeHandle() in Vulkan backend.
+ virtual void* DILIGENT_CALL_TYPE GetNativeHandle() override final
+ {
+ auto Handle = GetVkBLAS();
+ return reinterpret_cast<void*>(Handle);
+ }
+
+ /// Implementation of IBottomLevelASVk::GetVkBLAS().
+ virtual VkAccelerationStructureKHR DILIGENT_CALL_TYPE GetVkBLAS() const override { return m_VulkanBLAS; }
+
+ /// Implementation of IBottomLevelASVk::GetVkDeviceAddress().
+ virtual VkDeviceAddress DILIGENT_CALL_TYPE GetVkDeviceAddress() const override { return m_DeviceAddress; }
+
+ IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_BottomLevelASVk, TBottomLevelASBase);
+
+private:
+ VkDeviceAddress m_DeviceAddress = 0;
+ VulkanUtilities::AccelStructWrapper m_VulkanBLAS;
+ VulkanUtilities::BufferWrapper m_VulkanBuffer;
+ VulkanUtilities::VulkanMemoryAllocation m_MemoryAllocation;
+ VkDeviceSize m_MemoryAlignedOffset = 0;
+};
+
+} // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/include/BufferVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/BufferVkImpl.hpp
index de95de16..90bfb884 100644
--- a/Graphics/GraphicsEngineVulkan/include/BufferVkImpl.hpp
+++ b/Graphics/GraphicsEngineVulkan/include/BufferVkImpl.hpp
@@ -106,6 +106,9 @@ public:
/// Implementation of IBufferVk::GetAccessFlags().
virtual VkAccessFlags DILIGENT_CALL_TYPE GetAccessFlags() const override final;
+ /// Implementation of IBufferVk::GetVkDeviceAddress().
+ virtual VkDeviceAddress DILIGENT_CALL_TYPE GetVkDeviceAddress() const override final;
+
bool CheckAccessFlags(VkAccessFlags AccessFlags) const
{
return (GetAccessFlags() & AccessFlags) == AccessFlags;
diff --git a/Graphics/GraphicsEngineVulkan/include/DescriptorPoolManager.hpp b/Graphics/GraphicsEngineVulkan/include/DescriptorPoolManager.hpp
index 98438da3..b60f3d89 100644
--- a/Graphics/GraphicsEngineVulkan/include/DescriptorPoolManager.hpp
+++ b/Graphics/GraphicsEngineVulkan/include/DescriptorPoolManager.hpp
@@ -137,17 +137,7 @@ public:
std::string PoolName,
std::vector<VkDescriptorPoolSize> PoolSizes,
uint32_t MaxSets,
- bool AllowFreeing) noexcept:
- m_DeviceVkImpl{DeviceVkImpl },
- m_PoolName {std::move(PoolName) },
- m_PoolSizes (std::move(PoolSizes)),
- m_MaxSets {MaxSets },
- m_AllowFreeing{AllowFreeing }
- {
-#ifdef DILIGENT_DEVELOPMENT
- m_AllocatedPoolCounter = 0;
-#endif
- }
+ bool AllowFreeing) noexcept;
~DescriptorPoolManager();
DescriptorPoolManager (const DescriptorPoolManager&) = delete;
diff --git a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp
index 093ab8d9..3ff38c4f 100644
--- a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp
+++ b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp
@@ -50,6 +50,9 @@
#include "HashUtils.hpp"
#include "ManagedVulkanObject.hpp"
#include "QueryManagerVk.hpp"
+#include "BottomLevelASVkImpl.hpp"
+#include "TopLevelASVkImpl.hpp"
+#include "ShaderBindingTableVkImpl.hpp"
namespace Diligent
@@ -65,6 +68,8 @@ struct DeviceContextVkImplTraits
using QueryType = QueryVkImpl;
using FramebufferType = FramebufferVkImpl;
using RenderPassType = RenderPassVkImpl;
+ using BottomLevelASType = BottomLevelASVkImpl;
+ using TopLevelASType = TopLevelASVkImpl;
};
/// Device context implementation in Vulkan backend.
@@ -249,6 +254,27 @@ public:
/// Implementation of IDeviceContext::Flush() in Vulkan backend.
virtual void DILIGENT_CALL_TYPE Flush() override final;
+ /// Implementation of IDeviceContext::BuildBLAS() in Vulkan backend.
+ virtual void DILIGENT_CALL_TYPE BuildBLAS(const BuildBLASAttribs& Attribs) override final;
+
+ /// Implementation of IDeviceContext::BuildTLAS() in Vulkan backend.
+ virtual void DILIGENT_CALL_TYPE BuildTLAS(const BuildTLASAttribs& Attribs) override final;
+
+ /// Implementation of IDeviceContext::CopyBLAS() in Vulkan backend.
+ virtual void DILIGENT_CALL_TYPE CopyBLAS(const CopyBLASAttribs& Attribs) override final;
+
+ /// Implementation of IDeviceContext::CopyTLAS() in Vulkan backend.
+ virtual void DILIGENT_CALL_TYPE CopyTLAS(const CopyTLASAttribs& Attribs) override final;
+
+ /// Implementation of IDeviceContext::WriteBLASCompactedSize() in Vulkan backend.
+ virtual void DILIGENT_CALL_TYPE WriteBLASCompactedSize(const WriteBLASCompactedSizeAttribs& Attribs) override final;
+
+ /// Implementation of IDeviceContext::WriteTLASCompactedSize() in Vulkan backend.
+ virtual void DILIGENT_CALL_TYPE WriteTLASCompactedSize(const WriteTLASCompactedSizeAttribs& Attribs) override final;
+
+ /// Implementation of IDeviceContext::TraceRays() in Vulkan backend.
+ virtual void DILIGENT_CALL_TYPE TraceRays(const TraceRaysAttribs& Attribs) override final;
+
// Transitions texture subresources from OldState to NewState, and optionally updates
// internal texture state.
// If OldState == RESOURCE_STATE_UNKNOWN, internal texture state is used as old state.
@@ -279,6 +305,20 @@ public:
virtual void DILIGENT_CALL_TYPE BufferMemoryBarrier(IBuffer* pBuffer, VkAccessFlags NewAccessFlags) override final;
+ // Transitions BLAS state from OldState to NewState, and optionally updates internal state.
+ // If OldState == RESOURCE_STATE_UNKNOWN, internal BLAS state is used as old state.
+ void TransitionBLASState(BottomLevelASVkImpl& BLAS,
+ RESOURCE_STATE OldState,
+ RESOURCE_STATE NewState,
+ bool UpdateInternalState);
+
+ // Transitions TLAS state from OldState to NewState, and optionally updates internal state.
+ // If OldState == RESOURCE_STATE_UNKNOWN, internal TLAS state is used as old state.
+ void TransitionTLASState(TopLevelASVkImpl& TLAS,
+ RESOURCE_STATE OldState,
+ RESOURCE_STATE NewState,
+ bool UpdateInternalState);
+
void AddWaitSemaphore(ManagedSemaphore* pWaitSemaphore, VkPipelineStageFlags WaitDstStageMask)
{
VERIFY_EXPR(pWaitSemaphore != nullptr);
@@ -369,6 +409,15 @@ private:
VkImageLayout ExpectedLayout,
const char* OperationName);
+ __forceinline void TransitionOrVerifyBLASState(BottomLevelASVkImpl& BLAS,
+ RESOURCE_STATE_TRANSITION_MODE TransitionMode,
+ RESOURCE_STATE RequiredState,
+ const char* OperationName);
+
+ __forceinline void TransitionOrVerifyTLASState(TopLevelASVkImpl& TLAS,
+ RESOURCE_STATE_TRANSITION_MODE TransitionMode,
+ RESOURCE_STATE RequiredState,
+ const char* OperationName);
__forceinline void EnsureVkCmdBuffer()
{
@@ -407,9 +456,12 @@ private:
__forceinline void PrepareForIndexedDraw(DRAW_FLAGS Flags, VALUE_TYPE IndexType);
__forceinline BufferVkImpl* PrepareIndirectDrawAttribsBuffer(IBuffer* pAttribsBuffer, RESOURCE_STATE_TRANSITION_MODE TransitonMode);
__forceinline void PrepareForDispatchCompute();
+ __forceinline void PrepareForRayTracing();
void DvpLogRenderPass_PSOMismatch();
+ void CreateASCompactedSizeQueryPool();
+
VulkanUtilities::VulkanCommandBuffer m_CommandBuffer;
struct ContextState
@@ -490,6 +542,8 @@ private:
Int32 m_ActiveQueriesCounter = 0;
std::vector<VkClearValue> m_vkClearValues;
+
+ VulkanUtilities::QueryPoolWrapper m_ASQueryPool;
};
} // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/include/PipelineLayout.hpp b/Graphics/GraphicsEngineVulkan/include/PipelineLayout.hpp
index 73fced1f..f9f51920 100644
--- a/Graphics/GraphicsEngineVulkan/include/PipelineLayout.hpp
+++ b/Graphics/GraphicsEngineVulkan/include/PipelineLayout.hpp
@@ -48,7 +48,7 @@ class ShaderResourceCacheVk;
class PipelineLayout
{
public:
- static VkDescriptorType GetVkDescriptorType(const SPIRVShaderResourceAttribs& Res);
+ static VkDescriptorType GetVkDescriptorType(SPIRVShaderResourceAttribs::ResourceType Type);
PipelineLayout();
void Release(RenderDeviceVkImpl* pDeviceVkImpl, Uint64 CommandQueueMask);
@@ -69,8 +69,7 @@ public:
SHADER_TYPE ShaderType,
Uint32& DescriptorSet,
Uint32& Binding,
- Uint32& OffsetInCache,
- std::vector<uint32_t>& SPIRV);
+ Uint32& OffsetInCache);
Uint32 GetTotalDescriptors(SHADER_RESOURCE_VARIABLE_TYPE VarType) const
{
@@ -137,7 +136,7 @@ public:
// set by the same Vulkan command. If there are no dynamic descriptors, this
// function also binds descriptor sets rightaway.
void PrepareDescriptorSets(DeviceContextVkImpl* pCtxVkImpl,
- bool IsCompute,
+ VkPipelineBindPoint BindPoint,
const ShaderResourceCacheVk& ResourceCache,
DescriptorSetBindInfo& BindInfo,
VkDescriptorSet VkDynamicDescrSet) const;
diff --git a/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp
index d4f2fc36..6aa4e073 100644
--- a/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp
+++ b/Graphics/GraphicsEngineVulkan/include/PipelineStateVkImpl.hpp
@@ -59,6 +59,7 @@ public:
PipelineStateVkImpl(IReferenceCounters* pRefCounters, RenderDeviceVkImpl* pDeviceVk, const GraphicsPipelineStateCreateInfo& CreateInfo);
PipelineStateVkImpl(IReferenceCounters* pRefCounters, RenderDeviceVkImpl* pDeviceVk, const ComputePipelineStateCreateInfo& CreateInfo);
+ PipelineStateVkImpl(IReferenceCounters* pRefCounters, RenderDeviceVkImpl* pDeviceVk, const RayTracingPipelineStateCreateInfo& CreateInfo);
~PipelineStateVkImpl();
virtual void DILIGENT_CALL_TYPE QueryInterface(const INTERFACE_ID& IID, IObject** ppInterface) override final;
@@ -128,10 +129,11 @@ public:
private:
using TShaderStages = ShaderResourceLayoutVk::TShaderStages;
- template <typename PSOCreateInfoType>
+ template <typename PSOCreateInfoType, typename InitPSODescType>
void InitInternalObjects(const PSOCreateInfoType& CreateInfo,
std::vector<VkPipelineShaderStageCreateInfo>& vkShaderStages,
- std::vector<VulkanUtilities::ShaderModuleWrapper>& ShaderModules);
+ std::vector<VulkanUtilities::ShaderModuleWrapper>& ShaderModules,
+ InitPSODescType InitPSODesc);
void InitResourceLayouts(const PipelineStateCreateInfo& CreateInfo,
TShaderStages& ShaderStages);
@@ -168,7 +170,8 @@ private:
// 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};
+ 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_HasStaticResources = false;
bool m_HasNonStaticResources = false;
diff --git a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp
index 469e8119..2b8408ce 100644
--- a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp
+++ b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.hpp
@@ -78,6 +78,9 @@ public:
/// Implementation of IRenderDevice::CreateComputePipelineState() in Vulkan backend.
virtual void DILIGENT_CALL_TYPE CreateComputePipelineState(const ComputePipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState) override final;
+ /// Implementation of IRenderDevice::CreateRayTracingPipelineState() in Vulkan backend.
+ virtual void DILIGENT_CALL_TYPE CreateRayTracingPipelineState(const RayTracingPipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState) override final;
+
/// Implementation of IRenderDevice::CreateBuffer() in Vulkan backend.
virtual void DILIGENT_CALL_TYPE CreateBuffer(const BufferDesc& BuffDesc,
const BufferData* pBuffData,
@@ -115,6 +118,18 @@ public:
virtual void DILIGENT_CALL_TYPE CreateFramebuffer(const FramebufferDesc& Desc,
IFramebuffer** ppFramebuffer) override final;
+ /// Implementation of IRenderDevice::CreateBLAS() in Vulkan backend.
+ virtual void DILIGENT_CALL_TYPE CreateBLAS(const BottomLevelASDesc& Desc,
+ IBottomLevelAS** ppBLAS) override final;
+
+ /// Implementation of IRenderDevice::CreateTLAS() in Vulkan backend.
+ virtual void DILIGENT_CALL_TYPE CreateTLAS(const TopLevelASDesc& Desc,
+ ITopLevelAS** ppTLAS) override final;
+
+ /// Implementation of IRenderDevice::CreateSBT() in Vulkan backend.
+ virtual void DILIGENT_CALL_TYPE CreateSBT(const ShaderBindingTableDesc& Desc,
+ IShaderBindingTable** ppSBT) override final;
+
/// Implementation of IRenderDeviceVk::GetVkDevice().
virtual VkDevice DILIGENT_CALL_TYPE GetVkDevice() override final { return m_LogicalVkDevice->GetVkDevice(); }
@@ -136,6 +151,18 @@ public:
RESOURCE_STATE InitialState,
IBuffer** ppBuffer) override final;
+ /// Implementation of IRenderDeviceVk::CreateBLASFromVulkanResource().
+ virtual void DILIGENT_CALL_TYPE CreateBLASFromVulkanResource(VkAccelerationStructureKHR vkBLAS,
+ const BottomLevelASDesc& Desc,
+ RESOURCE_STATE InitialState,
+ IBottomLevelAS** ppBLAS) override final;
+
+ /// Implementation of IRenderDeviceVk::CreateTLASFromVulkanResource().
+ virtual void DILIGENT_CALL_TYPE CreateTLASFromVulkanResource(VkAccelerationStructureKHR vkTLAS,
+ const TopLevelASDesc& Desc,
+ RESOURCE_STATE InitialState,
+ ITopLevelAS** ppTLAS) override final;
+
/// Implementation of IRenderDevice::IdleGPU() in Vulkan backend.
virtual void DILIGENT_CALL_TYPE IdleGPU() override final;
@@ -163,16 +190,16 @@ public:
FramebufferCache& GetFramebufferCache() { return m_FramebufferCache; }
RenderPassCache& GetImplicitRenderPassCache() { return m_ImplicitRenderPassCache; }
- VulkanUtilities::VulkanMemoryAllocation AllocateMemory(const VkMemoryRequirements& MemReqs, VkMemoryPropertyFlags MemoryProperties)
+ VulkanUtilities::VulkanMemoryAllocation AllocateMemory(const VkMemoryRequirements& MemReqs, VkMemoryPropertyFlags MemoryProperties, VkMemoryAllocateFlags AllocateFlags = 0)
{
- return m_MemoryMgr.Allocate(MemReqs, MemoryProperties);
+ return m_MemoryMgr.Allocate(MemReqs, MemoryProperties, AllocateFlags);
}
- VulkanUtilities::VulkanMemoryAllocation AllocateMemory(VkDeviceSize Size, VkDeviceSize Alignment, uint32_t MemoryTypeIndex)
+ VulkanUtilities::VulkanMemoryAllocation AllocateMemory(VkDeviceSize Size, VkDeviceSize Alignment, uint32_t MemoryTypeIndex, VkMemoryAllocateFlags AllocateFlags = 0)
{
const auto& MemoryProps = m_PhysicalDevice->GetMemoryProperties();
VERIFY_EXPR(MemoryTypeIndex < MemoryProps.memoryTypeCount);
const auto MemoryFlags = MemoryProps.memoryTypes[MemoryTypeIndex].propertyFlags;
- return m_MemoryMgr.Allocate(Size, Alignment, MemoryTypeIndex, (MemoryFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0);
+ return m_MemoryMgr.Allocate(Size, Alignment, MemoryTypeIndex, (MemoryFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0, AllocateFlags);
}
VulkanUtilities::VulkanMemoryManager& GetGlobalMemoryManager() { return m_MemoryMgr; }
@@ -182,6 +209,21 @@ public:
IDXCompiler* GetDxCompiler() const { return m_pDxCompiler.get(); }
+ struct Properties
+ {
+ const Uint32 ShaderGroupHandleSize;
+ const Uint32 MaxShaderRecordStride;
+ const Uint32 ShaderGroupBaseAlignment;
+ const Uint32 MaxDrawMeshTasksCount;
+ const Uint32 MaxRayTracingRecursionDepth;
+ const Uint32 MaxRayGenThreads;
+ };
+
+ const Properties& GetProperties() const
+ {
+ return m_Properties;
+ }
+
private:
template <typename PSOCreateInfoType>
void CreatePipelineState(const PSOCreateInfoType& PSOCreateInfo, IPipelineState** ppPipelineState);
@@ -216,6 +258,8 @@ private:
VulkanDynamicMemoryManager m_DynamicMemoryManager;
std::unique_ptr<IDXCompiler> m_pDxCompiler;
+
+ Properties m_Properties;
};
} // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderBindingTableVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/ShaderBindingTableVkImpl.hpp
new file mode 100644
index 00000000..6adc1677
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/include/ShaderBindingTableVkImpl.hpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2019-2020 Diligent Graphics LLC
+ * Copyright 2015-2019 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Definition of the Diligent::ShaderBindingTableVkImpl class
+
+#include "RenderDeviceVk.h"
+#include "RenderDeviceVkImpl.hpp"
+#include "ShaderBindingTableVk.h"
+#include "ShaderBindingTableBase.hpp"
+#include "TopLevelASVkImpl.hpp"
+#include "PipelineStateVkImpl.hpp"
+#include "VulkanUtilities/VulkanObjectWrappers.hpp"
+
+namespace Diligent
+{
+
+class ShaderBindingTableVkImpl final : public ShaderBindingTableBase<IShaderBindingTableVk, PipelineStateVkImpl, TopLevelASVkImpl, RenderDeviceVkImpl>
+{
+public:
+ using TShaderBindingTableBase = ShaderBindingTableBase<IShaderBindingTableVk, PipelineStateVkImpl, TopLevelASVkImpl, RenderDeviceVkImpl>;
+
+ ShaderBindingTableVkImpl(IReferenceCounters* pRefCounters,
+ RenderDeviceVkImpl* pRenderDeviceVk,
+ const ShaderBindingTableDesc& Desc,
+ bool bIsDeviceInternal = false);
+ ~ShaderBindingTableVkImpl();
+
+ IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_ShaderBindingTableVk, TShaderBindingTableBase);
+};
+
+} // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderResourceBindingVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/ShaderResourceBindingVkImpl.hpp
index 00f2c33a..0b427640 100644
--- a/Graphics/GraphicsEngineVulkan/include/ShaderResourceBindingVkImpl.hpp
+++ b/Graphics/GraphicsEngineVulkan/include/ShaderResourceBindingVkImpl.hpp
@@ -83,7 +83,8 @@ private:
// Resource layout index in m_ShaderResourceCache array for every shader stage,
// indexed by the shader type pipeline index (returned by GetShaderTypePipelineIndex)
- std::array<Int8, MAX_SHADERS_IN_PIPELINE> m_ResourceLayoutIndex = {-1, -1, -1, -1, -1};
+ std::array<Int8, MAX_SHADERS_IN_PIPELINE> m_ResourceLayoutIndex = {-1, -1, -1, -1, -1, -1};
+ static_assert(MAX_SHADERS_IN_PIPELINE == 6, "Please update the initializer list above");
bool m_bStaticResourcesInitialized = false;
Uint8 m_NumShaders = 0;
diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.hpp b/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.hpp
index 7d77ff48..0bcf79a0 100644
--- a/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.hpp
+++ b/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.hpp
@@ -112,12 +112,13 @@ public:
/*1-7*/ // Unused
/* 8 */ RefCntAutoPtr<IDeviceObject> pObject;
- VkDescriptorBufferInfo GetUniformBufferDescriptorWriteInfo () const;
- VkDescriptorBufferInfo GetStorageBufferDescriptorWriteInfo () const;
- VkDescriptorImageInfo GetImageDescriptorWriteInfo (bool IsImmutableSampler)const;
- VkBufferView GetBufferViewWriteInfo () const;
- VkDescriptorImageInfo GetSamplerDescriptorWriteInfo() const;
- VkDescriptorImageInfo GetInputAttachmentDescriptorWriteInfo() const;
+ VkDescriptorBufferInfo GetUniformBufferDescriptorWriteInfo () const;
+ VkDescriptorBufferInfo GetStorageBufferDescriptorWriteInfo () const;
+ VkDescriptorImageInfo GetImageDescriptorWriteInfo (bool IsImmutableSampler) const;
+ VkBufferView GetBufferViewWriteInfo () const;
+ VkDescriptorImageInfo GetSamplerDescriptorWriteInfo() const;
+ VkDescriptorImageInfo GetInputAttachmentDescriptorWriteInfo() const;
+ VkWriteDescriptorSetAccelerationStructureKHR GetAccelerationStructureWriteInfo() const;
// clang-format on
};
diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.hpp b/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.hpp
index 9452a390..88885eee 100644
--- a/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.hpp
+++ b/Graphics/GraphicsEngineVulkan/include/ShaderResourceLayoutVk.hpp
@@ -44,20 +44,9 @@
// d == m_NumResources[SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC]
//
//
+// Every ShaderVariableVkImpl variable managed by ShaderVariableManagerVk keeps a reference to corresponding VkResource.
//
-// * Every VkResource structure holds a reference to SPIRVShaderResourceAttribs structure from SPIRVShaderResources.
-// * ShaderResourceLayoutVk keeps a shared pointer to SPIRVShaderResources instance.
-// * Every ShaderVariableVkImpl variable managed by ShaderVariableManagerVk keeps a reference to corresponding VkResource.
-//
-//
-// ______________________ ________________________________________________________________________
-// | | unique_ptr | | | | | | | |
-// | SPIRVShaderResources |--------------->| UBs | SBs | StrgImgs | SmplImgs | ACs | SepSamplers | SepImgs |
-// |______________________| |________|_________|__________|__________|_______|_____________|_________|
-// A A A
-// | | |
-// |shared_ptr Ref Ref
-// ________|__________________ ________\____________________|_____________________________________________
+// ___________________________ ___________________________________________________________________________
// | | unique_ptr | | | | |
// | ShaderResourceLayoutVk |--------------->| VkResource[0] | VkResource[1] | ... | VkResource[s+m+d-1] |
// |___________________________| |___________________|_________________|_______________|_____________________|
@@ -99,13 +88,14 @@
#include <array>
#include <memory>
+#include <unordered_map>
#include "PipelineState.h"
#include "ShaderBase.hpp"
#include "HashUtils.hpp"
#include "ShaderResourceCacheVk.hpp"
-#include "SPIRVShaderResources.hpp"
#include "VulkanUtilities/VulkanLogicalDevice.hpp"
+#include "StringPool.hpp"
namespace Diligent
{
@@ -113,24 +103,30 @@ namespace Diligent
class ShaderVkImpl;
/// Diligent::ShaderResourceLayoutVk class
-// sizeof(ShaderResourceLayoutVk)==56 (MS compiler, x64)
+// sizeof(ShaderResourceLayoutVk)==40 (MS compiler, x64)
class ShaderResourceLayoutVk
{
public:
struct ShaderStageInfo
{
- ShaderStageInfo(SHADER_TYPE _Type,
- const ShaderVkImpl* _pShader);
+ ShaderStageInfo() {}
+ ShaderStageInfo(SHADER_TYPE Stage, const ShaderVkImpl* pShader);
- const SHADER_TYPE Type;
- const ShaderVkImpl* const pShader;
- std::vector<uint32_t> SPIRV;
+ void Append(const ShaderVkImpl* pShader);
+ size_t Count() const;
+
+ 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
@@ -144,10 +140,10 @@ public:
// This method is called by PipelineStateVkImpl class instance to initialize static
// shader resource layout and the cache
- void InitializeStaticResourceLayout(const ShaderVkImpl* pShader,
- IMemoryAllocator& LayoutDataAllocator,
- const PipelineResourceLayoutDesc& ResourceLayoutDesc,
- ShaderResourceCacheVk& StaticResourceCache);
+ void InitializeStaticResourceLayout(const std::vector<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.
@@ -160,7 +156,7 @@ public:
bool VerifyVariables,
bool VerifyImmutableSamplers);
- // sizeof(VkResource) == 24 (x64)
+ // sizeof(VkResource) == 32 (x64)
struct VkResource
{
// clang-format off
@@ -178,40 +174,82 @@ public:
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 SPIRVShaderResourceAttribs& SpirvAttribs;
-/* 16 */ const ShaderResourceLayoutVk& ParentResLayout;
-
- VkResource(const ShaderResourceLayoutVk& _ParentLayout,
- const SPIRVShaderResourceAttribs& _SpirvAttribs,
- SHADER_RESOURCE_VARIABLE_TYPE _VariableType,
- uint32_t _Binding,
- uint32_t _DescriptorSet,
- Uint32 _CacheOffset,
- Uint32 _SamplerInd,
- bool _ImmutableSamplerAssigned = false)noexcept :
+/* 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,
+ Uint16 _ArraySize,
+ ResourceType _Type,
+ RESOURCE_DIMENSION _ResourceDim,
+ bool _IsMS,
+ SHADER_RESOURCE_VARIABLE_TYPE _VariableType,
+ uint32_t _Binding,
+ uint32_t _DescriptorSet,
+ Uint32 _CacheOffset,
+ Uint32 _SamplerInd,
+ bool _ImmutableSamplerAssigned,
+ Uint32 _BufferStaticSize,
+ Uint32 _BufferStride) 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},
- SpirvAttribs {_SpirvAttribs },
- ParentResLayout {_ParentLayout }
+ ArraySize {_ArraySize },
+ Type {_Type },
+ ResourceDim {_ResourceDim },
+ IsMS {_IsMS ? Uint8{1} : Uint8{0}},
+#ifdef DILIGENT_DEVELOPMENT
+ BufferStaticSize {_BufferStaticSize},
+ BufferStride {_BufferStride },
+#endif
+ Name {_Name },
+ ParentResLayout {_ParentLayout }
+ // clang-format on
{
+#if defined(_MSC_VER) && defined(_WIN64) && !defined(DILIGENT_DEBUG)
+ 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(_ResourceDim < (1 << ResourceDimBits), "Resource dimension (", Uint32{_ResourceDim}, ") exceeds max representable value ", (1 << ResourceDimBits) );
+ // clang-format on
}
- // clang-format on
+
// Checks if a resource is bound in ResourceCache at the given ArrayIndex
bool IsBound(Uint32 ArrayIndex, const ShaderResourceCacheVk& ResourceCache) const;
@@ -220,17 +258,18 @@ public:
void BindResource(IDeviceObject* pObject, Uint32 ArrayIndex, ShaderResourceCacheVk& ResourceCache) const;
// Updates resource descriptor in the descriptor set
- inline void UpdateDescriptorHandle(VkDescriptorSet vkDescrSet,
- uint32_t ArrayElement,
- const VkDescriptorImageInfo* pImageInfo,
- const VkDescriptorBufferInfo* pBufferInfo,
- const VkBufferView* pTexelBufferView) const;
+ inline void UpdateDescriptorHandle(VkDescriptorSet vkDescrSet,
+ uint32_t ArrayElement,
+ const VkDescriptorImageInfo* pImageInfo,
+ const VkDescriptorBufferInfo* pBufferInfo,
+ const VkBufferView* pTexelBufferView,
+ const VkWriteDescriptorSetAccelerationStructureKHR* pAccelStructInfo = nullptr) const;
bool IsImmutableSamplerAssigned() const
{
VERIFY(ImmutableSamplerAssigned == 0 ||
- SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage ||
- SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler,
+ Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage ||
+ Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler,
"Immutable sampler can only be assigned to a sampled image or separate sampler");
return ImmutableSamplerAssigned != 0;
}
@@ -240,6 +279,44 @@ public:
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,
@@ -276,6 +353,11 @@ public:
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,
@@ -310,15 +392,10 @@ public:
const Char* GetShaderName() const
{
- return m_pResources->GetShaderName();
- }
-
- SHADER_TYPE GetShaderType() const
- {
- return m_pResources->GetShaderType();
+ return GetStringPoolData();
}
- const SPIRVShaderResources& GetResources() const { return *m_pResources; }
+ SHADER_TYPE GetShaderType() const { return m_ShaderType; }
const VkResource& GetResource(SHADER_RESOURCE_VARIABLE_TYPE VarType, Uint32 r) const
{
@@ -327,7 +404,9 @@ public:
return Resources[GetResourceOffset(VarType, r)];
}
- bool IsUsingSeparateSamplers() const { return !m_pResources->IsUsingCombinedSamplers(); }
+ bool IsUsingSeparateSamplers() const { return m_IsUsingSeparateSamplers; }
+
+ bool IsCompatibleWith(const ShaderResourceLayoutVk& ResLayout) const;
private:
Uint32 GetResourceOffset(SHADER_RESOURCE_VARIABLE_TYPE VarType, Uint32 r) const
@@ -349,7 +428,7 @@ private:
const VkResource& GetResource(Uint32 r) const
{
VERIFY_EXPR(r < GetTotalResourceCount());
- auto* Resources = reinterpret_cast<const VkResource*>(m_ResourceBuffer.get());
+ const auto* Resources = reinterpret_cast<const VkResource*>(m_ResourceBuffer.get());
return Resources[r];
}
@@ -358,12 +437,24 @@ private:
return m_NumResources[SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES];
}
- void AllocateMemory(const ShaderVkImpl* pShader,
- IMemoryAllocator& Allocator,
- const PipelineResourceLayoutDesc& ResourceLayoutDesc,
- const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes,
- Uint32 NumAllowedTypes,
- bool AllocateImmutableSamplers);
+ 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
@@ -374,16 +465,16 @@ private:
}
// clang-format off
-/* 0 */ const VulkanUtilities::VulkanLogicalDevice& m_LogicalDevice;
-/* 8 */ std::unique_ptr<void, STDDeleterRawMem<void> > m_ResourceBuffer;
+/* 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 = {};
- // We must use shared_ptr to reference ShaderResources instance, because
- // there may be multiple objects referencing the same set of resources
-/*24 */ std::shared_ptr<const SPIRVShaderResources> m_pResources;
+/*32 */ Uint16 m_NumImmutableSamplers = 0;
+/*34 */ bool m_IsUsingSeparateSamplers = false;
+/*36 */ SHADER_TYPE m_ShaderType = SHADER_TYPE_UNKNOWN;
-/*40 */ std::array<Uint16, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES+1> m_NumResources = {};
-/*48 */ Uint32 m_NumImmutableSamplers = 0;
-/*56*/ // End of class
+/*40 */ // End of class
// clang-format on
};
diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderVariableVk.hpp b/Graphics/GraphicsEngineVulkan/include/ShaderVariableVk.hpp
index 27689c1e..6c88bf56 100644
--- a/Graphics/GraphicsEngineVulkan/include/ShaderVariableVk.hpp
+++ b/Graphics/GraphicsEngineVulkan/include/ShaderVariableVk.hpp
@@ -183,14 +183,14 @@ public:
Uint32 FirstElement,
Uint32 NumElements) override final
{
- VerifyAndCorrectSetArrayArguments(m_Resource.SpirvAttribs.Name, m_Resource.SpirvAttribs.ArraySize, FirstElement, NumElements);
+ VerifyAndCorrectSetArrayArguments(m_Resource.Name, m_Resource.ArraySize, FirstElement, NumElements);
for (Uint32 Elem = 0; Elem < NumElements; ++Elem)
m_Resource.BindResource(ppObjects[Elem], FirstElement + Elem, m_ParentManager.m_ResourceCache);
}
virtual void DILIGENT_CALL_TYPE GetResourceDesc(ShaderResourceDesc& ResourceDesc) const override final
{
- ResourceDesc = m_Resource.SpirvAttribs.GetResourceDesc();
+ ResourceDesc = m_Resource.GetResourceDesc();
}
virtual Uint32 DILIGENT_CALL_TYPE GetIndex() const override final
diff --git a/Graphics/GraphicsEngineVulkan/include/TopLevelASVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/TopLevelASVkImpl.hpp
new file mode 100644
index 00000000..6eda1339
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/include/TopLevelASVkImpl.hpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2019-2020 Diligent Graphics LLC
+ * Copyright 2015-2019 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Definition of the Diligent::TopLevelASVkImpl class
+
+#include "RenderDeviceVk.h"
+#include "RenderDeviceVkImpl.hpp"
+#include "TopLevelASVk.h"
+#include "TopLevelASBase.hpp"
+#include "BottomLevelASVkImpl.hpp"
+#include "VulkanUtilities/VulkanObjectWrappers.hpp"
+
+namespace Diligent
+{
+
+class TopLevelASVkImpl final : public TopLevelASBase<ITopLevelASVk, BottomLevelASVkImpl, RenderDeviceVkImpl>
+{
+public:
+ using TTopLevelASBase = TopLevelASBase<ITopLevelASVk, BottomLevelASVkImpl, RenderDeviceVkImpl>;
+
+ TopLevelASVkImpl(IReferenceCounters* pRefCounters,
+ RenderDeviceVkImpl* pRenderDeviceVk,
+ const TopLevelASDesc& Desc);
+ TopLevelASVkImpl(IReferenceCounters* pRefCounters,
+ RenderDeviceVkImpl* pRenderDeviceVk,
+ const TopLevelASDesc& Desc,
+ RESOURCE_STATE InitialState,
+ VkAccelerationStructureKHR vkTLAS);
+ ~TopLevelASVkImpl();
+
+ IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_TopLevelASVk, TTopLevelASBase);
+
+ /// Implementation of ITopLevelAS::GetNativeHandle() in Vulkan backend.
+ virtual void* DILIGENT_CALL_TYPE GetNativeHandle() override final
+ {
+ auto Handle = GetVkTLAS();
+ return reinterpret_cast<void*>(Handle);
+ }
+
+ /// Implementation of ITopLevelASVk::GetVkTLAS().
+ virtual VkAccelerationStructureKHR DILIGENT_CALL_TYPE GetVkTLAS() const override { return m_VulkanTLAS; }
+
+ /// Implementation of ITopLevelASVk::GetVkDeviceAddress().
+ virtual VkDeviceAddress DILIGENT_CALL_TYPE GetVkDeviceAddress() const override { return m_DeviceAddress; }
+
+ const VkAccelerationStructureKHR* GetVkTLASPtr() const { return &m_VulkanTLAS; }
+
+private:
+ VkDeviceAddress m_DeviceAddress = 0;
+ VulkanUtilities::AccelStructWrapper m_VulkanTLAS;
+ VulkanUtilities::BufferWrapper m_VulkanBuffer;
+ VulkanUtilities::VulkanMemoryAllocation m_MemoryAllocation;
+ VkDeviceSize m_MemoryAlignedOffset = 0;
+};
+
+} // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.hpp b/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.hpp
index 1e6749f1..405e9bfa 100644
--- a/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.hpp
+++ b/Graphics/GraphicsEngineVulkan/include/VulkanTypeConversions.hpp
@@ -40,7 +40,8 @@ namespace Diligent
VkFormat TexFormatToVkFormat(TEXTURE_FORMAT TexFmt);
TEXTURE_FORMAT VkFormatToTexFormat(VkFormat VkFmt);
-VkFormat TypeToVkFormat(VALUE_TYPE ValType, Uint32 NumComponents, Bool bIsNormalized);
+VkFormat TypeToVkFormat(VALUE_TYPE ValType, Uint32 NumComponents, Bool bIsNormalized);
+VkIndexType TypeToVkIndexType(VALUE_TYPE IndexType);
VkPipelineRasterizationStateCreateInfo RasterizerStateDesc_To_VkRasterizationStateCI(const struct RasterizerStateDesc& RasterizerDesc);
VkPipelineDepthStencilStateCreateInfo DepthStencilStateDesc_To_VkDepthStencilStateCI(const struct DepthStencilStateDesc& DepthStencilDesc);
@@ -64,8 +65,10 @@ VkSamplerMipmapMode FilterTypeToVkMipmapMode(FILTER_TYPE FilterType);
VkSamplerAddressMode AddressModeToVkAddressMode(TEXTURE_ADDRESS_MODE AddressMode);
VkBorderColor BorderColorToVkBorderColor(const Float32 BorderColor[]);
-VkAccessFlags ResourceStateFlagsToVkAccessFlags(RESOURCE_STATE StateFlags);
-VkImageLayout ResourceStateToVkImageLayout(RESOURCE_STATE StateFlag, bool IsInsideRenderPass = false);
+VkPipelineStageFlags ResourceStateFlagsToVkPipelineStageFlags(RESOURCE_STATE StateFlags, VkPipelineStageFlags ShaderStages);
+VkAccessFlags ResourceStateFlagsToVkAccessFlags(RESOURCE_STATE StateFlags);
+VkAccessFlags AccelStructStateFlagsToVkAccessFlags(RESOURCE_STATE StateFlags);
+VkImageLayout ResourceStateToVkImageLayout(RESOURCE_STATE StateFlag, bool IsInsideRenderPass = false);
RESOURCE_STATE VkAccessFlagsToResourceStates(VkAccessFlags AccessFlags);
RESOURCE_STATE VkImageLayoutToResourceState(VkImageLayout Layout);
@@ -85,4 +88,9 @@ VkAccessFlags AccessFlagsToVkAccessFlags(ACCESS_FLAGS AccessFlags);
VkShaderStageFlagBits ShaderTypeToVkShaderStageFlagBit(SHADER_TYPE ShaderType);
+VkBuildAccelerationStructureFlagsKHR BuildASFlagsToVkBuildAccelerationStructureFlags(RAYTRACING_BUILD_AS_FLAGS Flags);
+VkGeometryFlagsKHR GeometryFlagsToVkGeometryFlags(RAYTRACING_GEOMETRY_FLAGS Flags);
+VkGeometryInstanceFlagsKHR InstanceFlagsToVkGeometryInstanceFlags(RAYTRACING_INSTANCE_FLAGS Flags);
+VkCopyAccelerationStructureModeKHR CopyASModeToVkCopyAccelerationStructureMode(COPY_AS_MODE Mode);
+
} // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.hpp b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.hpp
index 7d66600d..c0d79648 100644
--- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.hpp
+++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.hpp
@@ -36,8 +36,8 @@ namespace VulkanUtilities
class VulkanCommandBuffer
{
public:
- VulkanCommandBuffer(VkPipelineStageFlags EnabledGraphicsShaderStages) noexcept :
- m_EnabledGraphicsShaderStages{EnabledGraphicsShaderStages}
+ VulkanCommandBuffer(VkPipelineStageFlags EnabledShaderStages) noexcept :
+ m_EnabledShaderStages{EnabledShaderStages}
{}
// clang-format off
@@ -140,27 +140,27 @@ public:
__forceinline void DrawMesh(uint32_t TaskCount, uint32_t FirstTask)
{
-#ifdef VK_NV_mesh_shader
+#if DILIGENT_USE_VOLK
VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE);
VERIFY(m_State.RenderPass != VK_NULL_HANDLE, "vkCmdDrawMeshTasksNV() must be called inside render pass");
VERIFY(m_State.GraphicsPipeline != VK_NULL_HANDLE, "No graphics pipeline bound");
vkCmdDrawMeshTasksNV(m_VkCmdBuffer, TaskCount, FirstTask);
#else
- UNSUPPORTED("DrawMesh is not supported in current Vulkan headers");
+ UNSUPPORTED("DrawMesh is not supported when vulkan library is linked statically");
#endif
}
__forceinline void DrawMeshIndirect(VkBuffer Buffer, VkDeviceSize Offset, uint32_t DrawCount, uint32_t Stride)
{
-#ifdef VK_NV_mesh_shader
+#if DILIGENT_USE_VOLK
VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE);
VERIFY(m_State.RenderPass != VK_NULL_HANDLE, "vkCmdDrawMeshTasksNV() must be called inside render pass");
VERIFY(m_State.GraphicsPipeline != VK_NULL_HANDLE, "No graphics pipeline bound");
vkCmdDrawMeshTasksIndirectNV(m_VkCmdBuffer, Buffer, Offset, DrawCount, Stride);
#else
- UNSUPPORTED("DrawMeshIndirect is not supported in current Vulkan headers");
+ UNSUPPORTED("DrawMeshIndirect is not supported when vulkan library is linked statically");
#endif
}
@@ -280,6 +280,17 @@ public:
}
}
+ __forceinline void BindRayTracingPipeline(VkPipeline RayTracingPipeline)
+ {
+ // 9.8
+ VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE);
+ if (m_State.RayTracingPipeline != RayTracingPipeline)
+ {
+ vkCmdBindPipeline(m_VkCmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, RayTracingPipeline);
+ m_State.RayTracingPipeline = RayTracingPipeline;
+ }
+ }
+
__forceinline void SetViewports(uint32_t FirstViewport, uint32_t ViewportCount, const VkViewport* pViewports)
{
VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE);
@@ -331,7 +342,7 @@ public:
VkImageLayout OldLayout,
VkImageLayout NewLayout,
const VkImageSubresourceRange& SubresRange,
- VkPipelineStageFlags EnabledGraphicsShaderStages,
+ VkPipelineStageFlags EnabledShaderStages,
VkPipelineStageFlags SrcStages = 0,
VkPipelineStageFlags DestStages = 0);
@@ -349,7 +360,7 @@ public:
// dependencies between attachments
EndRenderPass();
}
- TransitionImageLayout(m_VkCmdBuffer, Image, OldLayout, NewLayout, SubresRange, m_EnabledGraphicsShaderStages, SrcStages, DestStages);
+ TransitionImageLayout(m_VkCmdBuffer, Image, OldLayout, NewLayout, SubresRange, m_EnabledShaderStages, SrcStages, DestStages);
}
@@ -357,7 +368,7 @@ public:
VkBuffer Buffer,
VkAccessFlags srcAccessMask,
VkAccessFlags dstAccessMask,
- VkPipelineStageFlags EnabledGraphicsShaderStages,
+ VkPipelineStageFlags EnabledShaderStages,
VkPipelineStageFlags SrcStages = 0,
VkPipelineStageFlags DestStages = 0);
@@ -374,7 +385,31 @@ public:
// dependencies between attachments
EndRenderPass();
}
- BufferMemoryBarrier(m_VkCmdBuffer, Buffer, srcAccessMask, dstAccessMask, m_EnabledGraphicsShaderStages, SrcStages, DestStages);
+ BufferMemoryBarrier(m_VkCmdBuffer, Buffer, srcAccessMask, dstAccessMask, m_EnabledShaderStages, SrcStages, DestStages);
+ }
+
+
+ // for Acceleration structures
+ static void ASMemoryBarrier(VkCommandBuffer CmdBuffer,
+ VkAccessFlags srcAccessMask,
+ VkAccessFlags dstAccessMask,
+ VkPipelineStageFlags EnabledShaderStages,
+ VkPipelineStageFlags SrcStages = 0,
+ VkPipelineStageFlags DestStages = 0);
+
+ __forceinline void ASMemoryBarrier(VkAccessFlags srcAccessMask,
+ VkAccessFlags dstAccessMask,
+ VkPipelineStageFlags SrcStages = 0,
+ VkPipelineStageFlags DestStages = 0)
+ {
+ VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE);
+ if (m_State.RenderPass != VK_NULL_HANDLE)
+ {
+ // Image layout transitions within a render pass execute
+ // dependencies between attachments
+ EndRenderPass();
+ }
+ ASMemoryBarrier(m_VkCmdBuffer, srcAccessMask, dstAccessMask, m_EnabledShaderStages, SrcStages, DestStages);
}
__forceinline void BindDescriptorSets(VkPipelineBindPoint pipelineBindPoint,
@@ -570,6 +605,71 @@ public:
dstBuffer, dstOffset, stride, flags);
}
+ __forceinline void BuildAccelerationStructure(uint32_t infoCount,
+ const VkAccelerationStructureBuildGeometryInfoKHR* pInfos,
+ const VkAccelerationStructureBuildRangeInfoKHR* const* ppBuildRangeInfos)
+ {
+#if DILIGENT_USE_VOLK
+ VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE);
+ if (m_State.RenderPass != VK_NULL_HANDLE)
+ {
+ // Build AS operations must be performed outside of render pass.
+ EndRenderPass();
+ }
+ vkCmdBuildAccelerationStructuresKHR(m_VkCmdBuffer, infoCount, pInfos, ppBuildRangeInfos);
+#else
+ UNSUPPORTED("Ray tracing is not supported when vulkan library is linked statically");
+#endif
+ }
+
+ __forceinline void CopyAccelerationStructure(const VkCopyAccelerationStructureInfoKHR& Info)
+ {
+#if DILIGENT_USE_VOLK
+ VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE);
+ if (m_State.RenderPass != VK_NULL_HANDLE)
+ {
+ // Copy AS operations must be performed outside of render pass.
+ EndRenderPass();
+ }
+ vkCmdCopyAccelerationStructureKHR(m_VkCmdBuffer, &Info);
+#else
+ UNSUPPORTED("Ray tracing is not supported when vulkan library is linked statically");
+#endif
+ }
+
+ __forceinline void WriteAccelerationStructuresProperties(VkAccelerationStructureKHR accelerationStructure, VkQueryType queryType, VkQueryPool queryPool, uint32_t firstQuery)
+ {
+#if DILIGENT_USE_VOLK
+ VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE);
+ if (m_State.RenderPass != VK_NULL_HANDLE)
+ {
+ // Write AS properties operations must be performed outside of render pass.
+ EndRenderPass();
+ }
+ vkCmdWriteAccelerationStructuresPropertiesKHR(m_VkCmdBuffer, 1, &accelerationStructure, queryType, queryPool, firstQuery);
+#else
+ UNSUPPORTED("Ray tracing is not supported when vulkan library is linked statically");
+#endif
+ }
+
+ __forceinline void TraceRays(const VkStridedDeviceAddressRegionKHR& RaygenShaderBindingTable,
+ const VkStridedDeviceAddressRegionKHR& MissShaderBindingTable,
+ const VkStridedDeviceAddressRegionKHR& HitShaderBindingTable,
+ const VkStridedDeviceAddressRegionKHR& CallableShaderBindingTable,
+ uint32_t width,
+ uint32_t height,
+ uint32_t depth)
+ {
+#if DILIGENT_USE_VOLK
+ VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE);
+ VERIFY(m_State.RayTracingPipeline != VK_NULL_HANDLE, "No ray tracing pipeline bound");
+
+ vkCmdTraceRaysKHR(m_VkCmdBuffer, &RaygenShaderBindingTable, &MissShaderBindingTable, &HitShaderBindingTable, &CallableShaderBindingTable, width, height, depth);
+#else
+ UNSUPPORTED("Ray tracing is not supported when vulkan library is linked statically");
+#endif
+ }
+
void FlushBarriers();
__forceinline void SetVkCmdBuffer(VkCommandBuffer VkCmdBuffer)
@@ -578,12 +678,15 @@ public:
}
VkCommandBuffer GetVkCmdBuffer() const { return m_VkCmdBuffer; }
+ VkPipelineStageFlags GetEnabledShaderStages() const { return m_EnabledShaderStages; }
+
struct StateCache
{
VkRenderPass RenderPass = VK_NULL_HANDLE;
VkFramebuffer Framebuffer = VK_NULL_HANDLE;
VkPipeline GraphicsPipeline = VK_NULL_HANDLE;
VkPipeline ComputePipeline = VK_NULL_HANDLE;
+ VkPipeline RayTracingPipeline = VK_NULL_HANDLE;
VkBuffer IndexBuffer = VK_NULL_HANDLE;
VkDeviceSize IndexBufferOffset = 0;
VkIndexType IndexType = VK_INDEX_TYPE_MAX_ENUM;
@@ -598,7 +701,7 @@ public:
private:
StateCache m_State;
VkCommandBuffer m_VkCmdBuffer = VK_NULL_HANDLE;
- const VkPipelineStageFlags m_EnabledGraphicsShaderStages;
+ const VkPipelineStageFlags m_EnabledShaderStages;
};
} // namespace VulkanUtilities
diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanHeaders.h b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanHeaders.h
index ee6461fd..bb95a9e4 100644
--- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanHeaders.h
+++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanHeaders.h
@@ -30,15 +30,13 @@
#if DILIGENT_USE_VOLK
# define VK_NO_PROTOTYPES
#endif
+
#include "vulkan/vulkan.h"
+
#define VK_FORMAT_RANGE_SIZE (VK_FORMAT_ASTC_12x12_SRGB_BLOCK - VK_FORMAT_UNDEFINED + 1)
#if DILIGENT_USE_VOLK
# include "volk/volk.h"
-#else
-// Don't use extensions when statically linked with Vulkan
-# undef VK_KHR_get_physical_device_properties2
-# undef VK_NV_mesh_shader
#endif
#if defined(VK_USE_PLATFORM_XLIB_KHR) || defined(_X11_XLIB_H_)
diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanInstance.hpp b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanInstance.hpp
index f5b921a6..e2bb7ad8 100644
--- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanInstance.hpp
+++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanInstance.hpp
@@ -44,7 +44,8 @@ public:
VulkanInstance& operator = ( VulkanInstance&&) = delete;
// clang-format on
- static std::shared_ptr<VulkanInstance> Create(bool EnableValidation,
+ static std::shared_ptr<VulkanInstance> Create(uint32_t ApiVersion,
+ bool EnableValidation,
uint32_t GlobalExtensionCount,
const char* const* ppGlobalExtensionNames,
VkAllocationCallbacks* pVkAllocator);
@@ -61,7 +62,7 @@ public:
}
// clang-format off
- bool IsLayerAvailable (const char* LayerName) const;
+ bool IsLayerAvailable (const char* LayerName, uint32_t& Version) const;
bool IsExtensionAvailable(const char* ExtensionName)const;
bool IsExtensionEnabled (const char* ExtensionName)const;
@@ -69,10 +70,12 @@ public:
VkAllocationCallbacks* GetVkAllocator()const{return m_pVkAllocator;}
VkInstance GetVkInstance() const{return m_VkInstance; }
+ uint32_t GetVkVersion() const{return m_VkVersion; }
// clang-format on
private:
- VulkanInstance(bool EnableValidation,
+ VulkanInstance(uint32_t ApiVersion,
+ bool EnableValidation,
uint32_t GlobalExtensionCount,
const char* const* ppGlobalExtensionNames,
VkAllocationCallbacks* pVkAllocator);
@@ -80,6 +83,7 @@ private:
bool m_DebugUtilsEnabled = false;
VkAllocationCallbacks* const m_pVkAllocator;
VkInstance m_VkInstance = VK_NULL_HANDLE;
+ uint32_t m_VkVersion = VK_API_VERSION_1_0;
std::vector<VkLayerProperties> m_Layers;
std::vector<VkExtensionProperties> m_Extensions;
diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanLogicalDevice.hpp b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanLogicalDevice.hpp
index 3f06cb0e..6d2d827c 100644
--- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanLogicalDevice.hpp
+++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanLogicalDevice.hpp
@@ -28,7 +28,7 @@
#pragma once
#include <memory>
-#include "VulkanHeaders.h"
+#include "VulkanPhysicalDevice.hpp"
namespace VulkanUtilities
{
@@ -57,7 +57,8 @@ enum class VulkanHandleTypeId : uint32_t
Semaphore,
Queue,
Event,
- QueryPool
+ QueryPool,
+ AccelerationStructureKHR
};
template <typename VulkanObjectType, VulkanHandleTypeId>
@@ -81,13 +82,17 @@ using DescriptorPoolWrapper = DEFINE_VULKAN_OBJECT_WRAPPER(DescriptorPool);
using DescriptorSetLayoutWrapper = DEFINE_VULKAN_OBJECT_WRAPPER(DescriptorSetLayout);
using SemaphoreWrapper = DEFINE_VULKAN_OBJECT_WRAPPER(Semaphore);
using QueryPoolWrapper = DEFINE_VULKAN_OBJECT_WRAPPER(QueryPool);
+using AccelStructWrapper = DEFINE_VULKAN_OBJECT_WRAPPER(AccelerationStructureKHR);
#undef DEFINE_VULKAN_OBJECT_WRAPPER
class VulkanLogicalDevice : public std::enable_shared_from_this<VulkanLogicalDevice>
{
public:
- static std::shared_ptr<VulkanLogicalDevice> Create(VkPhysicalDevice vkPhysicalDevice,
+ using ExtensionFeatures = VulkanPhysicalDevice::ExtensionFeatures;
+
+ static std::shared_ptr<VulkanLogicalDevice> Create(const VulkanPhysicalDevice& PhysicalDevice,
const VkDeviceCreateInfo& DeviceCI,
+ const ExtensionFeatures& EnabledExtFeatures,
const VkAllocationCallbacks* vkAllocator);
// clang-format off
@@ -129,8 +134,9 @@ public:
RenderPassWrapper CreateRenderPass (const VkRenderPassCreateInfo& RenderPassCI,const char* DebugName = "") const;
DeviceMemoryWrapper AllocateDeviceMemory(const VkMemoryAllocateInfo & AllocInfo, const char* DebugName = "") const;
- PipelineWrapper CreateComputePipeline (const VkComputePipelineCreateInfo& PipelineCI, VkPipelineCache cache, const char* DebugName = "") const;
- PipelineWrapper CreateGraphicsPipeline(const VkGraphicsPipelineCreateInfo& PipelineCI, VkPipelineCache cache, const char* DebugName = "") const;
+ PipelineWrapper CreateComputePipeline (const VkComputePipelineCreateInfo& PipelineCI, VkPipelineCache cache, const char* DebugName = "") const;
+ PipelineWrapper CreateGraphicsPipeline (const VkGraphicsPipelineCreateInfo& PipelineCI, VkPipelineCache cache, const char* DebugName = "") const;
+ PipelineWrapper CreateRayTracingPipeline(const VkRayTracingPipelineCreateInfoKHR& PipelineCI, VkPipelineCache cache, const char* DebugName = "") const;
ShaderModuleWrapper CreateShaderModule (const VkShaderModuleCreateInfo& ShaderModuleCI, const char* DebugName = "") const;
PipelineLayoutWrapper CreatePipelineLayout (const VkPipelineLayoutCreateInfo& LayoutCI, const char* DebugName = "") const;
@@ -140,6 +146,7 @@ public:
SemaphoreWrapper CreateSemaphore(const VkSemaphoreCreateInfo& SemaphoreCI, const char* DebugName = "") const;
QueryPoolWrapper CreateQueryPool(const VkQueryPoolCreateInfo& QueryPoolCI, const char* DebugName = "") const;
+ AccelStructWrapper CreateAccelStruct(const VkAccelerationStructureCreateInfoKHR& CI, const char* DebugName = "") const;
VkCommandBuffer AllocateVkCommandBuffer(const VkCommandBufferAllocateInfo& AllocInfo, const char* DebugName = "") const;
VkDescriptorSet AllocateVkDescriptorSet(const VkDescriptorSetAllocateInfo& AllocInfo, const char* DebugName = "") const;
@@ -161,11 +168,13 @@ public:
void ReleaseVulkanObject(DescriptorSetLayoutWrapper&& DescriptorSetLayout) const;
void ReleaseVulkanObject(SemaphoreWrapper&& Semaphore) const;
void ReleaseVulkanObject(QueryPoolWrapper&& QueryPool) const;
+ void ReleaseVulkanObject(AccelStructWrapper&& AccelStruct) const;
void FreeDescriptorSet(VkDescriptorPool Pool, VkDescriptorSet Set) const;
VkMemoryRequirements GetBufferMemoryRequirements(VkBuffer vkBuffer) const;
- VkMemoryRequirements GetImageMemoryRequirements (VkImage vkImage ) const;
+ VkMemoryRequirements GetImageMemoryRequirements (VkImage vkImage ) const;
+ VkDeviceAddress GetAccelerationStructureDeviceAddress(VkAccelerationStructureKHR AS) const;
VkResult BindBufferMemory(VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize memoryOffset) const;
VkResult BindImageMemory (VkImage image, VkDeviceMemory memory, VkDeviceSize memoryOffset) const;
@@ -207,13 +216,19 @@ public:
dataSize, pData, stride, flags);
}
- VkPipelineStageFlags GetEnabledGraphicsShaderStages() const { return m_EnabledGraphicsShaderStages; }
+ void GetAccelerationStructureBuildSizes(const VkAccelerationStructureBuildGeometryInfoKHR& BuildInfo, const uint32_t* pMaxPrimitiveCounts, VkAccelerationStructureBuildSizesInfoKHR& SizeInfo) const;
+
+ VkResult GetRayTracingShaderGroupHandles(VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void* pData) const;
+
+ VkPipelineStageFlags GetEnabledShaderStages() const { return m_EnabledShaderStages; }
const VkPhysicalDeviceFeatures& GetEnabledFeatures() const { return m_EnabledFeatures; }
+ const ExtensionFeatures& GetEnabledExtFeatures() const { return m_EnabledExtFeatures; }
private:
- VulkanLogicalDevice(VkPhysicalDevice vkPhysicalDevice,
+ VulkanLogicalDevice(const VulkanPhysicalDevice& PhysicalDevice,
const VkDeviceCreateInfo& DeviceCI,
+ const ExtensionFeatures& EnabledExtFeatures,
const VkAllocationCallbacks* vkAllocator);
template <typename VkObjectType,
@@ -227,8 +242,11 @@ private:
VkDevice m_VkDevice = VK_NULL_HANDLE;
const VkAllocationCallbacks* const m_VkAllocator;
- VkPipelineStageFlags m_EnabledGraphicsShaderStages = 0;
+ VkPipelineStageFlags m_EnabledShaderStages = 0;
const VkPhysicalDeviceFeatures m_EnabledFeatures;
+ ExtensionFeatures m_EnabledExtFeatures = {};
};
+void EnableRayTracingKHRviaNV();
+
} // namespace VulkanUtilities
diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanMemoryManager.hpp b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanMemoryManager.hpp
index 4ada51be..4d9eaa7f 100644
--- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanMemoryManager.hpp
+++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanMemoryManager.hpp
@@ -95,10 +95,11 @@ struct VulkanMemoryAllocation
class VulkanMemoryPage
{
public:
- VulkanMemoryPage(VulkanMemoryManager& ParentMemoryMgr,
- VkDeviceSize PageSize,
- uint32_t MemoryTypeIndex,
- bool IsHostVisible) noexcept;
+ VulkanMemoryPage(VulkanMemoryManager& ParentMemoryMgr,
+ VkDeviceSize PageSize,
+ uint32_t MemoryTypeIndex,
+ bool IsHostVisible,
+ VkMemoryAllocateFlags AllocateFlags) noexcept;
~VulkanMemoryPage();
// clang-format off
@@ -198,8 +199,8 @@ public:
VulkanMemoryManager& operator= (VulkanMemoryManager&&) = delete;
// clang-format on
- VulkanMemoryAllocation Allocate(VkDeviceSize Size, VkDeviceSize Alignment, uint32_t MemoryTypeIndex, bool HostVisible);
- VulkanMemoryAllocation Allocate(const VkMemoryRequirements& MemReqs, VkMemoryPropertyFlags MemoryProps);
+ VulkanMemoryAllocation Allocate(VkDeviceSize Size, VkDeviceSize Alignment, uint32_t MemoryTypeIndex, bool HostVisible, VkMemoryAllocateFlags AllocateFlags);
+ VulkanMemoryAllocation Allocate(const VkMemoryRequirements& MemReqs, VkMemoryPropertyFlags MemoryProps, VkMemoryAllocateFlags AllocateFlags);
void ShrinkMemory();
protected:
@@ -218,19 +219,23 @@ protected:
std::mutex m_PagesMtx;
struct MemoryPageIndex
{
- const uint32_t MemoryTypeIndex;
- const bool IsHostVisible;
+ const uint32_t MemoryTypeIndex;
+ const VkMemoryAllocateFlags AllocateFlags;
+ const bool IsHostVisible;
// clang-format off
- MemoryPageIndex(uint32_t _MemoryTypeIndex,
- bool _IsHostVisible) :
- MemoryTypeIndex(_MemoryTypeIndex),
- IsHostVisible (_IsHostVisible)
+ MemoryPageIndex(uint32_t _MemoryTypeIndex,
+ bool _IsHostVisible,
+ VkMemoryAllocateFlags _AllocateFlags) :
+ MemoryTypeIndex{_MemoryTypeIndex},
+ AllocateFlags {_AllocateFlags},
+ IsHostVisible {_IsHostVisible}
{}
bool operator == (const MemoryPageIndex& rhs)const
{
return MemoryTypeIndex == rhs.MemoryTypeIndex &&
+ AllocateFlags == rhs.AllocateFlags &&
IsHostVisible == rhs.IsHostVisible;
}
// clang-format on
@@ -239,7 +244,7 @@ protected:
{
size_t operator()(const MemoryPageIndex& PageIndex) const
{
- return Diligent::ComputeHash(PageIndex.MemoryTypeIndex, PageIndex.IsHostVisible);
+ return Diligent::ComputeHash(PageIndex.MemoryTypeIndex, PageIndex.AllocateFlags, PageIndex.IsHostVisible);
}
};
};
diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanObjectWrappers.hpp b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanObjectWrappers.hpp
index 7e2f8385..5e0390f5 100644
--- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanObjectWrappers.hpp
+++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanObjectWrappers.hpp
@@ -87,6 +87,11 @@ public:
return m_VkObject;
}
+ const VulkanObjectType* operator&() const
+ {
+ return &m_VkObject;
+ }
+
void Release()
{
// For externally managed objects, m_pLogicalDevice is null
diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanPhysicalDevice.hpp b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanPhysicalDevice.hpp
index b4e734c7..404e3eee 100644
--- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanPhysicalDevice.hpp
+++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanPhysicalDevice.hpp
@@ -39,10 +39,24 @@ class VulkanPhysicalDevice
public:
struct ExtensionFeatures
{
- VkPhysicalDeviceMeshShaderFeaturesNV MeshShader = {};
- VkPhysicalDevice16BitStorageFeaturesKHR Storage16Bit = {};
- VkPhysicalDevice8BitStorageFeaturesKHR Storage8Bit = {};
- VkPhysicalDeviceShaderFloat16Int8FeaturesKHR ShaderFloat16Int8 = {};
+ VkPhysicalDeviceMeshShaderFeaturesNV MeshShader = {};
+ VkPhysicalDevice16BitStorageFeaturesKHR Storage16Bit = {};
+ VkPhysicalDevice8BitStorageFeaturesKHR Storage8Bit = {};
+ VkPhysicalDeviceShaderFloat16Int8FeaturesKHR ShaderFloat16Int8 = {};
+ VkPhysicalDeviceAccelerationStructureFeaturesKHR AccelStruct = {};
+ VkPhysicalDeviceRayTracingPipelineFeaturesKHR RayTracingPipeline = {};
+ bool Spirv14 = false; // Ray tracing requires Vulkan 1.2 or SPIRV 1.4 extension
+ bool Spirv15 = false; // DXC shaders with ray tracing requires Vulkan 1.2 with SPIRV 1.5
+ VkPhysicalDeviceBufferDeviceAddressFeaturesKHR BufferDeviceAddress = {};
+ VkPhysicalDeviceDescriptorIndexingFeaturesEXT DescriptorIndexing = {};
+ };
+
+ struct ExtensionProperties
+ {
+ VkPhysicalDeviceMeshShaderPropertiesNV MeshShader = {};
+ VkPhysicalDeviceAccelerationStructurePropertiesKHR AccelStruct = {};
+ VkPhysicalDeviceRayTracingPipelinePropertiesKHR RayTracingPipeline = {};
+ VkPhysicalDeviceDescriptorIndexingPropertiesEXT DescriptorIndexing = {};
};
public:
@@ -70,6 +84,7 @@ public:
const VkPhysicalDeviceProperties& GetProperties() const { return m_Properties; }
const VkPhysicalDeviceFeatures& GetFeatures() const { return m_Features; }
const ExtensionFeatures& GetExtFeatures() const { return m_ExtFeatures; }
+ const ExtensionProperties& GetExtProperties() const { return m_ExtProperties; }
const VkPhysicalDeviceMemoryProperties& GetMemoryProperties() const { return m_MemoryProperties; }
VkFormatProperties GetPhysicalDeviceFormatProperties(VkFormat imageFormat) const;
@@ -82,6 +97,7 @@ private:
VkPhysicalDeviceFeatures m_Features = {};
VkPhysicalDeviceMemoryProperties m_MemoryProperties = {};
ExtensionFeatures m_ExtFeatures = {};
+ ExtensionProperties m_ExtProperties = {};
std::vector<VkQueueFamilyProperties> m_QueueFamilyProperties;
std::vector<VkExtensionProperties> m_SupportedExtensions;
};
diff --git a/Graphics/GraphicsEngineVulkan/interface/BottomLevelASVk.h b/Graphics/GraphicsEngineVulkan/interface/BottomLevelASVk.h
new file mode 100644
index 00000000..ea785a51
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/interface/BottomLevelASVk.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2019-2020 Diligent Graphics LLC
+ * Copyright 2015-2019 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Definition of the Diligent::IBottomLevelASVk interface
+
+#include "../../GraphicsEngine/interface/BottomLevelAS.h"
+
+DILIGENT_BEGIN_NAMESPACE(Diligent)
+
+
+// {7212AFC9-02E2-4D7F-81A8-1CE5353CEA2D}
+static const INTERFACE_ID IID_BottomLevelASVk =
+ {0x7212afc9, 0x2e2, 0x4d7f, {0x81, 0xa8, 0x1c, 0xe5, 0x35, 0x3c, 0xea, 0x2d}};
+
+#define DILIGENT_INTERFACE_NAME IBottomLevelASVk
+#include "../../../Primitives/interface/DefineInterfaceHelperMacros.h"
+
+#define IBottomLevelASVkInclusiveMethods \
+ IBottomLevelASInclusiveMethods; \
+ IBottomLevelASVkMethods BottomLevelASVk
+
+/// Exposes Vulkan-specific functionality of a Bottom-level acceleration structure object.
+DILIGENT_BEGIN_INTERFACE(IBottomLevelASVk, IBottomLevelAS)
+{
+ /// Returns a Vulkan BLAS object handle.
+ VIRTUAL VkAccelerationStructureKHR METHOD(GetVkBLAS)(THIS) CONST PURE;
+
+ /// Returns a Vulkan BLAS device address.
+ VIRTUAL VkDeviceAddress METHOD(GetVkDeviceAddress)(THIS) CONST PURE;
+};
+DILIGENT_END_INTERFACE
+
+#include "../../../Primitives/interface/UndefInterfaceHelperMacros.h"
+
+#if DILIGENT_C_INTERFACE
+
+# define IBottomLevelASVk_GetVkBLAS(This) CALL_IFACE_METHOD(BottomLevelASVk, GetVkBLAS, This)
+# define IBottomLevelASVk_GetVkDeviceAddress(This) CALL_IFACE_METHOD(BottomLevelASVk, GetVkDeviceAddress, This)
+
+#endif
+
+DILIGENT_END_NAMESPACE // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/interface/BufferVk.h b/Graphics/GraphicsEngineVulkan/interface/BufferVk.h
index ea889795..af1f8673 100644
--- a/Graphics/GraphicsEngineVulkan/interface/BufferVk.h
+++ b/Graphics/GraphicsEngineVulkan/interface/BufferVk.h
@@ -62,6 +62,9 @@ DILIGENT_BEGIN_INTERFACE(IBufferVk, IBuffer)
/// If the buffer state is known to the engine (i.e. not Diligent::RESOURCE_STATE_UNKNOWN),
/// returns Vulkan access flags corresponding to the state. If the state is unknown, returns 0.
VIRTUAL VkAccessFlags METHOD(GetAccessFlags)(THIS) CONST PURE;
+
+ /// Returns a Vulkan device address.
+ VIRTUAL VkDeviceAddress METHOD(GetVkDeviceAddress)(THIS) CONST PURE;
};
DILIGENT_END_INTERFACE
@@ -72,6 +75,7 @@ DILIGENT_END_INTERFACE
# define IBufferVk_GetVkBuffer(This) CALL_IFACE_METHOD(BufferVk, GetVkBuffer, This)
# define IBufferVk_SetAccessFlags(This, ...) CALL_IFACE_METHOD(BufferVk, SetAccessFlags, This, __VA_ARGS__)
# define IBufferVk_GetAccessFlags(This) CALL_IFACE_METHOD(BufferVk, GetAccessFlags, This)
+# define IBufferVk_GetVkDeviceAddress(This) CALL_IFACE_METHOD(BufferVk, GetVkDeviceAddress, This)
#endif
diff --git a/Graphics/GraphicsEngineVulkan/interface/RenderDeviceVk.h b/Graphics/GraphicsEngineVulkan/interface/RenderDeviceVk.h
index dfded94f..cba7f360 100644
--- a/Graphics/GraphicsEngineVulkan/interface/RenderDeviceVk.h
+++ b/Graphics/GraphicsEngineVulkan/interface/RenderDeviceVk.h
@@ -112,6 +112,44 @@ DILIGENT_BEGIN_INTERFACE(IRenderDeviceVk, IRenderDevice)
const BufferDesc REF BuffDesc,
RESOURCE_STATE InitialState,
IBuffer** ppBuffer) PURE;
+
+ /// Creates a bottom-level AS object from native Vulkan resource
+
+ /// \param [in] vkBLAS - Vulkan acceleration structure handle.
+ /// \param [in] Desc - Bottom-level AS description.
+ /// \param [in] InitialState - Initial BLAS state. Can be RESOURCE_STATE_UNKNOWN, RESOURCE_STATE_BUILD_AS_READ, RESOURCE_STATE_BUILD_AS_WRITE.
+ /// See Diligent::RESOURCE_STATE.
+ /// \param [out] ppBLAS - Address of the memory location where the pointer to the
+ /// bottom-level AS interface will be stored.
+ /// The function calls AddRef(), so that the new object will contain
+ /// one reference.
+ /// \note Created bottom-level AS object does not take ownership of the Vulkan acceleration structure and will not
+ /// destroy it once released. The application must not destroy Vulkan acceleration structure while it is
+ /// in use by the engine.
+ VIRTUAL void METHOD(CreateBLASFromVulkanResource)(THIS_
+ VkAccelerationStructureKHR vkBLAS,
+ const BottomLevelASDesc REF Desc,
+ RESOURCE_STATE InitialState,
+ IBottomLevelAS** ppBLAS) PURE;
+
+ /// Creates a top-level AS object from native Vulkan resource
+
+ /// \param [in] vkTLAS - Vulkan acceleration structure handle.
+ /// \param [in] Desc - Bottom-level AS description.
+ /// \param [in] InitialState - Initial TLAS state. Can be RESOURCE_STATE_UNKNOWN, RESOURCE_STATE_BUILD_AS_READ, RESOURCE_STATE_BUILD_AS_WRITE, RESOURCE_STATE_RAY_TRACING.
+ /// See Diligent::RESOURCE_STATE.
+ /// \param [out] ppTLAS - Address of the memory location where the pointer to the
+ /// top-level AS interface will be stored.
+ /// The function calls AddRef(), so that the new object will contain
+ /// one reference.
+ /// \note Created top-level AS object does not take ownership of the Vulkan acceleration structure and will not
+ /// destroy it once released. The application must not destroy Vulkan acceleration structure while it is
+ /// in use by the engine.
+ VIRTUAL void METHOD(CreateTLASFromVulkanResource)(THIS_
+ VkAccelerationStructureKHR vkTLAS,
+ const TopLevelASDesc REF Desc,
+ RESOURCE_STATE InitialState,
+ ITopLevelAS** ppTLAS) PURE;
};
DILIGENT_END_INTERFACE
@@ -129,6 +167,8 @@ DILIGENT_END_INTERFACE
# define IRenderDeviceVk_IsFenceSignaled(This, ...) CALL_IFACE_METHOD(RenderDeviceVk, IsFenceSignaled, This, __VA_ARGS__)
# define IRenderDeviceVk_CreateTextureFromVulkanImage(This, ...) CALL_IFACE_METHOD(RenderDeviceVk, CreateTextureFromVulkanImage, This, __VA_ARGS__)
# define IRenderDeviceVk_CreateBufferFromVulkanResource(This, ...) CALL_IFACE_METHOD(RenderDeviceVk, CreateBufferFromVulkanResource, This, __VA_ARGS__)
+# define IRenderDeviceVk_CreateBLASFromVulkanResource(This, ...) CALL_IFACE_METHOD(RenderDeviceVk, CreateBLASFromVulkanResource, This, __VA_ARGS__)
+# define IRenderDeviceVk_CreateTLASFromVulkanResource(This, ...) CALL_IFACE_METHOD(RenderDeviceVk, CreateTLASFromVulkanResource, This, __VA_ARGS__)
// clang-format on
diff --git a/Graphics/GraphicsEngineVulkan/interface/ShaderBindingTableVk.h b/Graphics/GraphicsEngineVulkan/interface/ShaderBindingTableVk.h
new file mode 100644
index 00000000..10970156
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/interface/ShaderBindingTableVk.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2019-2020 Diligent Graphics LLC
+ * Copyright 2015-2019 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Definition of the Diligent::IShaderBindingTableVk interface
+
+#include "../../GraphicsEngine/interface/ShaderBindingTable.h"
+#include "DeviceContextVk.h"
+
+DILIGENT_BEGIN_NAMESPACE(Diligent)
+
+// {31ED9B4B-4FF4-44D8-AE71-12B5D8AF7F93}
+static const INTERFACE_ID IID_ShaderBindingTableVk =
+ {0x31ed9b4b, 0x4ff4, 0x44d8, {0xae, 0x71, 0x12, 0xb5, 0xd8, 0xaf, 0x7f, 0x93}};
+
+#define DILIGENT_INTERFACE_NAME IShaderBindingTableVk
+#include "../../../Primitives/interface/DefineInterfaceHelperMacros.h"
+
+#define IShaderBindingTableVkInclusiveMethods \
+ IShaderBindingTableInclusiveMethods; \
+ IShaderBindingTableVkMethods ShaderBindingTableVk
+
+#if DILIGENT_CPP_INTERFACE // Empty structs are not allwed in C
+
+// clang-format off
+/// Exposes Vulkan-specific functionality of a Shader binding table object.
+DILIGENT_BEGIN_INTERFACE(IShaderBindingTableVk, IShaderBindingTable)
+{
+};
+DILIGENT_END_INTERFACE
+// clang-format on
+
+#endif
+
+#include "../../../Primitives/interface/UndefInterfaceHelperMacros.h"
+
+#if DILIGENT_C_INTERFACE
+
+#endif
+
+DILIGENT_END_NAMESPACE // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/interface/TopLevelASVk.h b/Graphics/GraphicsEngineVulkan/interface/TopLevelASVk.h
new file mode 100644
index 00000000..c09f10c0
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/interface/TopLevelASVk.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2019-2020 Diligent Graphics LLC
+ * Copyright 2015-2019 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Definition of the Diligent::ITopLevelASVk interface
+
+#include "../../GraphicsEngine/interface/TopLevelAS.h"
+
+DILIGENT_BEGIN_NAMESPACE(Diligent)
+
+// {356FFFFA-9E57-49F7-8FF4-7017B61BE6A8}
+static const INTERFACE_ID IID_TopLevelASVk =
+ {0x356ffffa, 0x9e57, 0x49f7, {0x8f, 0xf4, 0x70, 0x17, 0xb6, 0x1b, 0xe6, 0xa8}};
+
+#define DILIGENT_INTERFACE_NAME ITopLevelASVk
+#include "../../../Primitives/interface/DefineInterfaceHelperMacros.h"
+
+#define ITopLevelASVkInclusiveMethods \
+ ITopLevelASInclusiveMethods; \
+ ITopLevelASVkMethods TopLevelASVk
+
+/// Exposes Vulkan-specific functionality of a Top-level acceleration structure object.
+DILIGENT_BEGIN_INTERFACE(ITopLevelASVk, ITopLevelAS)
+{
+ /// Returns a Vulkan TLAS object handle.
+ VIRTUAL VkAccelerationStructureKHR METHOD(GetVkTLAS)(THIS) CONST PURE;
+
+ /// Returns a Vulkan TLAS device address.
+ VIRTUAL VkDeviceAddress METHOD(GetVkDeviceAddress)(THIS) CONST PURE;
+};
+DILIGENT_END_INTERFACE
+
+#include "../../../Primitives/interface/UndefInterfaceHelperMacros.h"
+
+#if DILIGENT_C_INTERFACE
+
+# define ITopLevelASVk_GetVkTLAS(This) CALL_IFACE_METHOD(TopLevelASVk, GetVkTLAS, This)
+# define ITopLevelASVk_GetVkDeviceAddress(This) CALL_IFACE_METHOD(TopLevelASVk, GetVkDeviceAddress, This)
+
+#endif
+
+DILIGENT_END_NAMESPACE // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/src/BottomLevelASVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/BottomLevelASVkImpl.cpp
new file mode 100644
index 00000000..19253b1f
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/src/BottomLevelASVkImpl.cpp
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2019-2020 Diligent Graphics LLC
+ * Copyright 2015-2019 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#include "pch.h"
+#include "BottomLevelASVkImpl.hpp"
+#include "VulkanTypeConversions.hpp"
+
+namespace Diligent
+{
+
+BottomLevelASVkImpl::BottomLevelASVkImpl(IReferenceCounters* pRefCounters,
+ RenderDeviceVkImpl* pRenderDeviceVk,
+ const BottomLevelASDesc& Desc) :
+ TBottomLevelASBase{pRefCounters, pRenderDeviceVk, Desc}
+{
+ const auto& LogicalDevice = pRenderDeviceVk->GetLogicalDevice();
+ const auto& PhysicalDevice = pRenderDeviceVk->GetPhysicalDevice();
+ const auto& Limits = PhysicalDevice.GetExtProperties().AccelStruct;
+ Uint32 AccelStructSize = m_Desc.CompactedSize;
+
+ if (AccelStructSize == 0)
+ {
+ VkAccelerationStructureBuildGeometryInfoKHR vkBuildInfo = {};
+ std::vector<VkAccelerationStructureGeometryKHR> vkGeometries;
+ std::vector<uint32_t> MaxPrimitiveCounts;
+ VkAccelerationStructureBuildSizesInfoKHR vkSizeInfo = {VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR};
+
+ vkGeometries.resize(Desc.TriangleCount + Desc.BoxCount);
+ MaxPrimitiveCounts.resize(vkGeometries.size());
+
+ if (m_Desc.pTriangles != nullptr)
+ {
+ Uint32 MaxPrimitiveCount = 0;
+ for (uint32_t i = 0; i < m_Desc.TriangleCount; ++i)
+ {
+ auto& src = m_Desc.pTriangles[i];
+ auto& dst = vkGeometries[i];
+ auto& tri = dst.geometry.triangles;
+
+ dst.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR;
+ dst.pNext = nullptr;
+ dst.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR;
+ dst.flags = VkGeometryFlagsKHR(0);
+
+ tri.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR;
+ tri.pNext = nullptr;
+ tri.vertexFormat = TypeToVkFormat(src.VertexValueType, src.VertexComponentCount, src.VertexValueType < VT_FLOAT16);
+ tri.maxVertex = src.MaxVertexCount;
+ tri.indexType = TypeToVkIndexType(src.IndexType);
+ tri.transformData.deviceAddress = src.AllowsTransforms ? 1 : 0;
+ MaxPrimitiveCounts[i] = src.MaxPrimitiveCount;
+
+ MaxPrimitiveCount += src.MaxPrimitiveCount;
+ }
+ VERIFY_EXPR(MaxPrimitiveCount <= Limits.maxPrimitiveCount);
+ }
+ else if (m_Desc.pBoxes != nullptr)
+ {
+ Uint32 MaxBoxCount = 0;
+ for (uint32_t i = 0; i < m_Desc.BoxCount; ++i)
+ {
+ auto& src = m_Desc.pBoxes[i];
+ auto& dst = vkGeometries[i];
+ auto& box = dst.geometry.aabbs;
+
+ dst.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR;
+ dst.pNext = nullptr;
+ dst.geometryType = VK_GEOMETRY_TYPE_AABBS_KHR;
+
+ box.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR;
+ box.pNext = nullptr;
+ MaxPrimitiveCounts[i] = src.MaxBoxCount;
+
+ MaxBoxCount += src.MaxBoxCount;
+ }
+ VERIFY_EXPR(MaxBoxCount <= Limits.maxPrimitiveCount);
+ }
+ else
+ {
+ UNEXPECTED("Either pTriangles or pBoxes must not be null");
+ }
+
+ vkBuildInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR;
+ vkBuildInfo.flags = BuildASFlagsToVkBuildAccelerationStructureFlags(m_Desc.Flags);
+ vkBuildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
+ vkBuildInfo.pGeometries = vkGeometries.data();
+ vkBuildInfo.geometryCount = static_cast<uint32_t>(vkGeometries.size());
+
+ VERIFY_EXPR(vkBuildInfo.geometryCount <= Limits.maxGeometryCount);
+
+ LogicalDevice.GetAccelerationStructureBuildSizes(vkBuildInfo, MaxPrimitiveCounts.data(), vkSizeInfo);
+
+ AccelStructSize = static_cast<Uint32>(vkSizeInfo.accelerationStructureSize);
+ m_ScratchSize.Build = static_cast<Uint32>(vkSizeInfo.buildScratchSize);
+ m_ScratchSize.Update = static_cast<Uint32>(vkSizeInfo.updateScratchSize);
+ }
+
+ VkBufferCreateInfo vkBuffCI = {};
+
+ vkBuffCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+ vkBuffCI.flags = 0;
+ vkBuffCI.size = AccelStructSize;
+ vkBuffCI.usage = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR;
+ vkBuffCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+ vkBuffCI.queueFamilyIndexCount = 0;
+ vkBuffCI.pQueueFamilyIndices = nullptr;
+
+ m_VulkanBuffer = LogicalDevice.CreateBuffer(vkBuffCI, m_Desc.Name);
+
+ VkMemoryRequirements MemReqs = LogicalDevice.GetBufferMemoryRequirements(m_VulkanBuffer);
+ uint32_t MemoryTypeIndex = PhysicalDevice.GetMemoryTypeIndex(MemReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+
+ VERIFY(IsPowerOfTwo(MemReqs.alignment), "Alignment is not power of 2!");
+ m_MemoryAllocation = pRenderDeviceVk->AllocateMemory(MemReqs.size, MemReqs.alignment, MemoryTypeIndex, VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT);
+
+ m_MemoryAlignedOffset = Align(VkDeviceSize{m_MemoryAllocation.UnalignedOffset}, MemReqs.alignment);
+ VERIFY(m_MemoryAllocation.Size >= MemReqs.size + (m_MemoryAlignedOffset - m_MemoryAllocation.UnalignedOffset), "Size of memory allocation is too small");
+ auto Memory = m_MemoryAllocation.Page->GetVkMemory();
+ auto err = LogicalDevice.BindBufferMemory(m_VulkanBuffer, Memory, m_MemoryAlignedOffset);
+ CHECK_VK_ERROR_AND_THROW(err, "Failed to bind buffer memory");
+
+ VkAccelerationStructureCreateInfoKHR vkAccelStrCI = {};
+
+ vkAccelStrCI.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR;
+ vkAccelStrCI.createFlags = 0;
+ vkAccelStrCI.buffer = m_VulkanBuffer;
+ vkAccelStrCI.offset = 0;
+ vkAccelStrCI.size = AccelStructSize;
+ vkAccelStrCI.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
+
+ m_VulkanBLAS = LogicalDevice.CreateAccelStruct(vkAccelStrCI, m_Desc.Name);
+
+ m_DeviceAddress = LogicalDevice.GetAccelerationStructureDeviceAddress(m_VulkanBLAS);
+
+ SetState(RESOURCE_STATE_BUILD_AS_READ);
+}
+
+BottomLevelASVkImpl::BottomLevelASVkImpl(IReferenceCounters* pRefCounters,
+ RenderDeviceVkImpl* pRenderDeviceVk,
+ const BottomLevelASDesc& Desc,
+ RESOURCE_STATE InitialState,
+ VkAccelerationStructureKHR vkBLAS) :
+ TBottomLevelASBase{pRefCounters, pRenderDeviceVk, Desc},
+ m_VulkanBLAS{vkBLAS}
+{
+ SetState(InitialState);
+ m_DeviceAddress = pRenderDeviceVk->GetLogicalDevice().GetAccelerationStructureDeviceAddress(m_VulkanBLAS);
+}
+
+BottomLevelASVkImpl::~BottomLevelASVkImpl()
+{
+ // Vk object can only be destroyed when it is no longer used by the GPU
+ if (m_VulkanBLAS != VK_NULL_HANDLE)
+ m_pDevice->SafeReleaseDeviceObject(std::move(m_VulkanBLAS), m_Desc.CommandQueueMask);
+ if (m_VulkanBuffer != VK_NULL_HANDLE)
+ m_pDevice->SafeReleaseDeviceObject(std::move(m_VulkanBuffer), m_Desc.CommandQueueMask);
+ if (m_MemoryAllocation.Page != nullptr)
+ m_pDevice->SafeReleaseDeviceObject(std::move(m_MemoryAllocation), m_Desc.CommandQueueMask);
+}
+
+} // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp
index 0d41ec33..06bb887a 100644
--- a/Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/BufferVkImpl.cpp
@@ -86,54 +86,89 @@ BufferVkImpl::BufferVkImpl(IReferenceCounters* pRefCounters,
VkBuffCI.usage =
VK_BUFFER_USAGE_TRANSFER_SRC_BIT | // The buffer can be used as the source of a transfer command
VK_BUFFER_USAGE_TRANSFER_DST_BIT; // The buffer can be used as the destination of a transfer command
- if (m_Desc.BindFlags & BIND_UNORDERED_ACCESS)
- {
- // VkBuffCI.usage |= m_Desc.Mode == BUFFER_MODE_FORMATTED ? VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT : VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
- // HLSL formatted buffers are mapped to GLSL storage buffers:
- //
- // RWBuffer<uint4> RWBuff
- //
- // |
- // V
- //
- // layout(std140, binding = 3) buffer RWBuff
- // {
- // uvec4 data[];
- // }g_RWBuff;
- //
- // So we have to set both VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT and VK_BUFFER_USAGE_STORAGE_BUFFER_BIT bits
- VkBuffCI.usage |= VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
-
- // Each element of pDynamicOffsets of vkCmdBindDescriptorSets function which corresponds to a descriptor
- // binding with type VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC must be a multiple of
- // VkPhysicalDeviceLimits::minStorageBufferOffsetAlignment (13.2.5)
- m_DynamicOffsetAlignment = std::max(m_DynamicOffsetAlignment, static_cast<Uint32>(DeviceLimits.minTexelBufferOffsetAlignment));
- m_DynamicOffsetAlignment = std::max(m_DynamicOffsetAlignment, static_cast<Uint32>(DeviceLimits.minStorageBufferOffsetAlignment));
- }
- if (m_Desc.BindFlags & BIND_SHADER_RESOURCE)
- {
- // VkBuffCI.usage |= m_Desc.Mode == BUFFER_MODE_FORMATTED ? VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT : VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
- // HLSL buffer SRVs are mapped to storge buffers in GLSL, so we need to set both
- // VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT and VK_BUFFER_USAGE_STORAGE_BUFFER_BIT flags
- VkBuffCI.usage |= VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
- m_DynamicOffsetAlignment = std::max(m_DynamicOffsetAlignment, static_cast<Uint32>(DeviceLimits.minTexelBufferOffsetAlignment));
- m_DynamicOffsetAlignment = std::max(m_DynamicOffsetAlignment, static_cast<Uint32>(DeviceLimits.minStorageBufferOffsetAlignment));
- }
- if (m_Desc.BindFlags & BIND_VERTEX_BUFFER)
- VkBuffCI.usage |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
- if (m_Desc.BindFlags & BIND_INDEX_BUFFER)
- VkBuffCI.usage |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
- if (m_Desc.BindFlags & BIND_INDIRECT_DRAW_ARGS)
- VkBuffCI.usage |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
- if (m_Desc.BindFlags & BIND_UNIFORM_BUFFER)
+ static_assert(BIND_FLAGS_LAST == 0x400, "Please update this function to handle the new bind flags");
+
+ for (Uint32 BindFlag = 1; BindFlag <= m_Desc.BindFlags; BindFlag <<= 1)
{
- VkBuffCI.usage |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
+ if ((m_Desc.BindFlags & BindFlag) != BindFlag)
+ continue;
- // Each element of pDynamicOffsets parameter of vkCmdBindDescriptorSets function which corresponds to a descriptor
- // binding with type VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC must be a multiple of
- // VkPhysicalDeviceLimits::minUniformBufferOffsetAlignment (13.2.5)
- m_DynamicOffsetAlignment = std::max(m_DynamicOffsetAlignment, static_cast<Uint32>(DeviceLimits.minUniformBufferOffsetAlignment));
+ switch (BindFlag)
+ {
+ case BIND_UNORDERED_ACCESS:
+ {
+ // VkBuffCI.usage |= m_Desc.Mode == BUFFER_MODE_FORMATTED ? VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT : VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
+ // HLSL formatted buffers are mapped to GLSL storage buffers:
+ //
+ // RWBuffer<uint4> RWBuff
+ //
+ // |
+ // V
+ //
+ // layout(std140, binding = 3) buffer RWBuff
+ // {
+ // uvec4 data[];
+ // }g_RWBuff;
+ //
+ // So we have to set both VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT and VK_BUFFER_USAGE_STORAGE_BUFFER_BIT bits
+ VkBuffCI.usage |= VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
+
+ // Each element of pDynamicOffsets of vkCmdBindDescriptorSets function which corresponds to a descriptor
+ // binding with type VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC must be a multiple of
+ // VkPhysicalDeviceLimits::minStorageBufferOffsetAlignment (13.2.5)
+ m_DynamicOffsetAlignment = std::max(m_DynamicOffsetAlignment, static_cast<Uint32>(DeviceLimits.minTexelBufferOffsetAlignment));
+ m_DynamicOffsetAlignment = std::max(m_DynamicOffsetAlignment, static_cast<Uint32>(DeviceLimits.minStorageBufferOffsetAlignment));
+ break;
+ }
+ case BIND_SHADER_RESOURCE:
+ {
+ // VkBuffCI.usage |= m_Desc.Mode == BUFFER_MODE_FORMATTED ? VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT : VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
+ // HLSL buffer SRVs are mapped to storge buffers in GLSL, so we need to set both
+ // VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT and VK_BUFFER_USAGE_STORAGE_BUFFER_BIT flags
+ VkBuffCI.usage |= VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
+
+ m_DynamicOffsetAlignment = std::max(m_DynamicOffsetAlignment, static_cast<Uint32>(DeviceLimits.minTexelBufferOffsetAlignment));
+ m_DynamicOffsetAlignment = std::max(m_DynamicOffsetAlignment, static_cast<Uint32>(DeviceLimits.minStorageBufferOffsetAlignment));
+ break;
+ }
+ case BIND_VERTEX_BUFFER:
+ {
+ VkBuffCI.usage |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
+ break;
+ }
+ case BIND_INDEX_BUFFER:
+ {
+ VkBuffCI.usage |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
+ break;
+ }
+ case BIND_INDIRECT_DRAW_ARGS:
+ {
+ VkBuffCI.usage |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
+ break;
+ }
+ case BIND_UNIFORM_BUFFER:
+ {
+ VkBuffCI.usage |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
+
+ // Each element of pDynamicOffsets parameter of vkCmdBindDescriptorSets function which corresponds to a descriptor
+ // binding with type VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC must be a multiple of
+ // VkPhysicalDeviceLimits::minUniformBufferOffsetAlignment (13.2.5)
+ m_DynamicOffsetAlignment = std::max(m_DynamicOffsetAlignment, static_cast<Uint32>(DeviceLimits.minUniformBufferOffsetAlignment));
+ break;
+ }
+ case BIND_RAY_TRACING:
+ {
+ VkBuffCI.usage |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; // for scratch buffer
+ VkBuffCI.usage |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
+ VkBuffCI.usage |= VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR; // acceleration structure build inputs such as vertex, index, transform, aabb, and instance data
+ VkBuffCI.usage |= VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR;
+ break;
+ }
+ default:
+ UNEXPECTED("unsupported buffer binding type");
+ break;
+ }
}
if (m_Desc.Usage == USAGE_DYNAMIC)
@@ -213,11 +248,15 @@ BufferVkImpl::BufferVkImpl(IReferenceCounters* pRefCounters,
MemoryTypeIndex = PhysicalDevice.GetMemoryTypeIndex(MemReqs.memoryTypeBits, vkMemoryFlags);
}
+ VkMemoryAllocateFlags AllocateFlags = 0;
+ if (VkBuffCI.usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT)
+ AllocateFlags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
+
if (MemoryTypeIndex == VulkanUtilities::VulkanPhysicalDevice::InvalidMemoryTypeIndex)
LOG_ERROR_AND_THROW("Failed to find suitable memory type for buffer '", m_Desc.Name, '\'');
VERIFY(IsPowerOfTwo(MemReqs.alignment), "Alignment is not power of 2!");
- m_MemoryAllocation = pRenderDeviceVk->AllocateMemory(MemReqs.size, MemReqs.alignment, MemoryTypeIndex);
+ m_MemoryAllocation = pRenderDeviceVk->AllocateMemory(MemReqs.size, MemReqs.alignment, MemoryTypeIndex, AllocateFlags);
m_BufferMemoryAlignedOffset = Align(VkDeviceSize{m_MemoryAllocation.UnalignedOffset}, MemReqs.alignment);
VERIFY(m_MemoryAllocation.Size >= MemReqs.size + (m_BufferMemoryAlignedOffset - m_MemoryAllocation.UnalignedOffset), "Size of memory allocation is too small");
@@ -285,12 +324,12 @@ BufferVkImpl::BufferVkImpl(IReferenceCounters* pRefCounters,
VkCommandBuffer vkCmdBuff;
pRenderDeviceVk->AllocateTransientCmdPool(CmdPool, vkCmdBuff, "Transient command pool to copy staging data to a device buffer");
- auto EnabledGraphicsShaderStages = LogicalDevice.GetEnabledGraphicsShaderStages();
- VulkanUtilities::VulkanCommandBuffer::BufferMemoryBarrier(vkCmdBuff, StagingBuffer, 0, VK_ACCESS_TRANSFER_READ_BIT, EnabledGraphicsShaderStages);
+ auto EnabledShaderStages = LogicalDevice.GetEnabledShaderStages();
+ VulkanUtilities::VulkanCommandBuffer::BufferMemoryBarrier(vkCmdBuff, StagingBuffer, 0, VK_ACCESS_TRANSFER_READ_BIT, EnabledShaderStages);
InitialState = RESOURCE_STATE_COPY_DEST;
VkAccessFlags AccessFlags = ResourceStateFlagsToVkAccessFlags(InitialState);
VERIFY_EXPR(AccessFlags == VK_ACCESS_TRANSFER_WRITE_BIT);
- VulkanUtilities::VulkanCommandBuffer::BufferMemoryBarrier(vkCmdBuff, m_VulkanBuffer, 0, AccessFlags, EnabledGraphicsShaderStages);
+ VulkanUtilities::VulkanCommandBuffer::BufferMemoryBarrier(vkCmdBuff, m_VulkanBuffer, 0, AccessFlags, EnabledShaderStages);
// Copy commands MUST be recorded outside of a render pass instance. This is OK here
// as copy will be the only command in the cmd buffer
@@ -408,7 +447,7 @@ void BufferVkImpl::CreateViewInternal(const BufferViewDesc& OrigViewDesc, IBuffe
VulkanUtilities::BufferViewWrapper BufferVkImpl::CreateView(struct BufferViewDesc& ViewDesc)
{
VulkanUtilities::BufferViewWrapper BuffView;
- CorrectBufferViewDesc(ViewDesc);
+ ValidateAndCorrectBufferViewDesc(m_Desc, ViewDesc);
if ((ViewDesc.ViewType == BUFFER_VIEW_SHADER_RESOURCE || ViewDesc.ViewType == BUFFER_VIEW_UNORDERED_ACCESS) &&
(m_Desc.Mode == BUFFER_MODE_FORMATTED || m_Desc.Mode == BUFFER_MODE_RAW))
{
@@ -457,6 +496,32 @@ VkAccessFlags BufferVkImpl::GetAccessFlags() const
return ResourceStateFlagsToVkAccessFlags(GetState());
}
+VkDeviceAddress BufferVkImpl::GetVkDeviceAddress() const
+{
+ constexpr auto DeviceAddressFlags = BIND_RAY_TRACING;
+
+ if (m_VulkanBuffer != VK_NULL_HANDLE && (m_Desc.BindFlags & DeviceAddressFlags) != 0)
+ {
+#if DILIGENT_USE_VOLK
+ VkBufferDeviceAddressInfoKHR BufferInfo = {};
+
+ BufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_KHR;
+ BufferInfo.buffer = m_VulkanBuffer;
+ VkDeviceAddress Result = vkGetBufferDeviceAddressKHR(m_pDevice->GetLogicalDevice().GetVkDevice(), &BufferInfo);
+ VERIFY_EXPR(Result > 0);
+ return Result;
+#else
+ UNSUPPORTED("vkGetBufferDeviceAddressKHR is only available through Volk");
+ return VkDeviceAddress{};
+#endif
+ }
+ else
+ {
+ UNEXPECTED("Can't get device address for buffer");
+ return 0;
+ }
+}
+
#ifdef DILIGENT_DEVELOPMENT
void BufferVkImpl::DvpVerifyDynamicAllocation(DeviceContextVkImpl* pCtx) const
{
diff --git a/Graphics/GraphicsEngineVulkan/src/CommandPoolManager.cpp b/Graphics/GraphicsEngineVulkan/src/CommandPoolManager.cpp
index e7fbc9bd..cf24d9ea 100644
--- a/Graphics/GraphicsEngineVulkan/src/CommandPoolManager.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/CommandPoolManager.cpp
@@ -53,14 +53,17 @@ VulkanUtilities::CommandPoolWrapper CommandPoolManager::AllocateCommandPool(cons
{
std::lock_guard<std::mutex> LockGuard{m_Mutex};
+ const auto& LogicalDevice = m_DeviceVkImpl.GetLogicalDevice();
+
VulkanUtilities::CommandPoolWrapper CmdPool;
if (!m_CmdPools.empty())
{
CmdPool = std::move(m_CmdPools.front());
m_CmdPools.pop_front();
+
+ LogicalDevice.ResetCommandPool(CmdPool);
}
- auto& LogicalDevice = m_DeviceVkImpl.GetLogicalDevice();
if (CmdPool == VK_NULL_HANDLE)
{
VkCommandPoolCreateInfo CmdPoolCI = {};
@@ -74,8 +77,6 @@ VulkanUtilities::CommandPoolWrapper CommandPoolManager::AllocateCommandPool(cons
DEV_CHECK_ERR(CmdPool != VK_NULL_HANDLE, "Failed to create Vulkan command pool");
}
- LogicalDevice.ResetCommandPool(CmdPool);
-
#ifdef DILIGENT_DEVELOPMENT
++m_AllocatedPoolCounter;
#endif
diff --git a/Graphics/GraphicsEngineVulkan/src/DescriptorPoolManager.cpp b/Graphics/GraphicsEngineVulkan/src/DescriptorPoolManager.cpp
index 412ddd7b..56a83b85 100644
--- a/Graphics/GraphicsEngineVulkan/src/DescriptorPoolManager.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/DescriptorPoolManager.cpp
@@ -59,6 +59,44 @@ VulkanUtilities::DescriptorPoolWrapper DescriptorPoolManager::CreateDescriptorPo
return m_DeviceVkImpl.GetLogicalDevice().CreateDescriptorPool(PoolCI, DebugName);
}
+static std::vector<VkDescriptorPoolSize> PrunePoolSizes(RenderDeviceVkImpl& DeviceVkImpl, std::vector<VkDescriptorPoolSize>&& PoolSizes)
+{
+ const auto& Feats = DeviceVkImpl.GetLogicalDevice().GetEnabledExtFeatures();
+ for (auto iter = PoolSizes.begin(); iter != PoolSizes.end();)
+ {
+ switch (iter->type)
+ {
+ case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:
+ if (Feats.RayTracingPipeline.rayTracingPipeline == VK_FALSE)
+ iter = PoolSizes.erase(iter);
+ else
+ ++iter;
+ break;
+ default:
+ ++iter;
+ }
+ }
+ return PoolSizes;
+}
+
+DescriptorPoolManager::DescriptorPoolManager(RenderDeviceVkImpl& DeviceVkImpl,
+ std::string PoolName,
+ std::vector<VkDescriptorPoolSize> PoolSizes,
+ uint32_t MaxSets,
+ bool AllowFreeing) noexcept :
+ // clang-format off
+ m_DeviceVkImpl{DeviceVkImpl },
+ m_PoolName {std::move(PoolName) },
+ m_PoolSizes (PrunePoolSizes(DeviceVkImpl, std::move(PoolSizes))),
+ m_MaxSets {MaxSets },
+ m_AllowFreeing{AllowFreeing }
+// clang-format on
+{
+#ifdef DILIGENT_DEVELOPMENT
+ m_AllocatedPoolCounter = 0;
+#endif
+}
+
DescriptorPoolManager::~DescriptorPoolManager()
{
DEV_CHECK_ERR(m_AllocatedPoolCounter == 0, "Not all allocated descriptor pools are returned to the pool manager");
diff --git a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp
index 3520fa40..e0d6ee2b 100644
--- a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp
@@ -69,7 +69,7 @@ DeviceContextVkImpl::DeviceContextVkImpl(IReferenceCounters* p
bIsDeferred ? std::numeric_limits<decltype(m_NumCommandsToFlush)>::max() : EngineCI.NumCommandsToFlushCmdBuffer,
bIsDeferred
},
- m_CommandBuffer { pDeviceVkImpl->GetLogicalDevice().GetEnabledGraphicsShaderStages() },
+ m_CommandBuffer { pDeviceVkImpl->GetLogicalDevice().GetEnabledShaderStages() },
m_CmdListAllocator { GetRawAllocator(), sizeof(CommandListVkImpl), 64 },
// Command pools must be thread safe because command buffers are returned into pools by release queues
// potentially running in another thread
@@ -117,6 +117,8 @@ DeviceContextVkImpl::DeviceContextVkImpl(IReferenceCounters* p
m_DummyVB = pDummyVB.RawPtr<BufferVkImpl>();
m_vkClearValues.reserve(16);
+
+ CreateASCompactedSizeQueryPool();
}
DeviceContextVkImpl::~DeviceContextVkImpl()
@@ -298,6 +300,11 @@ void DeviceContextVkImpl::SetPipelineState(IPipelineState* pPipelineState)
m_CommandBuffer.BindComputePipeline(vkPipeline);
break;
}
+ case PIPELINE_TYPE_RAY_TRACING:
+ {
+ m_CommandBuffer.BindRayTracingPipeline(vkPipeline);
+ break;
+ }
default:
UNEXPECTED("unknown pipeline type");
}
@@ -526,7 +533,7 @@ void DeviceContextVkImpl::PrepareForIndexedDraw(DRAW_FLAGS Flags, VALUE_TYPE Ind
}
#endif
DEV_CHECK_ERR(IndexType == VT_UINT16 || IndexType == VT_UINT32, "Unsupported index format. Only R16_UINT and R32_UINT are allowed.");
- VkIndexType vkIndexType = IndexType == VT_UINT16 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32;
+ VkIndexType vkIndexType = TypeToVkIndexType(IndexType);
m_CommandBuffer.BindIndexBuffer(m_pIndexBuffer->GetVkBuffer(), m_IndexDataStartOffset + m_pIndexBuffer->GetDynamicOffset(m_ContextId, this), vkIndexType);
}
@@ -634,6 +641,19 @@ void DeviceContextVkImpl::PrepareForDispatchCompute()
#endif
}
+void DeviceContextVkImpl::PrepareForRayTracing()
+{
+ EnsureVkCmdBuffer();
+
+ if (m_DescrSetBindInfo.DynamicOffsetCount != 0)
+ {
+ if (!m_DescrSetBindInfo.DynamicDescriptorsBound || m_DescrSetBindInfo.DynamicBuffersPresent)
+ {
+ m_pPipelineState->BindDescriptorSetsWithDynamicOffsets(GetCommandBuffer(), m_ContextId, this, m_DescrSetBindInfo);
+ }
+ }
+}
+
void DeviceContextVkImpl::DispatchCompute(const DispatchComputeAttribs& Attribs)
{
if (!DvpVerifyDispatchArguments(Attribs))
@@ -2242,6 +2262,22 @@ void DeviceContextVkImpl::TransitionImageLayout(ITexture* pTexture, VkImageLayou
}
}
+namespace
+{
+NODISCARD inline bool ResourceStateHasWriteAccess(RESOURCE_STATE State)
+{
+ static_assert(RESOURCE_STATE_MAX_BIT == RESOURCE_STATE_RAY_TRACING, "This function must be updated to handle new resource state flag");
+ constexpr RESOURCE_STATE WriteAccessStates =
+ RESOURCE_STATE_RENDER_TARGET |
+ RESOURCE_STATE_UNORDERED_ACCESS |
+ RESOURCE_STATE_COPY_DEST |
+ RESOURCE_STATE_RESOLVE_DEST |
+ RESOURCE_STATE_BUILD_AS_WRITE;
+
+ return State & WriteAccessStates;
+}
+} // namespace
+
void DeviceContextVkImpl::TransitionTextureState(TextureVkImpl& TextureVk,
RESOURCE_STATE OldState,
RESOURCE_STATE NewState,
@@ -2304,15 +2340,22 @@ void DeviceContextVkImpl::TransitionTextureState(TextureVkImpl& Textur
pSubresRange->aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
}
- // Note that when both old and new states are RESOURCE_STATE_UNORDERED_ACCESS, we need to execute UAV barrier
- // to make sure that all UAV writes are complete and visible.
+ // Always add barrier after writes.
+ const bool AfterWrite = ResourceStateHasWriteAccess(OldState);
+
auto OldLayout = ResourceStateToVkImageLayout(OldState);
auto NewLayout = ResourceStateToVkImageLayout(NewState);
- m_CommandBuffer.TransitionImageLayout(vkImg, OldLayout, NewLayout, *pSubresRange);
- if (UpdateTextureState)
+ auto OldStages = ResourceStateFlagsToVkPipelineStageFlags(OldState, m_CommandBuffer.GetEnabledShaderStages());
+ auto NewStages = ResourceStateFlagsToVkPipelineStageFlags(NewState, m_CommandBuffer.GetEnabledShaderStages());
+
+ if (((OldState & NewState) != NewState) || OldLayout != NewLayout || AfterWrite)
{
- TextureVk.SetState(NewState);
- VERIFY_EXPR(TextureVk.GetLayout() == NewLayout);
+ m_CommandBuffer.TransitionImageLayout(vkImg, OldLayout, NewLayout, *pSubresRange, OldStages, NewStages);
+ if (UpdateTextureState)
+ {
+ TextureVk.SetState(NewState);
+ VERIFY_EXPR(TextureVk.GetLayout() == NewLayout);
+ }
}
}
@@ -2327,10 +2370,7 @@ void DeviceContextVkImpl::TransitionOrVerifyTextureState(TextureVkImpl&
VERIFY(m_pActiveRenderPass == nullptr, "State transitions are not allowed inside a render pass");
if (Texture.IsInKnownState())
{
- if (!Texture.CheckState(RequiredState))
- {
- TransitionTextureState(Texture, RESOURCE_STATE_UNKNOWN, RequiredState, true);
- }
+ TransitionTextureState(Texture, RESOURCE_STATE_UNKNOWN, RequiredState, true);
VERIFY_EXPR(Texture.GetLayout() == ExpectedLayout);
}
}
@@ -2395,9 +2435,10 @@ void DeviceContextVkImpl::TransitionBufferState(BufferVkImpl& BufferVk, RESOURCE
}
}
- // When both old and new states are RESOURCE_STATE_UNORDERED_ACCESS, we need to execute UAV barrier
- // to make sure that all UAV writes are complete and visible.
- if (((OldState & NewState) != NewState) || NewState == RESOURCE_STATE_UNORDERED_ACCESS)
+ // Always add barrier after writes.
+ const bool AfterWrite = ResourceStateHasWriteAccess(OldState);
+
+ if (((OldState & NewState) != NewState) || AfterWrite)
{
DEV_CHECK_ERR(BufferVk.m_VulkanBuffer != VK_NULL_HANDLE, "Cannot transition suballocated buffer");
VERIFY_EXPR(BufferVk.GetDynamicOffset(m_ContextId, this) == 0);
@@ -2406,7 +2447,9 @@ void DeviceContextVkImpl::TransitionBufferState(BufferVkImpl& BufferVk, RESOURCE
auto vkBuff = BufferVk.GetVkBuffer();
auto OldAccessFlags = ResourceStateFlagsToVkAccessFlags(OldState);
auto NewAccessFlags = ResourceStateFlagsToVkAccessFlags(NewState);
- m_CommandBuffer.BufferMemoryBarrier(vkBuff, OldAccessFlags, NewAccessFlags);
+ auto OldStages = ResourceStateFlagsToVkPipelineStageFlags(OldState, m_CommandBuffer.GetEnabledShaderStages());
+ auto NewStages = ResourceStateFlagsToVkPipelineStageFlags(NewState, m_CommandBuffer.GetEnabledShaderStages());
+ m_CommandBuffer.BufferMemoryBarrier(vkBuff, OldAccessFlags, NewAccessFlags, OldStages, NewStages);
if (UpdateBufferState)
{
BufferVk.SetState(NewState);
@@ -2425,10 +2468,7 @@ void DeviceContextVkImpl::TransitionOrVerifyBufferState(BufferVkImpl&
VERIFY(m_pActiveRenderPass == nullptr, "State transitions are not allowed inside a render pass");
if (Buffer.IsInKnownState())
{
- if (!Buffer.CheckState(RequiredState))
- {
- TransitionBufferState(Buffer, RESOURCE_STATE_UNKNOWN, RequiredState, true);
- }
+ TransitionBufferState(Buffer, RESOURCE_STATE_UNKNOWN, RequiredState, true);
VERIFY_EXPR(Buffer.CheckAccessFlags(ExpectedAccessFlags));
}
}
@@ -2440,6 +2480,145 @@ void DeviceContextVkImpl::TransitionOrVerifyBufferState(BufferVkImpl&
#endif
}
+void DeviceContextVkImpl::TransitionBLASState(BottomLevelASVkImpl& BLAS,
+ RESOURCE_STATE OldState,
+ RESOURCE_STATE NewState,
+ bool UpdateInternalState)
+{
+ VERIFY(m_pActiveRenderPass == nullptr, "State transitions are not allowed inside a render pass");
+ if (OldState == RESOURCE_STATE_UNKNOWN)
+ {
+ if (BLAS.IsInKnownState())
+ {
+ OldState = BLAS.GetState();
+ }
+ else
+ {
+ LOG_ERROR_MESSAGE("Failed to transition the state of BLAS '", BLAS.GetDesc().Name, "' because the BLAS state is unknown and is not explicitly specified");
+ return;
+ }
+ }
+ else
+ {
+ if (BLAS.IsInKnownState() && BLAS.GetState() != OldState)
+ {
+ LOG_ERROR_MESSAGE("The state ", GetResourceStateString(BLAS.GetState()), " of BLAS '",
+ BLAS.GetDesc().Name, "' does not match the old state ", GetResourceStateString(OldState),
+ " specified by the barrier");
+ }
+ }
+
+ // Always add barrier after writes.
+ const bool AfterWrite = ResourceStateHasWriteAccess(OldState);
+
+ if ((OldState & NewState) != NewState || AfterWrite)
+ {
+ EnsureVkCmdBuffer();
+ auto OldAccessFlags = AccelStructStateFlagsToVkAccessFlags(OldState);
+ auto NewAccessFlags = AccelStructStateFlagsToVkAccessFlags(NewState);
+ auto OldStages = ResourceStateFlagsToVkPipelineStageFlags(OldState, m_CommandBuffer.GetEnabledShaderStages());
+ auto NewStages = ResourceStateFlagsToVkPipelineStageFlags(NewState, m_CommandBuffer.GetEnabledShaderStages());
+ m_CommandBuffer.ASMemoryBarrier(OldAccessFlags, NewAccessFlags, OldStages, NewStages);
+ if (UpdateInternalState)
+ {
+ BLAS.SetState(NewState);
+ }
+ }
+}
+
+void DeviceContextVkImpl::TransitionTLASState(TopLevelASVkImpl& TLAS,
+ RESOURCE_STATE OldState,
+ RESOURCE_STATE NewState,
+ bool UpdateInternalState)
+{
+ VERIFY(m_pActiveRenderPass == nullptr, "State transitions are not allowed inside a render pass");
+ if (OldState == RESOURCE_STATE_UNKNOWN)
+ {
+ if (TLAS.IsInKnownState())
+ {
+ OldState = TLAS.GetState();
+ }
+ else
+ {
+ LOG_ERROR_MESSAGE("Failed to transition the state of TLAS '", TLAS.GetDesc().Name, "' because the TLAS state is unknown and is not explicitly specified");
+ return;
+ }
+ }
+ else
+ {
+ if (TLAS.IsInKnownState() && TLAS.GetState() != OldState)
+ {
+ LOG_ERROR_MESSAGE("The state ", GetResourceStateString(TLAS.GetState()), " of TLAS '",
+ TLAS.GetDesc().Name, "' does not match the old state ", GetResourceStateString(OldState),
+ " specified by the barrier");
+ }
+ }
+
+ // Always add barrier after writes.
+ const bool AfterWrite = ResourceStateHasWriteAccess(OldState);
+
+ if ((OldState & NewState) != NewState || AfterWrite)
+ {
+ EnsureVkCmdBuffer();
+ auto OldAccessFlags = AccelStructStateFlagsToVkAccessFlags(OldState);
+ auto NewAccessFlags = AccelStructStateFlagsToVkAccessFlags(NewState);
+ auto OldStages = ResourceStateFlagsToVkPipelineStageFlags(OldState, m_CommandBuffer.GetEnabledShaderStages());
+ auto NewStages = ResourceStateFlagsToVkPipelineStageFlags(NewState, m_CommandBuffer.GetEnabledShaderStages());
+ m_CommandBuffer.ASMemoryBarrier(OldAccessFlags, NewAccessFlags, OldStages, NewStages);
+ if (UpdateInternalState)
+ {
+ TLAS.SetState(NewState);
+ }
+ }
+}
+
+void DeviceContextVkImpl::TransitionOrVerifyBLASState(BottomLevelASVkImpl& BLAS,
+ RESOURCE_STATE_TRANSITION_MODE TransitionMode,
+ RESOURCE_STATE RequiredState,
+ const char* OperationName)
+{
+ if (TransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION)
+ {
+ VERIFY(m_pActiveRenderPass == nullptr, "State transitions are not allowed inside a render pass");
+ if (BLAS.IsInKnownState())
+ {
+ TransitionBLASState(BLAS, RESOURCE_STATE_UNKNOWN, RequiredState, true);
+ }
+ }
+#ifdef DILIGENT_DEVELOPMENT
+ else if (TransitionMode == RESOURCE_STATE_TRANSITION_MODE_VERIFY)
+ {
+ DvpVerifyBLASState(BLAS, RequiredState, OperationName);
+ }
+#endif
+}
+
+void DeviceContextVkImpl::TransitionOrVerifyTLASState(TopLevelASVkImpl& TLAS,
+ RESOURCE_STATE_TRANSITION_MODE TransitionMode,
+ RESOURCE_STATE RequiredState,
+ const char* OperationName)
+{
+ if (TransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION)
+ {
+ VERIFY(m_pActiveRenderPass == nullptr, "State transitions are not allowed inside a render pass");
+ if (TLAS.IsInKnownState())
+ {
+ TransitionTLASState(TLAS, RESOURCE_STATE_UNKNOWN, RequiredState, true);
+ }
+ }
+#ifdef DILIGENT_DEVELOPMENT
+ else if (TransitionMode == RESOURCE_STATE_TRANSITION_MODE_VERIFY)
+ {
+ DvpVerifyTLASState(TLAS, RequiredState, OperationName);
+ }
+
+ if (RequiredState & (RESOURCE_STATE_RAY_TRACING | RESOURCE_STATE_BUILD_AS_READ))
+ {
+ TLAS.ValidateContent();
+ }
+#endif
+}
+
VulkanDynamicAllocation DeviceContextVkImpl::AllocateDynamicSpace(Uint32 SizeInBytes, Uint32 Alignment)
{
auto DynAlloc = m_DynamicHeap.Allocate(SizeInBytes, Alignment);
@@ -2472,23 +2651,31 @@ void DeviceContextVkImpl::TransitionResourceStates(Uint32 BarrierCount, StateTra
}
VERIFY(Barrier.TransitionType == STATE_TRANSITION_TYPE_IMMEDIATE || Barrier.TransitionType == STATE_TRANSITION_TYPE_END, "Unexpected barrier type");
- if (Barrier.pTexture)
+ if (RefCntAutoPtr<TextureVkImpl> pTexture{Barrier.pResource, IID_TextureVk})
{
- auto* pTextureVkImpl = ValidatedCast<TextureVkImpl>(Barrier.pTexture);
-
VkImageSubresourceRange SubResRange;
SubResRange.aspectMask = 0;
SubResRange.baseMipLevel = Barrier.FirstMipLevel;
SubResRange.levelCount = (Barrier.MipLevelsCount == REMAINING_MIP_LEVELS) ? VK_REMAINING_MIP_LEVELS : Barrier.MipLevelsCount;
SubResRange.baseArrayLayer = Barrier.FirstArraySlice;
SubResRange.layerCount = (Barrier.ArraySliceCount == REMAINING_ARRAY_SLICES) ? VK_REMAINING_ARRAY_LAYERS : Barrier.ArraySliceCount;
- TransitionTextureState(*pTextureVkImpl, Barrier.OldState, Barrier.NewState, Barrier.UpdateResourceState, &SubResRange);
+ TransitionTextureState(*pTexture, Barrier.OldState, Barrier.NewState, Barrier.UpdateResourceState, &SubResRange);
+ }
+ else if (RefCntAutoPtr<BufferVkImpl> pBuffer{Barrier.pResource, IID_BufferVk})
+ {
+ TransitionBufferState(*pBuffer, Barrier.OldState, Barrier.NewState, Barrier.UpdateResourceState);
+ }
+ else if (RefCntAutoPtr<BottomLevelASVkImpl> pBottomLevelAS{Barrier.pResource, IID_BottomLevelAS})
+ {
+ TransitionBLASState(*pBottomLevelAS, Barrier.OldState, Barrier.NewState, Barrier.UpdateResourceState);
+ }
+ else if (RefCntAutoPtr<TopLevelASVkImpl> pTopLevelAS{Barrier.pResource, IID_TopLevelAS})
+ {
+ TransitionTLASState(*pTopLevelAS, Barrier.OldState, Barrier.NewState, Barrier.UpdateResourceState);
}
else
{
- VERIFY_EXPR(Barrier.pBuffer != nullptr);
- auto* pBufferVkImpl = ValidatedCast<BufferVkImpl>(Barrier.pBuffer);
- TransitionBufferState(*pBufferVkImpl, Barrier.OldState, Barrier.NewState, Barrier.UpdateResourceState);
+ UNEXPECTED("unsupported resource type");
}
}
}
@@ -2548,4 +2735,430 @@ void DeviceContextVkImpl::ResolveTextureSubresource(ITexture*
1, &ResolveRegion);
}
+void DeviceContextVkImpl::BuildBLAS(const BuildBLASAttribs& Attribs)
+{
+ if (!TDeviceContextBase::BuildBLAS(Attribs, 0))
+ return;
+
+ auto* pBLASVk = ValidatedCast<BottomLevelASVkImpl>(Attribs.pBLAS);
+ auto* pScratchVk = ValidatedCast<BufferVkImpl>(Attribs.pScratchBuffer);
+ auto& BLASDesc = pBLASVk->GetDesc();
+
+ EnsureVkCmdBuffer();
+
+ const char* OpName = "Build BottomLevelAS (DeviceContextVkImpl::BuildBLAS)";
+ TransitionOrVerifyBLASState(*pBLASVk, Attribs.BLASTransitionMode, RESOURCE_STATE_BUILD_AS_WRITE, OpName);
+ TransitionOrVerifyBufferState(*pScratchVk, Attribs.ScratchBufferTransitionMode, RESOURCE_STATE_BUILD_AS_WRITE, VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR, OpName);
+
+ VkAccelerationStructureBuildGeometryInfoKHR vkASBuildInfo = {};
+ std::vector<VkAccelerationStructureBuildRangeInfoKHR> vkRanges;
+ std::vector<VkAccelerationStructureGeometryKHR> vkGeometries;
+
+ if (Attribs.pTriangleData != nullptr)
+ {
+ vkGeometries.resize(Attribs.TriangleDataCount);
+ vkRanges.resize(Attribs.TriangleDataCount);
+ pBLASVk->SetActualGeometryCount(Attribs.TriangleDataCount);
+
+ for (Uint32 i = 0; i < Attribs.TriangleDataCount; ++i)
+ {
+ const auto& SrcTris = Attribs.pTriangleData[i];
+ Uint32 Idx = i;
+ Uint32 GeoIdx = pBLASVk->UpdateGeometryIndex(SrcTris.GeometryName, Idx, Attribs.Update);
+
+ if (GeoIdx == INVALID_INDEX || Idx == INVALID_INDEX)
+ {
+ UNEXPECTED("Failed to find geometry by name");
+ continue;
+ }
+
+ auto& vkGeo = vkGeometries[Idx];
+ auto& vkTris = vkGeo.geometry.triangles;
+ auto& off = vkRanges[Idx];
+ const auto& TriDesc = BLASDesc.pTriangles[GeoIdx];
+
+ vkGeo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR;
+ vkGeo.pNext = nullptr;
+ vkGeo.flags = GeometryFlagsToVkGeometryFlags(SrcTris.Flags);
+ vkGeo.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR;
+ vkTris.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR;
+ vkTris.pNext = nullptr;
+
+ auto* const pVB = ValidatedCast<BufferVkImpl>(SrcTris.pVertexBuffer);
+
+ // vertex format in SrcTris may be undefined, so use vertex format from description
+ vkTris.vertexFormat = TypeToVkFormat(TriDesc.VertexValueType, TriDesc.VertexComponentCount, TriDesc.VertexValueType < VT_FLOAT16);
+ vkTris.vertexStride = SrcTris.VertexStride;
+ vkTris.maxVertex = SrcTris.VertexCount;
+ vkTris.vertexData.deviceAddress = pVB->GetVkDeviceAddress() + SrcTris.VertexOffset;
+
+ TransitionOrVerifyBufferState(*pVB, Attribs.GeometryTransitionMode, RESOURCE_STATE_BUILD_AS_READ, VK_ACCESS_SHADER_READ_BIT, OpName);
+
+ if (SrcTris.pIndexBuffer)
+ {
+ auto* const pIB = ValidatedCast<BufferVkImpl>(SrcTris.pIndexBuffer);
+
+ // index type in SrcTris may be undefined, so use index type from description
+ vkTris.indexType = TypeToVkIndexType(TriDesc.IndexType);
+ vkTris.indexData.deviceAddress = pIB->GetVkDeviceAddress() + SrcTris.IndexOffset;
+
+ TransitionOrVerifyBufferState(*pIB, Attribs.GeometryTransitionMode, RESOURCE_STATE_BUILD_AS_READ, VK_ACCESS_SHADER_READ_BIT, OpName);
+ }
+ else
+ {
+ vkTris.indexType = VK_INDEX_TYPE_NONE_KHR;
+ vkTris.indexData.deviceAddress = 0;
+ }
+
+ if (SrcTris.pTransformBuffer)
+ {
+ auto* const pTB = ValidatedCast<BufferVkImpl>(SrcTris.pTransformBuffer);
+ vkTris.transformData.deviceAddress = pTB->GetVkDeviceAddress() + SrcTris.TransformBufferOffset;
+
+ TransitionOrVerifyBufferState(*pTB, Attribs.GeometryTransitionMode, RESOURCE_STATE_BUILD_AS_READ, VK_ACCESS_SHADER_READ_BIT, OpName);
+ }
+ else
+ {
+ vkTris.transformData.deviceAddress = 0;
+ }
+
+ off.primitiveCount = SrcTris.PrimitiveCount;
+ off.firstVertex = 0;
+ off.primitiveOffset = 0;
+ off.transformOffset = 0;
+ }
+ }
+ else if (Attribs.pBoxData != nullptr)
+ {
+ vkGeometries.resize(Attribs.BoxDataCount);
+ vkRanges.resize(Attribs.BoxDataCount);
+ pBLASVk->SetActualGeometryCount(Attribs.BoxDataCount);
+
+ for (Uint32 i = 0; i < Attribs.BoxDataCount; ++i)
+ {
+ const auto& SrcBoxes = Attribs.pBoxData[i];
+ Uint32 Idx = i;
+ Uint32 GeoIdx = pBLASVk->UpdateGeometryIndex(SrcBoxes.GeometryName, Idx, Attribs.Update);
+
+ if (GeoIdx == INVALID_INDEX || Idx == INVALID_INDEX)
+ {
+ UNEXPECTED("Failed to find geometry by name");
+ continue;
+ }
+
+ auto& vkGeo = vkGeometries[Idx];
+ auto& vkAABBs = vkGeo.geometry.aabbs;
+ auto& off = vkRanges[Idx];
+
+ vkGeo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR;
+ vkGeo.pNext = nullptr;
+ vkGeo.flags = GeometryFlagsToVkGeometryFlags(SrcBoxes.Flags);
+ vkGeo.geometryType = VK_GEOMETRY_TYPE_AABBS_KHR;
+
+ auto* const pBB = ValidatedCast<BufferVkImpl>(SrcBoxes.pBoxBuffer);
+ vkAABBs.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR;
+ vkAABBs.pNext = nullptr;
+ vkAABBs.stride = SrcBoxes.BoxStride;
+ vkAABBs.data.deviceAddress = pBB->GetVkDeviceAddress() + SrcBoxes.BoxOffset;
+
+ VERIFY(vkAABBs.data.deviceAddress % 8 == 0, "AABB start address is not properly aligned");
+
+ TransitionOrVerifyBufferState(*pBB, Attribs.GeometryTransitionMode, RESOURCE_STATE_BUILD_AS_READ, VK_ACCESS_SHADER_READ_BIT, OpName);
+
+ off.firstVertex = 0;
+ off.transformOffset = 0;
+ off.primitiveOffset = 0;
+ off.primitiveCount = SrcBoxes.BoxCount;
+ }
+ }
+
+ VkAccelerationStructureBuildRangeInfoKHR const* VkRangePtr = vkRanges.data();
+
+ vkASBuildInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR;
+ vkASBuildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; // type must be compatible with create info
+ vkASBuildInfo.flags = BuildASFlagsToVkBuildAccelerationStructureFlags(BLASDesc.Flags); // flags must be compatible with create info
+ vkASBuildInfo.mode = Attribs.Update ? VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR : VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR;
+ vkASBuildInfo.srcAccelerationStructure = Attribs.Update ? pBLASVk->GetVkBLAS() : VK_NULL_HANDLE;
+ vkASBuildInfo.dstAccelerationStructure = pBLASVk->GetVkBLAS();
+ vkASBuildInfo.geometryCount = static_cast<uint32_t>(vkGeometries.size());
+ vkASBuildInfo.pGeometries = vkGeometries.data();
+ vkASBuildInfo.ppGeometries = nullptr;
+ vkASBuildInfo.scratchData.deviceAddress = pScratchVk->GetVkDeviceAddress() + Attribs.ScratchBufferOffset;
+
+ EnsureVkCmdBuffer();
+ m_CommandBuffer.BuildAccelerationStructure(1, &vkASBuildInfo, &VkRangePtr);
+ ++m_State.NumCommands;
+
+#ifdef DILIGENT_DEVELOPMENT
+ pBLASVk->UpdateVersion();
+#endif
+}
+
+void DeviceContextVkImpl::BuildTLAS(const BuildTLASAttribs& Attribs)
+{
+ if (!TDeviceContextBase::BuildTLAS(Attribs, 0))
+ return;
+
+ static_assert(TLAS_INSTANCE_DATA_SIZE == sizeof(VkAccelerationStructureInstanceKHR), "Value in TLAS_INSTANCE_DATA_SIZE doesn't match the actual instance description size");
+
+ auto* pTLASVk = ValidatedCast<TopLevelASVkImpl>(Attribs.pTLAS);
+ auto* pScratchVk = ValidatedCast<BufferVkImpl>(Attribs.pScratchBuffer);
+ auto* pInstancesVk = ValidatedCast<BufferVkImpl>(Attribs.pInstanceBuffer);
+ auto& TLASDesc = pTLASVk->GetDesc();
+
+ EnsureVkCmdBuffer();
+
+ const char* OpName = "Build TopLevelAS (DeviceContextVkImpl::BuildTLAS)";
+ TransitionOrVerifyTLASState(*pTLASVk, Attribs.TLASTransitionMode, RESOURCE_STATE_BUILD_AS_WRITE, OpName);
+ TransitionOrVerifyBufferState(*pScratchVk, Attribs.ScratchBufferTransitionMode, RESOURCE_STATE_BUILD_AS_WRITE, VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR, OpName);
+
+ if (Attribs.Update)
+ {
+ if (!pTLASVk->UpdateInstances(Attribs.pInstances, Attribs.InstanceCount, Attribs.BaseContributionToHitGroupIndex, Attribs.HitGroupStride, Attribs.BindingMode))
+ return;
+ }
+ else
+ {
+ if (!pTLASVk->SetInstanceData(Attribs.pInstances, Attribs.InstanceCount, Attribs.BaseContributionToHitGroupIndex, Attribs.HitGroupStride, Attribs.BindingMode))
+ return;
+ }
+
+ // copy instance data into instance buffer
+ {
+ size_t Size = Attribs.InstanceCount * sizeof(VkAccelerationStructureInstanceKHR);
+ auto TmpSpace = m_UploadHeap.Allocate(Size, 16);
+
+ for (Uint32 i = 0; i < Attribs.InstanceCount; ++i)
+ {
+ const auto& Inst = Attribs.pInstances[i];
+ const auto InstDesc = pTLASVk->GetInstanceDesc(Inst.InstanceName);
+
+ if (InstDesc.InstanceIndex >= Attribs.InstanceCount)
+ {
+ UNEXPECTED("Failed to find instance by name");
+ return;
+ }
+
+ auto& vkASInst = static_cast<VkAccelerationStructureInstanceKHR*>(TmpSpace.CPUAddress)[InstDesc.InstanceIndex];
+ auto* pBLASVk = ValidatedCast<BottomLevelASVkImpl>(Inst.pBLAS);
+
+ static_assert(sizeof(vkASInst.transform) == sizeof(Inst.Transform), "size mismatch");
+ std::memcpy(&vkASInst.transform, Inst.Transform.data, sizeof(vkASInst.transform));
+
+ vkASInst.instanceCustomIndex = Inst.CustomId;
+ vkASInst.instanceShaderBindingTableRecordOffset = InstDesc.ContributionToHitGroupIndex;
+ vkASInst.mask = Inst.Mask;
+ vkASInst.flags = InstanceFlagsToVkGeometryInstanceFlags(Inst.Flags);
+ vkASInst.accelerationStructureReference = pBLASVk->GetVkDeviceAddress();
+
+ TransitionOrVerifyBLASState(*pBLASVk, Attribs.BLASTransitionMode, RESOURCE_STATE_BUILD_AS_READ, OpName);
+ }
+
+ UpdateBufferRegion(pInstancesVk, Attribs.InstanceBufferOffset, Size, TmpSpace.vkBuffer, TmpSpace.AlignedOffset, Attribs.InstanceBufferTransitionMode);
+ }
+ TransitionOrVerifyBufferState(*pInstancesVk, Attribs.InstanceBufferTransitionMode, RESOURCE_STATE_BUILD_AS_READ, VK_ACCESS_SHADER_READ_BIT, OpName);
+
+ VkAccelerationStructureBuildGeometryInfoKHR vkASBuildInfo = {};
+ VkAccelerationStructureBuildRangeInfoKHR vkRange = {};
+ VkAccelerationStructureBuildRangeInfoKHR const* vkRangePtr = &vkRange;
+ VkAccelerationStructureGeometryKHR vkASGeometry = {};
+
+ vkRange.primitiveCount = Attribs.InstanceCount;
+
+ vkASGeometry.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR;
+ vkASGeometry.pNext = nullptr;
+ vkASGeometry.geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR;
+ vkASGeometry.flags = 0;
+
+ auto& vkASInst = vkASGeometry.geometry.instances;
+ vkASInst.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR;
+ vkASInst.pNext = nullptr;
+ vkASInst.arrayOfPointers = VK_FALSE;
+ vkASInst.data.deviceAddress = pInstancesVk->GetVkDeviceAddress() + Attribs.InstanceBufferOffset;
+
+ VERIFY(vkASInst.data.deviceAddress % 16 == 0, "Instance data address is not properly aligned");
+
+ vkASBuildInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR;
+ vkASBuildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR; // type must be compatible with create info
+ vkASBuildInfo.flags = BuildASFlagsToVkBuildAccelerationStructureFlags(TLASDesc.Flags); // flags must be compatible with create info
+ vkASBuildInfo.mode = Attribs.Update ? VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR : VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR;
+ vkASBuildInfo.srcAccelerationStructure = Attribs.Update ? pTLASVk->GetVkTLAS() : VK_NULL_HANDLE;
+ vkASBuildInfo.dstAccelerationStructure = pTLASVk->GetVkTLAS();
+ vkASBuildInfo.geometryCount = 1;
+ vkASBuildInfo.pGeometries = &vkASGeometry;
+ vkASBuildInfo.ppGeometries = nullptr;
+ vkASBuildInfo.scratchData.deviceAddress = pScratchVk->GetVkDeviceAddress() + Attribs.ScratchBufferOffset;
+
+ m_CommandBuffer.BuildAccelerationStructure(1, &vkASBuildInfo, &vkRangePtr);
+ ++m_State.NumCommands;
+}
+
+void DeviceContextVkImpl::CopyBLAS(const CopyBLASAttribs& Attribs)
+{
+ if (!TDeviceContextBase::CopyBLAS(Attribs, 0))
+ return;
+
+ auto* pSrcVk = ValidatedCast<BottomLevelASVkImpl>(Attribs.pSrc);
+ auto* pDstVk = ValidatedCast<BottomLevelASVkImpl>(Attribs.pDst);
+
+ // Dst BLAS description has specified CompactedSize, but doesn't have specified pTriangles and pBoxes.
+ // We should copy geometries because it required for SBT to map geometry name to hit group.
+ pDstVk->CopyGeometryDescription(*pSrcVk);
+ pDstVk->SetActualGeometryCount(pSrcVk->GetActualGeometryCount());
+
+ VkCopyAccelerationStructureInfoKHR Info = {};
+
+ Info.sType = VK_STRUCTURE_TYPE_COPY_ACCELERATION_STRUCTURE_INFO_KHR;
+ Info.src = pSrcVk->GetVkBLAS();
+ Info.dst = pDstVk->GetVkBLAS();
+ Info.mode = CopyASModeToVkCopyAccelerationStructureMode(Attribs.Mode);
+
+ EnsureVkCmdBuffer();
+
+ const char* OpName = "Copy BottomLevelAS (DeviceContextVkImpl::CopyBLAS)";
+ TransitionOrVerifyBLASState(*pSrcVk, Attribs.SrcTransitionMode, RESOURCE_STATE_BUILD_AS_READ, OpName);
+ TransitionOrVerifyBLASState(*pDstVk, Attribs.DstTransitionMode, RESOURCE_STATE_BUILD_AS_WRITE, OpName);
+
+ m_CommandBuffer.CopyAccelerationStructure(Info);
+ ++m_State.NumCommands;
+
+#ifdef DILIGENT_DEVELOPMENT
+ pDstVk->UpdateVersion();
+#endif
+}
+
+void DeviceContextVkImpl::CopyTLAS(const CopyTLASAttribs& Attribs)
+{
+ if (!TDeviceContextBase::CopyTLAS(Attribs, 0))
+ return;
+
+ auto* pSrcVk = ValidatedCast<TopLevelASVkImpl>(Attribs.pSrc);
+ auto* pDstVk = ValidatedCast<TopLevelASVkImpl>(Attribs.pDst);
+
+ // Instances specified in BuildTLAS command.
+ // We should copy instances because it required for SBT to map instance name to hit group.
+ pDstVk->CopyInstancceData(*pSrcVk);
+
+ VkCopyAccelerationStructureInfoKHR Info = {};
+
+ Info.sType = VK_STRUCTURE_TYPE_COPY_ACCELERATION_STRUCTURE_INFO_KHR;
+ Info.src = pSrcVk->GetVkTLAS();
+ Info.dst = pDstVk->GetVkTLAS();
+ Info.mode = CopyASModeToVkCopyAccelerationStructureMode(Attribs.Mode);
+
+ EnsureVkCmdBuffer();
+
+ const char* OpName = "Copy TopLevelAS (DeviceContextVkImpl::CopyTLAS)";
+ TransitionOrVerifyTLASState(*pSrcVk, Attribs.SrcTransitionMode, RESOURCE_STATE_BUILD_AS_READ, OpName);
+ TransitionOrVerifyTLASState(*pDstVk, Attribs.DstTransitionMode, RESOURCE_STATE_BUILD_AS_WRITE, OpName);
+
+ m_CommandBuffer.CopyAccelerationStructure(Info);
+ ++m_State.NumCommands;
+}
+
+void DeviceContextVkImpl::WriteBLASCompactedSize(const WriteBLASCompactedSizeAttribs& Attribs)
+{
+ if (!TDeviceContextBase::WriteBLASCompactedSize(Attribs, 0))
+ return;
+
+ const Uint32 QueryIndex = 0;
+ auto* pBLASVk = ValidatedCast<BottomLevelASVkImpl>(Attribs.pBLAS);
+ auto* pDestBuffVk = ValidatedCast<BufferVkImpl>(Attribs.pDestBuffer);
+
+ EnsureVkCmdBuffer();
+
+ const char* OpName = "Write AS compacted size (DeviceContextVkImpl::WriteBLASCompactedSize)";
+ TransitionOrVerifyBLASState(*pBLASVk, Attribs.BLASTransitionMode, RESOURCE_STATE_BUILD_AS_READ, OpName);
+ TransitionOrVerifyBufferState(*pDestBuffVk, Attribs.BufferTransitionMode, RESOURCE_STATE_COPY_DEST, VK_ACCESS_TRANSFER_WRITE_BIT, OpName);
+
+ m_CommandBuffer.WriteAccelerationStructuresProperties(pBLASVk->GetVkBLAS(), VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR, m_ASQueryPool, QueryIndex);
+ m_CommandBuffer.CopyQueryPoolResults(m_ASQueryPool, QueryIndex, 1, pDestBuffVk->GetVkBuffer(), Attribs.DestBufferOffset, sizeof(Uint64), VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
+ m_CommandBuffer.ResetQueryPool(m_ASQueryPool, QueryIndex, 1);
+ ++m_State.NumCommands;
+}
+
+void DeviceContextVkImpl::WriteTLASCompactedSize(const WriteTLASCompactedSizeAttribs& Attribs)
+{
+ if (!TDeviceContextBase::WriteTLASCompactedSize(Attribs, 0))
+ return;
+
+ const Uint32 QueryIndex = 0;
+ auto* pTLASVk = ValidatedCast<TopLevelASVkImpl>(Attribs.pTLAS);
+ auto* pDestBuffVk = ValidatedCast<BufferVkImpl>(Attribs.pDestBuffer);
+
+ EnsureVkCmdBuffer();
+
+ const char* OpName = "Write AS compacted size (DeviceContextVkImpl::WriteTLASCompactedSize)";
+ TransitionOrVerifyTLASState(*pTLASVk, Attribs.TLASTransitionMode, RESOURCE_STATE_BUILD_AS_READ, OpName);
+ TransitionOrVerifyBufferState(*pDestBuffVk, Attribs.BufferTransitionMode, RESOURCE_STATE_COPY_DEST, VK_ACCESS_TRANSFER_WRITE_BIT, OpName);
+
+ m_CommandBuffer.WriteAccelerationStructuresProperties(pTLASVk->GetVkTLAS(), VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR, m_ASQueryPool, QueryIndex);
+ m_CommandBuffer.CopyQueryPoolResults(m_ASQueryPool, QueryIndex, 1, pDestBuffVk->GetVkBuffer(), Attribs.DestBufferOffset, sizeof(Uint64), VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
+ m_CommandBuffer.ResetQueryPool(m_ASQueryPool, QueryIndex, 1);
+ ++m_State.NumCommands;
+}
+
+void DeviceContextVkImpl::CreateASCompactedSizeQueryPool()
+{
+ if (m_pDevice->GetDeviceCaps().Features.RayTracing == DEVICE_FEATURE_STATE_ENABLED)
+ {
+ const auto& LogicalDevice = m_pDevice->GetLogicalDevice();
+ VkQueryPoolCreateInfo Info = {};
+
+ Info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
+ Info.queryCount = 1;
+ Info.queryType = VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR;
+
+ m_ASQueryPool = LogicalDevice.CreateQueryPool(Info);
+ }
+}
+
+void DeviceContextVkImpl::TraceRays(const TraceRaysAttribs& Attribs)
+{
+ if (!TDeviceContextBase::TraceRays(Attribs, 0))
+ return;
+
+ auto* pSBTVk = ValidatedCast<ShaderBindingTableVkImpl>(Attribs.pSBT);
+ IBuffer* pBuffer = nullptr;
+
+ ShaderBindingTableVkImpl::BindingTable RayGenShaderRecord = {};
+ ShaderBindingTableVkImpl::BindingTable MissShaderTable = {};
+ ShaderBindingTableVkImpl::BindingTable HitGroupTable = {};
+ ShaderBindingTableVkImpl::BindingTable CallableShaderTable = {};
+
+ pSBTVk->GetData(pBuffer, RayGenShaderRecord, MissShaderTable, HitGroupTable, CallableShaderTable);
+
+ auto* pSBTBufferVk = ValidatedCast<BufferVkImpl>(pBuffer);
+
+ const char* OpName = "Trace rays (DeviceContextVkImpl::TraceRays)";
+ TransitionOrVerifyBufferState(*pSBTBufferVk, Attribs.SBTTransitionMode, RESOURCE_STATE_COPY_DEST, VK_ACCESS_TRANSFER_WRITE_BIT, OpName);
+
+ // buffer ranges are not intersected, so we don't need to add barriers between them
+ if (RayGenShaderRecord.pData)
+ UpdateBuffer(pBuffer, RayGenShaderRecord.Offset, RayGenShaderRecord.Size, RayGenShaderRecord.pData, RESOURCE_STATE_TRANSITION_MODE_VERIFY);
+
+ if (MissShaderTable.pData)
+ UpdateBuffer(pBuffer, MissShaderTable.Offset, MissShaderTable.Size, MissShaderTable.pData, RESOURCE_STATE_TRANSITION_MODE_VERIFY);
+
+ if (HitGroupTable.pData)
+ UpdateBuffer(pBuffer, HitGroupTable.Offset, HitGroupTable.Size, HitGroupTable.pData, RESOURCE_STATE_TRANSITION_MODE_VERIFY);
+
+ if (CallableShaderTable.pData)
+ UpdateBuffer(pBuffer, CallableShaderTable.Offset, CallableShaderTable.Size, CallableShaderTable.pData, RESOURCE_STATE_TRANSITION_MODE_VERIFY);
+
+ TransitionOrVerifyBufferState(*pSBTBufferVk, Attribs.SBTTransitionMode, RESOURCE_STATE_RAY_TRACING, VK_ACCESS_SHADER_READ_BIT, OpName);
+
+ // clang-format off
+ VkStridedDeviceAddressRegionKHR RaygenShaderBindingTable = {pSBTBufferVk->GetVkDeviceAddress() + RayGenShaderRecord.Offset, RayGenShaderRecord.Stride, RayGenShaderRecord.Size };
+ VkStridedDeviceAddressRegionKHR MissShaderBindingTable = {pSBTBufferVk->GetVkDeviceAddress() + MissShaderTable.Offset, MissShaderTable.Stride, MissShaderTable.Size };
+ VkStridedDeviceAddressRegionKHR HitShaderBindingTable = {pSBTBufferVk->GetVkDeviceAddress() + HitGroupTable.Offset, HitGroupTable.Stride, HitGroupTable.Size };
+ VkStridedDeviceAddressRegionKHR CallableShaderBindingTable = {pSBTBufferVk->GetVkDeviceAddress() + CallableShaderTable.Offset, CallableShaderTable.Stride, CallableShaderTable.Size};
+ // clang-format on
+
+ PrepareForRayTracing();
+ m_CommandBuffer.TraceRays(RaygenShaderBindingTable, MissShaderBindingTable, HitShaderBindingTable, CallableShaderBindingTable,
+ Attribs.DimensionX, Attribs.DimensionY, Attribs.DimensionZ);
+ ++m_State.NumCommands;
+}
+
} // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp b/Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp
index fbbd9492..ed537333 100644
--- a/Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp
@@ -137,7 +137,12 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E
try
{
+ Uint32 Version = VK_API_VERSION_1_0;
+ if (EngineCI.Features.RayTracing != DEVICE_FEATURE_STATE_DISABLED)
+ Version = VK_API_VERSION_1_2;
+
auto Instance = VulkanUtilities::VulkanInstance::Create(
+ Version,
EngineCI.EnableValidation,
EngineCI.GlobalExtensionCount,
EngineCI.ppGlobalExtensionNames,
@@ -238,7 +243,11 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E
VK_KHR_MAINTENANCE1_EXTENSION_NAME // To allow negative viewport height
};
- const auto& DeviceExtFeatures = PhysicalDevice->GetExtFeatures();
+ const VulkanUtilities::VulkanPhysicalDevice::ExtensionFeatures& DeviceExtFeatures = PhysicalDevice->GetExtFeatures();
+ VulkanUtilities::VulkanPhysicalDevice::ExtensionFeatures EnabledExtFeats = {};
+
+ // SPIRV 1.5 is in Vulkan 1.2 core
+ EnabledExtFeats.Spirv15 = DeviceExtFeatures.Spirv15;
#define ENABLE_FEATURE(IsFeatureSupported, Feature, FeatureName) \
do \
@@ -247,64 +256,71 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E
GetFeatureState(EngineCI.Features.Feature, IsFeatureSupported, FeatureName); \
} while (false)
-
- auto MeshShaderFeats = DeviceExtFeatures.MeshShader;
+ const auto& MeshShaderFeats = DeviceExtFeatures.MeshShader;
ENABLE_FEATURE(MeshShaderFeats.taskShader != VK_FALSE && MeshShaderFeats.meshShader != VK_FALSE, MeshShaders, "Mesh shaders are");
- auto ShaderFloat16Int8 = DeviceExtFeatures.ShaderFloat16Int8;
+ const auto& ShaderFloat16Int8Feats = DeviceExtFeatures.ShaderFloat16Int8;
// clang-format off
- ENABLE_FEATURE(ShaderFloat16Int8.shaderFloat16 != VK_FALSE, ShaderFloat16, "16-bit float shader operations are");
- ENABLE_FEATURE(ShaderFloat16Int8.shaderInt8 != VK_FALSE, ShaderInt8, "8-bit int shader operations are");
+ ENABLE_FEATURE(ShaderFloat16Int8Feats.shaderFloat16 != VK_FALSE, ShaderFloat16, "16-bit float shader operations are");
+ ENABLE_FEATURE(ShaderFloat16Int8Feats.shaderInt8 != VK_FALSE, ShaderInt8, "8-bit int shader operations are");
// clang-format on
- auto Storage16BitFeats = DeviceExtFeatures.Storage16Bit;
+ const auto& Storage16BitFeats = DeviceExtFeatures.Storage16Bit;
// clang-format off
ENABLE_FEATURE(Storage16BitFeats.storageBuffer16BitAccess != VK_FALSE, ResourceBuffer16BitAccess, "16-bit resoure buffer access is");
ENABLE_FEATURE(Storage16BitFeats.uniformAndStorageBuffer16BitAccess != VK_FALSE, UniformBuffer16BitAccess, "16-bit uniform buffer access is");
ENABLE_FEATURE(Storage16BitFeats.storageInputOutput16 != VK_FALSE, ShaderInputOutput16, "16-bit shader inputs/outputs are");
// clang-format on
- auto Storage8BitFeats = DeviceExtFeatures.Storage8Bit;
+ const auto& Storage8BitFeats = DeviceExtFeatures.Storage8Bit;
// clang-format off
ENABLE_FEATURE(Storage8BitFeats.storageBuffer8BitAccess != VK_FALSE, ResourceBuffer8BitAccess, "8-bit resoure buffer access is");
ENABLE_FEATURE(Storage8BitFeats.uniformAndStorageBuffer8BitAccess != VK_FALSE, UniformBuffer8BitAccess, "8-bit uniform buffer access is");
// clang-format on
+
+ ENABLE_FEATURE(DeviceExtFeatures.AccelStruct.accelerationStructure != VK_FALSE && DeviceExtFeatures.RayTracingPipeline.rayTracingPipeline != VK_FALSE, RayTracing, "Ray tracing is");
#undef FeatureSupport
// To enable some device extensions you must enable instance extension VK_KHR_get_physical_device_properties2
// and add feature description to DeviceCreateInfo.pNext.
- const auto SupportsFeatures2 = Instance->IsExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+ bool SupportsFeatures2 = Instance->IsExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+
+ // Enable extensions
if (SupportsFeatures2)
{
void** NextExt = const_cast<void**>(&DeviceCreateInfo.pNext);
+
+ // Mesh shader
if (EngineCI.Features.MeshShaders != DEVICE_FEATURE_STATE_DISABLED)
{
- VERIFY_EXPR(MeshShaderFeats.taskShader != VK_FALSE && MeshShaderFeats.meshShader != VK_FALSE);
+ EnabledExtFeats.MeshShader = MeshShaderFeats;
+ VERIFY_EXPR(EnabledExtFeats.MeshShader.taskShader != VK_FALSE && EnabledExtFeats.MeshShader.meshShader != VK_FALSE);
VERIFY(PhysicalDevice->IsExtensionSupported(VK_NV_MESH_SHADER_EXTENSION_NAME),
"VK_NV_mesh_shader extension must be supported as it has already been checked by VulkanPhysicalDevice and "
"both taskShader and meshShader features are TRUE");
DeviceExtensions.push_back(VK_NV_MESH_SHADER_EXTENSION_NAME);
- *NextExt = &MeshShaderFeats;
- NextExt = &MeshShaderFeats.pNext;
+ *NextExt = &EnabledExtFeats.MeshShader;
+ NextExt = &EnabledExtFeats.MeshShader.pNext;
}
if (EngineCI.Features.ShaderFloat16 != DEVICE_FEATURE_STATE_DISABLED ||
EngineCI.Features.ShaderInt8 != DEVICE_FEATURE_STATE_DISABLED)
{
- VERIFY_EXPR(ShaderFloat16Int8.shaderFloat16 != VK_FALSE || ShaderFloat16Int8.shaderInt8 != VK_FALSE);
+ EnabledExtFeats.ShaderFloat16Int8 = ShaderFloat16Int8Feats;
+ VERIFY_EXPR(EnabledExtFeats.ShaderFloat16Int8.shaderFloat16 != VK_FALSE || EnabledExtFeats.ShaderFloat16Int8.shaderInt8 != VK_FALSE);
VERIFY(PhysicalDevice->IsExtensionSupported(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME),
"VK_KHR_shader_float16_int8 extension must be supported as it has already been checked by VulkanPhysicalDevice "
"and at least one of shaderFloat16 or shaderInt8 features is TRUE");
DeviceExtensions.push_back(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME);
if (EngineCI.Features.ShaderFloat16 == DEVICE_FEATURE_STATE_DISABLED)
- ShaderFloat16Int8.shaderFloat16 = VK_FALSE;
+ EnabledExtFeats.ShaderFloat16Int8.shaderFloat16 = VK_FALSE;
if (EngineCI.Features.ShaderInt8 == DEVICE_FEATURE_STATE_DISABLED)
- ShaderFloat16Int8.shaderInt8 = VK_FALSE;
+ EnabledExtFeats.ShaderFloat16Int8.shaderInt8 = VK_FALSE;
- *NextExt = &ShaderFloat16Int8;
- NextExt = &ShaderFloat16Int8.pNext;
+ *NextExt = &EnabledExtFeats.ShaderFloat16Int8;
+ NextExt = &EnabledExtFeats.ShaderFloat16Int8.pNext;
}
bool StorageBufferStorageClassExtensionRequired = false;
@@ -316,9 +332,10 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E
// clang-format on
{
// clang-format off
- VERIFY_EXPR(EngineCI.Features.ResourceBuffer16BitAccess == DEVICE_FEATURE_STATE_DISABLED || Storage16BitFeats.storageBuffer16BitAccess != VK_FALSE);
- VERIFY_EXPR(EngineCI.Features.UniformBuffer16BitAccess == DEVICE_FEATURE_STATE_DISABLED || Storage16BitFeats.uniformAndStorageBuffer16BitAccess != VK_FALSE);
- VERIFY_EXPR(EngineCI.Features.ShaderInputOutput16 == DEVICE_FEATURE_STATE_DISABLED || Storage16BitFeats.storageInputOutput16 != VK_FALSE);
+ EnabledExtFeats.Storage16Bit = Storage16BitFeats;
+ VERIFY_EXPR(EngineCI.Features.ResourceBuffer16BitAccess == DEVICE_FEATURE_STATE_DISABLED || EnabledExtFeats.Storage16Bit.storageBuffer16BitAccess != VK_FALSE);
+ VERIFY_EXPR(EngineCI.Features.UniformBuffer16BitAccess == DEVICE_FEATURE_STATE_DISABLED || EnabledExtFeats.Storage16Bit.uniformAndStorageBuffer16BitAccess != VK_FALSE);
+ VERIFY_EXPR(EngineCI.Features.ShaderInputOutput16 == DEVICE_FEATURE_STATE_DISABLED || EnabledExtFeats.Storage16Bit.storageInputOutput16 != VK_FALSE);
// clang-format on
VERIFY(PhysicalDevice->IsExtensionSupported(VK_KHR_16BIT_STORAGE_EXTENSION_NAME),
@@ -335,14 +352,14 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E
StorageBufferStorageClassExtensionRequired = true;
if (EngineCI.Features.ResourceBuffer16BitAccess == DEVICE_FEATURE_STATE_DISABLED)
- Storage16BitFeats.storageBuffer16BitAccess = VK_FALSE;
+ EnabledExtFeats.Storage16Bit.storageBuffer16BitAccess = VK_FALSE;
if (EngineCI.Features.UniformBuffer16BitAccess == DEVICE_FEATURE_STATE_DISABLED)
- Storage16BitFeats.uniformAndStorageBuffer16BitAccess = VK_FALSE;
+ EnabledExtFeats.Storage16Bit.uniformAndStorageBuffer16BitAccess = VK_FALSE;
if (EngineCI.Features.ShaderInputOutput16 == DEVICE_FEATURE_STATE_DISABLED)
- Storage16BitFeats.storageInputOutput16 = VK_FALSE;
+ EnabledExtFeats.Storage16Bit.storageInputOutput16 = VK_FALSE;
- *NextExt = &Storage16BitFeats;
- NextExt = &Storage16BitFeats.pNext;
+ *NextExt = &EnabledExtFeats.Storage16Bit;
+ NextExt = &EnabledExtFeats.Storage16Bit.pNext;
}
// clang-format off
@@ -351,8 +368,9 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E
// clang-format on
{
// clang-format off
- VERIFY_EXPR(EngineCI.Features.ResourceBuffer8BitAccess == DEVICE_FEATURE_STATE_DISABLED || Storage8BitFeats.storageBuffer8BitAccess != VK_FALSE);
- VERIFY_EXPR(EngineCI.Features.UniformBuffer8BitAccess == DEVICE_FEATURE_STATE_DISABLED || Storage8BitFeats.uniformAndStorageBuffer8BitAccess != VK_FALSE);
+ EnabledExtFeats.Storage8Bit = Storage8BitFeats;
+ VERIFY_EXPR(EngineCI.Features.ResourceBuffer8BitAccess == DEVICE_FEATURE_STATE_DISABLED || EnabledExtFeats.Storage8Bit.storageBuffer8BitAccess != VK_FALSE);
+ VERIFY_EXPR(EngineCI.Features.UniformBuffer8BitAccess == DEVICE_FEATURE_STATE_DISABLED || EnabledExtFeats.Storage8Bit.uniformAndStorageBuffer8BitAccess != VK_FALSE);
// clang-format on
VERIFY(PhysicalDevice->IsExtensionSupported(VK_KHR_8BIT_STORAGE_EXTENSION_NAME),
@@ -369,12 +387,12 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E
StorageBufferStorageClassExtensionRequired = true;
if (EngineCI.Features.ResourceBuffer8BitAccess == DEVICE_FEATURE_STATE_DISABLED)
- Storage8BitFeats.storageBuffer8BitAccess = VK_FALSE;
+ EnabledExtFeats.Storage8Bit.storageBuffer8BitAccess = VK_FALSE;
if (EngineCI.Features.UniformBuffer8BitAccess == DEVICE_FEATURE_STATE_DISABLED)
- Storage8BitFeats.uniformAndStorageBuffer8BitAccess = VK_FALSE;
+ EnabledExtFeats.Storage8Bit.uniformAndStorageBuffer8BitAccess = VK_FALSE;
- *NextExt = &Storage8BitFeats;
- NextExt = &Storage8BitFeats.pNext;
+ *NextExt = &EnabledExtFeats.Storage8Bit;
+ NextExt = &EnabledExtFeats.Storage8Bit.pNext;
}
if (StorageBufferStorageClassExtensionRequired)
@@ -383,21 +401,65 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E
DeviceExtensions.push_back(VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME);
}
- *NextExt = nullptr;
- }
+ // Ray tracing
+ if (EngineCI.Features.RayTracing != DEVICE_FEATURE_STATE_DISABLED)
+ {
+ // this extensions added to Vulkan 1.2 core
+ if (!DeviceExtFeatures.Spirv15)
+ {
+ DeviceExtensions.push_back(VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME); // required for VK_KHR_spirv_1_4
+ DeviceExtensions.push_back(VK_KHR_SPIRV_1_4_EXTENSION_NAME); // required for VK_KHR_ray_tracing_pipeline
+ EnabledExtFeats.Spirv14 = DeviceExtFeatures.Spirv14;
+ VERIFY_EXPR(DeviceExtFeatures.Spirv14);
+ }
+ DeviceExtensions.push_back(VK_KHR_MAINTENANCE3_EXTENSION_NAME); // required for VK_EXT_descriptor_indexing
+ DeviceExtensions.push_back(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); // required for VK_KHR_acceleration_structure
+ DeviceExtensions.push_back(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); // required for VK_KHR_acceleration_structure
+ DeviceExtensions.push_back(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); // required for VK_KHR_acceleration_structure
+ DeviceExtensions.push_back(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME); // required for ray tracing
+ DeviceExtensions.push_back(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME); // required for ray tracing
+
+ EnabledExtFeats.AccelStruct = DeviceExtFeatures.AccelStruct;
+ EnabledExtFeats.RayTracingPipeline = DeviceExtFeatures.RayTracingPipeline;
+ EnabledExtFeats.BufferDeviceAddress = DeviceExtFeatures.BufferDeviceAddress;
+ EnabledExtFeats.DescriptorIndexing = DeviceExtFeatures.DescriptorIndexing;
+
+ // disable unused features
+ EnabledExtFeats.AccelStruct.accelerationStructureCaptureReplay = false;
+ EnabledExtFeats.AccelStruct.accelerationStructureIndirectBuild = false;
+ EnabledExtFeats.AccelStruct.accelerationStructureHostCommands = false;
+ EnabledExtFeats.AccelStruct.descriptorBindingAccelerationStructureUpdateAfterBind = false;
+
+ EnabledExtFeats.RayTracingPipeline.rayTracingPipelineShaderGroupHandleCaptureReplay = false;
+ EnabledExtFeats.RayTracingPipeline.rayTracingPipelineShaderGroupHandleCaptureReplayMixed = false;
+ EnabledExtFeats.RayTracingPipeline.rayTracingPipelineTraceRaysIndirect = false;
+ EnabledExtFeats.RayTracingPipeline.rayTraversalPrimitiveCulling = false; // for GLSL_EXT_ray_flags_primitive_culling
+
+ *NextExt = &EnabledExtFeats.AccelStruct;
+ NextExt = &EnabledExtFeats.AccelStruct.pNext;
+ *NextExt = &EnabledExtFeats.RayTracingPipeline;
+ NextExt = &EnabledExtFeats.RayTracingPipeline.pNext;
+ *NextExt = &EnabledExtFeats.DescriptorIndexing;
+ NextExt = &EnabledExtFeats.DescriptorIndexing.pNext;
+ *NextExt = &EnabledExtFeats.BufferDeviceAddress;
+ NextExt = &EnabledExtFeats.BufferDeviceAddress.pNext;
+ }
+
+ // make sure that last pNext is null
+ *NextExt = nullptr;
+ }
#if defined(_MSC_VER) && defined(_WIN64)
- static_assert(sizeof(DeviceFeatures) == 31, "Did you add a new feature to DeviceFeatures? Please handle its satus here.");
+ static_assert(sizeof(DeviceFeatures) == 32, "Did you add a new feature to DeviceFeatures? Please handle its satus here.");
#endif
DeviceCreateInfo.ppEnabledExtensionNames = DeviceExtensions.empty() ? nullptr : DeviceExtensions.data();
DeviceCreateInfo.enabledExtensionCount = static_cast<uint32_t>(DeviceExtensions.size());
- auto vkAllocator = Instance->GetVkAllocator();
- auto vkPhysicalDevice = PhysicalDevice->GetVkDeviceHandle();
- auto LogicalDevice = VulkanUtilities::VulkanLogicalDevice::Create(vkPhysicalDevice, DeviceCreateInfo, vkAllocator);
+ auto vkAllocator = Instance->GetVkAllocator();
+ auto LogicalDevice = VulkanUtilities::VulkanLogicalDevice::Create(*PhysicalDevice, DeviceCreateInfo, EnabledExtFeats, vkAllocator);
auto& RawMemAllocator = GetRawAllocator();
diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp
index b221659a..3840b739 100644
--- a/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp
@@ -45,18 +45,19 @@ class ResourceTypeToVkDescriptorType
public:
ResourceTypeToVkDescriptorType()
{
- static_assert(SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes == 11, "Please add the corresponding decriptor type");
- m_Map[SPIRVShaderResourceAttribs::ResourceType::UniformBuffer] = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
- m_Map[SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer] = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
- m_Map[SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer] = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
- m_Map[SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer] = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
- m_Map[SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer] = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
- m_Map[SPIRVShaderResourceAttribs::ResourceType::StorageImage] = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
- m_Map[SPIRVShaderResourceAttribs::ResourceType::SampledImage] = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
- m_Map[SPIRVShaderResourceAttribs::ResourceType::AtomicCounter] = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
- m_Map[SPIRVShaderResourceAttribs::ResourceType::SeparateImage] = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
- m_Map[SPIRVShaderResourceAttribs::ResourceType::SeparateSampler] = VK_DESCRIPTOR_TYPE_SAMPLER;
- m_Map[SPIRVShaderResourceAttribs::ResourceType::InputAttachment] = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
+ static_assert(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
@@ -65,13 +66,13 @@ public:
}
private:
- std::array<VkDescriptorType, SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes> m_Map = {};
+ std::array<VkDescriptorType, Uint32{SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes}> m_Map = {};
};
-VkDescriptorType PipelineLayout::GetVkDescriptorType(const SPIRVShaderResourceAttribs& Res)
+VkDescriptorType PipelineLayout::GetVkDescriptorType(SPIRVShaderResourceAttribs::ResourceType Type)
{
static const ResourceTypeToVkDescriptorType ResTypeToVkDescrType;
- return ResTypeToVkDescrType[Res.Type];
+ return ResTypeToVkDescrType[Type];
}
PipelineLayout::DescriptorSetLayoutManager::DescriptorSetLayoutManager(IMemoryAllocator& MemAllocator) :
@@ -331,7 +332,7 @@ void PipelineLayout::DescriptorSetLayoutManager::AllocateResourceSlot(const SPIR
Binding = DescrSet.NumLayoutBindings;
VkBinding.binding = Binding;
- VkBinding.descriptorType = GetVkDescriptorType(ResAttribs);
+ VkBinding.descriptorType = GetVkDescriptorType(ResAttribs.Type);
VkBinding.descriptorCount = ResAttribs.ArraySize;
// There are no limitations on what combinations of stages can use a descriptor binding (13.2.1)
VkBinding.stageFlags = ShaderTypeToVkShaderStageFlagBit(ShaderType);
@@ -369,16 +370,13 @@ void PipelineLayout::AllocateResourceSlot(const SPIRVShaderResourceAttribs& ResA
SHADER_TYPE ShaderType,
Uint32& DescriptorSet, // Output parameter
Uint32& Binding, // Output parameter
- Uint32& OffsetInCache,
- std::vector<uint32_t>& SPIRV)
+ Uint32& OffsetInCache)
{
VERIFY((ResAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage ||
ResAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler) ||
vkImmutableSampler == VK_NULL_HANDLE,
"Immutable sampler should only be specified for combined image samplers or separate samplers");
m_LayoutMgr.AllocateResourceSlot(ResAttribs, VariableType, vkImmutableSampler, ShaderType, DescriptorSet, Binding, OffsetInCache);
- SPIRV[ResAttribs.BindingDecorationOffset] = Binding;
- SPIRV[ResAttribs.DescriptorSetDecorationOffset] = DescriptorSet;
}
void PipelineLayout::Finalize(const VulkanUtilities::VulkanLogicalDevice& LogicalDevice)
@@ -435,7 +433,7 @@ void PipelineLayout::InitResourceCache(RenderDeviceVkImpl* pDeviceVkImpl,
}
void PipelineLayout::PrepareDescriptorSets(DeviceContextVkImpl* pCtxVkImpl,
- bool IsCompute,
+ VkPipelineBindPoint BindPoint,
const ShaderResourceCacheVk& ResourceCache,
DescriptorSetBindInfo& BindInfo,
VkDescriptorSet VkDynamicDescrSet) const
@@ -481,7 +479,7 @@ void PipelineLayout::PrepareDescriptorSets(DeviceContextVkImpl* pCtxVkIm
BindInfo.DynamicOffsetCount = TotalDynamicDescriptors;
if (TotalDynamicDescriptors > BindInfo.DynamicOffsets.size())
BindInfo.DynamicOffsets.resize(TotalDynamicDescriptors);
- BindInfo.BindPoint = IsCompute ? VK_PIPELINE_BIND_POINT_COMPUTE : VK_PIPELINE_BIND_POINT_GRAPHICS;
+ BindInfo.BindPoint = BindPoint;
BindInfo.pResourceCache = &ResourceCache;
#ifdef DILIGENT_DEBUG
BindInfo.pDbgPipelineLayout = this;
diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp
index 2325f9cb..7d846b90 100644
--- a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp
@@ -44,98 +44,24 @@
namespace Diligent
{
-
-RenderPassDesc PipelineStateVkImpl::GetImplicitRenderPassDesc(
- Uint32 NumRenderTargets,
- const TEXTURE_FORMAT RTVFormats[],
- TEXTURE_FORMAT DSVFormat,
- Uint8 SampleCount,
- std::array<RenderPassAttachmentDesc, MAX_RENDER_TARGETS + 1>& Attachments,
- std::array<AttachmentReference, MAX_RENDER_TARGETS + 1>& AttachmentReferences,
- SubpassDesc& SubpassDesc)
+namespace
{
- VERIFY_EXPR(NumRenderTargets <= MAX_RENDER_TARGETS);
-
- RenderPassDesc RPDesc;
-
- RPDesc.AttachmentCount = (DSVFormat != TEX_FORMAT_UNKNOWN ? 1 : 0) + NumRenderTargets;
-
- uint32_t AttachmentInd = 0;
- AttachmentReference* pDepthAttachmentReference = nullptr;
- if (DSVFormat != TEX_FORMAT_UNKNOWN)
- {
- auto& DepthAttachment = Attachments[AttachmentInd];
-
- DepthAttachment.Format = DSVFormat;
- DepthAttachment.SampleCount = SampleCount;
- DepthAttachment.LoadOp = ATTACHMENT_LOAD_OP_LOAD; // previous contents of the image within the render area
- // will be preserved. For attachments with a depth/stencil format,
- // this uses the access type VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT.
- DepthAttachment.StoreOp = ATTACHMENT_STORE_OP_STORE; // the contents generated during the render pass and within the render
- // area are written to memory. For attachments with a depth/stencil format,
- // this uses the access type VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT.
- DepthAttachment.StencilLoadOp = ATTACHMENT_LOAD_OP_LOAD;
- DepthAttachment.StencilStoreOp = ATTACHMENT_STORE_OP_STORE;
- DepthAttachment.InitialState = RESOURCE_STATE_DEPTH_WRITE;
- DepthAttachment.FinalState = RESOURCE_STATE_DEPTH_WRITE;
-
- pDepthAttachmentReference = &AttachmentReferences[AttachmentInd];
- pDepthAttachmentReference->AttachmentIndex = AttachmentInd;
- pDepthAttachmentReference->State = RESOURCE_STATE_DEPTH_WRITE;
-
- ++AttachmentInd;
- }
-
- AttachmentReference* pColorAttachmentsReference = NumRenderTargets > 0 ? &AttachmentReferences[AttachmentInd] : nullptr;
- for (Uint32 rt = 0; rt < NumRenderTargets; ++rt, ++AttachmentInd)
- {
- auto& ColorAttachment = Attachments[AttachmentInd];
-
- ColorAttachment.Format = RTVFormats[rt];
- ColorAttachment.SampleCount = SampleCount;
- ColorAttachment.LoadOp = ATTACHMENT_LOAD_OP_LOAD; // previous contents of the image within the render area
- // will be preserved. For attachments with a depth/stencil format,
- // this uses the access type VK_ACCESS_COLOR_ATTACHMENT_READ_BIT.
- ColorAttachment.StoreOp = ATTACHMENT_STORE_OP_STORE; // the contents generated during the render pass and within the render
- // area are written to memory. For attachments with a color format,
- // this uses the access type VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT.
- ColorAttachment.StencilLoadOp = ATTACHMENT_LOAD_OP_DISCARD;
- ColorAttachment.StencilStoreOp = ATTACHMENT_STORE_OP_DISCARD;
- ColorAttachment.InitialState = RESOURCE_STATE_RENDER_TARGET;
- ColorAttachment.FinalState = RESOURCE_STATE_RENDER_TARGET;
-
- auto& ColorAttachmentRef = AttachmentReferences[AttachmentInd];
- ColorAttachmentRef.AttachmentIndex = AttachmentInd;
- ColorAttachmentRef.State = RESOURCE_STATE_RENDER_TARGET;
- }
-
- RPDesc.pAttachments = Attachments.data();
- RPDesc.SubpassCount = 1;
- RPDesc.pSubpasses = &SubpassDesc;
- RPDesc.DependencyCount = 0; // the number of dependencies between pairs of subpasses, or zero indicating no dependencies.
- RPDesc.pDependencies = nullptr; // an array of dependencyCount number of VkSubpassDependency structures describing
- // dependencies between pairs of subpasses, or NULL if dependencyCount is zero.
-
-
- SubpassDesc.InputAttachmentCount = 0;
- SubpassDesc.pInputAttachments = nullptr;
- SubpassDesc.RenderTargetAttachmentCount = NumRenderTargets;
- SubpassDesc.pRenderTargetAttachments = pColorAttachmentsReference;
- SubpassDesc.pResolveAttachments = nullptr;
- SubpassDesc.pDepthStencilAttachment = pDepthAttachmentReference;
- SubpassDesc.PreserveAttachmentCount = 0;
- SubpassDesc.pPreserveAttachments = nullptr;
-
- return RPDesc;
-}
-static bool StripReflection(std::vector<uint32_t>& SPIRV)
+bool StripReflection(const VulkanUtilities::VulkanLogicalDevice& LogicalDevice, std::vector<uint32_t>& SPIRV)
{
#if DILIGENT_NO_HLSL
- return false;
+ return true;
#else
std::vector<uint32_t> StrippedSPIRV;
- spvtools::Optimizer SpirvOptimizer(SPV_ENV_VULKAN_1_0);
+ spv_target_env Target = SPV_ENV_VULKAN_1_0;
+ const auto& ExtFeats = LogicalDevice.GetEnabledExtFeatures();
+
+ if (ExtFeats.Spirv15)
+ Target = SPV_ENV_VULKAN_1_2;
+ else if (ExtFeats.Spirv14)
+ Target = SPV_ENV_VULKAN_1_1_SPIRV_1_4;
+
+ spvtools::Optimizer SpirvOptimizer(Target);
// Decorations defined in SPV_GOOGLE_hlsl_functionality1 are the only instructions
// removed by strip-reflect-info pass. SPIRV offsets become INVALID after this operation.
SpirvOptimizer.RegisterPass(spvtools::CreateStripReflectInfoPass());
@@ -149,21 +75,25 @@ static bool StripReflection(std::vector<uint32_t>& SPIRV)
#endif
}
-static void InitPipelineShaderStages(const VulkanUtilities::VulkanLogicalDevice& LogicalDevice,
- ShaderResourceLayoutVk::TShaderStages& ShaderStages,
- std::vector<VulkanUtilities::ShaderModuleWrapper>& vkShaderModules,
- std::vector<VkPipelineShaderStageCreateInfo>& vkPipelineShaderStages)
+void InitPipelineShaderStages(const VulkanUtilities::VulkanLogicalDevice& LogicalDevice,
+ ShaderResourceLayoutVk::TShaderStages& ShaderStages,
+ std::vector<VulkanUtilities::ShaderModuleWrapper>& ShaderModules,
+ std::vector<VkPipelineShaderStageCreateInfo>& Stages)
{
for (size_t s = 0; s < ShaderStages.size(); ++s)
{
- auto& StageInfo = ShaderStages[s];
+ const auto& Shaders = ShaderStages[s].Shaders;
+ auto& SPIRVs = ShaderStages[s].SPIRVs;
+ const auto ShaderType = ShaderStages[s].Type;
+
+ VERIFY_EXPR(Shaders.size() == SPIRVs.size());
VkPipelineShaderStageCreateInfo StageCI = {};
StageCI.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
StageCI.pNext = nullptr;
StageCI.flags = 0; // reserved for future use
- StageCI.stage = ShaderTypeToVkShaderStageFlagBit(StageInfo.Type);
+ StageCI.stage = ShaderTypeToVkShaderStageFlagBit(ShaderType);
VkShaderModuleCreateInfo ShaderModuleCI = {};
@@ -171,25 +101,31 @@ static void InitPipelineShaderStages(const VulkanUtilities::VulkanLogicalDevice&
ShaderModuleCI.pNext = nullptr;
ShaderModuleCI.flags = 0;
- // We have to strip reflection instructions to fix the follownig validation error:
- // SPIR-V module not valid: DecorateStringGOOGLE requires one of the following extensions: SPV_GOOGLE_decorate_string
- // Optimizer also performs validation and may catch problems with the byte code.
- if (!StripReflection(StageInfo.SPIRV))
- LOG_ERROR("Failed to strip reflection information from shader '", StageInfo.pShader->GetDesc().Name, "'. This may indicate a problem with the byte code.");
+ for (size_t i = 0; i < Shaders.size(); ++i)
+ {
+ auto* pShader = Shaders[i];
+ auto& SPIRV = SPIRVs[i];
+
+ // We have to strip reflection instructions to fix the follownig validation error:
+ // SPIR-V module not valid: DecorateStringGOOGLE requires one of the following extensions: SPV_GOOGLE_decorate_string
+ // Optimizer also performs validation and may catch problems with the byte code.
+ if (!StripReflection(LogicalDevice, SPIRV))
+ LOG_ERROR("Failed to strip reflection information from shader '", pShader->GetDesc().Name, "'. This may indicate a problem with the byte code.");
- ShaderModuleCI.codeSize = StageInfo.SPIRV.size() * sizeof(uint32_t);
- ShaderModuleCI.pCode = StageInfo.SPIRV.data();
+ ShaderModuleCI.codeSize = SPIRV.size() * sizeof(uint32_t);
+ ShaderModuleCI.pCode = SPIRV.data();
- vkShaderModules.push_back(LogicalDevice.CreateShaderModule(ShaderModuleCI, StageInfo.pShader->GetDesc().Name));
+ ShaderModules.push_back(LogicalDevice.CreateShaderModule(ShaderModuleCI, pShader->GetDesc().Name));
- StageCI.module = vkShaderModules.back();
- StageCI.pName = StageInfo.pShader->GetEntryPoint();
- StageCI.pSpecializationInfo = nullptr;
+ StageCI.module = ShaderModules.back();
+ StageCI.pName = pShader->GetEntryPoint();
+ StageCI.pSpecializationInfo = nullptr;
- vkPipelineShaderStages.push_back(StageCI);
+ Stages.push_back(StageCI);
+ }
}
- VERIFY_EXPR(vkShaderModules.size() == vkPipelineShaderStages.size());
+ VERIFY_EXPR(ShaderModules.size() == Stages.size());
}
@@ -401,6 +337,253 @@ static void CreateGraphicsPipeline(RenderDeviceVkImpl*
Pipeline = LogicalDevice.CreateGraphicsPipeline(PipelineCI, VK_NULL_HANDLE, PSODesc.Name);
}
+
+static void CreateRayTracingPipeline(RenderDeviceVkImpl* pDeviceVk,
+ std::vector<VkPipelineShaderStageCreateInfo>& Stages,
+ const std::vector<VkRayTracingShaderGroupCreateInfoKHR>& ShaderGroups,
+ const PipelineLayout& Layout,
+ const PipelineStateDesc& PSODesc,
+ const RayTracingPipelineDesc& RayTracingPipeline,
+ VulkanUtilities::PipelineWrapper& Pipeline)
+{
+ const auto& LogicalDevice = pDeviceVk->GetLogicalDevice();
+
+ VkRayTracingPipelineCreateInfoKHR PipelineCI = {};
+
+ PipelineCI.sType = VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR;
+ PipelineCI.pNext = nullptr;
+#ifdef DILIGENT_DEBUG
+ PipelineCI.flags = VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT;
+#endif
+
+ PipelineCI.stageCount = static_cast<Uint32>(Stages.size());
+ PipelineCI.pStages = Stages.data();
+ PipelineCI.groupCount = static_cast<Uint32>(ShaderGroups.size());
+ PipelineCI.pGroups = ShaderGroups.data();
+ PipelineCI.maxPipelineRayRecursionDepth = std::max(1u, Uint32{RayTracingPipeline.MaxRecursionDepth}) - 1; // for compatibility with D3D12, zero means only one ray tracing depth.
+ PipelineCI.pLibraryInfo = nullptr;
+ PipelineCI.pLibraryInterface = nullptr;
+ PipelineCI.pDynamicState = nullptr;
+ PipelineCI.layout = Layout.GetVkPipelineLayout();
+ PipelineCI.basePipelineHandle = VK_NULL_HANDLE; // a pipeline to derive from
+ PipelineCI.basePipelineIndex = -1; // an index into the pCreateInfos parameter to use as a pipeline to derive from
+
+ Pipeline = LogicalDevice.CreateRayTracingPipeline(PipelineCI, VK_NULL_HANDLE, PSODesc.Name);
+}
+
+
+template <typename TNameToGroupIndexMap>
+void BuildRTPipelineDescription(const RayTracingPipelineStateCreateInfo& CreateInfo,
+ const TNameToGroupIndexMap& NameToGroupIndex,
+ std::vector<VkRayTracingShaderGroupCreateInfoKHR>& ShaderGroups,
+ const ShaderResourceLayoutVk::TShaderStages& ShaderStages)
+{
+#define LOG_PSO_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Description of ray tracing PSO '", CreateInfo.PSODesc.Name, "' is invalid: ", ##__VA_ARGS__)
+ ShaderGroups.reserve(CreateInfo.GeneralShaderCount + CreateInfo.TriangleHitShaderCount + CreateInfo.ProceduralHitShaderCount);
+
+ std::array<Uint32, MAX_SHADERS_IN_PIPELINE> ShaderIndices = {};
+ std::unordered_map<const IShader*, Uint32> UniqueShaders;
+
+ const auto ShaderToIndex = [&ShaderIndices, &UniqueShaders](const IShader* pShader) -> Uint32 {
+ if (pShader != nullptr)
+ {
+ Uint32& Index = ShaderIndices[GetShaderTypePipelineIndex(pShader->GetDesc().ShaderType, PIPELINE_TYPE_RAY_TRACING)];
+ auto Result = UniqueShaders.emplace(pShader, Index);
+ if (Result.second)
+ {
+ ++Index;
+ }
+ return Result.first->second;
+ }
+ return VK_SHADER_UNUSED_KHR;
+ };
+
+ Uint32 ShaderCount = 0;
+ for (auto& Stage : ShaderStages)
+ {
+ ShaderIndices[GetShaderTypePipelineIndex(Stage.Type, PIPELINE_TYPE_RAY_TRACING)] = ShaderCount;
+ ShaderCount += static_cast<Uint32>(Stage.Count());
+ }
+
+ for (Uint32 i = 0; i < CreateInfo.GeneralShaderCount; ++i)
+ {
+ const auto& GeneralShader = CreateInfo.pGeneralShaders[i];
+
+ VkRayTracingShaderGroupCreateInfoKHR Group = {};
+
+ Group.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR;
+ Group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
+ Group.generalShader = ShaderToIndex(GeneralShader.pShader);
+ Group.closestHitShader = VK_SHADER_UNUSED_KHR;
+ Group.anyHitShader = VK_SHADER_UNUSED_KHR;
+ Group.intersectionShader = VK_SHADER_UNUSED_KHR;
+
+#ifdef DILIGENT_DEVELOPMENT
+ auto Iter = NameToGroupIndex.find(GeneralShader.Name);
+ if (Iter == NameToGroupIndex.end())
+ LOG_PSO_ERROR_AND_THROW("Can't find general shader '", GeneralShader.Name, "'");
+ if (Iter->second != ShaderGroups.size())
+ LOG_PSO_ERROR_AND_THROW("General shader group '", GeneralShader.Name, "' index mismatch: (", Iter->second, ") != (", ShaderGroups.size(), ")");
+#endif
+
+ ShaderGroups.push_back(Group);
+ }
+
+ for (Uint32 i = 0; i < CreateInfo.TriangleHitShaderCount; ++i)
+ {
+ const auto& TriHitShader = CreateInfo.pTriangleHitShaders[i];
+
+ VkRayTracingShaderGroupCreateInfoKHR Group = {};
+
+ Group.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR;
+ Group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR;
+ Group.generalShader = VK_SHADER_UNUSED_KHR;
+ Group.closestHitShader = ShaderToIndex(TriHitShader.pClosestHitShader);
+ Group.anyHitShader = ShaderToIndex(TriHitShader.pAnyHitShader);
+ Group.intersectionShader = VK_SHADER_UNUSED_KHR;
+
+#ifdef DILIGENT_DEVELOPMENT
+ auto Iter = NameToGroupIndex.find(TriHitShader.Name);
+ if (Iter == NameToGroupIndex.end())
+ LOG_PSO_ERROR_AND_THROW("Can't find triangle hit group '", TriHitShader.Name, "'");
+ if (Iter->second != ShaderGroups.size())
+ LOG_PSO_ERROR_AND_THROW("Triangle hit group '", TriHitShader.Name, "' index mismatch: (", Iter->second, ") != (", ShaderGroups.size(), ")");
+#endif
+
+ ShaderGroups.push_back(Group);
+ }
+
+ for (Uint32 i = 0; i < CreateInfo.ProceduralHitShaderCount; ++i)
+ {
+ const auto& ProcHitShader = CreateInfo.pProceduralHitShaders[i];
+
+ VkRayTracingShaderGroupCreateInfoKHR Group = {};
+
+ Group.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR;
+ Group.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR;
+ Group.generalShader = VK_SHADER_UNUSED_KHR;
+ Group.intersectionShader = ShaderToIndex(ProcHitShader.pIntersectionShader);
+ Group.closestHitShader = ShaderToIndex(ProcHitShader.pClosestHitShader);
+ Group.anyHitShader = ShaderToIndex(ProcHitShader.pAnyHitShader);
+
+#ifdef DILIGENT_DEVELOPMENT
+ auto Iter = NameToGroupIndex.find(ProcHitShader.Name);
+ if (Iter == NameToGroupIndex.end())
+ LOG_PSO_ERROR_AND_THROW("Can't find procedural hit group '", ProcHitShader.Name, "'");
+ if (Iter->second != ShaderGroups.size())
+ LOG_PSO_ERROR_AND_THROW("Procedural hit group '", ProcHitShader.Name, "' index mismatch: (", Iter->second, ") != (", ShaderGroups.size(), ")");
+#endif
+
+ ShaderGroups.push_back(Group);
+ }
+
+#ifdef DILIGENT_DEVELOPMENT
+ Uint32 ShaderIndex2 = 0;
+ for (auto& Stage : ShaderStages)
+ {
+ for (auto* pShader : Stage.Shaders)
+ {
+ auto iter = UniqueShaders.find(static_cast<const IShader*>(pShader));
+ if (iter != UniqueShaders.end())
+ VERIFY_EXPR(iter->second == ShaderIndex2);
+ else
+ UNEXPECTED("Shader '", pShader->GetDesc().Name, "' is not used in ray tracing shader groups");
+
+ ++ShaderIndex2;
+ }
+ }
+ VERIFY_EXPR(UniqueShaders.size() == ShaderIndex2);
+#endif
+#undef LOG_PSO_ERROR_AND_THROW
+}
+
+} // namespace
+
+
+RenderPassDesc PipelineStateVkImpl::GetImplicitRenderPassDesc(
+ Uint32 NumRenderTargets,
+ const TEXTURE_FORMAT RTVFormats[],
+ TEXTURE_FORMAT DSVFormat,
+ Uint8 SampleCount,
+ std::array<RenderPassAttachmentDesc, MAX_RENDER_TARGETS + 1>& Attachments,
+ std::array<AttachmentReference, MAX_RENDER_TARGETS + 1>& AttachmentReferences,
+ SubpassDesc& SubpassDesc)
+{
+ VERIFY_EXPR(NumRenderTargets <= MAX_RENDER_TARGETS);
+
+ RenderPassDesc RPDesc;
+
+ RPDesc.AttachmentCount = (DSVFormat != TEX_FORMAT_UNKNOWN ? 1 : 0) + NumRenderTargets;
+
+ uint32_t AttachmentInd = 0;
+ AttachmentReference* pDepthAttachmentReference = nullptr;
+ if (DSVFormat != TEX_FORMAT_UNKNOWN)
+ {
+ auto& DepthAttachment = Attachments[AttachmentInd];
+
+ DepthAttachment.Format = DSVFormat;
+ DepthAttachment.SampleCount = SampleCount;
+ DepthAttachment.LoadOp = ATTACHMENT_LOAD_OP_LOAD; // previous contents of the image within the render area
+ // will be preserved. For attachments with a depth/stencil format,
+ // this uses the access type VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT.
+ DepthAttachment.StoreOp = ATTACHMENT_STORE_OP_STORE; // the contents generated during the render pass and within the render
+ // area are written to memory. For attachments with a depth/stencil format,
+ // this uses the access type VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT.
+ DepthAttachment.StencilLoadOp = ATTACHMENT_LOAD_OP_LOAD;
+ DepthAttachment.StencilStoreOp = ATTACHMENT_STORE_OP_STORE;
+ DepthAttachment.InitialState = RESOURCE_STATE_DEPTH_WRITE;
+ DepthAttachment.FinalState = RESOURCE_STATE_DEPTH_WRITE;
+
+ pDepthAttachmentReference = &AttachmentReferences[AttachmentInd];
+ pDepthAttachmentReference->AttachmentIndex = AttachmentInd;
+ pDepthAttachmentReference->State = RESOURCE_STATE_DEPTH_WRITE;
+
+ ++AttachmentInd;
+ }
+
+ AttachmentReference* pColorAttachmentsReference = NumRenderTargets > 0 ? &AttachmentReferences[AttachmentInd] : nullptr;
+ for (Uint32 rt = 0; rt < NumRenderTargets; ++rt, ++AttachmentInd)
+ {
+ auto& ColorAttachment = Attachments[AttachmentInd];
+
+ ColorAttachment.Format = RTVFormats[rt];
+ ColorAttachment.SampleCount = SampleCount;
+ ColorAttachment.LoadOp = ATTACHMENT_LOAD_OP_LOAD; // previous contents of the image within the render area
+ // will be preserved. For attachments with a depth/stencil format,
+ // this uses the access type VK_ACCESS_COLOR_ATTACHMENT_READ_BIT.
+ ColorAttachment.StoreOp = ATTACHMENT_STORE_OP_STORE; // the contents generated during the render pass and within the render
+ // area are written to memory. For attachments with a color format,
+ // this uses the access type VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT.
+ ColorAttachment.StencilLoadOp = ATTACHMENT_LOAD_OP_DISCARD;
+ ColorAttachment.StencilStoreOp = ATTACHMENT_STORE_OP_DISCARD;
+ ColorAttachment.InitialState = RESOURCE_STATE_RENDER_TARGET;
+ ColorAttachment.FinalState = RESOURCE_STATE_RENDER_TARGET;
+
+ auto& ColorAttachmentRef = AttachmentReferences[AttachmentInd];
+ ColorAttachmentRef.AttachmentIndex = AttachmentInd;
+ ColorAttachmentRef.State = RESOURCE_STATE_RENDER_TARGET;
+ }
+
+ RPDesc.pAttachments = Attachments.data();
+ RPDesc.SubpassCount = 1;
+ RPDesc.pSubpasses = &SubpassDesc;
+ RPDesc.DependencyCount = 0; // the number of dependencies between pairs of subpasses, or zero indicating no dependencies.
+ RPDesc.pDependencies = nullptr; // an array of dependencyCount number of VkSubpassDependency structures describing
+ // dependencies between pairs of subpasses, or NULL if dependencyCount is zero.
+
+
+ SubpassDesc.InputAttachmentCount = 0;
+ SubpassDesc.pInputAttachments = nullptr;
+ SubpassDesc.RenderTargetAttachmentCount = NumRenderTargets;
+ SubpassDesc.pRenderTargetAttachments = pColorAttachmentsReference;
+ SubpassDesc.pResolveAttachments = nullptr;
+ SubpassDesc.pDepthStencilAttachment = pDepthAttachmentReference;
+ SubpassDesc.PreserveAttachmentCount = 0;
+ SubpassDesc.pPreserveAttachments = nullptr;
+
+ return RPDesc;
+}
+
void PipelineStateVkImpl::InitResourceLayouts(const PipelineStateCreateInfo& CreateInfo,
TShaderStages& ShaderStages)
{
@@ -416,7 +599,7 @@ void PipelineStateVkImpl::InitResourceLayouts(const PipelineStateCreateInfo& Cre
m_ResourceLayoutIndex[ShaderTypeInd] = static_cast<Int8>(s);
auto& StaticResLayout = m_ShaderResourceLayouts[GetNumShaderStages() + s];
- StaticResLayout.InitializeStaticResourceLayout(StageInfo.pShader, GetRawAllocator(), m_Desc.ResourceLayout, m_StaticResCaches[s]);
+ StaticResLayout.InitializeStaticResourceLayout(StageInfo.Shaders, GetRawAllocator(), m_Desc.ResourceLayout, m_StaticResCaches[s]);
m_StaticVarsMgrs[s].Initialize(StaticResLayout, GetRawAllocator(), nullptr, 0);
}
@@ -460,17 +643,18 @@ void PipelineStateVkImpl::InitResourceLayouts(const PipelineStateCreateInfo& Cre
m_ShaderResourceLayoutHash = m_PipelineLayout.GetHash();
}
-template <typename PSOCreateInfoType>
+template <typename PSOCreateInfoType, typename InitPSODescType>
void PipelineStateVkImpl::InitInternalObjects(const PSOCreateInfoType& CreateInfo,
std::vector<VkPipelineShaderStageCreateInfo>& vkShaderStages,
- std::vector<VulkanUtilities::ShaderModuleWrapper>& ShaderModules)
+ std::vector<VulkanUtilities::ShaderModuleWrapper>& ShaderModules,
+ InitPSODescType InitPSODesc)
{
m_ResourceLayoutIndex.fill(-1);
TShaderStages ShaderStages;
ExtractShaders<ShaderVkImpl>(CreateInfo, ShaderStages);
- LinearAllocator MemPool{GetRawAllocator()};
+ FixedLinearAllocator MemPool{GetRawAllocator()};
const auto NumShaderStages = GetNumShaderStages();
VERIFY_EXPR(NumShaderStages > 0 && NumShaderStages == ShaderStages.size());
@@ -498,7 +682,7 @@ void PipelineStateVkImpl::InitInternalObjects(const PSOCreateInfoType&
for (Uint32 s = 0; s < NumShaderStages; ++s)
new (m_StaticVarsMgrs + s) ShaderVariableManagerVk{*this, m_StaticResCaches[s]};
- InitializePipelineDesc(CreateInfo, MemPool);
+ InitPSODesc(CreateInfo, MemPool, ShaderStages);
// It is important to construct all objects before initializing them because if an exception is thrown,
// destructors will be called for all objects
@@ -509,6 +693,7 @@ void PipelineStateVkImpl::InitInternalObjects(const PSOCreateInfoType&
InitPipelineShaderStages(GetDevice()->GetLogicalDevice(), ShaderStages, ShaderModules, vkShaderStages);
}
+
PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* pRefCounters,
RenderDeviceVkImpl* pDeviceVk,
const GraphicsPipelineStateCreateInfo& CreateInfo) :
@@ -520,7 +705,12 @@ PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters*
std::vector<VkPipelineShaderStageCreateInfo> vkShaderStages;
std::vector<VulkanUtilities::ShaderModuleWrapper> ShaderModules;
- InitInternalObjects(CreateInfo, vkShaderStages, ShaderModules);
+ InitInternalObjects(CreateInfo, vkShaderStages, ShaderModules,
+ [this](const GraphicsPipelineStateCreateInfo& CreateInfo, FixedLinearAllocator& MemPool, TShaderStages /*ShaderStages*/) //
+ {
+ InitializePipelineDesc(CreateInfo, MemPool);
+ } //
+ );
CreateGraphicsPipeline(pDeviceVk, vkShaderStages, m_PipelineLayout, m_Desc, GetGraphicsPipelineDesc(), m_Pipeline, m_pRenderPass);
}
@@ -543,7 +733,12 @@ PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* p
std::vector<VkPipelineShaderStageCreateInfo> vkShaderStages;
std::vector<VulkanUtilities::ShaderModuleWrapper> ShaderModules;
- InitInternalObjects(CreateInfo, vkShaderStages, ShaderModules);
+ InitInternalObjects(CreateInfo, vkShaderStages, ShaderModules,
+ [this](const ComputePipelineStateCreateInfo& CreateInfo, FixedLinearAllocator& MemPool, TShaderStages /*ShaderStages*/) //
+ {
+ InitializePipelineDesc(CreateInfo, MemPool);
+ } //
+ );
CreateComputePipeline(pDeviceVk, vkShaderStages, m_PipelineLayout, m_Desc, m_Pipeline);
}
@@ -554,6 +749,41 @@ PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* p
}
}
+PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* pRefCounters,
+ RenderDeviceVkImpl* pDeviceVk,
+ const RayTracingPipelineStateCreateInfo& CreateInfo) :
+ TPipelineStateBase{pRefCounters, pDeviceVk, CreateInfo},
+ m_SRBMemAllocator{GetRawAllocator()}
+{
+ try
+ {
+ const auto& LogicalDevice = pDeviceVk->GetLogicalDevice();
+ const auto ShaderGroupHandleSize = pDeviceVk->GetProperties().ShaderGroupHandleSize;
+
+ std::vector<VkPipelineShaderStageCreateInfo> vkShaderStages;
+ std::vector<VulkanUtilities::ShaderModuleWrapper> ShaderModules;
+ std::vector<VkRayTracingShaderGroupCreateInfoKHR> ShaderGroups;
+
+ InitInternalObjects(CreateInfo, vkShaderStages, ShaderModules,
+ [&](const RayTracingPipelineStateCreateInfo& CreateInfo, FixedLinearAllocator& MemPool, TShaderStages& ShaderStages) //
+ {
+ InitializePipelineDesc(CreateInfo, MemPool);
+ BuildRTPipelineDescription(CreateInfo, m_pRayTracingPipelineData->NameToGroupIndex, ShaderGroups, ShaderStages);
+ } //
+ );
+
+ CreateRayTracingPipeline(pDeviceVk, vkShaderStages, ShaderGroups, m_PipelineLayout, m_Desc, GetRayTracingPipelineDesc(), m_Pipeline);
+
+ auto err = LogicalDevice.GetRayTracingShaderGroupHandles(m_Pipeline, 0, static_cast<uint32_t>(ShaderGroups.size()), ShaderGroupHandleSize, &m_pRayTracingPipelineData->Shaders[0]);
+ VERIFY(err == VK_SUCCESS, "Failed to get shader group handles");
+ (void)err;
+ }
+ catch (...)
+ {
+ Destruct();
+ throw;
+ }
+}
PipelineStateVkImpl::~PipelineStateVkImpl()
{
@@ -562,6 +792,8 @@ PipelineStateVkImpl::~PipelineStateVkImpl()
void PipelineStateVkImpl::Destruct()
{
+ TPipelineStateBase::Destruct();
+
m_pDevice->SafeReleaseDeviceObject(std::move(m_Pipeline), m_Desc.CommandQueueMask);
m_PipelineLayout.Release(m_pDevice, m_Desc.CommandQueueMask);
@@ -617,7 +849,6 @@ bool PipelineStateVkImpl::IsCompatibleWith(const IPipelineState* pPSO) const
return false;
auto IsSamePipelineLayout = m_PipelineLayout.IsSameAs(pPSOVk->m_PipelineLayout);
-
#ifdef DILIGENT_DEBUG
{
bool IsCompatibleShaders = true;
@@ -634,8 +865,8 @@ bool PipelineStateVkImpl::IsCompatibleWith(const IPipelineState* pPSO) const
break;
}
- const auto& Res0 = GetShaderResLayout(s).GetResources();
- const auto& Res1 = pPSOVk->GetShaderResLayout(s).GetResources();
+ const auto& Res0 = GetShaderResLayout(s);
+ const auto& Res1 = pPSOVk->GetShaderResLayout(s);
if (!Res0.IsCompatibleWith(Res1))
{
IsCompatibleShaders = false;
@@ -736,9 +967,23 @@ void PipelineStateVkImpl::CommitAndTransitionShaderResources(IShaderResourceBind
Layout.CommitDynamicResources(ResourceCache, DynamicDescrSet);
}
}
- // Prepare descriptor sets, and also bind them if there are no dynamic descriptors
+
+
+ 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);
- m_PipelineLayout.PrepareDescriptorSets(pCtxVkImpl, m_Desc.IsComputePipeline(), ResourceCache, *pDescrSetBindInfo, DynamicDescrSet);
+ // 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().
}
diff --git a/Graphics/GraphicsEngineVulkan/src/QueryManagerVk.cpp b/Graphics/GraphicsEngineVulkan/src/QueryManagerVk.cpp
index fb09687b..ec94814e 100644
--- a/Graphics/GraphicsEngineVulkan/src/QueryManagerVk.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/QueryManagerVk.cpp
@@ -97,7 +97,7 @@ QueryManagerVk::QueryManagerVk(RenderDeviceVkImpl* pRenderDeviceVk,
VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT |
VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT;
- const auto EnabledShaderStages = LogicalDevice.GetEnabledGraphicsShaderStages();
+ const auto EnabledShaderStages = LogicalDevice.GetEnabledShaderStages();
if (EnabledShaderStages & VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT)
{
QueryPoolCI.pipelineStatistics |=
diff --git a/Graphics/GraphicsEngineVulkan/src/QueryVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/QueryVkImpl.cpp
index 381ee631..a0801cb7 100644
--- a/Graphics/GraphicsEngineVulkan/src/QueryVkImpl.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/QueryVkImpl.cpp
@@ -225,7 +225,7 @@ bool QueryVkImpl::GetData(void* pData, Uint32 DataSize, bool AutoInvalidate)
{
auto& QueryData = *reinterpret_cast<QueryDataPipelineStatistics*>(pData);
- const auto EnabledShaderStages = LogicalDevice.GetEnabledGraphicsShaderStages();
+ const auto EnabledShaderStages = LogicalDevice.GetEnabledShaderStages();
auto Idx = 0;
diff --git a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp
index ccfb74ac..44bc0eb8 100644
--- a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp
@@ -39,6 +39,9 @@
#include "QueryVkImpl.hpp"
#include "RenderPassVkImpl.hpp"
#include "FramebufferVkImpl.hpp"
+#include "BottomLevelASVkImpl.hpp"
+#include "TopLevelASVkImpl.hpp"
+#include "ShaderBindingTableVkImpl.hpp"
#include "EngineMemory.h"
namespace Diligent
@@ -75,7 +78,10 @@ RenderDeviceVkImpl::RenderDeviceVkImpl(IReferenceCounters*
sizeof(FenceVkImpl),
sizeof(QueryVkImpl),
sizeof(RenderPassVkImpl),
- sizeof(FramebufferVkImpl)
+ sizeof(FramebufferVkImpl),
+ sizeof(BottomLevelASVkImpl),
+ sizeof(TopLevelASVkImpl),
+ sizeof(ShaderBindingTableVkImpl),
}
},
m_VulkanInstance {Instance },
@@ -90,17 +96,18 @@ RenderDeviceVkImpl::RenderDeviceVkImpl(IReferenceCounters*
"Main descriptor pool",
std::vector<VkDescriptorPoolSize>
{
- {VK_DESCRIPTOR_TYPE_SAMPLER, EngineCI.MainDescriptorPoolSize.NumSeparateSamplerDescriptors},
- {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, EngineCI.MainDescriptorPoolSize.NumCombinedSamplerDescriptors},
- {VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, EngineCI.MainDescriptorPoolSize.NumSampledImageDescriptors},
- {VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, EngineCI.MainDescriptorPoolSize.NumStorageImageDescriptors},
- {VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, EngineCI.MainDescriptorPoolSize.NumUniformTexelBufferDescriptors},
- {VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, EngineCI.MainDescriptorPoolSize.NumStorageTexelBufferDescriptors},
- //{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, EngineCI.MainDescriptorPoolSize.NumUniformBufferDescriptors},
- //{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, EngineCI.MainDescriptorPoolSize.NumStorageBufferDescriptors},
- {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, EngineCI.MainDescriptorPoolSize.NumUniformBufferDescriptors},
- {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, EngineCI.MainDescriptorPoolSize.NumStorageBufferDescriptors},
- {VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, EngineCI.MainDescriptorPoolSize.NumInputAttachmentDescriptors},
+ {VK_DESCRIPTOR_TYPE_SAMPLER, EngineCI.MainDescriptorPoolSize.NumSeparateSamplerDescriptors},
+ {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, EngineCI.MainDescriptorPoolSize.NumCombinedSamplerDescriptors},
+ {VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, EngineCI.MainDescriptorPoolSize.NumSampledImageDescriptors},
+ {VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, EngineCI.MainDescriptorPoolSize.NumStorageImageDescriptors},
+ {VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, EngineCI.MainDescriptorPoolSize.NumUniformTexelBufferDescriptors},
+ {VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, EngineCI.MainDescriptorPoolSize.NumStorageTexelBufferDescriptors},
+ //{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, EngineCI.MainDescriptorPoolSize.NumUniformBufferDescriptors},
+ //{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, EngineCI.MainDescriptorPoolSize.NumStorageBufferDescriptors},
+ {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, EngineCI.MainDescriptorPoolSize.NumUniformBufferDescriptors},
+ {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, EngineCI.MainDescriptorPoolSize.NumStorageBufferDescriptors},
+ {VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, EngineCI.MainDescriptorPoolSize.NumInputAttachmentDescriptors},
+ {VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, EngineCI.MainDescriptorPoolSize.NumAccelStructDescriptors}
},
EngineCI.MainDescriptorPoolSize.MaxDescriptorSets,
true
@@ -111,17 +118,18 @@ RenderDeviceVkImpl::RenderDeviceVkImpl(IReferenceCounters*
"Dynamic descriptor pool",
std::vector<VkDescriptorPoolSize>
{
- {VK_DESCRIPTOR_TYPE_SAMPLER, EngineCI.DynamicDescriptorPoolSize.NumSeparateSamplerDescriptors},
- {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, EngineCI.DynamicDescriptorPoolSize.NumCombinedSamplerDescriptors},
- {VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, EngineCI.DynamicDescriptorPoolSize.NumSampledImageDescriptors},
- {VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, EngineCI.DynamicDescriptorPoolSize.NumStorageImageDescriptors},
- {VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, EngineCI.DynamicDescriptorPoolSize.NumUniformTexelBufferDescriptors},
- {VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, EngineCI.DynamicDescriptorPoolSize.NumStorageTexelBufferDescriptors},
- //{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, EngineCI.DynamicDescriptorPoolSize.NumUniformBufferDescriptors},
- //{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, EngineCI.DynamicDescriptorPoolSize.NumStorageBufferDescriptors},
- {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, EngineCI.DynamicDescriptorPoolSize.NumUniformBufferDescriptors},
- {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, EngineCI.DynamicDescriptorPoolSize.NumStorageBufferDescriptors},
- {VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, EngineCI.MainDescriptorPoolSize.NumInputAttachmentDescriptors},
+ {VK_DESCRIPTOR_TYPE_SAMPLER, EngineCI.DynamicDescriptorPoolSize.NumSeparateSamplerDescriptors},
+ {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, EngineCI.DynamicDescriptorPoolSize.NumCombinedSamplerDescriptors},
+ {VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, EngineCI.DynamicDescriptorPoolSize.NumSampledImageDescriptors},
+ {VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, EngineCI.DynamicDescriptorPoolSize.NumStorageImageDescriptors},
+ {VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, EngineCI.DynamicDescriptorPoolSize.NumUniformTexelBufferDescriptors},
+ {VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, EngineCI.DynamicDescriptorPoolSize.NumStorageTexelBufferDescriptors},
+ //{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, EngineCI.DynamicDescriptorPoolSize.NumUniformBufferDescriptors},
+ //{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, EngineCI.DynamicDescriptorPoolSize.NumStorageBufferDescriptors},
+ {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, EngineCI.DynamicDescriptorPoolSize.NumUniformBufferDescriptors},
+ {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, EngineCI.DynamicDescriptorPoolSize.NumStorageBufferDescriptors},
+ {VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, EngineCI.MainDescriptorPoolSize.NumInputAttachmentDescriptors},
+ {VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, EngineCI.MainDescriptorPoolSize.NumAccelStructDescriptors}
},
EngineCI.DynamicDescriptorPoolSize.MaxDescriptorSets,
false // Pools can only be reset
@@ -151,9 +159,27 @@ RenderDeviceVkImpl::RenderDeviceVkImpl(IReferenceCounters*
EngineCI.DynamicHeapSize,
~Uint64{0}
},
- m_pDxCompiler{CreateDXCompiler(DXCompilerTarget::Vulkan, EngineCI.pDxCompilerPath)}
+ m_pDxCompiler{CreateDXCompiler(DXCompilerTarget::Vulkan, EngineCI.pDxCompilerPath)},
+ m_Properties
+ {
+ m_PhysicalDevice->GetExtProperties().RayTracingPipeline.shaderGroupHandleSize,
+ m_PhysicalDevice->GetExtProperties().RayTracingPipeline.maxShaderGroupStride,
+ m_PhysicalDevice->GetExtProperties().RayTracingPipeline.shaderGroupBaseAlignment,
+ m_PhysicalDevice->GetExtProperties().MeshShader.maxDrawMeshTasksCount,
+ m_PhysicalDevice->GetExtProperties().RayTracingPipeline.maxRayRecursionDepth + 1, // for compatibility with D3D12
+ m_PhysicalDevice->GetExtProperties().RayTracingPipeline.maxRayDispatchInvocationCount
+ }
// 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");
+
+ // set device properties
+ {
+ static_assert(sizeof(DeviceProperties) == sizeof(Uint32) * 1, "Please set new properties below");
+ m_DeviceProperties.MaxRayTracingRecursionDepth = m_Properties.MaxRayTracingRecursionDepth;
+ }
+
m_DeviceCaps.DevType = RENDER_DEVICE_TYPE_VULKAN;
m_DeviceCaps.MajorVersion = 1;
m_DeviceCaps.MinorVersion = 0;
@@ -223,7 +249,7 @@ RenderDeviceVkImpl::RenderDeviceVkImpl(IReferenceCounters*
Features.DurationQueries = DEVICE_FEATURE_STATE_ENABLED;
#if defined(_MSC_VER) && defined(_WIN64)
- static_assert(sizeof(DeviceFeatures) == 31, "Did you add a new feature to DeviceFeatures? Please handle its satus here (if necessary).");
+ static_assert(sizeof(DeviceFeatures) == 32, "Did you add a new feature to DeviceFeatures? Please handle its satus here (if necessary).");
#endif
const auto& vkDeviceLimits = m_PhysicalDevice->GetProperties().limits;
@@ -567,6 +593,10 @@ void RenderDeviceVkImpl::CreateComputePipelineState(const ComputePipelineStateCr
CreatePipelineState(PSOCreateInfo, ppPipelineState);
}
+void RenderDeviceVkImpl::CreateRayTracingPipelineState(const RayTracingPipelineStateCreateInfo& PSOCreateInfo, IPipelineState** ppPipelineState)
+{
+ CreatePipelineState(PSOCreateInfo, ppPipelineState);
+}
void RenderDeviceVkImpl::CreateBufferFromVulkanResource(VkBuffer vkBuffer, const BufferDesc& BuffDesc, RESOURCE_STATE InitialState, IBuffer** ppBuffer)
{
@@ -732,4 +762,72 @@ void RenderDeviceVkImpl::CreateFramebuffer(const FramebufferDesc& Desc, IFramebu
});
}
+void RenderDeviceVkImpl::CreateBLASFromVulkanResource(VkAccelerationStructureKHR vkBLAS,
+ const BottomLevelASDesc& Desc,
+ RESOURCE_STATE InitialState,
+ IBottomLevelAS** ppBLAS)
+{
+ CreateDeviceObject(
+ "BottomLevelAS", Desc, ppBLAS,
+ [&]() //
+ {
+ BottomLevelASVkImpl* pBottomLevelASVk(NEW_RC_OBJ(m_BLASAllocator, "BottomLevelASVkImpl instance", BottomLevelASVkImpl)(this, Desc, InitialState, vkBLAS));
+ pBottomLevelASVk->QueryInterface(IID_BottomLevelAS, reinterpret_cast<IObject**>(ppBLAS));
+ OnCreateDeviceObject(pBottomLevelASVk);
+ } //
+ );
+}
+
+void RenderDeviceVkImpl::CreateBLAS(const BottomLevelASDesc& Desc,
+ IBottomLevelAS** ppBLAS)
+{
+ CreateDeviceObject("BottomLevelAS", Desc, ppBLAS,
+ [&]() //
+ {
+ BottomLevelASVkImpl* pBottomLevelASVk(NEW_RC_OBJ(m_BLASAllocator, "BottomLevelASVkImpl instance", BottomLevelASVkImpl)(this, Desc));
+ pBottomLevelASVk->QueryInterface(IID_BottomLevelAS, reinterpret_cast<IObject**>(ppBLAS));
+ OnCreateDeviceObject(pBottomLevelASVk);
+ });
+}
+
+void RenderDeviceVkImpl::CreateTLASFromVulkanResource(VkAccelerationStructureKHR vkTLAS,
+ const TopLevelASDesc& Desc,
+ RESOURCE_STATE InitialState,
+ ITopLevelAS** ppTLAS)
+{
+ CreateDeviceObject(
+ "TopLevelAS", Desc, ppTLAS,
+ [&]() //
+ {
+ TopLevelASVkImpl* pTopLevelASVk(NEW_RC_OBJ(m_BLASAllocator, "TopLevelASVkImpl instance", TopLevelASVkImpl)(this, Desc, InitialState, vkTLAS));
+ pTopLevelASVk->QueryInterface(IID_TopLevelAS, reinterpret_cast<IObject**>(ppTLAS));
+ OnCreateDeviceObject(pTopLevelASVk);
+ } //
+ );
+}
+
+void RenderDeviceVkImpl::CreateTLAS(const TopLevelASDesc& Desc,
+ ITopLevelAS** ppTLAS)
+{
+ CreateDeviceObject("TopLevelAS", Desc, ppTLAS,
+ [&]() //
+ {
+ TopLevelASVkImpl* pTopLevelASVk(NEW_RC_OBJ(m_TLASAllocator, "TopLevelASVkImpl instance", TopLevelASVkImpl)(this, Desc));
+ pTopLevelASVk->QueryInterface(IID_TopLevelAS, reinterpret_cast<IObject**>(ppTLAS));
+ OnCreateDeviceObject(pTopLevelASVk);
+ });
+}
+
+void RenderDeviceVkImpl::CreateSBT(const ShaderBindingTableDesc& Desc,
+ IShaderBindingTable** ppSBT)
+{
+ CreateDeviceObject("ShaderBindingTable", Desc, ppSBT,
+ [&]() //
+ {
+ ShaderBindingTableVkImpl* pSBTVk(NEW_RC_OBJ(m_SBTAllocator, "ShaderBindingTableVkImpl instance", ShaderBindingTableVkImpl)(this, Desc));
+ pSBTVk->QueryInterface(IID_ShaderBindingTable, reinterpret_cast<IObject**>(ppSBT));
+ OnCreateDeviceObject(pSBTVk);
+ });
+}
+
} // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderBindingTableVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderBindingTableVkImpl.cpp
new file mode 100644
index 00000000..194d15f4
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/src/ShaderBindingTableVkImpl.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2019-2020 Diligent Graphics LLC
+ * Copyright 2015-2019 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#include "pch.h"
+#include "ShaderBindingTableVkImpl.hpp"
+#include "BufferVkImpl.hpp"
+#include "VulkanTypeConversions.hpp"
+
+namespace Diligent
+{
+
+ShaderBindingTableVkImpl::ShaderBindingTableVkImpl(IReferenceCounters* pRefCounters,
+ RenderDeviceVkImpl* pRenderDeviceVk,
+ const ShaderBindingTableDesc& Desc,
+ bool bIsDeviceInternal) :
+ TShaderBindingTableBase{pRefCounters, pRenderDeviceVk, Desc, bIsDeviceInternal}
+{
+}
+
+ShaderBindingTableVkImpl::~ShaderBindingTableVkImpl()
+{
+}
+
+} // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp
index 3e4a65cf..d81fb675 100644
--- a/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/ShaderResourceBindingVkImpl.cpp
@@ -30,7 +30,7 @@
#include "PipelineStateVkImpl.hpp"
#include "ShaderVkImpl.hpp"
#include "RenderDeviceVkImpl.hpp"
-#include "LinearAllocator.hpp"
+#include "FixedLinearAllocator.hpp"
namespace Diligent
{
@@ -54,7 +54,7 @@ ShaderResourceBindingVkImpl::ShaderResourceBindingVkImpl(IReferenceCounters* pR
m_NumShaders = static_cast<decltype(m_NumShaders)>(pPSO->GetNumShaderStages());
- LinearAllocator MemPool{GetRawAllocator()};
+ FixedLinearAllocator MemPool{GetRawAllocator()};
MemPool.AddSpace<ShaderVariableManagerVk>(m_NumShaders);
MemPool.Reserve();
m_pShaderVarMgrs = MemPool.ConstructArray<ShaderVariableManagerVk>(m_NumShaders, std::ref(*this), std::ref(m_ShaderResourceCache));
diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp
index caf8ffd2..26516695 100644
--- a/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/ShaderResourceCacheVk.cpp
@@ -33,6 +33,7 @@
#include "TextureViewVkImpl.hpp"
#include "TextureVkImpl.hpp"
#include "SamplerVkImpl.hpp"
+#include "TopLevelASVkImpl.hpp"
#include "VulkanTypeConversions.hpp"
namespace Diligent
@@ -155,7 +156,7 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl)
for (Uint32 res = 0; res < m_TotalResources; ++res)
{
auto& Res = pResources[res];
- static_assert(SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes == 11, "Please handle the new resource type below");
+ static_assert(Uint32{SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes} == 12, "Please handle the new resource type below");
switch (Res.Type)
{
case SPIRVShaderResourceAttribs::ResourceType::UniformBuffer:
@@ -321,6 +322,40 @@ void ShaderResourceCacheVk::TransitionResources(DeviceContextVkImpl* pCtxVkImpl)
}
break;
+ case SPIRVShaderResourceAttribs::ResourceType::AccelerationStructure:
+ {
+ auto* pTLASVk = Res.pObject.RawPtr<TopLevelASVkImpl>();
+ if (pTLASVk != nullptr && pTLASVk->IsInKnownState())
+ {
+ constexpr RESOURCE_STATE RequiredState = RESOURCE_STATE_RAY_TRACING;
+ const bool IsInRequiredState = pTLASVk->CheckState(RequiredState);
+ if (VerifyOnly)
+ {
+ if (!IsInRequiredState)
+ {
+ LOG_ERROR_MESSAGE("State of TLAS '", pTLASVk->GetDesc().Name, "' is incorrect. Required state: ",
+ GetResourceStateString(RequiredState), ". Actual state: ",
+ GetResourceStateString(pTLASVk->GetState()),
+ ". Call IDeviceContext::TransitionShaderResources(), use RESOURCE_STATE_TRANSITION_MODE_TRANSITION "
+ "when calling IDeviceContext::CommitShaderResources() or explicitly transition the TLAS state "
+ "with IDeviceContext::TransitionResourceStates().");
+ }
+ }
+ else
+ {
+ if (!IsInRequiredState)
+ {
+ pCtxVkImpl->TransitionTLASState(*pTLASVk, RESOURCE_STATE_UNKNOWN, RequiredState, true);
+ }
+ }
+
+#ifdef DILIGENT_DEVELOPMENT
+ pTLASVk->ValidateContent();
+#endif
+ }
+ }
+ break;
+
default: UNEXPECTED("Unexpected resource type");
}
}
@@ -497,4 +532,20 @@ VkDescriptorImageInfo ShaderResourceCacheVk::Resource::GetInputAttachmentDescrip
return DescrImgInfo;
}
+VkWriteDescriptorSetAccelerationStructureKHR ShaderResourceCacheVk::Resource::GetAccelerationStructureWriteInfo() const
+{
+ VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::AccelerationStructure, "Acceleration structure resource is expected");
+ DEV_CHECK_ERR(pObject != nullptr, "Unable to get acceleration structure write info: cached object is null");
+
+ auto* pTLASVk = pObject.RawPtr<const TopLevelASVkImpl>();
+
+ VkWriteDescriptorSetAccelerationStructureKHR DescrAS;
+ DescrAS.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR;
+ DescrAS.pNext = nullptr;
+ DescrAS.accelerationStructureCount = 1;
+ DescrAS.pAccelerationStructures = pTLASVk->GetVkTLASPtr();
+
+ return DescrAS;
+}
+
} // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp
index e73ee9aa..e2ea6cb5 100644
--- a/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/ShaderResourceLayoutVk.cpp
@@ -39,6 +39,7 @@
#include "ShaderResourceVariableBase.hpp"
#include "StringTools.hpp"
#include "PipelineStateVkImpl.hpp"
+#include "TopLevelASVkImpl.hpp"
namespace Diligent
{
@@ -93,12 +94,24 @@ static SHADER_RESOURCE_VARIABLE_TYPE FindShaderVariableType(SHADER_TYPE
}
}
-ShaderResourceLayoutVk::ShaderStageInfo::ShaderStageInfo(SHADER_TYPE _Type,
- const ShaderVkImpl* _pShader) :
- Type{_Type},
- pShader{_pShader},
- SPIRV{pShader->GetSPIRV()}
+
+ShaderResourceLayoutVk::ShaderStageInfo::ShaderStageInfo(SHADER_TYPE Stage, const ShaderVkImpl* pShader) :
+ Type{Stage},
+ Shaders{pShader},
+ SPIRVs{pShader->GetSPIRV()}
+{
+}
+
+void ShaderResourceLayoutVk::ShaderStageInfo::Append(const ShaderVkImpl* pShader)
+{
+ Shaders.push_back(pShader);
+ SPIRVs.push_back(pShader->GetSPIRV());
+}
+
+size_t ShaderResourceLayoutVk::ShaderStageInfo::Count() const
{
+ VERIFY_EXPR(Shaders.size() == SPIRVs.size());
+ return Shaders.size();
}
@@ -111,33 +124,51 @@ ShaderResourceLayoutVk::~ShaderResourceLayoutVk()
GetImmutableSampler(s).~ImmutableSamplerPtrType();
}
-void ShaderResourceLayoutVk::AllocateMemory(const ShaderVkImpl* pShader,
- IMemoryAllocator& Allocator,
- const PipelineResourceLayoutDesc& ResourceLayoutDesc,
- const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes,
- Uint32 NumAllowedTypes,
- bool AllocateImmutableSamplers)
+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(!m_pResources);
- m_pResources = pShader->GetShaderResources();
+ 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 = ShaderName.length() + 1;
- const auto ShaderType = pShader->GetDesc().ShaderType;
- VERIFY_EXPR(m_pResources->GetShaderType() == ShaderType);
// Count the number of resources to allocate all needed memory
+ for (size_t s = 0; s < Shaders.size(); ++s)
{
- const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes);
- const auto* CombinedSamplerSuffix = m_pResources->GetCombinedSamplerSuffix();
- m_pResources->ProcessResources(
+ 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(ShaderType, ResAttribs, ResourceLayoutDesc, CombinedSamplerSuffix);
+ auto VarType = FindShaderVariableType(m_ShaderType, ResAttribs, ResourceLayoutDesc, CombinedSamplerSuffix);
if (IsAllowedType(VarType, AllowedTypeBits))
{
- // For immutable separate samplers we still allocate VkResource instances, but they are never exposed to the app
+ bool IsUniqueName = UniqueNames.emplace(HashMapStringKey{ResAttribs.Name}, Uint32{InvalidResourceIndex}).second;
+ if (IsUniqueName)
+ {
+ StringPoolSize += strlen(ResAttribs.Name) + 1;
- VERIFY(Uint32{m_NumResources[VarType]} + 1 <= Uint32{std::numeric_limits<Uint16>::max()}, "Number of resources exceeds Uint16 maximum representable value");
- ++m_NumResources[VarType];
+ // 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];
+ }
}
} //
);
@@ -157,24 +188,33 @@ void ShaderResourceLayoutVk::AllocateMemory(const ShaderVkImpl*
for (Uint32 s = 0; s < ResourceLayoutDesc.NumImmutableSamplers; ++s)
{
const auto& ImtblSamDesc = ResourceLayoutDesc.ImmutableSamplers[s];
- if ((ImtblSamDesc.ShaderStages & ShaderType) != 0)
+ if ((ImtblSamDesc.ShaderStages & m_ShaderType) != 0)
++m_NumImmutableSamplers;
}
}
- size_t MemSize = TotalResources * sizeof(VkResource) + m_NumImmutableSamplers * sizeof(ImmutableSamplerPtrType);
- static_assert((sizeof(VkResource) % sizeof(void*)) == 0, "sizeof(VkResource) must be multiple of sizeof(void*)");
- if (MemSize == 0)
- return;
+ FixedLinearAllocator MemPool{Allocator};
- auto* pRawMem = ALLOCATE_RAW(Allocator, "Raw memory buffer for shader resource layout resources", MemSize);
- m_ResourceBuffer = std::unique_ptr<void, STDDeleterRawMem<void>>(pRawMem, Allocator);
- for (Uint32 s = 0; s < m_NumImmutableSamplers; ++s)
- {
- // We need to initialize immutable samplers
- auto& UninitializedImmutableSampler = GetImmutableSampler(s);
- new (std::addressof(UninitializedImmutableSampler)) ImmutableSamplerPtrType;
- }
+ 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;
}
@@ -194,8 +234,8 @@ static Uint32 FindAssignedSampler(const ShaderResourceLayoutVk& Layout,
for (SamplerInd = 0; SamplerInd < CurrResourceCount; ++SamplerInd)
{
const auto& Res = Layout.GetResource(ImgVarType, SamplerInd);
- if (Res.SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler &&
- strcmp(Res.SpirvAttribs.Name, SepSampler.Name) == 0)
+ if (Res.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler &&
+ strcmp(Res.Name, SepSampler.Name) == 0)
{
VERIFY(ImgVarType == Res.GetVariableType(),
"The type (", GetShaderVariableTypeLiteralName(ImgVarType), ") of separate image variable '", SepImg.Name,
@@ -217,62 +257,103 @@ static Uint32 FindAssignedSampler(const ShaderResourceLayoutVk& Layout,
}
-void ShaderResourceLayoutVk::InitializeStaticResourceLayout(const ShaderVkImpl* pShader,
- IMemoryAllocator& LayoutDataAllocator,
- const PipelineResourceLayoutDesc& ResourceLayoutDesc,
- ShaderResourceCacheVk& StaticResourceCache)
+void ShaderResourceLayoutVk::InitializeStaticResourceLayout(const std::vector<const ShaderVkImpl*>& Shaders,
+ IMemoryAllocator& LayoutDataAllocator,
+ const PipelineResourceLayoutDesc& ResourceLayoutDesc,
+ ShaderResourceCacheVk& StaticResourceCache)
{
const auto AllowedVarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC;
// We do not need immutable samplers in static shader resource layout as they
// are relevant only when the main layout is initialized
- constexpr bool AllocateImmutableSamplers = false;
- AllocateMemory(pShader, LayoutDataAllocator, ResourceLayoutDesc, &AllowedVarType, 1, AllocateImmutableSamplers);
+ ResourceNameToIndex_t ResourceNameToIndex;
+ constexpr bool AllocateImmutableSamplers = false;
+
+ auto stringPool = AllocateMemory(Shaders, LayoutDataAllocator, ResourceLayoutDesc, &AllowedVarType, 1, ResourceNameToIndex, AllocateImmutableSamplers);
std::array<Uint32, SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES> CurrResInd = {};
- Uint32 StaticResCacheSize = 0;
+ Uint32 StaticResCacheSize = 0;
+ const Uint32 AllowedTypeBits = GetAllowedTypeBits(&AllowedVarType, 1);
- const Uint32 AllowedTypeBits = GetAllowedTypeBits(&AllowedVarType, 1);
- const auto* CombinedSamplerSuffix = m_pResources->GetCombinedSamplerSuffix();
- const auto ShaderType = pShader->GetDesc().ShaderType;
+ for (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;
- m_pResources->ProcessResources(
- [&](const SPIRVShaderResourceAttribs& Attribs, Uint32) //
- {
- auto VarType = FindShaderVariableType(ShaderType, Attribs, ResourceLayoutDesc, CombinedSamplerSuffix);
- if (!IsAllowedType(VarType, AllowedTypeBits))
- return;
+ auto ResIter = ResourceNameToIndex.find(HashMapStringKey{Attribs.Name});
+ VERIFY_EXPR(ResIter != ResourceNameToIndex.end());
- Int32 SrcImmutableSamplerInd = -1;
- if (Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage ||
- Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler)
- {
- // Only search for the immutable sampler for combined image samplers and separate samplers
- SrcImmutableSamplerInd = FindImmutableSampler(ShaderType, ResourceLayoutDesc, Attribs, CombinedSamplerSuffix);
- // For immutable separate samplers we allocate VkResource instances, but they are never exposed to the app
- }
+ if (ResIter->second == 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);
+ // For immutable separate samplers we allocate VkResource instances, but they are never exposed to the app
+ }
- Uint32 Binding = Attribs.Type;
- Uint32 DescriptorSet = 0;
- Uint32 CacheOffset = StaticResCacheSize;
- StaticResCacheSize += Attribs.ArraySize;
+ Uint32 Binding = 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, *m_pResources, Attribs, CurrResInd[VarType], VarType);
- }
- ::new (&GetResource(VarType, CurrResInd[VarType]++)) VkResource(*this, Attribs, VarType, Binding, DescriptorSet, CacheOffset, SamplerInd, SrcImmutableSamplerInd >= 0);
- } //
- );
+ Uint32 SamplerInd = VkResource::InvalidSamplerInd;
+ if (Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage)
+ {
+ // Separate samplers are enumerated before separate images, so the sampler
+ // assigned to this separate image must have already been created.
+ SamplerInd = FindAssignedSampler(*this, Resources, Attribs, CurrResInd[VarType], VarType);
+ }
+
+ // add new resource
+ ResIter->second = CurrResInd[VarType];
+ ::new (&GetResource(VarType, CurrResInd[VarType]++)) VkResource //
+ {
+ *this,
+ stringPool.CopyString(Attribs.Name),
+ Attribs.ArraySize,
+ Attribs.Type,
+ Attribs.GetResourceDimension(),
+ Attribs.IsMultisample(),
+ VarType,
+ Binding,
+ DescriptorSet,
+ CacheOffset,
+ SamplerInd,
+ SrcImmutableSamplerInd >= 0,
+ Attribs.BufferStaticSize,
+ Attribs.BufferStride //
+ };
+ }
+ else
+ {
+ // merge with existing
+ auto& ExistingRes = GetResource(VarType, ResIter->second);
+ VERIFY_EXPR(ExistingRes.VariableType == VarType);
+ VERIFY_EXPR(ExistingRes.Type == Attribs.Type);
+ VERIFY_EXPR(ExistingRes.ResourceDim == Attribs.ResourceDim);
+ VERIFY_EXPR(ExistingRes.IsMS == Attribs.IsMS);
+ VERIFY_EXPR(ExistingRes.ArraySize == Attribs.ArraySize);
+ }
+ } //
+ );
+ }
#ifdef DILIGENT_DEBUG
for (SHADER_RESOURCE_VARIABLE_TYPE VarType = SHADER_RESOURCE_VARIABLE_TYPE_STATIC; VarType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; VarType = static_cast<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);
@@ -293,14 +374,14 @@ void ShaderResourceLayoutVk::dvpVerifyResourceLayoutDesc(const TShaderStages&
std::string ShadersStr;
while (Stages != SHADER_TYPE_UNKNOWN)
{
- const auto ShaderType = Stages & static_cast<SHADER_TYPE>(~(static_cast<Uint32>(Stages) - 1));
- const char* ShaderName = nullptr;
+ 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 = StageInfo.pShader->GetDesc().Name;
+ ShaderName = GetShaderGroupName(StageInfo.Shaders);
break;
}
}
@@ -309,10 +390,10 @@ void ShaderResourceLayoutVk::dvpVerifyResourceLayoutDesc(const TShaderStages&
ShadersStr.append(", ");
ShadersStr.append(GetShaderTypeLiteralName(ShaderType));
ShadersStr.append(" (");
- if (ShaderName)
+ if (ShaderName.size())
{
ShadersStr.push_back('\'');
- ShadersStr.append(ShaderName ? ShaderName : "<Not enabled in PSO>");
+ ShadersStr.append(ShaderName);
ShadersStr.push_back('\'');
}
else
@@ -340,9 +421,15 @@ void ShaderResourceLayoutVk::dvpVerifyResourceLayoutDesc(const TShaderStages&
bool VariableFound = false;
for (size_t s = 0; s < ShaderStages.size() && !VariableFound; ++s)
{
- const auto& Resources = *ShaderStages[s].pShader->GetShaderResources();
- if ((VarDesc.ShaderStages & Resources.GetShaderType()) != 0)
+ 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);
@@ -373,28 +460,34 @@ void ShaderResourceLayoutVk::dvpVerifyResourceLayoutDesc(const TShaderStages&
bool SamplerFound = false;
for (size_t s = 0; s < ShaderStages.size() && !SamplerFound; ++s)
{
- const auto& Resources = *ShaderStages[s].pShader->GetShaderResources();
- if ((ImtblSamDesc.ShaderStages & Resources.GetShaderType()) == 0)
+ const auto& Stage = ShaderStages[s];
+ if ((Stage.Type & ImtblSamDesc.ShaderStages) == 0)
continue;
- // Irrespective of whether HLSL-style combined image samplers are used,
- // an immutable sampler can be assigned to a GLSL sampled image (i.e. sampler2D g_tex)
- for (Uint32 i = 0; i < Resources.GetNumSmpldImgs() && !SamplerFound; ++i)
+ for (size_t j = 0; j < Stage.Shaders.size() && !SamplerFound; ++j)
{
- const auto& SmplImg = Resources.GetSmpldImg(i);
- SamplerFound = (strcmp(SmplImg.Name, ImtblSamDesc.SamplerOrTextureName) == 0);
- }
+ const auto& Resources = *Stage.Shaders[j]->GetShaderResources();
+ VERIFY_EXPR(Resources.GetShaderType() == Stage.Type);
- if (!SamplerFound)
- {
- // Check if an immutable sampler is assigned to a separate sampler.
- // In case HLSL-style combined image samplers are used, the condition is SepSmpl.Name == "g_Texture" + "_sampler".
- // Otherwise the condition is SepSmpl.Name == "g_Texture_sampler" + "".
- const auto* CombinedSamplerSuffix = Resources.GetCombinedSamplerSuffix();
- for (Uint32 i = 0; i < Resources.GetNumSepSmplrs() && !SamplerFound; ++i)
+ // Irrespective of whether HLSL-style combined image samplers are used,
+ // 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)
{
- const auto& SepSmpl = Resources.GetSepSmplr(i);
- SamplerFound = StreqSuff(SepSmpl.Name, ImtblSamDesc.SamplerOrTextureName, CombinedSamplerSuffix);
+ // 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);
+ }
}
}
}
@@ -423,15 +516,22 @@ void ShaderResourceLayoutVk::Initialize(IRenderDevice* pRende
dvpVerifyResourceLayoutDesc(ShaderStages, ResourceLayoutDesc, VerifyVariables, VerifyImmutableSamplers);
#endif
- const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes = nullptr;
- const Uint32 NumAllowedTypes = 0;
- const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes);
- constexpr bool AllocateImmutableSamplers = true;
+ std::array<ResourceNameToIndex_t, MAX_SHADERS_IN_PIPELINE> ResourceNameToIndexArray;
+
+ const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes = nullptr;
+ const Uint32 NumAllowedTypes = 0;
+ const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes);
+ constexpr bool AllocateImmutableSamplers = true;
+
+ std::vector<StringPool> stringPools;
+ stringPools.reserve(ShaderStages.size());
for (size_t s = 0; s < ShaderStages.size(); ++s)
{
- Layouts[s].AllocateMemory(ShaderStages[s].pShader, LayoutDataAllocator, ResourceLayoutDesc,
- AllowedVarTypes, NumAllowedTypes, AllocateImmutableSamplers);
+ stringPools.emplace_back(
+ Layouts[s].AllocateMemory(ShaderStages[s].Shaders, LayoutDataAllocator, ResourceLayoutDesc,
+ AllowedVarTypes, NumAllowedTypes, ResourceNameToIndexArray[s],
+ AllocateImmutableSamplers));
}
//VERIFY_EXPR(NumShaders <= MAX_SHADERS_IN_PIPELINE);
@@ -441,77 +541,123 @@ void ShaderResourceLayoutVk::Initialize(IRenderDevice* pRende
std::unordered_map<Uint32, std::pair<Uint32, Uint32>> dbgBindings_CacheOffsets;
#endif
- auto AddResource = [&](Uint32 ShaderInd,
+ auto AddResource = [&](const Uint32 ShaderInd,
ShaderResourceLayoutVk& ResLayout,
const SPIRVShaderResources& Resources,
- const SPIRVShaderResourceAttribs& Attribs) //
+ const SPIRVShaderResourceAttribs& Attribs,
+ ResourceNameToIndex_t& ResourceNameToIndex,
+ std::vector<uint32_t>& SPIRV) //
{
const auto ShaderType = Resources.GetShaderType();
const SHADER_RESOURCE_VARIABLE_TYPE VarType = FindShaderVariableType(ShaderType, Attribs, ResourceLayoutDesc, Resources.GetCombinedSamplerSuffix());
if (!IsAllowedType(VarType, AllowedTypeBits))
return;
- Uint32 Binding = 0;
- Uint32 DescriptorSet = 0;
- Uint32 CacheOffset = 0;
- Uint32 SamplerInd = VkResource::InvalidSamplerInd;
+ auto ResIter = ResourceNameToIndex.find(HashMapStringKey{Attribs.Name});
+ VERIFY_EXPR(ResIter != ResourceNameToIndex.end());
- if (Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage)
+ const VkResource* pResource = nullptr;
+ if (ResIter->second == InvalidResourceIndex)
{
- // Separate samplers are enumerated before separate images, so the sampler
- // assigned to this separate image must have already been created.
- SamplerInd = FindAssignedSampler(ResLayout, Resources, Attribs, CurrResInd[ShaderInd][VarType], VarType);
- }
+ // add new resource
+ Uint32 Binding = 0;
+ Uint32 DescriptorSet = 0;
+ Uint32 CacheOffset = 0;
+ Uint32 SamplerInd = VkResource::InvalidSamplerInd;
- VkSampler vkImmutableSampler = VK_NULL_HANDLE;
- if (Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage ||
- Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler)
- {
- // Only search for the immutable sampler for combined image samplers and separate samplers
- Int32 SrcImmutableSamplerInd = FindImmutableSampler(ShaderType, ResourceLayoutDesc, Attribs, Resources.GetCombinedSamplerSuffix());
- if (SrcImmutableSamplerInd >= 0)
+ if (Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage)
+ {
+ // Separate samplers are enumerated before separate images, so the sampler
+ // assigned to this separate image must have already been created.
+ SamplerInd = FindAssignedSampler(ResLayout, Resources, Attribs, CurrResInd[ShaderInd][VarType], VarType);
+ }
+
+ VkSampler vkImmutableSampler = VK_NULL_HANDLE;
+ if (Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage ||
+ Attribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler)
{
- auto& ImmutableSampler = ResLayout.GetImmutableSampler(CurrImmutableSamplerInd[ShaderInd]++);
- VERIFY(!ImmutableSampler, "Immutable sampler has already been initialized!");
- const auto& ImmutableSamplerDesc = ResourceLayoutDesc.ImmutableSamplers[SrcImmutableSamplerInd].Desc;
- pRenderDevice->CreateSampler(ImmutableSamplerDesc, &ImmutableSampler);
- vkImmutableSampler = ImmutableSampler.RawPtr<SamplerVkImpl>()->GetVkSampler();
+ // Only search for the immutable sampler for combined image samplers and separate samplers
+ Int32 SrcImmutableSamplerInd = FindImmutableSampler(ShaderType, ResourceLayoutDesc, Attribs, Resources.GetCombinedSamplerSuffix());
+ if (SrcImmutableSamplerInd >= 0)
+ {
+ auto& ImmutableSampler = ResLayout.GetImmutableSampler(CurrImmutableSamplerInd[ShaderInd]++);
+ VERIFY(!ImmutableSampler, "Immutable sampler has already been initialized!");
+ const auto& ImmutableSamplerDesc = ResourceLayoutDesc.ImmutableSamplers[SrcImmutableSamplerInd].Desc;
+ pRenderDevice->CreateSampler(ImmutableSamplerDesc, &ImmutableSampler);
+ vkImmutableSampler = ImmutableSampler.RawPtr<SamplerVkImpl>()->GetVkSampler();
+ }
}
- }
- auto& ShaderSPIRV = ShaderStages[ShaderInd].SPIRV;
- PipelineLayout.AllocateResourceSlot(Attribs, VarType, vkImmutableSampler, Resources.GetShaderType(), DescriptorSet, Binding, CacheOffset, ShaderSPIRV);
- 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");
+ 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);
+ // Verify that bindings and cache offsets monotonically increase in every descriptor set
+ auto Binding_OffsetIt = dbgBindings_CacheOffsets.find(DescriptorSet);
+ if (Binding_OffsetIt != dbgBindings_CacheOffsets.end())
+ {
+ VERIFY(Binding > Binding_OffsetIt->second.first, "Binding for descriptor set ", DescriptorSet, " is not strictly monotonic");
+ VERIFY(CacheOffset > Binding_OffsetIt->second.second, "Cache offset for descriptor set ", DescriptorSet, " is not strictly monotonic");
+ }
+ dbgBindings_CacheOffsets[DescriptorSet] = std::make_pair(Binding, CacheOffset);
#endif
- auto& ResInd = CurrResInd[ShaderInd][VarType];
- ::new (&ResLayout.GetResource(VarType, ResInd++)) VkResource(ResLayout, Attribs, VarType, Binding, DescriptorSet, CacheOffset, SamplerInd, vkImmutableSampler != VK_NULL_HANDLE ? 1 : 0);
+ auto& ResInd = CurrResInd[ShaderInd][VarType];
+ ResIter->second = ResInd;
+
+ pResource = ::new (&ResLayout.GetResource(VarType, ResInd++)) VkResource //
+ {
+ ResLayout,
+ stringPools[ShaderInd].CopyString(Attribs.Name),
+ Attribs.ArraySize,
+ Attribs.Type,
+ Attribs.GetResourceDimension(),
+ Attribs.IsMultisample(),
+ VarType,
+ Binding,
+ DescriptorSet,
+ CacheOffset,
+ SamplerInd,
+ vkImmutableSampler != VK_NULL_HANDLE,
+ Attribs.BufferStaticSize,
+ Attribs.BufferStride //
+ };
+ }
+ else
+ {
+ // merge with existing
+ pResource = &ResLayout.GetResource(VarType, ResIter->second);
+
+ VERIFY_EXPR(pResource->VariableType == VarType);
+ VERIFY_EXPR(pResource->Type == Attribs.Type);
+ VERIFY_EXPR(pResource->ResourceDim == Attribs.ResourceDim);
+ VERIFY_EXPR(pResource->IsMS == Attribs.IsMS);
+ VERIFY_EXPR(pResource->ArraySize == Attribs.ArraySize);
+ }
+ 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;
auto& Layout = Layouts[s];
- auto* pShaderVk = ShaderStages[s].pShader;
- auto& Resources = *pShaderVk->GetShaderResources();
- for (Uint32 n = 0; n < Resources.GetNumUBs(); ++n)
+ auto& NameToIdx = ResourceNameToIndexArray[s];
+ for (size_t i = 0; i < Shaders.size(); ++i)
{
- const auto& UB = Resources.GetUB(n);
- auto VarType = GetShaderVariableType(Resources.GetShaderType(), UB.Name, ResourceLayoutDesc);
- if (IsAllowedType(VarType, AllowedTypeBits))
+ auto& SPIRV = ShaderStages[s].SPIRVs[i];
+ auto& Resources = *Shaders[i]->GetShaderResources();
+ for (Uint32 n = 0; n < Resources.GetNumUBs(); ++n)
{
- AddResource(static_cast<Uint32>(s), Layout, Resources, UB);
+ const auto& UB = Resources.GetUB(n);
+ auto VarType = GetShaderVariableType(Resources.GetShaderType(), UB.Name, ResourceLayoutDesc);
+ if (IsAllowedType(VarType, AllowedTypeBits))
+ {
+ AddResource(static_cast<Uint32>(s), Layout, Resources, UB, NameToIdx, SPIRV);
+ }
}
}
}
@@ -519,15 +665,21 @@ void ShaderResourceLayoutVk::Initialize(IRenderDevice* pRende
// Second, process all storage buffers
for (size_t s = 0; s < ShaderStages.size(); ++s)
{
+ auto& Shaders = ShaderStages[s].Shaders;
auto& Layout = Layouts[s];
- auto& Resources = *ShaderStages[s].pShader->GetShaderResources();
- for (Uint32 n = 0; n < Resources.GetNumSBs(); ++n)
+ auto& NameToIdx = ResourceNameToIndexArray[s];
+ for (size_t i = 0; i < Shaders.size(); ++i)
{
- const auto& SB = Resources.GetSB(n);
- auto VarType = GetShaderVariableType(Resources.GetShaderType(), SB.Name, ResourceLayoutDesc);
- if (IsAllowedType(VarType, AllowedTypeBits))
+ auto& Resources = *Shaders[i]->GetShaderResources();
+ auto& SPIRV = ShaderStages[s].SPIRVs[i];
+ for (Uint32 n = 0; n < Resources.GetNumSBs(); ++n)
{
- AddResource(static_cast<Uint32>(s), Layout, Resources, SB);
+ const auto& SB = Resources.GetSB(n);
+ auto VarType = GetShaderVariableType(Resources.GetShaderType(), SB.Name, ResourceLayoutDesc);
+ if (IsAllowedType(VarType, AllowedTypeBits))
+ {
+ AddResource(static_cast<Uint32>(s), Layout, Resources, SB, NameToIdx, SPIRV);
+ }
}
}
}
@@ -536,51 +688,62 @@ void ShaderResourceLayoutVk::Initialize(IRenderDevice* pRende
for (size_t s = 0; s < ShaderStages.size(); ++s)
{
auto& Layout = Layouts[s];
- auto& Resources = *ShaderStages[s].pShader->GetShaderResources();
- // clang-format off
- Resources.ProcessResources(
- [&](const SPIRVShaderResourceAttribs& UB, Uint32)
- {
- VERIFY_EXPR(UB.Type == SPIRVShaderResourceAttribs::ResourceType::UniformBuffer);
- // Skip
- },
- [&](const SPIRVShaderResourceAttribs& SB, Uint32)
- {
- VERIFY_EXPR(SB.Type == SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer || SB.Type == SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer);
- // Skip
- },
- [&](const SPIRVShaderResourceAttribs& Img, Uint32)
- {
- VERIFY_EXPR(Img.Type == SPIRVShaderResourceAttribs::ResourceType::StorageImage || Img.Type == SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer);
- AddResource(static_cast<Uint32>(s), Layout, Resources, Img);
- },
- [&](const SPIRVShaderResourceAttribs& SmplImg, Uint32)
- {
- VERIFY_EXPR(SmplImg.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage || SmplImg.Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer);
- AddResource(static_cast<Uint32>(s), Layout, Resources, SmplImg);
- },
- [&](const SPIRVShaderResourceAttribs& AC, Uint32)
- {
- VERIFY_EXPR(AC.Type == SPIRVShaderResourceAttribs::ResourceType::AtomicCounter);
- AddResource(static_cast<Uint32>(s), Layout, Resources, AC);
- },
- [&](const SPIRVShaderResourceAttribs& SepSmpl, Uint32)
- {
- VERIFY_EXPR(SepSmpl.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler);
- AddResource(static_cast<Uint32>(s), Layout, Resources, SepSmpl);
- },
- [&](const SPIRVShaderResourceAttribs& SepImg, Uint32)
- {
- VERIFY_EXPR(SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage || SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer);
- AddResource(static_cast<Uint32>(s), Layout, Resources, SepImg);
- },
- [&](const SPIRVShaderResourceAttribs& InputAtt, Uint32)
- {
- VERIFY_EXPR(InputAtt.Type == SPIRVShaderResourceAttribs::ResourceType::InputAttachment);
- AddResource(static_cast<Uint32>(s), Layout, Resources, InputAtt);
- }
- );
- // clang-format on
+ auto& Shaders = ShaderStages[s].Shaders;
+ auto& NameToIdx = ResourceNameToIndexArray[s];
+ for (size_t i = 0; i < Shaders.size(); ++i)
+ {
+ auto& Resources = *Shaders[i]->GetShaderResources();
+ auto& SPIRV = ShaderStages[s].SPIRVs[i];
+ // clang-format off
+ Resources.ProcessResources(
+ [&](const SPIRVShaderResourceAttribs& UB, Uint32)
+ {
+ VERIFY_EXPR(UB.Type == SPIRVShaderResourceAttribs::ResourceType::UniformBuffer);
+ // Skip
+ },
+ [&](const SPIRVShaderResourceAttribs& SB, Uint32)
+ {
+ VERIFY_EXPR(SB.Type == SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer || SB.Type == SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer);
+ // Skip
+ },
+ [&](const SPIRVShaderResourceAttribs& Img, Uint32)
+ {
+ VERIFY_EXPR(Img.Type == SPIRVShaderResourceAttribs::ResourceType::StorageImage || Img.Type == SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer);
+ AddResource(static_cast<Uint32>(s), Layout, Resources, Img, NameToIdx, SPIRV);
+ },
+ [&](const SPIRVShaderResourceAttribs& SmplImg, Uint32)
+ {
+ VERIFY_EXPR(SmplImg.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage || SmplImg.Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer);
+ AddResource(static_cast<Uint32>(s), Layout, Resources, SmplImg, NameToIdx, SPIRV);
+ },
+ [&](const SPIRVShaderResourceAttribs& AC, Uint32)
+ {
+ VERIFY_EXPR(AC.Type == SPIRVShaderResourceAttribs::ResourceType::AtomicCounter);
+ AddResource(static_cast<Uint32>(s), Layout, Resources, AC, NameToIdx, SPIRV);
+ },
+ [&](const SPIRVShaderResourceAttribs& SepSmpl, Uint32)
+ {
+ VERIFY_EXPR(SepSmpl.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler);
+ AddResource(static_cast<Uint32>(s), Layout, Resources, SepSmpl, NameToIdx, SPIRV);
+ },
+ [&](const SPIRVShaderResourceAttribs& SepImg, Uint32)
+ {
+ VERIFY_EXPR(SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage || SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer);
+ AddResource(static_cast<Uint32>(s), Layout, Resources, SepImg, NameToIdx, SPIRV);
+ },
+ [&](const SPIRVShaderResourceAttribs& InputAtt, Uint32)
+ {
+ VERIFY_EXPR(InputAtt.Type == SPIRVShaderResourceAttribs::ResourceType::InputAttachment);
+ AddResource(static_cast<Uint32>(s), Layout, Resources, InputAtt, NameToIdx, SPIRV);
+ },
+ [&](const SPIRVShaderResourceAttribs& AccelStruct, Uint32)
+ {
+ VERIFY_EXPR(AccelStruct.Type == SPIRVShaderResourceAttribs::ResourceType::AccelerationStructure);
+ AddResource(static_cast<Uint32>(s), Layout, Resources, AccelStruct, NameToIdx, SPIRV);
+ }
+ );
+ // clang-format on
+ }
}
#ifdef DILIGENT_DEBUG
@@ -593,28 +756,32 @@ void ShaderResourceLayoutVk::Initialize(IRenderDevice* pRende
}
// Some immutable samplers may never be initialized if they are not present in shaders
VERIFY_EXPR(CurrImmutableSamplerInd[s] <= Layout.m_NumImmutableSamplers);
+
+ VERIFY_EXPR(stringPools[s].GetRemainingSize() == 0);
}
#endif
}
-void ShaderResourceLayoutVk::VkResource::UpdateDescriptorHandle(VkDescriptorSet vkDescrSet,
- uint32_t ArrayElement,
- const VkDescriptorImageInfo* pImageInfo,
- const VkDescriptorBufferInfo* pBufferInfo,
- const VkBufferView* pTexelBufferView) const
+
+void ShaderResourceLayoutVk::VkResource::UpdateDescriptorHandle(VkDescriptorSet vkDescrSet,
+ uint32_t ArrayElement,
+ const VkDescriptorImageInfo* pImageInfo,
+ const VkDescriptorBufferInfo* pBufferInfo,
+ const VkBufferView* pTexelBufferView,
+ const VkWriteDescriptorSetAccelerationStructureKHR* pAccelStructInfo) const
{
VERIFY_EXPR(vkDescrSet != VK_NULL_HANDLE);
VkWriteDescriptorSet WriteDescrSet;
WriteDescrSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- WriteDescrSet.pNext = nullptr;
+ WriteDescrSet.pNext = pAccelStructInfo;
WriteDescrSet.dstSet = vkDescrSet;
WriteDescrSet.dstBinding = Binding;
WriteDescrSet.dstArrayElement = ArrayElement;
WriteDescrSet.descriptorCount = 1;
// descriptorType must be the same type as that specified in VkDescriptorSetLayoutBinding for dstSet at dstBinding.
// The type of the descriptor also controls which array the descriptors are taken from. (13.2.4)
- WriteDescrSet.descriptorType = PipelineLayout::GetVkDescriptorType(SpirvAttribs);
+ WriteDescrSet.descriptorType = PipelineLayout::GetVkDescriptorType(Type);
WriteDescrSet.pImageInfo = pImageInfo;
WriteDescrSet.pBufferInfo = pBufferInfo;
WriteDescrSet.pTexelBufferView = pTexelBufferView;
@@ -654,10 +821,18 @@ void ShaderResourceLayoutVk::VkResource::CacheUniformBuffer(IDeviceObject*
Uint32 ArrayInd,
Uint16& DynamicBuffersCounter) const
{
- VERIFY(SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::UniformBuffer, "Uniform buffer resource is expected");
+ VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::UniformBuffer, "Uniform buffer resource is expected");
RefCntAutoPtr<BufferVkImpl> pBufferVk{pBuffer, IID_BufferVk};
#ifdef DILIGENT_DEVELOPMENT
- VerifyConstantBufferBinding(SpirvAttribs, GetVariableType(), ArrayInd, pBuffer, pBufferVk.RawPtr(), DstRes.pObject.RawPtr(), ParentResLayout.GetShaderName());
+ VerifyConstantBufferBinding(*this, GetVariableType(), ArrayInd, pBuffer, pBufferVk.RawPtr(), DstRes.pObject.RawPtr(), ParentResLayout.GetShaderName());
+
+ 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) {
@@ -691,8 +866,8 @@ void ShaderResourceLayoutVk::VkResource::CacheStorageBuffer(IDeviceObject*
Uint16& DynamicBuffersCounter) const
{
// clang-format off
- VERIFY(SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer ||
- SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer,
+ VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer ||
+ Type == SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer,
"Storage buffer resource is expected");
// clang-format on
@@ -700,8 +875,8 @@ void ShaderResourceLayoutVk::VkResource::CacheStorageBuffer(IDeviceObject*
#ifdef DILIGENT_DEVELOPMENT
{
// HLSL buffer SRVs are mapped to storge buffers in GLSL
- auto RequiredViewType = SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer ? BUFFER_VIEW_SHADER_RESOURCE : BUFFER_VIEW_UNORDERED_ACCESS;
- VerifyResourceViewBinding(SpirvAttribs, GetVariableType(), ArrayInd, pBufferView, pBufferViewVk.RawPtr(), {RequiredViewType}, DstRes.pObject.RawPtr(), ParentResLayout.GetShaderName());
+ auto RequiredViewType = Type == SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer ? BUFFER_VIEW_SHADER_RESOURCE : BUFFER_VIEW_UNORDERED_ACCESS;
+ VerifyResourceViewBinding(*this, GetVariableType(), ArrayInd, pBufferView, pBufferViewVk.RawPtr(), {RequiredViewType}, DstRes.pObject.RawPtr(), ParentResLayout.GetShaderName());
if (pBufferViewVk != nullptr)
{
const auto& ViewDesc = pBufferViewVk->GetDesc();
@@ -709,7 +884,25 @@ void ShaderResourceLayoutVk::VkResource::CacheStorageBuffer(IDeviceObject*
if (BuffDesc.Mode != BUFFER_MODE_STRUCTURED && BuffDesc.Mode != BUFFER_MODE_RAW)
{
LOG_ERROR_MESSAGE("Error binding buffer view '", ViewDesc.Name, "' of buffer '", BuffDesc.Name, "' to shader variable '",
- SpirvAttribs.Name, "' in shader '", ParentResLayout.GetShaderName(), "': structured buffer view is expected.");
+ Name, "' in shader '", ParentResLayout.GetShaderName(), "': structured buffer view is expected.");
+ }
+
+ 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.");
}
}
}
@@ -747,8 +940,8 @@ void ShaderResourceLayoutVk::VkResource::CacheTexelBuffer(IDeviceObject*
Uint16& DynamicBuffersCounter) const
{
// clang-format off
- VERIFY(SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer ||
- SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer,
+ VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer ||
+ Type == SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer,
"Uniform or storage buffer resource is expected");
// clang-format on
@@ -756,8 +949,8 @@ void ShaderResourceLayoutVk::VkResource::CacheTexelBuffer(IDeviceObject*
#ifdef DILIGENT_DEVELOPMENT
{
// HLSL buffer SRVs are mapped to storge buffers in GLSL
- auto RequiredViewType = SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer ? BUFFER_VIEW_UNORDERED_ACCESS : BUFFER_VIEW_SHADER_RESOURCE;
- VerifyResourceViewBinding(SpirvAttribs, GetVariableType(), ArrayInd, pBufferView, pBufferViewVk.RawPtr(), {RequiredViewType}, DstRes.pObject.RawPtr(), ParentResLayout.GetShaderName());
+ auto RequiredViewType = Type == SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer ? BUFFER_VIEW_UNORDERED_ACCESS : BUFFER_VIEW_SHADER_RESOURCE;
+ VerifyResourceViewBinding(*this, GetVariableType(), ArrayInd, pBufferView, pBufferViewVk.RawPtr(), {RequiredViewType}, DstRes.pObject.RawPtr(), ParentResLayout.GetShaderName());
if (pBufferViewVk != nullptr)
{
const auto& ViewDesc = pBufferViewVk->GetDesc();
@@ -765,7 +958,7 @@ void ShaderResourceLayoutVk::VkResource::CacheTexelBuffer(IDeviceObject*
if (!((BuffDesc.Mode == BUFFER_MODE_FORMATTED && ViewDesc.Format.ValueType != VT_UNDEFINED) || BuffDesc.Mode == BUFFER_MODE_RAW))
{
LOG_ERROR_MESSAGE("Error binding buffer view '", ViewDesc.Name, "' of buffer '", BuffDesc.Name, "' to shader variable '",
- SpirvAttribs.Name, "' in shader '", ParentResLayout.GetShaderName(), "': formatted buffer view is expected.");
+ Name, "' in shader '", ParentResLayout.GetShaderName(), "': formatted buffer view is expected.");
}
}
}
@@ -805,9 +998,9 @@ void ShaderResourceLayoutVk::VkResource::CacheImage(IDeviceObject*
TCacheSampler CacheSampler) const
{
// clang-format off
- VERIFY(SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::StorageImage ||
- SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage ||
- SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage,
+ VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::StorageImage ||
+ Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage ||
+ Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage,
"Storage image, separate image or sampled image resource is expected");
// clang-format on
@@ -815,8 +1008,8 @@ void ShaderResourceLayoutVk::VkResource::CacheImage(IDeviceObject*
#ifdef DILIGENT_DEVELOPMENT
{
// HLSL buffer SRVs are mapped to storge buffers in GLSL
- auto RequiredViewType = SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::StorageImage ? TEXTURE_VIEW_UNORDERED_ACCESS : TEXTURE_VIEW_SHADER_RESOURCE;
- VerifyResourceViewBinding(SpirvAttribs, GetVariableType(), ArrayInd, pTexView, pTexViewVk0.RawPtr(), {RequiredViewType}, DstRes.pObject.RawPtr(), ParentResLayout.GetShaderName());
+ auto RequiredViewType = Type == SPIRVShaderResourceAttribs::ResourceType::StorageImage ? TEXTURE_VIEW_UNORDERED_ACCESS : TEXTURE_VIEW_SHADER_RESOURCE;
+ VerifyResourceViewBinding(*this, GetVariableType(), ArrayInd, pTexView, pTexViewVk0.RawPtr(), {RequiredViewType}, DstRes.pObject.RawPtr(), ParentResLayout.GetShaderName());
}
#endif
if (UpdateCachedResource(DstRes, std::move(pTexViewVk0), [](const TextureViewVkImpl*, const TextureViewVkImpl*) {}))
@@ -824,11 +1017,11 @@ void ShaderResourceLayoutVk::VkResource::CacheImage(IDeviceObject*
// We can do RawPtr here safely since UpdateCachedResource() returned true
auto* pTexViewVk = DstRes.pObject.RawPtr<TextureViewVkImpl>();
#ifdef DILIGENT_DEVELOPMENT
- if (SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage && !IsImmutableSamplerAssigned())
+ if (Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage && !IsImmutableSamplerAssigned())
{
if (pTexViewVk->GetSampler() == nullptr)
{
- LOG_ERROR_MESSAGE("Error binding texture view '", pTexViewVk->GetDesc().Name, "' to variable '", SpirvAttribs.GetPrintName(ArrayInd),
+ LOG_ERROR_MESSAGE("Error binding texture view '", pTexViewVk->GetDesc().Name, "' to variable '", GetPrintName(ArrayInd),
"' in shader '", ParentResLayout.GetShaderName(), "'. No sampler is assigned to the view");
}
}
@@ -844,11 +1037,11 @@ void ShaderResourceLayoutVk::VkResource::CacheImage(IDeviceObject*
if (SamplerInd != InvalidSamplerInd)
{
- VERIFY(SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage,
+ VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage,
"Only separate images can be assigned separate samplers when using HLSL-style combined samplers.");
VERIFY(!IsImmutableSamplerAssigned(), "Separate image can't be assigned an immutable sampler.");
const auto& SamplerAttribs = ParentResLayout.GetResource(GetVariableType(), SamplerInd);
- VERIFY_EXPR(SamplerAttribs.SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler);
+ VERIFY_EXPR(SamplerAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler);
if (!SamplerAttribs.IsImmutableSamplerAssigned())
{
auto* pSampler = pTexViewVk->GetSampler();
@@ -858,8 +1051,8 @@ void ShaderResourceLayoutVk::VkResource::CacheImage(IDeviceObject*
}
else
{
- LOG_ERROR_MESSAGE("Failed to bind sampler to sampler variable '", SamplerAttribs.SpirvAttribs.Name,
- "' assigned to separate image '", SpirvAttribs.GetPrintName(ArrayInd), "' in shader '",
+ LOG_ERROR_MESSAGE("Failed to bind sampler to sampler variable '", SamplerAttribs.Name,
+ "' assigned to separate image '", GetPrintName(ArrayInd), "' in shader '",
ParentResLayout.GetShaderName(), "': no sampler is set in texture view '", pTexViewVk->GetDesc().Name, '\'');
}
}
@@ -872,20 +1065,20 @@ void ShaderResourceLayoutVk::VkResource::CacheSeparateSampler(IDeviceObject*
VkDescriptorSet vkDescrSet,
Uint32 ArrayInd) const
{
- VERIFY(SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler, "Separate sampler resource is expected");
+ VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler, "Separate sampler resource is expected");
VERIFY(!IsImmutableSamplerAssigned(), "This separate sampler is assigned an immutable sampler");
RefCntAutoPtr<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 '", SpirvAttribs.GetPrintName(ArrayInd),
+ LOG_ERROR_MESSAGE("Failed to bind object '", pSampler->GetDesc().Name, "' to variable '", GetPrintName(ArrayInd),
"' in shader '", ParentResLayout.GetShaderName(), "'. Unexpected object type: sampler is expected");
}
if (GetVariableType() != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC && DstRes.pObject != nullptr && DstRes.pObject != pSamplerVk)
{
auto VarTypeStr = GetShaderVariableTypeLiteralName(GetVariableType());
- LOG_ERROR_MESSAGE("Non-null sampler is already bound to ", VarTypeStr, " shader variable '", SpirvAttribs.GetPrintName(ArrayInd),
+ LOG_ERROR_MESSAGE("Non-null sampler is already bound to ", VarTypeStr, " shader variable '", GetPrintName(ArrayInd),
"' in shader '", ParentResLayout.GetShaderName(),
"'. Attempting to bind another sampler or null is an error and may "
"cause unpredicted behavior. Use another shader resource binding instance or label the variable as dynamic.");
@@ -908,10 +1101,10 @@ void ShaderResourceLayoutVk::VkResource::CacheInputAttachment(IDeviceObject*
VkDescriptorSet vkDescrSet,
Uint32 ArrayInd) const
{
- VERIFY(SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::InputAttachment, "Input attachment resource is expected");
+ VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::InputAttachment, "Input attachment resource is expected");
RefCntAutoPtr<TextureViewVkImpl> pTexViewVk0{pTexView, IID_TextureViewVk};
#ifdef DILIGENT_DEVELOPMENT
- VerifyResourceViewBinding(SpirvAttribs, GetVariableType(), ArrayInd, pTexView, pTexViewVk0.RawPtr(), {TEXTURE_VIEW_SHADER_RESOURCE}, DstRes.pObject.RawPtr(), ParentResLayout.GetShaderName());
+ VerifyResourceViewBinding(*this, GetVariableType(), ArrayInd, pTexView, pTexViewVk0.RawPtr(), {TEXTURE_VIEW_SHADER_RESOURCE}, DstRes.pObject.RawPtr(), ParentResLayout.GetShaderName());
#endif
if (UpdateCachedResource(DstRes, std::move(pTexViewVk0), [](const TextureViewVkImpl*, const TextureViewVkImpl*) {}))
{
@@ -926,9 +1119,32 @@ void ShaderResourceLayoutVk::VkResource::CacheInputAttachment(IDeviceObject*
}
}
+void ShaderResourceLayoutVk::VkResource::CacheAccelerationStructure(IDeviceObject* pTLAS,
+ ShaderResourceCacheVk::Resource& DstRes,
+ VkDescriptorSet vkDescrSet,
+ Uint32 ArrayInd) const
+{
+ VERIFY(Type == SPIRVShaderResourceAttribs::ResourceType::AccelerationStructure, "Acceleration Structure resource is expected");
+ RefCntAutoPtr<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 < SpirvAttribs.ArraySize);
+ VERIFY_EXPR(ArrayIndex < ArraySize);
auto& DstDescrSet = ResourceCache.GetDescriptorSet(DescriptorSet);
auto vkDescrSet = DstDescrSet.GetVkDescriptorSet();
@@ -951,12 +1167,12 @@ void ShaderResourceLayoutVk::VkResource::BindResource(IDeviceObject* pObj, Uint3
}
#endif
auto& DstRes = DstDescrSet.GetResource(CacheOffset + ArrayIndex);
- VERIFY(DstRes.Type == SpirvAttribs.Type, "Inconsistent types");
+ VERIFY(DstRes.Type == Type, "Inconsistent types");
if (pObj)
{
- static_assert(SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes == 11, "Please handle the new resource type below");
- switch (SpirvAttribs.Type)
+ static_assert(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());
@@ -977,15 +1193,15 @@ void ShaderResourceLayoutVk::VkResource::BindResource(IDeviceObject* pObj, Uint3
case SPIRVShaderResourceAttribs::ResourceType::SampledImage:
CacheImage(pObj, DstRes, vkDescrSet, ArrayIndex,
[&](const VkResource& SeparateSampler, ISampler* pSampler) {
- VERIFY(!SeparateSampler.IsImmutableSamplerAssigned(), "Separate sampler '", SeparateSampler.SpirvAttribs.Name, "' is assigned an immutable sampler");
- VERIFY_EXPR(SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage);
- DEV_CHECK_ERR(SeparateSampler.SpirvAttribs.ArraySize == 1 || SeparateSampler.SpirvAttribs.ArraySize == SpirvAttribs.ArraySize,
- "Array size (", SeparateSampler.SpirvAttribs.ArraySize,
+ VERIFY(!SeparateSampler.IsImmutableSamplerAssigned(), "Separate sampler '", SeparateSampler.Name, "' is assigned an immutable sampler");
+ VERIFY_EXPR(Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage);
+ DEV_CHECK_ERR(SeparateSampler.ArraySize == 1 || SeparateSampler.ArraySize == ArraySize,
+ "Array size (", SeparateSampler.ArraySize,
") of separate sampler variable '",
- SeparateSampler.SpirvAttribs.Name,
- "' must be one or the same as the array size (", SpirvAttribs.ArraySize,
- ") of separate image variable '", SpirvAttribs.Name, "' it is assigned to");
- Uint32 SamplerArrInd = SeparateSampler.SpirvAttribs.ArraySize == 1 ? 0 : ArrayIndex;
+ SeparateSampler.Name,
+ "' must be one or the same as the array size (", ArraySize,
+ ") of separate image variable '", Name, "' it is assigned to");
+ Uint32 SamplerArrInd = SeparateSampler.ArraySize == 1 ? 0 : ArrayIndex;
SeparateSampler.BindResource(pSampler, SamplerArrInd, ResourceCache);
});
break;
@@ -999,7 +1215,7 @@ void ShaderResourceLayoutVk::VkResource::BindResource(IDeviceObject* pObj, Uint3
{
// Immutable samplers are permanently bound into the set layout; later binding a sampler
// into an immutable sampler slot in a descriptor set is not allowed (13.2.1)
- LOG_ERROR_MESSAGE("Attempting to assign a sampler to an immutable sampler '", SpirvAttribs.Name, '\'');
+ LOG_ERROR_MESSAGE("Attempting to assign a sampler to an immutable sampler '", Name, '\'');
}
break;
@@ -1007,14 +1223,18 @@ void ShaderResourceLayoutVk::VkResource::BindResource(IDeviceObject* pObj, Uint3
CacheInputAttachment(pObj, DstRes, vkDescrSet, ArrayIndex);
break;
- default: UNEXPECTED("Unknown resource type ", static_cast<Int32>(SpirvAttribs.Type));
+ 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 '", SpirvAttribs.Name, "' in shader '", ParentResLayout.GetShaderName(),
+ LOG_ERROR_MESSAGE("Shader variable '", Name, "' in shader '", ParentResLayout.GetShaderName(),
"' is not dynamic but being unbound. This is an error and may cause unpredicted behavior. "
"Use another shader resource binding instance or label shader variable as dynamic if you need to bind another resource.");
}
@@ -1025,7 +1245,7 @@ void ShaderResourceLayoutVk::VkResource::BindResource(IDeviceObject* pObj, Uint3
bool ShaderResourceLayoutVk::VkResource::IsBound(Uint32 ArrayIndex, const ShaderResourceCacheVk& ResourceCache) const
{
- VERIFY_EXPR(ArrayIndex < SpirvAttribs.ArraySize);
+ VERIFY_EXPR(ArrayIndex < ArraySize);
if (DescriptorSet < ResourceCache.GetNumDescriptorSets())
{
@@ -1055,21 +1275,21 @@ void ShaderResourceLayoutVk::InitializeStaticResources(const ShaderResourceLayou
// Get resource attributes
const auto& DstRes = GetResource(SHADER_RESOURCE_VARIABLE_TYPE_STATIC, r);
const auto& SrcRes = SrcLayout.GetResource(SHADER_RESOURCE_VARIABLE_TYPE_STATIC, r);
- VERIFY(SrcRes.Binding == SrcRes.SpirvAttribs.Type, "Unexpected binding");
- VERIFY(SrcRes.SpirvAttribs.ArraySize == DstRes.SpirvAttribs.ArraySize, "Inconsistent array size");
+ VERIFY(SrcRes.Binding == Uint32{SrcRes.Type}, "Unexpected binding");
+ VERIFY(SrcRes.ArraySize == DstRes.ArraySize, "Inconsistent array size");
- if (DstRes.SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler &&
+ if (DstRes.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler &&
DstRes.IsImmutableSamplerAssigned())
continue; // Skip immutable samplers
- for (Uint32 ArrInd = 0; ArrInd < DstRes.SpirvAttribs.ArraySize; ++ArrInd)
+ for (Uint32 ArrInd = 0; ArrInd < DstRes.ArraySize; ++ArrInd)
{
auto SrcOffset = SrcRes.CacheOffset + ArrInd;
const auto& SrcCachedSet = SrcResourceCache.GetDescriptorSet(SrcRes.DescriptorSet);
const auto& SrcCachedRes = SrcCachedSet.GetResource(SrcOffset);
IDeviceObject* pObject = SrcCachedRes.pObject.RawPtr<IDeviceObject>();
if (!pObject)
- LOG_ERROR_MESSAGE("No resource is assigned to static shader variable '", SrcRes.SpirvAttribs.GetPrintName(ArrInd), "' in shader '", GetShaderName(), "'.");
+ LOG_ERROR_MESSAGE("No resource is assigned to static shader variable '", SrcRes.GetPrintName(ArrInd), "' in shader '", GetShaderName(), "'.");
auto DstOffset = DstRes.CacheOffset + ArrInd;
IDeviceObject* pCachedResource = DstResourceCache.GetDescriptorSet(DstRes.DescriptorSet).GetResource(DstOffset).pObject;
@@ -1093,15 +1313,15 @@ bool ShaderResourceLayoutVk::dvpVerifyBindings(const ShaderResourceCacheVk& Reso
{
const auto& Res = GetResource(VarType, r);
VERIFY(Res.GetVariableType() == VarType, "Unexpected variable type");
- for (Uint32 ArrInd = 0; ArrInd < Res.SpirvAttribs.ArraySize; ++ArrInd)
+ for (Uint32 ArrInd = 0; ArrInd < Res.ArraySize; ++ArrInd)
{
const auto& CachedDescrSet = ResourceCache.GetDescriptorSet(Res.DescriptorSet);
const auto& CachedRes = CachedDescrSet.GetResource(Res.CacheOffset + ArrInd);
- VERIFY(CachedRes.Type == Res.SpirvAttribs.Type, "Inconsistent types");
+ VERIFY(CachedRes.Type == Res.Type, "Inconsistent types");
if (CachedRes.pObject == nullptr &&
- !(Res.SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler && Res.IsImmutableSamplerAssigned()))
+ !(Res.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler && Res.IsImmutableSamplerAssigned()))
{
- LOG_ERROR_MESSAGE("No resource is bound to ", GetShaderVariableTypeLiteralName(Res.GetVariableType()), " variable '", Res.SpirvAttribs.GetPrintName(ArrInd), "' in shader '", GetShaderName(), "'");
+ LOG_ERROR_MESSAGE("No resource is bound to ", GetShaderVariableTypeLiteralName(Res.GetVariableType()), " variable '", Res.GetPrintName(ArrInd), "' in shader '", GetShaderName(), "'");
BindingsOK = false;
}
# ifdef DILIGENT_DEBUG
@@ -1136,7 +1356,7 @@ void ShaderResourceLayoutVk::InitializeResourceMemoryInCache(ShaderResourceCache
for (Uint32 r = 0; r < TotalResources; ++r)
{
const auto& Res = GetResource(r);
- ResourceCache.InitializeResources(Res.DescriptorSet, Res.CacheOffset, Res.SpirvAttribs.ArraySize, Res.SpirvAttribs.Type);
+ ResourceCache.InitializeResources(Res.DescriptorSet, Res.CacheOffset, Res.ArraySize, Res.Type);
}
}
@@ -1151,24 +1371,28 @@ void ShaderResourceLayoutVk::CommitDynamicResources(const ShaderResourceCacheVk&
static constexpr size_t ImgUpdateBatchSize = 4;
static constexpr size_t BuffUpdateBatchSize = 2;
static constexpr size_t TexelBuffUpdateBatchSize = 2;
+ static constexpr size_t AccelStructBatchSize = 2;
static constexpr size_t WriteDescriptorSetBatchSize = 2;
#else
static constexpr size_t ImgUpdateBatchSize = 128;
static constexpr size_t BuffUpdateBatchSize = 64;
static constexpr size_t TexelBuffUpdateBatchSize = 32;
+ static constexpr size_t AccelStructBatchSize = 32;
static constexpr size_t WriteDescriptorSetBatchSize = 32;
#endif
// Do not zero-initiaize arrays!
- std::array<VkDescriptorImageInfo, ImgUpdateBatchSize> DescrImgInfoArr;
- std::array<VkDescriptorBufferInfo, BuffUpdateBatchSize> DescrBuffInfoArr;
- std::array<VkBufferView, TexelBuffUpdateBatchSize> DescrBuffViewArr;
- std::array<VkWriteDescriptorSet, WriteDescriptorSetBatchSize> WriteDescrSetArr;
+ 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
@@ -1195,14 +1419,15 @@ void ShaderResourceLayoutVk::CommitDynamicResources(const ShaderResourceCacheVk&
WriteDescrSetIt->dstArrayElement = ArrElem;
// descriptorType must be the same type as that specified in VkDescriptorSetLayoutBinding for dstSet at dstBinding.
// The type of the descriptor also controls which array the descriptors are taken from. (13.2.4)
- WriteDescrSetIt->descriptorType = PipelineLayout::GetVkDescriptorType(Res.SpirvAttribs);
+ WriteDescrSetIt->descriptorType = PipelineLayout::GetVkDescriptorType(Res.Type);
// For every resource type, try to batch as many descriptor updates as we can
- switch (Res.SpirvAttribs.Type)
+ static_assert(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.SpirvAttribs.ArraySize && DescrBuffIt != DescrBuffInfoArr.end())
+ while (ArrElem < Res.ArraySize && DescrBuffIt != DescrBuffInfoArr.end())
{
const auto& CachedRes = SetResources.GetResource(Res.CacheOffset + ArrElem);
*DescrBuffIt = CachedRes.GetUniformBufferDescriptorWriteInfo();
@@ -1214,7 +1439,7 @@ void ShaderResourceLayoutVk::CommitDynamicResources(const ShaderResourceCacheVk&
case SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer:
case SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer:
WriteDescrSetIt->pBufferInfo = &(*DescrBuffIt);
- while (ArrElem < Res.SpirvAttribs.ArraySize && DescrBuffIt != DescrBuffInfoArr.end())
+ while (ArrElem < Res.ArraySize && DescrBuffIt != DescrBuffInfoArr.end())
{
const auto& CachedRes = SetResources.GetResource(Res.CacheOffset + ArrElem);
*DescrBuffIt = CachedRes.GetStorageBufferDescriptorWriteInfo();
@@ -1226,7 +1451,7 @@ void ShaderResourceLayoutVk::CommitDynamicResources(const ShaderResourceCacheVk&
case SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer:
case SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer:
WriteDescrSetIt->pTexelBufferView = &(*BuffViewIt);
- while (ArrElem < Res.SpirvAttribs.ArraySize && BuffViewIt != DescrBuffViewArr.end())
+ while (ArrElem < Res.ArraySize && BuffViewIt != DescrBuffViewArr.end())
{
const auto& CachedRes = SetResources.GetResource(Res.CacheOffset + ArrElem);
*BuffViewIt = CachedRes.GetBufferViewWriteInfo();
@@ -1239,7 +1464,7 @@ void ShaderResourceLayoutVk::CommitDynamicResources(const ShaderResourceCacheVk&
case SPIRVShaderResourceAttribs::ResourceType::StorageImage:
case SPIRVShaderResourceAttribs::ResourceType::SampledImage:
WriteDescrSetIt->pImageInfo = &(*DescrImgIt);
- while (ArrElem < Res.SpirvAttribs.ArraySize && DescrImgIt != DescrImgInfoArr.end())
+ while (ArrElem < Res.ArraySize && DescrImgIt != DescrImgInfoArr.end())
{
const auto& CachedRes = SetResources.GetResource(Res.CacheOffset + ArrElem);
*DescrImgIt = CachedRes.GetImageDescriptorWriteInfo(Res.IsImmutableSamplerAssigned());
@@ -1259,7 +1484,7 @@ void ShaderResourceLayoutVk::CommitDynamicResources(const ShaderResourceCacheVk&
if (!Res.IsImmutableSamplerAssigned())
{
WriteDescrSetIt->pImageInfo = &(*DescrImgIt);
- while (ArrElem < Res.SpirvAttribs.ArraySize && DescrImgIt != DescrImgInfoArr.end())
+ while (ArrElem < Res.ArraySize && DescrImgIt != DescrImgInfoArr.end())
{
const auto& CachedRes = SetResources.GetResource(Res.CacheOffset + ArrElem);
*DescrImgIt = CachedRes.GetSamplerDescriptorWriteInfo();
@@ -1269,8 +1494,19 @@ void ShaderResourceLayoutVk::CommitDynamicResources(const ShaderResourceCacheVk&
}
else
{
- ArrElem = Res.SpirvAttribs.ArraySize;
- WriteDescrSetIt->dstArrayElement = Res.SpirvAttribs.ArraySize;
+ ArrElem = Res.ArraySize;
+ WriteDescrSetIt->dstArrayElement = Res.ArraySize;
+ }
+ break;
+
+ case SPIRVShaderResourceAttribs::ResourceType::AccelerationStructure:
+ WriteDescrSetIt->pNext = &(*AccelStructIt);
+ while (ArrElem < Res.ArraySize && AccelStructIt != DescrAccelStructArr.end())
+ {
+ const auto& CachedRes = SetResources.GetResource(Res.CacheOffset + ArrElem);
+ *AccelStructIt = CachedRes.GetAccelerationStructureWriteInfo();
+ ++AccelStructIt;
+ ++ArrElem;
}
break;
@@ -1279,7 +1515,7 @@ void ShaderResourceLayoutVk::CommitDynamicResources(const ShaderResourceCacheVk&
}
WriteDescrSetIt->descriptorCount = ArrElem - WriteDescrSetIt->dstArrayElement;
- if (ArrElem == Res.SpirvAttribs.ArraySize)
+ if (ArrElem == Res.ArraySize)
{
ArrElem = 0;
++ResNum;
@@ -1294,6 +1530,7 @@ void ShaderResourceLayoutVk::CommitDynamicResources(const ShaderResourceCacheVk&
DescrImgIt == DescrImgInfoArr.end() ||
DescrBuffIt == DescrBuffInfoArr.end() ||
BuffViewIt == DescrBuffViewArr.end() ||
+ AccelStructIt == DescrAccelStructArr.end() ||
WriteDescrSetIt == WriteDescrSetArr.end())
{
auto DescrWriteCount = static_cast<Uint32>(std::distance(WriteDescrSetArr.begin(), WriteDescrSetIt));
@@ -1303,9 +1540,27 @@ void ShaderResourceLayoutVk::CommitDynamicResources(const ShaderResourceCacheVk&
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 7e06bd69..062a5725 100644
--- a/Graphics/GraphicsEngineVulkan/src/ShaderVariableVk.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/ShaderVariableVk.cpp
@@ -52,7 +52,7 @@ size_t ShaderVariableManagerVk::GetRequiredMemorySize(const ShaderResourceLayout
// When using HLSL-style combined image samplers, we need to skip separate samplers.
// Also always skip immutable separate samplers.
- if (SrcRes.SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler &&
+ if (SrcRes.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler &&
(!UsingSeparateSamplers || SrcRes.IsImmutableSamplerAssigned()))
continue;
@@ -96,7 +96,7 @@ void ShaderVariableManagerVk::Initialize(const ShaderResourceLayoutVk& Sr
{
const auto& SrcRes = SrcLayout.GetResource(VarType, r);
// Skip separate samplers when using combined HLSL-style image samplers. Also always skip immutable separate samplers.
- if (SrcRes.SpirvAttribs.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler &&
+ if (SrcRes.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler &&
(!UsingSeparateSamplers || SrcRes.IsImmutableSamplerAssigned()))
continue;
@@ -132,7 +132,7 @@ ShaderVariableVkImpl* ShaderVariableManagerVk::GetVariable(const Char* Name) con
{
auto& Var = m_pVariables[v];
const auto& Res = Var.m_Resource;
- if (strcmp(Res.SpirvAttribs.Name, Name) == 0)
+ if (strcmp(Res.Name, Name) == 0)
{
pVar = &Var;
break;
@@ -190,18 +190,18 @@ void ShaderVariableManagerVk::BindResources(IResourceMapping* pResourceMapping,
const auto& Res = Var.m_Resource;
// There should be no immutable separate samplers
- VERIFY(Res.SpirvAttribs.Type != SPIRVShaderResourceAttribs::ResourceType::SeparateSampler || !Res.IsImmutableSamplerAssigned(),
+ VERIFY(Res.Type != SPIRVShaderResourceAttribs::ResourceType::SeparateSampler || !Res.IsImmutableSamplerAssigned(),
"There must be no shader resource variables for immutable separate samplers");
if ((Flags & (1 << Res.GetVariableType())) == 0)
continue;
- for (Uint32 ArrInd = 0; ArrInd < Res.SpirvAttribs.ArraySize; ++ArrInd)
+ for (Uint32 ArrInd = 0; ArrInd < Res.ArraySize; ++ArrInd)
{
if ((Flags & BIND_SHADER_RESOURCES_KEEP_EXISTING) && Res.IsBound(ArrInd, m_ResourceCache))
continue;
- const auto* VarName = Res.SpirvAttribs.Name;
+ const auto* VarName = Res.Name;
RefCntAutoPtr<IDeviceObject> pObj;
pResourceMapping->GetResource(VarName, &pObj, ArrInd);
if (pObj)
@@ -212,7 +212,7 @@ void ShaderVariableManagerVk::BindResources(IResourceMapping* pResourceMapping,
{
if ((Flags & BIND_SHADER_RESOURCES_VERIFY_ALL_RESOLVED) && !Res.IsBound(ArrInd, m_ResourceCache))
{
- LOG_ERROR_MESSAGE("Unable to bind resource to shader variable '", Res.SpirvAttribs.GetPrintName(ArrInd),
+ LOG_ERROR_MESSAGE("Unable to bind resource to shader variable '", Res.GetPrintName(ArrInd),
"': resource is not found in the resource mapping. "
"Do not use BIND_SHADER_RESOURCES_VERIFY_ALL_RESOLVED flag to suppress the message if this is not an issue.");
}
diff --git a/Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp
index 65505ad3..66393e9b 100644
--- a/Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/ShaderVkImpl.cpp
@@ -122,9 +122,17 @@ ShaderVkImpl::ShaderVkImpl(IReferenceCounters* pRefCounters,
SourceLength = GLSLSourceString.length();
}
+ GLSLangUtils::SpirvVersion spvVersion = GLSLangUtils::SpirvVersion::Vk100;
+ const auto& ExtFeats = GetDevice()->GetLogicalDevice().GetEnabledExtFeatures();
+ if (ExtFeats.Spirv15)
+ spvVersion = GLSLangUtils::SpirvVersion::Vk120;
+ else if (ExtFeats.Spirv14)
+ spvVersion = GLSLangUtils::SpirvVersion::Vk110_Spirv14;
+
m_SPIRV = GLSLangUtils::GLSLtoSPIRV(m_Desc.ShaderType, ShaderSource,
static_cast<int>(SourceLength), Macros,
ShaderCI.pShaderSourceStreamFactory,
+ spvVersion,
ShaderCI.ppCompilerOutput);
}
#endif
diff --git a/Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp
index ab53d639..b5f7e041 100644
--- a/Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp
@@ -423,6 +423,7 @@ void SwapChainVkImpl::CreateVulkanSwapChain()
swapchain_ci.imageColorSpace = ColorSpace;
DEV_CHECK_ERR(m_SwapChainDesc.Usage != 0, "No swap chain usage flags defined");
+ static_assert(SWAP_CHAIN_USAGE_LAST == SWAP_CHAIN_USAGE_COPY_SOURCE, "Please update this function to handle the new swapchain usage");
if (m_SwapChainDesc.Usage & SWAP_CHAIN_USAGE_RENDER_TARGET)
swapchain_ci.imageUsage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
if (m_SwapChainDesc.Usage & SWAP_CHAIN_USAGE_SHADER_INPUT)
@@ -639,9 +640,10 @@ VkResult SwapChainVkImpl::AcquireNextImage(DeviceContextVkImpl* pDeviceCtxVk)
m_ImageAcquiredFenceSubmitted[m_SemaphoreIndex] = (res == VK_SUCCESS);
if (res == VK_SUCCESS)
{
- // Next command in the device context must wait for the next image to be acquired
- // Unlike fences or events, the act of waiting for a semaphore also unsignals that semaphore (6.4.2)
- pDeviceCtxVk->AddWaitSemaphore(m_ImageAcquiredSemaphores[m_SemaphoreIndex], VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
+ // Next command in the device context must wait for the next image to be acquired.
+ // Unlike fences or events, the act of waiting for a semaphore also unsignals that semaphore (6.4.2).
+ // Swapchain image may be used as render target or as destination for copy command.
+ pDeviceCtxVk->AddWaitSemaphore(m_ImageAcquiredSemaphores[m_SemaphoreIndex], VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT);
if (!m_SwapChainImagesInitialized[m_BackBufferIndex])
{
// Vulkan validation layers do not like uninitialized memory.
diff --git a/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp
index 488e4bf6..0fb3dd79 100644
--- a/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp
@@ -223,13 +223,13 @@ TextureVkImpl::TextureVkImpl(IReferenceCounters* pRefCounters,
// For either clear or copy command, dst layout must be VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
VkImageSubresourceRange SubresRange;
- SubresRange.aspectMask = aspectMask;
- SubresRange.baseArrayLayer = 0;
- SubresRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
- SubresRange.baseMipLevel = 0;
- SubresRange.levelCount = VK_REMAINING_MIP_LEVELS;
- auto EnabledGraphicsShaderStages = LogicalDevice.GetEnabledGraphicsShaderStages();
- VulkanUtilities::VulkanCommandBuffer::TransitionImageLayout(vkCmdBuff, m_VulkanImage, ImageCI.initialLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, SubresRange, EnabledGraphicsShaderStages);
+ SubresRange.aspectMask = aspectMask;
+ SubresRange.baseArrayLayer = 0;
+ SubresRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
+ SubresRange.baseMipLevel = 0;
+ SubresRange.levelCount = VK_REMAINING_MIP_LEVELS;
+ auto EnabledShaderStages = LogicalDevice.GetEnabledShaderStages();
+ VulkanUtilities::VulkanCommandBuffer::TransitionImageLayout(vkCmdBuff, m_VulkanImage, ImageCI.initialLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, SubresRange, EnabledShaderStages);
SetState(RESOURCE_STATE_COPY_DEST);
const auto CurrentLayout = GetLayout();
VERIFY_EXPR(CurrentLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
@@ -350,7 +350,7 @@ TextureVkImpl::TextureVkImpl(IReferenceCounters* pRefCounters,
err = LogicalDevice.BindBufferMemory(StagingBuffer, StagingBufferMemory, AlignedStagingMemOffset);
CHECK_VK_ERROR_AND_THROW(err, "Failed to bind staging bufer memory");
- VulkanUtilities::VulkanCommandBuffer::BufferMemoryBarrier(vkCmdBuff, StagingBuffer, 0, VK_ACCESS_TRANSFER_READ_BIT, EnabledGraphicsShaderStages);
+ VulkanUtilities::VulkanCommandBuffer::BufferMemoryBarrier(vkCmdBuff, StagingBuffer, 0, VK_ACCESS_TRANSFER_READ_BIT, EnabledShaderStages);
// Copy commands MUST be recorded outside of a render pass instance. This is OK here
// as copy will be the only command in the cmd buffer
@@ -498,7 +498,7 @@ void TextureVkImpl::CreateViewInternal(const TextureViewDesc& ViewDesc, ITexture
VERIFY(&TexViewAllocator == &m_dbgTexViewObjAllocator, "Texture view allocator does not match allocator provided during texture initialization");
auto UpdatedViewDesc = ViewDesc;
- CorrectTextureViewDesc(UpdatedViewDesc);
+ ValidatedAndCorrectTextureViewDesc(m_Desc, UpdatedViewDesc);
VulkanUtilities::ImageViewWrapper ImgView = CreateImageView(UpdatedViewDesc);
auto pViewVk = NEW_RC_OBJ(TexViewAllocator, "TextureViewVkImpl instance", TextureViewVkImpl, bIsDefaultView ? this : nullptr)(GetDevice(), UpdatedViewDesc, this, std::move(ImgView), bIsDefaultView);
diff --git a/Graphics/GraphicsEngineVulkan/src/TopLevelASVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/TopLevelASVkImpl.cpp
new file mode 100644
index 00000000..03724a8a
--- /dev/null
+++ b/Graphics/GraphicsEngineVulkan/src/TopLevelASVkImpl.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2019-2020 Diligent Graphics LLC
+ * Copyright 2015-2019 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#include "pch.h"
+#include "TopLevelASVkImpl.hpp"
+#include "VulkanTypeConversions.hpp"
+
+namespace Diligent
+{
+
+TopLevelASVkImpl::TopLevelASVkImpl(IReferenceCounters* pRefCounters,
+ RenderDeviceVkImpl* pRenderDeviceVk,
+ const TopLevelASDesc& Desc) :
+ TTopLevelASBase{pRefCounters, pRenderDeviceVk, Desc}
+{
+ const auto& LogicalDevice = pRenderDeviceVk->GetLogicalDevice();
+ const auto& PhysicalDevice = pRenderDeviceVk->GetPhysicalDevice();
+ const auto& Limits = PhysicalDevice.GetExtProperties().AccelStruct;
+ Uint32 AccelStructSize = m_Desc.CompactedSize;
+
+ if (AccelStructSize == 0)
+ {
+ VkAccelerationStructureBuildGeometryInfoKHR vkBuildInfo = {};
+ VkAccelerationStructureBuildSizesInfoKHR vkSizeInfo = {VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR};
+ VkAccelerationStructureGeometryKHR vkGeometry = {};
+ VkAccelerationStructureGeometryInstancesDataKHR& vkInstances = vkGeometry.geometry.instances;
+ const uint32_t MaxPrimitiveCount = m_Desc.MaxInstanceCount;
+
+ vkGeometry.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR;
+ vkGeometry.geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR;
+ vkInstances.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR;
+ vkInstances.arrayOfPointers = VK_FALSE;
+
+ vkBuildInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR;
+ vkBuildInfo.flags = BuildASFlagsToVkBuildAccelerationStructureFlags(m_Desc.Flags);
+ vkBuildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR;
+ vkBuildInfo.pGeometries = &vkGeometry;
+ vkBuildInfo.geometryCount = 1;
+
+ VERIFY_EXPR(MaxPrimitiveCount <= Limits.maxInstanceCount);
+
+ LogicalDevice.GetAccelerationStructureBuildSizes(vkBuildInfo, &MaxPrimitiveCount, vkSizeInfo);
+
+ AccelStructSize = static_cast<Uint32>(vkSizeInfo.accelerationStructureSize);
+ m_ScratchSize.Build = static_cast<Uint32>(vkSizeInfo.buildScratchSize);
+ m_ScratchSize.Update = static_cast<Uint32>(vkSizeInfo.updateScratchSize);
+ }
+
+ VkBufferCreateInfo vkBuffCI = {};
+
+ vkBuffCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+ vkBuffCI.flags = 0;
+ vkBuffCI.size = AccelStructSize;
+ vkBuffCI.usage = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR;
+ vkBuffCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+ vkBuffCI.queueFamilyIndexCount = 0;
+ vkBuffCI.pQueueFamilyIndices = nullptr;
+
+ m_VulkanBuffer = LogicalDevice.CreateBuffer(vkBuffCI, m_Desc.Name);
+
+ VkMemoryRequirements MemReqs = LogicalDevice.GetBufferMemoryRequirements(m_VulkanBuffer);
+ uint32_t MemoryTypeIndex = PhysicalDevice.GetMemoryTypeIndex(MemReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+
+ VERIFY(IsPowerOfTwo(MemReqs.alignment), "Alignment is not power of 2!");
+ m_MemoryAllocation = pRenderDeviceVk->AllocateMemory(MemReqs.size, MemReqs.alignment, MemoryTypeIndex, VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT);
+
+ m_MemoryAlignedOffset = Align(VkDeviceSize{m_MemoryAllocation.UnalignedOffset}, MemReqs.alignment);
+ VERIFY(m_MemoryAllocation.Size >= MemReqs.size + (m_MemoryAlignedOffset - m_MemoryAllocation.UnalignedOffset), "Size of memory allocation is too small");
+ auto Memory = m_MemoryAllocation.Page->GetVkMemory();
+ auto err = LogicalDevice.BindBufferMemory(m_VulkanBuffer, Memory, m_MemoryAlignedOffset);
+ CHECK_VK_ERROR_AND_THROW(err, "Failed to bind buffer memory");
+
+ VkAccelerationStructureCreateInfoKHR vkAccelStrCI = {};
+
+ vkAccelStrCI.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR;
+ vkAccelStrCI.createFlags = 0;
+ vkAccelStrCI.buffer = m_VulkanBuffer;
+ vkAccelStrCI.offset = 0;
+ vkAccelStrCI.size = AccelStructSize;
+ vkAccelStrCI.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR;
+
+ m_VulkanTLAS = LogicalDevice.CreateAccelStruct(vkAccelStrCI, m_Desc.Name);
+
+ m_DeviceAddress = LogicalDevice.GetAccelerationStructureDeviceAddress(m_VulkanTLAS);
+
+ SetState(RESOURCE_STATE_BUILD_AS_READ);
+}
+
+TopLevelASVkImpl::TopLevelASVkImpl(IReferenceCounters* pRefCounters,
+ RenderDeviceVkImpl* pRenderDeviceVk,
+ const TopLevelASDesc& Desc,
+ RESOURCE_STATE InitialState,
+ VkAccelerationStructureKHR vkTLAS) :
+ TTopLevelASBase{pRefCounters, pRenderDeviceVk, Desc},
+ m_VulkanTLAS{vkTLAS}
+{
+ SetState(InitialState);
+ m_DeviceAddress = pRenderDeviceVk->GetLogicalDevice().GetAccelerationStructureDeviceAddress(m_VulkanTLAS);
+}
+
+TopLevelASVkImpl::~TopLevelASVkImpl()
+{
+ // Vk object can only be destroyed when it is no longer used by the GPU
+ if (m_VulkanTLAS != VK_NULL_HANDLE)
+ m_pDevice->SafeReleaseDeviceObject(std::move(m_VulkanTLAS), m_Desc.CommandQueueMask);
+ if (m_VulkanBuffer != VK_NULL_HANDLE)
+ m_pDevice->SafeReleaseDeviceObject(std::move(m_VulkanBuffer), m_Desc.CommandQueueMask);
+ if (m_MemoryAllocation.Page != nullptr)
+ m_pDevice->SafeReleaseDeviceObject(std::move(m_MemoryAllocation), m_Desc.CommandQueueMask);
+}
+
+} // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp
index 55bb7d8f..17c129c1 100644
--- a/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/VulkanTypeConversions.cpp
@@ -632,6 +632,21 @@ VkFormat TypeToVkFormat(VALUE_TYPE ValType, Uint32 NumComponents, Bool bIsNormal
}
}
+VkIndexType TypeToVkIndexType(VALUE_TYPE IndexType)
+{
+ switch (IndexType)
+ {
+ // clang-format off
+ case VT_UNDEFINED: return VK_INDEX_TYPE_NONE_KHR; // only for ray tracing
+ case VT_UINT16: return VK_INDEX_TYPE_UINT16;
+ case VT_UINT32: return VK_INDEX_TYPE_UINT32;
+ // clang-format on
+ default:
+ UNEXPECTED("Unexpected index type");
+ return VK_INDEX_TYPE_UINT32;
+ }
+}
+
VkPolygonMode FillModeToVkPolygonMode(FILL_MODE FillMode)
{
switch (FillMode)
@@ -1137,6 +1152,56 @@ VkBorderColor BorderColorToVkBorderColor(const Float32 BorderColor[])
}
+static VkPipelineStageFlags ResourceStateFlagToVkPipelineStage(RESOURCE_STATE StateFlag, VkPipelineStageFlags ShaderStages)
+{
+ static_assert(RESOURCE_STATE_MAX_BIT == RESOURCE_STATE_RAY_TRACING, "This function must be updated to handle new resource state flag");
+ VERIFY((StateFlag & (StateFlag - 1)) == 0, "Only single bit must be set");
+ switch (StateFlag)
+ {
+ // clang-format off
+ case RESOURCE_STATE_UNDEFINED: return 0;
+ case RESOURCE_STATE_VERTEX_BUFFER: return VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
+ case RESOURCE_STATE_CONSTANT_BUFFER: return ShaderStages;
+ case RESOURCE_STATE_INDEX_BUFFER: return VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
+ case RESOURCE_STATE_RENDER_TARGET: return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ case RESOURCE_STATE_UNORDERED_ACCESS: return ShaderStages;
+ case RESOURCE_STATE_DEPTH_WRITE: return VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
+ case RESOURCE_STATE_DEPTH_READ: return VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
+ case RESOURCE_STATE_SHADER_RESOURCE: return ShaderStages;
+ case RESOURCE_STATE_STREAM_OUT: return 0;
+ case RESOURCE_STATE_INDIRECT_ARGUMENT: return VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
+ case RESOURCE_STATE_COPY_DEST: return VK_PIPELINE_STAGE_TRANSFER_BIT;
+ case RESOURCE_STATE_COPY_SOURCE: return VK_PIPELINE_STAGE_TRANSFER_BIT;
+ case RESOURCE_STATE_RESOLVE_DEST: return VK_PIPELINE_STAGE_TRANSFER_BIT;
+ case RESOURCE_STATE_RESOLVE_SOURCE: return VK_PIPELINE_STAGE_TRANSFER_BIT;
+ case RESOURCE_STATE_INPUT_ATTACHMENT: return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+ case RESOURCE_STATE_PRESENT: return VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
+ case RESOURCE_STATE_BUILD_AS_READ: return VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR;
+ case RESOURCE_STATE_BUILD_AS_WRITE: return VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR;
+ case RESOURCE_STATE_RAY_TRACING: return VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR;
+ // clang-format on
+
+ default:
+ UNEXPECTED("Unexpected resource state flag");
+ return 0;
+ }
+}
+
+VkPipelineStageFlags ResourceStateFlagsToVkPipelineStageFlags(RESOURCE_STATE StateFlags, VkPipelineStageFlags vkShaderStages)
+{
+ VERIFY(Uint32{StateFlags} < (RESOURCE_STATE_MAX_BIT << 1), "Resource state flags are out of range");
+
+ VkPipelineStageFlags vkPipelineStages = 0;
+ while (StateFlags != RESOURCE_STATE_UNKNOWN)
+ {
+ auto StateBit = static_cast<RESOURCE_STATE>(1 << PlatformMisc::GetLSB(Uint32{StateFlags}));
+ vkPipelineStages |= ResourceStateFlagToVkPipelineStage(StateBit, vkShaderStages);
+ StateFlags &= ~StateBit;
+ }
+ return vkPipelineStages;
+}
+
+
static VkAccessFlags ResourceStateFlagToVkAccessFlags(RESOURCE_STATE StateFlag)
{
// Currently not used:
@@ -1151,10 +1216,8 @@ static VkAccessFlags ResourceStateFlagToVkAccessFlags(RESOURCE_STATE StateFlag)
//VK_ACCESS_COMMAND_PROCESS_WRITE_BIT_NVX
//VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT
//VK_ACCESS_SHADING_RATE_IMAGE_READ_BIT_NV
- //VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NVX
- //VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NVX
- static_assert(RESOURCE_STATE_MAX_BIT == 0x10000, "This function must be updated to handle new resource state flag");
+ static_assert(RESOURCE_STATE_MAX_BIT == RESOURCE_STATE_RAY_TRACING, "This function must be updated to handle new resource state flag");
VERIFY((StateFlag & (StateFlag - 1)) == 0, "Only single bit must be set");
switch (StateFlag)
{
@@ -1176,6 +1239,9 @@ static VkAccessFlags ResourceStateFlagToVkAccessFlags(RESOURCE_STATE StateFlag)
case RESOURCE_STATE_RESOLVE_SOURCE: return VK_ACCESS_TRANSFER_READ_BIT;
case RESOURCE_STATE_INPUT_ATTACHMENT: return VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
case RESOURCE_STATE_PRESENT: return 0;
+ case RESOURCE_STATE_BUILD_AS_READ: return VK_ACCESS_SHADER_READ_BIT; // for vertex, index, transform, AABB, instance buffers
+ case RESOURCE_STATE_BUILD_AS_WRITE: return VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR | VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR; // for scratch buffer
+ case RESOURCE_STATE_RAY_TRACING: return VK_ACCESS_SHADER_READ_BIT; // for SBT
// clang-format on
default:
@@ -1190,7 +1256,7 @@ public:
StateFlagBitPosToVkAccessFlags()
{
static_assert((1 << MaxFlagBitPos) == RESOURCE_STATE_MAX_BIT, "This function must be updated to handle new resource state flag");
- for (Uint32 bit = 0; bit < MaxFlagBitPos; ++bit)
+ for (Uint32 bit = 0; bit < FlagBitPosToVkAccessFlagsMap.size(); ++bit)
{
FlagBitPosToVkAccessFlagsMap[bit] = ResourceStateFlagToVkAccessFlags(static_cast<RESOURCE_STATE>(1 << bit));
}
@@ -1203,7 +1269,7 @@ public:
}
private:
- static constexpr const Uint32 MaxFlagBitPos = 16;
+ static constexpr const Uint32 MaxFlagBitPos = 19;
std::array<VkAccessFlags, MaxFlagBitPos + 1> FlagBitPosToVkAccessFlagsMap;
};
@@ -1224,7 +1290,31 @@ VkAccessFlags ResourceStateFlagsToVkAccessFlags(RESOURCE_STATE StateFlags)
return AccessFlags;
}
-RESOURCE_STATE VkAccessFlagsToResourceStates(VkAccessFlagBits AccessFlagBit)
+VkAccessFlags AccelStructStateFlagsToVkAccessFlags(RESOURCE_STATE StateFlags)
+{
+ VERIFY(Uint32{StateFlags} < (RESOURCE_STATE_MAX_BIT << 1), "Resource state flags are out of range");
+ static_assert(RESOURCE_STATE_MAX_BIT == RESOURCE_STATE_RAY_TRACING, "This function must be updated to handle new resource state flag");
+
+ VkAccessFlags AccessFlags = 0;
+ Uint32 Bits = StateFlags;
+ while (Bits != 0)
+ {
+ auto Bit = static_cast<RESOURCE_STATE>(1 << PlatformMisc::GetLSB(Bits));
+ switch (Bit)
+ {
+ // clang-format off
+ case RESOURCE_STATE_BUILD_AS_READ: AccessFlags |= VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR; break;
+ case RESOURCE_STATE_BUILD_AS_WRITE: AccessFlags |= VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR | VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR; break;
+ case RESOURCE_STATE_RAY_TRACING: AccessFlags |= VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR; break;
+ default: UNEXPECTED("Unexpected resource state flag");
+ // clang-format on
+ }
+ Bits &= ~Bit;
+ }
+ return AccessFlags;
+}
+
+static RESOURCE_STATE VkAccessFlagToResourceStates(VkAccessFlagBits AccessFlagBit)
{
VERIFY((AccessFlagBit & (AccessFlagBit - 1)) == 0, "Single access flag bit is expected");
@@ -1236,7 +1326,7 @@ RESOURCE_STATE VkAccessFlagsToResourceStates(VkAccessFlagBits AccessFlagBit)
case VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT: return RESOURCE_STATE_VERTEX_BUFFER;
case VK_ACCESS_UNIFORM_READ_BIT: return RESOURCE_STATE_CONSTANT_BUFFER;
case VK_ACCESS_INPUT_ATTACHMENT_READ_BIT: return RESOURCE_STATE_INPUT_ATTACHMENT;
- case VK_ACCESS_SHADER_READ_BIT: return RESOURCE_STATE_SHADER_RESOURCE;
+ case VK_ACCESS_SHADER_READ_BIT: return RESOURCE_STATE_SHADER_RESOURCE; // or RESOURCE_STATE_BUILD_AS_READ
case VK_ACCESS_SHADER_WRITE_BIT: return RESOURCE_STATE_UNORDERED_ACCESS;
case VK_ACCESS_COLOR_ATTACHMENT_READ_BIT: return RESOURCE_STATE_RENDER_TARGET;
case VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT: return RESOURCE_STATE_RENDER_TARGET;
@@ -1244,6 +1334,7 @@ RESOURCE_STATE VkAccessFlagsToResourceStates(VkAccessFlagBits AccessFlagBit)
case VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT: return RESOURCE_STATE_DEPTH_WRITE;
case VK_ACCESS_TRANSFER_READ_BIT: return RESOURCE_STATE_COPY_SOURCE;
case VK_ACCESS_TRANSFER_WRITE_BIT: return RESOURCE_STATE_COPY_DEST;
+ case VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR: return RESOURCE_STATE_BUILD_AS_WRITE;
case VK_ACCESS_HOST_READ_BIT: return RESOURCE_STATE_UNKNOWN;
case VK_ACCESS_HOST_WRITE_BIT: return RESOURCE_STATE_UNKNOWN;
case VK_ACCESS_MEMORY_READ_BIT: return RESOURCE_STATE_UNKNOWN;
@@ -1256,8 +1347,6 @@ RESOURCE_STATE VkAccessFlagsToResourceStates(VkAccessFlagBits AccessFlagBit)
case VK_ACCESS_COMMAND_PREPROCESS_WRITE_BIT_NV: return RESOURCE_STATE_UNKNOWN;
case VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT: return RESOURCE_STATE_UNKNOWN;
case VK_ACCESS_SHADING_RATE_IMAGE_READ_BIT_NV: return RESOURCE_STATE_UNKNOWN;
- case VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV: return RESOURCE_STATE_UNKNOWN;
- case VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV: return RESOURCE_STATE_UNKNOWN;
// clang-format on
default:
UNEXPECTED("Unknown access flag");
@@ -1271,9 +1360,9 @@ class VkAccessFlagBitPosToResourceState
public:
VkAccessFlagBitPosToResourceState()
{
- for (Uint32 bit = 0; bit < MaxFlagBitPos; ++bit)
+ for (Uint32 bit = 0; bit < FlagBitPosToResourceState.size(); ++bit)
{
- FlagBitPosToResourceState[bit] = VkAccessFlagsToResourceStates(static_cast<VkAccessFlagBits>(1 << bit));
+ FlagBitPosToResourceState[bit] = VkAccessFlagToResourceStates(static_cast<VkAccessFlagBits>(1 << bit));
}
}
@@ -1317,7 +1406,7 @@ VkImageLayout ResourceStateToVkImageLayout(RESOURCE_STATE StateFlag, bool IsInsi
//VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL,
//VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL,
- static_assert(RESOURCE_STATE_MAX_BIT == 0x10000, "This function must be updated to handle new resource state flag");
+ static_assert(RESOURCE_STATE_MAX_BIT == RESOURCE_STATE_RAY_TRACING, "This function must be updated to handle new resource state flag");
VERIFY((StateFlag & (StateFlag - 1)) == 0, "Only single bit must be set");
switch (StateFlag)
{
@@ -1339,6 +1428,9 @@ VkImageLayout ResourceStateToVkImageLayout(RESOURCE_STATE StateFlag, bool IsInsi
case RESOURCE_STATE_RESOLVE_SOURCE: return VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
case RESOURCE_STATE_INPUT_ATTACHMENT: return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
case RESOURCE_STATE_PRESENT: return VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
+ case RESOURCE_STATE_BUILD_AS_READ: UNEXPECTED("Invalid resource state"); return VK_IMAGE_LAYOUT_UNDEFINED;
+ case RESOURCE_STATE_BUILD_AS_WRITE: UNEXPECTED("Invalid resource state"); return VK_IMAGE_LAYOUT_UNDEFINED;
+ case RESOURCE_STATE_RAY_TRACING: UNEXPECTED("Invalid resource state"); return VK_IMAGE_LAYOUT_UNDEFINED;
// clang-format on
default:
@@ -1349,7 +1441,7 @@ VkImageLayout ResourceStateToVkImageLayout(RESOURCE_STATE StateFlag, bool IsInsi
RESOURCE_STATE VkImageLayoutToResourceState(VkImageLayout Layout)
{
- static_assert(RESOURCE_STATE_MAX_BIT == 0x10000, "This function must be updated to handle new resource state flag");
+ static_assert(RESOURCE_STATE_MAX_BIT == RESOURCE_STATE_RAY_TRACING, "This function must be updated to handle new resource state flag");
switch (Layout)
{
// clang-format off
@@ -1514,7 +1606,7 @@ VkAccessFlags AccessFlagsToVkAccessFlags(ACCESS_FLAGS AccessFlags)
VkShaderStageFlagBits ShaderTypeToVkShaderStageFlagBit(SHADER_TYPE ShaderType)
{
- static_assert(SHADER_TYPE_LAST == SHADER_TYPE_MESH, "Please update the switch below to handle the new shader type");
+ static_assert(SHADER_TYPE_LAST == SHADER_TYPE_CALLABLE, "Please update the switch below to handle the new shader type");
VERIFY(IsPowerOfTwo(Uint32{ShaderType}), "More than one shader type is specified");
switch (ShaderType)
{
@@ -1527,6 +1619,12 @@ VkShaderStageFlagBits ShaderTypeToVkShaderStageFlagBit(SHADER_TYPE ShaderType)
case SHADER_TYPE_COMPUTE: return VK_SHADER_STAGE_COMPUTE_BIT;
case SHADER_TYPE_AMPLIFICATION: return VK_SHADER_STAGE_TASK_BIT_NV;
case SHADER_TYPE_MESH: return VK_SHADER_STAGE_MESH_BIT_NV;
+ case SHADER_TYPE_RAY_GEN: return VK_SHADER_STAGE_RAYGEN_BIT_KHR;
+ case SHADER_TYPE_RAY_MISS: return VK_SHADER_STAGE_MISS_BIT_KHR;
+ case SHADER_TYPE_RAY_CLOSEST_HIT: return VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
+ case SHADER_TYPE_RAY_ANY_HIT: return VK_SHADER_STAGE_ANY_HIT_BIT_KHR;
+ case SHADER_TYPE_RAY_INTERSECTION: return VK_SHADER_STAGE_INTERSECTION_BIT_KHR;
+ case SHADER_TYPE_CALLABLE: return VK_SHADER_STAGE_CALLABLE_BIT_KHR;
// clang-format on
default:
UNEXPECTED("Unknown shader type");
@@ -1534,4 +1632,92 @@ VkShaderStageFlagBits ShaderTypeToVkShaderStageFlagBit(SHADER_TYPE ShaderType)
}
}
+VkBuildAccelerationStructureFlagsKHR BuildASFlagsToVkBuildAccelerationStructureFlags(RAYTRACING_BUILD_AS_FLAGS Flags)
+{
+ static_assert(RAYTRACING_BUILD_AS_FLAGS_LAST == RAYTRACING_BUILD_AS_LOW_MEMORY,
+ "Please update the switch below to handle the new ray tracing build flag");
+
+ VkBuildAccelerationStructureFlagsKHR Result = 0;
+ while (Flags != RAYTRACING_BUILD_AS_NONE)
+ {
+ auto FlagBit = static_cast<RAYTRACING_BUILD_AS_FLAGS>(1 << PlatformMisc::GetLSB(Uint32{Flags}));
+ switch (FlagBit)
+ {
+ // clang-format off
+ case RAYTRACING_BUILD_AS_ALLOW_UPDATE: Result |= VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR; break;
+ case RAYTRACING_BUILD_AS_ALLOW_COMPACTION: Result |= VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR; break;
+ case RAYTRACING_BUILD_AS_PREFER_FAST_TRACE: Result |= VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR; break;
+ case RAYTRACING_BUILD_AS_PREFER_FAST_BUILD: Result |= VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR; break;
+ case RAYTRACING_BUILD_AS_LOW_MEMORY: Result |= VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_KHR; break;
+ // clang-format on
+ default: UNEXPECTED("unknown build AS flag");
+ }
+ Flags = Flags & ~FlagBit;
+ }
+ return Result;
+}
+
+VkGeometryFlagsKHR GeometryFlagsToVkGeometryFlags(RAYTRACING_GEOMETRY_FLAGS Flags)
+{
+ static_assert(RAYTRACING_GEOMETRY_FLAGS_LAST == RAYTRACING_GEOMETRY_FLAG_NO_DUPLICATE_ANY_HIT_INVOCATION,
+ "Please update the switch below to handle the new ray tracing geometry flag");
+
+ VkGeometryFlagsKHR Result = 0;
+ while (Flags != RAYTRACING_GEOMETRY_FLAG_NONE)
+ {
+ auto FlagBit = static_cast<RAYTRACING_GEOMETRY_FLAGS>(1 << PlatformMisc::GetLSB(Uint32{Flags}));
+ switch (FlagBit)
+ {
+ // clang-format off
+ case RAYTRACING_GEOMETRY_FLAG_OPAQUE: Result |= VK_GEOMETRY_OPAQUE_BIT_KHR; break;
+ case RAYTRACING_GEOMETRY_FLAG_NO_DUPLICATE_ANY_HIT_INVOCATION: Result |= VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR; break;
+ // clang-format on
+ default: UNEXPECTED("unknown geometry flag");
+ }
+ Flags = Flags & ~FlagBit;
+ }
+ return Result;
+}
+
+VkGeometryInstanceFlagsKHR InstanceFlagsToVkGeometryInstanceFlags(RAYTRACING_INSTANCE_FLAGS Flags)
+{
+ static_assert(RAYTRACING_INSTANCE_FLAGS_LAST == RAYTRACING_INSTANCE_FORCE_NO_OPAQUE,
+ "Please update the switch below to handle the new ray tracing instance flag");
+
+ VkGeometryInstanceFlagsKHR Result = 0;
+ while (Flags != RAYTRACING_INSTANCE_NONE)
+ {
+ auto FlagBit = static_cast<RAYTRACING_INSTANCE_FLAGS>(1 << PlatformMisc::GetLSB(Uint32{Flags}));
+ switch (FlagBit)
+ {
+ // clang-format off
+ case RAYTRACING_INSTANCE_TRIANGLE_FACING_CULL_DISABLE: Result |= VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; break;
+ case RAYTRACING_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE: Result |= VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_KHR; break;
+ case RAYTRACING_INSTANCE_FORCE_OPAQUE: Result |= VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR; break;
+ case RAYTRACING_INSTANCE_FORCE_NO_OPAQUE: Result |= VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR; break;
+ // clang-format on
+ default: UNEXPECTED("unknown instance flag");
+ }
+ Flags = Flags & ~FlagBit;
+ }
+ return Result;
+}
+
+VkCopyAccelerationStructureModeKHR CopyASModeToVkCopyAccelerationStructureMode(COPY_AS_MODE Mode)
+{
+ static_assert(COPY_AS_MODE_LAST == COPY_AS_MODE_COMPACT,
+ "Please update the switch below to handle the new copy AS mode");
+
+ switch (Mode)
+ {
+ // clang-format off
+ case COPY_AS_MODE_CLONE: return VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_KHR;
+ case COPY_AS_MODE_COMPACT: return VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_KHR;
+ // clang-format on
+ default:
+ UNEXPECTED("unknown AS copy mode");
+ return VK_COPY_ACCELERATION_STRUCTURE_MODE_MAX_ENUM_KHR;
+ }
+}
+
} // namespace Diligent
diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUploadHeap.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUploadHeap.cpp
index 5a1894c0..ae460cde 100644
--- a/Graphics/GraphicsEngineVulkan/src/VulkanUploadHeap.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/VulkanUploadHeap.cpp
@@ -79,7 +79,7 @@ VulkanUploadHeap::UploadPageInfo VulkanUploadHeap::CreateNewPage(VkDeviceSize Si
"at least one bit set corresponding to a VkMemoryType with a propertyFlags that has both the "
"VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT bit AND the VK_MEMORY_PROPERTY_HOST_COHERENT_BIT bit set. (11.6)");
- auto MemAllocation = GlobalMemoryMgr.Allocate(MemReqs.size, MemReqs.alignment, MemoryTypeIndex, true);
+ auto MemAllocation = GlobalMemoryMgr.Allocate(MemReqs.size, MemReqs.alignment, MemoryTypeIndex, true, VkMemoryAllocateFlags{0});
auto AlignedOffset = (MemAllocation.UnalignedOffset + (MemReqs.alignment - 1)) & ~(MemReqs.alignment - 1);
auto err = LogicalDevice.BindBufferMemory(NewBuffer, MemAllocation.Page->GetVkMemory(), AlignedOffset);
diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBuffer.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBuffer.cpp
index 11444c33..1f81c872 100644
--- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBuffer.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBuffer.cpp
@@ -32,7 +32,7 @@ namespace VulkanUtilities
{
static VkPipelineStageFlags PipelineStageFromAccessFlags(VkAccessFlags AccessFlags,
- const VkPipelineStageFlags EnabledGraphicsShaderStages)
+ const VkPipelineStageFlags EnabledShaderStages)
{
// 6.1.3
VkPipelineStageFlags Stages = 0;
@@ -65,7 +65,7 @@ static VkPipelineStageFlags PipelineStageFromAccessFlags(VkAccessFlags
// Read access to a uniform buffer
case VK_ACCESS_UNIFORM_READ_BIT:
- Stages |= EnabledGraphicsShaderStages | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
+ Stages |= EnabledShaderStages;
break;
// Read access to an input attachment within a render pass during fragment shading
@@ -75,12 +75,12 @@ static VkPipelineStageFlags PipelineStageFromAccessFlags(VkAccessFlags
// Read access to a storage buffer, uniform texel buffer, storage texel buffer, sampled image, or storage image
case VK_ACCESS_SHADER_READ_BIT:
- Stages |= EnabledGraphicsShaderStages | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
+ Stages |= EnabledShaderStages;
break;
// Write access to a storage buffer, storage texel buffer, or storage image
case VK_ACCESS_SHADER_WRITE_BIT:
- Stages |= EnabledGraphicsShaderStages | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
+ Stages |= EnabledShaderStages;
break;
// Read access to a color attachment, such as via blending, logic operations, or via certain subpass load operations
@@ -134,6 +134,16 @@ static VkPipelineStageFlags PipelineStageFromAccessFlags(VkAccessFlags
case VK_ACCESS_MEMORY_WRITE_BIT:
break;
+ // Read access to acceleration structure or vertex/index/instance buffer in a build AS or trace rays operations.
+ case VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR:
+ Stages |= VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR;
+ break;
+
+ // Write access to acceleration structure or scratch buffer in a build AS operations.
+ case VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR:
+ Stages |= VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR;
+ break;
+
default:
UNEXPECTED("Unknown memory access flag");
}
@@ -223,8 +233,12 @@ static VkPipelineStageFlags AccessMaskFromImageLayout(VkImageLayout Layout,
AccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
break;
+ // When transitioning the image to VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR or VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
+ // there is no need to delay subsequent processing, or perform any visibility operations (as vkQueuePresentKHR
+ // performs automatic visibility operations). To achieve this, the dstAccessMask member of the VkImageMemoryBarrier
+ // should be set to 0, and the dstStageMask parameter should be set to VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT.
case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
- AccessMask = VK_ACCESS_MEMORY_READ_BIT;
+ AccessMask = 0;
break;
default:
@@ -240,7 +254,7 @@ void VulkanCommandBuffer::TransitionImageLayout(VkCommandBuffer C
VkImageLayout OldLayout,
VkImageLayout NewLayout,
const VkImageSubresourceRange& SubresRange,
- VkPipelineStageFlags EnabledGraphicsShaderStages,
+ VkPipelineStageFlags EnabledShaderStages,
VkPipelineStageFlags SrcStages,
VkPipelineStageFlags DestStages)
{
@@ -268,7 +282,7 @@ void VulkanCommandBuffer::TransitionImageLayout(VkCommandBuffer C
}
else if (ImgBarrier.srcAccessMask != 0)
{
- SrcStages = PipelineStageFromAccessFlags(ImgBarrier.srcAccessMask, EnabledGraphicsShaderStages);
+ SrcStages = PipelineStageFromAccessFlags(ImgBarrier.srcAccessMask, EnabledShaderStages);
}
else
{
@@ -282,11 +296,11 @@ void VulkanCommandBuffer::TransitionImageLayout(VkCommandBuffer C
{
if (NewLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR)
{
- DestStages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
+ DestStages = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
}
else if (ImgBarrier.dstAccessMask != 0)
{
- DestStages = PipelineStageFromAccessFlags(ImgBarrier.dstAccessMask, EnabledGraphicsShaderStages);
+ DestStages = PipelineStageFromAccessFlags(ImgBarrier.dstAccessMask, EnabledShaderStages);
}
else
{
@@ -327,7 +341,7 @@ void VulkanCommandBuffer::BufferMemoryBarrier(VkCommandBuffer CmdBuffer,
VkBuffer Buffer,
VkAccessFlags srcAccessMask,
VkAccessFlags dstAccessMask,
- VkPipelineStageFlags EnabledGraphicsShaderStages,
+ VkPipelineStageFlags EnabledShaderStages,
VkPipelineStageFlags SrcStages,
VkPipelineStageFlags DestStages)
{
@@ -344,7 +358,7 @@ void VulkanCommandBuffer::BufferMemoryBarrier(VkCommandBuffer CmdBuffer,
if (SrcStages == 0)
{
if (BuffBarrier.srcAccessMask != 0)
- SrcStages = PipelineStageFromAccessFlags(BuffBarrier.srcAccessMask, EnabledGraphicsShaderStages);
+ SrcStages = PipelineStageFromAccessFlags(BuffBarrier.srcAccessMask, EnabledShaderStages);
else
{
// An execution dependency with only VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT in the source stage
@@ -356,7 +370,7 @@ void VulkanCommandBuffer::BufferMemoryBarrier(VkCommandBuffer CmdBuffer,
if (DestStages == 0)
{
VERIFY(BuffBarrier.dstAccessMask != 0, "Dst access mask must not be zero");
- DestStages = PipelineStageFromAccessFlags(BuffBarrier.dstAccessMask, EnabledGraphicsShaderStages);
+ DestStages = PipelineStageFromAccessFlags(BuffBarrier.dstAccessMask, EnabledShaderStages);
}
vkCmdPipelineBarrier(CmdBuffer,
@@ -371,6 +385,55 @@ void VulkanCommandBuffer::BufferMemoryBarrier(VkCommandBuffer CmdBuffer,
nullptr);
}
+void VulkanCommandBuffer::ASMemoryBarrier(VkCommandBuffer CmdBuffer,
+ VkAccessFlags srcAccessMask,
+ VkAccessFlags dstAccessMask,
+ VkPipelineStageFlags EnabledShaderStages,
+ VkPipelineStageFlags SrcStages,
+ VkPipelineStageFlags DestStages)
+{
+ VkMemoryBarrier Barrier = {};
+ Barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
+ Barrier.pNext = nullptr;
+ Barrier.srcAccessMask = srcAccessMask;
+ Barrier.dstAccessMask = dstAccessMask;
+
+ if (SrcStages == 0)
+ {
+ if (Barrier.srcAccessMask != 0)
+ SrcStages = PipelineStageFromAccessFlags(Barrier.srcAccessMask, EnabledShaderStages);
+ else
+ {
+ // An execution dependency with only VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT in the source stage
+ // mask will effectively not wait for any prior commands to complete. (6.1.2)
+ SrcStages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
+ }
+ }
+
+ if (DestStages == 0)
+ {
+ VERIFY(Barrier.dstAccessMask != 0, "Dst access mask must not be zero");
+ DestStages = PipelineStageFromAccessFlags(Barrier.dstAccessMask, EnabledShaderStages);
+ }
+
+ // Other stages are not valid for acceleration structures
+ constexpr VkPipelineStageFlags StagesMask = VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR | VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
+
+ SrcStages &= StagesMask;
+ DestStages &= StagesMask;
+
+ vkCmdPipelineBarrier(CmdBuffer,
+ SrcStages, // must not be 0
+ DestStages, // must not be 0
+ 0, // a bitmask specifying how execution and memory dependencies are formed
+ 1, // memoryBarrierCount
+ &Barrier, // pMemoryBarriers
+ 0,
+ nullptr,
+ 0,
+ nullptr);
+}
+
void VulkanCommandBuffer::FlushBarriers()
{
}
diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanDebug.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanDebug.cpp
index 4feb8692..c1c20d79 100644
--- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanDebug.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanDebug.cpp
@@ -400,6 +400,11 @@ void SetQueryPoolName(VkDevice device, VkQueryPool queryPool, const char* name)
SetObjectName(device, (uint64_t)queryPool, VK_OBJECT_TYPE_QUERY_POOL, name);
}
+void SetAccelStructName(VkDevice device, VkAccelerationStructureKHR accelStruct, const char* name)
+{
+ SetObjectName(device, (uint64_t)accelStruct, VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR, name);
+}
+
template <>
void SetVulkanObjectName<VkCommandPool, VulkanHandleTypeId::CommandPool>(VkDevice device, VkCommandPool cmdPool, const char* name)
@@ -527,6 +532,11 @@ void SetVulkanObjectName<VkQueryPool, VulkanHandleTypeId::QueryPool>(VkDevice de
SetQueryPoolName(device, queryPool, name);
}
+template <>
+void SetVulkanObjectName<VkAccelerationStructureKHR, VulkanHandleTypeId::AccelerationStructureKHR>(VkDevice device, VkAccelerationStructureKHR accelStruct, const char* name)
+{
+ SetAccelStructName(device, accelStruct, name);
+}
const char* VkResultToString(VkResult errorCode)
@@ -558,6 +568,20 @@ const char* VkResultToString(VkResult errorCode)
STR(ERROR_INCOMPATIBLE_DISPLAY_KHR);
STR(ERROR_VALIDATION_FAILED_EXT);
STR(ERROR_INVALID_SHADER_NV);
+ STR(ERROR_FRAGMENTED_POOL);
+ STR(ERROR_UNKNOWN);
+ STR(ERROR_OUT_OF_POOL_MEMORY);
+ STR(ERROR_INVALID_EXTERNAL_HANDLE);
+ STR(ERROR_FRAGMENTATION);
+ STR(ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS);
+ STR(ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT);
+ STR(ERROR_NOT_PERMITTED_EXT);
+ STR(ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT);
+ STR(THREAD_IDLE_KHR);
+ STR(THREAD_DONE_KHR);
+ STR(OPERATION_DEFERRED_KHR);
+ STR(OPERATION_NOT_DEFERRED_KHR);
+ STR(PIPELINE_COMPILE_REQUIRED_EXT);
#undef STR
// clang-format on
default:
@@ -589,6 +613,8 @@ const char* VkAccessFlagBitToString(VkAccessFlagBits Bit)
ACCESS_FLAG_BIT_TO_STRING(VK_ACCESS_HOST_WRITE_BIT)
ACCESS_FLAG_BIT_TO_STRING(VK_ACCESS_MEMORY_READ_BIT)
ACCESS_FLAG_BIT_TO_STRING(VK_ACCESS_MEMORY_WRITE_BIT)
+ ACCESS_FLAG_BIT_TO_STRING(VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR)
+ ACCESS_FLAG_BIT_TO_STRING(VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR)
#undef ACCESS_FLAG_BIT_TO_STRING
default: UNEXPECTED("Unexpected bit"); return "";
// clang-format on
diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanInstance.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanInstance.cpp
index a03102d0..a88a5888 100644
--- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanInstance.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanInstance.cpp
@@ -46,12 +46,16 @@
namespace VulkanUtilities
{
-bool VulkanInstance::IsLayerAvailable(const char* LayerName) const
+bool VulkanInstance::IsLayerAvailable(const char* LayerName, uint32_t& Version) const
{
for (const auto& Layer : m_Layers)
+ {
if (strcmp(Layer.layerName, LayerName) == 0)
+ {
+ Version = Layer.specVersion;
return true;
-
+ }
+ }
return false;
}
@@ -73,16 +77,18 @@ bool VulkanInstance::IsExtensionEnabled(const char* ExtensionName) const
return false;
}
-std::shared_ptr<VulkanInstance> VulkanInstance::Create(bool EnableValidation,
+std::shared_ptr<VulkanInstance> VulkanInstance::Create(uint32_t ApiVersion,
+ bool EnableValidation,
uint32_t GlobalExtensionCount,
const char* const* ppGlobalExtensionNames,
VkAllocationCallbacks* pVkAllocator)
{
- auto Instance = new VulkanInstance{EnableValidation, GlobalExtensionCount, ppGlobalExtensionNames, pVkAllocator};
+ auto Instance = new VulkanInstance{ApiVersion, EnableValidation, GlobalExtensionCount, ppGlobalExtensionNames, pVkAllocator};
return std::shared_ptr<VulkanInstance>{Instance};
}
-VulkanInstance::VulkanInstance(bool EnableValidation,
+VulkanInstance::VulkanInstance(uint32_t ApiVersion,
+ bool EnableValidation,
uint32_t GlobalExtensionCount,
const char* const* ppGlobalExtensionNames,
VkAllocationCallbacks* pVkAllocator) :
@@ -184,6 +190,16 @@ VulkanInstance::VulkanInstance(bool EnableValidation,
}
}
+#if DILIGENT_USE_VOLK
+ if (vkEnumerateInstanceVersion != nullptr && ApiVersion > VK_API_VERSION_1_0)
+ {
+ uint32_t MaxApiVersion = 0;
+ vkEnumerateInstanceVersion(&MaxApiVersion);
+ ApiVersion = std::min(ApiVersion, MaxApiVersion);
+ LOG_INFO_MESSAGE("Using Vulkan API version ", VK_VERSION_MAJOR(ApiVersion), ".", VK_VERSION_MINOR(ApiVersion));
+ }
+#endif
+
VkApplicationInfo appInfo = {};
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
@@ -192,7 +208,7 @@ VulkanInstance::VulkanInstance(bool EnableValidation,
appInfo.applicationVersion = 0; // Developer-supplied version number of the application
appInfo.pEngineName = "Diligent Engine";
appInfo.engineVersion = 0; // Developer-supplied version number of the engine used to create the application.
- appInfo.apiVersion = VK_API_VERSION_1_0;
+ appInfo.apiVersion = ApiVersion;
VkInstanceCreateInfo InstanceCreateInfo = {};
@@ -208,11 +224,20 @@ VulkanInstance::VulkanInstance(bool EnableValidation,
bool ValidationLayersPresent = true;
for (size_t l = 0; l < _countof(VulkanUtilities::ValidationLayerNames); ++l)
{
- auto* pLayerName = VulkanUtilities::ValidationLayerNames[l];
- if (!IsLayerAvailable(pLayerName))
+ auto* pLayerName = VulkanUtilities::ValidationLayerNames[l];
+ uint32_t LayerVer = 0;
+ if (!IsLayerAvailable(pLayerName, LayerVer))
+ {
+ ValidationLayersPresent = false;
+ LOG_WARNING_MESSAGE("Failed to find '", pLayerName, "' layer. Validation will be disabled");
+ }
+ if (LayerVer < VK_HEADER_VERSION_COMPLETE)
{
ValidationLayersPresent = false;
- LOG_WARNING_MESSAGE("Failed to find ", pLayerName, " layer. Validation will be disabled");
+ LOG_WARNING_MESSAGE("Layer '", pLayerName, "' version (", VK_VERSION_MAJOR(LayerVer), ".", VK_VERSION_MINOR(LayerVer), ".", VK_VERSION_PATCH(LayerVer),
+ ") is less than header version (",
+ VK_VERSION_MAJOR(VK_HEADER_VERSION_COMPLETE), ".", VK_VERSION_MINOR(VK_HEADER_VERSION_COMPLETE), ".", VK_VERSION_PATCH(VK_HEADER_VERSION_COMPLETE),
+ "). Validation will be disabled");
}
}
if (ValidationLayersPresent)
@@ -229,6 +254,7 @@ VulkanInstance::VulkanInstance(bool EnableValidation,
#endif
m_EnabledExtensions = std::move(GlobalExtensions);
+ m_VkVersion = ApiVersion;
// If requested, we enable the default validation layers for debugging
if (m_DebugUtilsEnabled)
diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanLogicalDevice.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanLogicalDevice.cpp
index 5b720fd7..0d1534b8 100644
--- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanLogicalDevice.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanLogicalDevice.cpp
@@ -34,11 +34,12 @@
namespace VulkanUtilities
{
-std::shared_ptr<VulkanLogicalDevice> VulkanLogicalDevice::Create(VkPhysicalDevice vkPhysicalDevice,
+std::shared_ptr<VulkanLogicalDevice> VulkanLogicalDevice::Create(const VulkanPhysicalDevice& PhysicalDevice,
const VkDeviceCreateInfo& DeviceCI,
+ const ExtensionFeatures& EnabledExtFeatures,
const VkAllocationCallbacks* vkAllocator)
{
- auto* LogicalDevice = new VulkanLogicalDevice{vkPhysicalDevice, DeviceCI, vkAllocator};
+ auto* LogicalDevice = new VulkanLogicalDevice{PhysicalDevice, DeviceCI, EnabledExtFeatures, vkAllocator};
return std::shared_ptr<VulkanLogicalDevice>{LogicalDevice};
}
@@ -47,13 +48,15 @@ VulkanLogicalDevice::~VulkanLogicalDevice()
vkDestroyDevice(m_VkDevice, m_VkAllocator);
}
-VulkanLogicalDevice::VulkanLogicalDevice(VkPhysicalDevice vkPhysicalDevice,
+VulkanLogicalDevice::VulkanLogicalDevice(const VulkanPhysicalDevice& PhysicalDevice,
const VkDeviceCreateInfo& DeviceCI,
+ const ExtensionFeatures& EnabledExtFeatures,
const VkAllocationCallbacks* vkAllocator) :
m_VkAllocator{vkAllocator},
- m_EnabledFeatures{*DeviceCI.pEnabledFeatures}
+ m_EnabledFeatures{*DeviceCI.pEnabledFeatures},
+ m_EnabledExtFeatures{EnabledExtFeatures}
{
- auto res = vkCreateDevice(vkPhysicalDevice, &DeviceCI, vkAllocator, &m_VkDevice);
+ auto res = vkCreateDevice(PhysicalDevice.GetVkDeviceHandle(), &DeviceCI, vkAllocator, &m_VkDevice);
CHECK_VK_ERROR_AND_THROW(res, "Failed to create logical device");
#if DILIGENT_USE_VOLK
@@ -62,11 +65,15 @@ VulkanLogicalDevice::VulkanLogicalDevice(VkPhysicalDevice vkPhysical
volkLoadDevice(m_VkDevice);
#endif
- m_EnabledGraphicsShaderStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
+ m_EnabledShaderStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
if (DeviceCI.pEnabledFeatures->geometryShader)
- m_EnabledGraphicsShaderStages |= VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
+ m_EnabledShaderStages |= VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
if (DeviceCI.pEnabledFeatures->tessellationShader)
- m_EnabledGraphicsShaderStages |= VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT | VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;
+ m_EnabledShaderStages |= VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT | VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;
+ if (m_EnabledExtFeatures.MeshShader.meshShader != VK_FALSE && m_EnabledExtFeatures.MeshShader.taskShader != VK_FALSE)
+ m_EnabledShaderStages |= VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV | VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV;
+ if (m_EnabledExtFeatures.RayTracingPipeline.rayTracingPipeline != VK_FALSE)
+ m_EnabledShaderStages |= VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR;
}
VkQueue VulkanLogicalDevice::GetQueue(uint32_t queueFamilyIndex, uint32_t queueIndex)
@@ -222,6 +229,29 @@ PipelineWrapper VulkanLogicalDevice::CreateGraphicsPipeline(const VkGraphicsPipe
return PipelineWrapper{GetSharedPtr(), std::move(vkPipeline)};
}
+PipelineWrapper VulkanLogicalDevice::CreateRayTracingPipeline(const VkRayTracingPipelineCreateInfoKHR& PipelineCI, VkPipelineCache cache, const char* DebugName) const
+{
+#if DILIGENT_USE_VOLK
+ VERIFY_EXPR(PipelineCI.sType == VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR);
+
+ if (DebugName == nullptr)
+ DebugName = "";
+
+ VkPipeline vkPipeline = VK_NULL_HANDLE;
+
+ auto err = vkCreateRayTracingPipelinesKHR(m_VkDevice, VK_NULL_HANDLE, cache, 1, &PipelineCI, m_VkAllocator, &vkPipeline);
+ CHECK_VK_ERROR_AND_THROW(err, "Failed to create ray tracing pipeline '", DebugName, '\'');
+
+ if (*DebugName != 0)
+ SetPipelineName(m_VkDevice, vkPipeline, DebugName);
+
+ return PipelineWrapper{GetSharedPtr(), std::move(vkPipeline)};
+#else
+ UNSUPPORTED("vkCreateRayTracingPipelinesKHR is only available through Volk");
+ return PipelineWrapper{};
+#endif
+}
+
ShaderModuleWrapper VulkanLogicalDevice::CreateShaderModule(const VkShaderModuleCreateInfo& ShaderModuleCI, const char* DebugName) const
{
VERIFY_EXPR(ShaderModuleCI.sType == VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO);
@@ -264,6 +294,17 @@ QueryPoolWrapper VulkanLogicalDevice::CreateQueryPool(const VkQueryPoolCreateInf
return CreateVulkanObject<VkQueryPool, VulkanHandleTypeId::QueryPool>(vkCreateQueryPool, QueryPoolCI, DebugName, "query pool");
}
+AccelStructWrapper VulkanLogicalDevice::CreateAccelStruct(const VkAccelerationStructureCreateInfoKHR& CI, const char* DebugName) const
+{
+#if DILIGENT_USE_VOLK
+ VERIFY_EXPR(CI.sType == VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR);
+ return CreateVulkanObject<VkAccelerationStructureKHR, VulkanHandleTypeId::AccelerationStructureKHR>(vkCreateAccelerationStructureKHR, CI, DebugName, "acceleration structure");
+#else
+ UNSUPPORTED("vkCreateAccelerationStructureKHR is only available through Volk");
+ return AccelStructWrapper{};
+#endif
+}
+
VkCommandBuffer VulkanLogicalDevice::AllocateVkCommandBuffer(const VkCommandBufferAllocateInfo& AllocInfo, const char* DebugName) const
{
VERIFY_EXPR(AllocInfo.sType == VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO);
@@ -405,6 +446,16 @@ void VulkanLogicalDevice::ReleaseVulkanObject(QueryPoolWrapper&& QueryPool) cons
QueryPool.m_VkObject = VK_NULL_HANDLE;
}
+void VulkanLogicalDevice::ReleaseVulkanObject(AccelStructWrapper&& AccelStruct) const
+{
+#if DILIGENT_USE_VOLK
+ vkDestroyAccelerationStructureKHR(m_VkDevice, AccelStruct.m_VkObject, m_VkAllocator);
+ AccelStruct.m_VkObject = VK_NULL_HANDLE;
+#else
+ UNSUPPORTED("vkDestroyAccelerationStructureKHR is only available through Volk");
+#endif
+}
+
void VulkanLogicalDevice::FreeDescriptorSet(VkDescriptorPool Pool, VkDescriptorSet Set) const
{
VERIFY_EXPR(Pool != VK_NULL_HANDLE && Set != VK_NULL_HANDLE);
@@ -438,6 +489,31 @@ VkResult VulkanLogicalDevice::BindImageMemory(VkImage image, VkDeviceMemory memo
return vkBindImageMemory(m_VkDevice, image, memory, memoryOffset);
}
+VkDeviceAddress VulkanLogicalDevice::GetAccelerationStructureDeviceAddress(VkAccelerationStructureKHR AS) const
+{
+#if DILIGENT_USE_VOLK
+ VkAccelerationStructureDeviceAddressInfoKHR Info = {};
+
+ Info.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR;
+ Info.accelerationStructure = AS;
+
+ return vkGetAccelerationStructureDeviceAddressKHR(m_VkDevice, &Info);
+#else
+ UNSUPPORTED("vkGetAccelerationStructureDeviceAddressKHR is only available through Volk");
+ return VK_ERROR_FEATURE_NOT_PRESENT;
+#endif
+}
+
+void VulkanLogicalDevice::GetAccelerationStructureBuildSizes(const VkAccelerationStructureBuildGeometryInfoKHR& BuildInfo, const uint32_t* pMaxPrimitiveCounts, VkAccelerationStructureBuildSizesInfoKHR& SizeInfo) const
+{
+#if DILIGENT_USE_VOLK
+ vkGetAccelerationStructureBuildSizesKHR(m_VkDevice, VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, &BuildInfo, pMaxPrimitiveCounts, &SizeInfo);
+#else
+ UNSUPPORTED("vkGetAccelerationStructureDeviceAddressKHR is only available through Volk");
+ return VK_ERROR_FEATURE_NOT_PRESENT;
+#endif
+}
+
VkResult VulkanLogicalDevice::MapMemory(VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void** ppData) const
{
return vkMapMemory(m_VkDevice, memory, offset, size, flags, ppData);
@@ -502,4 +578,14 @@ VkResult VulkanLogicalDevice::ResetDescriptorPool(VkDescriptorPool vkD
return err;
}
+VkResult VulkanLogicalDevice::GetRayTracingShaderGroupHandles(VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void* pData) const
+{
+#if DILIGENT_USE_VOLK
+ return vkGetRayTracingShaderGroupHandlesKHR(m_VkDevice, pipeline, firstGroup, groupCount, dataSize, pData);
+#else
+ UNSUPPORTED("vkGetRayTracingShaderGroupHandlesKHR is only available through Volk");
+ return VK_ERROR_FEATURE_NOT_PRESENT;
+#endif
+}
+
} // namespace VulkanUtilities
diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanMemoryManager.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanMemoryManager.cpp
index f9cdcdea..2e2cdd31 100644
--- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanMemoryManager.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanMemoryManager.cpp
@@ -40,10 +40,11 @@ VulkanMemoryAllocation::~VulkanMemoryAllocation()
}
}
-VulkanMemoryPage::VulkanMemoryPage(VulkanMemoryManager& ParentMemoryMgr,
- VkDeviceSize PageSize,
- uint32_t MemoryTypeIndex,
- bool IsHostVisible) noexcept :
+VulkanMemoryPage::VulkanMemoryPage(VulkanMemoryManager& ParentMemoryMgr,
+ VkDeviceSize PageSize,
+ uint32_t MemoryTypeIndex,
+ bool IsHostVisible,
+ VkMemoryAllocateFlags AllocateFlags) noexcept :
// clang-format off
m_ParentMemoryMgr{ParentMemoryMgr},
m_AllocationMgr {static_cast<AllocationsMgrOffsetType>(PageSize), ParentMemoryMgr.m_Allocator}
@@ -53,13 +54,22 @@ VulkanMemoryPage::VulkanMemoryPage(VulkanMemoryManager& ParentMemoryMgr,
"PageSize (", PageSize, ") exceeds maximum allowed value ",
std::numeric_limits<AllocationsMgrOffsetType>::max());
- VkMemoryAllocateInfo MemAlloc = {};
+ VkMemoryAllocateInfo MemAlloc = {};
+ VkMemoryAllocateFlagsInfo MemFlagInfo = {};
MemAlloc.pNext = nullptr;
MemAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
MemAlloc.allocationSize = PageSize;
MemAlloc.memoryTypeIndex = MemoryTypeIndex;
+ if (AllocateFlags)
+ {
+ MemAlloc.pNext = &MemFlagInfo;
+ MemFlagInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO;
+ MemFlagInfo.pNext = nullptr;
+ MemFlagInfo.flags = AllocateFlags;
+ }
+
auto MemoryName = Diligent::FormatString("Device memory page. Size: ", Diligent::FormatMemorySize(PageSize, 2), ", type: ", MemoryTypeIndex);
m_VkMemory = ParentMemoryMgr.m_LogicalDevice.AllocateDeviceMemory(MemAlloc, MemoryName.c_str());
@@ -116,7 +126,7 @@ void VulkanMemoryPage::Free(VulkanMemoryAllocation&& Allocation)
Allocation = VulkanMemoryAllocation{};
}
-VulkanMemoryAllocation VulkanMemoryManager::Allocate(const VkMemoryRequirements& MemReqs, VkMemoryPropertyFlags MemoryProps)
+VulkanMemoryAllocation VulkanMemoryManager::Allocate(const VkMemoryRequirements& MemReqs, VkMemoryPropertyFlags MemoryProps, VkMemoryAllocateFlags AllocateFlags)
{
// memoryTypeBits is a bitmask and contains one bit set for every supported memory type for the resource.
// Bit i is set if and only if the memory type i in the VkPhysicalDeviceMemoryProperties structure for the
@@ -145,10 +155,10 @@ VulkanMemoryAllocation VulkanMemoryManager::Allocate(const VkMemoryRequirements&
}
bool HostVisible = (MemoryProps & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0;
- return Allocate(MemReqs.size, MemReqs.alignment, MemoryTypeIndex, HostVisible);
+ return Allocate(MemReqs.size, MemReqs.alignment, MemoryTypeIndex, HostVisible, AllocateFlags);
}
-VulkanMemoryAllocation VulkanMemoryManager::Allocate(VkDeviceSize Size, VkDeviceSize Alignment, uint32_t MemoryTypeIndex, bool HostVisible)
+VulkanMemoryAllocation VulkanMemoryManager::Allocate(VkDeviceSize Size, VkDeviceSize Alignment, uint32_t MemoryTypeIndex, bool HostVisible, VkMemoryAllocateFlags AllocateFlags)
{
VulkanMemoryAllocation Allocation;
@@ -159,7 +169,7 @@ VulkanMemoryAllocation VulkanMemoryManager::Allocate(VkDeviceSize Size, VkDevice
// even though on integrated GPUs same pages can be used for both GPU-only and staging
// allocations. Staging allocations are short-living and will be released when upload is
// complete, while GPU-only allocations are expected to be long-living.
- MemoryPageIndex PageIdx{MemoryTypeIndex, HostVisible};
+ MemoryPageIndex PageIdx{MemoryTypeIndex, HostVisible, AllocateFlags};
std::lock_guard<std::mutex> Lock{m_PagesMtx};
auto range = m_Pages.equal_range(PageIdx);
@@ -180,7 +190,7 @@ VulkanMemoryAllocation VulkanMemoryManager::Allocate(VkDeviceSize Size, VkDevice
m_CurrAllocatedSize[stat_ind] += PageSize;
m_PeakAllocatedSize[stat_ind] = std::max(m_PeakAllocatedSize[stat_ind], m_CurrAllocatedSize[stat_ind]);
- auto it = m_Pages.emplace(PageIdx, VulkanMemoryPage{*this, PageSize, MemoryTypeIndex, HostVisible});
+ auto it = m_Pages.emplace(PageIdx, VulkanMemoryPage{*this, PageSize, MemoryTypeIndex, HostVisible, AllocateFlags});
LOG_INFO_MESSAGE("VulkanMemoryManager '", m_MgrName, "': created new ", (HostVisible ? "host-visible" : "device-local"),
" page. (", Diligent::FormatMemorySize(PageSize, 2), ", type idx: ", MemoryTypeIndex,
"). Current allocated size: ", Diligent::FormatMemorySize(m_CurrAllocatedSize[stat_ind], 2));
diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp
index 92a5e4d4..61f9f8de 100644
--- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp
@@ -68,12 +68,13 @@ VulkanPhysicalDevice::VulkanPhysicalDevice(VkPhysicalDevice vkDevice,
VERIFY_EXPR(ExtensionCount == m_SupportedExtensions.size());
}
-#ifdef VK_KHR_get_physical_device_properties2
+#if DILIGENT_USE_VOLK
if (Instance.IsExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME))
{
VkPhysicalDeviceFeatures2 Feats2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2};
VkPhysicalDeviceProperties2 Props2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2};
void** NextFeat = &Feats2.pNext;
+ void** NextProp = &Props2.pNext;
if (IsExtensionSupported(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME))
{
@@ -103,23 +104,92 @@ VulkanPhysicalDevice::VulkanPhysicalDevice(VkPhysicalDevice vkDevice,
}
}
- // Enable mesh shader extension.
+ // Get mesh shader features and properties.
if (IsExtensionSupported(VK_NV_MESH_SHADER_EXTENSION_NAME))
{
*NextFeat = &m_ExtFeatures.MeshShader;
NextFeat = &m_ExtFeatures.MeshShader.pNext;
m_ExtFeatures.MeshShader.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_NV;
+
+ *NextProp = &m_ExtProperties.MeshShader;
+ NextProp = &m_ExtProperties.MeshShader.pNext;
+
+ m_ExtProperties.MeshShader.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_NV;
+ }
+
+ // Get acceleration structure features and properties.
+ if (IsExtensionSupported(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME))
+ {
+ *NextFeat = &m_ExtFeatures.AccelStruct;
+ NextFeat = &m_ExtFeatures.AccelStruct.pNext;
+
+ m_ExtFeatures.AccelStruct.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR;
+
+ *NextProp = &m_ExtProperties.AccelStruct;
+ NextProp = &m_ExtProperties.AccelStruct.pNext;
+
+ m_ExtProperties.AccelStruct.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR;
}
+ // Get ray tracing pipeline features and properties.
+ if (IsExtensionSupported(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME))
+ {
+ *NextFeat = &m_ExtFeatures.RayTracingPipeline;
+ NextFeat = &m_ExtFeatures.RayTracingPipeline.pNext;
+
+ m_ExtFeatures.RayTracingPipeline.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR;
+
+ *NextProp = &m_ExtProperties.RayTracingPipeline;
+ NextProp = &m_ExtProperties.RayTracingPipeline.pNext;
+
+ m_ExtProperties.RayTracingPipeline.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR;
+ }
+
+ // Additional extension that is required for ray tracing.
+ if (IsExtensionSupported(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME))
+ {
+ *NextFeat = &m_ExtFeatures.BufferDeviceAddress;
+ NextFeat = &m_ExtFeatures.BufferDeviceAddress.pNext;
+
+ m_ExtFeatures.BufferDeviceAddress.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR;
+ }
+
+ // Additional extension that is required for ray tracing.
+ if (IsExtensionSupported(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME))
+ {
+ *NextFeat = &m_ExtFeatures.DescriptorIndexing;
+ NextFeat = &m_ExtFeatures.DescriptorIndexing.pNext;
+
+ m_ExtFeatures.DescriptorIndexing.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT;
+
+ *NextProp = &m_ExtProperties.DescriptorIndexing;
+ NextProp = &m_ExtProperties.DescriptorIndexing.pNext;
+
+ m_ExtProperties.DescriptorIndexing.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES_EXT;
+ }
+
+ // Additional extension that is required for ray tracing shader.
+ if (IsExtensionSupported(VK_KHR_SPIRV_1_4_EXTENSION_NAME))
+ m_ExtFeatures.Spirv14 = true;
+
+ // Some features requires SPIRV 1.4 or 1.5 that added to Vulkan 1.2 core.
+ if (Instance.GetVkVersion() >= VK_API_VERSION_1_2)
+ {
+ m_ExtFeatures.Spirv14 = true;
+ m_ExtFeatures.Spirv15 = true;
+ }
+
+ // make sure that last pNext is null
*NextFeat = nullptr;
+ *NextProp = nullptr;
// Initialize device extension features by current physical device features.
// Some flags may not be supported by hardware.
vkGetPhysicalDeviceFeatures2KHR(m_VkDevice, &Feats2);
vkGetPhysicalDeviceProperties2KHR(m_VkDevice, &Props2);
}
-#endif
+#endif // DILIGENT_USE_VOLK
}
uint32_t VulkanPhysicalDevice::FindQueueFamily(VkQueueFlags QueueFlags) const