GL_ARB_enhanced_layouts, part 2: Full implementation of location/component, plus...
authorJohn Kessenich <cepheus@frii.com>
Wed, 8 Jan 2014 23:25:18 +0000 (23:25 +0000)
committerJohn Kessenich <cepheus@frii.com>
Wed, 8 Jan 2014 23:25:18 +0000 (23:25 +0000)
git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@24692 e7fa87d3-cd2b-0410-9028-fcbf551c1848

22 files changed:
Test/330.frag
Test/440.frag [new file with mode: 0644]
Test/440.vert [new file with mode: 0644]
Test/baseResults/150.geom.out
Test/baseResults/150.tesc.out
Test/baseResults/300layout.frag.out
Test/baseResults/300layout.vert.out
Test/baseResults/330.frag.out
Test/baseResults/400.geom.out
Test/baseResults/430.vert.out
Test/baseResults/440.frag.out [new file with mode: 0644]
Test/baseResults/440.vert.out [new file with mode: 0644]
Test/baseResults/specExamples.frag.out
Test/baseResults/specExamples.vert.out
Test/testlist
Todo.txt
glslang/Include/Types.h
glslang/Include/revision.h
glslang/MachineIndependent/ParseHelper.cpp
glslang/MachineIndependent/ParseHelper.h
glslang/MachineIndependent/linkValidate.cpp
glslang/MachineIndependent/localintermediate.h

index b90ae54..3fad83b 100644 (file)
@@ -45,9 +45,72 @@ layout(location = -2) in vec4 v1;         // ERROR
 layout(location = start + 2) in vec4 v2;  // ERROR
 layout(location = 4.7e10) in vec4 v20;    // ERROR
 
+struct S {
+    float f1;
+    layout(location = 3) float f2;        // ERROR
+};
+
+layout(location = 1) in inblock {         // ERROR
+    float f1;
+    layout(location = 3) float f2;        // ERROR
+};
+
+layout(location = 1) uniform ublock {     // ERROR
+    float f1;
+    layout(location = 3) float f2;        // ERROR
+} uinst;
+
 #extension GL_ARB_enhanced_layouts : enable
 
 layout(location = start) in vec4 v3;
 layout(location = -2) in vec4 v4;         // ERROR
 layout(location = -start) in vec4 v5;     // ERROR
-layout(location = start*start - 2) in vec4 v6;
+layout(location = start*start - 2 - 4) in vec4 v6;
+
+struct S2 {
+    float f1;
+    layout(location = 3) float f2;        // ERROR
+};
+
+layout(location = 28) in inblock2 {
+    bool b1;
+    float f1;
+    layout(location = 25) float f2;
+    vec4 f3;
+    layout(location = 21) S2 s2;
+    vec4 f4;
+    vec4 f5;
+} ininst2;
+
+layout(location = 13) uniform ublock2 {   // ERROR
+    float f1;
+    layout(location = 3) float f2;        // ERROR
+} uinst2;
+
+in inblock3 {                             // ERROR, mix of location internal with no location external
+    float f1;
+    layout(location = 40) float f2;
+} in3;
+
+in ublock4 {
+    layout(location = 50) float f1;
+    layout(location = 51) float f2;
+} in4;
+
+layout(location = 33) in struct SS {
+    vec3 a;    // gets location 33
+    mat2 b;    // gets locations 34 and 35
+    vec4 c[2]; // gets locations 36 and 37
+    layout (location = 38) vec2 A; // ERROR, can't use on struct member
+} s;
+
+layout(location = 44) in block {
+    vec4 d; // gets location 44
+    vec4 e; // gets location 45
+    layout(location = 47) vec4 f; // gets location 47
+    vec4 g; // gets location 48
+    layout (location = 41) vec4 h; // gets location 41
+    vec4 i; // gets location 42
+    vec4 j; // gets location 43
+    vec4 k; // ERROR, location 44 already used
+};
diff --git a/Test/440.frag b/Test/440.frag
new file mode 100644 (file)
index 0000000..23c43b4
--- /dev/null
@@ -0,0 +1,22 @@
+#version 440\r
+\r
+// Note 'location'-only tests for enhanced layouts are in 330.frag\r
+// Generic 'component' tests are in 440.vert\r
+\r
+// a consumes components 2 and 3 of location 4\r
+layout(location = 4, component = 2) in vec2 a; \r
+\r
+// b consumes component 1 of location 4\r
+layout(location = 4, component = 1) in float b; \r
+layout(location = 4, component = 2) in vec2 h;  // ERROR, component overlap not okay for fragment in\r
+\r
+layout(location = 3, component = 2) in vec3 c;  // ERROR: c overflows components 2 and 3\r
+\r
+// e consumes beginning (components 0, 1 and 2) of each of 6 slots\r
+layout(location = 20, component = 0) in vec3 e[6];\r
+\r
+// f consumes last component of the same 6 slots \r
+layout(location = 20, component = 3) in float f[6];\r
+\r
+layout(location = 30, component = 3) out int be;\r
+layout(location = 30, component = 0) out vec3 bf;  // ERROR, not the same basic type\r
diff --git a/Test/440.vert b/Test/440.vert
new file mode 100644 (file)
index 0000000..3aeebaa
--- /dev/null
@@ -0,0 +1,64 @@
+#version 440\r
+\r
+// Note 'location' tests for enhanced layouts are in 330.frag\r
+\r
+layout(location = 2, component = 2) in vec2 a; \r
+layout(location = 2, component = 1) in float b; \r
+\r
+layout(location = 3, component = 2) in vec3 c;      // ERROR: c overflows components 2 and 3\r
+\r
+layout(location = 0, component = 3) in float d[4]; \r
+\r
+layout(location = 4, component = 0) in vec3 e[5];\r
+layout(location = 4, component = 3) in float f[5];\r
+\r
+layout(location = 9, component = 4) in float g[6];   // ERROR, component too big\r
+\r
+layout(location = 4, component = 2) in vec2 h;       // component overlap okay for vertex in\r
+\r
+layout(location = 3, component = 2) out vec2 i;\r
+layout(location = 3, component = 0) out vec2 j;\r
+\r
+layout(location = 4, component = 2) out vec2 k;\r
+layout(location = 4, component = 2) out vec2 m;      // ERROR, component overlap\r
+\r
+layout(location = 2, component = 2) out vec2 n;\r
+layout(location = 2, component = 0) out vec3 p;      // ERROR, component overlap\r
+\r
+layout(location = 10, component = 3) out float q[6]; \r
+layout(location = 10, component = 0) out vec3 r[6];\r
+\r
+layout(location = 15, component = 3) out float s;    // ERROR, overlap\r
+layout(location = 10, component = 1) out float t;    // ERROR, overlap\r
+\r
+layout(location = 20, component = 2) out float u;\r
+layout(location = 20, component = 0) out float v;\r
+layout(location = 20, component = 3) out float w;\r
+layout(location = 20, component = 1) out vec2 x;     // ERROR, overlap\r
+\r
+layout(location = 30, component = 3) out vec2 y;     // ERROR, goes to component 4\r
+layout(location = 31, component = 1) out vec4 z;     // ERROR, goes to component 4\r
+\r
+layout(location = 32, component = 1) out mat4 ba;               // ERROR\r
+layout(location = 33, component = 1) out struct S {int a;} Ss;  // ERROR\r
+layout(location = 34, component = 1) out bn { int a;} bb;       // ERROR\r
+\r
+layout(component = 1) out float bc;    // ERROR, no location\r
+\r
+out blockname {\r
+    layout(location = 40, component = 2) out float u;\r
+    layout(location = 40, component = 0) out float v;\r
+    layout(location = 40, component = 3) out float w;\r
+    layout(location = 40, component = 1) out vec2 x;     // ERROR, overlap\r
+\r
+    layout(location = 41, component = 3) out vec2 y;     // ERROR, goes to component 4\r
+    layout(location = 42, component = 1) out vec4 z;     // ERROR, goes to component 4\r
+\r
+    layout(location = 42, component = 1) out mat4 ba;    // ERROR\r
+    layout(location = 43, component = 1) out S Ss;       // ERROR\r
+} bd;\r
+\r
+layout(location = 1, component = 1) out;                 // ERROR, no global setting\r
+\r
+layout(location = 50, component = 3) out int be;\r
+layout(location = 50, component = 0) out vec3 bf;\r
index 59180a7..30fd4ba 100644 (file)
@@ -9,6 +9,7 @@ ERROR: 0:44: 'stream' : can only be used on an output
 ERROR: 0:45: 'stream' : can only be used on an output \r
 ERROR: 0:46: 'stream' : can only be used on an output \r
 ERROR: 0:47: 'stream' : can only be used on an output \r
