GL_ARB_enhanced_layouts, part 6: Numerical side of uniform offset and align semantics...
authorJohn Kessenich <cepheus@frii.com>
Fri, 31 Jan 2014 02:40:19 +0000 (02:40 +0000)
committerJohn Kessenich <cepheus@frii.com>
Fri, 31 Jan 2014 02:40:19 +0000 (02:40 +0000)
 - moving offset calculations for std140/std430 from reflection to linkValidate.cpp
 - applying the offset/align rules on top of std140/std430
 - removing caching the structure's number of components (and correcting that this is components, not size)

git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@25174 e7fa87d3-cd2b-0410-9028-fcbf551c1848

15 files changed:
Test/440.frag
Test/baseResults/300layout.vert.out
Test/baseResults/440.frag.out
Test/baseResults/specExamples.vert.out
glslang/Include/Types.h
glslang/Include/revision.h
glslang/MachineIndependent/Constant.cpp
glslang/MachineIndependent/Intermediate.cpp
glslang/MachineIndependent/ParseHelper.cpp
glslang/MachineIndependent/SymbolTable.cpp
glslang/MachineIndependent/intermOut.cpp
glslang/MachineIndependent/linkValidate.cpp
glslang/MachineIndependent/localintermediate.h
glslang/MachineIndependent/parseConst.cpp
glslang/MachineIndependent/reflection.cpp

