diff options
| -rw-r--r-- | source/slang/slang-emit-spirv.cpp | 43 | ||||
| -rw-r--r-- | tests/bindings/binding-spv-storage-class.slang | 55 |
2 files changed, 92 insertions, 6 deletions
diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp index 28d66497d..f5bb21c00 100644 --- a/source/slang/slang-emit-spirv.cpp +++ b/source/slang/slang-emit-spirv.cpp @@ -1791,6 +1791,32 @@ struct SPIRVEmitContext } } + static SpvStorageClass getSpvStorageClass(IRPtrTypeBase* ptrType) + { + SpvStorageClass storageClass = SpvStorageClassFunction; + if (ptrType && ptrType->hasAddressSpace()) + { + storageClass = (SpvStorageClass)ptrType->getAddressSpace(); + } + return storageClass; + } + + // https://registry.khronos.org/vulkan/specs/1.3/html/chap37.html#VUID-StandaloneSpirv-DescriptorSet-06491 + // Only UniformConstant, Uniform or StorageBuffer storage class are allowed to be decorated with descriptor + // set or binding. + static inline bool isBindingAllowed(SpvStorageClass storageClass) + { + switch(storageClass) + { + case SpvStorageClassUniformConstant: + case SpvStorageClassUniform: + case SpvStorageClassStorageBuffer: + return true; + default: + return false; + } + } + SpvCapability getImageFormatCapability(SpvImageFormat format) { switch (format) @@ -2137,6 +2163,10 @@ struct SPIRVEmitContext void emitVarLayout(IRInst* var, SpvInst* varInst, IRVarLayout* layout) { + auto dataType = as<IRPtrTypeBase>(var->getDataType()); + SpvStorageClass storageClass = getSpvStorageClass(dataType); + + bool isBindingDecorationAllowed = isBindingAllowed(storageClass); bool needDefaultSetBindingDecoration = false; bool hasExplicitSetBinding = false; bool isDescirptorSetDecorated = false; @@ -2196,11 +2226,15 @@ struct SPIRVEmitContext case LayoutResourceKind::UnorderedAccess: case LayoutResourceKind::SamplerState: case LayoutResourceKind::DescriptorTableSlot: + if (!isBindingDecorationAllowed) + break; + emitOpDecorateBinding( getSection(SpvLogicalSectionID::Annotations), nullptr, varInst, SpvLiteralInteger::from32(int32_t(index))); + if (!isDescirptorSetDecorated) { if (space) @@ -2219,7 +2253,7 @@ struct SPIRVEmitContext } break; case LayoutResourceKind::RegisterSpace: - if (!isDescirptorSetDecorated) + if (!isDescirptorSetDecorated && isBindingDecorationAllowed) { emitOpDecorateDescriptorSet( getSection(SpvLogicalSectionID::Annotations), @@ -4344,11 +4378,8 @@ struct SPIRVEmitContext { auto ptrType = as<IRPtrTypeBase>(inst->getDataType()); SLANG_ASSERT(ptrType); - SpvStorageClass storageClass = SpvStorageClassFunction; - if (ptrType->hasAddressSpace()) - { - storageClass = (SpvStorageClass)ptrType->getAddressSpace(); - } + SpvStorageClass storageClass = getSpvStorageClass(ptrType); + auto varSpvInst = emitOpVariable(parent, inst, inst->getFullType(), storageClass); maybeEmitName(varSpvInst, inst); maybeEmitPointerDecoration(varSpvInst, inst); diff --git a/tests/bindings/binding-spv-storage-class.slang b/tests/bindings/binding-spv-storage-class.slang new file mode 100644 index 000000000..5e93a1fbd --- /dev/null +++ b/tests/bindings/binding-spv-storage-class.slang @@ -0,0 +1,55 @@ +// binding-spv-storage-class.slang + +//TEST:SIMPLE(filecheck=GL-SPIRV): -stage anyhit -entry main -target spirv-assembly -emit-spirv-via-glsl +//TEST:SIMPLE(filecheck=SPIRV): -stage anyhit -entry main -target spirv + +// This test checks that the only the resource with Uniform, Storage or UniformConstant storage class can be decorated by binding or descriptor set. +struct MyStruct +{ + float3 org; + float3 dir; +}; + +// ShaderRecordKHR storage class +layout(shaderRecordNV) ConstantBuffer<MyStruct> myStruct : register(b0, space1); + +// Uniform buffer +ConstantBuffer<MyStruct> myStruct1 : register(b1, space1); + +// Storage buffer +RWStructuredBuffer<MyStruct> myStruct2 : register(b2, space1); + +// UniformConstant +Texture2D<float> texture: register(b3, space1); +SamplerState sampler: register(b4, space1); + +[shader("anyhit")] +void main(out float3 pos) +{ + pos = myStruct.org + myStruct.dir + + myStruct1.org + myStruct1.dir + + myStruct2[0].org + myStruct2[0].dir; + + pos.x = texture.SampleLevel( + sampler, + pos.xy, 0); +} + +// SPIRV: OpDecorate %myStruct1{{.*}} Binding 1 +// SPIRV: OpDecorate %myStruct1{{.*}} DescriptorSet 1 +// SPIRV: OpDecorate %myStruct2{{.*}} Binding 2 +// SPIRV: OpDecorate %myStruct2{{.*}} DescriptorSet 1 +// SPIRV: OpDecorate %texture{{.*}} Binding 3 +// SPIRV: OpDecorate %texture{{.*}} DescriptorSet 1 +// SPIRV: OpDecorate %sampler{{.*}} Binding 4 +// SPIRV: OpDecorate %sampler{{.*}} DescriptorSet 1 +// +// +// GL-SPIRV: OpDecorate %myStruct1{{.*}} DescriptorSet 1 +// GL-SPIRV: OpDecorate %myStruct1{{.*}} Binding 1 +// GL-SPIRV: OpDecorate %myStruct2{{.*}} DescriptorSet 1 +// GL-SPIRV: OpDecorate %myStruct2{{.*}} Binding 2 +// GL-SPIRV: OpDecorate %texture{{.*}} DescriptorSet 1 +// GL-SPIRV: OpDecorate %texture{{.*}} Binding 3 +// GL-SPIRV: OpDecorate %sampler{{.*}} DescriptorSet 1 +// GL-SPIRV: OpDecorate %sampler{{.*}} Binding 4 |