+ERROR: 0:47: 'stream' : can only be used on an output \r
 ERROR: 0:60: 'stream' : member cannot contradict block \r
 ERROR: 0:65: 'max_vertices' : can only apply to a standalone qualifier \r
 ERROR: 0:70: 'points' : cannot change previously set output primitive \r
@@ -29,7 +30,8 @@ ERROR: 0:86: 'triangles_adjacency' : cannot change previously set input primitiv
 ERROR: 0:87: 'invocations' : not supported for this version or the enabled extensions \r
 ERROR: 0:88: 'max_vertices' : too large, must be less than gl_MaxGeometryOutputVertices \r
 ERROR: 0:91: 'stream' : member cannot contradict block \r
-ERROR: 29 compilation errors.  No code generated.\r
+ERROR: 0:91: 'stream' : can only be used on an output \r
+ERROR: 31 compilation errors.  No code generated.\r
 \r
 \r
 invocations = 4\r
index f6258e9..30646f9 100644 (file)
@@ -221,8 +221,8 @@ ERROR: 0:40: 'vertices' : cannot change previously set layout value
 ERROR: 0:44: '[' :  array index out of range '4'\r
 ERROR: 0:47: 'in' : type must be an array: ina\r
 ERROR: 0:49: '[]' : tessellation input array size must be gl_MaxPatchVertices or unsized \r
-ERROR: 0:56: 'location' : repeated use of location 4\r
-ERROR: 0:60: 'location' : repeated use of location 4\r
+ERROR: 0:56: 'location' : overlapping use of location 4\r
+ERROR: 0:60: 'location' : overlapping use of location 4\r
 ERROR: 11 compilation errors.  No code generated.\r
 \r
 \r
@@ -381,8 +381,8 @@ ERROR: 0:73: 'in' : type must be an array: ina
 ERROR: 0:75: '[]' : tessellation input array size must be gl_MaxPatchVertices or unsized \r
 ERROR: 0:78: 'in' : type must be an array: bla\r
 ERROR: 0:86: '[]' : tessellation input array size must be gl_MaxPatchVertices or unsized \r
-ERROR: 0:96: 'location' : repeated use of location 24\r
-ERROR: 0:99: 'location' : repeated use of location 24\r
+ERROR: 0:96: 'location' : overlapping use of location 24\r
+ERROR: 0:99: 'location' : overlapping use of location 24\r
 ERROR: 29 compilation errors.  No code generated.\r
 \r
 \r
index ac66569..0c952e4 100644 (file)
@@ -1,7 +1,7 @@
 300layout.frag\r
 ERROR: 0:4: 'location qualifier on input' : not supported in this stage: fragment\r
-ERROR: 0:18: 'location' : repeated use of location 41\r
-ERROR: 0:19: 'location' : repeated use of location 40\r
+ERROR: 0:18: 'location' : overlapping use of location 41\r
+ERROR: 0:19: 'location' : overlapping use of location 40\r
 ERROR: 3 compilation errors.  No code generated.\r
 \r
 \r
index a34e63f..4ce58fa 100644 (file)
@@ -2,9 +2,9 @@
 ERROR: 0:7: 'vertex input arrays' : not supported with this profile: es\r
 ERROR: 0:8: 'in' : cannot be a structure or array \r
 ERROR: 0:8: 'vertex input arrays' : not supported with this profile: es\r
-ERROR: 0:8: 'location' : repeated use of location 10\r
-ERROR: 0:12: 'badm4' : cannot specify matrix layout on a variable declaration \r
-ERROR: 0:12: 'badm4' : cannot specify packing on a variable declaration \r
+ERROR: 0:8: 'location' : overlapping use of location 10\r
+ERROR: 0:12: 'layout' : cannot specify matrix layout on a variable declaration \r
+ERROR: 0:12: 'layout' : cannot specify packing on a variable declaration \r
 ERROR: 0:19: 'badf' : member of uniform block cannot have an auxiliary or interpolation qualifier \r
 ERROR: 0:20: 'badg' : member storage qualifier cannot contradict block storage qualifier \r
 ERROR: 0:21: 'bad1' : member of block cannot have a packing layout qualifier \r
@@ -15,8 +15,8 @@ ERROR: 0:38: 'output block' : not supported with this profile: es
 ERROR: 0:42: 'location qualifier on output' : not supported in this stage: vertex\r
 ERROR: 0:50: 'shared' : not supported with this profile: es\r
 ERROR: 0:50: 'shared' : not supported in this stage: vertex\r
-ERROR: 0:54: 'aoeuntaoeu' : layout qualifiers for matrix layout and packing only apply to uniform or buffer blocks \r
-ERROR: 0:57: 'location' : repeated use of location 40\r
+ERROR: 0:54: 'layout' : qualifiers for matrix layout and block packing only apply to uniform or buffer blocks \r
+ERROR: 0:57: 'location' : overlapping use of location 40\r
 ERROR: 18 compilation errors.  No code generated.\r
 \r
 \r
index 0ada059..f8e9f2b 100644 (file)
@@ -10,9 +10,22 @@ ERROR: 0:44: 'layout-id value' : cannot be negative
 ERROR: 0:45: 'non-literal layout-id value' : not supported for this version or the enabled extensions \r
 ERROR: 0:46: 'layout-id value' : scalar integer expression required \r
 ERROR: 0:46: 'location' : location is too large \r
-ERROR: 0:51: 'layout-id value' : cannot be negative \r
-ERROR: 0:52: 'layout-id value' : cannot be negative \r
-ERROR: 12 compilation errors.  No code generated.\r
+ERROR: 0:50: 'f2' : cannot use layout qualifiers on structure members \r
+ERROR: 0:55: 'location on block member' : not supported for this version or the enabled extensions \r
+ERROR: 0:60: 'location on block member' : can only use in an in/out block \r
+ERROR: 0:60: 'location qualifier on uniform or buffer' : not supported for this version or the enabled extensions \r
+ERROR: 0:58: 'location qualifier on uniform or buffer' : not supported for this version or the enabled extensions \r
+ERROR: 0:66: 'layout-id value' : cannot be negative \r
+ERROR: 0:67: 'layout-id value' : cannot be negative \r
+ERROR: 0:72: 'f2' : cannot use layout qualifiers on structure members \r
+ERROR: 0:87: 'location on block member' : can only use in an in/out block \r
+ERROR: 0:87: 'location qualifier on uniform or buffer' : not supported for this version or the enabled extensions \r
+ERROR: 0:87: 'location' : overlapping use of location 3\r
+ERROR: 0:85: 'location qualifier on uniform or buffer' : not supported for this version or the enabled extensions \r
+ERROR: 0:90: 'location' : either the block needs a location, or all members need a location, or no members have a location \r
+ERROR: 0:104: 'A' : cannot use layout qualifiers on structure members \r
+ERROR: 0:115: 'location' : overlapping use of location 44\r
+ERROR: 25 compilation errors.  No code generated.\r
 \r
 \r
 ERROR: node is still EOpNull!\r
@@ -57,10 +70,18 @@ ERROR: node is still EOpNull!
 0:?     'v1' (smooth in 4-component vector of float)\r
 0:?     'v2' (layout(location=8 ) smooth in 4-component vector of float)\r
 0:?     'v20' (smooth in 4-component vector of float)\r
+0:?     '__anon__1' (in block{layout(location=1 component=0 ) in float f1, layout(location=3 ) in float f2})\r
+0:?     'uinst' (layout(location=1 column_major shared ) uniform block{layout(column_major shared ) uniform float f1, layout(location=3 column_major shared ) uniform float f2})\r
 0:?     'v3' (layout(location=6 ) smooth in 4-component vector of float)\r
 0:?     'v4' (smooth in 4-component vector of float)\r
 0:?     'v5' (smooth in 4-component vector of float)\r
