From fb8625d07a61031ebc575594552cf423367be273 Mon Sep 17 00:00:00 2001 From: hzqst <113660872@qq.com> Date: Fri, 12 Dec 2025 11:09:25 +0800 Subject: [PATCH 01/20] Add support for push constants to SPIRVShaderResources --- .../include/SPIRVShaderResources.hpp | 156 ++++++++++++------ .../ShaderTools/src/SPIRVShaderResources.cpp | 150 ++++++++++++++--- 2 files changed, 228 insertions(+), 78 deletions(-) diff --git a/Graphics/ShaderTools/include/SPIRVShaderResources.hpp b/Graphics/ShaderTools/include/SPIRVShaderResources.hpp index 891cd8a5e2..576971cb7e 100644 --- a/Graphics/ShaderTools/include/SPIRVShaderResources.hpp +++ b/Graphics/ShaderTools/include/SPIRVShaderResources.hpp @@ -32,9 +32,9 @@ // SPIRVShaderResources class uses continuous chunk of memory to store all resources, as follows: // -// m_MemoryBuffer m_TotalResources -// | | | -// | Uniform Buffers | Storage Buffers | Storage Images | Sampled Images | Atomic Counters | Separate Samplers | Separate Images | Stage Inputs | Resource Names | +// m_MemoryBuffer m_TotalResources +// | | | +// | Uniform Buffers | Storage Buffers | Storage Images | Sampled Images | Atomic Counters | Separate Samplers | Separate Images | Input Attachments | Accel Structs | Push Constants | Stage Inputs | Resource Names | #include #include @@ -79,6 +79,7 @@ struct SPIRVShaderResourceAttribs SeparateSampler, InputAttachment, AccelerationStructure, + PushConstant, // Vulkan push constant buffer - special inline constant that uses vkCmdPushConstants NumResourceTypes }; @@ -111,6 +112,11 @@ struct SPIRVShaderResourceAttribs Uint32 _BufferStaticSize = 0, Uint32 _BufferStride = 0) noexcept; + // Constructor for push constants (no binding or descriptor set decoration) + SPIRVShaderResourceAttribs(const char* _Name, + ResourceType _Type, + Uint32 _BufferStaticSize) noexcept; + ShaderResourceDesc GetResourceDesc() const { return ShaderResourceDesc{Name, GetShaderResourceType(Type), ArraySize}; @@ -125,6 +131,39 @@ struct SPIRVShaderResourceAttribs { return IsMS != 0; } + + Uint32 GetConstantBufferSize() const + { + VERIFY((Type == PushConstant || Type == UniformBuffer), "Invalid resource type: PushConstant or UniformBuffer expected"); + return BufferStaticSize; + } + + Uint32 GetInlineConstantCountOrThrow(const char* ShaderName) const + { + VERIFY_EXPR(Type == PushConstant || Type == UniformBuffer); + + if (ArraySize != 1) + { + LOG_ERROR_AND_THROW("Inline constants resource '", Name, "' in shader '", ShaderName, "' can not be an array."); + } + const Uint32 NumConstants = GetConstantBufferSize() / sizeof(Uint32); + + constexpr Uint32 kMaxInlineConstants = 64; + if (NumConstants > kMaxInlineConstants) + { + LOG_ERROR_AND_THROW("Inline constants resource '", Name, "' in shader '", ShaderName, "' has ", + NumConstants, " constants. The maximum supported number of inline constants is ", + kMaxInlineConstants, '.'); + } + + if (NumConstants == 0) + { + LOG_ERROR_AND_THROW("Resource '", Name, "' in shader '", ShaderName, + "' is marked as inline constants, but has zero buffer size. "); + } + + return NumConstants; + } }; static_assert(sizeof(SPIRVShaderResourceAttribs) % sizeof(void*) == 0, "Size of SPIRVShaderResourceAttribs struct must be multiple of sizeof(void*)"); @@ -166,28 +205,30 @@ class SPIRVShaderResources // clang-format off - Uint32 GetNumUBs ()const noexcept{ return (m_StorageBufferOffset - 0); } - Uint32 GetNumSBs ()const noexcept{ return (m_StorageImageOffset - m_StorageBufferOffset); } - Uint32 GetNumImgs ()const noexcept{ return (m_SampledImageOffset - m_StorageImageOffset); } - Uint32 GetNumSmpldImgs ()const noexcept{ return (m_AtomicCounterOffset - m_SampledImageOffset); } - Uint32 GetNumACs ()const noexcept{ return (m_SeparateSamplerOffset - m_AtomicCounterOffset); } - Uint32 GetNumSepSmplrs ()const noexcept{ return (m_SeparateImageOffset - m_SeparateSamplerOffset);} - Uint32 GetNumSepImgs ()const noexcept{ return (m_InputAttachmentOffset - m_SeparateImageOffset); } - Uint32 GetNumInptAtts ()const noexcept{ return (m_AccelStructOffset - m_InputAttachmentOffset);} - Uint32 GetNumAccelStructs()const noexcept{ return (m_TotalResources - m_AccelStructOffset); } + Uint32 GetNumUBs ()const noexcept{ return (m_StorageBufferOffset - 0); } + Uint32 GetNumSBs ()const noexcept{ return (m_StorageImageOffset - m_StorageBufferOffset); } + Uint32 GetNumImgs ()const noexcept{ return (m_SampledImageOffset - m_StorageImageOffset); } + Uint32 GetNumSmpldImgs ()const noexcept{ return (m_AtomicCounterOffset - m_SampledImageOffset); } + Uint32 GetNumACs ()const noexcept{ return (m_SeparateSamplerOffset - m_AtomicCounterOffset); } + Uint32 GetNumSepSmplrs ()const noexcept{ return (m_SeparateImageOffset - m_SeparateSamplerOffset); } + Uint32 GetNumSepImgs ()const noexcept{ return (m_InputAttachmentOffset - m_SeparateImageOffset); } + Uint32 GetNumInptAtts ()const noexcept{ return (m_AccelStructOffset - m_InputAttachmentOffset); } + Uint32 GetNumAccelStructs ()const noexcept{ return (m_PushConstantOffset - m_AccelStructOffset); } + Uint32 GetNumPushConstants()const noexcept{ return (m_TotalResources - m_PushConstantOffset); } Uint32 GetTotalResources () const noexcept { return m_TotalResources; } Uint32 GetNumShaderStageInputs()const noexcept { return m_NumShaderStageInputs; } - const SPIRVShaderResourceAttribs& GetUB (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumUBs(), 0 ); } - const SPIRVShaderResourceAttribs& GetSB (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumSBs(), m_StorageBufferOffset ); } - const SPIRVShaderResourceAttribs& GetImg (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumImgs(), m_StorageImageOffset ); } - const SPIRVShaderResourceAttribs& GetSmpldImg (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumSmpldImgs(), m_SampledImageOffset ); } - const SPIRVShaderResourceAttribs& GetAC (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumACs(), m_AtomicCounterOffset ); } - const SPIRVShaderResourceAttribs& GetSepSmplr (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumSepSmplrs(), m_SeparateSamplerOffset); } - const SPIRVShaderResourceAttribs& GetSepImg (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumSepImgs(), m_SeparateImageOffset ); } - const SPIRVShaderResourceAttribs& GetInptAtt (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumInptAtts(), m_InputAttachmentOffset); } - const SPIRVShaderResourceAttribs& GetAccelStruct(Uint32 n)const noexcept{ return GetResAttribs(n, GetNumAccelStructs(), m_AccelStructOffset ); } - const SPIRVShaderResourceAttribs& GetResource (Uint32 n)const noexcept{ return GetResAttribs(n, GetTotalResources(), 0 ); } + const SPIRVShaderResourceAttribs& GetUB (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumUBs(), 0 ); } + const SPIRVShaderResourceAttribs& GetSB (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumSBs(), m_StorageBufferOffset ); } + const SPIRVShaderResourceAttribs& GetImg (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumImgs(), m_StorageImageOffset ); } + const SPIRVShaderResourceAttribs& GetSmpldImg (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumSmpldImgs(), m_SampledImageOffset ); } + const SPIRVShaderResourceAttribs& GetAC (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumACs(), m_AtomicCounterOffset ); } + const SPIRVShaderResourceAttribs& GetSepSmplr (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumSepSmplrs(), m_SeparateSamplerOffset ); } + const SPIRVShaderResourceAttribs& GetSepImg (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumSepImgs(), m_SeparateImageOffset ); } + const SPIRVShaderResourceAttribs& GetInptAtt (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumInptAtts(), m_InputAttachmentOffset ); } + const SPIRVShaderResourceAttribs& GetAccelStruct (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumAccelStructs(), m_AccelStructOffset ); } + const SPIRVShaderResourceAttribs& GetPushConstant(Uint32 n)const noexcept{ return GetResAttribs(n, GetNumPushConstants(), m_PushConstantOffset ); } + const SPIRVShaderResourceAttribs& GetResource (Uint32 n)const noexcept{ return GetResAttribs(n, GetTotalResources(), 0 ); } // clang-format on @@ -217,15 +258,16 @@ class SPIRVShaderResources struct ResourceCounters { - Uint32 NumUBs = 0; - Uint32 NumSBs = 0; - Uint32 NumImgs = 0; - Uint32 NumSmpldImgs = 0; - Uint32 NumACs = 0; - Uint32 NumSepSmplrs = 0; - Uint32 NumSepImgs = 0; - Uint32 NumInptAtts = 0; - Uint32 NumAccelStructs = 0; + Uint32 NumUBs = 0; + Uint32 NumSBs = 0; + Uint32 NumImgs = 0; + Uint32 NumSmpldImgs = 0; + Uint32 NumACs = 0; + Uint32 NumSepSmplrs = 0; + Uint32 NumSepImgs = 0; + Uint32 NumInptAtts = 0; + Uint32 NumAccelStructs = 0; + Uint32 NumPushConstants = 0; // Vulkan push constant buffers (max 1 per Vulkan spec) }; SHADER_TYPE GetShaderType() const noexcept { return m_ShaderType; } @@ -243,16 +285,18 @@ class SPIRVShaderResources typename THandleSepSmpl, typename THandleSepImg, typename THandleInptAtt, - typename THandleAccelStruct> - void ProcessResources(THandleUB HandleUB, - THandleSB HandleSB, - THandleImg HandleImg, - THandleSmplImg HandleSmplImg, - THandleAC HandleAC, - THandleSepSmpl HandleSepSmpl, - THandleSepImg HandleSepImg, - THandleInptAtt HandleInptAtt, - THandleAccelStruct HandleAccelStruct) const + typename THandleAccelStruct, + typename THandlePushConstant> + void ProcessResources(THandleUB HandleUB, + THandleSB HandleSB, + THandleImg HandleImg, + THandleSmplImg HandleSmplImg, + THandleAC HandleAC, + THandleSepSmpl HandleSepSmpl, + THandleSepImg HandleSepImg, + THandleInptAtt HandleInptAtt, + THandleAccelStruct HandleAccelStruct, + THandlePushConstant HandlePushConstant) const { for (Uint32 n = 0; n < GetNumUBs(); ++n) { @@ -308,7 +352,13 @@ class SPIRVShaderResources HandleAccelStruct(AccelStruct, n); } - static_assert(Uint32{SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes} == 12, "Please handle the new resource type here, if needed"); + for (Uint32 n = 0; n < GetNumPushConstants(); ++n) + { + const SPIRVShaderResourceAttribs& PushConstant = GetPushConstant(n); + HandlePushConstant(PushConstant, n); + } + + static_assert(Uint32{SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes} == 13, "Please handle the new resource type here, if needed"); } template @@ -359,16 +409,17 @@ class SPIRVShaderResources // clang-format off - SPIRVShaderResourceAttribs& GetUB (Uint32 n)noexcept{ return GetResAttribs(n, GetNumUBs(), 0 ); } - SPIRVShaderResourceAttribs& GetSB (Uint32 n)noexcept{ return GetResAttribs(n, GetNumSBs(), m_StorageBufferOffset ); } - SPIRVShaderResourceAttribs& GetImg (Uint32 n)noexcept{ return GetResAttribs(n, GetNumImgs(), m_StorageImageOffset ); } - SPIRVShaderResourceAttribs& GetSmpldImg (Uint32 n)noexcept{ return GetResAttribs(n, GetNumSmpldImgs(), m_SampledImageOffset ); } - SPIRVShaderResourceAttribs& GetAC (Uint32 n)noexcept{ return GetResAttribs(n, GetNumACs(), m_AtomicCounterOffset ); } - SPIRVShaderResourceAttribs& GetSepSmplr (Uint32 n)noexcept{ return GetResAttribs(n, GetNumSepSmplrs(), m_SeparateSamplerOffset); } - SPIRVShaderResourceAttribs& GetSepImg (Uint32 n)noexcept{ return GetResAttribs(n, GetNumSepImgs(), m_SeparateImageOffset ); } - SPIRVShaderResourceAttribs& GetInptAtt (Uint32 n)noexcept{ return GetResAttribs(n, GetNumInptAtts(), m_InputAttachmentOffset); } - SPIRVShaderResourceAttribs& GetAccelStruct(Uint32 n)noexcept{ return GetResAttribs(n, GetNumAccelStructs(), m_AccelStructOffset ); } - SPIRVShaderResourceAttribs& GetResource (Uint32 n)noexcept{ return GetResAttribs(n, GetTotalResources(), 0 ); } + SPIRVShaderResourceAttribs& GetUB (Uint32 n)noexcept{ return GetResAttribs(n, GetNumUBs(), 0 ); } + SPIRVShaderResourceAttribs& GetSB (Uint32 n)noexcept{ return GetResAttribs(n, GetNumSBs(), m_StorageBufferOffset ); } + SPIRVShaderResourceAttribs& GetImg (Uint32 n)noexcept{ return GetResAttribs(n, GetNumImgs(), m_StorageImageOffset ); } + SPIRVShaderResourceAttribs& GetSmpldImg (Uint32 n)noexcept{ return GetResAttribs(n, GetNumSmpldImgs(), m_SampledImageOffset ); } + SPIRVShaderResourceAttribs& GetAC (Uint32 n)noexcept{ return GetResAttribs(n, GetNumACs(), m_AtomicCounterOffset ); } + SPIRVShaderResourceAttribs& GetSepSmplr (Uint32 n)noexcept{ return GetResAttribs(n, GetNumSepSmplrs(), m_SeparateSamplerOffset ); } + SPIRVShaderResourceAttribs& GetSepImg (Uint32 n)noexcept{ return GetResAttribs(n, GetNumSepImgs(), m_SeparateImageOffset ); } + SPIRVShaderResourceAttribs& GetInptAtt (Uint32 n)noexcept{ return GetResAttribs(n, GetNumInptAtts(), m_InputAttachmentOffset ); } + SPIRVShaderResourceAttribs& GetAccelStruct (Uint32 n)noexcept{ return GetResAttribs(n, GetNumAccelStructs(), m_AccelStructOffset ); } + SPIRVShaderResourceAttribs& GetPushConstant(Uint32 n)noexcept{ return GetResAttribs(n, GetNumPushConstants(), m_PushConstantOffset ); } + SPIRVShaderResourceAttribs& GetResource (Uint32 n)noexcept{ return GetResAttribs(n, GetTotalResources(), 0 ); } // clang-format on @@ -394,6 +445,7 @@ class SPIRVShaderResources OffsetType m_SeparateImageOffset = 0; OffsetType m_InputAttachmentOffset = 0; OffsetType m_AccelStructOffset = 0; + OffsetType m_PushConstantOffset = 0; OffsetType m_TotalResources = 0; OffsetType m_NumShaderStageInputs = 0; diff --git a/Graphics/ShaderTools/src/SPIRVShaderResources.cpp b/Graphics/ShaderTools/src/SPIRVShaderResources.cpp index dc65e596bb..92c15dd470 100644 --- a/Graphics/ShaderTools/src/SPIRVShaderResources.cpp +++ b/Graphics/ShaderTools/src/SPIRVShaderResources.cpp @@ -126,10 +126,29 @@ SPIRVShaderResourceAttribs::SPIRVShaderResourceAttribs(const diligent_spirv_cros // clang-format on {} +// Constructor for push constants (no binding or descriptor set decoration) +SPIRVShaderResourceAttribs::SPIRVShaderResourceAttribs(const char* _Name, + ResourceType _Type, + Uint32 _BufferStaticSize) noexcept : + // clang-format off + Name {_Name}, + // For push constants, ArraySize represents the number of 32-bit constants (BufferStaticSize / 4) + // This is consistent with how inline constants work in the pipeline resource signature + ArraySize {static_cast(_BufferStaticSize / sizeof(Uint32))}, + Type {_Type}, + ResourceDim {RESOURCE_DIM_BUFFER}, + IsMS {0}, + BindingDecorationOffset {0}, // Push constants have no binding decoration + DescriptorSetDecorationOffset {0}, // Push constants have no descriptor set decoration + BufferStaticSize {_BufferStaticSize}, + BufferStride {0} +// clang-format on +{} + SHADER_RESOURCE_TYPE SPIRVShaderResourceAttribs::GetShaderResourceType(ResourceType Type) { - static_assert(Uint32{SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes} == 12, "Please handle the new resource type below"); + static_assert(Uint32{SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes} == 13, "Please handle the new resource type below"); switch (Type) { case SPIRVShaderResourceAttribs::ResourceType::UniformBuffer: @@ -171,6 +190,10 @@ SHADER_RESOURCE_TYPE SPIRVShaderResourceAttribs::GetShaderResourceType(ResourceT case SPIRVShaderResourceAttribs::ResourceType::AccelerationStructure: return SHADER_RESOURCE_TYPE_ACCEL_STRUCT; + case SPIRVShaderResourceAttribs::ResourceType::PushConstant: + // Push constants map to constant buffer type with special inline constants flag + return SHADER_RESOURCE_TYPE_CONSTANT_BUFFER; + default: UNEXPECTED("Unknown SPIRV resource type"); return SHADER_RESOURCE_TYPE_UNKNOWN; @@ -179,7 +202,7 @@ SHADER_RESOURCE_TYPE SPIRVShaderResourceAttribs::GetShaderResourceType(ResourceT PIPELINE_RESOURCE_FLAGS SPIRVShaderResourceAttribs::GetPipelineResourceFlags(ResourceType Type) { - static_assert(Uint32{SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes} == 12, "Please handle the new resource type below"); + static_assert(Uint32{SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes} == 13, "Please handle the new resource type below"); switch (Type) { case SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer: @@ -189,6 +212,11 @@ PIPELINE_RESOURCE_FLAGS SPIRVShaderResourceAttribs::GetPipelineResourceFlags(Res case SPIRVShaderResourceAttribs::ResourceType::SampledImage: return PIPELINE_RESOURCE_FLAG_COMBINED_SAMPLER; + case SPIRVShaderResourceAttribs::ResourceType::PushConstant: + // Push constants are special inline constants that use vkCmdPushConstants + // Mark them with both INLINE_CONSTANTS and VULKAN_PUSH_CONSTANT flags + return PIPELINE_RESOURCE_FLAG_INLINE_CONSTANTS; + default: return PIPELINE_RESOURCE_FLAG_NONE; } @@ -262,6 +290,33 @@ const std::string& GetUBOrSBName(diligent_spirv_cross::Compiler& C return ((IRSource.hlsl || IRSource.lang == spv::SourceLanguageSlang) && !instance_name.empty()) ? instance_name : UB.name; } +// Get name for push constant buffer +// Push constants may have their variable name empty (e.g., when declared as [[vk::push_constant]] cbuffer in HLSL) +// In that case, we try to get the name from the base type (the struct type) +const std::string& GetPushConstantName(diligent_spirv_cross::Compiler& Compiler, + const diligent_spirv_cross::Resource& PC, + const diligent_spirv_cross::ParsedIR::Source& IRSource) +{ + // First, try the standard method used for UBs/SBs + const std::string& Name = GetUBOrSBName(Compiler, PC, IRSource); + if (!Name.empty()) + return Name; + + // If the name is empty, try to get the name from the base type + // This handles cases like: + // [[vk::push_constant]] + // cbuffer Constants { ... }; + // where the variable has no name but the struct type does + const std::string& base_type_name = Compiler.get_name(PC.base_type_id); + if (!base_type_name.empty()) + return base_type_name; + + // As a last resort, try to get the fallback name + // Note: get_fallback_name returns by value, so we can't return a reference to it + // Return the empty name and let the caller handle it + return Name; +} + static SHADER_CODE_BASIC_TYPE SpirvBaseTypeToShaderCodeBasicType(diligent_spirv_cross::SPIRType::BaseType SpvBaseType) { switch (SpvBaseType) @@ -423,7 +478,18 @@ SPIRVShaderResources::SPIRVShaderResources(IMemoryAllocator& Allocator, ResourceNamesPoolSize += GetUBOrSBName(Compiler, ub, ParsedIRSource).length() + 1; for (const diligent_spirv_cross::Resource& sb : resources.storage_buffers) ResourceNamesPoolSize += GetUBOrSBName(Compiler, sb, ParsedIRSource).length() + 1; - static_assert(Uint32{SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes} == 12, "Please account for the new resource type below"); + static_assert(Uint32{SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes} == 13, "Please account for the new resource type below"); + + // Process push constant buffers - Vulkan spec allows only one push_constant buffer per pipeline + if (resources.push_constant_buffers.size() > 1) + { + LOG_ERROR_AND_THROW("Shader '", shaderDesc.Name, "' contains ", resources.push_constant_buffers.size(), + " push constant buffers, but Vulkan spec allows only one push_constant buffer per pipeline."); + } + // For push constants, use GetPushConstantName which also tries to get the name from the base type + for (const diligent_spirv_cross::Resource& pc : resources.push_constant_buffers) + ResourceNamesPoolSize += GetPushConstantName(Compiler, pc, ParsedIRSource).length() + 1; + for (auto* pResType : { &resources.storage_images, @@ -493,16 +559,17 @@ SPIRVShaderResources::SPIRVShaderResources(IMemoryAllocator& Allocator, } ResourceCounters ResCounters; - ResCounters.NumUBs = static_cast(resources.uniform_buffers.size()); - ResCounters.NumSBs = static_cast(resources.storage_buffers.size()); - ResCounters.NumImgs = static_cast(resources.storage_images.size()); - ResCounters.NumSmpldImgs = static_cast(resources.sampled_images.size()); - ResCounters.NumACs = static_cast(resources.atomic_counters.size()); - ResCounters.NumSepSmplrs = static_cast(resources.separate_samplers.size()); - ResCounters.NumSepImgs = static_cast(resources.separate_images.size()); - ResCounters.NumInptAtts = static_cast(resources.subpass_inputs.size()); - ResCounters.NumAccelStructs = static_cast(resources.acceleration_structures.size()); - static_assert(Uint32{SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes} == 12, "Please set the new resource type counter here"); + ResCounters.NumUBs = static_cast(resources.uniform_buffers.size()); + ResCounters.NumSBs = static_cast(resources.storage_buffers.size()); + ResCounters.NumImgs = static_cast(resources.storage_images.size()); + ResCounters.NumSmpldImgs = static_cast(resources.sampled_images.size()); + ResCounters.NumACs = static_cast(resources.atomic_counters.size()); + ResCounters.NumSepSmplrs = static_cast(resources.separate_samplers.size()); + ResCounters.NumSepImgs = static_cast(resources.separate_images.size()); + ResCounters.NumInptAtts = static_cast(resources.subpass_inputs.size()); + ResCounters.NumAccelStructs = static_cast(resources.acceleration_structures.size()); + ResCounters.NumPushConstants = static_cast(resources.push_constant_buffers.size()); + static_assert(Uint32{SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes} == 13, "Please set the new resource type counter here"); // Resource names pool is only needed to facilitate string allocation. StringPool ResourceNamesPool; @@ -687,7 +754,26 @@ SPIRVShaderResources::SPIRVShaderResources(IMemoryAllocator& Allocator, VERIFY_EXPR(CurrAccelStruct == GetNumAccelStructs()); } - static_assert(Uint32{SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes} == 12, "Please initialize SPIRVShaderResourceAttribs for the new resource type here"); + { + Uint32 CurrPushConstant = 0; + for (const diligent_spirv_cross::Resource& PushConst : resources.push_constant_buffers) + { + const std::string& pcName = GetPushConstantName(Compiler, PushConst, ParsedIRSource); + const diligent_spirv_cross::SPIRType& Type = Compiler.get_type(PushConst.type_id); + const size_t Size = Compiler.get_declared_struct_size(Type); + + // Push constants use a special constructor without binding/descriptor set decorations + new (&GetPushConstant(CurrPushConstant++)) SPIRVShaderResourceAttribs // + { + ResourceNamesPool.CopyString(pcName), + SPIRVShaderResourceAttribs::ResourceType::PushConstant, + static_cast(Size) // + }; + } + VERIFY_EXPR(CurrPushConstant == GetNumPushConstants()); + } + + static_assert(Uint32{SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes} == 13, "Please initialize SPIRVShaderResourceAttribs for the new resource type here"); if (CombinedSamplerSuffix != nullptr) { @@ -757,8 +843,9 @@ void SPIRVShaderResources::Initialize(IMemoryAllocator& Allocator, m_SeparateImageOffset = AdvanceOffset(Counters.NumSepImgs); m_InputAttachmentOffset = AdvanceOffset(Counters.NumInptAtts); m_AccelStructOffset = AdvanceOffset(Counters.NumAccelStructs); + m_PushConstantOffset = AdvanceOffset(Counters.NumPushConstants); m_TotalResources = AdvanceOffset(0); - static_assert(Uint32{SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes} == 12, "Please update the new resource type offset"); + static_assert(Uint32{SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes} == 13, "Please update the new resource type offset"); VERIFY(NumShaderStageInputs <= MaxOffset, "Max offset exceeded"); m_NumShaderStageInputs = static_cast(NumShaderStageInputs); @@ -771,16 +858,17 @@ void SPIRVShaderResources::Initialize(IMemoryAllocator& Allocator, m_NumShaderStageInputs * sizeof(SPIRVShaderStageInputAttribs) + AlignedResourceNamesPoolSize * sizeof(char); - VERIFY_EXPR(GetNumUBs() == Counters.NumUBs); - VERIFY_EXPR(GetNumSBs() == Counters.NumSBs); - VERIFY_EXPR(GetNumImgs() == Counters.NumImgs); - VERIFY_EXPR(GetNumSmpldImgs() == Counters.NumSmpldImgs); - VERIFY_EXPR(GetNumACs() == Counters.NumACs); - VERIFY_EXPR(GetNumSepSmplrs() == Counters.NumSepSmplrs); - VERIFY_EXPR(GetNumSepImgs() == Counters.NumSepImgs); - VERIFY_EXPR(GetNumInptAtts() == Counters.NumInptAtts); - VERIFY_EXPR(GetNumAccelStructs() == Counters.NumAccelStructs); - static_assert(Uint32{SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes} == 12, "Please update the new resource count verification"); + VERIFY_EXPR(GetNumUBs() == Counters.NumUBs); + VERIFY_EXPR(GetNumSBs() == Counters.NumSBs); + VERIFY_EXPR(GetNumImgs() == Counters.NumImgs); + VERIFY_EXPR(GetNumSmpldImgs() == Counters.NumSmpldImgs); + VERIFY_EXPR(GetNumACs() == Counters.NumACs); + VERIFY_EXPR(GetNumSepSmplrs() == Counters.NumSepSmplrs); + VERIFY_EXPR(GetNumSepImgs() == Counters.NumSepImgs); + VERIFY_EXPR(GetNumInptAtts() == Counters.NumInptAtts); + VERIFY_EXPR(GetNumAccelStructs() == Counters.NumAccelStructs); + VERIFY_EXPR(GetNumPushConstants() == Counters.NumPushConstants); + static_assert(Uint32{SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes} == 13, "Please update the new resource count verification"); // clang-format on if (MemorySize) @@ -826,7 +914,10 @@ SPIRVShaderResources::~SPIRVShaderResources() for (Uint32 n = 0; n < GetNumAccelStructs(); ++n) GetAccelStruct(n).~SPIRVShaderResourceAttribs(); - static_assert(Uint32{SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes} == 12, "Please add destructor for the new resource"); + for (Uint32 n = 0; n < GetNumPushConstants(); ++n) + GetPushConstant(n).~SPIRVShaderResourceAttribs(); + + static_assert(Uint32{SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes} == 13, "Please add destructor for the new resource"); } void SPIRVShaderResources::MapHLSLVertexShaderInputs(std::vector& SPIRV) const @@ -966,6 +1057,13 @@ std::string SPIRVShaderResources::DumpResources() const ss << std::endl << std::setw(3) << ResNum << " Accel Struct "; DumpResource(AccelStruct); + }, + [&](const SPIRVShaderResourceAttribs& PushConst, Uint32) // + { + VERIFY(PushConst.Type == SPIRVShaderResourceAttribs::ResourceType::PushConstant, "Unexpected resource type"); + ss << std::endl + << std::setw(3) << ResNum << " Push Constant "; + DumpResource(PushConst); } // ); VERIFY_EXPR(ResNum == GetTotalResources()); From b9512bc9417bba47c27333f86e8924a7ba45820b Mon Sep 17 00:00:00 2001 From: hzqst <113660872@qq.com> Date: Fri, 12 Dec 2025 13:47:50 +0800 Subject: [PATCH 02/20] Add SPIRVShaderResourcesTest --- Tests/DiligentCoreTest/CMakeLists.txt | 6 + .../shaders/SPIRV/AccelerationStructures.glsl | 30 ++ .../assets/shaders/SPIRV/AtomicCounters.glsl | 30 ++ .../assets/shaders/SPIRV/InputAttachments.psh | 14 + .../assets/shaders/SPIRV/MixedResources.psh | 66 ++++ .../assets/shaders/SPIRV/PushConstants.psh | 26 ++ .../assets/shaders/SPIRV/StorageBuffers.psh | 43 +++ .../assets/shaders/SPIRV/StorageImages.psh | 20 ++ .../assets/shaders/SPIRV/TexelBuffers.psh | 15 + .../assets/shaders/SPIRV/Textures.psh | 30 ++ .../assets/shaders/SPIRV/UniformBuffers.psh | 24 ++ .../ShaderTools/SPIRVShaderResourcesTest.cpp | 336 ++++++++++++++++++ 12 files changed, 640 insertions(+) create mode 100644 Tests/DiligentCoreTest/assets/shaders/SPIRV/AccelerationStructures.glsl create mode 100644 Tests/DiligentCoreTest/assets/shaders/SPIRV/AtomicCounters.glsl create mode 100644 Tests/DiligentCoreTest/assets/shaders/SPIRV/InputAttachments.psh create mode 100644 Tests/DiligentCoreTest/assets/shaders/SPIRV/MixedResources.psh create mode 100644 Tests/DiligentCoreTest/assets/shaders/SPIRV/PushConstants.psh create mode 100644 Tests/DiligentCoreTest/assets/shaders/SPIRV/StorageBuffers.psh create mode 100644 Tests/DiligentCoreTest/assets/shaders/SPIRV/StorageImages.psh create mode 100644 Tests/DiligentCoreTest/assets/shaders/SPIRV/TexelBuffers.psh create mode 100644 Tests/DiligentCoreTest/assets/shaders/SPIRV/Textures.psh create mode 100644 Tests/DiligentCoreTest/assets/shaders/SPIRV/UniformBuffers.psh create mode 100644 Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp diff --git a/Tests/DiligentCoreTest/CMakeLists.txt b/Tests/DiligentCoreTest/CMakeLists.txt index d6fed71511..283b0f3569 100644 --- a/Tests/DiligentCoreTest/CMakeLists.txt +++ b/Tests/DiligentCoreTest/CMakeLists.txt @@ -20,6 +20,12 @@ if(NOT WEBGPU_SUPPORTED) ) endif() +if(NOT VULKAN_SUPPORTED) + list(REMOVE_ITEM SOURCE + ${CMAKE_CURRENT_SOURCE_DIR}/src/ShaderTools/SPIRVShaderResourcesTest.cpp + ) +endif() + set_source_files_properties(${SHADERS} PROPERTIES VS_TOOL_OVERRIDE "None") if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") diff --git a/Tests/DiligentCoreTest/assets/shaders/SPIRV/AccelerationStructures.glsl b/Tests/DiligentCoreTest/assets/shaders/SPIRV/AccelerationStructures.glsl new file mode 100644 index 0000000000..42f5e1787a --- /dev/null +++ b/Tests/DiligentCoreTest/assets/shaders/SPIRV/AccelerationStructures.glsl @@ -0,0 +1,30 @@ +// Test for acceleration structures +// GLSL ray gen shader for testing acceleration structure resource reflection +#version 460 +#extension GL_EXT_ray_tracing : require + +layout(set = 0, binding = 0) uniform accelerationStructureEXT g_AccelStruct; + +layout(location = 0) rayPayloadEXT vec4 payload; + +void main() +{ + // Use traceRayEXT to ensure g_AccelStruct is actually used and not optimized away + // This is the proper way to use acceleration structures in ray gen shaders + const vec2 uv = vec2(gl_LaunchIDEXT.xy + 0.5) / vec2(gl_LaunchSizeEXT.xy); + const vec3 origin = vec3(uv.x, 1.0 - uv.y, -1.0); + const vec3 direction = vec3(0.0, 0.0, 1.0); + + payload = vec4(0.0); + traceRayEXT(g_AccelStruct, // acceleration structure (first parameter) + gl_RayFlagsNoneEXT, // ray flags + 0xFF, // cullMask + 0, // sbtRecordOffset + 1, // sbtRecordStride + 0, // missIndex + origin, // ray origin + 0.01, // ray min range + direction, // ray direction + 10.0, // ray max range + 0); // payload location +} diff --git a/Tests/DiligentCoreTest/assets/shaders/SPIRV/AtomicCounters.glsl b/Tests/DiligentCoreTest/assets/shaders/SPIRV/AtomicCounters.glsl new file mode 100644 index 0000000000..efcf907ab3 --- /dev/null +++ b/Tests/DiligentCoreTest/assets/shaders/SPIRV/AtomicCounters.glsl @@ -0,0 +1,30 @@ +// Test for atomic counters +// GLSL fragment shader for testing atomic counter resource reflection +// Note: Vulkan does not support atomic_uint (AtomicCounter storage class). +// We use a storage buffer with atomic operations to simulate atomic counters. +// However, this will be reflected as RWStorageBuffer, not AtomicCounter. +#version 450 + +layout(binding = 0) coherent buffer AtomicCounterBuffer +{ + uint counter; +} g_AtomicCounter; + +layout(location = 0) out vec4 FragColor; + +void main() +{ + // Increment atomic counter using atomicAdd + // atomicAdd returns the value before the addition + uint counterValue = atomicAdd(g_AtomicCounter.counter, 1u); + + // Create a color based on counter value + vec4 color = vec4( + float(counterValue & 0xFFu) / 255.0, + float((counterValue >> 8u) & 0xFFu) / 255.0, + float((counterValue >> 16u) & 0xFFu) / 255.0, + 1.0 + ); + + FragColor = color; +} diff --git a/Tests/DiligentCoreTest/assets/shaders/SPIRV/InputAttachments.psh b/Tests/DiligentCoreTest/assets/shaders/SPIRV/InputAttachments.psh new file mode 100644 index 0000000000..817e0d09e8 --- /dev/null +++ b/Tests/DiligentCoreTest/assets/shaders/SPIRV/InputAttachments.psh @@ -0,0 +1,14 @@ +// Test for input attachments (subpass inputs) +// In HLSL, subpass inputs are declared using SubpassInput type with vk::input_attachment_index attribute +[[vk::input_attachment_index(0)]] +[[vk::binding(0)]] +SubpassInput g_InputAttachment; + +float4 main() : SV_Target +{ + // Read from input attachment (subpass input) + float4 color = g_InputAttachment.SubpassLoad(); + + // Process the input color + return color * 2.0; +} \ No newline at end of file diff --git a/Tests/DiligentCoreTest/assets/shaders/SPIRV/MixedResources.psh b/Tests/DiligentCoreTest/assets/shaders/SPIRV/MixedResources.psh new file mode 100644 index 0000000000..b89b11a210 --- /dev/null +++ b/Tests/DiligentCoreTest/assets/shaders/SPIRV/MixedResources.psh @@ -0,0 +1,66 @@ +// Test for mixed resources to verify all resource types work together + +struct BufferData +{ + float4 data[4]; +}; + +// Uniform buffer +cbuffer UniformBuff : register(b0) +{ + float4x4 g_WorldViewProj; + float4 g_MaterialParams; +}; + +// Read-only structured buffer +StructuredBuffer ROStorageBuff : register(t0); + +// Read-write structured buffer +RWStructuredBuffer RWStorageBuff : register(u0); + +// Sampled texture +Texture2D SampledTex : register(t1); + +// Storage texture +RWTexture2D StorageTex : register(u1); + +// Sampler +SamplerState Sampler : register(s0); + +// Test for push constants +struct PushConstants_t +{ + float2 Offset; + float Time; + uint FrameCount; +}; + +[[vk::push_constant]] +cbuffer PushConstants +{ + PushConstants_t g_PushConstants; +}; + +float4 main() : SV_Target +{ + // Use uniform buffer data + float4 color = g_MaterialParams; + + // Read from RO structured buffer + color += ROStorageBuff[0].data[0]; + + // Write to RW structured buffer + RWStorageBuff[1].data[1] = color * 2.0; + + // Sample texture + color += SampledTex.Sample(Sampler, float2(0.5, 0.5)); + + // Write to storage texture + StorageTex[uint2(0, 0)] = color; + + // Use push constant data + color.xy += g_PushConstants.Offset; + color.rgb *= sin(g_PushConstants.Time) * 0.5 + 0.5; + + return color; +} \ No newline at end of file diff --git a/Tests/DiligentCoreTest/assets/shaders/SPIRV/PushConstants.psh b/Tests/DiligentCoreTest/assets/shaders/SPIRV/PushConstants.psh new file mode 100644 index 0000000000..53aafb2a53 --- /dev/null +++ b/Tests/DiligentCoreTest/assets/shaders/SPIRV/PushConstants.psh @@ -0,0 +1,26 @@ +// Test for push constants +struct PushConstants_t +{ + float4x4 g_MVPMatrix; + float4 g_Color; + float2 g_Offset; + float g_Scale; + uint g_Padding; +}; + +[[vk::push_constant]] +cbuffer PushConstants +{ + PushConstants_t g_PushConstants; +}; + +float4 main() : SV_Target +{ + // Use push constant data through the structure instance + float4 result = g_PushConstants.g_Color * g_PushConstants.g_Scale; + + // Apply offset to result (simplified example) + result.xy += g_PushConstants.g_Offset; + + return result; +} \ No newline at end of file diff --git a/Tests/DiligentCoreTest/assets/shaders/SPIRV/StorageBuffers.psh b/Tests/DiligentCoreTest/assets/shaders/SPIRV/StorageBuffers.psh new file mode 100644 index 0000000000..9fd5506489 --- /dev/null +++ b/Tests/DiligentCoreTest/assets/shaders/SPIRV/StorageBuffers.psh @@ -0,0 +1,43 @@ +// Test for storage buffers (structured buffers and byte address buffers) +struct BufferData0 +{ + float4 data0; + float4 data1; +}; + +struct BufferData1 +{ + float4 data0; + float4 data1; + float4 data2; + float4 data3; +}; + +// Read-only structured buffer +StructuredBuffer g_ROBuffer : register(t0); + +// Read-write structured buffer +RWStructuredBuffer g_RWBuffer : register(u0); + +// Atomic counter buffers +ByteAddressBuffer g_ROAtomicBuffer : register(t1); +RWByteAddressBuffer g_RWAtomicBuffer : register(u1); + +float4 main() : SV_Target +{ + float4 result = float4(0.0, 0.0, 0.0, 0.0); + + // Read from RO buffer + result += g_ROBuffer[0].data0; + result += g_ROBuffer[1].data1; + + // Write to RW buffer + g_RWBuffer[0].data0 = result; + g_RWBuffer[1].data1 = result * 2.0; + + // Atomic operations + uint atomicValue = g_ROAtomicBuffer.Load(0); + g_RWAtomicBuffer.Store(0, atomicValue + 1); + + return result; +} \ No newline at end of file diff --git a/Tests/DiligentCoreTest/assets/shaders/SPIRV/StorageImages.psh b/Tests/DiligentCoreTest/assets/shaders/SPIRV/StorageImages.psh new file mode 100644 index 0000000000..d475a0137c --- /dev/null +++ b/Tests/DiligentCoreTest/assets/shaders/SPIRV/StorageImages.psh @@ -0,0 +1,20 @@ +// Test for storage images (read-write textures) +// Note: HLSL does not support RWTextureCube, so we only test 2D, 2DArray, and 3D storage images +RWTexture2D g_RWImage2D : register(u0); +RWTexture2DArray g_RWImage2DArray : register(u1); +RWTexture3D g_RWImage3D : register(u2); + +float4 main() : SV_Target +{ + // Write to storage images + g_RWImage2D[uint2(0, 0)] = float4(1.0, 0.0, 0.0, 1.0); + g_RWImage2DArray[uint3(0, 0, 0)] = float4(0.0, 1.0, 0.0, 1.0); + g_RWImage3D[uint3(0, 0, 0)] = float4(0.0, 0.0, 1.0, 1.0); + + // Read back and combine + float4 color = g_RWImage2D[uint2(0, 0)]; + color += g_RWImage2DArray[uint3(0, 0, 0)]; + color += g_RWImage3D[uint3(0, 0, 0)]; + + return color; +} \ No newline at end of file diff --git a/Tests/DiligentCoreTest/assets/shaders/SPIRV/TexelBuffers.psh b/Tests/DiligentCoreTest/assets/shaders/SPIRV/TexelBuffers.psh new file mode 100644 index 0000000000..f61ec5a607 --- /dev/null +++ b/Tests/DiligentCoreTest/assets/shaders/SPIRV/TexelBuffers.psh @@ -0,0 +1,15 @@ +// Test for texel buffers (buffer textures) +Buffer g_UniformTexelBuffer : register(t0); // Uniform texel buffer (read-only) +RWBuffer g_StorageTexelBuffer : register(u0); // Storage texel buffer (read-write) + +float4 main() : SV_Target +{ + // Read from uniform texel buffer + float4 value = g_UniformTexelBuffer[0]; + + // Write to storage texel buffer + g_StorageTexelBuffer[0] = value * 2.0; + + // Read back from storage texel buffer + return g_StorageTexelBuffer[0]; +} \ No newline at end of file diff --git a/Tests/DiligentCoreTest/assets/shaders/SPIRV/Textures.psh b/Tests/DiligentCoreTest/assets/shaders/SPIRV/Textures.psh new file mode 100644 index 0000000000..46d7ae89fc --- /dev/null +++ b/Tests/DiligentCoreTest/assets/shaders/SPIRV/Textures.psh @@ -0,0 +1,30 @@ +// Test for textures and samplers +Texture2D g_SampledImage : register(t0); // 2D texture (sampled image) +Texture2DMS g_SampledImageMS : register(t1); // 2D multisample texture +Texture3D g_SampledImage3D : register(t2); // 3D texture +TextureCube g_SampledImageCube : register(t3); // Cubemap texture + +SamplerState g_Sampler : register(s0); // Separate sampler +Texture2D g_SeparateImage : register(t4); // Separate image (used with separate sampler) + +// Combined sampler test - when texture and sampler follow the naming convention, +// they should be recognized as SampledImage instead of SeparateImage +Texture2D g_Texture : register(t5); +SamplerState g_Texture_sampler : register(s1); + +float4 main() : SV_Target +{ + // Sample textures + float4 color1 = g_SampledImage.Sample(g_Sampler, float2(0.5, 0.5)); + float4 color2 = g_SampledImageMS.Load(int2(0, 0), 0); // Texture2DMS uses Load instead of Sample + float4 color3 = g_SampledImage3D.Sample(g_Sampler, float3(0.5, 0.5, 0.5)); + float4 color4 = g_SampledImageCube.Sample(g_Sampler, float3(0.0, 1.0, 0.0)); + + // Sample separate image with separate sampler + float4 color5 = g_SeparateImage.Sample(g_Sampler, float2(0.25, 0.25)); + + // Sample combined sampler texture + float4 color6 = g_Texture.Sample(g_Texture_sampler, float2(0.5, 0.5)); + + return color1 + color2 + color3 + color4 + color5 + color6; +} \ No newline at end of file diff --git a/Tests/DiligentCoreTest/assets/shaders/SPIRV/UniformBuffers.psh b/Tests/DiligentCoreTest/assets/shaders/SPIRV/UniformBuffers.psh new file mode 100644 index 0000000000..63a93344bb --- /dev/null +++ b/Tests/DiligentCoreTest/assets/shaders/SPIRV/UniformBuffers.psh @@ -0,0 +1,24 @@ +// Test for uniform buffers (constant buffers) +cbuffer CB0 : register(b0) +{ + float4x4 g_WorldViewProj; +}; + +cbuffer CB1 : register(b1) +{ + float4 g_Color; + float3 g_LightDir; + float g_LightIntensity; + float2 g_TexScale; + uint2 g_Padding; +}; + +cbuffer CB2 : register(b2) +{ + float4 g_MaterialParams; +}; + +float4 main() : SV_Target +{ + return g_Color * g_MaterialParams; +} \ No newline at end of file diff --git a/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp b/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp new file mode 100644 index 0000000000..205c443f40 --- /dev/null +++ b/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp @@ -0,0 +1,336 @@ +/* + * Copyright 2025 Diligent Graphics LLC + * + * 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 "SPIRVShaderResources.hpp" +#include "GLSLangUtils.hpp" +#include "DefaultShaderSourceStreamFactory.h" +#include "RefCntAutoPtr.hpp" +#include "EngineMemory.h" +#include "BasicFileSystem.hpp" + +#include + +#include "TestingEnvironment.hpp" +#include "gtest/gtest.h" + +using namespace Diligent; +using namespace Diligent::Testing; + +namespace +{ + +const char* SPIRVShaderResourceTypeToString(SPIRVShaderResourceAttribs::ResourceType Type) +{ + switch (Type) + { + case SPIRVShaderResourceAttribs::ResourceType::UniformBuffer: + return "UniformBuffer"; + case SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer: + return "ROStorageBuffer"; + case SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer: + return "RWStorageBuffer"; + case SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer: + return "UniformTexelBuffer"; + case SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer: + return "StorageTexelBuffer"; + case SPIRVShaderResourceAttribs::ResourceType::StorageImage: + return "StorageImage"; + case SPIRVShaderResourceAttribs::ResourceType::SampledImage: + return "SampledImage"; + case SPIRVShaderResourceAttribs::ResourceType::AtomicCounter: + return "AtomicCounter"; + case SPIRVShaderResourceAttribs::ResourceType::SeparateImage: + return "SeparateImage"; + case SPIRVShaderResourceAttribs::ResourceType::SeparateSampler: + return "SeparateSampler"; + case SPIRVShaderResourceAttribs::ResourceType::InputAttachment: + return "InputAttachment"; + case SPIRVShaderResourceAttribs::ResourceType::AccelerationStructure: + return "AccelerationStructure"; + case SPIRVShaderResourceAttribs::ResourceType::PushConstant: + return "PushConstant"; + default: + return "Unknown"; + } +} + +std::vector HLSLtoSPIRV(const char* FilePath, SHADER_TYPE ShaderType = SHADER_TYPE_PIXEL) +{ + ShaderCreateInfo ShaderCI; + ShaderCI.SourceLanguage = SHADER_SOURCE_LANGUAGE_HLSL; + ShaderCI.FilePath = FilePath; + ShaderCI.Desc = {"SPIRV test shader", ShaderType}; + ShaderCI.EntryPoint = "main"; + + RefCntAutoPtr pShaderSourceStreamFactory; + CreateDefaultShaderSourceStreamFactory("shaders/SPIRV", &pShaderSourceStreamFactory); + if (!pShaderSourceStreamFactory) + return {}; + + ShaderCI.pShaderSourceStreamFactory = pShaderSourceStreamFactory; + + GLSLangUtils::InitializeGlslang(); + auto SPIRV = GLSLangUtils::HLSLtoSPIRV(ShaderCI, GLSLangUtils::SpirvVersion::Vk100, nullptr, nullptr); + GLSLangUtils::FinalizeGlslang(); + + return SPIRV; +} + +std::vector GLSLtoSPIRV(const char* FilePath, SHADER_TYPE ShaderType = SHADER_TYPE_PIXEL) +{ + RefCntAutoPtr pShaderSourceStreamFactory; + CreateDefaultShaderSourceStreamFactory("shaders/SPIRV", &pShaderSourceStreamFactory); + if (!pShaderSourceStreamFactory) + return {}; + + RefCntAutoPtr pShaderSourceStream; + pShaderSourceStreamFactory->CreateInputStream(FilePath, &pShaderSourceStream); + if (!pShaderSourceStream) + return {}; + + auto ShaderSourceSize = pShaderSourceStream->GetSize(); + if (ShaderSourceSize == 0) + return {}; + + std::vector ShaderSource(ShaderSourceSize); + pShaderSourceStream->Read(ShaderSource.data(), ShaderSourceSize); + + // Ray tracing shaders require Vulkan 1.1 or higher SPIR-V version + GLSLangUtils::SpirvVersion Version = GLSLangUtils::SpirvVersion::Vk100; + if (ShaderType == SHADER_TYPE_RAY_GEN || + ShaderType == SHADER_TYPE_RAY_MISS || + ShaderType == SHADER_TYPE_RAY_CLOSEST_HIT || + ShaderType == SHADER_TYPE_RAY_ANY_HIT || + ShaderType == SHADER_TYPE_RAY_INTERSECTION || + ShaderType == SHADER_TYPE_CALLABLE) + { + Version = GLSLangUtils::SpirvVersion::Vk110_Spirv14; + } + + GLSLangUtils::GLSLtoSPIRVAttribs Attribs; + Attribs.ShaderType = ShaderType; + Attribs.ShaderSource = ShaderSource.data(); + Attribs.SourceCodeLen = static_cast(ShaderSourceSize); + Attribs.pShaderSourceStreamFactory = pShaderSourceStreamFactory; + Attribs.Version = Version; + Attribs.AssignBindings = true; + + GLSLangUtils::InitializeGlslang(); + auto SPIRV = GLSLangUtils::GLSLtoSPIRV(Attribs); + GLSLangUtils::FinalizeGlslang(); + + return SPIRV; +} + +void TestSPIRVResources(const char* FilePath, + const std::vector& RefResources, + SHADER_TYPE ShaderType = SHADER_TYPE_PIXEL, + const char* CombinedSamplerSuffix = nullptr, + bool IsGLSL = false) +{ + const auto SPIRV = IsGLSL ? GLSLtoSPIRV(FilePath, ShaderType) : HLSLtoSPIRV(FilePath, ShaderType); + ASSERT_FALSE(SPIRV.empty()) << "Failed to compile HLSL to SPIRV: " << FilePath; + + ShaderDesc ShaderDesc; + ShaderDesc.Name = "SPIRVResources test"; + ShaderDesc.ShaderType = ShaderType; + + std::string EntryPoint; + SPIRVShaderResources Resources{ + GetRawAllocator(), + SPIRV, + ShaderDesc, + CombinedSamplerSuffix, + false, // LoadShaderStageInputs + false, // LoadUniformBufferReflection + EntryPoint + }; + + LOG_INFO_MESSAGE("Testing shader:", FilePath); + if (CombinedSamplerSuffix != nullptr) + { + LOG_INFO_MESSAGE("Using CombinedSamplerSuffix:", CombinedSamplerSuffix); + } + LOG_INFO_MESSAGE("SPIRV Resources:\n", Resources.DumpResources()); + + EXPECT_EQ(size_t{Resources.GetTotalResources()}, RefResources.size()); + + std::unordered_map RefResourcesMap; + for (const auto& RefRes : RefResources) + { + RefResourcesMap[RefRes.Name] = &RefRes; + } + + for (Uint32 i = 0; i < Resources.GetTotalResources(); ++i) + { + const auto& Res = const_cast(Resources).GetResource(i); + const auto* pRefRes = RefResourcesMap[Res.Name]; + ASSERT_NE(pRefRes, nullptr) << "Resource '" << Res.Name << "' is not found in the reference list"; + + EXPECT_EQ(Res.ArraySize, pRefRes->ArraySize) << Res.Name; + EXPECT_STREQ(SPIRVShaderResourceTypeToString(Res.Type), SPIRVShaderResourceTypeToString(pRefRes->Type)) << Res.Name; + EXPECT_EQ(Res.ArraySize, pRefRes->ArraySize) << Res.Name; + EXPECT_EQ(Res.ResourceDim, pRefRes->ResourceDim) << Res.Name; + EXPECT_EQ(Res.IsMS, pRefRes->IsMS) << Res.Name; + EXPECT_EQ(Res.BufferStaticSize, pRefRes->BufferStaticSize) << Res.Name; + EXPECT_EQ(Res.BufferStride, pRefRes->BufferStride) << Res.Name; + } +} + +using SPIRVResourceType = SPIRVShaderResourceAttribs::ResourceType; + +TEST(SPIRVShaderResources, UniformBuffers) +{ + TestSPIRVResources("UniformBuffers.psh", + { + // CB0 is optimized away as it's not used in the shader + SPIRVShaderResourceAttribs{"CB1", SPIRVResourceType::UniformBuffer, 1, RESOURCE_DIM_BUFFER, 0, 48, 0}, + SPIRVShaderResourceAttribs{"CB2", SPIRVResourceType::UniformBuffer, 1, RESOURCE_DIM_BUFFER, 0, 16, 0}, + }); +} + +TEST(SPIRVShaderResources, StorageBuffers) +{ + TestSPIRVResources("StorageBuffers.psh", + { + // StructuredBuffers have BufferStaticSize=0 (runtime array) and BufferStride is the element size + SPIRVShaderResourceAttribs{"g_ROBuffer", SPIRVResourceType::ROStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 32}, + SPIRVShaderResourceAttribs{"g_RWBuffer", SPIRVResourceType::RWStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 64}, + // ByteAddressBuffers also have BufferStaticSize=0 and BufferStride=4 (uint size) + SPIRVShaderResourceAttribs{"g_ROAtomicBuffer", SPIRVResourceType::ROStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 4}, + SPIRVShaderResourceAttribs{"g_RWAtomicBuffer", SPIRVResourceType::RWStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 4}, + }); +} + +TEST(SPIRVShaderResources, TexelBuffers) +{ + TestSPIRVResources("TexelBuffers.psh", + { + SPIRVShaderResourceAttribs{"g_UniformTexelBuffer", SPIRVResourceType::UniformTexelBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 0}, + SPIRVShaderResourceAttribs{"g_StorageTexelBuffer", SPIRVResourceType::StorageTexelBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 0}, + }); +} + +TEST(SPIRVShaderResources, Textures) +{ + TestSPIRVResources("Textures.psh", + { + // When textures and samplers are declared separately in HLSL, they are compiled as separate_images + // instead of sampled_images. This is the correct behavior for separate sampler/texture declarations. + SPIRVShaderResourceAttribs{"g_SampledImage", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_2D, 0, 0, 0}, + SPIRVShaderResourceAttribs{"g_SampledImageMS", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_2D, 1, 0, 0}, + SPIRVShaderResourceAttribs{"g_SampledImage3D", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_3D, 0, 0, 0}, + SPIRVShaderResourceAttribs{"g_SampledImageCube", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_CUBE, 0, 0, 0}, + SPIRVShaderResourceAttribs{"g_Sampler", SPIRVResourceType::SeparateSampler, 1, RESOURCE_DIM_UNDEFINED, 0, 0, 0}, + SPIRVShaderResourceAttribs{"g_SeparateImage", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_2D, 0, 0, 0}, + // Combined sampler: g_Texture and g_Texture_sampler + // Note: Even with CombinedSamplerSuffix, SPIRV may still classify them as separate_images + // if they are declared separately. The CombinedSamplerSuffix is mainly used for naming convention. + SPIRVShaderResourceAttribs{"g_Texture", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_2D, 0, 0, 0}, + SPIRVShaderResourceAttribs{"g_Texture_sampler", SPIRVResourceType::SeparateSampler, 1, RESOURCE_DIM_UNDEFINED, 0, 0, 0}, + }); +} + +TEST(SPIRVShaderResources, StorageImages) +{ + TestSPIRVResources("StorageImages.psh", + { + // Note: HLSL does not support RWTextureCube, so we only test 2D, 2DArray, and 3D storage images + SPIRVShaderResourceAttribs{"g_RWImage2D", SPIRVResourceType::StorageImage, 1, RESOURCE_DIM_TEX_2D, 0, 0, 0}, + SPIRVShaderResourceAttribs{"g_RWImage2DArray", SPIRVResourceType::StorageImage, 1, RESOURCE_DIM_TEX_2D_ARRAY, 0, 0, 0}, + SPIRVShaderResourceAttribs{"g_RWImage3D", SPIRVResourceType::StorageImage, 1, RESOURCE_DIM_TEX_3D, 0, 0, 0}, + }); +} + +TEST(SPIRVShaderResources, AtomicCounters) +{ + // Use GLSL for atomic counters. Note: Vulkan does not support atomic_uint (AtomicCounter storage class). + // We use a storage buffer with atomic operations to simulate atomic counters. + // This will be reflected as RWStorageBuffer, not AtomicCounter. + // The resource name is the buffer block name (AtomicCounterBuffer), not the instance name (g_AtomicCounter). + TestSPIRVResources("AtomicCounters.glsl", + { + SPIRVShaderResourceAttribs{"AtomicCounterBuffer", SPIRVResourceType::RWStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 4, 0}, + }, + SHADER_TYPE_PIXEL, + nullptr, + true); // IsGLSL = true +} + +TEST(SPIRVShaderResources, InputAttachments) +{ + TestSPIRVResources("InputAttachments.psh", + { + SPIRVShaderResourceAttribs{"g_InputAttachment", SPIRVResourceType::InputAttachment, 1, RESOURCE_DIM_UNDEFINED, 0, 0, 0}, + }); +} + +TEST(SPIRVShaderResources, AccelerationStructures) +{ + // Use GLSL for acceleration structures since HLSLtoSPIRV doesn't support raytracing shaders + // Acceleration structures are used in raytracing shaders, so we use SHADER_TYPE_RAY_GEN + // The ray gen shader uses traceRayEXT with g_AccelStruct to ensure it's not optimized away + TestSPIRVResources("AccelerationStructures.glsl", + { + SPIRVShaderResourceAttribs{"g_AccelStruct", SPIRVResourceType::AccelerationStructure, 1, RESOURCE_DIM_UNDEFINED, 0, 0, 0}, + }, + SHADER_TYPE_RAY_GEN, + nullptr, + true); // IsGLSL = true +} + +TEST(SPIRVShaderResources, PushConstants) +{ + // Push constant ArraySize represents the number of 32-bit words, not array elements + // PushConstants struct: float4x4 (16 floats) + float4 (4 floats) + float2 (2 floats) + float (1 float) + uint (1 uint) + // Total: 16 + 4 + 2 + 1 + 1 = 24 floats/uints = 24 * 4 bytes = 96 bytes = 24 words + TestSPIRVResources("PushConstants.psh", + { + SPIRVShaderResourceAttribs{"PushConstants", SPIRVResourceType::PushConstant, 24, RESOURCE_DIM_BUFFER, 0, 96, 0}, + }); +} + +TEST(SPIRVShaderResources, MixedResources) +{ + TestSPIRVResources("MixedResources.psh", + { + // UniformBuff: float4x4 (64 bytes) + float4 (16 bytes) = 80 bytes + SPIRVShaderResourceAttribs{"UniformBuff", SPIRVResourceType::UniformBuffer, 1, RESOURCE_DIM_BUFFER, 0, 80, 0}, + // ROStorageBuff: StructuredBuffer where BufferData = float4[4] = 64 bytes + // StructuredBuffers have BufferStaticSize=0 (runtime array) and BufferStride is the element size + SPIRVShaderResourceAttribs{"ROStorageBuff", SPIRVResourceType::ROStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 64}, + // RWStorageBuff: same as ROStorageBuff + SPIRVShaderResourceAttribs{"RWStorageBuff", SPIRVResourceType::RWStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 64}, + // SampledTex: When Texture2D and SamplerState are declared separately, they are compiled as SeparateImage + SPIRVShaderResourceAttribs{"SampledTex", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_2D, 0, 0, 0}, + SPIRVShaderResourceAttribs{"StorageTex", SPIRVResourceType::StorageImage, 1, RESOURCE_DIM_TEX_2D, 0, 0, 0}, + SPIRVShaderResourceAttribs{"Sampler", SPIRVResourceType::SeparateSampler, 1, RESOURCE_DIM_UNDEFINED, 0, 0, 0}, + // PushConstants: float2 (2 floats) + float (1 float) + uint (1 uint) = 4 words = 16 bytes + SPIRVShaderResourceAttribs{"PushConstants", SPIRVResourceType::PushConstant, 4, RESOURCE_DIM_BUFFER, 0, 16, 0}, + }); +} + +} // namespace \ No newline at end of file From b9c461aa20cff4f8c602e2739513c5e03685477e Mon Sep 17 00:00:00 2001 From: hzqst <113660872@qq.com> Date: Fri, 12 Dec 2025 13:49:47 +0800 Subject: [PATCH 03/20] Fixed an issue that diligent_spirv_cross::SPIRType::BaseType::Struct recognized as RESOURCE_DIM_UNDEFINED Fixed an issue that UniformTexelBuffer error out when DumpResources. --- .../include/SPIRVShaderResources.hpp | 9 ++++ .../ShaderTools/src/SPIRVShaderResources.cpp | 42 +++++++++++++++++-- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/Graphics/ShaderTools/include/SPIRVShaderResources.hpp b/Graphics/ShaderTools/include/SPIRVShaderResources.hpp index 576971cb7e..7d43747b9b 100644 --- a/Graphics/ShaderTools/include/SPIRVShaderResources.hpp +++ b/Graphics/ShaderTools/include/SPIRVShaderResources.hpp @@ -117,6 +117,15 @@ struct SPIRVShaderResourceAttribs ResourceType _Type, Uint32 _BufferStaticSize) noexcept; + // Test-only constructor for creating reference resources + SPIRVShaderResourceAttribs(const char* _Name, + ResourceType _Type, + Uint16 _ArraySize, + RESOURCE_DIMENSION _ResourceDim, + Uint8 _IsMS, + Uint32 _BufferStaticSize, + Uint32 _BufferStride) noexcept; + ShaderResourceDesc GetResourceDesc() const { return ShaderResourceDesc{Name, GetShaderResourceType(Type), ArraySize}; diff --git a/Graphics/ShaderTools/src/SPIRVShaderResources.cpp b/Graphics/ShaderTools/src/SPIRVShaderResources.cpp index 92c15dd470..b66b46a8b6 100644 --- a/Graphics/ShaderTools/src/SPIRVShaderResources.cpp +++ b/Graphics/ShaderTools/src/SPIRVShaderResources.cpp @@ -74,6 +74,11 @@ static RESOURCE_DIMENSION GetResourceDimension(const diligent_spirv_cross::Compi default: return RESOURCE_DIM_UNDEFINED; } } + else if (type.basetype == diligent_spirv_cross::SPIRType::BaseType::Struct) + { + // Uniform buffers and storage buffers are Struct types + return RESOURCE_DIM_BUFFER; + } else { return RESOURCE_DIM_UNDEFINED; @@ -145,6 +150,27 @@ SPIRVShaderResourceAttribs::SPIRVShaderResourceAttribs(const char* _Name, // clang-format on {} +// Test-only constructor for creating reference resources +SPIRVShaderResourceAttribs::SPIRVShaderResourceAttribs(const char* _Name, + ResourceType _Type, + Uint16 _ArraySize, + RESOURCE_DIMENSION _ResourceDim, + Uint8 _IsMS, + Uint32 _BufferStaticSize, + Uint32 _BufferStride) noexcept : + // clang-format off + Name {_Name}, + ArraySize {_ArraySize}, + Type {_Type}, + ResourceDim {static_cast(_ResourceDim)}, + IsMS {_IsMS}, + BindingDecorationOffset {0}, // Not used in tests + DescriptorSetDecorationOffset {0}, // Not used in tests + BufferStaticSize {_BufferStaticSize}, + BufferStride {_BufferStride} +// clang-format on +{} + SHADER_RESOURCE_TYPE SPIRVShaderResourceAttribs::GetShaderResourceType(ResourceType Type) { @@ -1039,9 +1065,19 @@ std::string SPIRVShaderResources::DumpResources() const }, [&](const SPIRVShaderResourceAttribs& SepImg, Uint32) // { - VERIFY(SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage, "Unexpected resource type"); - ss << std::endl - << std::setw(3) << ResNum << " Separate Img "; + VERIFY(SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage || + SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer, + "Unexpected resource type"); + if (SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer) + { + ss << std::endl + << std::setw(3) << ResNum << " Uniform Txl Buff "; + } + else + { + ss << std::endl + << std::setw(3) << ResNum << " Separate Img "; + } DumpResource(SepImg); }, [&](const SPIRVShaderResourceAttribs& InptAtt, Uint32) // From 743e7f24464ad4174b3cae441ed9a1959d37dd8b Mon Sep 17 00:00:00 2001 From: hzqst <113660872@qq.com> Date: Fri, 12 Dec 2025 13:53:12 +0800 Subject: [PATCH 04/20] fix formatting --- .../ShaderTools/SPIRVShaderResourcesTest.cpp | 163 +++++++++--------- 1 file changed, 81 insertions(+), 82 deletions(-) diff --git a/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp b/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp index 205c443f40..b93884e63a 100644 --- a/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp +++ b/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp @@ -131,12 +131,12 @@ std::vector GLSLtoSPIRV(const char* FilePath, SHADER_TYPE ShaderType = } GLSLangUtils::GLSLtoSPIRVAttribs Attribs; - Attribs.ShaderType = ShaderType; - Attribs.ShaderSource = ShaderSource.data(); - Attribs.SourceCodeLen = static_cast(ShaderSourceSize); - Attribs.pShaderSourceStreamFactory = pShaderSourceStreamFactory; - Attribs.Version = Version; - Attribs.AssignBindings = true; + Attribs.ShaderType = ShaderType; + Attribs.ShaderSource = ShaderSource.data(); + Attribs.SourceCodeLen = static_cast(ShaderSourceSize); + Attribs.pShaderSourceStreamFactory = pShaderSourceStreamFactory; + Attribs.Version = Version; + Attribs.AssignBindings = true; GLSLangUtils::InitializeGlslang(); auto SPIRV = GLSLangUtils::GLSLtoSPIRV(Attribs); @@ -147,9 +147,9 @@ std::vector GLSLtoSPIRV(const char* FilePath, SHADER_TYPE ShaderType = void TestSPIRVResources(const char* FilePath, const std::vector& RefResources, - SHADER_TYPE ShaderType = SHADER_TYPE_PIXEL, + SHADER_TYPE ShaderType = SHADER_TYPE_PIXEL, const char* CombinedSamplerSuffix = nullptr, - bool IsGLSL = false) + bool IsGLSL = false) { const auto SPIRV = IsGLSL ? GLSLtoSPIRV(FilePath, ShaderType) : HLSLtoSPIRV(FilePath, ShaderType); ASSERT_FALSE(SPIRV.empty()) << "Failed to compile HLSL to SPIRV: " << FilePath; @@ -158,7 +158,7 @@ void TestSPIRVResources(const char* FilePath, ShaderDesc.Name = "SPIRVResources test"; ShaderDesc.ShaderType = ShaderType; - std::string EntryPoint; + std::string EntryPoint; SPIRVShaderResources Resources{ GetRawAllocator(), SPIRV, @@ -166,8 +166,7 @@ void TestSPIRVResources(const char* FilePath, CombinedSamplerSuffix, false, // LoadShaderStageInputs false, // LoadUniformBufferReflection - EntryPoint - }; + EntryPoint}; LOG_INFO_MESSAGE("Testing shader:", FilePath); if (CombinedSamplerSuffix != nullptr) @@ -205,64 +204,64 @@ using SPIRVResourceType = SPIRVShaderResourceAttribs::ResourceType; TEST(SPIRVShaderResources, UniformBuffers) { TestSPIRVResources("UniformBuffers.psh", - { - // CB0 is optimized away as it's not used in the shader - SPIRVShaderResourceAttribs{"CB1", SPIRVResourceType::UniformBuffer, 1, RESOURCE_DIM_BUFFER, 0, 48, 0}, - SPIRVShaderResourceAttribs{"CB2", SPIRVResourceType::UniformBuffer, 1, RESOURCE_DIM_BUFFER, 0, 16, 0}, - }); + { + // CB0 is optimized away as it's not used in the shader + SPIRVShaderResourceAttribs{"CB1", SPIRVResourceType::UniformBuffer, 1, RESOURCE_DIM_BUFFER, 0, 48, 0}, + SPIRVShaderResourceAttribs{"CB2", SPIRVResourceType::UniformBuffer, 1, RESOURCE_DIM_BUFFER, 0, 16, 0}, + }); } TEST(SPIRVShaderResources, StorageBuffers) { TestSPIRVResources("StorageBuffers.psh", - { - // StructuredBuffers have BufferStaticSize=0 (runtime array) and BufferStride is the element size - SPIRVShaderResourceAttribs{"g_ROBuffer", SPIRVResourceType::ROStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 32}, - SPIRVShaderResourceAttribs{"g_RWBuffer", SPIRVResourceType::RWStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 64}, - // ByteAddressBuffers also have BufferStaticSize=0 and BufferStride=4 (uint size) - SPIRVShaderResourceAttribs{"g_ROAtomicBuffer", SPIRVResourceType::ROStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 4}, - SPIRVShaderResourceAttribs{"g_RWAtomicBuffer", SPIRVResourceType::RWStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 4}, - }); + { + // StructuredBuffers have BufferStaticSize=0 (runtime array) and BufferStride is the element size + SPIRVShaderResourceAttribs{"g_ROBuffer", SPIRVResourceType::ROStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 32}, + SPIRVShaderResourceAttribs{"g_RWBuffer", SPIRVResourceType::RWStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 64}, + // ByteAddressBuffers also have BufferStaticSize=0 and BufferStride=4 (uint size) + SPIRVShaderResourceAttribs{"g_ROAtomicBuffer", SPIRVResourceType::ROStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 4}, + SPIRVShaderResourceAttribs{"g_RWAtomicBuffer", SPIRVResourceType::RWStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 4}, + }); } TEST(SPIRVShaderResources, TexelBuffers) { TestSPIRVResources("TexelBuffers.psh", - { - SPIRVShaderResourceAttribs{"g_UniformTexelBuffer", SPIRVResourceType::UniformTexelBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 0}, - SPIRVShaderResourceAttribs{"g_StorageTexelBuffer", SPIRVResourceType::StorageTexelBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 0}, - }); + { + SPIRVShaderResourceAttribs{"g_UniformTexelBuffer", SPIRVResourceType::UniformTexelBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 0}, + SPIRVShaderResourceAttribs{"g_StorageTexelBuffer", SPIRVResourceType::StorageTexelBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 0}, + }); } TEST(SPIRVShaderResources, Textures) { TestSPIRVResources("Textures.psh", - { - // When textures and samplers are declared separately in HLSL, they are compiled as separate_images - // instead of sampled_images. This is the correct behavior for separate sampler/texture declarations. - SPIRVShaderResourceAttribs{"g_SampledImage", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_2D, 0, 0, 0}, - SPIRVShaderResourceAttribs{"g_SampledImageMS", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_2D, 1, 0, 0}, - SPIRVShaderResourceAttribs{"g_SampledImage3D", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_3D, 0, 0, 0}, - SPIRVShaderResourceAttribs{"g_SampledImageCube", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_CUBE, 0, 0, 0}, - SPIRVShaderResourceAttribs{"g_Sampler", SPIRVResourceType::SeparateSampler, 1, RESOURCE_DIM_UNDEFINED, 0, 0, 0}, - SPIRVShaderResourceAttribs{"g_SeparateImage", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_2D, 0, 0, 0}, - // Combined sampler: g_Texture and g_Texture_sampler - // Note: Even with CombinedSamplerSuffix, SPIRV may still classify them as separate_images - // if they are declared separately. The CombinedSamplerSuffix is mainly used for naming convention. - SPIRVShaderResourceAttribs{"g_Texture", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_2D, 0, 0, 0}, - SPIRVShaderResourceAttribs{"g_Texture_sampler", SPIRVResourceType::SeparateSampler, 1, RESOURCE_DIM_UNDEFINED, 0, 0, 0}, - }); + { + // When textures and samplers are declared separately in HLSL, they are compiled as separate_images + // instead of sampled_images. This is the correct behavior for separate sampler/texture declarations. + SPIRVShaderResourceAttribs{"g_SampledImage", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_2D, 0, 0, 0}, + SPIRVShaderResourceAttribs{"g_SampledImageMS", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_2D, 1, 0, 0}, + SPIRVShaderResourceAttribs{"g_SampledImage3D", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_3D, 0, 0, 0}, + SPIRVShaderResourceAttribs{"g_SampledImageCube", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_CUBE, 0, 0, 0}, + SPIRVShaderResourceAttribs{"g_Sampler", SPIRVResourceType::SeparateSampler, 1, RESOURCE_DIM_UNDEFINED, 0, 0, 0}, + SPIRVShaderResourceAttribs{"g_SeparateImage", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_2D, 0, 0, 0}, + // Combined sampler: g_Texture and g_Texture_sampler + // Note: Even with CombinedSamplerSuffix, SPIRV may still classify them as separate_images + // if they are declared separately. The CombinedSamplerSuffix is mainly used for naming convention. + SPIRVShaderResourceAttribs{"g_Texture", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_2D, 0, 0, 0}, + SPIRVShaderResourceAttribs{"g_Texture_sampler", SPIRVResourceType::SeparateSampler, 1, RESOURCE_DIM_UNDEFINED, 0, 0, 0}, + }); } TEST(SPIRVShaderResources, StorageImages) { TestSPIRVResources("StorageImages.psh", - { - // Note: HLSL does not support RWTextureCube, so we only test 2D, 2DArray, and 3D storage images - SPIRVShaderResourceAttribs{"g_RWImage2D", SPIRVResourceType::StorageImage, 1, RESOURCE_DIM_TEX_2D, 0, 0, 0}, - SPIRVShaderResourceAttribs{"g_RWImage2DArray", SPIRVResourceType::StorageImage, 1, RESOURCE_DIM_TEX_2D_ARRAY, 0, 0, 0}, - SPIRVShaderResourceAttribs{"g_RWImage3D", SPIRVResourceType::StorageImage, 1, RESOURCE_DIM_TEX_3D, 0, 0, 0}, - }); + { + // Note: HLSL does not support RWTextureCube, so we only test 2D, 2DArray, and 3D storage images + SPIRVShaderResourceAttribs{"g_RWImage2D", SPIRVResourceType::StorageImage, 1, RESOURCE_DIM_TEX_2D, 0, 0, 0}, + SPIRVShaderResourceAttribs{"g_RWImage2DArray", SPIRVResourceType::StorageImage, 1, RESOURCE_DIM_TEX_2D_ARRAY, 0, 0, 0}, + SPIRVShaderResourceAttribs{"g_RWImage3D", SPIRVResourceType::StorageImage, 1, RESOURCE_DIM_TEX_3D, 0, 0, 0}, + }); } TEST(SPIRVShaderResources, AtomicCounters) @@ -272,20 +271,20 @@ TEST(SPIRVShaderResources, AtomicCounters) // This will be reflected as RWStorageBuffer, not AtomicCounter. // The resource name is the buffer block name (AtomicCounterBuffer), not the instance name (g_AtomicCounter). TestSPIRVResources("AtomicCounters.glsl", - { - SPIRVShaderResourceAttribs{"AtomicCounterBuffer", SPIRVResourceType::RWStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 4, 0}, - }, - SHADER_TYPE_PIXEL, - nullptr, - true); // IsGLSL = true + { + SPIRVShaderResourceAttribs{"AtomicCounterBuffer", SPIRVResourceType::RWStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 4, 0}, + }, + SHADER_TYPE_PIXEL, + nullptr, + true); // IsGLSL = true } TEST(SPIRVShaderResources, InputAttachments) { TestSPIRVResources("InputAttachments.psh", - { - SPIRVShaderResourceAttribs{"g_InputAttachment", SPIRVResourceType::InputAttachment, 1, RESOURCE_DIM_UNDEFINED, 0, 0, 0}, - }); + { + SPIRVShaderResourceAttribs{"g_InputAttachment", SPIRVResourceType::InputAttachment, 1, RESOURCE_DIM_UNDEFINED, 0, 0, 0}, + }); } TEST(SPIRVShaderResources, AccelerationStructures) @@ -294,12 +293,12 @@ TEST(SPIRVShaderResources, AccelerationStructures) // Acceleration structures are used in raytracing shaders, so we use SHADER_TYPE_RAY_GEN // The ray gen shader uses traceRayEXT with g_AccelStruct to ensure it's not optimized away TestSPIRVResources("AccelerationStructures.glsl", - { - SPIRVShaderResourceAttribs{"g_AccelStruct", SPIRVResourceType::AccelerationStructure, 1, RESOURCE_DIM_UNDEFINED, 0, 0, 0}, - }, - SHADER_TYPE_RAY_GEN, - nullptr, - true); // IsGLSL = true + { + SPIRVShaderResourceAttribs{"g_AccelStruct", SPIRVResourceType::AccelerationStructure, 1, RESOURCE_DIM_UNDEFINED, 0, 0, 0}, + }, + SHADER_TYPE_RAY_GEN, + nullptr, + true); // IsGLSL = true } TEST(SPIRVShaderResources, PushConstants) @@ -308,29 +307,29 @@ TEST(SPIRVShaderResources, PushConstants) // PushConstants struct: float4x4 (16 floats) + float4 (4 floats) + float2 (2 floats) + float (1 float) + uint (1 uint) // Total: 16 + 4 + 2 + 1 + 1 = 24 floats/uints = 24 * 4 bytes = 96 bytes = 24 words TestSPIRVResources("PushConstants.psh", - { - SPIRVShaderResourceAttribs{"PushConstants", SPIRVResourceType::PushConstant, 24, RESOURCE_DIM_BUFFER, 0, 96, 0}, - }); + { + SPIRVShaderResourceAttribs{"PushConstants", SPIRVResourceType::PushConstant, 24, RESOURCE_DIM_BUFFER, 0, 96, 0}, + }); } TEST(SPIRVShaderResources, MixedResources) { TestSPIRVResources("MixedResources.psh", - { - // UniformBuff: float4x4 (64 bytes) + float4 (16 bytes) = 80 bytes - SPIRVShaderResourceAttribs{"UniformBuff", SPIRVResourceType::UniformBuffer, 1, RESOURCE_DIM_BUFFER, 0, 80, 0}, - // ROStorageBuff: StructuredBuffer where BufferData = float4[4] = 64 bytes - // StructuredBuffers have BufferStaticSize=0 (runtime array) and BufferStride is the element size - SPIRVShaderResourceAttribs{"ROStorageBuff", SPIRVResourceType::ROStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 64}, - // RWStorageBuff: same as ROStorageBuff - SPIRVShaderResourceAttribs{"RWStorageBuff", SPIRVResourceType::RWStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 64}, - // SampledTex: When Texture2D and SamplerState are declared separately, they are compiled as SeparateImage - SPIRVShaderResourceAttribs{"SampledTex", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_2D, 0, 0, 0}, - SPIRVShaderResourceAttribs{"StorageTex", SPIRVResourceType::StorageImage, 1, RESOURCE_DIM_TEX_2D, 0, 0, 0}, - SPIRVShaderResourceAttribs{"Sampler", SPIRVResourceType::SeparateSampler, 1, RESOURCE_DIM_UNDEFINED, 0, 0, 0}, - // PushConstants: float2 (2 floats) + float (1 float) + uint (1 uint) = 4 words = 16 bytes - SPIRVShaderResourceAttribs{"PushConstants", SPIRVResourceType::PushConstant, 4, RESOURCE_DIM_BUFFER, 0, 16, 0}, - }); + { + // UniformBuff: float4x4 (64 bytes) + float4 (16 bytes) = 80 bytes + SPIRVShaderResourceAttribs{"UniformBuff", SPIRVResourceType::UniformBuffer, 1, RESOURCE_DIM_BUFFER, 0, 80, 0}, + // ROStorageBuff: StructuredBuffer where BufferData = float4[4] = 64 bytes + // StructuredBuffers have BufferStaticSize=0 (runtime array) and BufferStride is the element size + SPIRVShaderResourceAttribs{"ROStorageBuff", SPIRVResourceType::ROStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 64}, + // RWStorageBuff: same as ROStorageBuff + SPIRVShaderResourceAttribs{"RWStorageBuff", SPIRVResourceType::RWStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 64}, + // SampledTex: When Texture2D and SamplerState are declared separately, they are compiled as SeparateImage + SPIRVShaderResourceAttribs{"SampledTex", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_2D, 0, 0, 0}, + SPIRVShaderResourceAttribs{"StorageTex", SPIRVResourceType::StorageImage, 1, RESOURCE_DIM_TEX_2D, 0, 0, 0}, + SPIRVShaderResourceAttribs{"Sampler", SPIRVResourceType::SeparateSampler, 1, RESOURCE_DIM_UNDEFINED, 0, 0, 0}, + // PushConstants: float2 (2 floats) + float (1 float) + uint (1 uint) = 4 words = 16 bytes + SPIRVShaderResourceAttribs{"PushConstants", SPIRVResourceType::PushConstant, 4, RESOURCE_DIM_BUFFER, 0, 16, 0}, + }); } } // namespace \ No newline at end of file From e1de8b37795b21651e67242aee496031c5dfa7c6 Mon Sep 17 00:00:00 2001 From: hzqst <113660872@qq.com> Date: Fri, 12 Dec 2025 14:23:13 +0800 Subject: [PATCH 05/20] moving it to SPIRVShaderResourceAttribs, make it static member ResourceTypeToString --- .../include/SPIRVShaderResources.hpp | 1 + .../ShaderTools/src/SPIRVShaderResources.cpp | 35 ++++++++++++++++++ .../ShaderTools/SPIRVShaderResourcesTest.cpp | 37 +------------------ 3 files changed, 37 insertions(+), 36 deletions(-) diff --git a/Graphics/ShaderTools/include/SPIRVShaderResources.hpp b/Graphics/ShaderTools/include/SPIRVShaderResources.hpp index 7d43747b9b..2d54bc5e70 100644 --- a/Graphics/ShaderTools/include/SPIRVShaderResources.hpp +++ b/Graphics/ShaderTools/include/SPIRVShaderResources.hpp @@ -85,6 +85,7 @@ struct SPIRVShaderResourceAttribs static SHADER_RESOURCE_TYPE GetShaderResourceType(ResourceType Type); static PIPELINE_RESOURCE_FLAGS GetPipelineResourceFlags(ResourceType Type); + static const char* ResourceTypeToString(ResourceType Type); // clang-format off diff --git a/Graphics/ShaderTools/src/SPIRVShaderResources.cpp b/Graphics/ShaderTools/src/SPIRVShaderResources.cpp index b66b46a8b6..240a233700 100644 --- a/Graphics/ShaderTools/src/SPIRVShaderResources.cpp +++ b/Graphics/ShaderTools/src/SPIRVShaderResources.cpp @@ -248,6 +248,41 @@ PIPELINE_RESOURCE_FLAGS SPIRVShaderResourceAttribs::GetPipelineResourceFlags(Res } } +const char* SPIRVShaderResourceAttribs::ResourceTypeToString(SPIRVShaderResourceAttribs::ResourceType Type) +{ + switch (Type) + { + case SPIRVShaderResourceAttribs::ResourceType::UniformBuffer: + return "UniformBuffer"; + case SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer: + return "ROStorageBuffer"; + case SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer: + return "RWStorageBuffer"; + case SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer: + return "UniformTexelBuffer"; + case SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer: + return "StorageTexelBuffer"; + case SPIRVShaderResourceAttribs::ResourceType::StorageImage: + return "StorageImage"; + case SPIRVShaderResourceAttribs::ResourceType::SampledImage: + return "SampledImage"; + case SPIRVShaderResourceAttribs::ResourceType::AtomicCounter: + return "AtomicCounter"; + case SPIRVShaderResourceAttribs::ResourceType::SeparateImage: + return "SeparateImage"; + case SPIRVShaderResourceAttribs::ResourceType::SeparateSampler: + return "SeparateSampler"; + case SPIRVShaderResourceAttribs::ResourceType::InputAttachment: + return "InputAttachment"; + case SPIRVShaderResourceAttribs::ResourceType::AccelerationStructure: + return "AccelerationStructure"; + case SPIRVShaderResourceAttribs::ResourceType::PushConstant: + return "PushConstant"; + default: + return "Unknown"; + } +} + spv::ExecutionModel ShaderTypeToSpvExecutionModel(SHADER_TYPE ShaderType) { static_assert(SHADER_TYPE_LAST == 0x4000, "Please handle the new shader type in the switch below"); diff --git a/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp b/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp index b93884e63a..822d936615 100644 --- a/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp +++ b/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp @@ -42,41 +42,6 @@ using namespace Diligent::Testing; namespace { -const char* SPIRVShaderResourceTypeToString(SPIRVShaderResourceAttribs::ResourceType Type) -{ - switch (Type) - { - case SPIRVShaderResourceAttribs::ResourceType::UniformBuffer: - return "UniformBuffer"; - case SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer: - return "ROStorageBuffer"; - case SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer: - return "RWStorageBuffer"; - case SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer: - return "UniformTexelBuffer"; - case SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer: - return "StorageTexelBuffer"; - case SPIRVShaderResourceAttribs::ResourceType::StorageImage: - return "StorageImage"; - case SPIRVShaderResourceAttribs::ResourceType::SampledImage: - return "SampledImage"; - case SPIRVShaderResourceAttribs::ResourceType::AtomicCounter: - return "AtomicCounter"; - case SPIRVShaderResourceAttribs::ResourceType::SeparateImage: - return "SeparateImage"; - case SPIRVShaderResourceAttribs::ResourceType::SeparateSampler: - return "SeparateSampler"; - case SPIRVShaderResourceAttribs::ResourceType::InputAttachment: - return "InputAttachment"; - case SPIRVShaderResourceAttribs::ResourceType::AccelerationStructure: - return "AccelerationStructure"; - case SPIRVShaderResourceAttribs::ResourceType::PushConstant: - return "PushConstant"; - default: - return "Unknown"; - } -} - std::vector HLSLtoSPIRV(const char* FilePath, SHADER_TYPE ShaderType = SHADER_TYPE_PIXEL) { ShaderCreateInfo ShaderCI; @@ -190,7 +155,7 @@ void TestSPIRVResources(const char* FilePath, ASSERT_NE(pRefRes, nullptr) << "Resource '" << Res.Name << "' is not found in the reference list"; EXPECT_EQ(Res.ArraySize, pRefRes->ArraySize) << Res.Name; - EXPECT_STREQ(SPIRVShaderResourceTypeToString(Res.Type), SPIRVShaderResourceTypeToString(pRefRes->Type)) << Res.Name; + EXPECT_STREQ(SPIRVShaderResourceAttribs::ResourceTypeToString(Res.Type), SPIRVShaderResourceAttribs::ResourceTypeToString(pRefRes->Type)) << Res.Name; EXPECT_EQ(Res.ArraySize, pRefRes->ArraySize) << Res.Name; EXPECT_EQ(Res.ResourceDim, pRefRes->ResourceDim) << Res.Name; EXPECT_EQ(Res.IsMS, pRefRes->IsMS) << Res.Name; From d13d1357b26e394768e059954d55fe337236a13c Mon Sep 17 00:00:00 2001 From: hzqst <113660872@qq.com> Date: Fri, 12 Dec 2025 14:53:12 +0800 Subject: [PATCH 06/20] Add SPIRVShaderResourceRefAttribs. Add compiled SPIRV. --- .../SPIRV/AccelerationStructures.glsl.spv | Bin 0 -> 1424 bytes .../shaders/SPIRV/AtomicCounters.glsl.spv | Bin 0 -> 1140 bytes .../shaders/SPIRV/MixedResources.psh.spv | Bin 0 -> 2764 bytes .../shaders/SPIRV/PushConstants.psh.spv | Bin 0 -> 1192 bytes .../shaders/SPIRV/StorageBuffers.psh.spv | Bin 0 -> 1844 bytes .../shaders/SPIRV/StorageImages.psh.spv | Bin 0 -> 1212 bytes .../assets/shaders/SPIRV/TexelBuffers.psh.spv | Bin 0 -> 796 bytes .../assets/shaders/SPIRV/Textures.psh.spv | Bin 0 -> 2068 bytes .../shaders/SPIRV/UniformBuffers.psh.spv | Bin 0 -> 1012 bytes .../ShaderTools/SPIRVShaderResourcesTest.cpp | 180 ++++++++++++++---- 10 files changed, 140 insertions(+), 40 deletions(-) create mode 100644 Tests/DiligentCoreTest/assets/shaders/SPIRV/AccelerationStructures.glsl.spv create mode 100644 Tests/DiligentCoreTest/assets/shaders/SPIRV/AtomicCounters.glsl.spv create mode 100644 Tests/DiligentCoreTest/assets/shaders/SPIRV/MixedResources.psh.spv create mode 100644 Tests/DiligentCoreTest/assets/shaders/SPIRV/PushConstants.psh.spv create mode 100644 Tests/DiligentCoreTest/assets/shaders/SPIRV/StorageBuffers.psh.spv create mode 100644 Tests/DiligentCoreTest/assets/shaders/SPIRV/StorageImages.psh.spv create mode 100644 Tests/DiligentCoreTest/assets/shaders/SPIRV/TexelBuffers.psh.spv create mode 100644 Tests/DiligentCoreTest/assets/shaders/SPIRV/Textures.psh.spv create mode 100644 Tests/DiligentCoreTest/assets/shaders/SPIRV/UniformBuffers.psh.spv diff --git a/Tests/DiligentCoreTest/assets/shaders/SPIRV/AccelerationStructures.glsl.spv b/Tests/DiligentCoreTest/assets/shaders/SPIRV/AccelerationStructures.glsl.spv new file mode 100644 index 0000000000000000000000000000000000000000..8185adc4129e606387b9baba7607912f310f893e GIT binary patch literal 1424 zcmY+D%WG3n5XL9(Hm#|(FW)AOui6-2ZLL-<0VRq7qY-f6lH}m~GflrY&yorp>aJwnqI~@bLbV zpcn21{a)B?cUy{0TTG$VTBBBe-QOy&tX^hk&Jr#Gz9}2G&$DJp>94|e7smnNuy9eh zDkSuaYyGATN#(58f_u-O{&$q6%xB2qHUG0a@xO4vT zjrQAZ=fRh>Q`*1NYqzKhn|gM`z0OX!<#JM6E2uP^+nq+gH)!@{R~1M76T%nug-tKm zUn84+ivoflyWlLd8Ffmp1=qDXeO`K6TwYjEd`2raae3KeTH(N)?5yMUCn27*;kb3; zC$+`|_>IV>W;o(=T8StBvTV*eBuF-WJU#jN6Vi$C`A%tmW`BD8F7~cxKaF^jT-|> z&MR6GY;t1rPKd8@Mf#t}rk*t+`@MLpr0VGXy5RHEpYLT|x=yL^RyWWD-z)Y_0a??O z@dosXaKFFAq_k2K@6L>K*Vx=UGmCv&Ht#zn@V1Y{=CmG+ICz9}cNNPXeag;X*9q7& z0`CsqN1U$N#o>D_j=tvvc*Jw_(&5PO^DRgx7N4*0h;(Mj*LPGp96(0vJ0=_d$EcR$ z(#Z*bN4LXWz*XcgXk8TG@&e~kYf*srF=wR{!@T*JbJF2IME#wY&ildFqqn^vom}{q z1kUH~;nA5tW{jN7&^3Yi!DcpA1>#>!PdZ;-I`hOzEv&>aQ_K-FL(bp2k#*rORmELE literal 0 HcmV?d00001 diff --git a/Tests/DiligentCoreTest/assets/shaders/SPIRV/AtomicCounters.glsl.spv b/Tests/DiligentCoreTest/assets/shaders/SPIRV/AtomicCounters.glsl.spv new file mode 100644 index 0000000000000000000000000000000000000000..e43278dd9e7ccc8cb6820ad43b88fb4422c53709 GIT binary patch literal 1140 zcmY+COHWf#6ot2xTkyq01bpHx#V6W0P-9}$U=z!L0f~uI(?B64KuvAOI`nrj@xS;B zoEZJSd(So3)9mcM)?Rm=bM|Rtsy!2NE-uDwbfR2~F$EKF%_8@9KJ0Y9jQ2awos85&-Z@RKkN=mZkrRi zmur>SMpNN-!AA7BgPb?-p?9zKf4vg7YS=y25?F z!?U>Le!*m9wVum;%wo^#`-`_wIfr?|**Tw|biDf&Lf$hu2lE@;^|JRGFLnMu)v<4 za?ZT+zDF%z_r4F7ue={n%jvz#oP3W*g!ge@`@WlVa>n+&pSmZ6oIT%8{F{H8Mqv4{vFBKk-A!7qZ(bMHCrO`S43Gr#%GoVn*rTA4mS6T(z@Cd`JvLLo=OG)Mre z<+gcq{pO`{wsq-^E0<*)43(TH=MbEIShe5o4NTlc55p0oIbJ1Hv42xg1ub){AP32P zIOuhUqyD>-ZkLWTIR+fIH#df(ovk~)&b_tK@Dp;gdCs%9H{Wk(ol&p7v(_H9`(yc4 z&N{4v*!v{brk&ABJ8K8(3(Wjhj>xNp)5N!0>)CMB-tOd66kKto9?5dg5xyK^$(_H6$8GOCn-`(kK-R|5k?(5aZ*a${7Tr(~vjhtF&fUQl&cN@dOIBO5G z@n)8PtGLqYcE_Ep_$D#$?{=@>F<0ZC*fhGzMRpp)$pEh3v;wxLZ_b~|aa`VDZ`S)? zHGx!lM|Yv#8DygeYs20kYfZA<39Z8ow!n8++=m;mQ+z&0_hRmm@0xhdFRzX^In!F_ zZ_-WP^Qe;Ib48fPC-7@%>gSFq>0E105zDEg&YJeXT4zY{lbTA7RmfZKj+AFGF3(`y zlm69wcYsPWRB|l!TO?QRXI$>*-jwsk=BH5Safixz<8r+_Rn8lydcU_ptT?xlF#C(m zmayrF%|*-|Qc|t&B__|=+>v=yISML%4o(HDe+|;Uw1^V*gUhl zUt(wR-78~pcgWZ?&R{)5%o&Z{8L>1|x+D8|m#NPMd}I5(fVD=f^n=h$8iq zVL!c#yY$=3l45&aj0w5+GEAMiSgglmK?4Bv7nfZ0BJ$%C}SZ68EwM2|u zzsSCse-jl`o%Jf#nlu}3F7^;}hPMkS=Q@M2yR3Nbb*%4|&egA@iszbNM(a`M@vUZY9DpK-QjC6?K42dm-$PTGeq4lcdD$3zZ*FZ>1q84wTJkli247xxcij) zPVg5|dwPDd?=Y!3Ydpg}_!M=IjNPGosQYq<{_e_sRF3#YJo7=s-HkNcXZX%x&R*`x z=eZxk$He-+sk~)wx{3V)^^MZETj%?H8FMYZ+V~-AovKWso@?%_+%IZA0P_vMjyNXV z0`cyCMa5H(#Qg@$9`;P!-|)q)5qDnq%BU!=Y1D*b4149qt+cj&CT)N;y<9` zuc305qPEDpe?Ow0ttxWeGvC_$BUFxk()>R~9P@bo-|@v$pTzwc%pUel-}(o>xHaO5 b`wPBY&rjSx@x`qXcc1*55dW9zx6uCpF=Ecg literal 0 HcmV?d00001 diff --git a/Tests/DiligentCoreTest/assets/shaders/SPIRV/PushConstants.psh.spv b/Tests/DiligentCoreTest/assets/shaders/SPIRV/PushConstants.psh.spv new file mode 100644 index 0000000000000000000000000000000000000000..c775350dfc222989f541a3271943a11aac9d2532 GIT binary patch literal 1192 zcmY+DU29WO5JgWClPY3AtZhXhUg@JyTF_dp)|P;Y(2{6Dd=Nrt(io^WlH7nk`Um{A zKKLTI*3CU74ov3Eo;`E+oFtX<_EHF?a68-#@50>HLK!50)$-UpJwM%LYGWrf$&H3Iv>^8<%8XVEd5QBj+*zjiXF_i z{lFG6-%NhQ+*RK30_Lt_odwK2#Xc=y-Y53Cz~U}qT9X~boYzF%9!9L~^KWp@ z+2mXUOYklDYBl$s`+VLZikVwqCR%sS2Kfpx!L>R}_l!M}E2m!QvYya)mv{?T>tT`m z_F~SxM@;Y%{-nq^IBPNA*iS{~A zedfNU*goI4eZGk%_6NlO#0fX3WgmARHLLSAY-c^kt;ti<0Umkkm8ZrRMeSGqOAO&9 zxxM1{Cd5NL_PUF`>VH+#+T3VKAP4wATkKDZ literal 0 HcmV?d00001 diff --git a/Tests/DiligentCoreTest/assets/shaders/SPIRV/StorageBuffers.psh.spv b/Tests/DiligentCoreTest/assets/shaders/SPIRV/StorageBuffers.psh.spv new file mode 100644 index 0000000000000000000000000000000000000000..1d4aa191e1f37a87fe80e05d86e306490190dc28 GIT binary patch literal 1844 zcmaKr+fNfw5XOg=w%~<}2zaAzsduzmO^k`rP+|gaBw)lh($IzQfS6@#!khjB{=L4K z`2BXzuqV-Yn(3VHn{Up{&e^Tkx-GK_Gn=vJ`e)5sEim;06P>lDP0F)B86JNjP?ODB zz2J0+c6DpWe^#Jjmxavo^RH=dH_yfg`8Z2Q8{@;nH0zb_!!RGdkfxy@XUA+aaH4G# zbk5NOTwk7CY98(HY?t|E?WVY*_Rijas`ra*dar8t^`s4hW5u=M;@Ylb4(MLWJIAxb zy^^QHDS7p{SM@k$)8dLAH_r2PFdAj)*;y5D*`+dPdyt==93Oau^QJZ3i|6}CHky`Q z2{r%DZxwfUI?j9FhFNd-)BeX{c9iDQa})6$Zwm8#Z5a#9yjKfU;ZB5k);JE1<2+X! z2NS0*=hJr_2YY<0=um`Kw{+$l`EYYG&bcbjdyvS`a3`!PZ}Nh>A%0T`4Tj#|fl6O; zaUIvy!nsM5%Q@uoj?>SKJpHW8$Yam)^QjL<9{O2%Fy97x-WQhZw-j;C`v;Sco_B=h zdd`OCZEW7*0q2av}X~&E}sCjh=UgkRN*DzIDa|9)S_pt z^|tb{}SH68BA^W2lqtcj7&48i2zk|!Sy9W$nPbj%Kn z?zTKSIAYArV|PLf4(*CO{ZM~FS$r!UF?Z$JqeA9Q_hn78arO)4*=o{G|yQ+k2 literal 0 HcmV?d00001 diff --git a/Tests/DiligentCoreTest/assets/shaders/SPIRV/StorageImages.psh.spv b/Tests/DiligentCoreTest/assets/shaders/SPIRV/StorageImages.psh.spv new file mode 100644 index 0000000000000000000000000000000000000000..70ba9f816e016343a15b0a666abf173c623f833b GIT binary patch literal 1212 zcmZ{i*-JuE5XMigtuC3GtygV>hm6T265Ur5BHITN=r6_FJ;NuBpf zB!!1P7{0ar=Cj}J1)aA1q<+-tJY3yf5^J6-l9odfx)cJGPH>RxoylgPc)X)a-7o>2&q1Z(sGCDmeLM{BP z^+vUFvWYQAL)*sBOTnP7{-SJG*PYB#P#ivQ-O!ukFG(FgTBE3VbUtRR=q7Nv54&Ox zC)mV1^(loxuyFWZq8xBYlv5ssEEW#m3LG&1^;r%%VCh@YNl$iM5NkzeRgqPl*hk@P zyaj?!U)~?VrzY=>;8T+x^{8sxxhnOf^h8|0nr!+xTwOLXY9e3i0e?$M4f1Y| dZQ0D>xI40mO>%b?gHQfMn_y?eezdJa=`U%+K`H=nhizt=y$ZasW?=prAU75_JYT#(d6wIH5%+h=TcX}V?Tz@x2A2y8)3m5$kB_W zvf8`q`G55#4f==jj-3Almp63f?0!*24hJ0OF+JsACQiSvoSxUe)fL=J|3{Zz$$tUj C^EJKz literal 0 HcmV?d00001 diff --git a/Tests/DiligentCoreTest/assets/shaders/SPIRV/Textures.psh.spv b/Tests/DiligentCoreTest/assets/shaders/SPIRV/Textures.psh.spv new file mode 100644 index 0000000000000000000000000000000000000000..25fe64493431f634cc5c929132c61792d5620a3d GIT binary patch literal 2068 zcmaKtT~AX%5QdjxtzRIhfPhLXeuGs(5k)=}6XS(f5cIC8azaQ%Ni9b2@Lzjl;`5wy zRyGivWV$o&%;Ha(*jP93S4&Byed)3N5$-p8!$tjYvuj?}D@P@Ho%)_lv`?%;BMHJnRo z1l_-{z_Q(Tr`^qp0nP2t@%8LScdt`$QG-`!E3wwW=Jq4MU-!Dr@9j==ZKJi`?rddU zuqq6u-@)7g@SKNYi+^Mo8~jh~!ZEQooZIqDEOBdm4Q{oF(UGOD=8Xuclop+AP2qnb0$>N#>U&0W*K zg2r=PV}Dn%mFO4Wa(_A2O%O9j+%@Lau|wEjigPsZ>ZOkIdOX`6oWpse=qq*lj69la zjT|4YF+Z)D#8=F<#99MJG0>s=gCh%?B^DRL{U#@Snx|jFI z_#IZ~Dey|Ti`@XZ$ErP!?K?C_+jnPQ+P*W-TVNl#aZg3xxqT~&zBBnY6n*>kEhzf- z>D^cK-OszOMBlru#C-3vqVF7XW1n-dZSV0rILmLMQ>=^Rnlp{sufE*eM?HUoTIX$| z=7_&%68U+6iu(o>YyGYdQD<$zjCqer%zM6qde6<3w;5C(JV!2PODsL-af$l|6l>-A z2`XpS%Kco4rM3RYiTe%|Yn^ua`gh0`?%L4wmIUF zt0ipl$ki`;mYZc%9_1)vE7;=B9kG|#E2#5C>=m}SeMW2*Tio-On6$zw_J^-OkNyRV ChMFn> literal 0 HcmV?d00001 diff --git a/Tests/DiligentCoreTest/assets/shaders/SPIRV/UniformBuffers.psh.spv b/Tests/DiligentCoreTest/assets/shaders/SPIRV/UniformBuffers.psh.spv new file mode 100644 index 0000000000000000000000000000000000000000..bd15f2fe9eaea9a49e324a73a491457799c0e3ba GIT binary patch literal 1012 zcmY+BTT8=05QW!P>%HEsH%inOK`7{h2%=ysR6(Io5#Pe1AqHwIF^c{G|FbWG=i6p& z-7=jyXJ*dKZiBJh~u!)>-17_C0B=T99}2!Q+AQ0)J`~_899H|&7$sWl6}(e z`K2hPRpkD`4x`- zl6<3nsCeAnz4w;Y-fdcI--Wj}jib!fjsAP1rlxX-s*D3>j~#~wcw3k^AkUoPJeWK> zmu?dUI=g-M$I%ZrFY|Tuz-HS@N|xu2cF5X*Pay)WE}Ekc{uV_O{Nb`uR}jIfokXEsiUTv z?@TQ@-iRFc058aUttDj^g}22l$rDqvEKd&_C%HcNfCHn+xAGWGVswu*37ruc2iCm$wqYwT})7b&;N7IjGzl$L~#Q*>R literal 0 HcmV?d00001 diff --git a/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp b/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp index 822d936615..df6d211a50 100644 --- a/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp +++ b/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp @@ -32,6 +32,7 @@ #include "BasicFileSystem.hpp" #include +#include #include "TestingEnvironment.hpp" #include "gtest/gtest.h" @@ -42,8 +43,79 @@ using namespace Diligent::Testing; namespace { -std::vector HLSLtoSPIRV(const char* FilePath, SHADER_TYPE ShaderType = SHADER_TYPE_PIXEL) +struct SPIRVShaderResourceRefAttribs { + // clang-format off + +/* 0 */const char* const Name; +/* 8 */const Uint16 ArraySize; +/* 10 */const SPIRVShaderResourceAttribs::ResourceType Type; +/* 11.0*/const Uint8 ResourceDim : 7; // RESOURCE_DIMENSION +/* 11.7*/const Uint8 IsMS : 1; + + // Offset in SPIRV words (uint32_t) of binding & descriptor set decorations in SPIRV binary +/* 12 */const uint32_t BindingDecorationOffset; +/* 16 */const uint32_t DescriptorSetDecorationOffset; + +/* 20 */const Uint32 BufferStaticSize; +/* 24 */const Uint32 BufferStride; +/* 28 */ +/* 32 */ // End of structure + + // clang-format on + // + // Test-only constructor for creating reference resources + SPIRVShaderResourceRefAttribs(const char* _Name, + SPIRVShaderResourceAttribs::ResourceType _Type, + Uint16 _ArraySize, + RESOURCE_DIMENSION _ResourceDim, + Uint8 _IsMS, + Uint32 _BufferStaticSize, + Uint32 _BufferStride) noexcept : + // clang-format off + Name {_Name}, + ArraySize {_ArraySize}, + Type {_Type}, + ResourceDim {static_cast(_ResourceDim)}, + IsMS {_IsMS}, + BindingDecorationOffset {0}, // Not used in tests + DescriptorSetDecorationOffset {0}, // Not used in tests + BufferStaticSize {_BufferStaticSize}, + BufferStride {_BufferStride} + // clang-format on + {} +}; + +static_assert(sizeof(SPIRVShaderResourceRefAttribs) == sizeof(SPIRVShaderResourceAttribs), "Size of SPIRVShaderResourceRefAttribs struct must be equal to SPIRVShaderResourceAttribs"); + +std::vector HLSLtoSPIRV(const char* FilePath, SHADER_TYPE ShaderType = SHADER_TYPE_PIXEL) +{ + std::vector SPIRV; + +#if DILIGENT_NO_HLSL + // When DILIGENT_NO_HLSL is defined, use {FilePath}.spv as raw SPIRV shader source. + // i.e. FilePath="Textures.psh", then we load RAW SPIRV from "Textures.psh.spv" + std::string SPIRVFilePath = std::string(FilePath) + ".spv"; + + RefCntAutoPtr pShaderSourceStreamFactory; + CreateDefaultShaderSourceStreamFactory("shaders/SPIRV", &pShaderSourceStreamFactory); + if (!pShaderSourceStreamFactory) + return {}; + + RefCntAutoPtr pSPIRVStream; + pShaderSourceStreamFactory->CreateInputStream(SPIRVFilePath.c_str(), &pSPIRVStream); + if (!pSPIRVStream) + return {}; + + const size_t ByteCodeSize = pSPIRVStream->GetSize(); + if (ByteCodeSize == 0 || ByteCodeSize % 4 != 0) + return {}; + + SPIRV.resize(ByteCodeSize / 4); + pSPIRVStream->Read(SPIRV.data(), ByteCodeSize); + +#else + ShaderCreateInfo ShaderCI; ShaderCI.SourceLanguage = SHADER_SOURCE_LANGUAGE_HLSL; ShaderCI.FilePath = FilePath; @@ -58,14 +130,41 @@ std::vector HLSLtoSPIRV(const char* FilePath, SHADER_TYPE ShaderType = ShaderCI.pShaderSourceStreamFactory = pShaderSourceStreamFactory; GLSLangUtils::InitializeGlslang(); - auto SPIRV = GLSLangUtils::HLSLtoSPIRV(ShaderCI, GLSLangUtils::SpirvVersion::Vk100, nullptr, nullptr); + SPIRV = GLSLangUtils::HLSLtoSPIRV(ShaderCI, GLSLangUtils::SpirvVersion::Vk100, nullptr, nullptr); GLSLangUtils::FinalizeGlslang(); +#endif return SPIRV; } -std::vector GLSLtoSPIRV(const char* FilePath, SHADER_TYPE ShaderType = SHADER_TYPE_PIXEL) +std::vector GLSLtoSPIRV(const char* FilePath, SHADER_TYPE ShaderType = SHADER_TYPE_PIXEL) { + std::vector SPIRV; + +#if DILIGENT_NO_GLSL + // When DILIGENT_NO_GLSL is defined, use {FilePath}.spv as raw SPIRV shader source. + // i.e. FilePath="AtomicCounters.glsl", then we load RAW SPIRV from "AtomicCounters.glsl.spv" + std::string SPIRVFilePath = std::string(FilePath) + ".spv"; + + RefCntAutoPtr pShaderSourceStreamFactory; + CreateDefaultShaderSourceStreamFactory("shaders/SPIRV", &pShaderSourceStreamFactory); + if (!pShaderSourceStreamFactory) + return {}; + + RefCntAutoPtr pSPIRVStream; + pShaderSourceStreamFactory->CreateInputStream(SPIRVFilePath.c_str(), &pSPIRVStream); + if (!pSPIRVStream) + return {}; + + const size_t ByteCodeSize = pSPIRVStream->GetSize(); + if (ByteCodeSize == 0 || ByteCodeSize % 4 != 0) + return {}; + + SPIRV.resize(ByteCodeSize / 4); + pSPIRVStream->Read(SPIRV.data(), ByteCodeSize); + +#else + RefCntAutoPtr pShaderSourceStreamFactory; CreateDefaultShaderSourceStreamFactory("shaders/SPIRV", &pShaderSourceStreamFactory); if (!pShaderSourceStreamFactory) @@ -104,17 +203,18 @@ std::vector GLSLtoSPIRV(const char* FilePath, SHADER_TYPE ShaderType = Attribs.AssignBindings = true; GLSLangUtils::InitializeGlslang(); - auto SPIRV = GLSLangUtils::GLSLtoSPIRV(Attribs); + SPIRV = GLSLangUtils::GLSLtoSPIRV(Attribs); GLSLangUtils::FinalizeGlslang(); +#endif return SPIRV; } -void TestSPIRVResources(const char* FilePath, - const std::vector& RefResources, - SHADER_TYPE ShaderType = SHADER_TYPE_PIXEL, - const char* CombinedSamplerSuffix = nullptr, - bool IsGLSL = false) +void TestSPIRVResources(const char* FilePath, + const std::vector& RefResources, + SHADER_TYPE ShaderType = SHADER_TYPE_PIXEL, + const char* CombinedSamplerSuffix = nullptr, + bool IsGLSL = false) { const auto SPIRV = IsGLSL ? GLSLtoSPIRV(FilePath, ShaderType) : HLSLtoSPIRV(FilePath, ShaderType); ASSERT_FALSE(SPIRV.empty()) << "Failed to compile HLSL to SPIRV: " << FilePath; @@ -142,7 +242,7 @@ void TestSPIRVResources(const char* FilePath, EXPECT_EQ(size_t{Resources.GetTotalResources()}, RefResources.size()); - std::unordered_map RefResourcesMap; + std::unordered_map RefResourcesMap; for (const auto& RefRes : RefResources) { RefResourcesMap[RefRes.Name] = &RefRes; @@ -171,8 +271,8 @@ TEST(SPIRVShaderResources, UniformBuffers) TestSPIRVResources("UniformBuffers.psh", { // CB0 is optimized away as it's not used in the shader - SPIRVShaderResourceAttribs{"CB1", SPIRVResourceType::UniformBuffer, 1, RESOURCE_DIM_BUFFER, 0, 48, 0}, - SPIRVShaderResourceAttribs{"CB2", SPIRVResourceType::UniformBuffer, 1, RESOURCE_DIM_BUFFER, 0, 16, 0}, + SPIRVShaderResourceRefAttribs{"CB1", SPIRVResourceType::UniformBuffer, 1, RESOURCE_DIM_BUFFER, 0, 48, 0}, + SPIRVShaderResourceRefAttribs{"CB2", SPIRVResourceType::UniformBuffer, 1, RESOURCE_DIM_BUFFER, 0, 16, 0}, }); } @@ -181,11 +281,11 @@ TEST(SPIRVShaderResources, StorageBuffers) TestSPIRVResources("StorageBuffers.psh", { // StructuredBuffers have BufferStaticSize=0 (runtime array) and BufferStride is the element size - SPIRVShaderResourceAttribs{"g_ROBuffer", SPIRVResourceType::ROStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 32}, - SPIRVShaderResourceAttribs{"g_RWBuffer", SPIRVResourceType::RWStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 64}, + SPIRVShaderResourceRefAttribs{"g_ROBuffer", SPIRVResourceType::ROStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 32}, + SPIRVShaderResourceRefAttribs{"g_RWBuffer", SPIRVResourceType::RWStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 64}, // ByteAddressBuffers also have BufferStaticSize=0 and BufferStride=4 (uint size) - SPIRVShaderResourceAttribs{"g_ROAtomicBuffer", SPIRVResourceType::ROStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 4}, - SPIRVShaderResourceAttribs{"g_RWAtomicBuffer", SPIRVResourceType::RWStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 4}, + SPIRVShaderResourceRefAttribs{"g_ROAtomicBuffer", SPIRVResourceType::ROStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 4}, + SPIRVShaderResourceRefAttribs{"g_RWAtomicBuffer", SPIRVResourceType::RWStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 4}, }); } @@ -193,8 +293,8 @@ TEST(SPIRVShaderResources, TexelBuffers) { TestSPIRVResources("TexelBuffers.psh", { - SPIRVShaderResourceAttribs{"g_UniformTexelBuffer", SPIRVResourceType::UniformTexelBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 0}, - SPIRVShaderResourceAttribs{"g_StorageTexelBuffer", SPIRVResourceType::StorageTexelBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 0}, + SPIRVShaderResourceRefAttribs{"g_UniformTexelBuffer", SPIRVResourceType::UniformTexelBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 0}, + SPIRVShaderResourceRefAttribs{"g_StorageTexelBuffer", SPIRVResourceType::StorageTexelBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 0}, }); } @@ -204,17 +304,17 @@ TEST(SPIRVShaderResources, Textures) { // When textures and samplers are declared separately in HLSL, they are compiled as separate_images // instead of sampled_images. This is the correct behavior for separate sampler/texture declarations. - SPIRVShaderResourceAttribs{"g_SampledImage", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_2D, 0, 0, 0}, - SPIRVShaderResourceAttribs{"g_SampledImageMS", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_2D, 1, 0, 0}, - SPIRVShaderResourceAttribs{"g_SampledImage3D", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_3D, 0, 0, 0}, - SPIRVShaderResourceAttribs{"g_SampledImageCube", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_CUBE, 0, 0, 0}, - SPIRVShaderResourceAttribs{"g_Sampler", SPIRVResourceType::SeparateSampler, 1, RESOURCE_DIM_UNDEFINED, 0, 0, 0}, - SPIRVShaderResourceAttribs{"g_SeparateImage", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_2D, 0, 0, 0}, + SPIRVShaderResourceRefAttribs{"g_SampledImage", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_2D, 0, 0, 0}, + SPIRVShaderResourceRefAttribs{"g_SampledImageMS", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_2D, 1, 0, 0}, + SPIRVShaderResourceRefAttribs{"g_SampledImage3D", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_3D, 0, 0, 0}, + SPIRVShaderResourceRefAttribs{"g_SampledImageCube", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_CUBE, 0, 0, 0}, + SPIRVShaderResourceRefAttribs{"g_Sampler", SPIRVResourceType::SeparateSampler, 1, RESOURCE_DIM_UNDEFINED, 0, 0, 0}, + SPIRVShaderResourceRefAttribs{"g_SeparateImage", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_2D, 0, 0, 0}, // Combined sampler: g_Texture and g_Texture_sampler // Note: Even with CombinedSamplerSuffix, SPIRV may still classify them as separate_images // if they are declared separately. The CombinedSamplerSuffix is mainly used for naming convention. - SPIRVShaderResourceAttribs{"g_Texture", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_2D, 0, 0, 0}, - SPIRVShaderResourceAttribs{"g_Texture_sampler", SPIRVResourceType::SeparateSampler, 1, RESOURCE_DIM_UNDEFINED, 0, 0, 0}, + SPIRVShaderResourceRefAttribs{"g_Texture", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_2D, 0, 0, 0}, + SPIRVShaderResourceRefAttribs{"g_Texture_sampler", SPIRVResourceType::SeparateSampler, 1, RESOURCE_DIM_UNDEFINED, 0, 0, 0}, }); } @@ -223,9 +323,9 @@ TEST(SPIRVShaderResources, StorageImages) TestSPIRVResources("StorageImages.psh", { // Note: HLSL does not support RWTextureCube, so we only test 2D, 2DArray, and 3D storage images - SPIRVShaderResourceAttribs{"g_RWImage2D", SPIRVResourceType::StorageImage, 1, RESOURCE_DIM_TEX_2D, 0, 0, 0}, - SPIRVShaderResourceAttribs{"g_RWImage2DArray", SPIRVResourceType::StorageImage, 1, RESOURCE_DIM_TEX_2D_ARRAY, 0, 0, 0}, - SPIRVShaderResourceAttribs{"g_RWImage3D", SPIRVResourceType::StorageImage, 1, RESOURCE_DIM_TEX_3D, 0, 0, 0}, + SPIRVShaderResourceRefAttribs{"g_RWImage2D", SPIRVResourceType::StorageImage, 1, RESOURCE_DIM_TEX_2D, 0, 0, 0}, + SPIRVShaderResourceRefAttribs{"g_RWImage2DArray", SPIRVResourceType::StorageImage, 1, RESOURCE_DIM_TEX_2D_ARRAY, 0, 0, 0}, + SPIRVShaderResourceRefAttribs{"g_RWImage3D", SPIRVResourceType::StorageImage, 1, RESOURCE_DIM_TEX_3D, 0, 0, 0}, }); } @@ -237,7 +337,7 @@ TEST(SPIRVShaderResources, AtomicCounters) // The resource name is the buffer block name (AtomicCounterBuffer), not the instance name (g_AtomicCounter). TestSPIRVResources("AtomicCounters.glsl", { - SPIRVShaderResourceAttribs{"AtomicCounterBuffer", SPIRVResourceType::RWStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 4, 0}, + SPIRVShaderResourceRefAttribs{"AtomicCounterBuffer", SPIRVResourceType::RWStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 4, 0}, }, SHADER_TYPE_PIXEL, nullptr, @@ -248,7 +348,7 @@ TEST(SPIRVShaderResources, InputAttachments) { TestSPIRVResources("InputAttachments.psh", { - SPIRVShaderResourceAttribs{"g_InputAttachment", SPIRVResourceType::InputAttachment, 1, RESOURCE_DIM_UNDEFINED, 0, 0, 0}, + SPIRVShaderResourceRefAttribs{"g_InputAttachment", SPIRVResourceType::InputAttachment, 1, RESOURCE_DIM_UNDEFINED, 0, 0, 0}, }); } @@ -259,7 +359,7 @@ TEST(SPIRVShaderResources, AccelerationStructures) // The ray gen shader uses traceRayEXT with g_AccelStruct to ensure it's not optimized away TestSPIRVResources("AccelerationStructures.glsl", { - SPIRVShaderResourceAttribs{"g_AccelStruct", SPIRVResourceType::AccelerationStructure, 1, RESOURCE_DIM_UNDEFINED, 0, 0, 0}, + SPIRVShaderResourceRefAttribs{"g_AccelStruct", SPIRVResourceType::AccelerationStructure, 1, RESOURCE_DIM_UNDEFINED, 0, 0, 0}, }, SHADER_TYPE_RAY_GEN, nullptr, @@ -273,7 +373,7 @@ TEST(SPIRVShaderResources, PushConstants) // Total: 16 + 4 + 2 + 1 + 1 = 24 floats/uints = 24 * 4 bytes = 96 bytes = 24 words TestSPIRVResources("PushConstants.psh", { - SPIRVShaderResourceAttribs{"PushConstants", SPIRVResourceType::PushConstant, 24, RESOURCE_DIM_BUFFER, 0, 96, 0}, + SPIRVShaderResourceRefAttribs{"PushConstants", SPIRVResourceType::PushConstant, 24, RESOURCE_DIM_BUFFER, 0, 96, 0}, }); } @@ -282,18 +382,18 @@ TEST(SPIRVShaderResources, MixedResources) TestSPIRVResources("MixedResources.psh", { // UniformBuff: float4x4 (64 bytes) + float4 (16 bytes) = 80 bytes - SPIRVShaderResourceAttribs{"UniformBuff", SPIRVResourceType::UniformBuffer, 1, RESOURCE_DIM_BUFFER, 0, 80, 0}, + SPIRVShaderResourceRefAttribs{"UniformBuff", SPIRVResourceType::UniformBuffer, 1, RESOURCE_DIM_BUFFER, 0, 80, 0}, // ROStorageBuff: StructuredBuffer where BufferData = float4[4] = 64 bytes // StructuredBuffers have BufferStaticSize=0 (runtime array) and BufferStride is the element size - SPIRVShaderResourceAttribs{"ROStorageBuff", SPIRVResourceType::ROStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 64}, + SPIRVShaderResourceRefAttribs{"ROStorageBuff", SPIRVResourceType::ROStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 64}, // RWStorageBuff: same as ROStorageBuff - SPIRVShaderResourceAttribs{"RWStorageBuff", SPIRVResourceType::RWStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 64}, + SPIRVShaderResourceRefAttribs{"RWStorageBuff", SPIRVResourceType::RWStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 64}, // SampledTex: When Texture2D and SamplerState are declared separately, they are compiled as SeparateImage - SPIRVShaderResourceAttribs{"SampledTex", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_2D, 0, 0, 0}, - SPIRVShaderResourceAttribs{"StorageTex", SPIRVResourceType::StorageImage, 1, RESOURCE_DIM_TEX_2D, 0, 0, 0}, - SPIRVShaderResourceAttribs{"Sampler", SPIRVResourceType::SeparateSampler, 1, RESOURCE_DIM_UNDEFINED, 0, 0, 0}, + SPIRVShaderResourceRefAttribs{"SampledTex", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_2D, 0, 0, 0}, + SPIRVShaderResourceRefAttribs{"StorageTex", SPIRVResourceType::StorageImage, 1, RESOURCE_DIM_TEX_2D, 0, 0, 0}, + SPIRVShaderResourceRefAttribs{"Sampler", SPIRVResourceType::SeparateSampler, 1, RESOURCE_DIM_UNDEFINED, 0, 0, 0}, // PushConstants: float2 (2 floats) + float (1 float) + uint (1 uint) = 4 words = 16 bytes - SPIRVShaderResourceAttribs{"PushConstants", SPIRVResourceType::PushConstant, 4, RESOURCE_DIM_BUFFER, 0, 16, 0}, + SPIRVShaderResourceRefAttribs{"PushConstants", SPIRVResourceType::PushConstant, 4, RESOURCE_DIM_BUFFER, 0, 16, 0}, }); } From 345f1014ce4d19c0de31337c669be2a9b8c95b9c Mon Sep 17 00:00:00 2001 From: hzqst <113660872@qq.com> Date: Fri, 12 Dec 2025 14:55:11 +0800 Subject: [PATCH 07/20] rename HLSLtoSPIRV -> LoadSPIRVFromHLSL --- .../src/ShaderTools/SPIRVShaderResourcesTest.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp b/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp index df6d211a50..0c3dbdccd1 100644 --- a/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp +++ b/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp @@ -88,7 +88,7 @@ struct SPIRVShaderResourceRefAttribs static_assert(sizeof(SPIRVShaderResourceRefAttribs) == sizeof(SPIRVShaderResourceAttribs), "Size of SPIRVShaderResourceRefAttribs struct must be equal to SPIRVShaderResourceAttribs"); -std::vector HLSLtoSPIRV(const char* FilePath, SHADER_TYPE ShaderType = SHADER_TYPE_PIXEL) +std::vector LoadSPIRVFromHLSL(const char* FilePath, SHADER_TYPE ShaderType = SHADER_TYPE_PIXEL) { std::vector SPIRV; @@ -137,7 +137,7 @@ std::vector HLSLtoSPIRV(const char* FilePath, SHADER_TYPE ShaderTy return SPIRV; } -std::vector GLSLtoSPIRV(const char* FilePath, SHADER_TYPE ShaderType = SHADER_TYPE_PIXEL) +std::vector LoadSPIRVFromGLSL(const char* FilePath, SHADER_TYPE ShaderType = SHADER_TYPE_PIXEL) { std::vector SPIRV; @@ -216,7 +216,7 @@ void TestSPIRVResources(const char* FilePa const char* CombinedSamplerSuffix = nullptr, bool IsGLSL = false) { - const auto SPIRV = IsGLSL ? GLSLtoSPIRV(FilePath, ShaderType) : HLSLtoSPIRV(FilePath, ShaderType); + const auto SPIRV = IsGLSL ? LoadSPIRVFromGLSL(FilePath, ShaderType) : LoadSPIRVFromHLSL(FilePath, ShaderType); ASSERT_FALSE(SPIRV.empty()) << "Failed to compile HLSL to SPIRV: " << FilePath; ShaderDesc ShaderDesc; From 4da3afbf9268dc0bdaf7441e2cf3771c7ceb9a8c Mon Sep 17 00:00:00 2001 From: hzqst <113660872@qq.com> Date: Fri, 12 Dec 2025 15:03:15 +0800 Subject: [PATCH 08/20] DILIGENT_NO_GLSL -> DILIGENT_NO_GLSLANG --- .../src/ShaderTools/SPIRVShaderResourcesTest.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp b/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp index 0c3dbdccd1..1168720d4d 100644 --- a/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp +++ b/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp @@ -141,8 +141,8 @@ std::vector LoadSPIRVFromGLSL(const char* FilePath, SHADER_TYPE Sh { std::vector SPIRV; -#if DILIGENT_NO_GLSL - // When DILIGENT_NO_GLSL is defined, use {FilePath}.spv as raw SPIRV shader source. +#if DILIGENT_NO_GLSLANG + // When DILIGENT_NO_GLSLANG is defined, use {FilePath}.spv as raw SPIRV shader source. // i.e. FilePath="AtomicCounters.glsl", then we load RAW SPIRV from "AtomicCounters.glsl.spv" std::string SPIRVFilePath = std::string(FilePath) + ".spv"; From 5e4b751eb4d92e0a84dd1e0ae303158d24348c5f Mon Sep 17 00:00:00 2001 From: hzqst <113660872@qq.com> Date: Fri, 12 Dec 2025 15:11:42 +0800 Subject: [PATCH 09/20] aggregate-initialize the SPIRVShaderResourceRefAttribs. --- .../ShaderTools/SPIRVShaderResourcesTest.cpp | 113 +++++++----------- 1 file changed, 42 insertions(+), 71 deletions(-) diff --git a/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp b/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp index 1168720d4d..0fbf51929d 100644 --- a/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp +++ b/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp @@ -45,49 +45,20 @@ namespace struct SPIRVShaderResourceRefAttribs { - // clang-format off - -/* 0 */const char* const Name; -/* 8 */const Uint16 ArraySize; -/* 10 */const SPIRVShaderResourceAttribs::ResourceType Type; -/* 11.0*/const Uint8 ResourceDim : 7; // RESOURCE_DIMENSION -/* 11.7*/const Uint8 IsMS : 1; - - // Offset in SPIRV words (uint32_t) of binding & descriptor set decorations in SPIRV binary -/* 12 */const uint32_t BindingDecorationOffset; -/* 16 */const uint32_t DescriptorSetDecorationOffset; - -/* 20 */const Uint32 BufferStaticSize; -/* 24 */const Uint32 BufferStride; -/* 28 */ -/* 32 */ // End of structure - - // clang-format on - // - // Test-only constructor for creating reference resources - SPIRVShaderResourceRefAttribs(const char* _Name, - SPIRVShaderResourceAttribs::ResourceType _Type, - Uint16 _ArraySize, - RESOURCE_DIMENSION _ResourceDim, - Uint8 _IsMS, - Uint32 _BufferStaticSize, - Uint32 _BufferStride) noexcept : - // clang-format off - Name {_Name}, - ArraySize {_ArraySize}, - Type {_Type}, - ResourceDim {static_cast(_ResourceDim)}, - IsMS {_IsMS}, - BindingDecorationOffset {0}, // Not used in tests - DescriptorSetDecorationOffset {0}, // Not used in tests - BufferStaticSize {_BufferStaticSize}, - BufferStride {_BufferStride} - // clang-format on - {} + const char* const Name; + const Uint16 ArraySize; + const SPIRVShaderResourceAttribs::ResourceType Type; + const Uint8 ResourceDim; // RESOURCE_DIMENSION + const Uint8 IsMS; + + // Offset in SPIRV words (uint32_t) of binding & descriptor set decorations in SPIRV binary + const uint32_t BindingDecorationOffset; + const uint32_t DescriptorSetDecorationOffset; + + const Uint32 BufferStaticSize; + const Uint32 BufferStride; }; -static_assert(sizeof(SPIRVShaderResourceRefAttribs) == sizeof(SPIRVShaderResourceAttribs), "Size of SPIRVShaderResourceRefAttribs struct must be equal to SPIRVShaderResourceAttribs"); - std::vector LoadSPIRVFromHLSL(const char* FilePath, SHADER_TYPE ShaderType = SHADER_TYPE_PIXEL) { std::vector SPIRV; @@ -271,8 +242,8 @@ TEST(SPIRVShaderResources, UniformBuffers) TestSPIRVResources("UniformBuffers.psh", { // CB0 is optimized away as it's not used in the shader - SPIRVShaderResourceRefAttribs{"CB1", SPIRVResourceType::UniformBuffer, 1, RESOURCE_DIM_BUFFER, 0, 48, 0}, - SPIRVShaderResourceRefAttribs{"CB2", SPIRVResourceType::UniformBuffer, 1, RESOURCE_DIM_BUFFER, 0, 16, 0}, + SPIRVShaderResourceRefAttribs{"CB1", 1, SPIRVResourceType::UniformBuffer, RESOURCE_DIM_BUFFER, 0, 48, 0}, + SPIRVShaderResourceRefAttribs{"CB2", 1, SPIRVResourceType::UniformBuffer, RESOURCE_DIM_BUFFER, 0, 16, 0}, }); } @@ -281,11 +252,11 @@ TEST(SPIRVShaderResources, StorageBuffers) TestSPIRVResources("StorageBuffers.psh", { // StructuredBuffers have BufferStaticSize=0 (runtime array) and BufferStride is the element size - SPIRVShaderResourceRefAttribs{"g_ROBuffer", SPIRVResourceType::ROStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 32}, - SPIRVShaderResourceRefAttribs{"g_RWBuffer", SPIRVResourceType::RWStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 64}, + SPIRVShaderResourceRefAttribs{"g_ROBuffer", 1, SPIRVResourceType::ROStorageBuffer, RESOURCE_DIM_BUFFER, 0, 0, 32}, + SPIRVShaderResourceRefAttribs{"g_RWBuffer", 1, SPIRVResourceType::RWStorageBuffer, RESOURCE_DIM_BUFFER, 0, 0, 64}, // ByteAddressBuffers also have BufferStaticSize=0 and BufferStride=4 (uint size) - SPIRVShaderResourceRefAttribs{"g_ROAtomicBuffer", SPIRVResourceType::ROStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 4}, - SPIRVShaderResourceRefAttribs{"g_RWAtomicBuffer", SPIRVResourceType::RWStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 4}, + SPIRVShaderResourceRefAttribs{"g_ROAtomicBuffer", 1, SPIRVResourceType::ROStorageBuffer, RESOURCE_DIM_BUFFER, 0, 0, 4}, + SPIRVShaderResourceRefAttribs{"g_RWAtomicBuffer", 1, SPIRVResourceType::RWStorageBuffer, RESOURCE_DIM_BUFFER, 0, 0, 4}, }); } @@ -293,8 +264,8 @@ TEST(SPIRVShaderResources, TexelBuffers) { TestSPIRVResources("TexelBuffers.psh", { - SPIRVShaderResourceRefAttribs{"g_UniformTexelBuffer", SPIRVResourceType::UniformTexelBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 0}, - SPIRVShaderResourceRefAttribs{"g_StorageTexelBuffer", SPIRVResourceType::StorageTexelBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 0}, + SPIRVShaderResourceRefAttribs{"g_UniformTexelBuffer", 1, SPIRVResourceType::UniformTexelBuffer, RESOURCE_DIM_BUFFER, 0, 0, 0}, + SPIRVShaderResourceRefAttribs{"g_StorageTexelBuffer", 1, SPIRVResourceType::StorageTexelBuffer, RESOURCE_DIM_BUFFER, 0, 0, 0}, }); } @@ -304,17 +275,17 @@ TEST(SPIRVShaderResources, Textures) { // When textures and samplers are declared separately in HLSL, they are compiled as separate_images // instead of sampled_images. This is the correct behavior for separate sampler/texture declarations. - SPIRVShaderResourceRefAttribs{"g_SampledImage", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_2D, 0, 0, 0}, - SPIRVShaderResourceRefAttribs{"g_SampledImageMS", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_2D, 1, 0, 0}, - SPIRVShaderResourceRefAttribs{"g_SampledImage3D", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_3D, 0, 0, 0}, - SPIRVShaderResourceRefAttribs{"g_SampledImageCube", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_CUBE, 0, 0, 0}, - SPIRVShaderResourceRefAttribs{"g_Sampler", SPIRVResourceType::SeparateSampler, 1, RESOURCE_DIM_UNDEFINED, 0, 0, 0}, - SPIRVShaderResourceRefAttribs{"g_SeparateImage", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_2D, 0, 0, 0}, + SPIRVShaderResourceRefAttribs{"g_SampledImage", 1, SPIRVResourceType::SeparateImage, RESOURCE_DIM_TEX_2D, 0, 0, 0}, + SPIRVShaderResourceRefAttribs{"g_SampledImageMS", 1, SPIRVResourceType::SeparateImage, RESOURCE_DIM_TEX_2D, 1, 0, 0}, + SPIRVShaderResourceRefAttribs{"g_SampledImage3D", 1, SPIRVResourceType::SeparateImage, RESOURCE_DIM_TEX_3D, 0, 0, 0}, + SPIRVShaderResourceRefAttribs{"g_SampledImageCube", 1, SPIRVResourceType::SeparateImage, RESOURCE_DIM_TEX_CUBE, 0, 0, 0}, + SPIRVShaderResourceRefAttribs{"g_Sampler", 1, SPIRVResourceType::SeparateSampler, RESOURCE_DIM_UNDEFINED, 0, 0, 0}, + SPIRVShaderResourceRefAttribs{"g_SeparateImage", 1, SPIRVResourceType::SeparateImage, RESOURCE_DIM_TEX_2D, 0, 0, 0}, // Combined sampler: g_Texture and g_Texture_sampler // Note: Even with CombinedSamplerSuffix, SPIRV may still classify them as separate_images // if they are declared separately. The CombinedSamplerSuffix is mainly used for naming convention. - SPIRVShaderResourceRefAttribs{"g_Texture", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_2D, 0, 0, 0}, - SPIRVShaderResourceRefAttribs{"g_Texture_sampler", SPIRVResourceType::SeparateSampler, 1, RESOURCE_DIM_UNDEFINED, 0, 0, 0}, + SPIRVShaderResourceRefAttribs{"g_Texture", 1, SPIRVResourceType::SeparateImage, RESOURCE_DIM_TEX_2D, 0, 0, 0}, + SPIRVShaderResourceRefAttribs{"g_Texture_sampler", 1, SPIRVResourceType::SeparateSampler, RESOURCE_DIM_UNDEFINED, 0, 0, 0}, }); } @@ -323,9 +294,9 @@ TEST(SPIRVShaderResources, StorageImages) TestSPIRVResources("StorageImages.psh", { // Note: HLSL does not support RWTextureCube, so we only test 2D, 2DArray, and 3D storage images - SPIRVShaderResourceRefAttribs{"g_RWImage2D", SPIRVResourceType::StorageImage, 1, RESOURCE_DIM_TEX_2D, 0, 0, 0}, - SPIRVShaderResourceRefAttribs{"g_RWImage2DArray", SPIRVResourceType::StorageImage, 1, RESOURCE_DIM_TEX_2D_ARRAY, 0, 0, 0}, - SPIRVShaderResourceRefAttribs{"g_RWImage3D", SPIRVResourceType::StorageImage, 1, RESOURCE_DIM_TEX_3D, 0, 0, 0}, + SPIRVShaderResourceRefAttribs{"g_RWImage2D", 1, SPIRVResourceType::StorageImage, RESOURCE_DIM_TEX_2D, 0, 0, 0}, + SPIRVShaderResourceRefAttribs{"g_RWImage2DArray", 1, SPIRVResourceType::StorageImage, RESOURCE_DIM_TEX_2D_ARRAY, 0, 0, 0}, + SPIRVShaderResourceRefAttribs{"g_RWImage3D", 1, SPIRVResourceType::StorageImage, RESOURCE_DIM_TEX_3D, 0, 0, 0}, }); } @@ -337,7 +308,7 @@ TEST(SPIRVShaderResources, AtomicCounters) // The resource name is the buffer block name (AtomicCounterBuffer), not the instance name (g_AtomicCounter). TestSPIRVResources("AtomicCounters.glsl", { - SPIRVShaderResourceRefAttribs{"AtomicCounterBuffer", SPIRVResourceType::RWStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 4, 0}, + SPIRVShaderResourceRefAttribs{"AtomicCounterBuffer", 1, SPIRVResourceType::RWStorageBuffer, RESOURCE_DIM_BUFFER, 0, 4, 0}, }, SHADER_TYPE_PIXEL, nullptr, @@ -348,7 +319,7 @@ TEST(SPIRVShaderResources, InputAttachments) { TestSPIRVResources("InputAttachments.psh", { - SPIRVShaderResourceRefAttribs{"g_InputAttachment", SPIRVResourceType::InputAttachment, 1, RESOURCE_DIM_UNDEFINED, 0, 0, 0}, + SPIRVShaderResourceRefAttribs{"g_InputAttachment", 1, SPIRVResourceType::InputAttachment, RESOURCE_DIM_UNDEFINED, 0, 0, 0}, }); } @@ -359,7 +330,7 @@ TEST(SPIRVShaderResources, AccelerationStructures) // The ray gen shader uses traceRayEXT with g_AccelStruct to ensure it's not optimized away TestSPIRVResources("AccelerationStructures.glsl", { - SPIRVShaderResourceRefAttribs{"g_AccelStruct", SPIRVResourceType::AccelerationStructure, 1, RESOURCE_DIM_UNDEFINED, 0, 0, 0}, + SPIRVShaderResourceRefAttribs{"g_AccelStruct", 1, SPIRVResourceType::AccelerationStructure, RESOURCE_DIM_UNDEFINED, 0, 0, 0}, }, SHADER_TYPE_RAY_GEN, nullptr, @@ -373,7 +344,7 @@ TEST(SPIRVShaderResources, PushConstants) // Total: 16 + 4 + 2 + 1 + 1 = 24 floats/uints = 24 * 4 bytes = 96 bytes = 24 words TestSPIRVResources("PushConstants.psh", { - SPIRVShaderResourceRefAttribs{"PushConstants", SPIRVResourceType::PushConstant, 24, RESOURCE_DIM_BUFFER, 0, 96, 0}, + SPIRVShaderResourceRefAttribs{"PushConstants", 24, SPIRVResourceType::PushConstant, RESOURCE_DIM_BUFFER, 0, 96, 0}, }); } @@ -382,18 +353,18 @@ TEST(SPIRVShaderResources, MixedResources) TestSPIRVResources("MixedResources.psh", { // UniformBuff: float4x4 (64 bytes) + float4 (16 bytes) = 80 bytes - SPIRVShaderResourceRefAttribs{"UniformBuff", SPIRVResourceType::UniformBuffer, 1, RESOURCE_DIM_BUFFER, 0, 80, 0}, + SPIRVShaderResourceRefAttribs{"UniformBuff", 1, SPIRVResourceType::UniformBuffer, RESOURCE_DIM_BUFFER, 0, 80, 0}, // ROStorageBuff: StructuredBuffer where BufferData = float4[4] = 64 bytes // StructuredBuffers have BufferStaticSize=0 (runtime array) and BufferStride is the element size - SPIRVShaderResourceRefAttribs{"ROStorageBuff", SPIRVResourceType::ROStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 64}, + SPIRVShaderResourceRefAttribs{"ROStorageBuff", 1, SPIRVResourceType::ROStorageBuffer, RESOURCE_DIM_BUFFER, 0, 0, 64}, // RWStorageBuff: same as ROStorageBuff - SPIRVShaderResourceRefAttribs{"RWStorageBuff", SPIRVResourceType::RWStorageBuffer, 1, RESOURCE_DIM_BUFFER, 0, 0, 64}, + SPIRVShaderResourceRefAttribs{"RWStorageBuff", 1, SPIRVResourceType::RWStorageBuffer, RESOURCE_DIM_BUFFER, 0, 0, 64}, // SampledTex: When Texture2D and SamplerState are declared separately, they are compiled as SeparateImage - SPIRVShaderResourceRefAttribs{"SampledTex", SPIRVResourceType::SeparateImage, 1, RESOURCE_DIM_TEX_2D, 0, 0, 0}, - SPIRVShaderResourceRefAttribs{"StorageTex", SPIRVResourceType::StorageImage, 1, RESOURCE_DIM_TEX_2D, 0, 0, 0}, - SPIRVShaderResourceRefAttribs{"Sampler", SPIRVResourceType::SeparateSampler, 1, RESOURCE_DIM_UNDEFINED, 0, 0, 0}, + SPIRVShaderResourceRefAttribs{"SampledTex", 1, SPIRVResourceType::SeparateImage, RESOURCE_DIM_TEX_2D, 0, 0, 0}, + SPIRVShaderResourceRefAttribs{"StorageTex", 1, SPIRVResourceType::StorageImage, RESOURCE_DIM_TEX_2D, 0, 0, 0}, + SPIRVShaderResourceRefAttribs{"Sampler", 1, SPIRVResourceType::SeparateSampler, RESOURCE_DIM_UNDEFINED, 0, 0, 0}, // PushConstants: float2 (2 floats) + float (1 float) + uint (1 uint) = 4 words = 16 bytes - SPIRVShaderResourceRefAttribs{"PushConstants", SPIRVResourceType::PushConstant, 4, RESOURCE_DIM_BUFFER, 0, 16, 0}, + SPIRVShaderResourceRefAttribs{"PushConstants", 4, SPIRVResourceType::PushConstant, RESOURCE_DIM_BUFFER, 0, 16, 0}, }); } From 048c27f699ff067059f9c35b0bdfe27b3fb489a5 Mon Sep 17 00:00:00 2001 From: hzqst <113660872@qq.com> Date: Fri, 12 Dec 2025 15:13:10 +0800 Subject: [PATCH 10/20] fix formatting --- .../ShaderTools/SPIRVShaderResourcesTest.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp b/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp index 0fbf51929d..d042ea67ab 100644 --- a/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp +++ b/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp @@ -45,18 +45,18 @@ namespace struct SPIRVShaderResourceRefAttribs { - const char* const Name; - const Uint16 ArraySize; - const SPIRVShaderResourceAttribs::ResourceType Type; - const Uint8 ResourceDim; // RESOURCE_DIMENSION - const Uint8 IsMS; + const char* const Name; + const Uint16 ArraySize; + const SPIRVShaderResourceAttribs::ResourceType Type; + const Uint8 ResourceDim; // RESOURCE_DIMENSION + const Uint8 IsMS; // Offset in SPIRV words (uint32_t) of binding & descriptor set decorations in SPIRV binary - const uint32_t BindingDecorationOffset; - const uint32_t DescriptorSetDecorationOffset; + const uint32_t BindingDecorationOffset; + const uint32_t DescriptorSetDecorationOffset; - const Uint32 BufferStaticSize; - const Uint32 BufferStride; + const Uint32 BufferStaticSize; + const Uint32 BufferStride; }; std::vector LoadSPIRVFromHLSL(const char* FilePath, SHADER_TYPE ShaderType = SHADER_TYPE_PIXEL) From a473ef8a75485fe1067c64e3f6b1614639f9f0d6 Mon Sep 17 00:00:00 2001 From: hzqst <113660872@qq.com> Date: Fri, 12 Dec 2025 15:15:50 +0800 Subject: [PATCH 11/20] skip test when DILIGENT_NO_HLSL / DILIGENT_NO_GLSLANG defined. --- .../SPIRV/AccelerationStructures.glsl.spv | Bin 1424 -> 0 bytes .../shaders/SPIRV/AtomicCounters.glsl.spv | Bin 1140 -> 0 bytes .../shaders/SPIRV/MixedResources.psh.spv | Bin 2764 -> 0 bytes .../shaders/SPIRV/PushConstants.psh.spv | Bin 1192 -> 0 bytes .../shaders/SPIRV/StorageBuffers.psh.spv | Bin 1844 -> 0 bytes .../shaders/SPIRV/StorageImages.psh.spv | Bin 1212 -> 0 bytes .../assets/shaders/SPIRV/TexelBuffers.psh.spv | Bin 796 -> 0 bytes .../assets/shaders/SPIRV/Textures.psh.spv | Bin 2068 -> 0 bytes .../shaders/SPIRV/UniformBuffers.psh.spv | Bin 1012 -> 0 bytes .../ShaderTools/SPIRVShaderResourcesTest.cpp | 55 +++--------------- 10 files changed, 8 insertions(+), 47 deletions(-) delete mode 100644 Tests/DiligentCoreTest/assets/shaders/SPIRV/AccelerationStructures.glsl.spv delete mode 100644 Tests/DiligentCoreTest/assets/shaders/SPIRV/AtomicCounters.glsl.spv delete mode 100644 Tests/DiligentCoreTest/assets/shaders/SPIRV/MixedResources.psh.spv delete mode 100644 Tests/DiligentCoreTest/assets/shaders/SPIRV/PushConstants.psh.spv delete mode 100644 Tests/DiligentCoreTest/assets/shaders/SPIRV/StorageBuffers.psh.spv delete mode 100644 Tests/DiligentCoreTest/assets/shaders/SPIRV/StorageImages.psh.spv delete mode 100644 Tests/DiligentCoreTest/assets/shaders/SPIRV/TexelBuffers.psh.spv delete mode 100644 Tests/DiligentCoreTest/assets/shaders/SPIRV/Textures.psh.spv delete mode 100644 Tests/DiligentCoreTest/assets/shaders/SPIRV/UniformBuffers.psh.spv diff --git a/Tests/DiligentCoreTest/assets/shaders/SPIRV/AccelerationStructures.glsl.spv b/Tests/DiligentCoreTest/assets/shaders/SPIRV/AccelerationStructures.glsl.spv deleted file mode 100644 index 8185adc4129e606387b9baba7607912f310f893e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1424 zcmY+D%WG3n5XL9(Hm#|(FW)AOui6-2ZLL-<0VRq7qY-f6lH}m~GflrY&yorp>aJwnqI~@bLbV zpcn21{a)B?cUy{0TTG$VTBBBe-QOy&tX^hk&Jr#Gz9}2G&$DJp>94|e7smnNuy9eh zDkSuaYyGATN#(58f_u-O{&$q6%xB2qHUG0a@xO4vT zjrQAZ=fRh>Q`*1NYqzKhn|gM`z0OX!<#JM6E2uP^+nq+gH)!@{R~1M76T%nug-tKm zUn84+ivoflyWlLd8Ffmp1=qDXeO`K6TwYjEd`2raae3KeTH(N)?5yMUCn27*;kb3; zC$+`|_>IV>W;o(=T8StBvTV*eBuF-WJU#jN6Vi$C`A%tmW`BD8F7~cxKaF^jT-|> z&MR6GY;t1rPKd8@Mf#t}rk*t+`@MLpr0VGXy5RHEpYLT|x=yL^RyWWD-z)Y_0a??O z@dosXaKFFAq_k2K@6L>K*Vx=UGmCv&Ht#zn@V1Y{=CmG+ICz9}cNNPXeag;X*9q7& z0`CsqN1U$N#o>D_j=tvvc*Jw_(&5PO^DRgx7N4*0h;(Mj*LPGp96(0vJ0=_d$EcR$ z(#Z*bN4LXWz*XcgXk8TG@&e~kYf*srF=wR{!@T*JbJF2IME#wY&ildFqqn^vom}{q z1kUH~;nA5tW{jN7&^3Yi!DcpA1>#>!PdZ;-I`hOzEv&>aQ_K-FL(bp2k#*rORmELE diff --git a/Tests/DiligentCoreTest/assets/shaders/SPIRV/AtomicCounters.glsl.spv b/Tests/DiligentCoreTest/assets/shaders/SPIRV/AtomicCounters.glsl.spv deleted file mode 100644 index e43278dd9e7ccc8cb6820ad43b88fb4422c53709..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1140 zcmY+COHWf#6ot2xTkyq01bpHx#V6W0P-9}$U=z!L0f~uI(?B64KuvAOI`nrj@xS;B zoEZJSd(So3)9mcM)?Rm=bM|Rtsy!2NE-uDwbfR2~F$EKF%_8@9KJ0Y9jQ2awos85&-Z@RKkN=mZkrRi zmur>SMpNN-!AA7BgPb?-p?9zKf4vg7YS=y25?F z!?U>Le!*m9wVum;%wo^#`-`_wIfr?|**Tw|biDf&Lf$hu2lE@;^|JRGFLnMu)v<4 za?ZT+zDF%z_r4F7ue={n%jvz#oP3W*g!ge@`@WlVa>n+&pSmZ6oIT%8{F{H8Mqv4{vFBKk-A!7qZ(bMHCrO`S43Gr#%GoVn*rTA4mS6T(z@Cd`JvLLo=OG)Mre z<+gcq{pO`{wsq-^E0<*)43(TH=MbEIShe5o4NTlc55p0oIbJ1Hv42xg1ub){AP32P zIOuhUqyD>-ZkLWTIR+fIH#df(ovk~)&b_tK@Dp;gdCs%9H{Wk(ol&p7v(_H9`(yc4 z&N{4v*!v{brk&ABJ8K8(3(Wjhj>xNp)5N!0>)CMB-tOd66kKto9?5dg5xyK^$(_H6$8GOCn-`(kK-R|5k?(5aZ*a${7Tr(~vjhtF&fUQl&cN@dOIBO5G z@n)8PtGLqYcE_Ep_$D#$?{=@>F<0ZC*fhGzMRpp)$pEh3v;wxLZ_b~|aa`VDZ`S)? zHGx!lM|Yv#8DygeYs20kYfZA<39Z8ow!n8++=m;mQ+z&0_hRmm@0xhdFRzX^In!F_ zZ_-WP^Qe;Ib48fPC-7@%>gSFq>0E105zDEg&YJeXT4zY{lbTA7RmfZKj+AFGF3(`y zlm69wcYsPWRB|l!TO?QRXI$>*-jwsk=BH5Safixz<8r+_Rn8lydcU_ptT?xlF#C(m zmayrF%|*-|Qc|t&B__|=+>v=yISML%4o(HDe+|;Uw1^V*gUhl zUt(wR-78~pcgWZ?&R{)5%o&Z{8L>1|x+D8|m#NPMd}I5(fVD=f^n=h$8iq zVL!c#yY$=3l45&aj0w5+GEAMiSgglmK?4Bv7nfZ0BJ$%C}SZ68EwM2|u zzsSCse-jl`o%Jf#nlu}3F7^;}hPMkS=Q@M2yR3Nbb*%4|&egA@iszbNM(a`M@vUZY9DpK-QjC6?K42dm-$PTGeq4lcdD$3zZ*FZ>1q84wTJkli247xxcij) zPVg5|dwPDd?=Y!3Ydpg}_!M=IjNPGosQYq<{_e_sRF3#YJo7=s-HkNcXZX%x&R*`x z=eZxk$He-+sk~)wx{3V)^^MZETj%?H8FMYZ+V~-AovKWso@?%_+%IZA0P_vMjyNXV z0`cyCMa5H(#Qg@$9`;P!-|)q)5qDnq%BU!=Y1D*b4149qt+cj&CT)N;y<9` zuc305qPEDpe?Ow0ttxWeGvC_$BUFxk()>R~9P@bo-|@v$pTzwc%pUel-}(o>xHaO5 b`wPBY&rjSx@x`qXcc1*55dW9zx6uCpF=Ecg diff --git a/Tests/DiligentCoreTest/assets/shaders/SPIRV/PushConstants.psh.spv b/Tests/DiligentCoreTest/assets/shaders/SPIRV/PushConstants.psh.spv deleted file mode 100644 index c775350dfc222989f541a3271943a11aac9d2532..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1192 zcmY+DU29WO5JgWClPY3AtZhXhUg@JyTF_dp)|P;Y(2{6Dd=Nrt(io^WlH7nk`Um{A zKKLTI*3CU74ov3Eo;`E+oFtX<_EHF?a68-#@50>HLK!50)$-UpJwM%LYGWrf$&H3Iv>^8<%8XVEd5QBj+*zjiXF_i z{lFG6-%NhQ+*RK30_Lt_odwK2#Xc=y-Y53Cz~U}qT9X~boYzF%9!9L~^KWp@ z+2mXUOYklDYBl$s`+VLZikVwqCR%sS2Kfpx!L>R}_l!M}E2m!QvYya)mv{?T>tT`m z_F~SxM@;Y%{-nq^IBPNA*iS{~A zedfNU*goI4eZGk%_6NlO#0fX3WgmARHLLSAY-c^kt;ti<0Umkkm8ZrRMeSGqOAO&9 zxxM1{Cd5NL_PUF`>VH+#+T3VKAP4wATkKDZ diff --git a/Tests/DiligentCoreTest/assets/shaders/SPIRV/StorageBuffers.psh.spv b/Tests/DiligentCoreTest/assets/shaders/SPIRV/StorageBuffers.psh.spv deleted file mode 100644 index 1d4aa191e1f37a87fe80e05d86e306490190dc28..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1844 zcmaKr+fNfw5XOg=w%~<}2zaAzsduzmO^k`rP+|gaBw)lh($IzQfS6@#!khjB{=L4K z`2BXzuqV-Yn(3VHn{Up{&e^Tkx-GK_Gn=vJ`e)5sEim;06P>lDP0F)B86JNjP?ODB zz2J0+c6DpWe^#Jjmxavo^RH=dH_yfg`8Z2Q8{@;nH0zb_!!RGdkfxy@XUA+aaH4G# zbk5NOTwk7CY98(HY?t|E?WVY*_Rijas`ra*dar8t^`s4hW5u=M;@Ylb4(MLWJIAxb zy^^QHDS7p{SM@k$)8dLAH_r2PFdAj)*;y5D*`+dPdyt==93Oau^QJZ3i|6}CHky`Q z2{r%DZxwfUI?j9FhFNd-)BeX{c9iDQa})6$Zwm8#Z5a#9yjKfU;ZB5k);JE1<2+X! z2NS0*=hJr_2YY<0=um`Kw{+$l`EYYG&bcbjdyvS`a3`!PZ}Nh>A%0T`4Tj#|fl6O; zaUIvy!nsM5%Q@uoj?>SKJpHW8$Yam)^QjL<9{O2%Fy97x-WQhZw-j;C`v;Sco_B=h zdd`OCZEW7*0q2av}X~&E}sCjh=UgkRN*DzIDa|9)S_pt z^|tb{}SH68BA^W2lqtcj7&48i2zk|!Sy9W$nPbj%Kn z?zTKSIAYArV|PLf4(*CO{ZM~FS$r!UF?Z$JqeA9Q_hn78arO)4*=o{G|yQ+k2 diff --git a/Tests/DiligentCoreTest/assets/shaders/SPIRV/StorageImages.psh.spv b/Tests/DiligentCoreTest/assets/shaders/SPIRV/StorageImages.psh.spv deleted file mode 100644 index 70ba9f816e016343a15b0a666abf173c623f833b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1212 zcmZ{i*-JuE5XMigtuC3GtygV>hm6T265Ur5BHITN=r6_FJ;NuBpf zB!!1P7{0ar=Cj}J1)aA1q<+-tJY3yf5^J6-l9odfx)cJGPH>RxoylgPc)X)a-7o>2&q1Z(sGCDmeLM{BP z^+vUFvWYQAL)*sBOTnP7{-SJG*PYB#P#ivQ-O!ukFG(FgTBE3VbUtRR=q7Nv54&Ox zC)mV1^(loxuyFWZq8xBYlv5ssEEW#m3LG&1^;r%%VCh@YNl$iM5NkzeRgqPl*hk@P zyaj?!U)~?VrzY=>;8T+x^{8sxxhnOf^h8|0nr!+xTwOLXY9e3i0e?$M4f1Y| dZQ0D>xI40mO>%b?gHQfMn_y?eezdJa=`U%+K`H=nhizt=y$ZasW?=prAU75_JYT#(d6wIH5%+h=TcX}V?Tz@x2A2y8)3m5$kB_W zvf8`q`G55#4f==jj-3Almp63f?0!*24hJ0OF+JsACQiSvoSxUe)fL=J|3{Zz$$tUj C^EJKz diff --git a/Tests/DiligentCoreTest/assets/shaders/SPIRV/Textures.psh.spv b/Tests/DiligentCoreTest/assets/shaders/SPIRV/Textures.psh.spv deleted file mode 100644 index 25fe64493431f634cc5c929132c61792d5620a3d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2068 zcmaKtT~AX%5QdjxtzRIhfPhLXeuGs(5k)=}6XS(f5cIC8azaQ%Ni9b2@Lzjl;`5wy zRyGivWV$o&%;Ha(*jP93S4&Byed)3N5$-p8!$tjYvuj?}D@P@Ho%)_lv`?%;BMHJnRo z1l_-{z_Q(Tr`^qp0nP2t@%8LScdt`$QG-`!E3wwW=Jq4MU-!Dr@9j==ZKJi`?rddU zuqq6u-@)7g@SKNYi+^Mo8~jh~!ZEQooZIqDEOBdm4Q{oF(UGOD=8Xuclop+AP2qnb0$>N#>U&0W*K zg2r=PV}Dn%mFO4Wa(_A2O%O9j+%@Lau|wEjigPsZ>ZOkIdOX`6oWpse=qq*lj69la zjT|4YF+Z)D#8=F<#99MJG0>s=gCh%?B^DRL{U#@Snx|jFI z_#IZ~Dey|Ti`@XZ$ErP!?K?C_+jnPQ+P*W-TVNl#aZg3xxqT~&zBBnY6n*>kEhzf- z>D^cK-OszOMBlru#C-3vqVF7XW1n-dZSV0rILmLMQ>=^Rnlp{sufE*eM?HUoTIX$| z=7_&%68U+6iu(o>YyGYdQD<$zjCqer%zM6qde6<3w;5C(JV!2PODsL-af$l|6l>-A z2`XpS%Kco4rM3RYiTe%|Yn^ua`gh0`?%L4wmIUF zt0ipl$ki`;mYZc%9_1)vE7;=B9kG|#E2#5C>=m}SeMW2*Tio-On6$zw_J^-OkNyRV ChMFn> diff --git a/Tests/DiligentCoreTest/assets/shaders/SPIRV/UniformBuffers.psh.spv b/Tests/DiligentCoreTest/assets/shaders/SPIRV/UniformBuffers.psh.spv deleted file mode 100644 index bd15f2fe9eaea9a49e324a73a491457799c0e3ba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1012 zcmY+BTT8=05QW!P>%HEsH%inOK`7{h2%=ysR6(Io5#Pe1AqHwIF^c{G|FbWG=i6p& z-7=jyXJ*dKZiBJh~u!)>-17_C0B=T99}2!Q+AQ0)J`~_899H|&7$sWl6}(e z`K2hPRpkD`4x`- zl6<3nsCeAnz4w;Y-fdcI--Wj}jib!fjsAP1rlxX-s*D3>j~#~wcw3k^AkUoPJeWK> zmu?dUI=g-M$I%ZrFY|Tuz-HS@N|xu2cF5X*Pay)WE}Ekc{uV_O{Nb`uR}jIfokXEsiUTv z?@TQ@-iRFc058aUttDj^g}22l$rDqvEKd&_C%HcNfCHn+xAGWGVswu*37ruc2iCm$wqYwT})7b&;N7IjGzl$L~#Q*>R diff --git a/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp b/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp index d042ea67ab..8ab2723f67 100644 --- a/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp +++ b/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp @@ -63,29 +63,7 @@ std::vector LoadSPIRVFromHLSL(const char* FilePath, SHADER_TYPE Sh { std::vector SPIRV; -#if DILIGENT_NO_HLSL - // When DILIGENT_NO_HLSL is defined, use {FilePath}.spv as raw SPIRV shader source. - // i.e. FilePath="Textures.psh", then we load RAW SPIRV from "Textures.psh.spv" - std::string SPIRVFilePath = std::string(FilePath) + ".spv"; - - RefCntAutoPtr pShaderSourceStreamFactory; - CreateDefaultShaderSourceStreamFactory("shaders/SPIRV", &pShaderSourceStreamFactory); - if (!pShaderSourceStreamFactory) - return {}; - - RefCntAutoPtr pSPIRVStream; - pShaderSourceStreamFactory->CreateInputStream(SPIRVFilePath.c_str(), &pSPIRVStream); - if (!pSPIRVStream) - return {}; - - const size_t ByteCodeSize = pSPIRVStream->GetSize(); - if (ByteCodeSize == 0 || ByteCodeSize % 4 != 0) - return {}; - - SPIRV.resize(ByteCodeSize / 4); - pSPIRVStream->Read(SPIRV.data(), ByteCodeSize); - -#else +#if !DILIGENT_NO_HLSL ShaderCreateInfo ShaderCI; ShaderCI.SourceLanguage = SHADER_SOURCE_LANGUAGE_HLSL; @@ -103,6 +81,7 @@ std::vector LoadSPIRVFromHLSL(const char* FilePath, SHADER_TYPE Sh GLSLangUtils::InitializeGlslang(); SPIRV = GLSLangUtils::HLSLtoSPIRV(ShaderCI, GLSLangUtils::SpirvVersion::Vk100, nullptr, nullptr); GLSLangUtils::FinalizeGlslang(); + #endif return SPIRV; @@ -112,30 +91,8 @@ std::vector LoadSPIRVFromGLSL(const char* FilePath, SHADER_TYPE Sh { std::vector SPIRV; -#if DILIGENT_NO_GLSLANG - // When DILIGENT_NO_GLSLANG is defined, use {FilePath}.spv as raw SPIRV shader source. - // i.e. FilePath="AtomicCounters.glsl", then we load RAW SPIRV from "AtomicCounters.glsl.spv" - std::string SPIRVFilePath = std::string(FilePath) + ".spv"; - - RefCntAutoPtr pShaderSourceStreamFactory; - CreateDefaultShaderSourceStreamFactory("shaders/SPIRV", &pShaderSourceStreamFactory); - if (!pShaderSourceStreamFactory) - return {}; - - RefCntAutoPtr pSPIRVStream; - pShaderSourceStreamFactory->CreateInputStream(SPIRVFilePath.c_str(), &pSPIRVStream); - if (!pSPIRVStream) - return {}; - - const size_t ByteCodeSize = pSPIRVStream->GetSize(); - if (ByteCodeSize == 0 || ByteCodeSize % 4 != 0) - return {}; - - SPIRV.resize(ByteCodeSize / 4); - pSPIRVStream->Read(SPIRV.data(), ByteCodeSize); - -#else - +#if !DILIGENT_NO_GLSLANG + RefCntAutoPtr pShaderSourceStreamFactory; CreateDefaultShaderSourceStreamFactory("shaders/SPIRV", &pShaderSourceStreamFactory); if (!pShaderSourceStreamFactory) @@ -187,6 +144,10 @@ void TestSPIRVResources(const char* FilePa const char* CombinedSamplerSuffix = nullptr, bool IsGLSL = false) { +#if DILIGENT_NO_GLSLANG || DILIGENT_NO_HLSL + GTEST_SKIP(); +#endif + const auto SPIRV = IsGLSL ? LoadSPIRVFromGLSL(FilePath, ShaderType) : LoadSPIRVFromHLSL(FilePath, ShaderType); ASSERT_FALSE(SPIRV.empty()) << "Failed to compile HLSL to SPIRV: " << FilePath; From 654278c36c9ce50bdf189231f988f1bec86a5c1f Mon Sep 17 00:00:00 2001 From: hzqst <113660872@qq.com> Date: Fri, 12 Dec 2025 15:37:12 +0800 Subject: [PATCH 12/20] BindingDecorationOffset not needed if NOT VULKAN_SUPPORTED OR NOT TARGET glslang, skip SPIRVShaderResourcesTest --- Tests/DiligentCoreTest/CMakeLists.txt | 2 +- .../src/ShaderTools/SPIRVShaderResourcesTest.cpp | 13 ++++--------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/Tests/DiligentCoreTest/CMakeLists.txt b/Tests/DiligentCoreTest/CMakeLists.txt index 283b0f3569..58c158778d 100644 --- a/Tests/DiligentCoreTest/CMakeLists.txt +++ b/Tests/DiligentCoreTest/CMakeLists.txt @@ -20,7 +20,7 @@ if(NOT WEBGPU_SUPPORTED) ) endif() -if(NOT VULKAN_SUPPORTED) +if(NOT VULKAN_SUPPORTED OR NOT TARGET glslang) list(REMOVE_ITEM SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/src/ShaderTools/SPIRVShaderResourcesTest.cpp ) diff --git a/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp b/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp index 8ab2723f67..8e5e65c516 100644 --- a/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp +++ b/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp @@ -50,13 +50,8 @@ struct SPIRVShaderResourceRefAttribs const SPIRVShaderResourceAttribs::ResourceType Type; const Uint8 ResourceDim; // RESOURCE_DIMENSION const Uint8 IsMS; - - // Offset in SPIRV words (uint32_t) of binding & descriptor set decorations in SPIRV binary - const uint32_t BindingDecorationOffset; - const uint32_t DescriptorSetDecorationOffset; - - const Uint32 BufferStaticSize; - const Uint32 BufferStride; + const Uint32 BufferStaticSize; + const Uint32 BufferStride; }; std::vector LoadSPIRVFromHLSL(const char* FilePath, SHADER_TYPE ShaderType = SHADER_TYPE_PIXEL) @@ -92,7 +87,7 @@ std::vector LoadSPIRVFromGLSL(const char* FilePath, SHADER_TYPE Sh std::vector SPIRV; #if !DILIGENT_NO_GLSLANG - + RefCntAutoPtr pShaderSourceStreamFactory; CreateDefaultShaderSourceStreamFactory("shaders/SPIRV", &pShaderSourceStreamFactory); if (!pShaderSourceStreamFactory) @@ -145,7 +140,7 @@ void TestSPIRVResources(const char* FilePa bool IsGLSL = false) { #if DILIGENT_NO_GLSLANG || DILIGENT_NO_HLSL - GTEST_SKIP(); + GTEST_SKIP(); #endif const auto SPIRV = IsGLSL ? LoadSPIRVFromGLSL(FilePath, ShaderType) : LoadSPIRVFromHLSL(FilePath, ShaderType); From d2a7a961d213bd28928349cb5f82b82207ee7237 Mon Sep 17 00:00:00 2001 From: hzqst <113660872@qq.com> Date: Fri, 12 Dec 2025 15:38:34 +0800 Subject: [PATCH 13/20] Test-only constructor for SPIRVShaderResourceAttribs not needed --- .../include/SPIRVShaderResources.hpp | 9 -------- .../ShaderTools/src/SPIRVShaderResources.cpp | 22 ------------------- 2 files changed, 31 deletions(-) diff --git a/Graphics/ShaderTools/include/SPIRVShaderResources.hpp b/Graphics/ShaderTools/include/SPIRVShaderResources.hpp index 2d54bc5e70..33dc6b3f4d 100644 --- a/Graphics/ShaderTools/include/SPIRVShaderResources.hpp +++ b/Graphics/ShaderTools/include/SPIRVShaderResources.hpp @@ -118,15 +118,6 @@ struct SPIRVShaderResourceAttribs ResourceType _Type, Uint32 _BufferStaticSize) noexcept; - // Test-only constructor for creating reference resources - SPIRVShaderResourceAttribs(const char* _Name, - ResourceType _Type, - Uint16 _ArraySize, - RESOURCE_DIMENSION _ResourceDim, - Uint8 _IsMS, - Uint32 _BufferStaticSize, - Uint32 _BufferStride) noexcept; - ShaderResourceDesc GetResourceDesc() const { return ShaderResourceDesc{Name, GetShaderResourceType(Type), ArraySize}; diff --git a/Graphics/ShaderTools/src/SPIRVShaderResources.cpp b/Graphics/ShaderTools/src/SPIRVShaderResources.cpp index 240a233700..16edca462a 100644 --- a/Graphics/ShaderTools/src/SPIRVShaderResources.cpp +++ b/Graphics/ShaderTools/src/SPIRVShaderResources.cpp @@ -150,28 +150,6 @@ SPIRVShaderResourceAttribs::SPIRVShaderResourceAttribs(const char* _Name, // clang-format on {} -// Test-only constructor for creating reference resources -SPIRVShaderResourceAttribs::SPIRVShaderResourceAttribs(const char* _Name, - ResourceType _Type, - Uint16 _ArraySize, - RESOURCE_DIMENSION _ResourceDim, - Uint8 _IsMS, - Uint32 _BufferStaticSize, - Uint32 _BufferStride) noexcept : - // clang-format off - Name {_Name}, - ArraySize {_ArraySize}, - Type {_Type}, - ResourceDim {static_cast(_ResourceDim)}, - IsMS {_IsMS}, - BindingDecorationOffset {0}, // Not used in tests - DescriptorSetDecorationOffset {0}, // Not used in tests - BufferStaticSize {_BufferStaticSize}, - BufferStride {_BufferStride} -// clang-format on -{} - - SHADER_RESOURCE_TYPE SPIRVShaderResourceAttribs::GetShaderResourceType(ResourceType Type) { static_assert(Uint32{SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes} == 13, "Please handle the new resource type below"); From b93202bac2435b6d3eb7071ba134399abc554c75 Mon Sep 17 00:00:00 2001 From: hzqst <113660872@qq.com> Date: Fri, 12 Dec 2025 15:44:18 +0800 Subject: [PATCH 14/20] Add test for GetInlineConstantCountOrThrow --- .../src/ShaderTools/SPIRVShaderResourcesTest.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp b/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp index 8e5e65c516..fa8200dd32 100644 --- a/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp +++ b/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp @@ -188,6 +188,12 @@ void TestSPIRVResources(const char* FilePa EXPECT_EQ(Res.IsMS, pRefRes->IsMS) << Res.Name; EXPECT_EQ(Res.BufferStaticSize, pRefRes->BufferStaticSize) << Res.Name; EXPECT_EQ(Res.BufferStride, pRefRes->BufferStride) << Res.Name; + + if (Res.Type == SPIRVShaderResourceAttribs::ResourceType::UniformBuffer || + Res.Type == SPIRVShaderResourceAttribs::ResourceType::PushConstant) + { + EXPECT_EQ(Res.GetInlineConstantCountOrThrow(FilePath), pRefRes->BufferStride / 4) << Res.Name; + } } } From 5317509befbc726a9658903072496dde067d8c3d Mon Sep 17 00:00:00 2001 From: hzqst <113660872@qq.com> Date: Fri, 12 Dec 2025 15:45:04 +0800 Subject: [PATCH 15/20] remove dup EXPECT_EQ --- .../src/ShaderTools/SPIRVShaderResourcesTest.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp b/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp index fa8200dd32..d5cc6b8d68 100644 --- a/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp +++ b/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp @@ -181,7 +181,6 @@ void TestSPIRVResources(const char* FilePa const auto* pRefRes = RefResourcesMap[Res.Name]; ASSERT_NE(pRefRes, nullptr) << "Resource '" << Res.Name << "' is not found in the reference list"; - EXPECT_EQ(Res.ArraySize, pRefRes->ArraySize) << Res.Name; EXPECT_STREQ(SPIRVShaderResourceAttribs::ResourceTypeToString(Res.Type), SPIRVShaderResourceAttribs::ResourceTypeToString(pRefRes->Type)) << Res.Name; EXPECT_EQ(Res.ArraySize, pRefRes->ArraySize) << Res.Name; EXPECT_EQ(Res.ResourceDim, pRefRes->ResourceDim) << Res.Name; From e8addd91c6be13f671c7186dc192f5ee6ac9cc3e Mon Sep 17 00:00:00 2001 From: hzqst <113660872@qq.com> Date: Fri, 12 Dec 2025 16:22:43 +0800 Subject: [PATCH 16/20] fix typo --- .../src/ShaderTools/SPIRVShaderResourcesTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp b/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp index d5cc6b8d68..bf9d68334f 100644 --- a/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp +++ b/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp @@ -191,7 +191,7 @@ void TestSPIRVResources(const char* FilePa if (Res.Type == SPIRVShaderResourceAttribs::ResourceType::UniformBuffer || Res.Type == SPIRVShaderResourceAttribs::ResourceType::PushConstant) { - EXPECT_EQ(Res.GetInlineConstantCountOrThrow(FilePath), pRefRes->BufferStride / 4) << Res.Name; + EXPECT_EQ(Res.GetInlineConstantCountOrThrow(FilePath), pRefRes->BufferStaticSize / 4) << Res.Name; } } } From 2d42263c2f1255f1a63fd7214133149d0def4cb2 Mon Sep 17 00:00:00 2001 From: hzqst <113660872@qq.com> Date: Fri, 12 Dec 2025 16:23:50 +0800 Subject: [PATCH 17/20] no need to use InitializeGlslang/FinalizeGlslang as already been called by TestingEnvironmentVk. --- .../src/ShaderTools/SPIRVShaderResourcesTest.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp b/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp index bf9d68334f..8e27133ee8 100644 --- a/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp +++ b/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp @@ -73,9 +73,7 @@ std::vector LoadSPIRVFromHLSL(const char* FilePath, SHADER_TYPE Sh ShaderCI.pShaderSourceStreamFactory = pShaderSourceStreamFactory; - GLSLangUtils::InitializeGlslang(); SPIRV = GLSLangUtils::HLSLtoSPIRV(ShaderCI, GLSLangUtils::SpirvVersion::Vk100, nullptr, nullptr); - GLSLangUtils::FinalizeGlslang(); #endif @@ -125,9 +123,7 @@ std::vector LoadSPIRVFromGLSL(const char* FilePath, SHADER_TYPE Sh Attribs.Version = Version; Attribs.AssignBindings = true; - GLSLangUtils::InitializeGlslang(); SPIRV = GLSLangUtils::GLSLtoSPIRV(Attribs); - GLSLangUtils::FinalizeGlslang(); #endif return SPIRV; From 0ea6f7b9910737d1e9c940545b43c26c48c1e471 Mon Sep 17 00:00:00 2001 From: hzqst <113660872@qq.com> Date: Fri, 12 Dec 2025 16:40:45 +0800 Subject: [PATCH 18/20] For push constants, ArraySize always be 1 --- Graphics/ShaderTools/src/SPIRVShaderResources.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Graphics/ShaderTools/src/SPIRVShaderResources.cpp b/Graphics/ShaderTools/src/SPIRVShaderResources.cpp index 16edca462a..92fef6e43a 100644 --- a/Graphics/ShaderTools/src/SPIRVShaderResources.cpp +++ b/Graphics/ShaderTools/src/SPIRVShaderResources.cpp @@ -137,9 +137,9 @@ SPIRVShaderResourceAttribs::SPIRVShaderResourceAttribs(const char* _Name, Uint32 _BufferStaticSize) noexcept : // clang-format off Name {_Name}, - // For push constants, ArraySize represents the number of 32-bit constants (BufferStaticSize / 4) + // For push constants, ArraySize always be 1 // This is consistent with how inline constants work in the pipeline resource signature - ArraySize {static_cast(_BufferStaticSize / sizeof(Uint32))}, + ArraySize {1}, Type {_Type}, ResourceDim {RESOURCE_DIM_BUFFER}, IsMS {0}, From 98033c3e76b661a302a944935b531a98b92474c9 Mon Sep 17 00:00:00 2001 From: hzqst <113660872@qq.com> Date: Fri, 12 Dec 2025 16:57:09 +0800 Subject: [PATCH 19/20] fix PushConstant ArraySize --- .../src/ShaderTools/SPIRVShaderResourcesTest.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp b/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp index 8e27133ee8..7916273c35 100644 --- a/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp +++ b/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp @@ -301,7 +301,7 @@ TEST(SPIRVShaderResources, PushConstants) // Total: 16 + 4 + 2 + 1 + 1 = 24 floats/uints = 24 * 4 bytes = 96 bytes = 24 words TestSPIRVResources("PushConstants.psh", { - SPIRVShaderResourceRefAttribs{"PushConstants", 24, SPIRVResourceType::PushConstant, RESOURCE_DIM_BUFFER, 0, 96, 0}, + SPIRVShaderResourceRefAttribs{"PushConstants", 1, SPIRVResourceType::PushConstant, RESOURCE_DIM_BUFFER, 0, 96, 0}, }); } @@ -321,7 +321,7 @@ TEST(SPIRVShaderResources, MixedResources) SPIRVShaderResourceRefAttribs{"StorageTex", 1, SPIRVResourceType::StorageImage, RESOURCE_DIM_TEX_2D, 0, 0, 0}, SPIRVShaderResourceRefAttribs{"Sampler", 1, SPIRVResourceType::SeparateSampler, RESOURCE_DIM_UNDEFINED, 0, 0, 0}, // PushConstants: float2 (2 floats) + float (1 float) + uint (1 uint) = 4 words = 16 bytes - SPIRVShaderResourceRefAttribs{"PushConstants", 4, SPIRVResourceType::PushConstant, RESOURCE_DIM_BUFFER, 0, 16, 0}, + SPIRVShaderResourceRefAttribs{"PushConstants", 1, SPIRVResourceType::PushConstant, RESOURCE_DIM_BUFFER, 0, 16, 0}, }); } From cf905998d2a112a2979c548e54b2469ab29d8aec Mon Sep 17 00:00:00 2001 From: assiduous Date: Fri, 12 Dec 2025 20:45:20 -0800 Subject: [PATCH 20/20] Fixed memory leaks in the test + code cleanup --- .../include/SPIRVShaderResources.hpp | 20 ++++-- .../ShaderTools/src/SPIRVShaderResources.cpp | 9 ++- Tests/DiligentCoreTest/CMakeLists.txt | 2 +- .../assets/shaders/SPIRV/InputAttachments.psh | 2 +- .../assets/shaders/SPIRV/MixedResources.psh | 2 +- .../assets/shaders/SPIRV/PushConstants.psh | 2 +- .../assets/shaders/SPIRV/StorageBuffers.psh | 2 +- .../assets/shaders/SPIRV/StorageImages.psh | 2 +- .../assets/shaders/SPIRV/TexelBuffers.psh | 2 +- .../assets/shaders/SPIRV/Textures.psh | 2 +- .../assets/shaders/SPIRV/UniformBuffers.psh | 2 +- .../ShaderTools/SPIRVShaderResourcesTest.cpp | 72 +++++++++---------- 12 files changed, 60 insertions(+), 59 deletions(-) diff --git a/Graphics/ShaderTools/include/SPIRVShaderResources.hpp b/Graphics/ShaderTools/include/SPIRVShaderResources.hpp index 33dc6b3f4d..51d07f7904 100644 --- a/Graphics/ShaderTools/include/SPIRVShaderResources.hpp +++ b/Graphics/ShaderTools/include/SPIRVShaderResources.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2019-2024 Diligent Graphics LLC + * Copyright 2019-2025 Diligent Graphics LLC * Copyright 2015-2019 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -32,9 +32,19 @@ // SPIRVShaderResources class uses continuous chunk of memory to store all resources, as follows: // -// m_MemoryBuffer m_TotalResources -// | | | -// | Uniform Buffers | Storage Buffers | Storage Images | Sampled Images | Atomic Counters | Separate Samplers | Separate Images | Input Attachments | Accel Structs | Push Constants | Stage Inputs | Resource Names | +// _ _ _ m_MemoryBuffer +// | Uniform Buffers | +// | Storage Buffers | | +// | Storage Images | V +// | Sampled Images | +// | Atomic Counters | +// | Separate Samplers | +// | Separate Images | +// | Input Attachments | +// | Accel Structs | +// | Push Constants | _ _ _ m_TotalResources +// | Stage Inputs | +// | Resource Names | #include #include @@ -79,7 +89,7 @@ struct SPIRVShaderResourceAttribs SeparateSampler, InputAttachment, AccelerationStructure, - PushConstant, // Vulkan push constant buffer - special inline constant that uses vkCmdPushConstants + PushConstant, NumResourceTypes }; diff --git a/Graphics/ShaderTools/src/SPIRVShaderResources.cpp b/Graphics/ShaderTools/src/SPIRVShaderResources.cpp index 92fef6e43a..8ef61ab0bd 100644 --- a/Graphics/ShaderTools/src/SPIRVShaderResources.cpp +++ b/Graphics/ShaderTools/src/SPIRVShaderResources.cpp @@ -137,7 +137,7 @@ SPIRVShaderResourceAttribs::SPIRVShaderResourceAttribs(const char* _Name, Uint32 _BufferStaticSize) noexcept : // clang-format off Name {_Name}, - // For push constants, ArraySize always be 1 + // For push constants, ArraySize is always 1 // This is consistent with how inline constants work in the pipeline resource signature ArraySize {1}, Type {_Type}, @@ -217,8 +217,7 @@ PIPELINE_RESOURCE_FLAGS SPIRVShaderResourceAttribs::GetPipelineResourceFlags(Res return PIPELINE_RESOURCE_FLAG_COMBINED_SAMPLER; case SPIRVShaderResourceAttribs::ResourceType::PushConstant: - // Push constants are special inline constants that use vkCmdPushConstants - // Mark them with both INLINE_CONSTANTS and VULKAN_PUSH_CONSTANT flags + // Push constants map to constant buffer with the inline constants flag return PIPELINE_RESOURCE_FLAG_INLINE_CONSTANTS; default: @@ -1078,8 +1077,8 @@ std::string SPIRVShaderResources::DumpResources() const }, [&](const SPIRVShaderResourceAttribs& SepImg, Uint32) // { - VERIFY(SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage || - SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer, + VERIFY((SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage || + SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer), "Unexpected resource type"); if (SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer) { diff --git a/Tests/DiligentCoreTest/CMakeLists.txt b/Tests/DiligentCoreTest/CMakeLists.txt index 58c158778d..478a3f0559 100644 --- a/Tests/DiligentCoreTest/CMakeLists.txt +++ b/Tests/DiligentCoreTest/CMakeLists.txt @@ -20,7 +20,7 @@ if(NOT WEBGPU_SUPPORTED) ) endif() -if(NOT VULKAN_SUPPORTED OR NOT TARGET glslang) +if(NOT ${DILIGENT_USE_SPIRV_TOOLCHAIN} OR ${DILIGENT_NO_GLSLANG}) list(REMOVE_ITEM SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/src/ShaderTools/SPIRVShaderResourcesTest.cpp ) diff --git a/Tests/DiligentCoreTest/assets/shaders/SPIRV/InputAttachments.psh b/Tests/DiligentCoreTest/assets/shaders/SPIRV/InputAttachments.psh index 817e0d09e8..1691087c1b 100644 --- a/Tests/DiligentCoreTest/assets/shaders/SPIRV/InputAttachments.psh +++ b/Tests/DiligentCoreTest/assets/shaders/SPIRV/InputAttachments.psh @@ -11,4 +11,4 @@ float4 main() : SV_Target // Process the input color return color * 2.0; -} \ No newline at end of file +} diff --git a/Tests/DiligentCoreTest/assets/shaders/SPIRV/MixedResources.psh b/Tests/DiligentCoreTest/assets/shaders/SPIRV/MixedResources.psh index b89b11a210..ac86013752 100644 --- a/Tests/DiligentCoreTest/assets/shaders/SPIRV/MixedResources.psh +++ b/Tests/DiligentCoreTest/assets/shaders/SPIRV/MixedResources.psh @@ -63,4 +63,4 @@ float4 main() : SV_Target color.rgb *= sin(g_PushConstants.Time) * 0.5 + 0.5; return color; -} \ No newline at end of file +} diff --git a/Tests/DiligentCoreTest/assets/shaders/SPIRV/PushConstants.psh b/Tests/DiligentCoreTest/assets/shaders/SPIRV/PushConstants.psh index 53aafb2a53..9020ed7444 100644 --- a/Tests/DiligentCoreTest/assets/shaders/SPIRV/PushConstants.psh +++ b/Tests/DiligentCoreTest/assets/shaders/SPIRV/PushConstants.psh @@ -23,4 +23,4 @@ float4 main() : SV_Target result.xy += g_PushConstants.g_Offset; return result; -} \ No newline at end of file +} diff --git a/Tests/DiligentCoreTest/assets/shaders/SPIRV/StorageBuffers.psh b/Tests/DiligentCoreTest/assets/shaders/SPIRV/StorageBuffers.psh index 9fd5506489..c47aebf8e2 100644 --- a/Tests/DiligentCoreTest/assets/shaders/SPIRV/StorageBuffers.psh +++ b/Tests/DiligentCoreTest/assets/shaders/SPIRV/StorageBuffers.psh @@ -40,4 +40,4 @@ float4 main() : SV_Target g_RWAtomicBuffer.Store(0, atomicValue + 1); return result; -} \ No newline at end of file +} diff --git a/Tests/DiligentCoreTest/assets/shaders/SPIRV/StorageImages.psh b/Tests/DiligentCoreTest/assets/shaders/SPIRV/StorageImages.psh index d475a0137c..3a5537e0a9 100644 --- a/Tests/DiligentCoreTest/assets/shaders/SPIRV/StorageImages.psh +++ b/Tests/DiligentCoreTest/assets/shaders/SPIRV/StorageImages.psh @@ -17,4 +17,4 @@ float4 main() : SV_Target color += g_RWImage3D[uint3(0, 0, 0)]; return color; -} \ No newline at end of file +} diff --git a/Tests/DiligentCoreTest/assets/shaders/SPIRV/TexelBuffers.psh b/Tests/DiligentCoreTest/assets/shaders/SPIRV/TexelBuffers.psh index f61ec5a607..737cfdc044 100644 --- a/Tests/DiligentCoreTest/assets/shaders/SPIRV/TexelBuffers.psh +++ b/Tests/DiligentCoreTest/assets/shaders/SPIRV/TexelBuffers.psh @@ -12,4 +12,4 @@ float4 main() : SV_Target // Read back from storage texel buffer return g_StorageTexelBuffer[0]; -} \ No newline at end of file +} diff --git a/Tests/DiligentCoreTest/assets/shaders/SPIRV/Textures.psh b/Tests/DiligentCoreTest/assets/shaders/SPIRV/Textures.psh index 46d7ae89fc..525244ce25 100644 --- a/Tests/DiligentCoreTest/assets/shaders/SPIRV/Textures.psh +++ b/Tests/DiligentCoreTest/assets/shaders/SPIRV/Textures.psh @@ -27,4 +27,4 @@ float4 main() : SV_Target float4 color6 = g_Texture.Sample(g_Texture_sampler, float2(0.5, 0.5)); return color1 + color2 + color3 + color4 + color5 + color6; -} \ No newline at end of file +} diff --git a/Tests/DiligentCoreTest/assets/shaders/SPIRV/UniformBuffers.psh b/Tests/DiligentCoreTest/assets/shaders/SPIRV/UniformBuffers.psh index 63a93344bb..ae8e697849 100644 --- a/Tests/DiligentCoreTest/assets/shaders/SPIRV/UniformBuffers.psh +++ b/Tests/DiligentCoreTest/assets/shaders/SPIRV/UniformBuffers.psh @@ -21,4 +21,4 @@ cbuffer CB2 : register(b2) float4 main() : SV_Target { return g_Color * g_MaterialParams; -} \ No newline at end of file +} diff --git a/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp b/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp index 7916273c35..827b76e289 100644 --- a/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp +++ b/Tests/DiligentCoreTest/src/ShaderTools/SPIRVShaderResourcesTest.cpp @@ -33,6 +33,7 @@ #include #include +#include #include "TestingEnvironment.hpp" #include "gtest/gtest.h" @@ -43,12 +44,27 @@ using namespace Diligent::Testing; namespace { +class SPIRVShaderResourcesTest : public ::testing::Test +{ +protected: + static void SetUpTestSuite() + { + GLSLangUtils::InitializeGlslang(); + } + + static void TearDownTestSuite() + { + GLSLangUtils::FinalizeGlslang(); + } +}; + + struct SPIRVShaderResourceRefAttribs { const char* const Name; const Uint16 ArraySize; const SPIRVShaderResourceAttribs::ResourceType Type; - const Uint8 ResourceDim; // RESOURCE_DIMENSION + const RESOURCE_DIMENSION ResourceDim; const Uint8 IsMS; const Uint32 BufferStaticSize; const Uint32 BufferStride; @@ -56,10 +72,6 @@ struct SPIRVShaderResourceRefAttribs std::vector LoadSPIRVFromHLSL(const char* FilePath, SHADER_TYPE ShaderType = SHADER_TYPE_PIXEL) { - std::vector SPIRV; - -#if !DILIGENT_NO_HLSL - ShaderCreateInfo ShaderCI; ShaderCI.SourceLanguage = SHADER_SOURCE_LANGUAGE_HLSL; ShaderCI.FilePath = FilePath; @@ -73,19 +85,11 @@ std::vector LoadSPIRVFromHLSL(const char* FilePath, SHADER_TYPE Sh ShaderCI.pShaderSourceStreamFactory = pShaderSourceStreamFactory; - SPIRV = GLSLangUtils::HLSLtoSPIRV(ShaderCI, GLSLangUtils::SpirvVersion::Vk100, nullptr, nullptr); - -#endif - - return SPIRV; + return GLSLangUtils::HLSLtoSPIRV(ShaderCI, GLSLangUtils::SpirvVersion::Vk100, nullptr, nullptr); } std::vector LoadSPIRVFromGLSL(const char* FilePath, SHADER_TYPE ShaderType = SHADER_TYPE_PIXEL) { - std::vector SPIRV; - -#if !DILIGENT_NO_GLSLANG - RefCntAutoPtr pShaderSourceStreamFactory; CreateDefaultShaderSourceStreamFactory("shaders/SPIRV", &pShaderSourceStreamFactory); if (!pShaderSourceStreamFactory) @@ -96,7 +100,7 @@ std::vector LoadSPIRVFromGLSL(const char* FilePath, SHADER_TYPE Sh if (!pShaderSourceStream) return {}; - auto ShaderSourceSize = pShaderSourceStream->GetSize(); + size_t ShaderSourceSize = pShaderSourceStream->GetSize(); if (ShaderSourceSize == 0) return {}; @@ -123,10 +127,7 @@ std::vector LoadSPIRVFromGLSL(const char* FilePath, SHADER_TYPE Sh Attribs.Version = Version; Attribs.AssignBindings = true; - SPIRV = GLSLangUtils::GLSLtoSPIRV(Attribs); - -#endif - return SPIRV; + return GLSLangUtils::GLSLtoSPIRV(Attribs); } void TestSPIRVResources(const char* FilePath, @@ -135,10 +136,6 @@ void TestSPIRVResources(const char* FilePa const char* CombinedSamplerSuffix = nullptr, bool IsGLSL = false) { -#if DILIGENT_NO_GLSLANG || DILIGENT_NO_HLSL - GTEST_SKIP(); -#endif - const auto SPIRV = IsGLSL ? LoadSPIRVFromGLSL(FilePath, ShaderType) : LoadSPIRVFromHLSL(FilePath, ShaderType); ASSERT_FALSE(SPIRV.empty()) << "Failed to compile HLSL to SPIRV: " << FilePath; @@ -156,17 +153,12 @@ void TestSPIRVResources(const char* FilePa false, // LoadUniformBufferReflection EntryPoint}; - LOG_INFO_MESSAGE("Testing shader:", FilePath); - if (CombinedSamplerSuffix != nullptr) - { - LOG_INFO_MESSAGE("Using CombinedSamplerSuffix:", CombinedSamplerSuffix); - } LOG_INFO_MESSAGE("SPIRV Resources:\n", Resources.DumpResources()); EXPECT_EQ(size_t{Resources.GetTotalResources()}, RefResources.size()); std::unordered_map RefResourcesMap; - for (const auto& RefRes : RefResources) + for (const SPIRVShaderResourceRefAttribs& RefRes : RefResources) { RefResourcesMap[RefRes.Name] = &RefRes; } @@ -194,7 +186,7 @@ void TestSPIRVResources(const char* FilePa using SPIRVResourceType = SPIRVShaderResourceAttribs::ResourceType; -TEST(SPIRVShaderResources, UniformBuffers) +TEST_F(SPIRVShaderResourcesTest, UniformBuffers) { TestSPIRVResources("UniformBuffers.psh", { @@ -204,7 +196,7 @@ TEST(SPIRVShaderResources, UniformBuffers) }); } -TEST(SPIRVShaderResources, StorageBuffers) +TEST_F(SPIRVShaderResourcesTest, StorageBuffers) { TestSPIRVResources("StorageBuffers.psh", { @@ -217,7 +209,7 @@ TEST(SPIRVShaderResources, StorageBuffers) }); } -TEST(SPIRVShaderResources, TexelBuffers) +TEST_F(SPIRVShaderResourcesTest, TexelBuffers) { TestSPIRVResources("TexelBuffers.psh", { @@ -226,7 +218,7 @@ TEST(SPIRVShaderResources, TexelBuffers) }); } -TEST(SPIRVShaderResources, Textures) +TEST_F(SPIRVShaderResourcesTest, Textures) { TestSPIRVResources("Textures.psh", { @@ -246,7 +238,7 @@ TEST(SPIRVShaderResources, Textures) }); } -TEST(SPIRVShaderResources, StorageImages) +TEST_F(SPIRVShaderResourcesTest, StorageImages) { TestSPIRVResources("StorageImages.psh", { @@ -257,7 +249,7 @@ TEST(SPIRVShaderResources, StorageImages) }); } -TEST(SPIRVShaderResources, AtomicCounters) +TEST_F(SPIRVShaderResourcesTest, AtomicCounters) { // Use GLSL for atomic counters. Note: Vulkan does not support atomic_uint (AtomicCounter storage class). // We use a storage buffer with atomic operations to simulate atomic counters. @@ -272,7 +264,7 @@ TEST(SPIRVShaderResources, AtomicCounters) true); // IsGLSL = true } -TEST(SPIRVShaderResources, InputAttachments) +TEST_F(SPIRVShaderResourcesTest, InputAttachments) { TestSPIRVResources("InputAttachments.psh", { @@ -280,7 +272,7 @@ TEST(SPIRVShaderResources, InputAttachments) }); } -TEST(SPIRVShaderResources, AccelerationStructures) +TEST_F(SPIRVShaderResourcesTest, AccelerationStructures) { // Use GLSL for acceleration structures since HLSLtoSPIRV doesn't support raytracing shaders // Acceleration structures are used in raytracing shaders, so we use SHADER_TYPE_RAY_GEN @@ -294,7 +286,7 @@ TEST(SPIRVShaderResources, AccelerationStructures) true); // IsGLSL = true } -TEST(SPIRVShaderResources, PushConstants) +TEST_F(SPIRVShaderResourcesTest, PushConstants) { // Push constant ArraySize represents the number of 32-bit words, not array elements // PushConstants struct: float4x4 (16 floats) + float4 (4 floats) + float2 (2 floats) + float (1 float) + uint (1 uint) @@ -305,7 +297,7 @@ TEST(SPIRVShaderResources, PushConstants) }); } -TEST(SPIRVShaderResources, MixedResources) +TEST_F(SPIRVShaderResourcesTest, MixedResources) { TestSPIRVResources("MixedResources.psh", { @@ -325,4 +317,4 @@ TEST(SPIRVShaderResources, MixedResources) }); } -} // namespace \ No newline at end of file +} // namespace