ParseHelper: assign global XfbBuffer to a block missing it
If a block has assigned a XfbOffset it is assumed that it would
inherit the current global XfbBuffer. This commit fixes two use cases:
1) Getting the members of a Block with a XfbOffset to be assigned an
offset, as explained on GLSL 4.60 spec, section "4.4.2 Output
Layout Qualifiers", subsection "Transform Feedback Layout
Qualifiers".
2) Compute properly an error on overlapping ranges if a block is
assigned a XfbOffset and one of it members is assigned a explicit
one. This gets working because when the members of a block get
assigned a Offset/Buffer at fixBlockXfbOffsets, then the block is
deassigned the Offsets, so ranges are computed only with the block
members.
BTW, this is already done when redeclaring block builtins.
Fixes #1535
diff --git a/Test/baseResults/spv.xfbOffsetOnBlockMembersAssignment.vert.out b/Test/baseResults/spv.xfbOffsetOnBlockMembersAssignment.vert.out
new file mode 100644
index 0000000..066aa3a
--- /dev/null
+++ b/Test/baseResults/spv.xfbOffsetOnBlockMembersAssignment.vert.out
@@ -0,0 +1,76 @@
+spv.xfbOffsetOnBlockMembersAssignment.vert
+// Module Version 10000
+// Generated by (magic number): 80007
+// Id's are bound by 33
+
+ Capability Shader
+ Capability TransformFeedback
+ 1: ExtInstImport "GLSL.std.450"
+ MemoryModel Logical GLSL450
+ EntryPoint Vertex 4 "main" 10 27 31 32
+ ExecutionMode 4 Xfb
+ Source GLSL 450
+ Name 4 "main"
+ Name 8 "block2"
+ MemberName 8(block2) 0 "y1_out"
+ MemberName 8(block2) 1 "y2_out"
+ Name 10 ""
+ Name 25 "gl_PerVertex"
+ MemberName 25(gl_PerVertex) 0 "gl_Position"
+ MemberName 25(gl_PerVertex) 1 "gl_PointSize"
+ MemberName 25(gl_PerVertex) 2 "gl_ClipDistance"
+ MemberName 25(gl_PerVertex) 3 "gl_CullDistance"
+ Name 27 ""
+ Name 31 "gl_VertexID"
+ Name 32 "gl_InstanceID"
+ MemberDecorate 8(block2) 0 Offset 0
+ MemberDecorate 8(block2) 1 Offset 4
+ Decorate 8(block2) Block
+ Decorate 10 Location 5
+ Decorate 10 XfbBuffer 2
+ Decorate 10 XfbStride 20
+ MemberDecorate 25(gl_PerVertex) 0 BuiltIn Position
+ MemberDecorate 25(gl_PerVertex) 1 BuiltIn PointSize
+ MemberDecorate 25(gl_PerVertex) 2 BuiltIn ClipDistance
+ MemberDecorate 25(gl_PerVertex) 3 BuiltIn CullDistance
+ Decorate 25(gl_PerVertex) Block
+ Decorate 27 XfbBuffer 0
+ Decorate 27 XfbStride 0
+ Decorate 31(gl_VertexID) BuiltIn VertexId
+ Decorate 32(gl_InstanceID) BuiltIn InstanceId
+ 2: TypeVoid
+ 3: TypeFunction 2
+ 6: TypeFloat 32
+ 7: TypeVector 6(float) 4
+ 8(block2): TypeStruct 6(float) 7(fvec4)
+ 9: TypePointer Output 8(block2)
+ 10: 9(ptr) Variable Output
+ 11: TypeInt 32 1
+ 12: 11(int) Constant 0
+ 13: 6(float) Constant 1088421888
+ 14: TypePointer Output 6(float)
+ 16: 11(int) Constant 1
+ 17: 6(float) Constant 1065353216
+ 18: 6(float) Constant 0
+ 19: 7(fvec4) ConstantComposite 17 18 18 17
+ 20: TypePointer Output 7(fvec4)
+ 22: TypeInt 32 0
+ 23: 22(int) Constant 1
+ 24: TypeArray 6(float) 23
+25(gl_PerVertex): TypeStruct 7(fvec4) 6(float) 24 24
+ 26: TypePointer Output 25(gl_PerVertex)
+ 27: 26(ptr) Variable Output
+ 28: 7(fvec4) ConstantComposite 18 18 18 18
+ 30: TypePointer Input 11(int)
+ 31(gl_VertexID): 30(ptr) Variable Input
+32(gl_InstanceID): 30(ptr) Variable Input
+ 4(main): 2 Function None 3
+ 5: Label
+ 15: 14(ptr) AccessChain 10 12
+ Store 15 13
+ 21: 20(ptr) AccessChain 10 16
+ Store 21 19
+ 29: 20(ptr) AccessChain 27 12
+ Store 29 28
+ Return
+ FunctionEnd
diff --git a/Test/baseResults/spv.xfbOverlapOffsetCheckWithBlockAndMember.vert.out b/Test/baseResults/spv.xfbOverlapOffsetCheckWithBlockAndMember.vert.out
new file mode 100644
index 0000000..ebc4962
--- /dev/null
+++ b/Test/baseResults/spv.xfbOverlapOffsetCheckWithBlockAndMember.vert.out
@@ -0,0 +1,88 @@
+spv.xfbOverlapOffsetCheckWithBlockAndMember.vert
+// Module Version 10000
+// Generated by (magic number): 80007
+// Id's are bound by 39
+
+ Capability Shader
+ Capability TransformFeedback
+ 1: ExtInstImport "GLSL.std.450"
+ MemoryModel Logical GLSL450
+ EntryPoint Vertex 4 "main" 10 33 37 38
+ ExecutionMode 4 Xfb
+ Source GLSL 450
+ Name 4 "main"
+ Name 8 "block2"
+ MemberName 8(block2) 0 "v"
+ MemberName 8(block2) 1 "u"
+ MemberName 8(block2) 2 "w"
+ MemberName 8(block2) 3 "x"
+ Name 10 ""
+ Name 31 "gl_PerVertex"
+ MemberName 31(gl_PerVertex) 0 "gl_Position"
+ MemberName 31(gl_PerVertex) 1 "gl_PointSize"
+ MemberName 31(gl_PerVertex) 2 "gl_ClipDistance"
+ MemberName 31(gl_PerVertex) 3 "gl_CullDistance"
+ Name 33 ""
+ Name 37 "gl_VertexID"
+ Name 38 "gl_InstanceID"
+ MemberDecorate 8(block2) 0 Offset 12
+ MemberDecorate 8(block2) 1 Offset 28
+ MemberDecorate 8(block2) 2 Offset 40
+ MemberDecorate 8(block2) 3 Offset 56
+ Decorate 8(block2) Block
+ Decorate 10 Location 5
+ Decorate 10 XfbBuffer 3
+ Decorate 10 XfbStride 72
+ MemberDecorate 31(gl_PerVertex) 0 BuiltIn Position
+ MemberDecorate 31(gl_PerVertex) 1 BuiltIn PointSize
+ MemberDecorate 31(gl_PerVertex) 2 BuiltIn ClipDistance
+ MemberDecorate 31(gl_PerVertex) 3 BuiltIn CullDistance
+ Decorate 31(gl_PerVertex) Block
+ Decorate 33 XfbBuffer 0
+ Decorate 33 XfbStride 0
+ Decorate 37(gl_VertexID) BuiltIn VertexId
+ Decorate 38(gl_InstanceID) BuiltIn InstanceId
+ 2: TypeVoid
+ 3: TypeFunction 2
+ 6: TypeFloat 32
+ 7: TypeVector 6(float) 4
+ 8(block2): TypeStruct 7(fvec4) 6(float) 7(fvec4) 7(fvec4)
+ 9: TypePointer Output 8(block2)
+ 10: 9(ptr) Variable Output
+ 11: TypeInt 32 1
+ 12: 11(int) Constant 0
+ 13: 6(float) Constant 1065353216
+ 14: 6(float) Constant 0
+ 15: 7(fvec4) ConstantComposite 13 14 13 14
+ 16: TypePointer Output 7(fvec4)
+ 18: 11(int) Constant 1
+ 19: 6(float) Constant 1084227584
+ 20: TypePointer Output 6(float)
+ 22: 11(int) Constant 2
+ 23: 7(fvec4) ConstantComposite 13 14 14 13
+ 25: 11(int) Constant 3
+ 26: 7(fvec4) ConstantComposite 19 14 14 14
+ 28: TypeInt 32 0
+ 29: 28(int) Constant 1
+ 30: TypeArray 6(float) 29
+31(gl_PerVertex): TypeStruct 7(fvec4) 6(float) 30 30
+ 32: TypePointer Output 31(gl_PerVertex)
+ 33: 32(ptr) Variable Output
+ 34: 7(fvec4) ConstantComposite 14 14 14 14
+ 36: TypePointer Input 11(int)
+ 37(gl_VertexID): 36(ptr) Variable Input
+38(gl_InstanceID): 36(ptr) Variable Input
+ 4(main): 2 Function None 3
+ 5: Label
+ 17: 16(ptr) AccessChain 10 12
+ Store 17 15
+ 21: 20(ptr) AccessChain 10 18
+ Store 21 19
+ 24: 16(ptr) AccessChain 10 22
+ Store 24 23
+ 27: 16(ptr) AccessChain 10 25
+ Store 27 26
+ 35: 16(ptr) AccessChain 33 12
+ Store 35 34
+ Return
+ FunctionEnd
diff --git a/Test/spv.xfbOffsetOnBlockMembersAssignment.vert b/Test/spv.xfbOffsetOnBlockMembersAssignment.vert
new file mode 100644
index 0000000..40943f7
--- /dev/null
+++ b/Test/spv.xfbOffsetOnBlockMembersAssignment.vert
@@ -0,0 +1,13 @@
+#version 450
+
+layout(xfb_buffer=2) out;
+layout(location=5, xfb_offset=0) out block2 {
+ float y1_out;
+ vec4 y2_out;
+};
+
+void main() {
+ y1_out = 7.0;
+ y2_out = vec4(1.0, 0.0, 0.0, 1.0);
+ gl_Position = vec4(0.0);
+}
diff --git a/Test/spv.xfbOverlapOffsetCheckWithBlockAndMember.vert b/Test/spv.xfbOverlapOffsetCheckWithBlockAndMember.vert
new file mode 100644
index 0000000..3f493dc
--- /dev/null
+++ b/Test/spv.xfbOverlapOffsetCheckWithBlockAndMember.vert
@@ -0,0 +1,19 @@
+#version 450
+
+/* block definition from GLSL spec 4.60, section 4.4.2, Output Layout Qualifiers */
+
+layout(location=5, xfb_buffer = 3, xfb_offset = 12) out block2 {
+ vec4 v; // v will be written to byte offsets 12 through 27 of buffer
+ float u; // u will be written to offset 28
+ layout(xfb_offset = 40) vec4 w;
+ vec4 x; // x will be written to offset 56, the next available offset
+};
+
+void main() {
+ v = vec4(1.0, 0.0, 1.0, 0.0);
+ u = 5.0;
+ w = vec4(1.0, 0.0, 0.0, 1.0);
+ x = vec4(5.0, 0.0, 0.0, 0.0);
+
+ gl_Position = vec4(0.0);
+}
diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp
index fba75dd..ad1645d 100755
--- a/glslang/MachineIndependent/ParseHelper.cpp
+++ b/glslang/MachineIndependent/ParseHelper.cpp
@@ -6843,6 +6843,16 @@
layoutMemberLocationArrayCheck(loc, memberWithLocation, arraySizes);
+ // Ensure that the block has an XfbBuffer assigned. This is needed
+ // because if the block has a XfbOffset assigned, then it is
+ // assumed that it has implicitly assigned the current global
+ // XfbBuffer, and because it's members need to be assigned a
+ // XfbOffset if they lack it.
+ if (currentBlockQualifier.storage == EvqVaryingOut && globalOutputDefaults.hasXfbBuffer()) {
+ if (!currentBlockQualifier.hasXfbBuffer() && currentBlockQualifier.hasXfbOffset())
+ currentBlockQualifier.layoutXfbBuffer = globalOutputDefaults.layoutXfbBuffer;
+ }
+
// Process the members
fixBlockLocations(loc, currentBlockQualifier, typeList, memberWithLocation, memberWithoutLocation);
fixXfbOffsets(currentBlockQualifier, typeList);
diff --git a/gtests/Spv.FromFile.cpp b/gtests/Spv.FromFile.cpp
index bc05eed..ee8cf00 100644
--- a/gtests/Spv.FromFile.cpp
+++ b/gtests/Spv.FromFile.cpp
@@ -440,7 +440,9 @@
"spv.rankShift.comp",
"spv.specConst.vert",
"spv.OVR_multiview.vert",
+ "spv.xfbOffsetOnBlockMembersAssignment.vert",
"spv.xfbOffsetOnStructMembersAssignment.vert",
+ "spv.xfbOverlapOffsetCheckWithBlockAndMember.vert",
})),
FileNameAsCustomTestSuffix
);