-0:?     'v6' (layout(location=34 ) smooth in 4-component vector of float)\r
+0:?     'v6' (layout(location=30 ) smooth in 4-component vector of float)\r
+0:?     'ininst2' (in block{layout(location=28 component=0 ) in bool b1, layout(location=29 component=0 ) in float f1, layout(location=25 ) in float f2, layout(location=26 component=0 ) in 4-component vector of float f3, layout(location=21 ) in structure{float f1, float f2} s2, layout(location=23 component=0 ) in 4-component vector of float f4, layout(location=24 component=0 ) in 4-component vector of float f5})\r
+0:?     'uinst2' (layout(location=13 column_major shared ) uniform block{layout(column_major shared ) uniform float f1, layout(location=3 column_major shared ) uniform float f2})\r
+0:?     'in3' (in block{in float f1, layout(location=40 ) in float f2})\r
+0:?     'in4' (in block{layout(location=50 ) in float f1, layout(location=51 ) in float f2})\r
+0:?     's' (layout(location=33 ) smooth in structure{3-component vector of float a, 2X2 matrix of float b, 2-element array of 4-component vector of float c, 2-component vector of float A})\r
+0:?     '__anon__2' (in block{layout(location=44 component=0 ) in 4-component vector of float d, layout(location=45 component=0 ) in 4-component vector of float e, layout(location=47 ) in 4-component vector of float f, layout(location=48 component=0 ) in 4-component vector of float g, layout(location=41 ) in 4-component vector of float h, layout(location=42 component=0 ) in 4-component vector of float i, layout(location=43 component=0 ) in 4-component vector of float j, layout(location=44 component=0 ) in 4-component vector of float k})\r
 \r
 \r
 Linked fragment stage:\r
index d2e69a8..163ebfd 100644 (file)
@@ -8,7 +8,7 @@ ERROR: 0:25: 'length' :  array must first be sized by a redeclaration or layout
 ERROR: 0:36: 'length' :  array must first be sized by a redeclaration or layout qualifier\r
 ERROR: 0:40: 'triangles' : inconsistent input primitive for array size of colorBad\r
 ERROR: 0:44: 'triangles' : inconsistent input primitive for array size of colorbad2\r
-ERROR: 0:56: 'location' : repeated use of location 4\r
+ERROR: 0:56: 'location' : overlapping use of location 4\r
 ERROR: 0:58: 'patch' : not supported in this stage: geometry\r
 ERROR: 0:59: 'patch' : not supported in this stage: geometry\r
 ERROR: 0:61: 'in' : type must be an array: scalar\r
index f407711..9176bfa 100644 (file)
@@ -1,6 +1,6 @@
 430.vert\r
 Warning, version 430 is not yet complete; some version-specific features are present, but many are missing.\r
-ERROR: 0:3: 'v4' : location qualifiers only appy to uniform, buffer, in, or out storage qualifiers \r
+ERROR: 0:3: 'location' : can only appy to uniform, buffer, in, or out storage qualifiers \r
 ERROR: 0:7: 'location qualifier on in/out block' : not supported for this version or the enabled extensions \r
 ERROR: 0:8: 'location qualifier on in/out block' : not supported for this version or the enabled extensions \r
 ERROR: 0:21: 'g' : cannot use storage or interpolation qualifiers on structure members \r
@@ -11,7 +11,7 @@ ERROR: 0:25: 'm3' : cannot use layout qualifiers on structure members
 ERROR: 0:28: '' : cannot use invariant qualifier on a function parameter \r
 ERROR: 0:30: '' : cannot use layout qualifiers on a function parameter \r
 ERROR: 0:31: '' : cannot use auxiliary or interpolation qualifiers on a function parameter \r
-ERROR: 0:42: 'location' : repeated use of location 53\r
+ERROR: 0:42: 'location' : overlapping use of location 53\r
 ERROR: 0:47: 'gl_ClipDistance array size' : must be less than gl_MaxClipDistances (8)\r
 ERROR: 13 compilation errors.  No code generated.\r
 \r
diff --git a/Test/baseResults/440.frag.out b/Test/baseResults/440.frag.out
new file mode 100644 (file)
index 0000000..771715f
--- /dev/null
@@ -0,0 +1,25 @@
+440.frag\r
+Warning, version 440 is not yet complete; some version-specific features are present, but many are missing.\r
+ERROR: 0:11: 'location' : overlapping use of location 4\r
+ERROR: 0:13: 'component' : type overflows the available 4 components \r
+ERROR: 0:22: 'location' : fragment outputs sharing the same location must be the same basic type 30\r
+ERROR: 3 compilation errors.  No code generated.\r
+\r
+\r
+ERROR: node is still EOpNull!\r
+0:?   Linker Objects\r
+0:?     'a' (layout(location=4 component=2 ) smooth in 2-component vector of float)\r
+0:?     'b' (layout(location=4 component=1 ) smooth in float)\r
+0:?     'h' (layout(location=4 component=2 ) smooth in 2-component vector of float)\r
+0:?     'c' (layout(location=3 component=2 ) smooth in 3-component vector of float)\r
+0:?     'e' (layout(location=20 component=0 ) smooth in 6-element array of 3-component vector of float)\r
+0:?     'f' (layout(location=20 component=3 ) smooth in 6-element array of float)\r
+0:?     'be' (layout(location=30 component=3 ) out int)\r
+0:?     'bf' (layout(location=30 component=0 ) out 3-component vector of float)\r
+\r
+\r
+Linked fragment stage:\r
+\r
+ERROR: Linking fragment stage: Missing entry point: Each stage requires one "void main()" entry point\r
+\r
+\r
diff --git a/Test/baseResults/440.vert.out b/Test/baseResults/440.vert.out
new file mode 100644 (file)
index 0000000..ed94e05
--- /dev/null
@@ -0,0 +1,66 @@
+440.vert\r
+Warning, version 440 is not yet complete; some version-specific features are present, but many are missing.\r
+ERROR: 0:8: 'component' : type overflows the available 4 components \r
+ERROR: 0:15: 'component' : component is too large \r
+ERROR: 0:23: 'location' : overlapping use of location 4\r
+ERROR: 0:26: 'location' : overlapping use of location 2\r
+ERROR: 0:31: 'location' : overlapping use of location 15\r
+ERROR: 0:32: 'location' : overlapping use of location 10\r
+ERROR: 0:37: 'location' : overlapping use of location 20\r
+ERROR: 0:39: 'component' : type overflows the available 4 components \r
+ERROR: 0:40: 'component' : type overflows the available 4 components \r
+ERROR: 0:42: 'component' : cannot apply to a matrix, structure, or block \r
+ERROR: 0:43: 'component' : cannot apply to a matrix, structure, or block \r
+ERROR: 0:44: 'component' : cannot apply to a matrix, structure, or block \r
+ERROR: 0:46: 'component' : must specify 'location' to use 'component' \r
+ERROR: 0:52: 'location' : overlapping use of location 40\r
+ERROR: 0:54: 'component' : type overflows the available 4 components \r
+ERROR: 0:55: 'component' : type overflows the available 4 components \r
+ERROR: 0:57: 'component' : cannot apply to a matrix, structure, or block \r
+ERROR: 0:58: 'component' : cannot apply to a matrix, structure, or block \r
+ERROR: 0:61: 'location' : cannot declare a default, use a full declaration \r
+ERROR: 19 compilation errors.  No code generated.\r
+\r
+\r
+ERROR: node is still EOpNull!\r
+0:?   Linker Objects\r
+0:?     'a' (layout(location=2 component=2 ) in 2-component vector of float)\r
+0:?     'b' (layout(location=2 component=1 ) in float)\r
+0:?     'c' (layout(location=3 component=2 ) in 3-component vector of float)\r
+0:?     'd' (layout(location=0 component=3 ) in 4-element array of float)\r
+0:?     'e' (layout(location=4 component=0 ) in 5-element array of 3-component vector of float)\r
+0:?     'f' (layout(location=4 component=3 ) in 5-element array of float)\r
+0:?     'g' (layout(location=9 ) in 6-element array of float)\r
+0:?     'h' (layout(location=4 component=2 ) in 2-component vector of float)\r
+0:?     'i' (layout(location=3 component=2 ) smooth out 2-component vector of float)\r
+0:?     'j' (layout(location=3 component=0 ) smooth out 2-component vector of float)\r
+0:?     'k' (layout(location=4 component=2 ) smooth out 2-component vector of float)\r
+0:?     'm' (layout(location=4 component=2 ) smooth out 2-component vector of float)\r
+0:?     'n' (layout(location=2 component=2 ) smooth out 2-component vector of float)\r
+0:?     'p' (layout(location=2 component=0 ) smooth out 3-component vector of float)\r
+0:?     'q' (layout(location=10 component=3 ) smooth out 6-element array of float)\r
+0:?     'r' (layout(location=10 component=0 ) smooth out 6-element array of 3-component vector of float)\r
+0:?     's' (layout(location=15 component=3 ) smooth out float)\r
+0:?     't' (layout(location=10 component=1 ) smooth out float)\r
+0:?     'u' (layout(location=20 component=2 ) smooth out float)\r
+0:?     'v' (layout(location=20 component=0 ) smooth out float)\r
+0:?     'w' (layout(location=20 component=3 ) smooth out float)\r
+0:?     'x' (layout(location=20 component=1 ) smooth out 2-component vector of float)\r
+0:?     'y' (layout(location=30 component=3 ) smooth out 2-component vector of float)\r
+0:?     'z' (layout(location=31 component=1 ) smooth out 4-component vector of float)\r
+0:?     'ba' (layout(location=32 component=1 ) smooth out 4X4 matrix of float)\r
+0:?     'Ss' (layout(location=33 component=1 ) smooth out structure{int a})\r
+0:?     'bb' (layout(location=34 component=1 ) out block{out int a})\r
+0:?     'bc' (layout(location=63 component=1 ) smooth out float)\r
+0:?     'bd' (out block{layout(location=40 component=2 ) out float u, layout(location=40 component=0 ) out float v, layout(location=40 component=3 ) out float w, layout(location=40 component=1 ) out 2-component vector of float x, layout(location=41 component=3 ) out 2-component vector of float y, layout(location=42 component=1 ) out 4-component vector of float z, layout(location=42 component=1 ) out 4X4 matrix of float ba, layout(location=43 component=1 ) out structure{int a} Ss})\r
+0:?     'be' (layout(location=50 component=3 ) smooth out int)\r
+0:?     'bf' (layout(location=50 component=0 ) smooth out 3-component vector of float)\r
+0:?     'gl_VertexID' (gl_VertexId int)\r
+0:?     'gl_InstanceID' (gl_InstanceId int)\r
+\r
+\r
+Linked vertex stage:\r
+\r
+ERROR: Linking vertex stage: Missing entry point: Each stage requires one "void main()" entry point\r
+\r
+\r
index cc136af..9c0c1c5 100644 (file)
@@ -16,7 +16,7 @@ ERROR: 0:99: 'local_size_y' : there is no such layout identifier for this stage
 ERROR: 0:100: 'local_size_x' : there is no such layout identifier for this stage taking an assigned value \r
 ERROR: 0:102: 'color' : redefinition \r
 ERROR: 0:103: 'index' : there is no such layout identifier for this stage taking an assigned value \r
