[25/63] arb_gl_spirv: add xfb tests

Submitted by apinheiro on Feb. 23, 2019, 11:45 p.m.

Details

Message ID 20190223234551.21111-26-apinheiro@igalia.com
State New
Headers show
Series "ARB_gl_spirv full series" ( rev: 1 ) in Piglit

Not browsing as part of any series.

Commit Message

apinheiro Feb. 23, 2019, 11:45 p.m.
Testing different things, from very basic types, to something more
complex like arrays of blocks where just one member is captured.

All of them are VS, as it is the most common use case.
---
 .../execution/xfb/vs_aoa.shader_test          | 131 +++++++++++++
 .../execution/xfb/vs_block.shader_test        | 121 ++++++++++++
 .../execution/xfb/vs_block_array.shader_test  | 158 ++++++++++++++++
 ..._block_array_offset_per_member.shader_test | 154 ++++++++++++++++
 .../execution/xfb/vs_double.shader_test       | 126 +++++++++++++
 .../execution/xfb/vs_simple.shader_test       |  80 ++++++++
 .../vs_simple_multiple_samples.shader_test    |  88 +++++++++
 .../execution/xfb/vs_struct.shader_test       | 116 ++++++++++++
 .../execution/xfb/vs_struct_array.shader_test | 153 ++++++++++++++++
 .../execution/xfb/vs_two_block.shader_test    | 170 +++++++++++++++++
 .../execution/xfb/vs_two_sets.shader_test     | 160 ++++++++++++++++
 .../execution/xfb/vs_two_sets_ifc.shader_test | 165 +++++++++++++++++
 .../xfb/vs_two_sets_struct.shader_test        | 173 ++++++++++++++++++
 13 files changed, 1795 insertions(+)
 create mode 100644 tests/spec/arb_gl_spirv/execution/xfb/vs_aoa.shader_test
 create mode 100644 tests/spec/arb_gl_spirv/execution/xfb/vs_block.shader_test
 create mode 100644 tests/spec/arb_gl_spirv/execution/xfb/vs_block_array.shader_test
 create mode 100644 tests/spec/arb_gl_spirv/execution/xfb/vs_block_array_offset_per_member.shader_test
 create mode 100644 tests/spec/arb_gl_spirv/execution/xfb/vs_double.shader_test
 create mode 100644 tests/spec/arb_gl_spirv/execution/xfb/vs_simple.shader_test
 create mode 100644 tests/spec/arb_gl_spirv/execution/xfb/vs_simple_multiple_samples.shader_test
 create mode 100644 tests/spec/arb_gl_spirv/execution/xfb/vs_struct.shader_test
 create mode 100644 tests/spec/arb_gl_spirv/execution/xfb/vs_struct_array.shader_test
 create mode 100644 tests/spec/arb_gl_spirv/execution/xfb/vs_two_block.shader_test
 create mode 100644 tests/spec/arb_gl_spirv/execution/xfb/vs_two_sets.shader_test
 create mode 100644 tests/spec/arb_gl_spirv/execution/xfb/vs_two_sets_ifc.shader_test
 create mode 100644 tests/spec/arb_gl_spirv/execution/xfb/vs_two_sets_struct.shader_test

Patch hide | download patch | download mbox

