From 3efd89673b48bedffcf36b6b8c66d587512854a1 Mon Sep 17 00:00:00 2001 From: azhirnov Date: Mon, 15 Mar 2021 03:14:26 +0300 Subject: Added inline ray tracing & trace rays indirect command. --- .../include/DeviceContextVkImpl.hpp | 5 +- .../VulkanUtilities/VulkanCommandBuffer.hpp | 16 ++++++ .../VulkanUtilities/VulkanPhysicalDevice.hpp | 1 + .../src/DeviceContextVkImpl.cpp | 64 ++++++++++++++++++++-- .../GraphicsEngineVulkan/src/EngineFactoryVk.cpp | 42 +++++++++++--- .../src/RenderDeviceVkImpl.cpp | 2 +- .../src/VulkanUtilities/VulkanPhysicalDevice.cpp | 9 +++ 7 files changed, 123 insertions(+), 16 deletions(-) (limited to 'Graphics/GraphicsEngineVulkan') diff --git a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp index ed2adf11..ee207091 100644 --- a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.hpp @@ -269,6 +269,9 @@ public: /// Implementation of IDeviceContext::TraceRays() in Vulkan backend. virtual void DILIGENT_CALL_TYPE TraceRays(const TraceRaysAttribs& Attribs) override final; + /// Implementation of IDeviceContext::TraceRaysIndirect() in Vulkan backend. + virtual void DILIGENT_CALL_TYPE TraceRaysIndirect(const TraceRaysIndirectAttribs& Attribs, IBuffer* pAttribsBuffer) 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. @@ -451,7 +454,7 @@ private: __forceinline void PrepareForDraw(DRAW_FLAGS Flags); __forceinline void PrepareForIndexedDraw(DRAW_FLAGS Flags, VALUE_TYPE IndexType); - __forceinline BufferVkImpl* PrepareIndirectDrawAttribsBuffer(IBuffer* pAttribsBuffer, RESOURCE_STATE_TRANSITION_MODE TransitonMode); + __forceinline BufferVkImpl* PrepareIndirectAttribsBuffer(IBuffer* pAttribsBuffer, RESOURCE_STATE_TRANSITION_MODE TransitonMode, const char* OpName); __forceinline void PrepareForDispatchCompute(); __forceinline void PrepareForRayTracing(); diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.hpp b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.hpp index 7f15e642..49a37dc2 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.hpp +++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.hpp @@ -670,6 +670,22 @@ public: #endif } + __forceinline void TraceRaysIndirect(const VkStridedDeviceAddressRegionKHR& RaygenShaderBindingTable, + const VkStridedDeviceAddressRegionKHR& MissShaderBindingTable, + const VkStridedDeviceAddressRegionKHR& HitShaderBindingTable, + const VkStridedDeviceAddressRegionKHR& CallableShaderBindingTable, + VkDeviceAddress indirectDeviceAddress) + { +#if DILIGENT_USE_VOLK + VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE); + VERIFY(m_State.RayTracingPipeline != VK_NULL_HANDLE, "No ray tracing pipeline bound"); + + vkCmdTraceRaysIndirectKHR(m_VkCmdBuffer, &RaygenShaderBindingTable, &MissShaderBindingTable, &HitShaderBindingTable, &CallableShaderBindingTable, indirectDeviceAddress); +#else + UNSUPPORTED("Ray tracing is not supported when vulkan library is linked statically"); +#endif + } + void FlushBarriers(); __forceinline void SetVkCmdBuffer(VkCommandBuffer VkCmdBuffer) diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanPhysicalDevice.hpp b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanPhysicalDevice.hpp index 38813f20..5f17d666 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanPhysicalDevice.hpp +++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanPhysicalDevice.hpp @@ -45,6 +45,7 @@ public: VkPhysicalDeviceShaderFloat16Int8FeaturesKHR ShaderFloat16Int8 = {}; VkPhysicalDeviceAccelerationStructureFeaturesKHR AccelStruct = {}; VkPhysicalDeviceRayTracingPipelineFeaturesKHR RayTracingPipeline = {}; + VkPhysicalDeviceRayQueryFeaturesKHR RayQuery = {}; 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 = {}; diff --git a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp index 723e2c7c..0707a989 100644 --- a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp @@ -792,7 +792,9 @@ void DeviceContextVkImpl::PrepareForDraw(DRAW_FLAGS Flags) #endif } -BufferVkImpl* DeviceContextVkImpl::PrepareIndirectDrawAttribsBuffer(IBuffer* pAttribsBuffer, RESOURCE_STATE_TRANSITION_MODE TransitonMode) +BufferVkImpl* DeviceContextVkImpl::PrepareIndirectAttribsBuffer(IBuffer* pAttribsBuffer, + RESOURCE_STATE_TRANSITION_MODE TransitonMode, + const char* OpName) { DEV_CHECK_ERR(pAttribsBuffer, "Indirect draw attribs buffer must not be null"); auto* pIndirectDrawAttribsVk = ValidatedCast(pAttribsBuffer); @@ -804,7 +806,7 @@ BufferVkImpl* DeviceContextVkImpl::PrepareIndirectDrawAttribsBuffer(IBuffer* pAt // Buffer memory barries must be executed outside of render pass TransitionOrVerifyBufferState(*pIndirectDrawAttribsVk, TransitonMode, RESOURCE_STATE_INDIRECT_ARGUMENT, - VK_ACCESS_INDIRECT_COMMAND_READ_BIT, "Indirect draw (DeviceContextVkImpl::Draw)"); + VK_ACCESS_INDIRECT_COMMAND_READ_BIT, OpName); return pIndirectDrawAttribsVk; } @@ -852,7 +854,7 @@ void DeviceContextVkImpl::DrawIndirect(const DrawIndirectAttribs& Attribs, IBuff // We must prepare indirect draw attribs buffer first because state transitions must // be performed outside of render pass, and PrepareForDraw commits render pass - BufferVkImpl* pIndirectDrawAttribsVk = PrepareIndirectDrawAttribsBuffer(pAttribsBuffer, Attribs.IndirectAttribsBufferStateTransitionMode); + BufferVkImpl* pIndirectDrawAttribsVk = PrepareIndirectAttribsBuffer(pAttribsBuffer, Attribs.IndirectAttribsBufferStateTransitionMode, "Indirect draw (DeviceContextVkImpl::DrawIndirect)"); PrepareForDraw(Attribs.Flags); @@ -867,7 +869,7 @@ void DeviceContextVkImpl::DrawIndexedIndirect(const DrawIndexedIndirectAttribs& // We must prepare indirect draw attribs buffer first because state transitions must // be performed outside of render pass, and PrepareForDraw commits render pass - BufferVkImpl* pIndirectDrawAttribsVk = PrepareIndirectDrawAttribsBuffer(pAttribsBuffer, Attribs.IndirectAttribsBufferStateTransitionMode); + BufferVkImpl* pIndirectDrawAttribsVk = PrepareIndirectAttribsBuffer(pAttribsBuffer, Attribs.IndirectAttribsBufferStateTransitionMode, "Indirect draw (DeviceContextVkImpl::DrawIndexedIndirect)"); PrepareForIndexedDraw(Attribs.Flags, Attribs.IndexType); @@ -893,7 +895,7 @@ void DeviceContextVkImpl::DrawMeshIndirect(const DrawMeshIndirectAttribs& Attrib // We must prepare indirect draw attribs buffer first because state transitions must // be performed outside of render pass, and PrepareForDraw commits render pass - BufferVkImpl* pIndirectDrawAttribsVk = PrepareIndirectDrawAttribsBuffer(pAttribsBuffer, Attribs.IndirectAttribsBufferStateTransitionMode); + BufferVkImpl* pIndirectDrawAttribsVk = PrepareIndirectAttribsBuffer(pAttribsBuffer, Attribs.IndirectAttribsBufferStateTransitionMode, "Indirect draw (DeviceContextVkImpl::DrawMeshIndirect)"); PrepareForDraw(Attribs.Flags); @@ -3471,4 +3473,56 @@ void DeviceContextVkImpl::TraceRays(const TraceRaysAttribs& Attribs) ++m_State.NumCommands; } +void DeviceContextVkImpl::TraceRaysIndirect(const TraceRaysIndirectAttribs& Attribs, IBuffer* pAttribsBuffer) +{ + if (!TDeviceContextBase::TraceRaysIndirect(Attribs, pAttribsBuffer, 0)) + return; + + auto* pSBTVk = ValidatedCast(Attribs.pSBT); + IBuffer* pBuffer = nullptr; + + ShaderBindingTableVkImpl::BindingTable RayGenShaderRecord = {}; + ShaderBindingTableVkImpl::BindingTable MissShaderTable = {}; + ShaderBindingTableVkImpl::BindingTable HitGroupTable = {}; + ShaderBindingTableVkImpl::BindingTable CallableShaderTable = {}; + + pSBTVk->GetData(pBuffer, RayGenShaderRecord, MissShaderTable, HitGroupTable, CallableShaderTable); + + const char* OpName = "Trace rays indirect (DeviceContextVkImpl::TraceRaysIndirect)"; + auto* const pSBTBufferVk = ValidatedCast(pBuffer); + auto* const pIndirectAttribsVk = PrepareIndirectAttribsBuffer(pAttribsBuffer, Attribs.IndirectAttribsBufferStateTransitionMode, OpName); + const auto IndirectBuffOffset = Attribs.ArgsByteOffset + (Attribs.ArgsByteSize == sizeof(Uint32) * 3 ? 0 : TraceRaysIndirectCommandSBTSize); + + if (RayGenShaderRecord.pData || MissShaderTable.pData || HitGroupTable.pData || CallableShaderTable.pData) + { + TransitionOrVerifyBufferState(*pSBTBufferVk, RESOURCE_STATE_TRANSITION_MODE_TRANSITION, 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, RESOURCE_STATE_TRANSITION_MODE_TRANSITION, 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.TraceRaysIndirect(RaygenShaderBindingTable, MissShaderBindingTable, HitShaderBindingTable, CallableShaderBindingTable, + pIndirectAttribsVk->GetVkDeviceAddress() + IndirectBuffOffset); + ++m_State.NumCommands; +} + } // namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp b/Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp index 7e08a361..027fa892 100644 --- a/Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp +++ b/Graphics/GraphicsEngineVulkan/src/EngineFactoryVk.cpp @@ -138,7 +138,7 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E try { Uint32 Version = VK_API_VERSION_1_0; - if (EngineCI.Features.RayTracing != DEVICE_FEATURE_STATE_DISABLED) + if (EngineCI.Features.RayTracing != DEVICE_FEATURE_STATE_DISABLED || EngineCI.Features.RayTracing2 != DEVICE_FEATURE_STATE_DISABLED) Version = VK_API_VERSION_1_2; auto Instance = VulkanUtilities::VulkanInstance::Create( @@ -280,8 +280,18 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E const auto& DescrIndexingFeats = DeviceExtFeatures.DescriptorIndexing; ENABLE_FEATURE(DescrIndexingFeats.runtimeDescriptorArray != VK_FALSE, ShaderResourceRuntimeArray, "Shader resource runtime array is"); - - ENABLE_FEATURE(DeviceExtFeatures.AccelStruct.accelerationStructure != VK_FALSE && DeviceExtFeatures.RayTracingPipeline.rayTracingPipeline != VK_FALSE, RayTracing, "Ray tracing is"); + const auto& AccelStructFeats = DeviceExtFeatures.AccelStruct; + const auto& RayTracingFeats = DeviceExtFeatures.RayTracingPipeline; + const auto& RayQueryFeats = DeviceExtFeatures.RayQuery; + // clang-format off + ENABLE_FEATURE(AccelStructFeats.accelerationStructure != VK_FALSE && + RayTracingFeats.rayTracingPipeline != VK_FALSE, RayTracing, "Ray tracing is"); + ENABLE_FEATURE(AccelStructFeats.accelerationStructure != VK_FALSE && + RayTracingFeats.rayTracingPipeline != VK_FALSE && + RayTracingFeats.rayTracingPipelineTraceRaysIndirect != VK_FALSE && + RayTracingFeats.rayTraversalPrimitiveCulling != VK_FALSE && + RayQueryFeats.rayQuery != VK_FALSE, RayTracing2, "Inline ray tracing is"); + // clang-format on #undef FeatureSupport @@ -417,13 +427,13 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E } // Ray tracing - if (EngineCI.Features.RayTracing != DEVICE_FEATURE_STATE_DISABLED) + if (EngineCI.Features.RayTracing != DEVICE_FEATURE_STATE_DISABLED || EngineCI.Features.RayTracing2 != 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 + DeviceExtensions.push_back(VK_KHR_SPIRV_1_4_EXTENSION_NAME); // required for VK_KHR_ray_tracing_pipeline or VK_KHR_ray_query EnabledExtFeats.Spirv14 = DeviceExtFeatures.Spirv14; VERIFY_EXPR(DeviceExtFeatures.Spirv14); } @@ -439,14 +449,11 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E // 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; @@ -454,6 +461,23 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E NextExt = &EnabledExtFeats.RayTracingPipeline.pNext; *NextExt = &EnabledExtFeats.BufferDeviceAddress; NextExt = &EnabledExtFeats.BufferDeviceAddress.pNext; + + // Inline ray tracing from any shader. + if (EngineCI.Features.RayTracing2 != DEVICE_FEATURE_STATE_DISABLED) + { + DeviceExtensions.push_back(VK_KHR_RAY_QUERY_EXTENSION_NAME); + + EnabledExtFeats.RayQuery = RayQueryFeats; + + *NextExt = &EnabledExtFeats.RayQuery; + NextExt = &EnabledExtFeats.RayQuery.pNext; + } + else + { + EnabledExtFeats.AccelStruct.accelerationStructureIndirectBuild = false; + EnabledExtFeats.RayTracingPipeline.rayTracingPipelineTraceRaysIndirect = false; + EnabledExtFeats.RayTracingPipeline.rayTraversalPrimitiveCulling = false; // for GLSL_EXT_ray_flags_primitive_culling + } } // make sure that last pNext is null @@ -461,7 +485,7 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk(const EngineVkCreateInfo& _E } #if defined(_MSC_VER) && defined(_WIN64) - static_assert(sizeof(DeviceFeatures) == 33, "Did you add a new feature to DeviceFeatures? Please handle its satus here."); + static_assert(sizeof(DeviceFeatures) == 34, "Did you add a new feature to DeviceFeatures? Please handle its satus here."); #endif DeviceCreateInfo.ppEnabledExtensionNames = DeviceExtensions.empty() ? nullptr : DeviceExtensions.data(); diff --git a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp index 8debcd97..e1ce9efa 100644 --- a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp @@ -234,7 +234,7 @@ RenderDeviceVkImpl::RenderDeviceVkImpl(IReferenceCounters* Features.DurationQueries = DEVICE_FEATURE_STATE_ENABLED; #if defined(_MSC_VER) && defined(_WIN64) - static_assert(sizeof(DeviceFeatures) == 33, "Did you add a new feature to DeviceFeatures? Please handle its satus here (if necessary)."); + static_assert(sizeof(DeviceFeatures) == 34, "Did you add a new feature to DeviceFeatures? Please handle its satus here (if necessary)."); #endif const auto& vkDeviceLimits = m_PhysicalDevice->GetProperties().limits; diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp index 343893e9..cf1cbd3f 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp @@ -146,6 +146,15 @@ VulkanPhysicalDevice::VulkanPhysicalDevice(VkPhysicalDevice vkDevice, m_ExtProperties.RayTracingPipeline.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR; } + // Get inline ray tracing features. + if (IsExtensionSupported(VK_KHR_RAY_QUERY_EXTENSION_NAME)) + { + *NextFeat = &m_ExtFeatures.RayQuery; + NextFeat = &m_ExtFeatures.RayQuery.pNext; + + m_ExtFeatures.RayQuery.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR; + } + // Additional extension that is required for ray tracing. if (IsExtensionSupported(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME)) { -- cgit v1.2.3