-ERROR: 0:104: 'location' : repeated use of location 3\r
+ERROR: 0:104: 'location' : overlapping use of location 3\r
 ERROR: 0:106: 'depth_greater' : unrecognized layout identifier, or qualifier requires assignemnt (e.g., binding = 4) \r
 ERROR: 0:112: 'depth_any' : unrecognized layout identifier, or qualifier requires assignemnt (e.g., binding = 4) \r
 ERROR: 0:115: 'depth_greater' : unrecognized layout identifier, or qualifier requires assignemnt (e.g., binding = 4) \r
index 1d3416d..c9ce162 100644 (file)
@@ -1,7 +1,7 @@
 specExamples.vert\r
 Warning, version 430 is not yet complete; some version-specific features are present, but many are missing.\r
 ERROR: 0:23: 'transforms' : redeclaration of array with size \r
-ERROR: 0:29: 's' : location qualifiers only appy to uniform, buffer, in, or out storage qualifiers \r
+ERROR: 0:29: 'location' : can only appy to uniform, buffer, in, or out storage qualifiers \r
 ERROR: 0:31: 'triangles' : unrecognized layout identifier, or qualifier requires assignemnt (e.g., binding = 4) \r
 ERROR: 0:31: 'invocations' : there is no such layout identifier for this stage taking an assigned value \r
 ERROR: 0:33: 'lines' : unrecognized layout identifier, or qualifier requires assignemnt (e.g., binding = 4) \r
@@ -17,15 +17,15 @@ ERROR: 0:47: 'stream' : there is no such layout identifier for this stage taking
 ERROR: 0:50: 'stream' : there is no such layout identifier for this stage taking an assigned value \r
 ERROR: 0:55: 'stream' : there is no such layout identifier for this stage taking an assigned value \r
 ERROR: 0:80: 's17' : redefinition \r
-ERROR: 0:85: 'offset' : there is no such layout identifier for this stage taking an assigned value \r
+ERROR: 0:85: 'uniform buffer-member offset' : not supported for this version or the enabled extensions \r
 ERROR: 0:85: 'binding' : requires block, or sampler/image, or atomic-counter type \r
 ERROR: 0:87: 'binding' : requires block, or sampler/image, or atomic-counter type \r
-ERROR: 0:89: 'offset' : there is no such layout identifier for this stage taking an assigned value \r
+ERROR: 0:89: 'uniform buffer-member offset' : not supported for this version or the enabled extensions \r
 WARNING: 0:89: 'layout' : useless application of layout qualifier \r
 ERROR: 0:91: 'bar' : redefinition \r
-ERROR: 0:92: 'offset' : there is no such layout identifier for this stage taking an assigned value \r
+ERROR: 0:92: 'uniform buffer-member offset' : not supported for this version or the enabled extensions \r
 ERROR: 0:92: 'bar' : redefinition \r
-ERROR: 0:94: 'offset' : there is no such layout identifier for this stage taking an assigned value \r
+ERROR: 0:94: 'uniform buffer-member offset' : not supported for this version or the enabled extensions \r
 ERROR: 0:94: 'a2' : redefinition \r
 ERROR: 0:95: 'binding' : requires block, or sampler/image, or atomic-counter type \r
 ERROR: 0:96: 'binding' : requires block, or sampler/image, or atomic-counter type \r
@@ -291,7 +291,7 @@ ERROR: node is still EOpNull!
 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__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 ) uniform int)\r
+0:?     'a2' (layout(binding=2 offset=4 ) uniform int)\r
 0:?     'bar' (layout(binding=2 ) uniform int)\r
 0:?     'b2' (layout(binding=2 ) uniform int)\r
 0:?     'c2' (layout(binding=3 ) uniform int)\r
index 06f8b57..6e686f3 100644 (file)
@@ -59,6 +59,8 @@ numeral.frag
 410.geom
 430.vert
 430.comp
+440.vert
+440.frag
 dce.frag
 ../../LunarGLASS/test/aggOps.frag
 ../../LunarGLASS/test/always-discard.frag
index 35e8a7e..83c1a8c 100644 (file)
--- a/Todo.txt
+++ b/Todo.txt
@@ -209,43 +209,39 @@ Shader Functionality to Implement/Finish
       - Arrays of arrays are now supported, as per the GL_ARB_arrays_of_arrays extension.
       - Compute shaders are now supported, as per the GL_ARB_compute_shader extension.
       - Added imageSize() built-ins to query the dimensions of an image.
-      - Define robust out-of-bounds access behavior when enabled, as per the GL_ARB_robust_buffer_access_behavior extension.
       - All choice of depth or stencil texturing, for a packed depth-stencil texture, as per the 
         GL_ARB_stencil_texturing extension.
       - Allow explicit locations/indexes to be assigned to uniform variables and subroutines, as per the 
         GL_ARB_explicit_uniform_location extension.
-      - Accept ES GLSL shader #version statements, which will request ES functionality for ES GLSL 
+      + Accept ES GLSL shader #version statements, which will request ES functionality for ES GLSL 
         versions 100 and 300, as per the GL_ARB_ES3_compatibility extension.
-      - Clarify and correct scoping rules to what would normally be expected and what was intended. 
+      + Clarify and correct scoping rules to what would normally be expected and what was intended. 
         (Function parameters and body nest inside global space. Loop variables and body nest inside 
         loop scope.)
-      - There are no digraphs (trigraphs were already disallowed).
-      - Remove the CPP difference that it is a compile-time error to use #if or #elif on expressions 
+      + There are no digraphs (trigraphs were already disallowed).
+      + Remove the CPP difference that it is a compile-time error to use #if or #elif on expressions 
         containing undefined macro names. This reverts back to following expected CPP behavior.
-      - Set both gl_MaxFragmentImageUniformsand gl_MaxCombinedImageUniforms to 8.
+      + Set both gl_MaxFragmentImageUniforms and gl_MaxCombinedImageUniforms to 8.
       - Clarify textureSize() for cube map arrays.
       - For layout qualifiers,
