SPV: Nested layouts: Recursively send around the top-level std140 or std430 packing.
authorJohn Kessenich <cepheus@frii.com>
Sat, 19 Dec 2015 20:57:10 +0000 (13:57 -0700)
committerJohn Kessenich <cepheus@frii.com>
Sat, 19 Dec 2015 22:21:38 +0000 (15:21 -0700)
This also distinguishes between the same struct included in multiple parent packings.

SPIRV/GlslangToSpv.cpp
Test/baseResults/spv.layoutNested.vert.out [new file with mode: 0644]
Test/spv.layoutNested.vert [new file with mode: 0644]
Test/test-spirv-list
glslang/Include/revision.h

index 27a9bc2..ca6a577 100755 (executable)
@@ -91,11 +91,11 @@ protected:
     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&);
@@ -140,7 +140,7 @@ protected:
     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 };
@@ -1455,12 +1455,12 @@ spv::Id TGlslangToSpvTraverser::getSampledType(const glslang::TSampler& sampler)
 // 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;
 
@@ -1505,7 +1505,7 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty
             // 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;
 
@@ -1530,7 +1530,7 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty
 
             // 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;
@@ -1552,18 +1552,17 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty
                         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);
@@ -1621,26 +1620,41 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty
         // 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
@@ -1655,10 +1669,10 @@ int TGlslangToSpvTraverser::getArrayStride(const glslang::TType& arrayType)
 
 // 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
@@ -1667,14 +1681,12 @@ int TGlslangToSpvTraverser::getMatrixStride(const glslang::TType& matrixType)
 // '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;
@@ -1684,14 +1696,14 @@ void TGlslangToSpvTraverser::updateMemberOffset(const glslang::TType& structType
     // 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;
     
@@ -1699,7 +1711,7 @@ void TGlslangToSpvTraverser::updateMemberOffset(const glslang::TType& structType
     // 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;
 }
diff --git a/Test/baseResults/spv.layoutNested.vert.out b/Test/baseResults/spv.layoutNested.vert.out
new file mode 100644 (file)
index 0000000..007c029
--- /dev/null
@@ -0,0 +1,138 @@
+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
diff --git a/Test/spv.layoutNested.vert b/Test/spv.layoutNested.vert
new file mode 100644 (file)
index 0000000..aa403fc
--- /dev/null
@@ -0,0 +1,31 @@
+#version 450\r
+\r
+// should get 3 SPV types: no layout, 140, and 430\r
+struct S\r
+{\r
+       highp uvec3 a;\r
+       mediump mat2 b[4];\r
+       lowp uint c;\r
+};\r
+\r
+layout(set = 0, binding = 0, std140) uniform Block140\r
+{\r
+       mediump int u;\r
+       S s[2][3];\r
+       mediump vec2 v;\r
+} inst140;\r
+\r
+layout(set = 0, binding = 1, std430) buffer Block430\r
+{\r
+       mediump int u;\r
+       S s[2][3];\r
+       mediump vec2 v;\r
+} inst430;\r
+\r
+S s;\r
+\r
+void main()\r
+{\r
+    s.c = inst140.u;\r
+    gl_Position = vec4(s.c);\r
+}\r
index 32be4be..799148d 100644 (file)
@@ -48,6 +48,7 @@ spv.forwardFun.frag
 spv.functionCall.frag
 spv.functionSemantics.frag
 spv.interpOps.frag
+spv.layoutNested.vert
 spv.length.frag
 spv.localAggregates.frag
 spv.loops.frag
index e3418b1..42a916c 100644 (file)
@@ -2,5 +2,5 @@
 // For the version, it uses the latest git tag followed by the number of commits.
 // For the date, it uses the current date (when then script is run).
 
-#define GLSLANG_REVISION "SPIRV99.851"
+#define GLSLANG_REVISION "SPIRV99.860"
 #define GLSLANG_DATE "19-Dec-2015"