spv::Id createSpvVariable(const glslang::TIntermSymbol*);
spv::Id getSampledType(const glslang::TSampler&);
spv::Id convertGlslangToSpvType(const glslang::TType& type);
- spv::Id convertGlslangToSpvType(const glslang::TType& type, bool explicitLayout);
- bool requiresExplicitLayout(const glslang::TType& type) const;
- int getArrayStride(const glslang::TType& arrayType);
- int getMatrixStride(const glslang::TType& matrixType);
- void updateMemberOffset(const glslang::TType& structType, const glslang::TType& memberType, int& currentOffset, int& nextOffset);
+ spv::Id convertGlslangToSpvType(const glslang::TType& type, glslang::TLayoutPacking);
+ glslang::TLayoutPacking getExplicitLayout(const glslang::TType& type) const;
+ int getArrayStride(const glslang::TType& arrayType, glslang::TLayoutPacking);
+ int getMatrixStride(const glslang::TType& matrixType, glslang::TLayoutPacking);
+ void updateMemberOffset(const glslang::TType& structType, const glslang::TType& memberType, int& currentOffset, int& nextOffset, glslang::TLayoutPacking);
bool isShaderEntrypoint(const glslang::TIntermAggregate* node);
void makeFunctions(const glslang::TIntermSequence&);
std::unordered_map<int, spv::Id> symbolValues;
std::unordered_set<int> constReadOnlyParameters; // set of formal function parameters that have glslang qualifier constReadOnly, so we know they are not local function "const" that are write-once
std::unordered_map<std::string, spv::Function*> functionMap;
- std::unordered_map<const glslang::TTypeList*, spv::Id> structMap;
+ std::unordered_map<const glslang::TTypeList*, spv::Id> structMap[glslang::ElpStd430 + 1];
std::unordered_map<const glslang::TTypeList*, std::vector<int> > memberRemapper; // for mapping glslang block indices to spv indices (e.g., due to hidden members)
std::stack<bool> breakForLoop; // false means break for switch
std::stack<glslang::TIntermTyped*> loopTerminal; // code from the last part of a for loop: for(...; ...; terminal), needed for e.g., continue };
// recursive version of this function.
spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type)
{
- return convertGlslangToSpvType(type, requiresExplicitLayout(type));
+ return convertGlslangToSpvType(type, getExplicitLayout(type));
}
// Do full recursive conversion of an arbitrary glslang type to a SPIR-V Id.
// explicitLayout can be kept the same throughout the heirarchical recursive walk.
-spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type, bool explicitLayout)
+spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type, glslang::TLayoutPacking explicitLayout)
{
spv::Id spvType = 0;
// If we've seen this struct type, return it
const glslang::TTypeList* glslangStruct = type.getStruct();
std::vector<spv::Id> structFields;
- spvType = structMap[glslangStruct];
+ spvType = structMap[explicitLayout][glslangStruct];
if (spvType)
break;
// Make the SPIR-V type
spvType = builder.makeStructType(structFields, type.getTypeName().c_str());
- structMap[glslangStruct] = spvType;
+ structMap[explicitLayout][glslangStruct] = spvType;
// Name and decorate the non-hidden members
int offset = -1;
builder.addMemberDecoration(spvType, member, spv::DecorationComponent, glslangType.getQualifier().layoutComponent);
if (glslangType.getQualifier().hasXfbOffset())
builder.addMemberDecoration(spvType, member, spv::DecorationOffset, glslangType.getQualifier().layoutXfbOffset);
- else if (explicitLayout) {
+ else if (explicitLayout != glslang::ElpNone) {
// figure out what to do with offset, which is accumulating
int nextOffset;
- updateMemberOffset(type, glslangType, offset, nextOffset);
+ updateMemberOffset(type, glslangType, offset, nextOffset, explicitLayout);
if (offset >= 0)
builder.addMemberDecoration(spvType, member, spv::DecorationOffset, offset);
offset = nextOffset;
}
- if (glslangType.isMatrix() && explicitLayout) {
- builder.addMemberDecoration(spvType, member, spv::DecorationMatrixStride, getMatrixStride(glslangType));
- }
+ if (glslangType.isMatrix() && explicitLayout != glslang::ElpNone)
+ builder.addMemberDecoration(spvType, member, spv::DecorationMatrixStride, getMatrixStride(glslangType, explicitLayout));
// built-in variable decorations
spv::BuiltIn builtIn = TranslateBuiltInDecoration(glslangType.getQualifier().builtIn);
// except for the very top if it is an array of blocks; that array is
// not laid out in memory in a way needing a stride.
if (explicitLayout && type.getBasicType() != glslang::EbtBlock)
- builder.addDecoration(spvType, spv::DecorationArrayStride, getArrayStride(type));
+ builder.addDecoration(spvType, spv::DecorationArrayStride, getArrayStride(type, explicitLayout));
}
return spvType;
}
-bool TGlslangToSpvTraverser::requiresExplicitLayout(const glslang::TType& type) const
+// Decide whether or not this type should be
+// decorated with offsets and strides, and if so
+// whether std140 or std430 rules should be applied.
+glslang::TLayoutPacking TGlslangToSpvTraverser::getExplicitLayout(const glslang::TType& type) const
{
- return type.getBasicType() == glslang::EbtBlock &&
- type.getQualifier().layoutPacking != glslang::ElpShared &&
- type.getQualifier().layoutPacking != glslang::ElpPacked &&
- (type.getQualifier().storage == glslang::EvqUniform ||
- type.getQualifier().storage == glslang::EvqBuffer);
+ // has to be a block
+ if (type.getBasicType() != glslang::EbtBlock)
+ return glslang::ElpNone;
+
+ // has to be a uniform or buffer block
+ if (type.getQualifier().storage != glslang::EvqUniform &&
+ type.getQualifier().storage != glslang::EvqBuffer)
+ return glslang::ElpNone;
+
+ // return the layout to use
+ switch (type.getQualifier().layoutPacking) {
+ case glslang::ElpStd140:
+ case glslang::ElpStd430:
+ return type.getQualifier().layoutPacking;
+ default:
+ return glslang::ElpNone;
+ }
}
// Given an array type, returns the integer stride required for that array
-int TGlslangToSpvTraverser::getArrayStride(const glslang::TType& arrayType)
+int TGlslangToSpvTraverser::getArrayStride(const glslang::TType& arrayType, glslang::TLayoutPacking explicitLayout)
{
int size;
- int stride = glslangIntermediate->getBaseAlignment(arrayType, size, arrayType.getQualifier().layoutPacking == glslang::ElpStd140);
+ int stride = glslangIntermediate->getBaseAlignment(arrayType, size, explicitLayout == glslang::ElpStd140);
if (arrayType.isMatrix()) {
// GLSL strides are set to alignments of the matrix flattened to individual rows/cols,
// but SPV needs an array stride for the whole matrix, not the rows/cols
// Given a matrix type, returns the integer stride required for that matrix
// when used as a member of an interface block
-int TGlslangToSpvTraverser::getMatrixStride(const glslang::TType& matrixType)
+int TGlslangToSpvTraverser::getMatrixStride(const glslang::TType& matrixType, glslang::TLayoutPacking explicitLayout)
{
int size;
- return glslangIntermediate->getBaseAlignment(matrixType, size, matrixType.getQualifier().layoutPacking == glslang::ElpStd140);
+ return glslangIntermediate->getBaseAlignment(matrixType, size, explicitLayout == glslang::ElpStd140);
}
// Given a member type of a struct, realign the current offset for it, and compute
// 'currentOffset' should be passed in already initialized, ready to modify, and reflecting
// the migration of data from nextOffset -> currentOffset. It should be -1 on the first call.
// -1 means a non-forced member offset (no decoration needed).
-void TGlslangToSpvTraverser::updateMemberOffset(const glslang::TType& structType, const glslang::TType& memberType, int& currentOffset, int& nextOffset)
+void TGlslangToSpvTraverser::updateMemberOffset(const glslang::TType& structType, const glslang::TType& memberType, int& currentOffset, int& nextOffset,
+ glslang::TLayoutPacking explicitLayout)
{
// this will get a positive value when deemed necessary
nextOffset = -1;
- bool forceOffset = structType.getQualifier().layoutPacking == glslang::ElpStd140 ||
- structType.getQualifier().layoutPacking == glslang::ElpStd430;
-
// override anything in currentOffset with user-set offset
if (memberType.getQualifier().hasOffset())
currentOffset = memberType.getQualifier().layoutOffset;
// once cross-compilation unit GLSL validation is done, as the original user
// settings are needed in layoutOffset, and then the following will come into play.
- if (! forceOffset) {
+ if (explicitLayout == glslang::ElpNone) {
if (! memberType.getQualifier().hasOffset())
currentOffset = -1;
return;
}
- // Getting this far means we are forcing offsets
+ // Getting this far means we need explicit offsets
if (currentOffset < 0)
currentOffset = 0;
// but possibly not yet correctly aligned.
int memberSize;
- int memberAlignment = glslangIntermediate->getBaseAlignment(memberType, memberSize, memberType.getQualifier().layoutPacking == glslang::ElpStd140);
+ int memberAlignment = glslangIntermediate->getBaseAlignment(memberType, memberSize, explicitLayout == glslang::ElpStd140);
glslang::RoundToPow2(currentOffset, memberAlignment);
nextOffset = currentOffset + memberSize;
}
--- /dev/null
+spv.layoutNested.vert
+Warning, version 450 is not yet complete; most version-specific features are present, but some are missing.
+
+
+Linked vertex stage:
+
+
+// Module Version 10000
+// Generated by (magic number): 80001
+// Id's are bound by 54
+
+ Capability Shader
+ 1: ExtInstImport "GLSL.std.450"
+ MemoryModel Logical GLSL450
+ EntryPoint Vertex 4 "main" 38 52 53
+ Source GLSL 450
+ Name 4 "main"
+ Name 13 "S"
+ MemberName 13(S) 0 "a"
+ MemberName 13(S) 1 "b"
+ MemberName 13(S) 2 "c"
+ Name 15 "s"
+ Name 18 "S"
+ MemberName 18(S) 0 "a"
+ MemberName 18(S) 1 "b"
+ MemberName 18(S) 2 "c"
+ Name 23 "Block140"
+ MemberName 23(Block140) 0 "u"
+ MemberName 23(Block140) 1 "s"
+ MemberName 23(Block140) 2 "v"
+ Name 25 "inst140"
+ Name 36 "gl_PerVertex"
+ MemberName 36(gl_PerVertex) 0 "gl_Position"
+ MemberName 36(gl_PerVertex) 1 "gl_PointSize"
+ MemberName 36(gl_PerVertex) 2 "gl_ClipDistance"
+ MemberName 36(gl_PerVertex) 3 "gl_CullDistance"
+ Name 38 ""
+ Name 45 "S"
+ MemberName 45(S) 0 "a"
+ MemberName 45(S) 1 "b"
+ MemberName 45(S) 2 "c"
+ Name 48 "Block430"
+ MemberName 48(Block430) 0 "u"
+ MemberName 48(Block430) 1 "s"
+ MemberName 48(Block430) 2 "v"
+ Name 50 "inst430"
+ Name 52 "gl_VertexID"
+ Name 53 "gl_InstanceID"
+ MemberDecorate 13(S) 1 ColMajor
+ Decorate 12 ArrayStride 32
+ MemberDecorate 18(S) 0 Offset 0
+ MemberDecorate 18(S) 1 ColMajor
+ MemberDecorate 18(S) 1 Offset 16
+ MemberDecorate 18(S) 1 MatrixStride 16
+ MemberDecorate 18(S) 2 Offset 144
+ Decorate 22 ArrayStride 16
+ MemberDecorate 23(Block140) 0 Offset 0
+ MemberDecorate 23(Block140) 1 Offset 16
+ MemberDecorate 23(Block140) 2 Offset 976
+ Decorate 23(Block140) Block
+ Decorate 25(inst140) DescriptorSet 0
+ Decorate 25(inst140) Binding 0
+ MemberDecorate 36(gl_PerVertex) 0 BuiltIn Position
+ MemberDecorate 36(gl_PerVertex) 1 BuiltIn PointSize
+ MemberDecorate 36(gl_PerVertex) 2 BuiltIn ClipDistance
+ MemberDecorate 36(gl_PerVertex) 3 BuiltIn CullDistance
+ Decorate 36(gl_PerVertex) Block
+ Decorate 12 ArrayStride 16
+ MemberDecorate 45(S) 0 Offset 0
+ MemberDecorate 45(S) 1 ColMajor
+ MemberDecorate 45(S) 1 Offset 16
+ MemberDecorate 45(S) 1 MatrixStride 8
+ MemberDecorate 45(S) 2 Offset 80
+ Decorate 47 ArrayStride 16
+ MemberDecorate 48(Block430) 0 Offset 0
+ MemberDecorate 48(Block430) 1 Offset 16
+ MemberDecorate 48(Block430) 2 Offset 592
+ Decorate 48(Block430) BufferBlock
+ Decorate 50(inst430) DescriptorSet 0
+ Decorate 50(inst430) Binding 1
+ Decorate 52(gl_VertexID) BuiltIn VertexId
+ Decorate 53(gl_InstanceID) BuiltIn InstanceId
+ 2: TypeVoid
+ 3: TypeFunction 2
+ 6: TypeInt 32 0
+ 7: TypeVector 6(int) 3
+ 8: TypeFloat 32
+ 9: TypeVector 8(float) 2
+ 10: TypeMatrix 9(fvec2) 2
+ 11: 6(int) Constant 4
+ 12: TypeArray 10 11
+ 13(S): TypeStruct 7(ivec3) 12 6(int)
+ 14: TypePointer Private 13(S)
+ 15(s): 14(ptr) Variable Private
+ 16: TypeInt 32 1
+ 17: 16(int) Constant 2
+ 18(S): TypeStruct 7(ivec3) 12 6(int)
+ 19: 6(int) Constant 3
+ 20: TypeArray 18(S) 19
+ 21: 6(int) Constant 2
+ 22: TypeArray 20 21
+ 23(Block140): TypeStruct 16(int) 22 9(fvec2)
+ 24: TypePointer Uniform 23(Block140)
+ 25(inst140): 24(ptr) Variable Uniform
+ 26: 16(int) Constant 0
+ 27: TypePointer Uniform 16(int)
+ 31: TypePointer Private 6(int)
+ 33: TypeVector 8(float) 4
+ 34: 6(int) Constant 1
+ 35: TypeArray 8(float) 34
+36(gl_PerVertex): TypeStruct 33(fvec4) 8(float) 35 35
+ 37: TypePointer Output 36(gl_PerVertex)
+ 38: 37(ptr) Variable Output
+ 43: TypePointer Output 33(fvec4)
+ 45(S): TypeStruct 7(ivec3) 12 6(int)
+ 46: TypeArray 45(S) 19
+ 47: TypeArray 46 21
+ 48(Block430): TypeStruct 16(int) 47 9(fvec2)
+ 49: TypePointer Uniform 48(Block430)
+ 50(inst430): 49(ptr) Variable Uniform
+ 51: TypePointer Input 16(int)
+ 52(gl_VertexID): 51(ptr) Variable Input
+53(gl_InstanceID): 51(ptr) Variable Input
+ 4(main): 2 Function None 3
+ 5: Label
+ 28: 27(ptr) AccessChain 25(inst140) 26
+ 29: 16(int) Load 28
+ 30: 6(int) Bitcast 29
+ 32: 31(ptr) AccessChain 15(s) 17
+ Store 32 30
+ 39: 31(ptr) AccessChain 15(s) 17
+ 40: 6(int) Load 39
+ 41: 8(float) ConvertUToF 40
+ 42: 33(fvec4) CompositeConstruct 41 41 41 41
+ 44: 43(ptr) AccessChain 38 26
+ Store 44 42
+ Return
+ FunctionEnd