-            - make negative output locations a compile-time error, once integer expressions are allowed in layouts
+            + make negative output locations a compile-time error, once integer expressions are allowed in layouts
             - make indexes outside the range [0,1] a compile-time error.
       - Add textureQueryLevels() built-ins to query the number of mipmap levels, as per the 
         GL_ARB_texture_query_levels extension.
       + Make gl_Layer and gl_ViewportIndex also be inputs to the fragment shader, as per the 
         GL_ARB_fragment_layer_viewport extension.
-      - Add more examples and rules to be more specific about the required behavior of the precise 
-        qualifier.
       - Clarify fragment output variables cannot be double precision.
-      - Allow the new shared keyword to be in layout-qualifier-id, allowing backward compatibility 
+      + Allow the new shared keyword to be in layout-qualifier-id, allowing backward compatibility 
         with the shared identifier that was previously used.
       + Added overlooked texture function float textureOffset (sampler2DArrayShadow sampler, vec4 P, vec2 offset [, float bias] ).
       + Add missing type in grammar, ATOMIC_UINT, and missing qualifiers COHERENT, VOLATILE, RESTRICT, READONLY, and WRITEONLY.
-      - do version checking for the above
       + Add missing initializer lists to grammar.
     GLSL 4.4
       - Incorporate the ARB_enhanced_layouts extension, which adds
-        - compile-time constant expressions for layout qualifier integers
+        + compile-time constant expressions for layout qualifier integers
         - new offset and align layout qualifiers for control over buffer block layouts
-        - add location layout qualifier for input and output blocks and block members
-        - new componentlayout qualifier for finer-grained layout control of input and output variables and blocks
+        + add location layout qualifier for input and output blocks and block members
+        + new component layout qualifier for finer-grained layout control of input and output variables and blocks
         - new xfb_buffer, xfb_stride, and xfb_offsetlayout qualifiers to allow the shader to control 
           transform feedback buffering.
       + Bug 10530: To be consistent with ES, include sample types as valid in a precision statement. 
index 67ebfd5..8424126 100644 (file)
@@ -353,29 +353,55 @@ public:
     {
         layoutMatrix = ElmNone;
         layoutPacking = ElpNone;
+        layoutOffset = -1;
+        layoutAlign = -1;
+
         layoutLocation = layoutLocationEnd;
+        layoutComponent = layoutComponentEnd;
         layoutBinding = layoutBindingEnd;
         layoutStream = layoutStreamEnd;
+
+        layoutXfbBuffer = layoutXfbBufferEnd;
+        layoutXfbStride = layoutXfbStrideEnd;
+        layoutXfbOffset = layoutXfbOffsetEnd;
     }
     bool hasLayout() const
     {
-        return layoutMatrix != ElmNone ||
-               layoutPacking != ElpNone ||
+        return hasUniformLayout() || 
                hasLocation() ||
                hasBinding() ||
-               hasStream();
+               hasStream() ||
+               hasXfb();
+    }
+    TLayoutMatrix  layoutMatrix                     : 3;
+    TLayoutPacking layoutPacking                    : 4;
+    int layoutOffset;
+    int layoutAlign;
+                 unsigned int layoutLocation        : 7;
+    static const unsigned int layoutLocationEnd =  0x3F;
+                 unsigned int layoutComponent       : 3;
+    static const unsigned int layoutComponentEnd =    4;
+                 unsigned int layoutBinding         : 8;
+    static const unsigned int layoutBindingEnd =   0xFF;
+                 unsigned int layoutStream          : 8;
+    static const unsigned int layoutStreamEnd =    0xFF;    
+                 unsigned int layoutXfbBuffer       : 4;
+    static const unsigned int layoutXfbBufferEnd =  0xF;
+                 unsigned int layoutXfbStride       : 8;
+    static const unsigned int layoutXfbStrideEnd = 0xFF;
+                 unsigned int layoutXfbOffset       : 8;
+    static const unsigned int layoutXfbOffsetEnd = 0xFF;
+    bool hasUniformLayout() const
+    {
+        return layoutMatrix  != ElmNone ||
+               layoutPacking != ElpNone ||
+               layoutOffset  != -1 ||
+               layoutAlign   != -1;
     }
