GLSL/SPV: Implement SPV_EXT_descriptor_indexing and GL_EXT_nonuniform_qualifier
diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp
index 74cb9e9..1434cba 100755
--- a/SPIRV/GlslangToSpv.cpp
+++ b/SPIRV/GlslangToSpv.cpp
@@ -102,6 +102,7 @@
struct OpDecorations {
spv::Decoration precision;
spv::Decoration noContraction;
+ spv::Decoration nonUniform;
};
} // namespace
@@ -136,12 +137,14 @@
spv::Decoration TranslateInterpolationDecoration(const glslang::TQualifier& qualifier);
spv::Decoration TranslateAuxiliaryStorageDecoration(const glslang::TQualifier& qualifier);
+ spv::Decoration TranslateNonUniformDecoration(const glslang::TQualifier& qualifier);
spv::BuiltIn TranslateBuiltInDecoration(glslang::TBuiltInVariable, bool memberDeclaration);
spv::ImageFormat TranslateImageFormat(const glslang::TType& type);
spv::SelectionControlMask TranslateSelectionControl(const glslang::TIntermSelection&) const;
spv::SelectionControlMask TranslateSwitchControl(const glslang::TIntermSwitch&) const;
spv::LoopControlMask TranslateLoopControl(const glslang::TIntermLoop&, unsigned int& dependencyLength) const;
spv::StorageClass TranslateStorageClass(const glslang::TType&);
+ void addIndirectionIndexCapabilities(const glslang::TType& baseType, const glslang::TType& indexType);
spv::Id createSpvVariable(const glslang::TIntermSymbol*);
spv::Id getSampledType(const glslang::TSampler&);
spv::Id getInvertedSwizzleType(const glslang::TIntermTyped&);
@@ -443,6 +446,17 @@
return spv::DecorationMax;
}
+// If glslang type is nonUniform, return SPIR-V NonUniform decoration.
+spv::Decoration TGlslangToSpvTraverser::TranslateNonUniformDecoration(const glslang::TQualifier& qualifier)
+{
+ if (qualifier.isNonUniform()) {
+ builder.addExtension("SPV_EXT_descriptor_indexing");
+ builder.addCapability(spv::CapabilityShaderNonUniformEXT);
+ return spv::DecorationNonUniformEXT;
+ } else
+ return spv::DecorationMax;
+}
+
// Translate a glslang built-in variable to a SPIR-V built in decoration. Also generate
// associated capabilities when required. For some built-in variables, a capability
// is generated only when using the variable in an executable instruction, but not when
@@ -889,6 +903,42 @@
return spv::StorageClassFunction;
}
+// Add capabilities pertaining to how an array is indexed.
+void TGlslangToSpvTraverser::addIndirectionIndexCapabilities(const glslang::TType& baseType,
+ const glslang::TType& indexType)
+{
+ if (indexType.getQualifier().isNonUniform()) {
+ // deal with an asserted non-uniform index
+ if (baseType.getBasicType() == glslang::EbtSampler) {
+ if (baseType.getQualifier().hasAttachment())
+ builder.addCapability(spv::CapabilityInputAttachmentArrayNonUniformIndexingEXT);
+ else if (baseType.isImage() && baseType.getSampler().dim == glslang::EsdBuffer)
+ builder.addCapability(spv::CapabilityStorageTexelBufferArrayNonUniformIndexingEXT);
+ else if (baseType.isTexture() && baseType.getSampler().dim == glslang::EsdBuffer)
+ builder.addCapability(spv::CapabilityUniformTexelBufferArrayNonUniformIndexingEXT);
+ else if (baseType.isImage())
+ builder.addCapability(spv::CapabilityStorageImageArrayNonUniformIndexingEXT);
+ else if (baseType.isTexture())
+ builder.addCapability(spv::CapabilitySampledImageArrayNonUniformIndexingEXT);
+ } else if (baseType.getBasicType() == glslang::EbtBlock) {
+ if (baseType.getQualifier().storage == glslang::EvqBuffer)
+ builder.addCapability(spv::CapabilityStorageBufferArrayNonUniformIndexingEXT);
+ else if (baseType.getQualifier().storage == glslang::EvqUniform)
+ builder.addCapability(spv::CapabilityUniformBufferArrayNonUniformIndexingEXT);
+ }
+ } else {
+ // assume a dynamically uniform index
+ if (baseType.getBasicType() == glslang::EbtSampler) {
+ if (baseType.getQualifier().hasAttachment())
+ builder.addCapability(spv::CapabilityInputAttachmentArrayDynamicIndexingEXT);
+ else if (baseType.isImage() && baseType.getSampler().dim == glslang::EsdBuffer)
+ builder.addCapability(spv::CapabilityStorageTexelBufferArrayDynamicIndexingEXT);
+ else if (baseType.isTexture() && baseType.getSampler().dim == glslang::EsdBuffer)
+ builder.addCapability(spv::CapabilityUniformTexelBufferArrayDynamicIndexingEXT);
+ }
+ }
+}
+
// Return whether or not the given type is something that should be tied to a
// descriptor set.
bool IsDescriptorResource(const glslang::TType& type)
@@ -1286,7 +1336,8 @@
// do the operation
OpDecorations decorations = { TranslatePrecisionDecoration(node->getOperationPrecision()),
- TranslateNoContractionDecoration(node->getType().getQualifier()) };
+ TranslateNoContractionDecoration(node->getType().getQualifier()),
+ TranslateNonUniformDecoration(node->getType().getQualifier()) };
rValue = createBinaryOperation(node->getOp(), decorations,
convertGlslangToSpvType(node->getType()), leftRValue, rValue,
node->getType().getBasicType());
@@ -1362,6 +1413,8 @@
node->getRight()->traverse(this);
spv::Id index = accessChainLoad(node->getRight()->getType());
+ addIndirectionIndexCapabilities(node->getLeft()->getType(), node->getRight()->getType());
+
// restore the saved access chain
builder.setAccessChain(partial);
@@ -1415,7 +1468,8 @@
// get result
OpDecorations decorations = { TranslatePrecisionDecoration(node->getOperationPrecision()),
- TranslateNoContractionDecoration(node->getType().getQualifier()) };
+ TranslateNoContractionDecoration(node->getType().getQualifier()),
+ TranslateNonUniformDecoration(node->getType().getQualifier()) };
spv::Id result = createBinaryOperation(node->getOp(), decorations,
convertGlslangToSpvType(node->getType()), left, right,
node->getLeft()->getType().getBasicType());
@@ -1454,6 +1508,11 @@
if (node->getOp() == glslang::EOpArrayLength) {
// Quite special; won't want to evaluate the operand.
+ // Currently, the front-end does not allow .length() on an array until it is sized,
+ // except for the last block membeor of an SSBO.
+ // TODO: If this changes, link-time sized arrays might show up here, and need their
+ // size extracted.
+
// Normal .length() would have been constant folded by the front-end.
// So, this has to be block.lastMember.length().
// SPV wants "block" and member number as the operands, go get them.
@@ -1495,7 +1554,8 @@
operand = accessChainLoad(node->getOperand()->getType());
OpDecorations decorations = { TranslatePrecisionDecoration(node->getOperationPrecision()),
- TranslateNoContractionDecoration(node->getType().getQualifier()) };
+ TranslateNoContractionDecoration(node->getType().getQualifier()),
+ TranslateNonUniformDecoration(node->getType().getQualifier()) };
// it could be a conversion
if (! result)
@@ -1506,8 +1566,10 @@
result = createUnaryOperation(node->getOp(), decorations, resultType(), operand, node->getOperand()->getBasicType());
if (result) {
- if (invertedType)
+ if (invertedType) {
result = createInvertedSwizzle(decorations.precision, *node->getOperand(), result);
+ builder.addDecoration(result, decorations.nonUniform);
+ }
builder.clearAccessChain();
builder.setAccessChainRValue(result);
@@ -1934,7 +1996,8 @@
builder.setLine(node->getLoc().line);
OpDecorations decorations = { precision,
- TranslateNoContractionDecoration(node->getType().getQualifier()) };
+ TranslateNoContractionDecoration(node->getType().getQualifier()),
+ TranslateNonUniformDecoration(node->getType().getQualifier()) };
result = createBinaryOperation(binOp, decorations,
resultType(), leftId, rightId,
left->getType().getBasicType(), reduceComparison);
@@ -2035,7 +2098,8 @@
case 1:
{
OpDecorations decorations = { precision,
- TranslateNoContractionDecoration(node->getType().getQualifier()) };
+ TranslateNoContractionDecoration(node->getType().getQualifier()),
+ TranslateNonUniformDecoration(node->getType().getQualifier()) };
result = createUnaryOperation(
node->getOp(), decorations,
resultType(), operands.front(),
@@ -2651,8 +2715,13 @@
// (Unsized arrays that survive through linking will be runtime-sized arrays)
if (type.isSizedArray())
spvType = builder.makeArrayType(spvType, makeArraySizeId(*type.getArraySizes(), 0), stride);
- else
+ else {
+ if (!lastBufferBlockMember) {
+ builder.addExtension("SPV_EXT_descriptor_indexing");
+ builder.addCapability(spv::CapabilityRuntimeDescriptorArrayEXT);
+ }
spvType = builder.makeRuntimeArray(spvType);
+ }
if (stride > 0)
builder.addDecoration(spvType, spv::DecorationArrayStride, stride);
}
@@ -2824,6 +2893,9 @@
if (builtIn != spv::BuiltInMax)
builder.addMemberDecoration(spvType, member, spv::DecorationBuiltIn, (int)builtIn);
+ // nonuniform
+ builder.addMemberDecoration(spvType, member, TranslateNonUniformDecoration(glslangMember.getQualifier()));
+
if (glslangIntermediate->getHlslFunctionality1() && memberQualifier.semanticName != nullptr) {
builder.addExtension("SPV_GOOGLE_hlsl_functionality1");
builder.addMemberDecoration(spvType, member, (spv::Decoration)spv::DecorationHlslSemanticGOOGLE,
@@ -2891,7 +2963,8 @@
spv::Id TGlslangToSpvTraverser::accessChainLoad(const glslang::TType& type)
{
spv::Id nominalTypeId = builder.accessChainGetInferredType();
- spv::Id loadedId = builder.accessChainLoad(TranslatePrecisionDecoration(type), nominalTypeId);
+ spv::Id loadedId = builder.accessChainLoad(TranslatePrecisionDecoration(type),
+ TranslateNonUniformDecoration(type.getQualifier()), nominalTypeId);
// Need to convert to abstract types when necessary
if (type.getBasicType() == glslang::EbtBool) {
@@ -4102,6 +4175,7 @@
spv::Id result = builder.createBinOp(binOp, typeId, left, right);
builder.addDecoration(result, decorations.noContraction);
+ builder.addDecoration(result, decorations.nonUniform);
return builder.setPrecision(result, decorations.precision);
}
@@ -4113,6 +4187,7 @@
if (reduceComparison && (op == glslang::EOpEqual || op == glslang::EOpNotEqual)
&& (builder.isVector(left) || builder.isMatrix(left) || builder.isAggregate(left))) {
spv::Id result = builder.createCompositeCompare(decorations.precision, left, right, op == glslang::EOpEqual);
+ builder.addDecoration(result, decorations.nonUniform);
return result;
}
@@ -4174,6 +4249,7 @@
if (binOp != spv::OpNop) {
spv::Id result = builder.createBinOp(binOp, typeId, left, right);
builder.addDecoration(result, decorations.noContraction);
+ builder.addDecoration(result, decorations.nonUniform);
return builder.setPrecision(result, decorations.precision);
}
@@ -4235,6 +4311,7 @@
if (firstClass) {
spv::Id result = builder.createBinOp(op, typeId, left, right);
builder.addDecoration(result, decorations.noContraction);
+ builder.addDecoration(result, decorations.nonUniform);
return builder.setPrecision(result, decorations.precision);
}
@@ -4274,11 +4351,13 @@
spv::Id rightVec = rightMat ? builder.createCompositeExtract(right, vecType, indexes) : smearVec;
spv::Id result = builder.createBinOp(op, vecType, leftVec, rightVec);
builder.addDecoration(result, decorations.noContraction);
+ builder.addDecoration(result, decorations.nonUniform);
results.push_back(builder.setPrecision(result, decorations.precision));
}
// put the pieces together
spv::Id result = builder.setPrecision(builder.createCompositeConstruct(typeId, results), decorations.precision);
+ builder.addDecoration(result, decorations.nonUniform);
return result;
}
default:
@@ -4687,6 +4766,7 @@
}
builder.addDecoration(id, decorations.noContraction);
+ builder.addDecoration(id, decorations.nonUniform);
return builder.setPrecision(id, decorations.precision);
}
@@ -4715,11 +4795,13 @@
spv::Id srcVec = builder.createCompositeExtract(operand, srcVecType, indexes);
spv::Id destVec = builder.createUnaryOp(op, destVecType, srcVec);
builder.addDecoration(destVec, decorations.noContraction);
+ builder.addDecoration(destVec, decorations.nonUniform);
results.push_back(builder.setPrecision(destVec, decorations.precision));
}
// put the pieces together
spv::Id result = builder.setPrecision(builder.createCompositeConstruct(typeId, results), decorations.precision);
+ builder.addDecoration(result, decorations.nonUniform);
return result;
}
@@ -5177,6 +5259,7 @@
result = builder.createUnaryOp(convOp, destType, operand);
result = builder.setPrecision(result, decorations.precision);
+ builder.addDecoration(result, decorations.nonUniform);
return result;
}
@@ -6396,6 +6479,9 @@
if (builtIn != spv::BuiltInMax)
builder.addDecoration(id, spv::DecorationBuiltIn, (int)builtIn);
+ // nonuniform
+ builder.addDecoration(id, TranslateNonUniformDecoration(symbol->getType().getQualifier()));
+
#ifdef NV_EXTENSIONS
if (builtIn == spv::BuiltInSampleMask) {
spv::Decoration decoration;
diff --git a/SPIRV/SpvBuilder.cpp b/SPIRV/SpvBuilder.cpp
index 1660787..27ce71c 100644
--- a/SPIRV/SpvBuilder.cpp
+++ b/SPIRV/SpvBuilder.cpp
@@ -2331,7 +2331,7 @@
}
// Comments in header
-Id Builder::accessChainLoad(Decoration precision, Id resultType)
+Id Builder::accessChainLoad(Decoration precision, Decoration nonUniform, Id resultType)
{
Id id;
@@ -2377,6 +2377,7 @@
// load through the access chain
id = createLoad(collapseAccessChain());
setPrecision(id, precision);
+ addDecoration(id, nonUniform);
}
// Done, unless there are swizzles to do
@@ -2397,6 +2398,7 @@
if (accessChain.component != NoResult)
id = setPrecision(createVectorExtractDynamic(id, resultType, accessChain.component), precision);
+ addDecoration(id, nonUniform);
return id;
}
diff --git a/SPIRV/SpvBuilder.h b/SPIRV/SpvBuilder.h
index dc76dae..099b1d9 100755
--- a/SPIRV/SpvBuilder.h
+++ b/SPIRV/SpvBuilder.h
@@ -554,7 +554,7 @@
void accessChainStore(Id rvalue);
// use accessChain and swizzle to load an r-value
- Id accessChainLoad(Decoration precision, Id ResultType);
+ Id accessChainLoad(Decoration precision, Decoration nonUniform, Id ResultType);
// get the direct pointer for an l-value
Id accessChainGetLValue();
diff --git a/SPIRV/doc.cpp b/SPIRV/doc.cpp
index 9317d50..a905968 100755
--- a/SPIRV/doc.cpp
+++ b/SPIRV/doc.cpp
@@ -255,6 +255,7 @@
case DecorationSecondaryViewportRelativeNV: return "SecondaryViewportRelativeNV";
#endif
+ case DecorationNonUniformEXT: return "DecorationNonUniformEXT";
case DecorationHlslCounterBufferGOOGLE: return "DecorationHlslCounterBufferGOOGLE";
case DecorationHlslSemanticGOOGLE: return "DecorationHlslSemanticGOOGLE";
}
@@ -815,6 +816,19 @@
case CapabilityFragmentFullyCoveredEXT: return "FragmentFullyCoveredEXT";
+ case CapabilityShaderNonUniformEXT: return "CapabilityShaderNonUniformEXT";
+ case CapabilityRuntimeDescriptorArrayEXT: return "CapabilityRuntimeDescriptorArrayEXT";
+ case CapabilityInputAttachmentArrayDynamicIndexingEXT: return "CapabilityInputAttachmentArrayDynamicIndexingEXT";
+ case CapabilityUniformTexelBufferArrayDynamicIndexingEXT: return "CapabilityUniformTexelBufferArrayDynamicIndexingEXT";
+ case CapabilityStorageTexelBufferArrayDynamicIndexingEXT: return "CapabilityStorageTexelBufferArrayDynamicIndexingEXT";
+ case CapabilityUniformBufferArrayNonUniformIndexingEXT: return "CapabilityUniformBufferArrayNonUniformIndexingEXT";
+ case CapabilitySampledImageArrayNonUniformIndexingEXT: return "CapabilitySampledImageArrayNonUniformIndexingEXT";
+ case CapabilityStorageBufferArrayNonUniformIndexingEXT: return "CapabilityStorageBufferArrayNonUniformIndexingEXT";
+ case CapabilityStorageImageArrayNonUniformIndexingEXT: return "CapabilityStorageImageArrayNonUniformIndexingEXT";
+ case CapabilityInputAttachmentArrayNonUniformIndexingEXT: return "CapabilityInputAttachmentArrayNonUniformIndexingEXT";
+ case CapabilityUniformTexelBufferArrayNonUniformIndexingEXT: return "CapabilityUniformTexelBufferArrayNonUniformIndexingEXT";
+ case CapabilityStorageTexelBufferArrayNonUniformIndexingEXT: return "CapabilityStorageTexelBufferArrayNonUniformIndexingEXT";
+
default: return "Bad";
}
}
diff --git a/SPIRV/spirv.hpp b/SPIRV/spirv.hpp
old mode 100755
new mode 100644
index 3c599f1..e21762d
--- a/SPIRV/spirv.hpp
+++ b/SPIRV/spirv.hpp
@@ -393,6 +393,7 @@
DecorationPassthroughNV = 5250,
DecorationViewportRelativeNV = 5252,
DecorationSecondaryViewportRelativeNV = 5256,
+ DecorationNonUniformEXT = 5300,
DecorationHlslCounterBufferGOOGLE = 5634,
DecorationHlslSemanticGOOGLE = 5635,
DecorationMax = 0x7fffffff,
@@ -692,6 +693,18 @@
CapabilityPerViewAttributesNV = 5260,
CapabilityFragmentFullyCoveredEXT = 5265,
CapabilityGroupNonUniformPartitionedNV = 5297,
+ CapabilityShaderNonUniformEXT = 5301,
+ CapabilityRuntimeDescriptorArrayEXT = 5302,
+ CapabilityInputAttachmentArrayDynamicIndexingEXT = 5303,
+ CapabilityUniformTexelBufferArrayDynamicIndexingEXT = 5304,
+ CapabilityStorageTexelBufferArrayDynamicIndexingEXT = 5305,
+ CapabilityUniformBufferArrayNonUniformIndexingEXT = 5306,
+ CapabilitySampledImageArrayNonUniformIndexingEXT = 5307,
+ CapabilityStorageBufferArrayNonUniformIndexingEXT = 5308,
+ CapabilityStorageImageArrayNonUniformIndexingEXT = 5309,
+ CapabilityInputAttachmentArrayNonUniformIndexingEXT = 5310,
+ CapabilityUniformTexelBufferArrayNonUniformIndexingEXT = 5311,
+ CapabilityStorageTexelBufferArrayNonUniformIndexingEXT = 5312,
CapabilitySubgroupShuffleINTEL = 5568,
CapabilitySubgroupBufferBlockIOINTEL = 5569,
CapabilitySubgroupImageBlockIOINTEL = 5570,