summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--source/slang/slang-emit-spirv.cpp43
-rw-r--r--tests/bindings/binding-spv-storage-class.slang55
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