-    TLayoutMatrix  layoutMatrix       : 3;
-    TLayoutPacking layoutPacking      : 4;
-    unsigned int   layoutLocation : 7;  // ins/outs should have small numbers, buffer offsets could be large
-    static const unsigned int layoutLocationEnd = 0x3F;
-    unsigned int layoutBinding        : 8;
-    static const unsigned int layoutBindingEnd = 0xFF;
-    unsigned int layoutStream          : 8;
-    static const unsigned int layoutStreamEnd = 0xFF;
     bool hasLocation() const
     {
-        return layoutLocation != layoutLocationEnd;
+        return layoutLocation  != layoutLocationEnd ||
+               layoutComponent != layoutComponentEnd;
     }
     bool hasBinding() const
     {
@@ -385,6 +411,12 @@ public:
     {
         return layoutStream != layoutStreamEnd;
     }
+    bool hasXfb() const
+    {
+        return layoutXfbBuffer != layoutXfbBufferEnd ||
+               layoutXfbStride != layoutXfbStrideEnd ||
+               layoutXfbOffset != layoutXfbOffsetEnd;
+    }
     static const char* getLayoutPackingString(TLayoutPacking packing)
     {
         switch (packing) {
@@ -824,8 +856,11 @@ public:
 
         if (qualifier.hasLayout()) {
             p += snprintf(p, end - p, "layout(");
-            if (qualifier.hasLocation())
+            if (qualifier.hasLocation()) {
                 p += snprintf(p, end - p, "location=%d ", qualifier.layoutLocation);
+                if (qualifier.layoutComponent != qualifier.layoutComponentEnd)
+                    p += snprintf(p, end - p, "component=%d ", qualifier.layoutComponent);
+            }
             if (qualifier.hasBinding())
                 p += snprintf(p, end - p, "binding=%d ", qualifier.layoutBinding);
             if (qualifier.hasStream())
@@ -834,6 +869,17 @@ public:
                 p += snprintf(p, end - p, "%s ", TQualifier::getLayoutMatrixString(qualifier.layoutMatrix));
             if (qualifier.layoutPacking != ElpNone)
                 p += snprintf(p, end - p, "%s ", TQualifier::getLayoutPackingString(qualifier.layoutPacking));
+            if (qualifier.layoutOffset != -1)
+                p += snprintf(p, end - p, "offset=%d ", qualifier.layoutOffset);
+            if (qualifier.layoutAlign != -1)
+                p += snprintf(p, end - p, "align=%d ", qualifier.layoutAlign);
+
+            if (qualifier.layoutXfbBuffer != qualifier.layoutXfbBufferEnd)
+                p += snprintf(p, end - p, "xfb_buffer=%d ", qualifier.layoutXfbBuffer);
+            if (qualifier.layoutXfbOffset != qualifier.layoutXfbOffsetEnd)
+                p += snprintf(p, end - p, "xfb_offset=%d ", qualifier.layoutXfbOffset);
+            if (qualifier.layoutXfbStride != qualifier.layoutXfbStrideEnd)
+                p += snprintf(p, end - p, "xfb_stride=%d ", qualifier.layoutXfbStride);
             p += snprintf(p, end - p, ") ");
         }
 
index 90a7e27..828d576 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 "24674"\r
-#define GLSLANG_DATE     "2014/01/07 10:44:41"\r
+#define GLSLANG_REVISION "24675"\r
+#define GLSLANG_DATE     "2014/01/07 11:14:48"\r
index 12cfb59..632a17f 100644 (file)
@@ -101,6 +101,8 @@ TParseContext::TParseContext(TSymbolTable& symt, TIntermediate& interm, bool pb,
     globalBufferDefaults.layoutMatrix = ElmColumnMajor;
     globalBufferDefaults.layoutPacking = ElpShared;
 
+    // TODO: 4.4 enhanced layouts: defaults for xfb?
+
     globalInputDefaults.clear();
 
     globalOutputDefaults.clear();
@@ -2429,7 +2431,7 @@ void TParseContext::redeclareBuiltinBlock(TSourceLoc loc, TTypeList& newTypeList
     symbolTable.insert(*block);
 
     // Check for general layout qualifier errors
-    layoutTypeCheck(loc, *block);
+    layoutObjectCheck(loc, *block);
 
     // Tracking for implicit sizing of array
     if (isIoResizeArray(block->getType())) {
@@ -2829,7 +2831,20 @@ void TParseContext::setLayoutQualifier(TSourceLoc loc, TPublicType& publicType,
     }
 
     std::transform(id.begin(), id.end(), id.begin(), ::tolower);
-    if (id == "location") {
+    
+    if (id == "offset") {
+        const char* feature = "uniform buffer-member offset";
+        requireProfile(loc, ECoreProfile | ECompatibilityProfile, feature);
+        profileRequires(loc, ECoreProfile | ECompatibilityProfile, 440, GL_ARB_enhanced_layouts, feature);
+        publicType.qualifier.layoutOffset = value;
+        return;
+    } else if (id == "align") {
+        const char* feature = "uniform buffer-member align";
+        requireProfile(loc, ECoreProfile | ECompatibilityProfile, feature);
+        profileRequires(loc, ECoreProfile | ECompatibilityProfile, 440, GL_ARB_enhanced_layouts, feature);
+        publicType.qualifier.layoutAlign = value;
+        return;
+    } else if (id == "location") {
         requireProfile(loc, EEsProfile | ECoreProfile | ECompatibilityProfile, "location");
         profileRequires(loc, ECoreProfile | ECompatibilityProfile, 330, 0, "location");
         if ((unsigned int)value >= TQualifier::layoutLocationEnd)
@@ -2837,8 +2852,7 @@ void TParseContext::setLayoutQualifier(TSourceLoc loc, TPublicType& publicType,
         else
             publicType.qualifier.layoutLocation = value;
         return;
-    }
-    if (id == "binding") {
+    } else if (id == "binding") {
         requireProfile(loc, ECoreProfile | ECompatibilityProfile, "binding");
         profileRequires(loc, ECoreProfile | ECompatibilityProfile, 420, GL_ARB_shading_language_420pack, "binding");
         if ((unsigned int)value >= TQualifier::layoutBindingEnd)
@@ -2846,7 +2860,37 @@ void TParseContext::setLayoutQualifier(TSourceLoc loc, TPublicType& publicType,
         else
             publicType.qualifier.layoutBinding = value;
         return;
+    } else if (id == "component") {
+        requireProfile(loc, ECoreProfile | ECompatibilityProfile, "component");
+        profileRequires(loc, ECoreProfile | ECompatibilityProfile, 440, GL_ARB_enhanced_layouts, "component");
+        if ((unsigned)value >= TQualifier::layoutComponentEnd)
+            error(loc, "component is too large", id.c_str(), "");
+        else
+            publicType.qualifier.layoutComponent = value;
+        return;
+    } else if (id.compare(0, 4, "xfb_") == 0) {
+        const char* feature = "transform feedback qualifier";
+        requireStage(loc, (EShLanguageMask)(EShLangVertexMask | EShLangGeometryMask | EShLangTessControlMask | EShLangTessEvaluationMask), feature);
+        requireProfile(loc, ECoreProfile | ECompatibilityProfile, feature);
+        profileRequires(loc, ECoreProfile | ECompatibilityProfile, 440, GL_ARB_enhanced_layouts, feature);
+        if (id == "xfb_buffer") {
+            if (value >= TQualifier::layoutXfbBufferEnd)   // TODO: 4.4 enhanced layouts: also check against gl_MaxTransformFeedbackBuffers
+                error(loc, "buffer is too large", id.c_str(), "");
+            else
+                publicType.qualifier.layoutXfbBuffer = value;
+        } else if (id == "xfb_offset") {
+            if (value >= TQualifier::layoutXfbOffsetEnd)   // TODO: 4.4 enhanced layouts: also check against gl_MaxTransformFeedbackInterleavedComponents
+                error(loc, "offset is too large", id.c_str(), "");
+            else
+                publicType.qualifier.layoutXfbOffset = value;
+        } else if (id == "xfb_stride") {
+            if (value >= TQualifier::layoutXfbStrideEnd)    // TODO: 4.4 enhanced layouts: also check against gl_MaxTransformFeedbackInterleavedComponents
+                error(loc, "stride is too large", id.c_str(), "");
+            else
+                publicType.qualifier.layoutXfbStride = value;
+        }
     }
+
     switch (language) {
     case EShLangVertex:
         break;
@@ -2900,51 +2944,122 @@ void TParseContext::mergeObjectLayoutQualifiers(TSourceLoc loc, TQualifier& dst,
     if (src.layoutPacking != ElpNone)
         dst.layoutPacking = src.layoutPacking;
 
+    if (src.hasStream())
+        dst.layoutStream = src.layoutStream;
+
+    if (src.layoutXfbBuffer != TQualifier::layoutXfbBufferEnd)
+        dst.layoutXfbBuffer = src.layoutXfbBuffer;
+
     if (! inheritOnly) {
-        if (src.hasLocation())
+        if (src.layoutLocation != TQualifier::layoutLocationEnd)
             dst.layoutLocation = src.layoutLocation;
-        if (src.hasBinding())
+        if (src.layoutComponent != TQualifier::layoutComponentEnd)
+            dst.layoutComponent = src.layoutComponent;
+        
+        if (src.layoutOffset != -1)
+            dst.layoutOffset = src.layoutOffset;
+        if (src.layoutAlign != -1)
+            dst.layoutAlign = src.layoutAlign;
+
+        if (src.layoutBinding != TQualifier::layoutBindingEnd)
             dst.layoutBinding = src.layoutBinding;
-    }
 
-    if (src.hasStream())
-        dst.layoutStream = src.layoutStream;
+        if (src.layoutXfbStride != TQualifier::layoutXfbStrideEnd)
+            dst.layoutXfbStride = src.layoutXfbStride;
+        if (src.layoutXfbOffset != TQualifier::layoutXfbOffsetEnd)
+            dst.layoutXfbOffset = src.layoutXfbOffset;
+    }
 }
 
 // Do error layout error checking given a full variable/block declaration.
-void TParseContext::layoutTypeCheck(TSourceLoc loc, const TSymbol& symbol)
+void TParseContext::layoutObjectCheck(TSourceLoc loc, const TSymbol& symbol)
 {
     const TType& type = symbol.getType();
     const TQualifier& qualifier = type.getQualifier();
 
-    // first, qualifier only error checking
+    // first, cross check WRT to just the type
+    layoutTypeCheck(loc, type);
+
+    // now, any remaining error checking based on the object itself
+
+    if (qualifier.hasLocation()) {
+        switch (qualifier.storage) {
+        case EvqUniform:
+        case EvqBuffer:
+            if (symbol.getAsVariable() == 0)
+                error(loc, "can only be used on variable declaration", "location", "");
+            break;
+        default:
+            break;
+        }
+    }
+
+    // Check packing and matrix 
+    // TODO: 4.4 enhanced layouts: generalize to include offset/align
+    if (qualifier.layoutMatrix || qualifier.layoutPacking) {
+        switch (qualifier.storage) {
+        case EvqBuffer:
+        case EvqUniform:
+            if (type.getBasicType() != EbtBlock) {
+                if (qualifier.layoutMatrix != ElmNone)
+                    error(loc, "cannot specify matrix layout on a variable declaration", "layout", "");
+                if (qualifier.layoutPacking != ElpNone)
+                    error(loc, "cannot specify packing on a variable declaration", "layout", "");
+            }
+            break;
+        default:
+            if (type.getBasicType() != EbtBlock && symbol.getAsVariable()) {
+                if (qualifier.layoutMatrix != ElmNone ||
+                    qualifier.layoutPacking != ElpNone)
+                    error(loc, "qualifiers for matrix layout and block packing only apply to uniform or buffer blocks", "layout", "");
+            }
+        }
+    }
+}
+
+// Do error layout error checking with respect to a type.
+void TParseContext::layoutTypeCheck(TSourceLoc loc, const TType& type)
+{
+    const TQualifier& qualifier = type.getQualifier();
+
+    // first, intra layout qualifier-only error checking
     layoutQualifierCheck(loc, qualifier);
 
     // now, error checking combining type and qualifier
 
     if (qualifier.hasLocation()) {
+        if (qualifier.layoutComponent != TQualifier::layoutComponentEnd) {
+            // "It is a compile-time error if this sequence of components gets larger than 3."
+            if (qualifier.layoutComponent + type.getVectorSize() > 4)
+                error(loc, "type overflows the available 4 components", "component", "");
+
+            // "It is a compile-time error to apply the component qualifier to a matrix, a structure, a block, or an array containing any of these."
+            if (type.isMatrix() || type.getBasicType() == EbtBlock || type.getBasicType() == EbtStruct)
+                error(loc, "cannot apply to a matrix, structure, or block", "component", "");
+        }
+
         switch (qualifier.storage) {
         case EvqVaryingIn:
         case EvqVaryingOut:
             if (type.getBasicType() == EbtBlock)
-                profileRequires(loc, ECoreProfile | ECompatibilityProfile, 440, 0 /* TODO ARB_enhanced_layouts*/, "location qualifier on in/out block");
+                profileRequires(loc, ECoreProfile | ECompatibilityProfile, 440, GL_ARB_enhanced_layouts, "location qualifier on in/out block");
             break;
         case EvqUniform:
         case EvqBuffer:
-        {
-            const char* feature = "location qualifier on uniform or buffer";
-            if (symbol.getAsVariable() == 0)
-                error(loc, "can only be used on variable declaration", feature, "");
             break;
-        }
         default:
-            error(loc, "location qualifiers only appy to uniform, buffer, in, or out storage qualifiers", symbol.getName().c_str(), "");
+            error(loc, "can only appy to uniform, buffer, in, or out storage qualifiers", "location", "");
             break;
         }
 
-        int repeated = intermediate.addUsedLocation(qualifier, type);
-        if (repeated >= 0)
-            error(loc, "repeated use of location", "location", "%d", repeated);
+        bool typeCollision;
+        int repeated = intermediate.addUsedLocation(qualifier, type, typeCollision);
+        if (repeated >= 0 && ! typeCollision)
+            error(loc, "overlapping use of location", "location", "%d", repeated);
+        // "fragment-shader outputs ... if two variables are placed within the same
+        // location, they must have the same underlying type (floating-point or integer)"
+        if (typeCollision && language == EShLangFragment && qualifier.isPipeOutput())
+            error(loc, "fragment outputs sharing the same location must be the same basic type", "location", "%d", repeated);
     }
 
     if (qualifier.hasBinding()) {
@@ -2967,34 +3082,22 @@ void TParseContext::layoutTypeCheck(TSourceLoc loc, const TSymbol& symbol)
                 error(loc, "sampler binding not less than gl_MaxCombinedTextureImageUnits", "binding", type.isArray() ? "(using array)" : "");
         }
     }
-
-    // Check packing and matrix
-    if (qualifier.layoutMatrix || qualifier.layoutPacking) {
-        switch (qualifier.storage) {
-        case EvqBuffer:
-        case EvqUniform:
-            if (symbol.getType().getBasicType() != EbtBlock) {
-                if (qualifier.layoutMatrix != ElmNone)
-                    error(loc, "cannot specify matrix layout on a variable declaration", symbol.getName().c_str(), "");
-                if (qualifier.layoutPacking != ElpNone)
-                    error(loc, "cannot specify packing on a variable declaration", symbol.getName().c_str(), "");
-            }
-            break;
-        default:
-            if (symbol.getType().getBasicType() != EbtBlock && symbol.getAsVariable()) {
-                if (qualifier.layoutMatrix != ElmNone ||
-                    qualifier.layoutPacking != ElpNone)
-                    error(loc, "layout qualifiers for matrix layout and packing only apply to uniform or buffer blocks", symbol.getName().c_str(), "");
-            }
-        }
-    }
 }
 
 // Do layout error checking that can be done within a qualifier proper, not needing to know
 // if there are blocks, atomic counters, variables, etc.
 void TParseContext::layoutQualifierCheck(TSourceLoc loc, const TQualifier& qualifier)
 {
+    // "It is a compile-time error to use *component* without also specifying the location qualifier (order does not matter)."
+    if (qualifier.layoutComponent != TQualifier::layoutComponentEnd && qualifier.layoutLocation == TQualifier::layoutLocationEnd)
+        error(loc, "must specify 'location' to use 'component'", "component", "");
+
     if (qualifier.hasLocation()) {
+
+        // "As with input layout qualifiers, all shaders except compute shaders 
+        // allow *location* layout qualifiers on output variable declarations, 
+        // output block declarations, and output block member declarations."
+
         switch (qualifier.storage) {
         case EvqVaryingIn:
         {
@@ -3257,7 +3360,7 @@ TIntermNode* TParseContext::declareVariable(TSourceLoc loc, TString& identifier,
     }
 
     // look for errors/adjustments in layout qualifier use
-    layoutTypeCheck(loc, *symbol);
+    layoutObjectCheck(loc, *symbol);
 
     // see if it's a linker-level object to track
     if (newDeclaration && symbolTable.atGlobalLevel())
@@ -3710,7 +3813,10 @@ void TParseContext::declareBlock(TSourceLoc loc, TTypeList& typeList, const TStr
     }
 
     // fix and check for member layout qualifiers
+    // TODO: 4.4 enhanced layouts: generalize to include offset/align
     mergeObjectLayoutQualifiers(loc, defaultQualification, currentBlockQualifier, true);
+    bool memberWithLocation = false;
+    bool memberWithoutLocation = false;
     for (unsigned int member = 0; member < typeList.size(); ++member) {
         TQualifier& memberQualifier = typeList[member].type->getQualifier();
         TSourceLoc memberLoc = typeList[member].loc;
@@ -3720,10 +3826,28 @@ void TParseContext::declareBlock(TSourceLoc loc, TTypeList& typeList, const TStr
         }
         if (memberQualifier.layoutPacking != ElpNone)
             error(memberLoc, "member of block cannot have a packing layout qualifier", typeList[member].type->getFieldName().c_str(), "");
+        if (memberQualifier.hasLocation()) {
+            const char* feature = "location on block member";
+            switch (currentBlockQualifier.storage) {
+            case EvqVaryingIn:
+            case EvqVaryingOut:
+                requireProfile(memberLoc, ECoreProfile | ECompatibilityProfile, feature);
+                profileRequires(memberLoc, ECoreProfile | ECompatibilityProfile, 440, GL_ARB_enhanced_layouts, feature);
+                memberWithLocation = true;
+                break;
+            default:
+                error(memberLoc, "can only use in an in/out block", feature, "");
+                break;
+            }
+        } else
+            memberWithoutLocation = true;
         TQualifier newMemberQualification = defaultQualification;
         mergeQualifiers(memberLoc, newMemberQualification, memberQualifier, false);
         memberQualifier = newMemberQualification;
     }
+    fixBlockLocations(loc, currentBlockQualifier, typeList, memberWithLocation, memberWithoutLocation);
+    for (unsigned int member = 0; member < typeList.size(); ++member)
+        layoutTypeCheck(typeList[member].loc, *typeList[member].type);
 
     // reverse merge, so that currentBlockQualifier now has all layout information
     // (can't use defaultQualification directly, it's missing other non-layout-default-class qualifiers)
@@ -3783,7 +3907,7 @@ void TParseContext::declareBlock(TSourceLoc loc, TTypeList& typeList, const TStr
     }
 
     // Check for general layout qualifier errors
-    layoutTypeCheck(loc, variable);
+    layoutObjectCheck(loc, variable);
 
     if (isIoResizeArray(blockType)) {
         ioArraySymbolResizeList.push_back(&variable);
@@ -3795,6 +3919,46 @@ void TParseContext::declareBlock(TSourceLoc loc, TTypeList& typeList, const TStr
     intermediate.addSymbolLinkageNode(linkage, variable);
 }
 
+//
+// "For a block, this process applies to the entire block, or until the first member 
+// is reached that has a location layout qualifier. When a block member is declared with a location 
+// qualifier, its location comes from that qualifier: The member's location qualifier overrides the block-level
+// declaration. Subsequent members are again assigned consecutive locations, based on the newest location, 
+// until the next member declared with a location qualifier. The values used for locations do not have to be 
+// declared in increasing order."
+void TParseContext::fixBlockLocations(TSourceLoc loc, TQualifier& qualifier, TTypeList& typeList, bool memberWithLocation, bool memberWithoutLocation)
+{
+    // "If a block has no block-level location layout qualifier, it is required that either all or none of its members 
+    // have a location layout qualifier, or a compile-time error results."
+    if (! qualifier.hasLocation() && memberWithLocation && memberWithoutLocation)
+        error(loc, "either the block needs a location, or all members need a location, or no members have a location", "location", "");
+    else {
+        if (memberWithLocation) {
+            // remove any block-level location and make it per *every* member
+            int nextLocation;  // by the rule above, initial value is not relevant
+            if (qualifier.hasLocation()) {
+                nextLocation = qualifier.layoutLocation;
+                qualifier.layoutLocation = TQualifier::layoutLocationEnd;
+                if (qualifier.layoutComponent != TQualifier::layoutComponentEnd) {
+                    // "It is a compile-time error to apply the *component* qualifier to a ... block"
+                    error(loc, "cannot apply to a block", "component", "");
+                }
+            }
+            for (unsigned int member = 0; member < typeList.size(); ++member) {
+                TQualifier& memberQualifier = typeList[member].type->getQualifier();
+                TSourceLoc memberLoc = typeList[member].loc;
+                if (! memberQualifier.hasLocation()) {
+                    if (nextLocation >= TQualifier::layoutLocationEnd)
+                        error(memberLoc, "location is too large", "location", "");
+                    memberQualifier.layoutLocation = nextLocation;
+                    memberQualifier.layoutComponent = 0;
+                }
+                nextLocation = memberQualifier.layoutLocation + intermediate.computeTypeLocationSize(*typeList[member].type);
+            }
+        }
+    }
+}
+
 // For an identifier that is already declared, add more qualification to it.
 void TParseContext::addQualifierToExisting(TSourceLoc loc, TQualifier qualifier, const TString& identifier)
 {
@@ -3941,6 +4105,7 @@ void TParseContext::updateStandaloneQualifierDefaults(TSourceLoc loc, const TPub
 
     layoutQualifierCheck(loc, qualifier);
 
+    // TODO: 4.4 enhanced layouts:  generalize to include all new ones
     switch (qualifier.storage) {
     case EvqUniform:
         if (qualifier.layoutMatrix != ElmNone)
index a2dcc60..7a7763e 100644 (file)
@@ -150,7 +150,8 @@ public:
     void setLayoutQualifier(TSourceLoc, TPublicType&, TString&);
     void setLayoutQualifier(TSourceLoc, TPublicType&, TString&, const TIntermTyped*);
     void mergeObjectLayoutQualifiers(TSourceLoc, TQualifier& dest, const TQualifier& src, bool inheritOnly);
-    void layoutTypeCheck(TSourceLoc, const TSymbol&);
+    void layoutObjectCheck(TSourceLoc, const TSymbol&);
+    void layoutTypeCheck(TSourceLoc, const TType&);
     void layoutQualifierCheck(TSourceLoc, const TQualifier&);
     void checkNoShaderLayouts(TSourceLoc, const TShaderQualifiers&);
 
@@ -163,6 +164,7 @@ public:
     TIntermTyped* constructStruct(TIntermNode*, const TType&, int, TSourceLoc);
     TIntermTyped* constructBuiltIn(const TType&, TOperator, TIntermNode*, TSourceLoc, bool subset);
     void declareBlock(TSourceLoc, TTypeList& typeList, const TString* instanceName = 0, TArraySizes* arraySizes = 0);
+    void fixBlockLocations(TSourceLoc, TQualifier&, TTypeList&, bool memberWithLocation, bool memberWithoutLocation);
     void addQualifierToExisting(TSourceLoc, TQualifier, const TString& identifier);
     void addQualifierToExisting(TSourceLoc, TQualifier, TIdentifierList&);
     void invariantCheck(TSourceLoc, const TType&, const TString& identifier);
index e62f84f..0b9b50b 100644 (file)
@@ -252,7 +252,8 @@ void TIntermediate::mergeErrorCheck(TInfoSink& infoSink, const TIntermSymbol& sy
         writeTypeComparison = true;\r
     }\r
 \r
-    // Layouts...\r
+    // Layouts... \r
+    // TODO: 4.4 enhanced layouts: generalize to include offset/align\r
     if (symbol.getQualifier().layoutMatrix   != unitSymbol.getQualifier().layoutMatrix ||\r
         symbol.getQualifier().layoutPacking  != unitSymbol.getQualifier().layoutPacking ||\r
         symbol.getQualifier().layoutLocation != unitSymbol.getQualifier().layoutLocation ||\r
@@ -481,8 +482,14 @@ bool TIntermediate::userOutputUsed() const
 // as the accumulation is done.\r
 //\r
 // Returns < 0 if no collision, >= 0 if collision and the value returned is a colliding value.\r
-int TIntermediate::addUsedLocation(const TQualifier& qualifier, const TType& type)\r
+//\r
+// typeCollision is set to true if there is no direct collision, but the types in the same location\r
+// are different.\r
+//\r
+int TIntermediate::addUsedLocation(const TQualifier& qualifier, const TType& type, bool& typeCollision)\r
 {\r
+    typeCollision = false;\r
+\r
     int set;\r
     if (qualifier.isPipeInput())\r
         set = 0;\r
@@ -510,20 +517,34 @@ int TIntermediate::addUsedLocation(const TQualifier& qualifier, const TType& typ
             size = computeTypeLocationSize(type);\r
     }\r
 \r
-    TRange range = { qualifier.layoutLocation, qualifier.layoutLocation + size - 1 };\r
+    TRange locationRange = { qualifier.layoutLocation, qualifier.layoutLocation + size - 1 };\r
+    TRange componentRange = { 0, 3 };\r
+    if (qualifier.layoutComponent != TQualifier::layoutComponentEnd) {\r
+        componentRange.start = qualifier.layoutComponent;\r
+        componentRange.last = componentRange.start + type.getVectorSize() - 1;\r
+    }\r
 \r
     // check for collisions, except for vertex inputs on desktop\r
     if (! (profile != EEsProfile && language == EShLangVertex && qualifier.isPipeInput())) {\r
-        for (size_t r = 0; r < usedLocations[set].size(); ++r) {\r
-            if (range.last  >= usedLocations[set][r].start &&\r
-                range.start <= usedLocations[set][r].last) {\r
+        for (size_t r = 0; r < usedIo[set].size(); ++r) {\r
+            if (locationRange.last  >= usedIo[set][r].location.start &&\r
+                locationRange.start <= usedIo[set][r].location.last &&\r
+                componentRange.last  >= usedIo[set][r].component.start &&\r
+                componentRange.start <= usedIo[set][r].component.last) {\r
                 // there is a collision; pick one\r
-                return std::max(range.start, usedLocations[set][r].start);\r
+                return std::max(locationRange.start, usedIo[set][r].location.start);\r
+            } else if (locationRange.last  >= usedIo[set][r].location.start &&\r
+                       locationRange.start <= usedIo[set][r].location.last &&\r
+                       type.getBasicType() != usedIo[set][r].basicType) {\r
+                typeCollision = true;\r
+                return std::max(locationRange.start, usedIo[set][r].location.start);\r
             }\r
         }\r
     }\r
 \r
-    usedLocations[set].push_back(range);\r
+    TIoRange range = { locationRange, componentRange, type.getBasicType() };\r
+\r
+    usedIo[set].push_back(range);\r
 \r
     return -1;\r
 }\r
@@ -546,7 +567,6 @@ int TIntermediate::computeTypeLocationSize(const TType& type)
     // "The locations consumed by block and structure members are determined by applying the rules above \r
     // recursively..."    \r
     if (type.isStruct()) {\r
-        // TODO: 440 functionality: input/output block locations when members also have locations\r
         int size = 0;\r
         for (size_t member = 0; member < type.getStruct()->size(); ++member) {\r
             TType memberType(type, member);\r
index eb85daf..2ffda5d 100644 (file)
@@ -172,7 +172,8 @@ public:
     void addIoAccessed(const TString& name) { ioAccessed.insert(name); }
     bool inIoAccessed(const TString& name) const { return ioAccessed.find(name) != ioAccessed.end(); }
 
-    int addUsedLocation(const TQualifier&, const TType&);
+    int addUsedLocation(const TQualifier&, const TType&, bool& typeCollision);
+    int computeTypeLocationSize(const TType&);
 
 protected:
     void error(TInfoSink& infoSink, const char*);
@@ -183,7 +184,6 @@ protected:
     void inOutLocationCheck(TInfoSink&);
     TIntermSequence& findLinkerObjects() const;
     bool userOutputUsed() const;
-    int computeTypeLocationSize(const TType&);
 
 protected:
     const EShLanguage language;
@@ -217,11 +217,19 @@ protected:
 
     std::set<TString> ioAccessed;  // set of names of statically read/written I/O that might need extra checking
 
+    // A location range is a 2-D rectangle; the set of (location, component) pairs all lying
+    // both within the location range and the component range.
+    // The following are entirely encapsulated by addUsedLocation().
     struct TRange {
         int start;
         int last;
     };
-    std::vector<TRange> usedLocations[3];    // sets of used locations, one for each of in, out, and uniform
+    struct TIoRange {
+        TRange location;
+        TRange component;
+        TBasicType basicType;
+    };
+    std::vector<TIoRange> usedIo[3];    // sets of used locations, one for each of in, out, and uniform
 
 private:
     void operator=(TIntermediate&); // prevent assignments