index 22d46f5..a32706c 100644 (file)
@@ -79,13 +79,58 @@ uniform ubl11 {
 \r
 layout(std140) uniform block {\r
                         vec4   a;     // a takes offsets 0-15\r
-    layout(offset = 20) vec3   b;     // b takes offsets 32-43\r
+    layout(offset = 32) vec3   b;     // b takes offsets 32-43\r
     layout(offset = 40) vec2   c;     // ERROR, lies within previous member\r
+    layout(align = 6)   double g;     // ERROR, 6 is not a power of 2\r
+    layout(offset=68)   double h;     // ERROR, offset not aligned\r
+} specExampleErrors;\r
+\r
+layout(std140) uniform block2 {\r
+                        vec4   a;     // a takes offsets 0-15\r
+    layout(offset = 32) vec3   b;     // b takes offsets 32-43\r
     layout(offset = 48) vec2   d;     // d takes offsets 48-55\r
     layout(align = 16)  float  e;     // e takes offsets 64-67\r
     layout(align = 2)   double f;     // f takes offsets 72-79\r
-    layout(align = 6)   double g;     // ERROR, 6 is not a power of 2\r
     layout(offset = 80) float  h;     // h takes offsets 80-83\r
     layout(align = 64)  dvec3  i;     // i takes offsets 128-151\r
-    layout(offset = 153, align = 8) float  j;     // j takes offsets 160-163\r
+    layout(offset = 164, align = 8) float  j;     // j takes offsets 168-171\r
 } specExample;\r
+\r
+layout(std430) uniform block430 {\r
+                        vec4   a;     // a takes offsets 0-15\r
+    layout(offset = 32) vec3   b;     // b takes offsets 32-43\r
+    layout(offset = 40) vec2   c;     // ERROR, lies within previous member\r
+    layout(align = 6)   double g;     // ERROR, 6 is not a power of 2\r
+    layout(offset=68)   double h;     // ERROR, offset not aligned\r
+} specExampleErrors430;\r
+\r
+layout(std430) uniform block2430 {\r
+                        vec4   a;     // a takes offsets 0-15\r
+    layout(offset = 32) vec3   b;     // b takes offsets 32-43\r
+    layout(offset = 48) vec2   d;     // d takes offsets 48-55\r
+    layout(align = 16)  float  e;     // e takes offsets 64-67\r
+    layout(align = 2)   double f;     // f takes offsets 72-79\r
+    layout(offset = 80) float  h;     // h takes offsets 80-83\r
+    layout(align = 64)  dvec3  i;     // i takes offsets 128-151\r
+    layout(offset = 164, align = 8) float  j;     // j takes offsets 168-171\r
+} specExample430;\r
+\r
+layout(std430, align = 128) uniform block24300 {\r
+    vec4   a;\r
+    vec3   b;\r
+    vec2   d;\r
+    float  e;\r
+    double f;\r
+    float  h;\r
+    dvec3  i;\r
+} specExample4300;\r
+\r
+layout(std430, align = 128) uniform block24301 {\r
+    vec4   a;\r
+    vec3   b;\r
+    vec2   d;\r
+    layout(offset=388) float  e;\r
+    layout(align=8) double f;\r
+    float  h;\r
+    dvec3  i;\r
+} specExample4301;\r
index 0ce4b3c..4d2c3a5 100644 (file)
@@ -32,12 +32,12 @@ ERROR: node is still EOpNull!
 0:46            add (highp 4X4 matrix of float)\r
 0:46              add (highp 4X4 matrix of float)\r
 0:46                add (highp 4X4 matrix of float)\r
-0:46                  M1: direct index for structure (layout(row_major std140 ) uniform highp 4X4 matrix of float)\r
-0:46                    'tblock' (layout(row_major std140 ) uniform block{layout(row_major std140 ) uniform highp 4X4 matrix of float M1, layout(column_major std140 ) uniform highp 4X4 matrix of float M2, layout(row_major std140 ) uniform highp 3X3 matrix of float N1, layout(row_major std140 ) centroid uniform highp float badf, layout(row_major std140 ) uniform highp float badg, layout(row_major std140 ) uniform highp float bad1, layout(row_major shared ) uniform highp float bad2, layout(row_major packed ) uniform highp float bad3})\r
+0:46                  M1: direct index for structure (layout(row_major std140 offset=0 ) uniform highp 4X4 matrix of float)\r
+0:46                    'tblock' (layout(row_major std140 ) uniform block{layout(row_major std140 offset=0 ) uniform highp 4X4 matrix of float M1, layout(column_major std140 offset=64 ) uniform highp 4X4 matrix of float M2, layout(row_major std140 offset=128 ) uniform highp 3X3 matrix of float N1, layout(row_major std140 offset=176 ) centroid uniform highp float badf, layout(row_major std140 offset=180 ) uniform highp float badg, layout(row_major std140 offset=184 ) uniform highp float bad1, layout(row_major shared offset=188 ) uniform highp float bad2, layout(row_major packed offset=192 ) uniform highp float bad3})\r
 0:46                    Constant:\r
 0:46                      0 (const int)\r
-0:46                  M2: direct index for structure (layout(column_major std140 ) uniform highp 4X4 matrix of float)\r
-0:46                    'tblock' (layout(row_major std140 ) uniform block{layout(row_major std140 ) uniform highp 4X4 matrix of float M1, layout(column_major std140 ) uniform highp 4X4 matrix of float M2, layout(row_major std140 ) uniform highp 3X3 matrix of float N1, layout(row_major std140 ) centroid uniform highp float badf, layout(row_major std140 ) uniform highp float badg, layout(row_major std140 ) uniform highp float bad1, layout(row_major shared ) uniform highp float bad2, layout(row_major packed ) uniform highp float bad3})\r
+0:46                  M2: direct index for structure (layout(column_major std140 offset=64 ) uniform highp 4X4 matrix of float)\r
+0:46                    'tblock' (layout(row_major std140 ) uniform block{layout(row_major std140 offset=0 ) uniform highp 4X4 matrix of float M1, layout(column_major std140 offset=64 ) uniform highp 4X4 matrix of float M2, layout(row_major std140 offset=128 ) uniform highp 3X3 matrix of float N1, layout(row_major std140 offset=176 ) centroid uniform highp float badf, layout(row_major std140 offset=180 ) uniform highp float badg, layout(row_major std140 offset=184 ) uniform highp float bad1, layout(row_major shared offset=188 ) uniform highp float bad2, layout(row_major packed offset=192 ) uniform highp float bad3})\r
 0:46                    Constant:\r
 0:46                      1 (const int)\r
 0:46                M4: direct index for structure (layout(row_major shared ) uniform highp 4X4 matrix of float)\r
@@ -56,8 +56,8 @@ ERROR: node is still EOpNull!
 0:47        'color' (smooth out highp 3-component vector of float)\r
 0:47        vector-times-matrix (highp 3-component vector of float)\r
 0:47          'c' (layout(location=7 ) in highp 3-component vector of float)\r
-0:47          N1: direct index for structure (layout(row_major std140 ) uniform highp 3X3 matrix of float)\r
-0:47            'tblock' (layout(row_major std140 ) uniform block{layout(row_major std140 ) uniform highp 4X4 matrix of float M1, layout(column_major std140 ) uniform highp 4X4 matrix of float M2, layout(row_major std140 ) uniform highp 3X3 matrix of float N1, layout(row_major std140 ) centroid uniform highp float badf, layout(row_major std140 ) uniform highp float badg, layout(row_major std140 ) uniform highp float bad1, layout(row_major shared ) uniform highp float bad2, layout(row_major packed ) uniform highp float bad3})\r
+0:47          N1: direct index for structure (layout(row_major std140 offset=128 ) uniform highp 3X3 matrix of float)\r
+0:47            'tblock' (layout(row_major std140 ) uniform block{layout(row_major std140 offset=0 ) uniform highp 4X4 matrix of float M1, layout(column_major std140 offset=64 ) uniform highp 4X4 matrix of float M2, layout(row_major std140 offset=128 ) uniform highp 3X3 matrix of float N1, layout(row_major std140 offset=176 ) centroid uniform highp float badf, layout(row_major std140 offset=180 ) uniform highp float badg, layout(row_major std140 offset=184 ) uniform highp float bad1, layout(row_major shared offset=188 ) uniform highp float bad2, layout(row_major packed offset=192 ) uniform highp float bad3})\r
 0:47            Constant:\r
 0:47              2 (const int)\r
 0:?   Linker Objects\r
@@ -68,7 +68,7 @@ ERROR: node is still EOpNull!
 0:?     'pos' (smooth out highp 4-component vector of float)\r
 0:?     'color' (smooth out highp 3-component vector of float)\r
 0:?     'badm4' (layout(column_major shared ) uniform highp 4X4 matrix of float)\r
-0:?     'tblock' (layout(row_major std140 ) uniform block{layout(row_major std140 ) uniform highp 4X4 matrix of float M1, layout(column_major std140 ) uniform highp 4X4 matrix of float M2, layout(row_major std140 ) uniform highp 3X3 matrix of float N1, layout(row_major std140 ) centroid uniform highp float badf, layout(row_major std140 ) uniform highp float badg, layout(row_major std140 ) uniform highp float bad1, layout(row_major shared ) uniform highp float bad2, layout(row_major packed ) uniform highp float bad3})\r
+0:?     'tblock' (layout(row_major std140 ) uniform block{layout(row_major std140 offset=0 ) uniform highp 4X4 matrix of float M1, layout(column_major std140 offset=64 ) uniform highp 4X4 matrix of float M2, layout(row_major std140 offset=128 ) uniform highp 3X3 matrix of float N1, layout(row_major std140 offset=176 ) centroid uniform highp float badf, layout(row_major std140 offset=180 ) uniform highp float badg, layout(row_major std140 offset=184 ) uniform highp float bad1, layout(row_major shared offset=188 ) uniform highp float bad2, layout(row_major packed offset=192 ) uniform highp float bad3})\r
 0:?     '__anon__0' (layout(row_major shared ) uniform block{layout(row_major shared ) uniform bool b, layout(row_major shared ) uniform highp 4X4 matrix of float t2m})\r
 0:?     '__anon__2' (out block{out highp float f})\r
 0:?     'badoutA' (layout(location=10 ) smooth out highp 4-component vector of float)\r
index b81870c..c020f07 100644 (file)
@@ -39,8 +39,13 @@ ERROR: 0:58: 'align' : can only be used with std140 or std430 layout packing
 ERROR: 0:63: 'align' : can only be used with std140 or std430 layout packing \r
 ERROR: 0:62: 'layout' : offset/align can only be used on a uniform or buffer \r
 ERROR: 0:63: 'layout' : offset/align can only be used on a uniform or buffer \r
-ERROR: 0:87: 'align' : must be a power of 2 \r
-ERROR: 40 compilation errors.  No code generated.\r
+ERROR: 0:84: 'align' : must be a power of 2 \r
+ERROR: 0:83: 'offset' : cannot lie in previous members \r
+ERROR: 0:85: 'offset' : must be a multiple of the member's alignment \r
+ERROR: 0:103: 'align' : must be a power of 2 \r
+ERROR: 0:102: 'offset' : cannot lie in previous members \r
+ERROR: 0:104: 'offset' : must be a multiple of the member's alignment \r
+ERROR: 45 compilation errors.  No code generated.\r
 \r
 \r
 ERROR: node is still EOpNull!\r
@@ -56,7 +61,7 @@ ERROR: node is still EOpNull!
 0:?     'inst1' (layout(column_major shared offset=12 ) uniform block{layout(column_major shared ) uniform int a})\r
 0:?     'inst2' (layout(offset=12 ) in block{in int a})\r
 0:?     'inst3' (layout(offset=12 ) out block{out int a})\r
-0:?     'inst4' (layout(column_major std140 align=16 ) uniform block{layout(column_major std140 align=16 ) uniform int a})\r
+0:?     'inst4' (layout(column_major std140 align=16 ) uniform block{layout(column_major std140 offset=0 align=16 ) uniform int a})\r
 0:?     'inst8' (layout(column_major shared align=16 ) uniform block{layout(column_major shared ) uniform int a})\r
 0:?     'inst5' (layout(align=16 ) in block{in int a})\r
 0:?     'inst6' (layout(align=16 ) out block{out int a})\r
@@ -71,7 +76,12 @@ ERROR: node is still EOpNull!
 0:?     'inst10' (in block{layout(offset=12 ) in float f, layout(align=4 ) in float g})\r
 0:?     'inst9' (layout(column_major std430 align=32 ) uniform block{layout(column_major std430 align=32 ) uniform float e, layout(column_major std430 offset=12 align=4 ) uniform float f, layout(column_major std430 offset=20 align=32 ) uniform float g, layout(column_major std430 align=32 ) uniform float h})\r
 0:?     'inst11' (layout(column_major std430 ) uniform block{layout(column_major std430 offset=12 align=4 ) uniform float f, layout(column_major std430 ) uniform float g})\r
-0:?     'specExample' (layout(column_major std140 ) uniform block{layout(column_major std140 ) uniform 4-component vector of float a, layout(column_major std140 offset=20 ) uniform 3-component vector of float b, layout(column_major std140 offset=40 ) uniform 2-component vector of float c, layout(column_major std140 offset=48 ) uniform 2-component vector of float d, layout(column_major std140 align=16 ) uniform float e, layout(column_major std140 align=2 ) uniform double f, layout(column_major std140 ) uniform double g, layout(column_major std140 offset=80 ) uniform float h, layout(column_major std140 align=64 ) uniform 3-component vector of double i, layout(column_major std140 offset=153 align=8 ) uniform float j})\r
+0:?     'specExampleErrors' (layout(column_major std140 ) uniform block{layout(column_major std140 offset=0 ) uniform 4-component vector of float a, layout(column_major std140 offset=32 ) uniform 3-component vector of float b, layout(column_major std140 offset=48 ) uniform 2-component vector of float c, layout(column_major std140 offset=56 ) uniform double g, layout(column_major std140 offset=72 ) uniform double h})\r
+0:?     'specExample' (layout(column_major std140 ) uniform block{layout(column_major std140 offset=0 ) uniform 4-component vector of float a, layout(column_major std140 offset=32 ) uniform 3-component vector of float b, layout(column_major std140 offset=48 ) uniform 2-component vector of float d, layout(column_major std140 offset=64 align=16 ) uniform float e, layout(column_major std140 offset=72 align=2 ) uniform double f, layout(column_major std140 offset=80 ) uniform float h, layout(column_major std140 offset=128 align=64 ) uniform 3-component vector of double i, layout(column_major std140 offset=168 align=8 ) uniform float j})\r
+0:?     'specExampleErrors430' (layout(column_major std430 ) uniform block{layout(column_major std430 offset=0 ) uniform 4-component vector of float a, layout(column_major std430 offset=32 ) uniform 3-component vector of float b, layout(column_major std430 offset=48 ) uniform 2-component vector of float c, layout(column_major std430 offset=56 ) uniform double g, layout(column_major std430 offset=72 ) uniform double h})\r
+0:?     'specExample430' (layout(column_major std430 ) uniform block{layout(column_major std430 offset=0 ) uniform 4-component vector of float a, layout(column_major std430 offset=32 ) uniform 3-component vector of float b, layout(column_major std430 offset=48 ) uniform 2-component vector of float d, layout(column_major std430 offset=64 align=16 ) uniform float e, layout(column_major std430 offset=72 align=2 ) uniform double f, layout(column_major std430 offset=80 ) uniform float h, layout(column_major std430 offset=128 align=64 ) uniform 3-component vector of double i, layout(column_major std430 offset=168 align=8 ) uniform float j})\r
+0:?     'specExample4300' (layout(column_major std430 align=128 ) uniform block{layout(column_major std430 offset=0 align=128 ) uniform 4-component vector of float a, layout(column_major std430 offset=128 align=128 ) uniform 3-component vector of float b, layout(column_major std430 offset=256 align=128 ) uniform 2-component vector of float d, layout(column_major std430 offset=384 align=128 ) uniform float e, layout(column_major std430 offset=512 align=128 ) uniform double f, layout(column_major std430 offset=640 align=128 ) uniform float h, layout(column_major std430 offset=768 align=128 ) uniform 3-component vector of double i})\r
+0:?     'specExample4301' (layout(column_major std430 align=128 ) uniform block{layout(column_major std430 offset=0 align=128 ) uniform 4-component vector of float a, layout(column_major std430 offset=128 align=128 ) uniform 3-component vector of float b, layout(column_major std430 offset=256 align=128 ) uniform 2-component vector of float d, layout(column_major std430 offset=512 align=128 ) uniform float e, layout(column_major std430 offset=520 align=8 ) uniform double f, layout(column_major std430 offset=640 align=128 ) uniform float h, layout(column_major std430 offset=768 align=128 ) uniform 3-component vector of double i})\r
 \r
 \r
 Linked fragment stage:\r
index b69695a..0a7c408 100644 (file)
@@ -289,7 +289,7 @@ ERROR: node is still EOpNull!
 0:?     'var5' (smooth out 4-component vector of float)\r
 0:?     '__anon__2' (out block{out 4-component vector of float var6})\r
 0:?     'var7' (smooth out 4-component vector of float)\r
-0:?     '__anon__3' (layout(row_major std140 ) uniform block{layout(row_major std140 ) uniform 4X4 matrix of float M1, layout(column_major std140 ) uniform 4X4 matrix of float M2, layout(row_major std140 ) uniform 3X3 matrix of float N1})\r
+0:?     '__anon__3' (layout(row_major std140 ) uniform block{layout(row_major std140 offset=0 ) uniform 4X4 matrix of float M1, layout(column_major std140 offset=64 ) uniform 4X4 matrix of float M2, layout(row_major std140 offset=128 ) uniform 3X3 matrix of float N1})\r
 0:?     '__anon__4' (layout(column_major shared ) uniform block{layout(column_major shared ) uniform 4X4 matrix of float M13, layout(row_major shared ) uniform 4X4 matrix of float m14, layout(column_major shared ) uniform 3X3 matrix of float N12})\r
 0:?     's17' (layout(binding=3 ) uniform sampler2D)\r
 0:?     'a2' (layout(binding=2 offset=4 ) uniform int)\r
index a7435d0..3a712cb 100644 (file)
@@ -42,7 +42,7 @@
 
 namespace glslang {
 
-const int GlslangMaxTypeLength = 200;
+const int GlslangMaxTypeLength = 200;  // TODO: need to print block/struct one member per line, so this can stay bounded
 
 //
 // Details within a sampler type
@@ -643,7 +643,7 @@ public:
     // for "empty" type (no args) or simple scalar/vector/matrix
     explicit TType(TBasicType t = EbtVoid, TStorageQualifier q = EvqTemporary, int vs = 1, int mc = 0, int mr = 0) :
                             basicType(t), vectorSize(vs), matrixCols(mc), matrixRows(mr), arraySizes(0),
-                            structure(0), structureSize(0), fieldName(0), typeName(0)
+                            structure(0), fieldName(0), typeName(0)
                             {
                                 sampler.clear();
                                 qualifier.clear();
@@ -652,7 +652,7 @@ public:
     // for explicit precision qualifier
     TType(TBasicType t, TStorageQualifier q, TPrecisionQualifier p, int vs = 1, int mc = 0, int mr = 0) :
                             basicType(t), vectorSize(vs), matrixCols(mc), matrixRows(mr), arraySizes(0),
-                            structure(0), structureSize(0), fieldName(0), typeName(0)
+                            structure(0), fieldName(0), typeName(0)
                             {
                                 sampler.clear();
                                 qualifier.clear();
@@ -663,7 +663,7 @@ public:
     // for turning a TPublicType into a TType
     explicit TType(const TPublicType& p) :
                             basicType(p.basicType), vectorSize(p.vectorSize), matrixCols(p.matrixCols), matrixRows(p.matrixRows), arraySizes(p.arraySizes),
-                            structure(0), structureSize(0), fieldName(0), typeName(0)
+                            structure(0), fieldName(0), typeName(0)
                             {
                                 if (basicType == EbtSampler)
                                     sampler = p.sampler;
@@ -723,7 +723,6 @@ public:
         matrixRows = copyOf.matrixRows;
         arraySizes = copyOf.arraySizes;
         structure = copyOf.structure;
-        structureSize = copyOf.structureSize;
         fieldName = copyOf.fieldName;
         typeName = copyOf.typeName;
     }
@@ -1015,24 +1014,25 @@ public:
     TTypeList* getStruct() { return structure; }
     TTypeList* getStruct() const { return structure; }
 
-    int getObjectSize() const
+    int computeNumComponents() const
     {
-        int totalSize;
+        int components = 0;
 
-        if (getBasicType() == EbtStruct || getBasicType() == EbtBlock)
-            totalSize = getStructSize();
-        else if (matrixCols)
-            totalSize = matrixCols * matrixRows;
+        if (getBasicType() == EbtStruct || getBasicType() == EbtBlock) {
+            for (TTypeList::iterator tl = getStruct()->begin(); tl != getStruct()->end(); tl++)
+                components += ((*tl).type)->computeNumComponents();
+        } else if (matrixCols)
+            components = matrixCols * matrixRows;
         else
-            totalSize = vectorSize;
+            components = vectorSize;
 
         if (isArray()) {
             // this function can only be used in paths that don't allow unsized arrays
             assert(getArraySize() > 0);
-            totalSize *= getArraySize();
+            components *= getArraySize();
         }
 
-        return totalSize;
+        return components;
     }
 
     // append this type's mangled name to the passed in 'name'
@@ -1117,7 +1117,6 @@ protected:
     TType& operator=(const TType& type);
 
     void buildMangledName(TString&);
-    int getStructSize() const;
 
     TBasicType basicType : 8;
     int vectorSize       : 4;
@@ -1129,7 +1128,6 @@ protected:
     TArraySizes* arraySizes;
 
     TTypeList* structure;       // 0 unless this is a struct
-    mutable int structureSize;  // a cache, updated on first access
     TString *fieldName;         // for structure field names
     TString *typeName;          // for structure type name
 };
index 1a2b8fe..a8b56f3 100644 (file)
@@ -9,5 +9,5 @@
 // source have to figure out how to create revision.h just to get a build\r
 // going.  However, if it is not updated, it can be a version behind.\r
 \r
-#define GLSLANG_REVISION "25043"\r
-#define GLSLANG_DATE     "2014/01/27 13:02:12"\r
+#define GLSLANG_REVISION "25092"\r
+#define GLSLANG_DATE     "2014/01/28 14:13:59"\r
index 801cf1d..4648b55 100644 (file)
@@ -101,50 +101,52 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TIntermTyped* const
     TConstUnionArray rightUnionArray = node->getConstArray();
 
     // Figure out the size of the result
-    int objectSize;
+    int newComps;
+    int constComps;
     switch(op) {
     case EOpMatrixTimesMatrix:
-        objectSize = getMatrixRows() * node->getMatrixCols();
+        newComps = getMatrixRows() * node->getMatrixCols();
         break;
     case EOpMatrixTimesVector:
-        objectSize = getMatrixRows();
+        newComps = getMatrixRows();
         break;
     case EOpVectorTimesMatrix:
-        objectSize = node->getMatrixCols();
+        newComps = node->getMatrixCols();
         break;
     default:
-        objectSize = getType().getObjectSize();                    
-        if (constantNode->getType().getObjectSize() == 1 && getType().getObjectSize() > 1) {
+        newComps = getType().computeNumComponents();
+        constComps = constantNode->getType().computeNumComponents();
+        if (constComps == 1 && newComps > 1) {
             // for a case like vec4 f = vec4(2,3,4,5) + 1.2;
-            TConstUnionArray smearedArray(objectSize, node->getConstArray()[0]);
+            TConstUnionArray smearedArray(newComps, node->getConstArray()[0]);
             rightUnionArray = smearedArray;
-        } else if (constantNode->getType().getObjectSize() > 1 && getType().getObjectSize() == 1) {
+        } else if (constComps > 1 && newComps == 1) {
             // for a case like vec4 f = 1.2 + vec4(2,3,4,5);            
-            objectSize = constantNode->getType().getObjectSize();
+            newComps = constComps;
             rightUnionArray = node->getConstArray();
-            TConstUnionArray smearedArray(objectSize, getConstArray()[0]);
+            TConstUnionArray smearedArray(newComps, getConstArray()[0]);
             unionArray = smearedArray;
             returnType.shallowCopy(node->getType());
         }
         break;
     }
 
-    TConstUnionArray newConstArray(objectSize);
+    TConstUnionArray newConstArray(newComps);
 
     switch(op) {
     case EOpAdd:
-        for (int i = 0; i < objectSize; i++)
+        for (int i = 0; i < newComps; i++)
             newConstArray[i] = unionArray[i] + rightUnionArray[i];
         break;
     case EOpSub:
-        for (int i = 0; i < objectSize; i++)
+        for (int i = 0; i < newComps; i++)
             newConstArray[i] = unionArray[i] - rightUnionArray[i];
         break;
 
     case EOpMul:
     case EOpVectorTimesScalar:
     case EOpMatrixTimesScalar:
-        for (int i = 0; i < objectSize; i++)
+        for (int i = 0; i < newComps; i++)
             newConstArray[i] = unionArray[i] * rightUnionArray[i];
         break;
     case EOpMatrixTimesMatrix:
@@ -159,7 +161,7 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TIntermTyped* const
         returnType.shallowCopy(TType(getType().getBasicType(), EvqConst, 0, getMatrixRows(), node->getMatrixCols()));
         break;
     case EOpDiv:
-        for (int i = 0; i < objectSize; i++) {
+        for (int i = 0; i < newComps; i++) {
             switch (getType().getBasicType()) {
             case EbtDouble:
             case EbtFloat:
@@ -211,7 +213,7 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TIntermTyped* const
         break;
 
     case EOpMod:
-        for (int i = 0; i < objectSize; i++) {
+        for (int i = 0; i < newComps; i++) {
             if (rightUnionArray[i] == 0)
                 newConstArray[i] = unionArray[i];
             else
@@ -220,40 +222,40 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TIntermTyped* const
         break;
 
     case EOpRightShift:
-        for (int i = 0; i < objectSize; i++)
+        for (int i = 0; i < newComps; i++)
             newConstArray[i] = unionArray[i] >> rightUnionArray[i];
         break;
 
     case EOpLeftShift:
-        for (int i = 0; i < objectSize; i++)
+        for (int i = 0; i < newComps; i++)
             newConstArray[i] = unionArray[i] << rightUnionArray[i];
         break;
 
     case EOpAnd:
-        for (int i = 0; i < objectSize; i++)
+        for (int i = 0; i < newComps; i++)
             newConstArray[i] = unionArray[i] & rightUnionArray[i];
         break;
     case EOpInclusiveOr:
-        for (int i = 0; i < objectSize; i++)
+        for (int i = 0; i < newComps; i++)
             newConstArray[i] = unionArray[i] | rightUnionArray[i];
         break;
     case EOpExclusiveOr:
-        for (int i = 0; i < objectSize; i++)
+        for (int i = 0; i < newComps; i++)
             newConstArray[i] = unionArray[i] ^ rightUnionArray[i];
         break;
 
     case EOpLogicalAnd: // this code is written for possible future use, will not get executed currently
-        for (int i = 0; i < objectSize; i++)
+        for (int i = 0; i < newComps; i++)
             newConstArray[i] = unionArray[i] && rightUnionArray[i];
         break;
 
     case EOpLogicalOr: // this code is written for possible future use, will not get executed currently
-        for (int i = 0; i < objectSize; i++)
+        for (int i = 0; i < newComps; i++)
             newConstArray[i] = unionArray[i] || rightUnionArray[i];
         break;
 
     case EOpLogicalXor:
-        for (int i = 0; i < objectSize; i++) {
+        for (int i = 0; i < newComps; i++) {
             switch (getType().getBasicType()) {
             case EbtBool: newConstArray[i].setBConst((unionArray[i] == rightUnionArray[i]) ? false : true); break;
             default: assert(false && "Default missing");
@@ -309,6 +311,7 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TType& returnType)
     int resultSize;
     bool componentWise = true;
 
+    int objectSize = getType().computeNumComponents();
     switch (op) {
     case EOpDeterminant:
     case EOpAny:
@@ -339,18 +342,17 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TType& returnType)
 
     case EOpNormalize:
         componentWise = false;
-        resultSize = getType().getObjectSize();
+        resultSize = objectSize;
         break;
 
     default:
-        resultSize = getType().getObjectSize();
+        resultSize = objectSize;
         break;
     }
 
     // Set up for processing
     TConstUnionArray newConstArray(resultSize);
     const TConstUnionArray& unionArray = getConstArray();
-    int objectSize = getType().getObjectSize();
 
     // Process non-component-wise operations
     switch (op) {
@@ -593,13 +595,13 @@ TIntermTyped* TIntermediate::fold(TIntermAggregate* aggrNode)
     case EOpVectorEqual:
     case EOpVectorNotEqual:
         componentwise = true;
-        objectSize = children[0]->getAsConstantUnion()->getType().getObjectSize();
+        objectSize = children[0]->getAsConstantUnion()->getType().computeNumComponents();
         break;
     case EOpCross:
     case EOpReflect:
     case EOpRefract:
     case EOpFaceForward:
-        objectSize = children[0]->getAsConstantUnion()->getType().getObjectSize();
+        objectSize = children[0]->getAsConstantUnion()->getType().computeNumComponents();
         break;
     case EOpDistance:
     case EOpDot:
@@ -726,7 +728,7 @@ TIntermTyped* TIntermediate::fold(TIntermAggregate* aggrNode)
     } else {
         // Non-componentwise...
 
-        int numComps = children[0]->getAsConstantUnion()->getType().getObjectSize();
+        int numComps = children[0]->getAsConstantUnion()->getType().computeNumComponents();
         double dot;
 
         switch (aggrNode->getOp()) {
@@ -788,7 +790,7 @@ TIntermTyped* TIntermediate::fold(TIntermAggregate* aggrNode)
         case EOpOuterProduct:
         {
             int numRows = numComps;
-            int numCols = children[1]->getAsConstantUnion()->getType().getObjectSize();
+            int numCols = children[1]->getAsConstantUnion()->getType().computeNumComponents();
             for (int row = 0; row < numRows; ++row)
                 for (int col = 0; col < numCols; ++col)
                     newConstArray[col * numRows + row] = childConstUnions[0][row] * childConstUnions[1][col];
@@ -828,7 +830,7 @@ TIntermTyped* TIntermediate::foldConstructor(TIntermAggregate* aggrNode)
 {
     bool error = false;
 
-    TConstUnionArray unionArray(aggrNode->getType().getObjectSize());
+    TConstUnionArray unionArray(aggrNode->getType().computeNumComponents());
     if (aggrNode->getSequence().size() == 1)
         error = parseConstTree(aggrNode, unionArray, aggrNode->getOp(), aggrNode->getType(), true);
     else
@@ -850,13 +852,13 @@ TIntermTyped* TIntermediate::foldDereference(TIntermTyped* node, int index, TSou
     TType dereferencedType(node->getType(), index);
     dereferencedType.getQualifier().storage = EvqConst;
     TIntermTyped* result = 0;
-    int size = dereferencedType.getObjectSize();
+    int size = dereferencedType.computeNumComponents();
     
     int start;
     if (node->isStruct()) {
         start = 0;
         for (int i = 0; i < index; ++i)
-            start += (*node->getType().getStruct())[i].type->getObjectSize();
+            start += (*node->getType().getStruct())[i].type->computeNumComponents();
     } else
         start = size * index;
 
index 952d103..80c98f1 100644 (file)
@@ -1415,7 +1415,7 @@ void TIntermTyped::propagatePrecision(TPrecisionQualifier newPrecision)
 TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermConstantUnion* node) 
 {
     const TConstUnionArray& rightUnionArray = node->getConstArray();
-    int size = node->getType().getObjectSize();
+    int size = node->getType().computeNumComponents();
 
     TConstUnionArray leftUnionArray(size);
 
index 34699c5..91ef2dd 100644 (file)
@@ -1602,13 +1602,13 @@ bool TParseContext::constructorError(TSourceLoc loc, TIntermNode* node, TFunctio
     bool matrixInMatrix = false;
     bool arrayArg = false;
     for (int i = 0; i < function.getParamCount(); ++i) {
-        size += function[i].type->getObjectSize();
+        size += function[i].type->computeNumComponents();
 
         if (constructingMatrix && function[i].type->isMatrix())
             matrixInMatrix = true;
         if (full)
             overFull = true;
-        if (op != EOpConstructStruct && ! type.isArray() && size >= type.getObjectSize())
+        if (op != EOpConstructStruct && ! type.isArray() && size >= type.computeNumComponents())
             full = true;
         if (function[i].type->getQualifier().storage != EvqConst)
             constType = false;
@@ -1649,8 +1649,8 @@ bool TParseContext::constructorError(TSourceLoc loc, TIntermNode* node, TFunctio
         return true;
     }
 
-    if ((op != EOpConstructStruct && size != 1 && size < type.getObjectSize()) ||
-        (op == EOpConstructStruct && size < type.getObjectSize())) {
+    if ((op != EOpConstructStruct && size != 1 && size < type.computeNumComponents()) ||
+        (op == EOpConstructStruct && size < type.computeNumComponents())) {
         error(loc, "not enough data provided for construction", "constructor", "");
         return true;
     }
@@ -4097,10 +4097,58 @@ void TParseContext::fixBlockXfbOffsets(TSourceLoc loc, TQualifier& qualifier, TT
     qualifier.layoutXfbOffset = TQualifier::layoutXfbOffsetEnd;
 }
 
+// Calculate and save the offset of each block member, using the recursively 
+// defined block offset rules and the user-provided offset and align.
+//
+// Also, compute and save the total size of the block. For the block's size, arrayness 
+// is not taken into account, as each element is backed by a separate buffer.
+//
 void TParseContext::fixBlockUniformOffsets(TSourceLoc loc, TQualifier& qualifier, TTypeList& typeList)
 {
-    if (qualifier.storage != EvqUniform || qualifier.storage != EvqBuffer)
+    if (qualifier.storage != EvqUniform && qualifier.storage != EvqBuffer)
         return;
+    if (qualifier.layoutPacking != ElpStd140 && qualifier.layoutPacking != ElpStd430)
+        return;
+
+    int offset = 0;
+    int memberSize;
+    for (unsigned int member = 0; member < typeList.size(); ++member) {
+        TQualifier& memberQualifier = typeList[member].type->getQualifier();
+        TSourceLoc memberLoc = typeList[member].loc;
+
+        // "When align is applied to an array, it effects only the start of the array, not the array's internal stride."
+        
+        int memberAlignment = intermediate.getBaseAlignment(*typeList[member].type, memberSize, qualifier.layoutPacking == ElpStd140);
+        if (memberQualifier.hasOffset()) {
+            // "The specified offset must be a multiple 
+            // of the base alignment of the type of the block member it qualifies, or a compile-time error results."
+            if (! IsMultipleOfPow2(memberQualifier.layoutOffset, memberAlignment))
+                error(memberLoc, "must be a multiple of the member's alignment", "offset", "");
+
+            // "It is a compile-time error to specify an offset that is smaller than the offset of the previous 
+            // member in the block or that lies within the previous member of the block"
+            if (memberQualifier.layoutOffset < offset)
+                error(memberLoc, "cannot lie in previous members", "offset", "");
+
+            // "The offset qualifier forces the qualified member to start at or after the specified 
+            // integral-constant expression, which will be its byte offset from the beginning of the buffer. 
+            // "The actual offset of a member is computed as 
+            // follows: If offset was declared, start with that offset, otherwise start with the next available offset."
+            offset = std::max(offset, memberQualifier.layoutOffset);
+        }
+
+        // "The actual alignment of a member will be the greater of the specified align alignment and the standard 
+        // (e.g., std140) base alignment for the member's type."
+        if (memberQualifier.hasAlign())
+            memberAlignment = std::max(memberAlignment, memberQualifier.layoutAlign);
+
+        // "If the resulting offset is not a multiple of the actual alignment,
+        // increase it to the first offset that is a multiple of 
+        // the actual alignment."
+        RoundToPow2(offset, memberAlignment);
+        typeList[member].type->getQualifier().layoutOffset = offset;
+        offset += memberSize;
+    }
 }
 
 // For an identifier that is already declared, add more qualification to it.
index 1384c46..9a2f3b2 100644 (file)
@@ -118,20 +118,6 @@ void TType::buildMangledName(TString& mangledName)
     }
 }
 
-int TType::getStructSize() const
-{
-    if (! isStruct()) {
-        assert(false && "Not a struct");
-        return 0;
-    }
-
-    if (structureSize == 0)
-        for (TTypeList::iterator tl = getStruct()->begin(); tl != getStruct()->end(); tl++)
-            structureSize += ((*tl).type)->getObjectSize();
-
-    return structureSize;
-}
-
 //
 // Dump functions.
 //
@@ -256,7 +242,6 @@ TVariable::TVariable(const TVariable& copyOf) : TSymbol(copyOf)
 
     if (! copyOf.unionArray.empty()) {
         assert(! copyOf.type.isStruct());
-        assert(copyOf.type.getObjectSize() == 1);
         TConstUnionArray newArray(1);
         newArray[0] = copyOf.unionArray[0];
         unionArray = newArray;
index f510353..9f89cad 100644 (file)
@@ -411,7 +411,7 @@ bool TOutputTraverser::visitSelection(TVisit /* visit */, TIntermSelection* node
 
 void OutputConstantUnion(TInfoSink& out, const TIntermTyped* node, const TConstUnionArray& constUnion, int depth)
 {
-    int size = node->getType().getObjectSize();
+    int size = node->getType().computeNumComponents();
 
     for (int i = 0; i < size; i++) {
         OutputTreeText(out, node, depth);
index 491b637..ec32c90 100644 (file)
@@ -60,6 +60,10 @@ void TIntermediate::error(TInfoSink& infoSink, const char* message)
     ++numErrors;\r
 }\r
 \r
+// TODO: 4.4 offset/align:  "Two blocks linked together in the same program with the same block \r
+// name must have the exact same set of members qualified with offset and their integral-constant \r
+// expression values must be the same, or a link-time error results."\r
+\r
 //\r
 // Merge the information from 'unit' into 'this'\r
 //\r
@@ -266,7 +270,9 @@ void TIntermediate::mergeErrorCheck(TInfoSink& infoSink, const TIntermSymbol& sy
     }\r
 \r
     // Layouts... \r
-    // TODO: 4.4 enhanced layouts: generalize to include offset/align\r
+    // TODO: 4.4 enhanced layouts: Generalize to include offset/align: currrent spec \r
+    //       requires separate user-supplied offset from actual computed offset, but \r
+    //       current implementation only has one offset.\r
     if (symbol.getQualifier().layoutMatrix   != unitSymbol.getQualifier().layoutMatrix ||\r
         symbol.getQualifier().layoutPacking  != unitSymbol.getQualifier().layoutPacking ||\r
         symbol.getQualifier().layoutLocation != unitSymbol.getQualifier().layoutLocation ||\r
@@ -321,7 +327,7 @@ void TIntermediate::finalCheck(TInfoSink& infoSink)
 \r
         // "It is a compile-time or link-time error to have \r
         // any xfb_offset that overflows xfb_stride, whether stated on declarations before or after the xfb_stride, or\r
-        // in different compilation units. While xfb_stridecan be declared multiple times for the same buffer, it is a\r
+        // in different compilation units. While xfb_stride can be declared multiple times for the same buffer, it is a\r
         // compile-time or link-time error to have different values specified for the stride for the same buffer."\r
         if (xfbBuffers[b].stride != TQualifier::layoutXfbStrideEnd && xfbBuffers[b].implicitStride > xfbBuffers[b].stride) {\r
             error(infoSink, "xfb_stride is too small to hold all buffer entries:");\r
@@ -740,4 +746,153 @@ unsigned int TIntermediate::computeTypeXfbSize(const TType& type, bool& contains
         return 4 * numComponents;\r
 }\r
 \r
+const int baseAlignmentVec4Std140 = 16;\r
+\r
+// Return the size and alignment of a scalar.\r
+// The size is returned in the 'size' parameter\r
+// Return value is the alignment of the type.\r
+int TIntermediate::getBaseAlignmentScalar(const TType& type, int& size) const\r
+{\r
+    switch (type.getBasicType()) {\r
+    case EbtDouble:  size = 8; return 8;\r
+    default:         size = 4; return 4;\r
+    }\r
+}\r
+\r
+// Implement base-alignment and size rules from section 7.6.2.2 Standard Uniform Block Layout\r
+// Operates recursively.\r
+//\r
+// If std140 is true, it does the rounding up to vec4 size required by std140, \r
+// otherwise it does not, yielding std430 rules.\r
+//\r
+// The size is returned in the 'size' parameter\r
+// Return value is the alignment of the type.\r
+int TIntermediate::getBaseAlignment(const TType& type, int& size, bool std140) const\r
+{\r
+    int alignment;\r
+\r
+    // When using the std140 storage layout, structures will be laid out in buffer\r
+    // storage with its members stored in monotonically increasing order based on their\r
+    // location in the declaration. A structure and each structure member have a base\r
+    // offset and a base alignment, from which an aligned offset is computed by rounding\r
+    // the base offset up to a multiple of the base alignment. The base offset of the first\r
+    // member of a structure is taken from the aligned offset of the structure itself. The\r
+    // base offset of all other structure members is derived by taking the offset of the\r
+    // last basic machine unit consumed by the previous member and adding one. Each\r
+    // structure member is stored in memory at its aligned offset. The members of a top-\r
+    // level uniform block are laid out in buffer storage by treating the uniform block as\r
+    // a structure with a base offset of zero.\r
+    //\r
+    //   1. If the member is a scalar consuming N basic machine units, the base alignment is N.\r
+    //\r
+    //   2. If the member is a two- or four-component vector with components consuming N basic \r
+    //      machine units, the base alignment is 2N or 4N, respectively.\r
+    //\r
+    //   3. If the member is a three-component vector with components consuming N\r
+    //      basic machine units, the base alignment is 4N.\r
+    //\r
+    //   4. If the member is an array of scalars or vectors, the base alignment and array\r
+    //      stride are set to match the base alignment of a single array element, according\r
+    //      to rules (1), (2), and (3), and rounded up to the base alignment of a vec4. The\r
+    //      array may have padding at the end; the base offset of the member following\r
+    //      the array is rounded up to the next multiple of the base alignment.\r
+    //\r
+    //   5. If the member is a column-major matrix with C columns and R rows, the\r
+    //      matrix is stored identically to an array of C column vectors with R \r
+    //      components each, according to rule (4).\r
+    //\r
+    //   6. If the member is an array of S column-major matrices with C columns and\r
+    //      R rows, the matrix is stored identically to a row of S \ 2 C column vectors\r
+    //      with R components each, according to rule (4).\r
+    //\r
+    //   7. If the member is a row-major matrix with C columns and R rows, the matrix\r
+    //      is stored identically to an array of R row vectors with C components each,\r
+    //      according to rule (4).\r
+    //\r
+    //   8. If the member is an array of S row-major matrices with C columns and R\r
+    //      rows, the matrix is stored identically to a row of S \ 2 R row vectors with C\r
+    //      components each, according to rule (4).\r
+    //\r
+    //   9. If the member is a structure, the base alignment of the structure is N , where\r
+    //      N is the largest base alignment value of any    of its members, and rounded\r
+    //      up to the base alignment of a vec4. The individual members of this substructure \r
+    //      are then assigned offsets by applying this set of rules recursively,\r
+    //      where the base offset of the first member of the sub-structure is equal to the\r
+    //      aligned offset of the structure. The structure may have padding at the end;\r
+    //      the base offset of the member following the sub-structure is rounded up to\r
+    //      the next multiple of the base alignment of the structure.\r
+    //\r
+    //   10. If the member is an array of S structures, the S elements of the array are laid\r
+    //       out in order, according to rule (9).\r
+\r
+    // rules 4, 6, and 8\r
+    if (type.isArray()) {\r
+        TType derefType(type, 0);\r
+        alignment = getBaseAlignment(derefType, size, std140);\r
+        if (std140)\r
+            alignment = std::max(baseAlignmentVec4Std140, alignment);\r
+        RoundToPow2(size, alignment);\r
+        size *= type.getArraySize();\r
+        return alignment;\r
+    }\r
+\r
+    // rule 9\r
+    if (type.getBasicType() == EbtStruct) {\r
+        const TTypeList& memberList = *type.getStruct();\r
+\r
+        size = 0;\r
+        int maxAlignment = std140 ? baseAlignmentVec4Std140 : 0;\r
+        for (size_t m = 0; m < memberList.size(); ++m) {\r
+            int memberSize;\r
+            int memberAlignment = getBaseAlignment(*memberList[m].type, memberSize, std140);\r
+            maxAlignment = std::max(maxAlignment, memberAlignment);\r
+            RoundToPow2(size, memberAlignment);         \r
+            size += memberSize;\r
+        }\r
+\r
+        return maxAlignment;\r
+    }\r
+\r
+    // rule 1\r
+    if (type.isScalar())\r
+        return getBaseAlignmentScalar(type, size);\r
+\r
+    // rules 2 and 3\r
+    if (type.isVector()) {\r
+        int scalarAlign = getBaseAlignmentScalar(type, size);\r
+        switch (type.getVectorSize()) {\r
+        case 2:\r
+            size *= 2;\r
+            return 2 * scalarAlign;\r
+        default: \r
+            size *= type.getVectorSize();\r
+            return 4 * scalarAlign;\r
+        }\r
+    }\r
+\r
+    // rules 5 and 7\r
+    if (type.isMatrix()) {\r
+        TType derefType(type, 0);\r
+            \r
+        // rule 5: deref to row, not to column, meaning the size of vector is num columns instead of num rows\r
+        if (type.getQualifier().layoutMatrix == ElmRowMajor)\r
+            derefType.setElementType(derefType.getBasicType(), type.getMatrixCols(), 0, 0, 0);\r
+            \r
+        alignment = getBaseAlignment(derefType, size, std140);\r
+        if (std140)\r
+            alignment = std::max(baseAlignmentVec4Std140, alignment);\r
+        RoundToPow2(size, alignment);\r
+        if (type.getQualifier().layoutMatrix == ElmRowMajor)\r
+            size *= type.getMatrixRows();\r
+        else\r
+            size *= type.getMatrixCols();\r
+\r
+        return alignment;\r
+    }\r
+\r
+    assert(0);  // all cases should be covered above\r
+    size = baseAlignmentVec4Std140;\r
+    return baseAlignmentVec4Std140;\r
+}\r
+\r
 } // end namespace glslang\r
index c3d7588..9bb1709 100644 (file)
@@ -239,6 +239,7 @@ public:
     }
     int addXfbBufferOffset(const TType&);
     unsigned int computeTypeXfbSize(const TType&, bool& containsDouble) const;
+    int getBaseAlignment(const TType&, int& size, bool std140) const;
 
 protected:
     void error(TInfoSink& infoSink, const char*);
@@ -249,6 +250,7 @@ protected:
     void inOutLocationCheck(TInfoSink&);
     TIntermSequence& findLinkerObjects() const;
     bool userOutputUsed() const;
+    int getBaseAlignmentScalar(const TType&, int& size) const;
 
 protected:
     const EShLanguage language;
index ac643b6..978dc8a 100644 (file)
@@ -82,7 +82,7 @@ bool TConstTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node)
     if (flag) {
         singleConstantParam = true; 
         constructorType = node->getOp();
-        size = node->getType().getObjectSize();
+        size = node->getType().computeNumComponents();
 
         if (node->getType().isMatrix()) {
             isMatrix = true;
@@ -115,13 +115,13 @@ bool TConstTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node)
 void TConstTraverser::visitConstantUnion(TIntermConstantUnion* node)
 {
     TConstUnionArray leftUnionArray(unionArray);
-    int instanceSize = type.getObjectSize();
+    int instanceSize = type.computeNumComponents();
 
     if (index >= instanceSize)
         return;
 
     if (! singleConstantParam) {
-        int rightUnionSize = node->getType().getObjectSize();
+        int rightUnionSize = node->getType().computeNumComponents();
     
         const TConstUnionArray& rightUnionArray = node->getConstArray();
         for (int i = 0; i < rightUnionSize; i++) {
@@ -136,6 +136,7 @@ void TConstTraverser::visitConstantUnion(TIntermConstantUnion* node)
         const TConstUnionArray& rightUnionArray = node->getConstArray();
         if (! isMatrix) {
             int count = 0;
+            int nodeComps = node->getType().computeNumComponents();
             for (int i = index; i < endIndex; i++) {
                 if (i >= instanceSize)
                     return;
@@ -144,7 +145,7 @@ void TConstTraverser::visitConstantUnion(TIntermConstantUnion* node)
 
                 (index)++;
                 
-                if (node->getType().getObjectSize() > 1)
+                if (nodeComps > 1)
                     count++;
             }
         } else {
@@ -169,6 +170,7 @@ void TConstTraverser::visitConstantUnion(TIntermConstantUnion* node)
                 // matrix from vector
                 int count = 0;
                 const int startIndex = index;
+                int nodeComps = node->getType().computeNumComponents();
                 for (int i = startIndex; i < endIndex; i++) {
                     if (i >= instanceSize)
                         return;
@@ -179,7 +181,7 @@ void TConstTraverser::visitConstantUnion(TIntermConstantUnion* node)
 
                     index++;
 
-                    if (node->getType().getObjectSize() > 1)
+                    if (nodeComps > 1)
                         count++;                
                 }
             }
index 164ced5..709fc45 100644 (file)
@@ -108,139 +108,42 @@ public:
         }\r
     }\r
 \r
-    static const int baseAlignmentVec4Std140;\r
-\r
-    // align a value:  if 'value' is not aligned to 'alignment', move it up to a multiple of alignment\r
-    void align(int& value, int alignment)\r
-    {\r
-        int error = value % alignment;\r
-        if (error)\r
-            value += alignment - error;\r
-    }\r
-\r
-    // return the size and alignment of a scalar\r
-    int getBaseAlignmentScalar(const TType& type, int& size)\r
-    {\r
-        switch (type.getBasicType()) {\r
-        case EbtDouble:  size = 8; return 8;\r
-        default:         size = 4; return 4;\r
-        }\r
-    }\r
-\r
-    // Implement base-alignment and size rules from section 7.6.2.2 Standard Uniform Block Layout\r
-    // Operates recursively.\r
-    // If std140 is true, it does the rounding up to vec4 size required by std140, \r
-    // otherwise it does not, yielding std430 rules.\r
-    //\r
-    // Returns the size of the type.\r
-    int getBaseAlignment(const TType& type, int& size, bool std140)\r
+    // Lookup or calculate the offset of a block member, using the recursively \r
+    // defined block offset rules.\r
+    int getOffset(const TType& type, int index)\r
     {\r
-        int alignment;\r
-\r
-        // rules 4, 6, and 8\r
-        if (type.isArray()) {\r
-            TType derefType(type, 0);\r
-            alignment = getBaseAlignment(derefType, size, std140);\r
-            if (std140)\r
-                alignment = std::max(baseAlignmentVec4Std140, alignment);\r
-            align(size, alignment);\r
-            size *= type.getArraySize();\r
-            return alignment;\r
-        }\r
-\r
-        // rule 9\r
-        if (type.getBasicType() == EbtStruct) {\r
-            const TTypeList& memberList = *type.getStruct();\r
-\r
-            size = 0;\r
-            int maxAlignment = std140 ? baseAlignmentVec4Std140 : 0;\r
-            for (size_t m = 0; m < memberList.size(); ++m) {\r
-                int memberSize;\r
-                int memberAlignment = getBaseAlignment(*memberList[m].type, memberSize, std140);\r
-                maxAlignment = std::max(maxAlignment, memberAlignment);\r
-                align(size, memberAlignment);         \r
-                size += memberSize;\r
-            }\r
-\r
-            return maxAlignment;\r
-        }\r
-\r
-        // rule 1\r
-        if (type.isScalar())\r
-            return getBaseAlignmentScalar(type, size);\r
-\r
-        // rules 2 and 3\r
-        if (type.isVector()) {\r
-            int scalarAlign = getBaseAlignmentScalar(type, size);\r
-            switch (type.getVectorSize()) {\r
-            case 2:\r
-                size *= 2;\r
-                return 2 * scalarAlign;\r
-            default: \r
-                size *= type.getVectorSize();\r
-                return 4 * scalarAlign;\r
-            }\r
-        }\r
-\r
-        // rules 5 and 7\r
-        if (type.isMatrix()) {\r
-            TType derefType(type, 0);\r
-            \r
-            // rule 5: deref to row, not to column, meaning the size of vector is num columns instead of num rows\r
-            if (type.getQualifier().layoutMatrix == ElmRowMajor)\r
-                derefType.setElementType(derefType.getBasicType(), type.getMatrixCols(), 0, 0, 0);\r
-            \r
-            alignment = getBaseAlignment(derefType, size, std140);\r
-            if (std140)\r
-                alignment = std::max(baseAlignmentVec4Std140, alignment);\r
-            align(size, alignment);\r
-            if (type.getQualifier().layoutMatrix == ElmRowMajor)\r
-                size *= type.getMatrixRows();\r
-            else\r
-                size *= type.getMatrixCols();\r
-\r
-            return alignment;\r
-        }\r
+        const TTypeList& memberList = *type.getStruct();\r
 \r
-        assert(0);  // all cases should be covered above\r
-        size = baseAlignmentVec4Std140;\r
-        return baseAlignmentVec4Std140;\r
-    }\r
-\r
-    // Calculate the offset of a block member, using the recursively defined\r
-    // block offset rules.\r
-    int getBlockMemberOffset(const TType& blockType, int index)\r
-    {\r
-        // TODO: reflection performance: cache intermediate results instead of recomputing them\r
+        // Don't calculate offset if one is present, it could be user supplied\r
+        // and different than what would be calculated.  That is, this is faster,\r
+        // but not just an optimization.\r
+        if (memberList[index].type->getQualifier().hasOffset())\r
+            return memberList[index].type->getQualifier().layoutOffset;\r
 \r
-        int offset = 0;\r
-        const TTypeList& memberList = *blockType.getStruct();        \r
         int memberSize;\r
-        for (int m = 0; m < index; ++m) {\r
-            int memberAlignment = getBaseAlignment(*memberList[m].type, memberSize, blockType.getQualifier().layoutPacking == ElpStd140);\r
-            align(offset, memberAlignment);\r
-            offset += memberSize;\r
+        int offset = 0;\r
+        for (int m = 0; m <= index; ++m) {\r
+            int memberAlignment = intermediate.getBaseAlignment(*memberList[m].type, memberSize, type.getQualifier().layoutPacking == ElpStd140);\r
+            RoundToPow2(offset, memberAlignment);\r
+            if (m < index)\r
+                offset += memberSize;\r
         }\r
-        int memberAlignment = getBaseAlignment(*memberList[index].type, memberSize, blockType.getQualifier().layoutPacking == ElpStd140);\r
-        align(offset, memberAlignment);\r
 \r
         return offset;\r
     }\r
 \r
     // Calculate the block data size.\r
-    // Arrayness is not taken into account, each element is backed by a separate buffer.\r
+    // Block arrayness is not taken into account, each element is backed by a separate buffer.\r
     int getBlockSize(const TType& blockType)\r
     {\r
-        int size = 0;\r
-        const TTypeList& memberList = *blockType.getStruct();        \r
-        int memberSize;\r
-        for (size_t m = 0; m < memberList.size(); ++m) {\r
-            int memberAlignment = getBaseAlignment(*memberList[m].type, memberSize, blockType.getQualifier().layoutPacking == ElpStd140);\r
-            align(size, memberAlignment);\r
-            size += memberSize;\r
-        }\r
+        const TTypeList& memberList = *blockType.getStruct();\r
+        int lastIndex = memberList.size() - 1;\r
+        int lastOffset = getOffset(blockType, lastIndex);\r
 \r
-        return size;\r
+        int lastMemberSize;\r
+        intermediate.getBaseAlignment(*memberList[lastIndex].type, lastMemberSize, blockType.getQualifier().layoutPacking == ElpStd140);\r
+\r
+        return lastOffset + lastMemberSize;\r
     }\r
 \r
     // Traverse the provided deref chain, including the base, and\r
@@ -283,7 +186,7 @@ public:
             case EOpIndexDirectStruct:\r
                 index = visitNode->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();\r
                 if (offset >= 0)\r
-                    offset += getBlockMemberOffset(visitNode->getLeft()->getType(), index);\r
+                    offset += getOffset(visitNode->getLeft()->getType(), index);\r
                 if (name.size() > 0)\r
                     name.append(".");\r
                 name.append((*visitNode->getLeft()->getType().getStruct())[index].type->getFieldName());\r
@@ -715,8 +618,6 @@ public:
     std::set<const TIntermNode*> processedDerefs;\r
 };\r
 \r
-const int TLiveTraverser::baseAlignmentVec4Std140 = 16;\r
-\r
 //\r
 // Implement the traversal functions of interest.\r
 //\r