diff --git a/tests/spec/arb_gl_spirv/execution/xfb/vs_aoa.shader_test b/tests/spec/arb_gl_spirv/execution/xfb/vs_aoa.shader_test
new file mode 100644
index 000000000..be9e5ddfb
--- /dev/null
+++ b/tests/spec/arb_gl_spirv/execution/xfb/vs_aoa.shader_test
@@ -0,0 +1,131 @@ 
+# XFB test using an array of arrays input variable
+
+[require]
+SPIRV YES
+GL >= 3.3
+GLSL >= 4.50
+GL_ARB_gl_spirv
+
+[vertex shader spirv]
+; Automatically generated from the GLSL by shader_test_spirv.py. DO NOT EDIT
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 41
+; Schema: 0
+               OpCapability Shader
+               OpCapability TransformFeedback
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %main "main" %color %var %extra %gl_VertexID %gl_InstanceID
+               OpExecutionMode %main Xfb
+               OpSource GLSL 450
+               OpDecorate %color Location 0
+               OpDecorate %color XfbBuffer 0
+               OpDecorate %color XfbStride 28
+               OpDecorate %var Location 1
+               OpDecorate %var XfbBuffer 0
+               OpDecorate %var XfbStride 28
+               OpDecorate %var Offset 0
+               OpDecorate %extra Location 10
+               OpDecorate %extra XfbBuffer 0
+               OpDecorate %extra XfbStride 28
+               OpDecorate %extra Offset 24
+               OpDecorate %gl_VertexID BuiltIn VertexId
+               OpDecorate %gl_InstanceID BuiltIn InstanceId
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+      %color = OpVariable %_ptr_Output_v4float Output
+    %float_0 = OpConstant %float 0
+    %float_1 = OpConstant %float 1
+         %12 = OpConstantComposite %v4float %float_0 %float_1 %float_0 %float_1
+       %uint = OpTypeInt 32 0
+     %uint_3 = OpConstant %uint 3
+%_arr_float_uint_3 = OpTypeArray %float %uint_3
+     %uint_2 = OpConstant %uint 2
+%_arr__arr_float_uint_3_uint_2 = OpTypeArray %_arr_float_uint_3 %uint_2
+%_ptr_Output__arr__arr_float_uint_3_uint_2 = OpTypePointer Output %_arr__arr_float_uint_3_uint_2
+        %var = OpVariable %_ptr_Output__arr__arr_float_uint_3_uint_2 Output
+        %int = OpTypeInt 32 1
+      %int_0 = OpConstant %int 0
+%_ptr_Output_float = OpTypePointer Output %float
+      %int_1 = OpConstant %int 1
+    %float_2 = OpConstant %float 2
+      %int_2 = OpConstant %int 2
+    %float_3 = OpConstant %float 3
+    %float_4 = OpConstant %float 4
+    %float_5 = OpConstant %float 5
+    %float_6 = OpConstant %float 6
+      %extra = OpVariable %_ptr_Output_float Output
+   %float_16 = OpConstant %float 16
+%_ptr_Input_int = OpTypePointer Input %int
+%gl_VertexID = OpVariable %_ptr_Input_int Input
+%gl_InstanceID = OpVariable %_ptr_Input_int Input
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+               OpStore %color %12
+         %23 = OpAccessChain %_ptr_Output_float %var %int_0 %int_0
+               OpStore %23 %float_1
+         %26 = OpAccessChain %_ptr_Output_float %var %int_0 %int_1
+               OpStore %26 %float_2
+         %29 = OpAccessChain %_ptr_Output_float %var %int_0 %int_2
+               OpStore %29 %float_3
+         %31 = OpAccessChain %_ptr_Output_float %var %int_1 %int_0
+               OpStore %31 %float_4
+         %33 = OpAccessChain %_ptr_Output_float %var %int_1 %int_1
+               OpStore %33 %float_5
+         %35 = OpAccessChain %_ptr_Output_float %var %int_1 %int_2
+               OpStore %35 %float_6
+               OpStore %extra %float_16
+               OpReturn
+               OpFunctionEnd
+
+[vertex shader]
+#version 450
+
+layout(location=0) out vec4 color;
+layout(location=1, xfb_offset=0, xfb_buffer=0) out float var[2][3];
+
+//variable below added as a canary, to check that variables get
+//properly assigned after the aoa
+
+layout(location=10, xfb_offset=24, xfb_buffer=0) out float extra;
+
+void main() {
+  color = vec4(0.0, 1.0, 0.0, 1.0);
+
+  var[0][0] = 1.0;
+  var[0][1] = 2.0;
+  var[0][2] = 3.0;
+
+  var[1][0] = 4.0;
+  var[1][1] = 5.0;
+  var[1][2] = 6.0;
+
+  extra = 16.0;
+}
+
+[test]
+xfb buffer object 0 64
+
+xfb draw arrays GL_POINTS 0 1
+
+verify query_object GL_PRIMITIVES_GENERATED 1
+verify query_object GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 1
+
+expected buffer 128
+
+expected buffer float 0  1.0
+expected buffer float 1  2.0
+expected buffer float 2  3.0
+expected buffer float 3  4.0
+expected buffer float 4  5.0
+expected buffer float 5  6.0
+expected buffer float 6  16.0
+
+probe xfb buffer float 0 7
+
+verify program_query GL_TRANSFORM_FEEDBACK_VARYINGS 3
diff --git a/tests/spec/arb_gl_spirv/execution/xfb/vs_block.shader_test b/tests/spec/arb_gl_spirv/execution/xfb/vs_block.shader_test
new file mode 100644
index 000000000..cd39fdfd4
--- /dev/null
+++ b/tests/spec/arb_gl_spirv/execution/xfb/vs_block.shader_test
@@ -0,0 +1,121 @@ 
+# XFB test using a input block. On the original GLSL, setting the
+# xfb_offset on the block. That means that the frontend (glslang) will
+# assign an xfb_offset for all the members of the block, and all of
+# them will be captured.
+
+[require]
+SPIRV YES
+GL >= 3.3
+GLSL >= 4.50
+GL_ARB_gl_spirv
+
+[vertex shader spirv]
+; Automatically generated from the GLSL by shader_test_spirv.py. DO NOT EDIT
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 38
+; Schema: 0
+               OpCapability Shader
+               OpCapability TransformFeedback
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %main "main" %color %x %gl_VertexID %gl_InstanceID
+               OpExecutionMode %main Xfb
+               OpSource GLSL 450
+               OpDecorate %color Location 0
+               OpDecorate %color XfbBuffer 0
+               OpDecorate %color XfbStride 28
+               OpMemberDecorate %block 0 Offset 0
+               OpMemberDecorate %block 1 Offset 4
+               OpMemberDecorate %block 2 Offset 20
+               OpDecorate %block Block
+               OpDecorate %x Location 0
+               OpDecorate %x XfbBuffer 0
+               OpDecorate %x XfbStride 28
+               OpDecorate %gl_VertexID BuiltIn VertexId
+               OpDecorate %gl_InstanceID BuiltIn InstanceId
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+      %color = OpVariable %_ptr_Output_v4float Output
+    %float_0 = OpConstant %float 0
+         %11 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
+       %uint = OpTypeInt 32 0
+     %uint_2 = OpConstant %uint 2
+%_arr_float_uint_2 = OpTypeArray %float %uint_2
+      %block = OpTypeStruct %float %v4float %_arr_float_uint_2
+%_ptr_Output_block = OpTypePointer Output %block
+          %x = OpVariable %_ptr_Output_block Output
+        %int = OpTypeInt 32 1
+      %int_0 = OpConstant %int 0
+    %float_1 = OpConstant %float 1
+%_ptr_Output_float = OpTypePointer Output %float
+      %int_1 = OpConstant %int 1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+    %float_4 = OpConstant %float 4
+    %float_5 = OpConstant %float 5
+         %28 = OpConstantComposite %v4float %float_2 %float_3 %float_4 %float_5
+      %int_2 = OpConstant %int 2
+    %float_6 = OpConstant %float 6
+    %float_7 = OpConstant %float 7
+%_ptr_Input_int = OpTypePointer Input %int
+%gl_VertexID = OpVariable %_ptr_Input_int Input
+%gl_InstanceID = OpVariable %_ptr_Input_int Input
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+               OpStore %color %11
+         %22 = OpAccessChain %_ptr_Output_float %x %int_0
+               OpStore %22 %float_1
+         %29 = OpAccessChain %_ptr_Output_v4float %x %int_1
+               OpStore %29 %28
+         %32 = OpAccessChain %_ptr_Output_float %x %int_2 %int_0
+               OpStore %32 %float_6
+         %34 = OpAccessChain %_ptr_Output_float %x %int_2 %int_1
+               OpStore %34 %float_7
+               OpReturn
+               OpFunctionEnd
+
+[vertex shader]
+#version 450
+
+layout(xfb_buffer=0, xfb_offset=0) out block {
+    float f;
+    vec4 v;
+    float f2[2];
+} x;
+
+layout(location=0) out vec4 color;
+
+void main() {
+  color = vec4(0.0);
+
+  x.f = 1.0;
+  x.v = vec4(2.0, 3.0, 4.0, 5.0);
+  x.f2[0] = 6.0;
+  x.f2[1] = 7.0;
+}
+
+[test]
+xfb buffer object 0 256
+
+xfb draw arrays GL_POINTS 0 1
+
+verify query_object GL_PRIMITIVES_GENERATED 1
+verify query_object GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 1
+
+expected buffer 256
+
+expected buffer float 0 1.0
+expected buffer float 1 2.0
+expected buffer float 2 3.0
+expected buffer float 3 4.0
+expected buffer float 4 5.0
+expected buffer float 5 6.0
+expected buffer float 6 7.0
+probe xfb buffer float 0 7
+
+verify program_query GL_TRANSFORM_FEEDBACK_VARYINGS 3
diff --git a/tests/spec/arb_gl_spirv/execution/xfb/vs_block_array.shader_test b/tests/spec/arb_gl_spirv/execution/xfb/vs_block_array.shader_test
new file mode 100644
index 000000000..754a3d8b9
--- /dev/null
+++ b/tests/spec/arb_gl_spirv/execution/xfb/vs_block_array.shader_test
@@ -0,0 +1,158 @@ 
+# XFB test with an array of blocks. On the original GLSL, setting the
+# xfb_offset on the block. That means that the frontend (glslang) will
+# assign an xfb_offset for all the members of the block, and all of
+# them will be captured, and for each iteration of the array (on a
+# different buffer per array index)
+
+[require]
+SPIRV YES
+GL >= 3.3
+GLSL >= 4.50
+GL_ARB_gl_spirv
+
+[vertex shader spirv]
+; Automatically generated from the GLSL by shader_test_spirv.py. DO NOT EDIT
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 51
+; Schema: 0
+               OpCapability Shader
+               OpCapability TransformFeedback
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %main "main" %color %x %gl_VertexID %gl_InstanceID
+               OpExecutionMode %main Xfb
+               OpSource GLSL 450
+               OpDecorate %color Location 0
+               OpDecorate %color XfbBuffer 0
+               OpDecorate %color XfbStride 28
+               OpMemberDecorate %block 0 Offset 0
+               OpMemberDecorate %block 1 Offset 4
+               OpMemberDecorate %block 2 Offset 20
+               OpDecorate %block Block
+               OpDecorate %x Location 0
+               OpDecorate %x XfbBuffer 0
+               OpDecorate %x XfbStride 28
+               OpDecorate %gl_VertexID BuiltIn VertexId
+               OpDecorate %gl_InstanceID BuiltIn InstanceId
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+      %color = OpVariable %_ptr_Output_v4float Output
+    %float_0 = OpConstant %float 0
+         %11 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
+       %uint = OpTypeInt 32 0
+     %uint_2 = OpConstant %uint 2
+%_arr_float_uint_2 = OpTypeArray %float %uint_2
+      %block = OpTypeStruct %float %v4float %_arr_float_uint_2
+%_arr_block_uint_2 = OpTypeArray %block %uint_2
+%_ptr_Output__arr_block_uint_2 = OpTypePointer Output %_arr_block_uint_2
+          %x = OpVariable %_ptr_Output__arr_block_uint_2 Output
+        %int = OpTypeInt 32 1
+      %int_0 = OpConstant %int 0
+    %float_1 = OpConstant %float 1
+%_ptr_Output_float = OpTypePointer Output %float
+      %int_1 = OpConstant %int 1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+    %float_4 = OpConstant %float 4
+    %float_5 = OpConstant %float 5
+         %29 = OpConstantComposite %v4float %float_2 %float_3 %float_4 %float_5
+      %int_2 = OpConstant %int 2
+    %float_6 = OpConstant %float 6
+    %float_7 = OpConstant %float 7
+    %float_8 = OpConstant %float 8
+    %float_9 = OpConstant %float 9
+   %float_10 = OpConstant %float 10
+   %float_11 = OpConstant %float 11
+   %float_12 = OpConstant %float 12
+         %42 = OpConstantComposite %v4float %float_9 %float_10 %float_11 %float_12
+   %float_13 = OpConstant %float 13
+   %float_14 = OpConstant %float 14
+%_ptr_Input_int = OpTypePointer Input %int
+%gl_VertexID = OpVariable %_ptr_Input_int Input
+%gl_InstanceID = OpVariable %_ptr_Input_int Input
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+               OpStore %color %11
+         %23 = OpAccessChain %_ptr_Output_float %x %int_0 %int_0
+               OpStore %23 %float_1
+         %30 = OpAccessChain %_ptr_Output_v4float %x %int_0 %int_1
+               OpStore %30 %29
+         %33 = OpAccessChain %_ptr_Output_float %x %int_0 %int_2 %int_0
+               OpStore %33 %float_6
+         %35 = OpAccessChain %_ptr_Output_float %x %int_0 %int_2 %int_1
+               OpStore %35 %float_7
+         %37 = OpAccessChain %_ptr_Output_float %x %int_1 %int_0
+               OpStore %37 %float_8
+         %43 = OpAccessChain %_ptr_Output_v4float %x %int_1 %int_1
+               OpStore %43 %42
+         %45 = OpAccessChain %_ptr_Output_float %x %int_1 %int_2 %int_0
+               OpStore %45 %float_13
+         %47 = OpAccessChain %_ptr_Output_float %x %int_1 %int_2 %int_1
+               OpStore %47 %float_14
+               OpReturn
+               OpFunctionEnd
+
+[vertex shader]
+#version 450
+
+layout(xfb_buffer=0, xfb_offset=0) out block {
+    float f;
+    vec4 v;
+    float f2[2];
+} x[2];
+
+layout(location=0) out vec4 color;
+
+void main() {
+  color = vec4(0.0);
+
+  x[0].f = 1.0;
+  x[0].v = vec4(2.0, 3.0, 4.0, 5.0);
+  x[0].f2[0] = 6.0;
+  x[0].f2[1] = 7.0;
+
+  x[1].f = 8.0;
+  x[1].v = vec4(9.0, 10.0, 11.0, 12);
+  x[1].f2[0] = 13.0;
+  x[1].f2[1] = 14.0;
+}
+
+[test]
+# With arrays of blocks, each component uses a different buffer, see
+# GLSL spec section 4.4.2
+
+xfb buffer object 0 256
+xfb buffer object 1 256
+
+xfb draw arrays GL_POINTS 0 1
+
+verify query_object GL_PRIMITIVES_GENERATED 1
+verify query_object GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 1
+
+expected buffer 256
+
+expected buffer float 0 1.0
+expected buffer float 1 2.0
+expected buffer float 2 3.0
+expected buffer float 3 4.0
+expected buffer float 4 5.0
+expected buffer float 5 6.0
+expected buffer float 6 7.0
+probe xfb buffer float 0 7
+
+expected buffer 256 # Not really needed to call again, just to force a clean-up
+expected buffer float 0 8.0
+expected buffer float 1 9.0
+expected buffer float 2 10.0
+expected buffer float 3 11.0
+expected buffer float 4 12.0
+expected buffer float 5 13.0
+expected buffer float 6 14.0
+probe xfb buffer float 1 7
+
+verify program_query GL_TRANSFORM_FEEDBACK_VARYINGS 6
diff --git a/tests/spec/arb_gl_spirv/execution/xfb/vs_block_array_offset_per_member.shader_test b/tests/spec/arb_gl_spirv/execution/xfb/vs_block_array_offset_per_member.shader_test
new file mode 100644
index 000000000..49ad18ae3
--- /dev/null
+++ b/tests/spec/arb_gl_spirv/execution/xfb/vs_block_array_offset_per_member.shader_test
@@ -0,0 +1,154 @@ 
+# XFB test with an array of blocks, setting the xfb_offset on one
+# member of the block. That means that only that member (for each
+# iteration of the array) will be captured.
+
+[require]
+SPIRV YES
+GL >= 3.3
+GLSL >= 4.50
+GL_ARB_gl_spirv
+
+[vertex shader spirv]
+; Automatically generated from the GLSL by shader_test_spirv.py. DO NOT EDIT
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 51
+; Schema: 0
+               OpCapability Shader
+               OpCapability TransformFeedback
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %main "main" %color %x %gl_VertexID %gl_InstanceID
+               OpExecutionMode %main Xfb
+               OpSource GLSL 450
+               OpDecorate %color Location 0
+               OpDecorate %color XfbBuffer 0
+               OpDecorate %color XfbStride 32
+               OpMemberDecorate %block 1 Offset 16
+               OpDecorate %block Block
+               OpDecorate %x Location 0
+               OpDecorate %x XfbBuffer 0
+               OpDecorate %x XfbStride 32
+               OpDecorate %gl_VertexID BuiltIn VertexId
+               OpDecorate %gl_InstanceID BuiltIn InstanceId
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+      %color = OpVariable %_ptr_Output_v4float Output
+    %float_0 = OpConstant %float 0
+         %11 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
+       %uint = OpTypeInt 32 0
+     %uint_2 = OpConstant %uint 2
+%_arr_float_uint_2 = OpTypeArray %float %uint_2
+      %block = OpTypeStruct %float %v4float %_arr_float_uint_2
+%_arr_block_uint_2 = OpTypeArray %block %uint_2
+%_ptr_Output__arr_block_uint_2 = OpTypePointer Output %_arr_block_uint_2
+          %x = OpVariable %_ptr_Output__arr_block_uint_2 Output
+        %int = OpTypeInt 32 1
+      %int_0 = OpConstant %int 0
+    %float_1 = OpConstant %float 1
+%_ptr_Output_float = OpTypePointer Output %float
+      %int_1 = OpConstant %int 1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+    %float_4 = OpConstant %float 4
+    %float_5 = OpConstant %float 5
+         %29 = OpConstantComposite %v4float %float_2 %float_3 %float_4 %float_5
+      %int_2 = OpConstant %int 2
+    %float_6 = OpConstant %float 6
+    %float_7 = OpConstant %float 7
+    %float_8 = OpConstant %float 8
+    %float_9 = OpConstant %float 9
+   %float_10 = OpConstant %float 10
+   %float_11 = OpConstant %float 11
+   %float_12 = OpConstant %float 12
+         %42 = OpConstantComposite %v4float %float_9 %float_10 %float_11 %float_12
+   %float_13 = OpConstant %float 13
+   %float_14 = OpConstant %float 14
+%_ptr_Input_int = OpTypePointer Input %int
+%gl_VertexID = OpVariable %_ptr_Input_int Input
+%gl_InstanceID = OpVariable %_ptr_Input_int Input
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+               OpStore %color %11
+         %23 = OpAccessChain %_ptr_Output_float %x %int_0 %int_0
+               OpStore %23 %float_1
+         %30 = OpAccessChain %_ptr_Output_v4float %x %int_0 %int_1
+               OpStore %30 %29
+         %33 = OpAccessChain %_ptr_Output_float %x %int_0 %int_2 %int_0
+               OpStore %33 %float_6
+         %35 = OpAccessChain %_ptr_Output_float %x %int_0 %int_2 %int_1
+               OpStore %35 %float_7
+         %37 = OpAccessChain %_ptr_Output_float %x %int_1 %int_0
+               OpStore %37 %float_8
+         %43 = OpAccessChain %_ptr_Output_v4float %x %int_1 %int_1
+               OpStore %43 %42
+         %45 = OpAccessChain %_ptr_Output_float %x %int_1 %int_2 %int_0
+               OpStore %45 %float_13
+         %47 = OpAccessChain %_ptr_Output_float %x %int_1 %int_2 %int_1
+               OpStore %47 %float_14
+               OpReturn
+               OpFunctionEnd
+
+[vertex shader]
+#version 450
+
+out block {
+  float f;
+  layout(xfb_buffer=0, xfb_offset = 16) vec4 v; // we only capture this, but twice
+  float f2[2];
+} x[2];
+
+layout(location=0) out vec4 color;
+
+void main() {
+  color = vec4(0.0);
+
+  x[0].f = 1.0;
+  x[0].v = vec4(2.0, 3.0, 4.0, 5.0);
+  x[0].f2[0] = 6.0;
+  x[0].f2[1] = 7.0;
+
+  x[1].f = 8.0;
+  x[1].v = vec4(9.0, 10.0, 11.0, 12.0);
+  x[1].f2[0] = 13.0;
+  x[1].f2[1] = 14.0;
+}
+
+[test]
+xfb buffer object 0 64
+xfb buffer object 1 64
+
+xfb draw arrays GL_POINTS 0 1
+
+verify query_object GL_PRIMITIVES_GENERATED 1
+verify query_object GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 1
+
+expected buffer 64
+#Only the vector is captured, so the buffer is not touched for other components
+expected buffer float 0 0
+expected buffer float 1 0
+expected buffer float 2 0
+expected buffer float 3 0
+expected buffer float 4 2.0
+expected buffer float 5 3.0
+expected buffer float 6 4.0
+expected buffer float 7 5.0
+probe xfb buffer float 0 8
+
+expected buffer 64 # Not really needed, just to clean.
+#Only the vector is captured, so the buffer is not touched for other components
+expected buffer float 0 0
+expected buffer float 1 0
+expected buffer float 2 0
+expected buffer float 3 0
+expected buffer float 4 9.0
+expected buffer float 5 10.0
+expected buffer float 6 11.0
+expected buffer float 7 12.0
+probe xfb buffer float 1 8
+
+verify program_query GL_TRANSFORM_FEEDBACK_VARYINGS 2
diff --git a/tests/spec/arb_gl_spirv/execution/xfb/vs_double.shader_test b/tests/spec/arb_gl_spirv/execution/xfb/vs_double.shader_test
new file mode 100644
index 000000000..daf058546
--- /dev/null
+++ b/tests/spec/arb_gl_spirv/execution/xfb/vs_double.shader_test
@@ -0,0 +1,126 @@ 
+#XFB test using 64-bit floating types (double, dvecX).
+
+[require]
+SPIRV YES
+GL >= 3.3
+GLSL >= 4.50
+GL_ARB_gl_spirv
+
+[vertex shader spirv]
+; Automatically generated from the GLSL by shader_test_spirv.py. DO NOT EDIT
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 41
+; Schema: 0
+               OpCapability Shader
+               OpCapability Float64
+               OpCapability TransformFeedback
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %main "main" %_ %x1_out %x2_out %x3_out %gl_VertexID %gl_InstanceID
+               OpExecutionMode %main Xfb
+               OpSource GLSL 450
+               OpSourceExtension "GL_ARB_enhanced_layouts"
+               OpName %_ ""
+               OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
+               OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize
+               OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance
+               OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance
+               OpDecorate %gl_PerVertex Block
+               OpDecorate %_ XfbBuffer 0
+               OpDecorate %_ XfbStride 56
+               OpDecorate %x1_out Location 0
+               OpDecorate %x1_out XfbBuffer 0
+               OpDecorate %x1_out XfbStride 56
+               OpDecorate %x1_out Offset 0
+               OpDecorate %x2_out Location 1
+               OpDecorate %x2_out XfbBuffer 0
+               OpDecorate %x2_out XfbStride 56
+               OpDecorate %x2_out Offset 8
+               OpDecorate %x3_out Location 2
+               OpDecorate %x3_out XfbBuffer 0
+               OpDecorate %x3_out XfbStride 56
+               OpDecorate %x3_out Offset 24
+               OpDecorate %gl_VertexID BuiltIn VertexId
+               OpDecorate %gl_InstanceID BuiltIn InstanceId
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+       %uint = OpTypeInt 32 0
+     %uint_1 = OpConstant %uint 1
+%_arr_float_uint_1 = OpTypeArray %float %uint_1
+%gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1
+%_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex
+          %_ = OpVariable %_ptr_Output_gl_PerVertex Output
+        %int = OpTypeInt 32 1
+      %int_0 = OpConstant %int 0
+    %float_0 = OpConstant %float 0
+         %17 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+     %double = OpTypeFloat 64
+%_ptr_Output_double = OpTypePointer Output %double
+     %x1_out = OpVariable %_ptr_Output_double Output
+   %double_1 = OpConstant %double 1
+   %v2double = OpTypeVector %double 2
+%_ptr_Output_v2double = OpTypePointer Output %v2double
+     %x2_out = OpVariable %_ptr_Output_v2double Output
+   %double_2 = OpConstant %double 2
+   %double_3 = OpConstant %double 3
+         %29 = OpConstantComposite %v2double %double_2 %double_3
+   %v4double = OpTypeVector %double 4
+%_ptr_Output_v4double = OpTypePointer Output %v4double
+     %x3_out = OpVariable %_ptr_Output_v4double Output
+   %double_4 = OpConstant %double 4
+   %double_5 = OpConstant %double 5
+   %double_6 = OpConstant %double 6
+   %double_7 = OpConstant %double 7
+         %37 = OpConstantComposite %v4double %double_4 %double_5 %double_6 %double_7
+%_ptr_Input_int = OpTypePointer Input %int
+%gl_VertexID = OpVariable %_ptr_Input_int Input
+%gl_InstanceID = OpVariable %_ptr_Input_int Input
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+         %19 = OpAccessChain %_ptr_Output_v4float %_ %int_0
+               OpStore %19 %17
+               OpStore %x1_out %double_1
+               OpStore %x2_out %29
+               OpStore %x3_out %37
+               OpReturn
+               OpFunctionEnd
+
+[vertex shader]
+#version 450
+#extension GL_ARB_enhanced_layouts: require
+
+layout(location = 0, xfb_offset = 0) out double x1_out;
+layout(location = 1, xfb_offset = 8) out dvec2 x2_out;
+layout(location = 2, xfb_offset = 24) out dvec4 x3_out;
+
+void main() {
+        gl_Position = vec4(0.0);
+        x1_out = 1.0lf;
+        x2_out = dvec2(2.0lf, 3.0lf);
+        x3_out = dvec4(4.0lf, 5.0lf, 6.0lf, 7.0lf);
+}
+
+[test]
+xfb buffer object 0 128
+
+xfb draw arrays GL_POINTS 0 1
+
+verify query_object GL_PRIMITIVES_GENERATED 1
+verify query_object GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 1
+
+expected buffer 64
+expected buffer double 0 1.0
+expected buffer double 1 2.0
+expected buffer double 2 3.0
+expected buffer double 3 4.0
+expected buffer double 4 5.0
+expected buffer double 5 6.0
+
+probe xfb buffer double 0 5
+
+verify program_query GL_TRANSFORM_FEEDBACK_VARYINGS 3
\ No newline at end of file
diff --git a/tests/spec/arb_gl_spirv/execution/xfb/vs_simple.shader_test b/tests/spec/arb_gl_spirv/execution/xfb/vs_simple.shader_test
new file mode 100644
index 000000000..96521f458
--- /dev/null
+++ b/tests/spec/arb_gl_spirv/execution/xfb/vs_simple.shader_test
@@ -0,0 +1,80 @@ 
+# Really simple XFB test
+
+[require]
+SPIRV YES
+GL >= 3.3
+GLSL >= 4.50
+GL_ARB_gl_spirv
+
+[vertex shader spirv]
+; Automatically generated from the GLSL by shader_test_spirv.py. DO NOT EDIT
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 20
+; Schema: 0
+               OpCapability Shader
+               OpCapability TransformFeedback
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %main "main" %color %xfb_out %gl_VertexID %gl_InstanceID
+               OpExecutionMode %main Xfb
+               OpSource GLSL 450
+               OpDecorate %color Location 0
+               OpDecorate %color XfbBuffer 0
+               OpDecorate %color XfbStride 4
+               OpDecorate %xfb_out Location 1
+               OpDecorate %xfb_out XfbBuffer 0
+               OpDecorate %xfb_out XfbStride 4
+               OpDecorate %xfb_out Offset 0
+               OpDecorate %gl_VertexID BuiltIn VertexId
+               OpDecorate %gl_InstanceID BuiltIn InstanceId
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+      %color = OpVariable %_ptr_Output_v4float Output
+    %float_0 = OpConstant %float 0
+    %float_1 = OpConstant %float 1
+         %12 = OpConstantComposite %v4float %float_0 %float_1 %float_0 %float_1
+%_ptr_Output_float = OpTypePointer Output %float
+    %xfb_out = OpVariable %_ptr_Output_float Output
+%float_1_23099995 = OpConstant %float 1.23099995
+        %int = OpTypeInt 32 1
+%_ptr_Input_int = OpTypePointer Input %int
+%gl_VertexID = OpVariable %_ptr_Input_int Input
+%gl_InstanceID = OpVariable %_ptr_Input_int Input
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+               OpStore %color %12
+               OpStore %xfb_out %float_1_23099995
+               OpReturn
+               OpFunctionEnd
+
+[vertex shader]
+#version 450
+
+layout(location = 0) out vec4 color;
+layout(location = 1, xfb_buffer=0, xfb_offset = 0) out float xfb_out;
+
+void main() {
+  color = vec4(0.0, 1.0, 0.0, 1.0);
+  xfb_out = 1.231;
+}
+
+[test]
+
+xfb buffer object 0 4
+
+xfb draw arrays GL_POINTS 0 1
+
+verify query_object GL_PRIMITIVES_GENERATED 1
+verify query_object GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 1
+
+expected buffer 4
+expected buffer float 0 1.231
+
+probe xfb buffer float 0 1
+
+verify program_query GL_TRANSFORM_FEEDBACK_VARYINGS 1
\ No newline at end of file
diff --git a/tests/spec/arb_gl_spirv/execution/xfb/vs_simple_multiple_samples.shader_test b/tests/spec/arb_gl_spirv/execution/xfb/vs_simple_multiple_samples.shader_test
new file mode 100644
index 000000000..6f0e5a3da
--- /dev/null
+++ b/tests/spec/arb_gl_spirv/execution/xfb/vs_simple_multiple_samples.shader_test
@@ -0,0 +1,88 @@ 
+#XFB simple test, but using multiple samples, as for simplicity, most
+#shader_runner tests are drawing just one sample (usually just one
+#GL_POINTS).
+
+[require]
+SPIRV YES
+GL >= 3.3
+GLSL >= 4.50
+GL_ARB_gl_spirv
+
+[vertex shader spirv]
+; Automatically generated from the GLSL by shader_test_spirv.py. DO NOT EDIT
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 23
+; Schema: 0
+               OpCapability Shader
+               OpCapability TransformFeedback
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %main "main" %color %xfb_out %gl_VertexID %gl_InstanceID
+               OpExecutionMode %main Xfb
+               OpSource GLSL 450
+               OpDecorate %color Location 0
+               OpDecorate %color XfbBuffer 0
+               OpDecorate %color XfbStride 4
+               OpDecorate %xfb_out Location 1
+               OpDecorate %xfb_out XfbBuffer 0
+               OpDecorate %xfb_out XfbStride 4
+               OpDecorate %xfb_out Offset 0
+               OpDecorate %gl_VertexID BuiltIn VertexId
+               OpDecorate %gl_InstanceID BuiltIn InstanceId
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+      %color = OpVariable %_ptr_Output_v4float Output
+    %float_0 = OpConstant %float 0
+    %float_1 = OpConstant %float 1
+         %12 = OpConstantComposite %v4float %float_0 %float_1 %float_0 %float_1
+%_ptr_Output_float = OpTypePointer Output %float
+    %xfb_out = OpVariable %_ptr_Output_float Output
+        %int = OpTypeInt 32 1
+%_ptr_Input_int = OpTypePointer Input %int
+%gl_VertexID = OpVariable %_ptr_Input_int Input
+%float_0_314099997 = OpConstant %float 0.314099997
+%gl_InstanceID = OpVariable %_ptr_Input_int Input
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+               OpStore %color %12
+         %18 = OpLoad %int %gl_VertexID
+         %19 = OpConvertSToF %float %18
+         %21 = OpFMul %float %19 %float_0_314099997
+               OpStore %xfb_out %21
+               OpReturn
+               OpFunctionEnd
+
+[vertex shader]
+#version 450
+
+layout(location = 0) out vec4 color;
+layout(location = 1, xfb_buffer=0, xfb_offset = 0) out float xfb_out;
+
+void main() {
+  color = vec4(0.0, 1.0, 0.0, 1.0);
+  xfb_out = gl_VertexID * 0.3141;
+}
+
+[test]
+
+xfb buffer object 0 16
+
+xfb draw arrays GL_POINTS 0 4
+
+verify query_object GL_PRIMITIVES_GENERATED 4
+verify query_object GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 4
+
+expected buffer 16
+expected buffer float 0 0
+expected buffer float 1 0.3141
+expected buffer float 2 0.6282
+expected buffer float 3 0.9423
+
+probe xfb buffer float 0 4
+
+verify program_query GL_TRANSFORM_FEEDBACK_VARYINGS 1
\ No newline at end of file
diff --git a/tests/spec/arb_gl_spirv/execution/xfb/vs_struct.shader_test b/tests/spec/arb_gl_spirv/execution/xfb/vs_struct.shader_test
new file mode 100644
index 000000000..d938e7b01
--- /dev/null
+++ b/tests/spec/arb_gl_spirv/execution/xfb/vs_struct.shader_test
@@ -0,0 +1,116 @@ 
+# XFB test with a variable that is an struct.
+[require]
+SPIRV YES
+GL >= 3.3
+GLSL >= 4.50
+GL_ARB_gl_spirv
+
+[vertex shader spirv]
+; Automatically generated from the GLSL by shader_test_spirv.py. DO NOT EDIT
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 38
+; Schema: 0
+               OpCapability Shader
+               OpCapability TransformFeedback
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %main "main" %color %var %gl_VertexID %gl_InstanceID
+               OpExecutionMode %main Xfb
+               OpSource GLSL 450
+               OpDecorate %color Location 0
+               OpDecorate %color XfbBuffer 0
+               OpDecorate %color XfbStride 28
+               OpDecorate %var Location 0
+               OpDecorate %var XfbBuffer 0
+               OpDecorate %var XfbStride 28
+               OpDecorate %var Offset 0
+               OpDecorate %gl_VertexID BuiltIn VertexId
+               OpDecorate %gl_InstanceID BuiltIn InstanceId
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+      %color = OpVariable %_ptr_Output_v4float Output
+    %float_0 = OpConstant %float 0
+    %float_1 = OpConstant %float 1
+         %12 = OpConstantComposite %v4float %float_0 %float_1 %float_0 %float_1
+       %uint = OpTypeInt 32 0
+     %uint_2 = OpConstant %uint 2
+%_arr_float_uint_2 = OpTypeArray %float %uint_2
+          %S = OpTypeStruct %float %v4float %_arr_float_uint_2
+%_ptr_Output_S = OpTypePointer Output %S
+        %var = OpVariable %_ptr_Output_S Output
+        %int = OpTypeInt 32 1
+      %int_0 = OpConstant %int 0
+%_ptr_Output_float = OpTypePointer Output %float
+      %int_1 = OpConstant %int 1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+    %float_4 = OpConstant %float 4
+    %float_5 = OpConstant %float 5
+         %28 = OpConstantComposite %v4float %float_2 %float_3 %float_4 %float_5
+      %int_2 = OpConstant %int 2
+    %float_6 = OpConstant %float 6
+    %float_7 = OpConstant %float 7
+%_ptr_Input_int = OpTypePointer Input %int
+%gl_VertexID = OpVariable %_ptr_Input_int Input
+%gl_InstanceID = OpVariable %_ptr_Input_int Input
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+               OpStore %color %12
+         %22 = OpAccessChain %_ptr_Output_float %var %int_0
+               OpStore %22 %float_1
+         %29 = OpAccessChain %_ptr_Output_v4float %var %int_1
+               OpStore %29 %28
+         %32 = OpAccessChain %_ptr_Output_float %var %int_2 %int_0
+               OpStore %32 %float_6
+         %34 = OpAccessChain %_ptr_Output_float %var %int_2 %int_1
+               OpStore %34 %float_7
+               OpReturn
+               OpFunctionEnd
+
+[vertex shader]
+#version 450
+
+struct S {
+   float f;
+   vec4 v;
+   float f2[2];
+};
+
+layout(location=0) out vec4 color;
+
+layout(xfb_offset=0, xfb_buffer=0) out S var;
+
+void main() {
+  color = vec4(0.0, 1.0, 0.0, 1.0);
+
+  var.f = 1.0;
+  var.v = vec4(2.0, 3.0, 4.0, 5.0);
+  var.f2[0] = 6.0;
+  var.f2[1] = 7.0;
+}
+
+[test]
+xfb buffer object 0 32
+
+xfb draw arrays GL_POINTS 0 1
+
+verify query_object GL_PRIMITIVES_GENERATED 1
+verify query_object GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 1
+
+expected buffer 32
+
+expected buffer float 0  1.0
+expected buffer float 1  2.0
+expected buffer float 2  3.0
+expected buffer float 3  4.0
+expected buffer float 4  5.0
+expected buffer float 5  6.0
+
+probe xfb buffer float 0 6
+
+verify program_query GL_TRANSFORM_FEEDBACK_VARYINGS 3
diff --git a/tests/spec/arb_gl_spirv/execution/xfb/vs_struct_array.shader_test b/tests/spec/arb_gl_spirv/execution/xfb/vs_struct_array.shader_test
new file mode 100644
index 000000000..36135b60a
--- /dev/null
+++ b/tests/spec/arb_gl_spirv/execution/xfb/vs_struct_array.shader_test
@@ -0,0 +1,153 @@ 
+# XFB test using an array of structs variable, that behaves
+# differently that an array of blocks (in this case, everything is
+# captured to the same xfb buffer).
+
+[require]
+SPIRV YES
+GL >= 3.3
+GLSL >= 4.50
+GL_ARB_gl_spirv
+
+[vertex shader spirv]
+; Automatically generated from the GLSL by shader_test_spirv.py. DO NOT EDIT
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 51
+; Schema: 0
+               OpCapability Shader
+               OpCapability TransformFeedback
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %main "main" %color %var %gl_VertexID %gl_InstanceID
+               OpExecutionMode %main Xfb
+               OpSource GLSL 450
+               OpSourceExtension "GL_ARB_enhanced_layouts"
+               OpDecorate %color Location 0
+               OpDecorate %color XfbBuffer 0
+               OpDecorate %color XfbStride 56
+               OpMemberDecorate %S 1 Offset 4
+               OpMemberDecorate %S 2 Offset 20
+               OpDecorate %var Location 0
+               OpDecorate %var XfbBuffer 0
+               OpDecorate %var XfbStride 56
+               OpDecorate %var Offset 0
+               OpDecorate %gl_VertexID BuiltIn VertexId
+               OpDecorate %gl_InstanceID BuiltIn InstanceId
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+      %color = OpVariable %_ptr_Output_v4float Output
+    %float_0 = OpConstant %float 0
+    %float_1 = OpConstant %float 1
+         %12 = OpConstantComposite %v4float %float_0 %float_1 %float_0 %float_1
+       %uint = OpTypeInt 32 0
+     %uint_2 = OpConstant %uint 2
+%_arr_float_uint_2 = OpTypeArray %float %uint_2
+          %S = OpTypeStruct %float %v4float %_arr_float_uint_2
+%_arr_S_uint_2 = OpTypeArray %S %uint_2
+%_ptr_Output__arr_S_uint_2 = OpTypePointer Output %_arr_S_uint_2
+        %var = OpVariable %_ptr_Output__arr_S_uint_2 Output
+        %int = OpTypeInt 32 1
+      %int_0 = OpConstant %int 0
+%_ptr_Output_float = OpTypePointer Output %float
+      %int_1 = OpConstant %int 1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+    %float_4 = OpConstant %float 4
+    %float_5 = OpConstant %float 5
+         %29 = OpConstantComposite %v4float %float_2 %float_3 %float_4 %float_5
+      %int_2 = OpConstant %int 2
+    %float_6 = OpConstant %float 6
+    %float_7 = OpConstant %float 7
+    %float_8 = OpConstant %float 8
+    %float_9 = OpConstant %float 9
+   %float_10 = OpConstant %float 10
+   %float_11 = OpConstant %float 11
+   %float_12 = OpConstant %float 12
+         %42 = OpConstantComposite %v4float %float_9 %float_10 %float_11 %float_12
+   %float_13 = OpConstant %float 13
+   %float_14 = OpConstant %float 14
+%_ptr_Input_int = OpTypePointer Input %int
+%gl_VertexID = OpVariable %_ptr_Input_int Input
+%gl_InstanceID = OpVariable %_ptr_Input_int Input
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+               OpStore %color %12
+         %23 = OpAccessChain %_ptr_Output_float %var %int_0 %int_0
+               OpStore %23 %float_1
+         %30 = OpAccessChain %_ptr_Output_v4float %var %int_0 %int_1
+               OpStore %30 %29
+         %33 = OpAccessChain %_ptr_Output_float %var %int_0 %int_2 %int_0
+               OpStore %33 %float_6
+         %35 = OpAccessChain %_ptr_Output_float %var %int_0 %int_2 %int_1
+               OpStore %35 %float_7
+         %37 = OpAccessChain %_ptr_Output_float %var %int_1 %int_0
+               OpStore %37 %float_8
+         %43 = OpAccessChain %_ptr_Output_v4float %var %int_1 %int_1
+               OpStore %43 %42
+         %45 = OpAccessChain %_ptr_Output_float %var %int_1 %int_2 %int_0
+               OpStore %45 %float_13
+         %47 = OpAccessChain %_ptr_Output_float %var %int_1 %int_2 %int_1
+               OpStore %47 %float_14
+               OpReturn
+               OpFunctionEnd
+
+[vertex shader]
+#version 450
+#extension GL_ARB_enhanced_layouts: require
+
+struct S {
+   float f;
+   vec4 v;
+   float f2[2];
+};
+layout(xfb_offset=0, xfb_buffer=0) out S var[2];
+
+layout(location=0) out vec4 color;
+
+void main() {
+  color = vec4(0.0, 1.0, 0.0, 1.0);
+
+  var[0].f = 1.0;
+  var[0].v = vec4(2.0, 3.0, 4.0, 5.0);
+  var[0].f2[0] = 6.0;
+  var[0].f2[1] = 7.0;
+
+  var[1].f = 8.0;
+  var[1].v = vec4(9.0, 10.0, 11.0, 12);
+  var[1].f2[0] = 13.0;
+  var[1].f2[1] = 14.0;
+}
+
+[test]
+xfb buffer object 0 64
+
+xfb draw arrays GL_POINTS 0 1
+
+verify query_object GL_PRIMITIVES_GENERATED 1
+verify query_object GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 1
+
+expected buffer 128
+
+expected buffer float 0 1.0
+expected buffer float 1 2.0
+expected buffer float 2 3.0
+expected buffer float 3 4.0
+expected buffer float 4 5.0
+expected buffer float 5 6.0
+expected buffer float 6 7.0
+
+expected buffer float 7 8.0
+expected buffer float 8 9.0
+expected buffer float 9 10.0
+expected buffer float 10 11.0
+expected buffer float 11 12.0
+expected buffer float 12 13.0
+expected buffer float 13 14.0
+
+probe xfb buffer float 0 14
+
+verify program_query GL_TRANSFORM_FEEDBACK_VARYINGS 6
diff --git a/tests/spec/arb_gl_spirv/execution/xfb/vs_two_block.shader_test b/tests/spec/arb_gl_spirv/execution/xfb/vs_two_block.shader_test
new file mode 100644
index 000000000..b45ff5496
--- /dev/null
+++ b/tests/spec/arb_gl_spirv/execution/xfb/vs_two_block.shader_test
@@ -0,0 +1,170 @@ 
+# XFB test using two input blocks, both with the same structure, but
+# captured to different buffers.
+
+[require]
+SPIRV YES
+GL >= 3.3
+GLSL >= 4.50
+GL_ARB_gl_spirv
+
+[vertex shader spirv]
+; Automatically generated from the GLSL by shader_test_spirv.py. DO NOT EDIT
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 53
+; Schema: 0
+               OpCapability Shader
+               OpCapability TransformFeedback
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %main "main" %color %x0 %x1 %gl_VertexID %gl_InstanceID
+               OpExecutionMode %main Xfb
+               OpSource GLSL 450
+               OpDecorate %color Location 0
+               OpDecorate %color XfbBuffer 0
+               OpDecorate %color XfbStride 28
+               OpMemberDecorate %block0 0 Offset 0
+               OpMemberDecorate %block0 1 Offset 4
+               OpMemberDecorate %block0 2 Offset 20
+               OpDecorate %block0 Block
+               OpDecorate %x0 Location 0
+               OpDecorate %x0 XfbBuffer 0
+               OpDecorate %x0 XfbStride 28
+               OpMemberDecorate %block1 0 Offset 0
+               OpMemberDecorate %block1 1 Offset 4
+               OpMemberDecorate %block1 2 Offset 20
+               OpDecorate %block1 Block
+               OpDecorate %x1 Location 4
+               OpDecorate %x1 XfbBuffer 1
+               OpDecorate %x1 XfbStride 28
+               OpDecorate %gl_VertexID BuiltIn VertexId
+               OpDecorate %gl_InstanceID BuiltIn InstanceId
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+      %color = OpVariable %_ptr_Output_v4float Output
+    %float_0 = OpConstant %float 0
+         %11 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
+       %uint = OpTypeInt 32 0
+     %uint_2 = OpConstant %uint 2
+%_arr_float_uint_2 = OpTypeArray %float %uint_2
+     %block0 = OpTypeStruct %float %v4float %_arr_float_uint_2
+%_ptr_Output_block0 = OpTypePointer Output %block0
+         %x0 = OpVariable %_ptr_Output_block0 Output
+        %int = OpTypeInt 32 1
+      %int_0 = OpConstant %int 0
+    %float_1 = OpConstant %float 1
+%_ptr_Output_float = OpTypePointer Output %float
+      %int_1 = OpConstant %int 1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+    %float_4 = OpConstant %float 4
+    %float_5 = OpConstant %float 5
+         %28 = OpConstantComposite %v4float %float_2 %float_3 %float_4 %float_5
+      %int_2 = OpConstant %int 2
+    %float_6 = OpConstant %float 6
+    %float_7 = OpConstant %float 7
+     %block1 = OpTypeStruct %float %v4float %_arr_float_uint_2
+%_ptr_Output_block1 = OpTypePointer Output %block1
+         %x1 = OpVariable %_ptr_Output_block1 Output
+    %float_8 = OpConstant %float 8
+    %float_9 = OpConstant %float 9
+   %float_10 = OpConstant %float 10
+   %float_11 = OpConstant %float 11
+   %float_12 = OpConstant %float 12
+         %44 = OpConstantComposite %v4float %float_9 %float_10 %float_11 %float_12
+   %float_13 = OpConstant %float 13
+   %float_14 = OpConstant %float 14
+%_ptr_Input_int = OpTypePointer Input %int
+%gl_VertexID = OpVariable %_ptr_Input_int Input
+%gl_InstanceID = OpVariable %_ptr_Input_int Input
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+               OpStore %color %11
+         %22 = OpAccessChain %_ptr_Output_float %x0 %int_0
+               OpStore %22 %float_1
+         %29 = OpAccessChain %_ptr_Output_v4float %x0 %int_1
+               OpStore %29 %28
+         %32 = OpAccessChain %_ptr_Output_float %x0 %int_2 %int_0
+               OpStore %32 %float_6
+         %34 = OpAccessChain %_ptr_Output_float %x0 %int_2 %int_1
+               OpStore %34 %float_7
+         %39 = OpAccessChain %_ptr_Output_float %x1 %int_0
+               OpStore %39 %float_8
+         %45 = OpAccessChain %_ptr_Output_v4float %x1 %int_1
+               OpStore %45 %44
+         %47 = OpAccessChain %_ptr_Output_float %x1 %int_2 %int_0
+               OpStore %47 %float_13
+         %49 = OpAccessChain %_ptr_Output_float %x1 %int_2 %int_1
+               OpStore %49 %float_14
+               OpReturn
+               OpFunctionEnd
+
+[vertex shader]
+#version 450
+
+layout(xfb_buffer=0, xfb_offset=0) out block0 {
+    float f;
+    vec4 v;
+    float f2[2];
+} x0;
+
+layout(xfb_buffer=1, xfb_offset=0) out block1 {
+    float f;
+    vec4 v;
+    float f2[2];
+} x1;
+
+layout(location=0) out vec4 color;
+
+void main() {
+  color = vec4(0.0);
+
+  x0.f = 1.0;
+  x0.v = vec4(2.0, 3.0, 4.0, 5.0);
+  x0.f2[0] = 6.0;
+  x0.f2[1] = 7.0;
+
+  x1.f = 8.0;
+  x1.v = vec4(9.0, 10.0, 11.0, 12);
+  x1.f2[0] = 13.0;
+  x1.f2[1] = 14.0;
+}
+
+[test]
+# With arrays of blocks, each component uses a different buffer, see
+# GLSL spec section 4.4.2
+
+xfb buffer object 0 256
+xfb buffer object 1 256
+
+xfb draw arrays GL_POINTS 0 1
+
+verify query_object GL_PRIMITIVES_GENERATED 1
+verify query_object GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 1
+
+expected buffer 256
+
+expected buffer float 0 1.0
+expected buffer float 1 2.0
+expected buffer float 2 3.0
+expected buffer float 3 4.0
+expected buffer float 4 5.0
+expected buffer float 5 6.0
+expected buffer float 6 7.0
+probe xfb buffer float 0 7
+
+expected buffer 256 # Not really needed to call again, just to force a clean-up
+expected buffer float 0 8.0
+expected buffer float 1 9.0
+expected buffer float 2 10.0
+expected buffer float 3 11.0
+expected buffer float 4 12.0
+expected buffer float 5 13.0
+expected buffer float 6 14.0
+probe xfb buffer float 1 7
+
+verify program_query GL_TRANSFORM_FEEDBACK_VARYINGS 6
diff --git a/tests/spec/arb_gl_spirv/execution/xfb/vs_two_sets.shader_test b/tests/spec/arb_gl_spirv/execution/xfb/vs_two_sets.shader_test
new file mode 100644
index 000000000..b07fb62f1
--- /dev/null
+++ b/tests/spec/arb_gl_spirv/execution/xfb/vs_two_sets.shader_test
@@ -0,0 +1,160 @@ 
+# XFB test using two different sets (buffers), equivalent to
+# arb_enhanced_layouts transform-feedback-layout-qualifiers vs
+
+[require]
+SPIRV YES
+GL >= 3.3
+GLSL >= 4.50
+GL_ARB_gl_spirv
+
+[vertex shader spirv]
+; Automatically generated from the GLSL by shader_test_spirv.py. DO NOT EDIT
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 50
+; Schema: 0
+               OpCapability Shader
+               OpCapability TransformFeedback
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %main "main" %_ %x1_out %x2_out %x3_out %y1_out %y2_out %gl_VertexID %gl_InstanceID
+               OpExecutionMode %main Xfb
+               OpSource GLSL 450
+               OpSourceExtension "GL_ARB_enhanced_layouts"
+               OpName %_ ""
+               OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
+               OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize
+               OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance
+               OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance
+               OpDecorate %gl_PerVertex Block
+               OpDecorate %_ XfbBuffer 0
+               OpDecorate %_ XfbStride 24
+               OpDecorate %x1_out Location 0
+               OpDecorate %x1_out XfbBuffer 0
+               OpDecorate %x1_out XfbStride 24
+               OpDecorate %x1_out Offset 0
+               OpDecorate %x2_out Location 1
+               OpDecorate %x2_out XfbBuffer 0
+               OpDecorate %x2_out XfbStride 24
+               OpDecorate %x2_out Offset 4
+               OpDecorate %x3_out Location 3
+               OpDecorate %x3_out XfbBuffer 0
+               OpDecorate %x3_out XfbStride 24
+               OpDecorate %x3_out Offset 12
+               OpDecorate %y1_out Location 4
+               OpDecorate %y1_out XfbBuffer 2
+               OpDecorate %y1_out XfbStride 20
+               OpDecorate %y1_out Offset 0
+               OpDecorate %y2_out Location 5
+               OpDecorate %y2_out XfbBuffer 2
+               OpDecorate %y2_out XfbStride 20
+               OpDecorate %y2_out Offset 4
+               OpDecorate %gl_VertexID BuiltIn VertexId
+               OpDecorate %gl_InstanceID BuiltIn InstanceId
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+       %uint = OpTypeInt 32 0
+     %uint_1 = OpConstant %uint 1
+%_arr_float_uint_1 = OpTypeArray %float %uint_1
+%gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1
+%_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex
+          %_ = OpVariable %_ptr_Output_gl_PerVertex Output
+        %int = OpTypeInt 32 1
+      %int_0 = OpConstant %int 0
+    %float_0 = OpConstant %float 0
+         %17 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+%_ptr_Output_float = OpTypePointer Output %float
+     %x1_out = OpVariable %_ptr_Output_float Output
+    %float_1 = OpConstant %float 1
+     %uint_2 = OpConstant %uint 2
+%_arr_float_uint_2 = OpTypeArray %float %uint_2
+%_ptr_Output__arr_float_uint_2 = OpTypePointer Output %_arr_float_uint_2
+     %x2_out = OpVariable %_ptr_Output__arr_float_uint_2 Output
+    %float_2 = OpConstant %float 2
+      %int_1 = OpConstant %int 1
+    %float_3 = OpConstant %float 3
+    %v3float = OpTypeVector %float 3
+%_ptr_Output_v3float = OpTypePointer Output %v3float
+     %x3_out = OpVariable %_ptr_Output_v3float Output
+    %float_4 = OpConstant %float 4
+    %float_5 = OpConstant %float 5
+    %float_6 = OpConstant %float 6
+         %38 = OpConstantComposite %v3float %float_4 %float_5 %float_6
+     %y1_out = OpVariable %_ptr_Output_float Output
+    %float_7 = OpConstant %float 7
+     %y2_out = OpVariable %_ptr_Output_v4float Output
+    %float_8 = OpConstant %float 8
+    %float_9 = OpConstant %float 9
+   %float_10 = OpConstant %float 10
+   %float_11 = OpConstant %float 11
+         %46 = OpConstantComposite %v4float %float_8 %float_9 %float_10 %float_11
+%_ptr_Input_int = OpTypePointer Input %int
+%gl_VertexID = OpVariable %_ptr_Input_int Input
+%gl_InstanceID = OpVariable %_ptr_Input_int Input
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+         %19 = OpAccessChain %_ptr_Output_v4float %_ %int_0
+               OpStore %19 %17
+               OpStore %x1_out %float_1
+         %28 = OpAccessChain %_ptr_Output_float %x2_out %int_0
+               OpStore %28 %float_2
+         %31 = OpAccessChain %_ptr_Output_float %x2_out %int_1
+               OpStore %31 %float_3
+               OpStore %x3_out %38
+               OpStore %y1_out %float_7
+               OpStore %y2_out %46
+               OpReturn
+               OpFunctionEnd
+
+[vertex shader]
+#version 150
+#extension GL_ARB_enhanced_layouts: require
+
+layout(xfb_offset = 0) out float x1_out;
+layout(xfb_offset = 4) out float x2_out[2];
+layout(xfb_offset = 12) out vec3 x3_out;
+layout(xfb_buffer = 2) out;
+layout(xfb_offset = 0, xfb_buffer = 2) out float y1_out;
+layout(xfb_offset = 4) out vec4 y2_out;
+void main() {
+  gl_Position = vec4(0.0);
+  x1_out = 1.0;
+  x2_out[0] = 2.0;
+  x2_out[1] = 3.0;
+  x3_out = vec3(4.0, 5.0, 6.0);
+  y1_out = 7.0;
+  y2_out = vec4(8.0, 9.0, 10.0, 11.0);
+}
+
+[test]
+xfb buffer object 0 64
+xfb buffer object 2 64
+
+xfb draw arrays GL_POINTS 0 1
+
+verify query_object GL_PRIMITIVES_GENERATED 1
+verify query_object GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 1
+
+expected buffer 64
+expected buffer float 0 1.0
+expected buffer float 1 2.0
+expected buffer float 2 3.0
+expected buffer float 3 4.0
+expected buffer float 4 5.0
+expected buffer float 5 6.0
+
+probe xfb buffer float 0 5
+
+expected buffer 64 # Not really needed, just to clean.
+expected buffer float 0 7.0
+expected buffer float 1 8.0
+expected buffer float 2 9.0
+expected buffer float 3 10.0
+expected buffer float 4 11.0
+
+probe xfb buffer float 2 5
+verify program_query GL_TRANSFORM_FEEDBACK_VARYINGS 5
\ No newline at end of file
diff --git a/tests/spec/arb_gl_spirv/execution/xfb/vs_two_sets_ifc.shader_test b/tests/spec/arb_gl_spirv/execution/xfb/vs_two_sets_ifc.shader_test
new file mode 100644
index 000000000..06abbf01c
--- /dev/null
+++ b/tests/spec/arb_gl_spirv/execution/xfb/vs_two_sets_ifc.shader_test
@@ -0,0 +1,165 @@ 
+# XFB test using two sets, different buffer and structure, using an
+# output block.
+
+[require]
+SPIRV YES
+GL >= 3.3
+GLSL >= 4.50
+GL_ARB_gl_spirv
+
+[vertex shader spirv]
+; Automatically generated from the GLSL by shader_test_spirv.py. DO NOT EDIT
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 55
+; Schema: 0
+               OpCapability Shader
+               OpCapability TransformFeedback
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %main "main" %_ %__0 %__1 %gl_VertexID %gl_InstanceID
+               OpExecutionMode %main Xfb
+               OpSource GLSL 450
+               OpSourceExtension "GL_ARB_enhanced_layouts"
+               OpName %_ ""
+               OpName %__0 ""
+               OpName %__1 ""
+               OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
+               OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize
+               OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance
+               OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance
+               OpDecorate %gl_PerVertex Block
+               OpDecorate %_ XfbBuffer 0
+               OpDecorate %_ XfbStride 24
+               OpMemberDecorate %block 0 Offset 12
+               OpMemberDecorate %block 1 Offset 16
+               OpMemberDecorate %block 3 Offset 0
+               OpDecorate %block Block
+               OpDecorate %__0 Location 0
+               OpDecorate %__0 XfbBuffer 0
+               OpDecorate %__0 XfbStride 24
+               OpMemberDecorate %block2 0 Offset 0
+               OpMemberDecorate %block2 1 Offset 4
+               OpDecorate %block2 Block
+               OpDecorate %__1 Location 4
+               OpDecorate %__1 XfbBuffer 2
+               OpDecorate %__1 XfbStride 20
+               OpDecorate %gl_VertexID BuiltIn VertexId
+               OpDecorate %gl_InstanceID BuiltIn InstanceId
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+       %uint = OpTypeInt 32 0
+     %uint_1 = OpConstant %uint 1
+%_arr_float_uint_1 = OpTypeArray %float %uint_1
+%gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1
+%_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex
+          %_ = OpVariable %_ptr_Output_gl_PerVertex Output
+        %int = OpTypeInt 32 1
+      %int_0 = OpConstant %int 0
+    %float_0 = OpConstant %float 0
+         %17 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+    %v2float = OpTypeVector %float 2
+    %v3float = OpTypeVector %float 3
+      %block = OpTypeStruct %float %v2float %v3float %v3float
+%_ptr_Output_block = OpTypePointer Output %block
+        %__0 = OpVariable %_ptr_Output_block Output
+    %float_4 = OpConstant %float 4
+%_ptr_Output_float = OpTypePointer Output %float
+      %int_1 = OpConstant %int 1
+    %float_5 = OpConstant %float 5
+    %float_6 = OpConstant %float 6
+         %31 = OpConstantComposite %v2float %float_5 %float_6
+%_ptr_Output_v2float = OpTypePointer Output %v2float
+      %int_3 = OpConstant %int 3
+    %float_1 = OpConstant %float 1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+         %38 = OpConstantComposite %v3float %float_1 %float_2 %float_3
+%_ptr_Output_v3float = OpTypePointer Output %v3float
+     %block2 = OpTypeStruct %float %v4float
+%_ptr_Output_block2 = OpTypePointer Output %block2
+        %__1 = OpVariable %_ptr_Output_block2 Output
+    %float_7 = OpConstant %float 7
+    %float_8 = OpConstant %float 8
+    %float_9 = OpConstant %float 9
+   %float_10 = OpConstant %float 10
+   %float_11 = OpConstant %float 11
+         %50 = OpConstantComposite %v4float %float_8 %float_9 %float_10 %float_11
+%_ptr_Input_int = OpTypePointer Input %int
+%gl_VertexID = OpVariable %_ptr_Input_int Input
+%gl_InstanceID = OpVariable %_ptr_Input_int Input
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+         %19 = OpAccessChain %_ptr_Output_v4float %_ %int_0
+               OpStore %19 %17
+         %27 = OpAccessChain %_ptr_Output_float %__0 %int_0
+               OpStore %27 %float_4
+         %33 = OpAccessChain %_ptr_Output_v2float %__0 %int_1
+               OpStore %33 %31
+         %40 = OpAccessChain %_ptr_Output_v3float %__0 %int_3
+               OpStore %40 %38
+         %45 = OpAccessChain %_ptr_Output_float %__1 %int_0
+               OpStore %45 %float_7
+         %51 = OpAccessChain %_ptr_Output_v4float %__1 %int_1
+               OpStore %51 %50
+               OpReturn
+               OpFunctionEnd
+
+[vertex shader]
+#version 150
+#extension GL_ARB_enhanced_layouts: require
+
+out block {
+  layout(xfb_offset = 12) out float x1_out;
+  layout(xfb_offset = 16) out vec2 x2_out;
+  layout(xfb_buffer = 0) out vec3 not_captured;
+  layout(xfb_offset = 0) out vec3 x3_out;
+};
+layout(xfb_buffer = 2) out;
+layout(xfb_offset = 0) out block2 {
+  float y1_out;
+  vec4 y2_out;
+};
+
+void main() {
+  gl_Position = vec4(0.0);
+  x1_out = 4.0;
+  x2_out = vec2(5.0, 6.0);
+  x3_out = vec3(1.0, 2.0, 3.0);
+  y1_out = 7.0;
+  y2_out = vec4(8.0, 9.0, 10.0, 11.0);
+}
+
+[test]
+xfb buffer object 0 64
+xfb buffer object 2 64
+
+xfb draw arrays GL_POINTS 0 1
+
+verify query_object GL_PRIMITIVES_GENERATED 1
+verify query_object GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 1
+
+expected buffer 64
+expected buffer float 0 1.0
+expected buffer float 1 2.0
+expected buffer float 2 3.0
+expected buffer float 3 4.0
+expected buffer float 4 5.0
+expected buffer float 5 6.0
+
+probe xfb buffer float 0 5
+
+expected buffer 64 # Not really needed, just to clean.
+expected buffer float 0 7.0
+expected buffer float 1 8.0
+expected buffer float 2 9.0
+expected buffer float 3 10.0
+expected buffer float 4 11.0
+
+probe xfb buffer float 2 5
+
+verify program_query GL_TRANSFORM_FEEDBACK_VARYINGS 5
\ No newline at end of file
diff --git a/tests/spec/arb_gl_spirv/execution/xfb/vs_two_sets_struct.shader_test b/tests/spec/arb_gl_spirv/execution/xfb/vs_two_sets_struct.shader_test
new file mode 100644
index 000000000..f0030ae31
--- /dev/null
+++ b/tests/spec/arb_gl_spirv/execution/xfb/vs_two_sets_struct.shader_test
@@ -0,0 +1,173 @@ 
+# XFB test using two different buffers, mixed basic types with
+# structures.
+
+[require]
+SPIRV YES
+GL >= 3.3
+GLSL >= 4.50
+GL_ARB_gl_spirv
+
+[vertex shader spirv]
+; Automatically generated from the GLSL by shader_test_spirv.py. DO NOT EDIT
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 7
+; Bound: 57
+; Schema: 0
+               OpCapability Shader
+               OpCapability TransformFeedback
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %main "main" %_ %s1 %s2 %gl_VertexID %gl_InstanceID
+               OpExecutionMode %main Xfb
+               OpSource GLSL 450
+               OpSourceExtension "GL_ARB_enhanced_layouts"
+               OpName %_ ""
+               OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
+               OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize
+               OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance
+               OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance
+               OpDecorate %gl_PerVertex Block
+               OpDecorate %_ XfbBuffer 0
+               OpDecorate %_ XfbStride 24
+               OpDecorate %s1 Location 0
+               OpDecorate %s1 XfbBuffer 0
+               OpDecorate %s1 XfbStride 24
+               OpDecorate %s1 Offset 0
+               OpMemberDecorate %S2 0 Offset 0
+               OpMemberDecorate %S2 1 Offset 4
+               OpDecorate %s2 Location 6
+               OpDecorate %s2 XfbBuffer 2
+               OpDecorate %s2 XfbStride 20
+               OpDecorate %s2 Offset 0
+               OpDecorate %gl_VertexID BuiltIn VertexId
+               OpDecorate %gl_InstanceID BuiltIn InstanceId
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+       %uint = OpTypeInt 32 0
+     %uint_1 = OpConstant %uint 1
+%_arr_float_uint_1 = OpTypeArray %float %uint_1
+%gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1
+%_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex
+          %_ = OpVariable %_ptr_Output_gl_PerVertex Output
+        %int = OpTypeInt 32 1
+      %int_0 = OpConstant %int 0
+    %float_0 = OpConstant %float 0
+         %17 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+      %Array = OpTypeStruct %float
+     %uint_2 = OpConstant %uint 2
+%_arr_Array_uint_2 = OpTypeArray %Array %uint_2
+        %AoA = OpTypeStruct %_arr_Array_uint_2
+%_arr_AoA_uint_2 = OpTypeArray %AoA %uint_2
+          %S = OpTypeStruct %float %_arr_AoA_uint_2 %float
+%_ptr_Output_S = OpTypePointer Output %S
+         %s1 = OpVariable %_ptr_Output_S Output
+    %float_1 = OpConstant %float 1
+%_ptr_Output_float = OpTypePointer Output %float
+      %int_1 = OpConstant %int 1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+    %float_4 = OpConstant %float 4
+    %float_5 = OpConstant %float 5
+      %int_2 = OpConstant %int 2
+    %float_6 = OpConstant %float 6
+         %S2 = OpTypeStruct %float %v4float
+%_ptr_Output_S2 = OpTypePointer Output %S2
+         %s2 = OpVariable %_ptr_Output_S2 Output
+    %float_7 = OpConstant %float 7
+    %float_8 = OpConstant %float 8
+    %float_9 = OpConstant %float 9
+   %float_10 = OpConstant %float 10
+   %float_11 = OpConstant %float 11
+         %52 = OpConstantComposite %v4float %float_8 %float_9 %float_10 %float_11
+%_ptr_Input_int = OpTypePointer Input %int
+%gl_VertexID = OpVariable %_ptr_Input_int Input
+%gl_InstanceID = OpVariable %_ptr_Input_int Input
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+         %19 = OpAccessChain %_ptr_Output_v4float %_ %int_0
+               OpStore %19 %17
+         %30 = OpAccessChain %_ptr_Output_float %s1 %int_0
+               OpStore %30 %float_1
+         %33 = OpAccessChain %_ptr_Output_float %s1 %int_1 %int_0 %int_0 %int_0 %int_0
+               OpStore %33 %float_2
+         %35 = OpAccessChain %_ptr_Output_float %s1 %int_1 %int_0 %int_0 %int_1 %int_0
+               OpStore %35 %float_3
+         %37 = OpAccessChain %_ptr_Output_float %s1 %int_1 %int_1 %int_0 %int_0 %int_0
+               OpStore %37 %float_4
+         %39 = OpAccessChain %_ptr_Output_float %s1 %int_1 %int_1 %int_0 %int_1 %int_0
+               OpStore %39 %float_5
+         %42 = OpAccessChain %_ptr_Output_float %s1 %int_2
+               OpStore %42 %float_6
+         %47 = OpAccessChain %_ptr_Output_float %s2 %int_0
+               OpStore %47 %float_7
+         %53 = OpAccessChain %_ptr_Output_v4float %s2 %int_1
+               OpStore %53 %52
+               OpReturn
+               OpFunctionEnd
+
+[vertex shader]
+#version 150
+#extension GL_ARB_enhanced_layouts: require
+
+struct Array {
+  float x2_out;
+};
+struct AoA {
+  Array x2_Array[2];
+};
+struct S {
+  float x1_out;
+  AoA x2_AoA[2];
+  float x3_out;
+};
+layout(xfb_offset = 0) out S s1;
+layout(xfb_offset = 0, xfb_buffer = 2) out struct S2 {
+  float y1_out;
+  vec4 y2_out;
+} s2;
+void main() {
+  gl_Position = vec4(0.0);
+  s1.x1_out = 1.0;
+  s1.x2_AoA[0].x2_Array[0].x2_out = 2.0;
+  s1.x2_AoA[0].x2_Array[1].x2_out = 3.0;
+  s1.x2_AoA[1].x2_Array[0].x2_out = 4.0;
+  s1.x2_AoA[1].x2_Array[1].x2_out = 5.0;
+  s1.x3_out = 6.0;
+  s2.y1_out = 7.0;
+  s2.y2_out = vec4(8.0, 9.0, 10.0, 11.0);
+}
+
+[test]
+xfb buffer object 0 64
+xfb buffer object 2 64
+
+xfb draw arrays GL_POINTS 0 1
+
+verify query_object GL_PRIMITIVES_GENERATED 1
+verify query_object GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 1
+
+expected buffer 64
+
+expected buffer float 0 1.0
+expected buffer float 1 2.0
+expected buffer float 2 3.0
+expected buffer float 3 4.0
+expected buffer float 4 5.0
+expected buffer float 5 6.0
+
+probe xfb buffer float 0 5
+
+expected buffer 64 # Not really needed, just to clean.
+expected buffer float 0 7.0
+expected buffer float 1 8.0
+expected buffer float 2 9.0
+expected buffer float 3 10.0
+expected buffer float 4 11.0
+
+probe xfb buffer float 2 5
+
+verify program_query GL_TRANSFORM_FEEDBACK_VARYINGS 8
\ No newline at end of file