On 25/03/15 18:01, Martin Peres wrote:
This tests primarily glGetProgramInterfaceiv in various (potentially
tricky) program pipelines. All the calls are supposed to succeed as
this test is purely functional.

This test requires a OpenGL 3.2 core context but also has optional
subtests that depend on the following extensions:
  - GL_ARB_shader_atomic_counters
  - GL_ARB_shader_storage_buffer_object
  - GL_ARB_shader_subroutine
  - GL_ARB_tessellation_shader
  - GL_ARB_compute_shader
  - GL_ARB_shader_image_load_store

Signed-off-by: Martin Peres <martin.pe...@linux.intel.com>
---
  tests/all.py                                       |   1 +
  .../arb_program_interface_query/CMakeLists.gl.txt  |   1 +
  tests/spec/arb_program_interface_query/common.h    | 238 +++++++
  .../arb_program_interface_query/resource-query.c   | 741 +++++++++++++++++++++
  4 files changed, 981 insertions(+)
  mode change 100644 => 100755 tests/all.py
  mode change 100644 => 100755 
tests/spec/arb_program_interface_query/CMakeLists.gl.txt
  create mode 100755 tests/spec/arb_program_interface_query/common.h
  create mode 100755 tests/spec/arb_program_interface_query/resource-query.c

diff --git a/tests/all.py b/tests/all.py
old mode 100644
new mode 100755
index b2266db..f47e198
--- a/tests/all.py
+++ b/tests/all.py
@@ -2274,6 +2274,7 @@ with profile.group_manager(
          grouptools.join('spec', 'ARB_program_interface_query')) as g:
      g(['arb_program_interface_query-resource-location'], run_concurrent=False)
      g(['arb_program_interface_query-resource-index'], run_concurrent=False)
+    g(['arb_program_interface_query-resource-query'], run_concurrent=False)
# Group ARB_explicit_uniform_location
  with profile.group_manager(
diff --git a/tests/spec/arb_program_interface_query/CMakeLists.gl.txt 
b/tests/spec/arb_program_interface_query/CMakeLists.gl.txt
old mode 100644
new mode 100755
index 2028553..9535798
--- a/tests/spec/arb_program_interface_query/CMakeLists.gl.txt
+++ b/tests/spec/arb_program_interface_query/CMakeLists.gl.txt
@@ -11,3 +11,4 @@ link_libraries (
piglit_add_executable (arb_program_interface_query-resource-location resource-location.c)
  piglit_add_executable (arb_program_interface_query-resource-index 
resource-index.c)
+piglit_add_executable (arb_program_interface_query-resource-query 
resource-query.c)
diff --git a/tests/spec/arb_program_interface_query/common.h 
b/tests/spec/arb_program_interface_query/common.h
new file mode 100755
index 0000000..4e5ff01
--- /dev/null
+++ b/tests/spec/arb_program_interface_query/common.h
@@ -0,0 +1,238 @@
+/*
+ * Copyright © 2015 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#pragma once
+#ifndef __COMMON_H__
+#define __COMMON_H__
+
+static const char vs_std[] =
+       "#version 150\n"
+       "struct vs_struct {\n"
+       "  vec4 a[2];\n"
+       "};\n"
+       "uniform vs_uniform_block {\n"
+       "  vec4 vs_test;\n"
+       "};\n"
+       "uniform vs_struct sa[2];\n"
+       "in vec4 vs_input0;\n"
+       "in vec4 vs_input1;\n"
+       "void main() {\n"
+       "  gl_Position = vs_input0 * vs_test * vs_input1 + sa[0].a[1] +"
+       "                sa[1].a[1];\n"
+       "}";
+
+const char gs_std[] =
+       "#version 150\n"
+       "layout(triangles) in;\n"
+       "layout(triangle_strip, max_vertices = 6) out;\n"
+       "uniform gs_uniform_block {\n"
+       "  vec4 gs_test;\n"
+       "};\n"
+       "in vec4 gs_input[3];\n"
+       "out vec4 gs_output0;\n"
+       "void main() {\n"
+       "  for (int i = 0; i < 6; i++) {\n"
+       "          gl_Position = gs_input[i % 3] *"
+       "                        gl_in[i % 3].gl_Position * gs_test;\n"
+       "          gs_output0 = gs_input[0];\n"
+       "          EmitVertex();\n"
+       "  }\n"
+       "}\n";
+
+static const char fs_std[] =
+       "#version 150\n"
+       "uniform fs_uniform_block {"
+       "  vec4 fs_color;\n"
+       "  float fs_array[4];\n"
+       "};"
+       "in vec4 fs_input1;\n"
+       "out vec4 fs_output0;\n"
+       "out vec4 fs_output1;\n"
+       "void main() {\n"
+               "fs_output0 = fs_color * fs_input1 * fs_array[2];\n"
+               "fs_output1 = fs_color * fs_input1 * fs_array[3];\n"
+       "}";
+
+static const char vs_stor[] =
+       "#version 150\n"
+       "#extension GL_ARB_shader_storage_buffer_object : require\n"
+       "buffer vs_buffer_block { vec4 vs_buf_var; };"
+       "out vec4 vs_output1;\n"
+       "void main() {\n"
+               "vs_output1 = vs_buf_var;\n"
+       "}";
+
+static const char gs_stor[] =
+       "#version 150\n"
+       "#extension GL_ARB_shader_storage_buffer_object : require\n"
+       "layout(triangles) in;\n"
+       "layout(triangle_strip, max_vertices = 6) out;\n"
+       "buffer gs_buffer_block { vec4 gs_buf_var; };"
+       "in vec4 vs_output1[3];\n"
+       "void main() {\n"
+       "  for (int i = 0; i < 6; i++) {\n"
+       "          gl_Position = vs_output1[i % 3] * gs_buf_var;\n"
+       "          EmitVertex();\n"
+       "  }\n"
+       "}";
+
+static const char fs_stor[] =
+       "#version 150\n"
+       "#extension GL_ARB_shader_storage_buffer_object : require\n"
+       "buffer fs_buffer_block { vec4 fs_buf_var; };\n"
+       "out vec4 fs_output0;\n"
+       "void main() {\n"
+       "  fs_output0 = fs_buf_var;\n"
+       "}";
+
+static const char vs_atom[] =
+       "#version 150\n"
+       "#extension GL_ARB_shader_atomic_counters : require\n"
+       "layout (binding=0) uniform atomic_uint vs_counter;\n"
+       "void main() {\n"
+       "  atomicCounterIncrement(vs_counter);\n"
+       "}";
+
+static const char gs_atom[] =
+       "#version 150\n"
+       "#extension GL_ARB_shader_atomic_counters : require\n"
+       "layout(triangles) in;\n"
+       "layout(triangle_strip, max_vertices = 6) out;\n"
+       "layout (binding=1) uniform atomic_uint gs_counter;\n"
+       "void main() {\n"
+       "  atomicCounterIncrement(gs_counter);\n"
+       "}";
+
+static const char fs_atom[] =
+       "#version 150\n"
+       "#extension GL_ARB_shader_atomic_counters : require\n"
+       "layout (binding=2) uniform atomic_uint fs_counter;\n"
+       "void main() {\n"
+       "  atomicCounterIncrement(fs_counter);\n"
+       "}";
+
+static const char vs_tfv[] =
+       "#version 150\n"
+       "in vec4 vs_input0;\n"
+       "out vec4 vs_output1;\n"
+       "out vec4 outValue;\n"
+       "void main() {\n"
+       "  vs_output1 = vs_input0;\n"
+       "  outValue = vs_input0;\n"
+       "}";
+
+static const char vs_sub[] =
+       "#version 150\n"
+       "#extension GL_ARB_shader_subroutine : require\n"
+       "in vec4 vs_input0;\n"
+       "subroutine vec4 vs_offset();\n"
+       "subroutine uniform vs_offset VERTEX;\n"
+       "subroutine (vs_offset) vec4 vss() { return vec4(1, 0, 0, 0); }\n"
+       "void main() {\n"
+       "  gl_Position = vs_input0 + VERTEX();\n"
+       "}";
+
+static const char gs_sub[] =
+       "#version 150\n"
+       "#extension GL_ARB_shader_subroutine : require\n"
+       "layout(triangles) in;\n"
+       "layout(triangle_strip, max_vertices = 6) out;\n"
+       "subroutine vec4 gs_offset();\n"
+       "subroutine uniform gs_offset GEOMETRY;\n"
+       "subroutine (gs_offset) vec4 gss() { return vec4(1, 0, 0, 0); }\n"
+       "in vec4 vs_output1[3];\n"
+       "void main() {\n"
+       "  for (int i = 0; i < 6; i++) {\n"
+       "          gl_Position = vs_output1[i % 3] + GEOMETRY();\n"
+       "          EmitVertex();\n"
+       "  }\n"
+       "}";
+
+static const char fs_sub[] =
+       "#version 150\n"
+       "#extension GL_ARB_shader_subroutine : require\n"
+       "subroutine vec4 fs_offset();\n"
+       "subroutine uniform fs_offset FRAGMENT;\n"
+       "subroutine (fs_offset) vec4 fss() { return vec4(1, 0, 0, 1); }\n"
+       "out vec4 fs_output0;\n"
+       "void main() {\n"
+       "  fs_output0 = FRAGMENT();\n"
+       "}";
+
+static const char tcs_sub[] =
+       "#version 150\n"
+       "#extension GL_ARB_shader_subroutine : require\n"
+       "#extension GL_ARB_tessellation_shader : require\n"
+       "layout(vertices = 3) out;\n"
+       "uniform tcs_uniform_block {\n"
+       "  vec4 tcs_test;\n"
+       "};\n"
+       "out vec4 tcs_output[1];\n"
+       "in vec4 tcs_input[gl_MaxPatchVertices];\n"
+       "subroutine vec4 tcs_offset();\n"
+       "subroutine uniform tcs_offset TESS_CONTROL;\n"
+       "subroutine (tcs_offset) vec4 tcss() { return vec4(1, 0, 0, 0); }\n"
+       "void main() {\n"
+       "  gl_out[gl_InvocationID].gl_Position = tcs_test +"
+       "                                        gl_in[0].gl_Position *"
+       "                                        TESS_CONTROL();\n"
+       "  tcs_output[gl_InvocationID] = tcs_input[0] + TESS_CONTROL();\n"
+       "}";
+
+static const char tes_sub[] =
+       "#version 150\n"
+       "#extension GL_ARB_shader_subroutine : require\n"
+       "#extension GL_ARB_tessellation_shader : require\n"
+       "layout(triangles) in;\n"
+       "uniform tes_uniform_block {\n"
+       "  vec4 tes_test;\n"
+       "};\n"
+       "out vec4 tes_output[1];\n"
+       "in vec4 tes_input[gl_MaxPatchVertices];\n"
+       "subroutine vec4 tes_offset();\n"
+       "subroutine uniform tes_offset TESS_EVALUATION;\n"
+       "subroutine (tes_offset) vec4 tess() { return vec4(1, 0, 0, 0); }\n"
+       "void main() {\n"
+       "  gl_Position = tes_test + gl_in[0].gl_Position +"
+       "                TESS_EVALUATION();\n"
+       "  tes_output[0] = tes_input[0] + TESS_EVALUATION();\n"
+       "}";
+
+static const char cs_sub[] =
+       "#version 150\n"
+       "#extension GL_ARB_shader_subroutine : require\n"
+       "#extension GL_ARB_shader_image_load_store : require\n"
+       "#extension GL_ARB_compute_shader : require\n"
+       "layout(local_size_x = 4) in;\n"
+       "uniform cs_uniform_block {\n"
+       "  uniform vec4 cs_test;\n"
+       "};\n"
+       "layout(size4x32) uniform image2D tex;\n"
+       "subroutine vec4 com_offset();\n"
+       "subroutine uniform com_offset COMPUTE;\n"
+       "subroutine (com_offset) vec4 css() { return vec4(1, 0, 0, 0); }\n"
+       "void main() {\n"
+       "  imageStore(tex, ivec2(0.0), cs_test + COMPUTE());\n"
+       "}";
+
+#endif
diff --git a/tests/spec/arb_program_interface_query/resource-query.c 
b/tests/spec/arb_program_interface_query/resource-query.c
new file mode 100755
index 0000000..469e54d
--- /dev/null
+++ b/tests/spec/arb_program_interface_query/resource-query.c
@@ -0,0 +1,741 @@
+/*
+ * Copyright © 2015 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/**
+ * \file resource-query.c
+ *
+ * Tests querying resources.
+ *
+ * From the GL_ARB_program_interface_query spec:
+ *      "The command
+ *
+ *      void GetProgramInterfaceiv(uint program, enum programInterface,
+ *                                 enum pname, int *params);
+ *
+ *      queries a property of the interface <programInterface> in program
+ *      <program>, returning its value in <params>.  The property to return is
+ *      specified by <pname>.
+ *
+ *      If <pname> is ACTIVE_RESOURCES, the value returned is the number of
+ *      resources in the active resource list for <programInterface>. If the
+ *      list of active resources for <programInterface> is empty, zero is
+ *      returned.
+ *
+ *      If <pname> is MAX_NAME_LENGTH, the value returned is the length of the
+ *      longest active name string for an active resource in 
<programInterface>.
+ *      This length includes an extra character for the null terminator. If
+ *      the list of active resources for <programInterface> is empty, zero is
+ *      returned.  The error INVALID_OPERATION is generated if
+ *      <programInterface> is ATOMIC_COUNTER_BUFFER, since active atomic 
counter
+ *      buffer resources are not assigned name strings.
+ *
+ *      If <pname> is MAX_NUM_ACTIVE_VARIABLES, the value returned is the 
number
+ *      of active variables belonging to the interface block or atomic counter
+ *      buffer resource in <programInterface> with the most active variables.
+ *      If the list of active resources for <programInterface> is empty, zero 
is
+ *      returned.  The error INVALID_OPERATION is generated if
+ *      <programInterface> is not UNIFORM_BLOCK, ATOMIC_COUNTER_BUFFER, or
+ *      SHADER_STORAGE_BLOCK.
+ *
+ *      If <pname> is MAX_NUM_COMPATIBLE_SUBROUTINES, the value returned is the
+ *      number of compatible subroutines belonging to the active subroutine
+ *      uniform in <programInterface> with the most compatible subroutines. If
+ *      the list of active resources for <programInterface> is empty, zero is
+ *      returned.  The error INVALID_OPERATION is generated unless
+ *      <programInterface> is VERTEX_SUBROUTINE_UNIFORM,
+ *      TESS_CONTROL_SUBROUTINE_UNIFORM, TESS_EVALUATION_SUBROUTINE_UNIFORM,
+ *      GEOMETRY_SUBROUTINE_UNIFORM, FRAGMENT_SUBROUTINE_UNIFORM, or
+ *      COMPUTE_SUBROUTINE_UNIFORM.
+ *
+ *      The command
+ *
+ *      uint GetProgramResourceIndex(uint program, enum programInterface,
+ *                                   const char *name);
+ *
+ *      returns the unsigned integer index assigned to a resource named <name>
+ *      in the interface type <programInterface> of program object <program>.
+ *      The error INVALID_ENUM is generated if <programInterface> is
+ *      ATOMIC_COUNTER_BUFFER, since active atomic counter buffer resources are
+ *      not assigned name strings.
+ *
+ *      If <name> exactly matches the name string of one of the active 
resources
+ *      for <programInterface>, the index of the matched resource is returned.
+ *      Additionally, if <name> would exactly match the name string of an 
active
+ *      resource if "[0]" were appended to <name>, the index of the matched
+ *      resource is returned.  Otherwise, <name> is considered not to be the
+ *      name of an active resource, and INVALID_INDEX is returned.  Note that 
if
+ *      an interface enumerates a single active resource list entry for an 
array
+ *      variable (e.g., "a[0]"), a <name> identifying any array element other
+ *      than the first (e.g., "a[1]") is not considered to match.
+ *
+ *      For the interface TRANSFORM_FEEDBACK_VARYING, the value INVALID_INDEX
+ *      should be returned when querying the index assigned to the special 
names
+ *      "gl_NextBuffer", "gl_SkipComponents1", "gl_SkipComponents2",
+ *      "gl_SkipComponents3", and "gl_SkipComponents4".
+ *
+ *      The command
+ *
+ *      void GetProgramResourceName(uint program, enum programInterface,
+ *                                  uint index, sizei bufSize, sizei *length,
+ *                                  char *name);
+ *
+ *      returns the name string assigned to the single active resource with an
+ *      index of <index> in the interface <programInterface> of program object
+ *      <program>.  The error INVALID_VALUE is generated if <index> is greater
+ *      than or equal to the number of entries in the active resource list for
+ *      <programInterface>.  The error INVALID_ENUM is generated if
+ *      <programInterface> is ATOMIC_COUNTER_BUFFER, since active atomic 
counter
+ *      buffer resources are not assigned name strings.
+ *
+ *      The name string assigned to the active resource identified by <index> 
is
+ *      returned as a null-terminated string in <name>.  The actual number of
+ *      characters written into <name>, excluding the null terminator, is
+ *      returned in <length>.  If <length> is NULL, no length is returned. The
+ *      maximum number of characters that may be written into <name>, including
+ *      the null terminator, is specified by <bufSize>.  If the length of the
+ *      name string (including the null terminator) is greater than <bufSize>,
+ *      the first <bufSize>-1 characters of the name string will be written to
+ *      <name>, followed by a null terminator.  If <bufSize> is zero, no error
+ *      will be generated but no characters will be written to <name>.  The
+ *      length of the longest name string for <programInterface>, including a
+ *      null terminator, can be queried by calling GetProgramInterfaceiv with a
+ *      <pname> of MAX_NAME_LENGTH.
+ */
+
+#include "piglit-util-gl.h"
+#include "common.h"
+
+PIGLIT_GL_TEST_CONFIG_BEGIN
+
+       config.supports_gl_core_version = 32;
+
+PIGLIT_GL_TEST_CONFIG_END
+
+/* Naming conventions, from the GL_ARB_program_interface_query extension:
+ *
+ * "When building a list of active variable or interface blocks, resources
+ * with aggregate types (such as arrays or structures) may produce multiple
+ * entries in the active resource list for the corresponding interface.
+ * Additionally, each active variable, interface block, or subroutine in the
+ * list is assigned an associated name string that can be used by
+ * applications to refer to the resources.  For interfaces involving
+ * variables, interface blocks, or subroutines, the entries of active
+ * resource lists are generated as follows:
+ *
+ *  * For an active variable declared as a single instance of a basic type,
+ *    a single entry will be generated, using the variable name from the
+ *    shader source.
+ *
+ *  * For an active variable declared as an array of basic types, a single
+ *    entry will be generated, with its name string formed by concatenating
+ *    the name of the array and the string "[0]".
+ *
+ *  * For an active variable declared as a structure, a separate entry will
+ *    be generated for each active structure member.  The name of each entry
+ *    is formed by concatenating the name of the structure, the "."
+ *    character, and the name of the structure member.  If a structure
+ *    member to enumerate is itself a structure or array, these enumeration
+ *    rules are applied recursively.
+ *
+ *  * For an active variable declared as an array of an aggregate data type
+ *    (structures or arrays), a separate entry will be generated for each
+ *    active array element, unless noted immediately below.  The name of
+ *    each entry is formed by concatenating the name of the array, the "["
+ *    character, an integer identifying the element number, and the "]"
+ *    character.  These enumeration rules are applied recursively, treating
+ *    each enumerated array element as a separate active variable.
+ *
+ *  * For an active shader storage block member declared as an array, an
+ *    entry will be generated only for the first array element, regardless
+ *    of its type.  For arrays of aggregate types, the enumeration rules are
+ *    applied recursively for the single enumerated array element.
+ *
+ *  * For an active interface block not declared as an array of block
+ *    instances, a single entry will be generated, using the block name from
+ *    the shader source.
+ *
+ *  * For an active interface block declared as an array of instances,
+ *    separate entries will be generated for each active instance.  The name
+ *    of the instance is formed by concatenating the block name, the "["
+ *    character, an integer identifying the instance number, and the "]"
+ *    character.
+ *
+ *  * For an active subroutine, a single entry will be generated, using the
+ *    subroutine name from the shader source.
+ *
+ * When an integer array element or block instance number is part of the name
+ * string, it will be specified in decimal form without a "+" or "-" sign or
+ * any extra leading zeroes.  Additionally, the name string will not include
+ * white space anywhere in the string.
+ */
+static const char *st_r_uniform[] = {"vs_test", "gs_test", "fs_color",
+                                    "fs_array[0]", "sa[0].a[0]", "sa[1].a[0]",
+                                    NULL};
+static const char *st_r_tess_uniform[] = {"tcs_test", "tes_test", NULL};
+static const char *st_r_cs_uniform[] = {"cs_test", "tex", NULL};
+static const char *st_r_uniform_block[] = {"vs_uniform_block",
+                                           "gs_uniform_block",
+                                           "fs_uniform_block", NULL};
+static const char *st_r_tess_uniform_block[] = {"tcs_uniform_block",
+                                                "tes_uniform_block", NULL};
+static const char *st_r_cs_uniform_block[] = {"cs_uniform_block", NULL};
+static const char *st_r_in_vs[] = {"vs_input0", "vs_input1", NULL};
+static const char *st_r_in_gs[] = {"gs_input", "gl_Position", NULL};
+static const char *st_r_in_fs[] = {"fs_input1", NULL};
+static const char *st_r_in_tes[] = {"tes_input", "gl_Position", NULL};
+static const char *st_r_in_tcs[] = {"tcs_input", "gl_Position", NULL};
+static const char *st_r_out_vs[] = {"gl_Position", NULL};
+static const char *st_r_out_gs[] = {"gs_output0", "gl_Position", NULL};
+static const char *st_r_out_fs[] = {"fs_output0", "fs_output1", NULL};
+static const char *st_r_out_tes[] = {"tes_output[0]", "gl_Position", NULL};
+static const char *st_r_out_tcs[] = {"tcs_output", "gl_Position",
+                                     "gl_BackColor", "gl_BackSecondaryColor",
+                                     "gl_ClipDistance[0]", 
"gl_CullDistance[0]",
+                                     "gl_FogFragCoord", "gl_FrontColor",
+                                     "gl_FrontSecondaryColor", "gl_Layer",
+                                     "gl_PointSize", "gl_TexCoord[0]",
+                                     "gl_ViewportIndex", "gl_ViewportMask[0]",
+                                     NULL};
+static const char *st_r_buffer[] = {"vs_buf_var", "gs_buf_var", "fs_buf_var",
+                                    NULL};
+static const char *st_r_stor_block[] = {"vs_buffer_block", "gs_buffer_block",
+                                        "fs_buffer_block", NULL};
+static const char *st_r_tf_varying[] = {"gl_Position", "gs_output0", NULL};
+static const char *st_r_vs_sub[] = {"vss", NULL};
+static const char *st_r_gs_sub[] = {"gss", NULL};
+static const char *st_r_fs_sub[] = {"fss", NULL};
+static const char *st_r_cs_sub[] = {"css", NULL};
+static const char *st_r_tcs_sub[] = {"tcss", NULL};
+static const char *st_r_tes_sub[] = {"tess", NULL};
+static const char *st_r_vs_sub_uni[] = {"VERTEX", NULL};
+static const char *st_r_gs_sub_uni[] = {"GEOMETRY", NULL};
+static const char *st_r_fs_sub_uni[] = {"FRAGMENT", NULL};
+static const char *st_r_cs_sub_uni[] = {"COMPUTE", NULL};
+static const char *st_r_tcs_sub_uni[] = {"TESS_CONTROL", NULL};
+static const char *st_r_tes_sub_uni[] = {"TESS_EVALUATION", NULL};
+
+/* From the GL_ARB_program_interface_query extension:
+ *
+ * "The GL provides a number of commands to query properties of the interfaces
+ * of a program object.  Each such command accepts a <programInterface>
+ * token, identifying a specific interface.  The supported values for
+ * <programInterface> are as follows:
+ *  * UNIFORM corresponds to the set of active uniform variables (section
+ *    2.14.7) used by <program>.
+ *
+ *  * UNIFORM_BLOCK corresponds to the set of active uniform blocks (section
+ *    2.14.7) used by <program>.
+ *
+ *  * ATOMIC_COUNTER_BUFFER corresponds to the set of active atomic counter
+ *    buffer binding points (section 2.14.7) used by <program>.
+
+ *  * PROGRAM_INPUT corresponds to the set of active input variables used by
+ *    the first shader stage of <program>.  If <program> includes multiple
+ *    shader stages, input variables from any shader stage other than the
+ *    first will not be enumerated.
+ *
+ *  * PROGRAM_OUTPUT corresponds to the set of active output variables
+ *    (section 2.14.11) used by the last shader stage of <program>.  If
+ *    <program> includes multiple shader stages, output variables from any
+ *    shader stage other than the last will not be enumerated.
+ *
+ *  * VERTEX_SUBROUTINE, TESS_CONTROL_SUBROUTINE,
+ *    TESS_EVALUATION_SUBROUTINE, GEOMETRY_SUBROUTINE, FRAGMENT_SUBROUTINE,
+ *    and COMPUTE_SUBROUTINE correspond to the set of active subroutines for
+ *    the vertex, tessellation control, tessellation evaluation, geometry,
+ *    fragment, and compute shader stages of <program>, respectively
+ *    (section 2.14.8).
+ *
+ *  * VERTEX_SUBROUTINE_UNIFORM, TESS_CONTROL_SUBROUTINE_UNIFORM,
+ *    TESS_EVALUATION_SUBROUTINE_UNIFORM, GEOMETRY_SUBROUTINE_UNIFORM,
+ *    FRAGMENT_SUBROUTINE_UNIFORM, and COMPUTE_SUBROUTINE_UNIFORM correspond
+ *    to the set of active subroutine uniform variables used by the vertex,
+ *    tessellation control, tessellation evaluation, geometry, fragment, and
+ *    compute shader stages of <program>, respectively (section 2.14.8).
+ *
+ *  * TRANSFORM_FEEDBACK_VARYING corresponds to the set of output variables
+ *    in the last non-fragment stage of <program> that would be captured
+ *    when transform feedback is active (section 2.20.2).
+ *
+ *  * BUFFER_VARIABLE corresponds to the set of active buffer variables (see
+ *    the ARB_shader_storage_buffer_object extension) used by <program>.
+ *
+ *  * SHADER_STORAGE_BLOCK corresponds to the set of active shader storage
+ *    blocks (see the ARB_shader_storage_buffer_object extension) used by
+ *    <program>."
+ *
+ * Additionally, from the GL_ARB_program_interface_query extension:
+ *
+ * "For the ATOMIC_COUNTER_BUFFER interface, the list of active buffer binding
+ * points is built by identifying each unique binding point associated with
+ * one or more active atomic counter uniform variables.  Active atomic
+ * counter buffers do not have an associated name string.
+ *
+ * For the UNIFORM, PROGRAM_INPUT, PROGRAM_OUTPUT, and
+ * TRANSFORM_FEEDBACK_VARYING interfaces, the active resource list will
+ * include all active variables for the interface, including any active
+ * built-in variables.
+ *
+ * For PROGRAM_INPUT and PROGRAM_OUTPUT interfaces for shaders that recieve
+ * or produce patch primitves, the active resource list will include both
+ * per-vertex and per-patch inputs and outputs.
+ *
+ * For the TRANSFORM_FEEDBACK_VARYING interface, the active resource list
+ * will entries for the special varying names gl_NextBuffer,
+ * gl_SkipComponents1, gl_SkipComponents2, gl_SkipComponents3, and
+ * gl_SkipComponents4 (section 2.14.11).  These variables are used to control
+ * how varying values are written to transform feedback buffers.  When
+ * enumerating the properties of such resources, these variables are
+ * considered to have a TYPE of NONE and an ARRAY_SIZE of 0 (gl_NextBuffer),
+ * 1, 2, 3, and 4, respectively."
+ */
+
+struct subtest_t {
+       GLenum programInterface;
+
+       const char *programInterface_str;
+       const char *active_resources_str;
+       const char *max_length_name_str;
+       const char *max_num_active_str;
+       const char *max_num_compat_sub_str;
+
+       /* set to -1 to disable the test */
+       int active_resources;
+       int max_length_name;
+       int max_num_active;
+       int max_num_compat_sub;
+
+       const char *vs_text;
+       const char *gs_text;
+       const char *fs_text;
+       const char *tcs_text;
+       const char *tes_text;
+       const char *cs_text;
+
+       const char **resources;
+};
+
+#define ST(active_r, max_len, max_num_active, max_num_compat_sub, vs, tcs, \
+          tes, gs, fs, cs, name, suffix, resources) { \
+       (name), #name suffix, #name suffix " active resources", \
+       #name suffix " max length name", \
+       #name suffix " max num active", \
+       #name suffix " max num compat sub", \
+       (active_r), (max_len), (max_num_active), (max_num_compat_sub), \
+       (vs), (gs), (fs), (tcs), (tes), (cs), (resources) \
+}
+
+static const struct subtest_t subtests[] = {
+ ST( 6, 12, -1, -1,  vs_std,    NULL,    NULL,  gs_std,  fs_std,   NULL, GL_UNIFORM, 
"(vs,gs,fs)", st_r_uniform),
+ ST( 2,  9, -1, -1,    NULL, tcs_sub, tes_sub,    NULL,    NULL,   NULL, GL_UNIFORM, 
"(tes,tcs)", st_r_tess_uniform),
+ ST( 2,  8, -1, -1,    NULL,    NULL,    NULL,    NULL,    NULL, cs_sub, GL_UNIFORM, 
"(cs)", st_r_cs_uniform),
+ ST( 3, 17,  2, -1,  vs_std,    NULL,    NULL,  gs_std,  fs_std,   NULL, 
GL_UNIFORM_BLOCK, "(vs,gs,fs)", st_r_uniform_block),
+ ST( 2, 18, -1, -1,    NULL, tcs_sub, tes_sub,    NULL,    NULL,   NULL, 
GL_UNIFORM_BLOCK, "(tcs,tes)", st_r_tess_uniform_block),
+ ST( 1, 17, -1, -1,    NULL,    NULL,    NULL,    NULL,    NULL, cs_sub, 
GL_UNIFORM_BLOCK, "(cs)", st_r_cs_uniform_block),
+ ST( 2, 10, -1, -1,  vs_std,    NULL,    NULL,    NULL,    NULL,   NULL, 
GL_PROGRAM_INPUT, "(vs)", st_r_in_vs),
+ ST( 2, 12, -1, -1,    NULL,    NULL,    NULL,  gs_std,    NULL,   NULL, 
GL_PROGRAM_INPUT, "(gs)", st_r_in_gs),
+ ST( 1, 10, -1, -1,    NULL,    NULL,    NULL,    NULL,  fs_std,   NULL, 
GL_PROGRAM_INPUT, "(fs)", st_r_in_fs),
+ ST( 2, 10, -1, -1,  vs_std,    NULL,    NULL,    NULL,  fs_std,   NULL, 
GL_PROGRAM_INPUT, "(vs,fs)", st_r_in_vs),
+ ST( 2, 10, -1, -1,  vs_std,    NULL,    NULL,  gs_std,    NULL,   NULL, 
GL_PROGRAM_INPUT, "(vs,gs)", st_r_in_vs),
+ ST( 2, 12, -1, -1,    NULL,    NULL,    NULL,  gs_std,  fs_std,   NULL, 
GL_PROGRAM_INPUT, "(gs,fs)", st_r_in_gs),
+ ST( 2, 10, -1, -1,  vs_std,    NULL,    NULL,  gs_std,  fs_std,   NULL, 
GL_PROGRAM_INPUT, "(vs,gs,fs)", st_r_in_vs),
+ ST( 2, 12, -1, -1,    NULL,    NULL, tes_sub,    NULL,    NULL,   NULL, 
GL_PROGRAM_INPUT, "(tes)", st_r_in_tes),
+ ST( 2, 12, -1, -1,    NULL, tcs_sub,    NULL,    NULL,    NULL,   NULL, 
GL_PROGRAM_INPUT, "(tcs)", st_r_in_tcs),
+ ST( 2, 12, -1, -1,    NULL, tcs_sub, tes_sub,    NULL,    NULL,   NULL, 
GL_PROGRAM_INPUT, "(tcs,tes)", st_r_in_tcs),
+ ST( 2, 10, -1, -1,  vs_std, tcs_sub, tes_sub,    NULL,    NULL,   NULL, 
GL_PROGRAM_INPUT, "(vs,tcs,tes)", st_r_in_vs),
+ ST( 0,  0, -1, -1,    NULL,    NULL,    NULL,    NULL,    NULL, cs_sub, 
GL_PROGRAM_OUTPUT, "(cs)", NULL),
The above line should read GL_PROGRAM_INPUT instead of GL_PROGRAM_OUTPU.
+ ST( 1, 12, -1, -1,  vs_std,    NULL,    NULL,    NULL,    NULL,   NULL, 
GL_PROGRAM_OUTPUT, "(vs)", st_r_out_vs),
+ ST( 2, 12, -1, -1,    NULL,    NULL,    NULL,  gs_std,    NULL,   NULL, 
GL_PROGRAM_OUTPUT, "(gs)", st_r_out_gs),
+ ST( 2, 11, -1, -1,    NULL,    NULL,    NULL,    NULL,  fs_std,   NULL, 
GL_PROGRAM_OUTPUT, "(fs)", st_r_out_fs),
+ ST( 2, 11, -1, -1,  vs_std,    NULL,    NULL,    NULL,  fs_std,   NULL, 
GL_PROGRAM_OUTPUT, "(vs,fs)", st_r_out_fs),
+ ST( 2, 12, -1, -1,  vs_std,    NULL,    NULL,  gs_std,    NULL,   NULL, 
GL_PROGRAM_OUTPUT, "(vs,gs)", st_r_out_gs),
+ ST( 2, 11, -1, -1,    NULL,    NULL,    NULL,  gs_std,  fs_std,   NULL, 
GL_PROGRAM_OUTPUT, "(gs,fs)", st_r_out_fs),
+ ST( 2, 11, -1, -1,  vs_std,    NULL,    NULL,  gs_std,  fs_std,   NULL, 
GL_PROGRAM_OUTPUT, "(vs,gs,fs)", st_r_out_fs),
+ ST( 2, 14, -1, -1,    NULL,    NULL, tes_sub,    NULL,    NULL,   NULL, 
GL_PROGRAM_OUTPUT, "(tes)", st_r_out_tes),
+ ST(14, 23, -1, -1,    NULL, tcs_sub,    NULL,    NULL,    NULL,   NULL, 
GL_PROGRAM_OUTPUT, "(tcs)", st_r_out_tcs),
+ ST( 2, 14, -1, -1,    NULL, tcs_sub, tes_sub,    NULL,    NULL,   NULL, 
GL_PROGRAM_OUTPUT, "(tcs,tes)", st_r_out_tes),
+ ST( 2, 12, -1, -1,    NULL, tcs_sub, tes_sub,  gs_std,    NULL,   NULL, 
GL_PROGRAM_OUTPUT, "(tcs,tes,gs)", st_r_out_gs),
+ ST( 0,  0, -1, -1,    NULL,    NULL,    NULL,    NULL,    NULL, cs_sub, 
GL_PROGRAM_OUTPUT, "(cs)", st_r_cs_sub),
+ ST( 3, 11, -1, -1, vs_stor,    NULL,    NULL, gs_stor, fs_stor,   NULL, 
GL_BUFFER_VARIABLE, "", st_r_buffer),
+ ST( 3, 16,  1, -1, vs_stor,    NULL,    NULL, gs_stor, fs_stor,   NULL, 
GL_SHADER_STORAGE_BLOCK, "", st_r_stor_block),
+ ST( 3, -1,  1, -1, vs_atom,    NULL,    NULL, gs_atom, fs_atom,   NULL, 
GL_ATOMIC_COUNTER_BUFFER, "", NULL),
+ ST( 2, 12, -1, -1,  vs_std,    NULL,    NULL,  gs_std,    NULL,   NULL, 
GL_TRANSFORM_FEEDBACK_VARYING, "", st_r_tf_varying),
+ ST( 1,  4, -1, -1,  vs_sub,    NULL,    NULL,    NULL,    NULL,   NULL, 
GL_VERTEX_SUBROUTINE, "", st_r_vs_sub),
+ ST( 1,  4, -1, -1,  vs_sub,    NULL,    NULL,  gs_sub,    NULL,   NULL, 
GL_GEOMETRY_SUBROUTINE, "", st_r_gs_sub),
+ ST( 1,  4, -1, -1,  vs_sub,    NULL,    NULL,  gs_sub,  fs_sub,   NULL, 
GL_FRAGMENT_SUBROUTINE, "", st_r_fs_sub),
+ ST( 1,  4, -1, -1,    NULL,    NULL,    NULL,    NULL,    NULL, cs_sub, 
GL_COMPUTE_SUBROUTINE, "", st_r_cs_sub),
+ ST( 1,  5, -1, -1,  vs_sub,    tcs_sub, NULL,    NULL,    NULL,   NULL, 
GL_TESS_CONTROL_SUBROUTINE, "", st_r_tcs_sub),
+ ST( 1,  5, -1, -1,  vs_sub,    NULL, tes_sub,    NULL,    NULL,   NULL, 
GL_TESS_EVALUATION_SUBROUTINE, "", st_r_tes_sub),
+ ST( 1,  7, -1,  1,  vs_sub,    NULL,    NULL,    NULL,    NULL,   NULL, 
GL_VERTEX_SUBROUTINE_UNIFORM, "", st_r_vs_sub_uni),
+ ST( 1,  9, -1,  1,  vs_sub,    NULL,    NULL,  gs_sub,    NULL,   NULL, 
GL_GEOMETRY_SUBROUTINE_UNIFORM, "", st_r_gs_sub_uni),
+ ST( 1,  9, -1,  1,  vs_sub,    NULL,    NULL,  gs_sub,  fs_sub,   NULL, 
GL_FRAGMENT_SUBROUTINE_UNIFORM, "", st_r_fs_sub_uni),
+ ST( 1, 13, -1,  1,  vs_sub,    tcs_sub, NULL,    NULL,    NULL,   NULL, 
GL_TESS_CONTROL_SUBROUTINE_UNIFORM, "", st_r_tcs_sub_uni),
+ ST( 1, 16, -1,  1,  vs_sub,    NULL, tes_sub,    NULL,    NULL,   NULL, 
GL_TESS_EVALUATION_SUBROUTINE_UNIFORM, "", st_r_tes_sub_uni),
+ ST( 1,  8, -1,  1,    NULL,    NULL,    NULL,    NULL,    NULL, cs_sub, 
GL_COMPUTE_SUBROUTINE_UNIFORM, "", st_r_cs_sub_uni),
+};
+
+static void
+check_pname(GLuint prog, GLenum programInterface, GLenum pname, bool *pass,
+           const char *subtest, int expected_value)
+{
+       int value;
+
+       if (expected_value < 0) {
+               return;
+       }
+
+       glGetProgramInterfaceiv(prog, programInterface, pname, &value);
+       if (!piglit_check_gl_error(GL_NO_ERROR)) {
+               printf("   Latest error generated while running '%s'\n",
+                      subtest);
+       }
+
+       if (value != expected_value) {
+               fprintf(stderr, "'%s' expected %i but got %i\n", subtest,
+                       expected_value, value);
+               *pass = false;
+       }
+}
+
+static bool
+is_resource_in_list(const char **list, const char *resource, int index,
+                   bool check_order)
+{
+       int i = 0;
+       while (list && list[i]) {
+               if (strcmp(list[i], resource) == 0) {
+                       return !check_order || index == i;
+               }
+               i++;
+       }
+
+       return false;
+}
+
+static bool
+consistency_check(GLuint prog, GLenum programInterface, const char *name,
+                 GLint index)
+{
+       bool subroutine = false;
+       const GLchar *names[] = { name };
+       GLuint old_idx = 0xdeadcafe;
+       GLenum shader;
+
+       /* Validate result against old API. */
+       switch (programInterface) {
+       case GL_UNIFORM:
+               glGetUniformIndices(prog, 1, names, &old_idx);
+               piglit_check_gl_error(GL_NO_ERROR);
+               break;
+
+       case GL_UNIFORM_BLOCK:
+               old_idx = glGetUniformBlockIndex(prog, name);
+               piglit_check_gl_error(GL_NO_ERROR);
+               break;
+
+       case GL_VERTEX_SUBROUTINE:
+               shader = GL_VERTEX_SHADER;
+               subroutine = true;
+               break;
+
+       case GL_TESS_CONTROL_SUBROUTINE:
+               shader = GL_TESS_CONTROL_SHADER;
+               subroutine = true;
+               break;
+
+       case GL_TESS_EVALUATION_SUBROUTINE:
+               shader = GL_TESS_EVALUATION_SHADER;
+               subroutine = true;
+               break;
+
+       case GL_GEOMETRY_SUBROUTINE:
+               shader = GL_GEOMETRY_SHADER;
+               subroutine = true;
+               break;
+
+       case GL_FRAGMENT_SUBROUTINE:
+               shader = GL_FRAGMENT_SHADER;
+               subroutine = true;
+               break;
+
+       case GL_COMPUTE_SUBROUTINE:
+               shader = GL_COMPUTE_SHADER;
+               subroutine = true;
+               break;
+
+       default:
+               /* There are no old APIs for this program interface */
+               return true;
+       }
+
+       if (subroutine) {
+               old_idx = glGetSubroutineIndex(prog, shader,
+                                                name);
+               piglit_check_gl_error(GL_NO_ERROR);
+       }
+
+       if (index != old_idx) {
+               printf("Index inconsistent with the old API: %i vs %i\n",
+                      index, old_idx);
+               return false;
+       } else
+               return true;
+}
+
+
+static void
+validate_resources(const struct subtest_t st, GLuint prog, bool *pass)
+{
+       GLsizei max_size = 0, size, i;
+       char * name;
+
+       /* Do not run the test for GL_ATOMIC_COUNTER_BUFFER.
+        * From the GL_ARB_program_interface_query extension:
+        *
+        * "The error INVALID_OPERATION is generated if <programInterface>
+        * is ATOMIC_COUNTER_BUFFER, since active atomic counter buffer
+        * resources are not assigned name strings."
+        */
+       if (st.programInterface == GL_ATOMIC_COUNTER_BUFFER)
+               return;
+
+       name = (char *) malloc(st.max_length_name);
+       for (i = 0; i < st.active_resources; i++) {
+               GLuint index;
+
+               glGetProgramResourceName(prog, st.programInterface,
+                                        i, st.max_length_name,
+                                        &size, name);
+               piglit_check_gl_error(GL_NO_ERROR);
+
+               /* keep track of the maximum size */
+               if (size > max_size) {
+                       max_size = size;
+               }
+
+               /* Check the names. Transform feedback requires the order to be
+                * the same as the one given in glTransformFeedbackVaryings.
+                * From the GL_ARB_program_interface_query extension:
+                *
+                * "The order of the active resource list is
+                * implementation-dependent for all interfaces except for
+                * TRANSFORM_FEEDBACK_VARYING. For TRANSFORM_FEEDBACK_VARYING,
+                * the active resource list will use the variable order
+                * specified in the the most recent call to
+                * TransformFeedbackVaryings before the last call to
+                * LinkProgram.
+                */
+               if (st.resources && !is_resource_in_list(st.resources, name, i,
+                       st.programInterface == GL_TRANSFORM_FEEDBACK_VARYING)) {
+                       fprintf(stderr, "Resource '%s' not found in '%s' "
+                                       "resource list or found at the wrong "
+                                       "index\n", name,
+                               st.programInterface_str);
+                       *pass = false;
+               }
+
+               /* Check the position of the arguments and see if it matches
+                * with the current position we are in.
+                */
+               index = glGetProgramResourceIndex(prog, st.programInterface,
+                                                 name);
+               if (index != i) {
+                       fprintf(stderr, "%s: Resource '%s' is not at the "
+                                       "position reported by "
+                                       "glGetProgramResourceIndex (%i instead "
+                                       "of %i)\n",
+                               st.programInterface_str, name, index, i);
+                       *pass = false;
+               }
+
+               /* check the equivalence with the old API */
+               if (!consistency_check(prog, st.programInterface, name,
+                                      index)) {
+                       *pass = false;
+               }
+       }
+       free(name);
+
+       /* glGetProgramResourceName does not count the NULL terminator as part
+        * of the size contrarily to glGetProgramInterfaceiv.
+        * From the GL_ARB_program_interface_query extension:
+        *
+        * "void GetProgramInterfaceiv(uint program, enum programInterface,
+        *                             enum pname, int *params);
+        * [...]
+        * If <pname> is MAX_NAME_LENGTH, the value returned is the length of
+        * the longest active name string for an active resource in
+        * <programInterface>. This length includes an extra character for the
+        * null terminator."
+        *
+        * "void GetProgramResourceName(uint program, enum programInterface,
+        *                              uint index, sizei bufSize,
+        *                              sizei *length, char *name);
+        * [...]
+        * The actual number of characters written into <name>, excluding the
+        * null terminator, is returned in <length>."
+        */
+       if (max_size != MAX2(0, st.max_length_name - 1)) {
+               fprintf(stderr, "'%s actual max length' expected %i but got "
+                               "%i\n", st.programInterface_str,
+                       st.max_length_name - 1, max_size);
+               *pass = false;
+       }
+}
+
+static bool
+check_extensions(const struct subtest_t st)
+{
+       if (st.programInterface == GL_ATOMIC_COUNTER_BUFFER &&
+           !piglit_is_extension_supported("GL_ARB_shader_atomic_counters")) {
+               return false;
+       }
+
+       if ((st.programInterface == GL_BUFFER_VARIABLE ||
+           st.programInterface == GL_SHADER_STORAGE_BLOCK) &&
+           
!piglit_is_extension_supported("GL_ARB_shader_storage_buffer_object")) {
+               return false;
+       }
+
+       if ((st.programInterface == GL_VERTEX_SUBROUTINE ||
+            st.programInterface == GL_GEOMETRY_SUBROUTINE ||
+            st.programInterface == GL_FRAGMENT_SUBROUTINE ||
+            st.programInterface == GL_COMPUTE_SUBROUTINE ||
+            st.programInterface == GL_VERTEX_SUBROUTINE_UNIFORM ||
+            st.programInterface == GL_GEOMETRY_SUBROUTINE_UNIFORM ||
+            st.programInterface == GL_FRAGMENT_SUBROUTINE_UNIFORM ||
+            st.programInterface == GL_COMPUTE_SUBROUTINE_UNIFORM ||
+            st.programInterface == GL_TESS_CONTROL_SUBROUTINE ||
+            st.programInterface == GL_TESS_EVALUATION_SUBROUTINE ||
+            st.programInterface == GL_TESS_CONTROL_SUBROUTINE_UNIFORM ||
+            st.programInterface == GL_TESS_EVALUATION_SUBROUTINE_UNIFORM ||
+            st.programInterface == GL_COMPUTE_SUBROUTINE_UNIFORM) &&
+            !piglit_is_extension_supported("GL_ARB_shader_subroutine")) {
+                return false;
+        }
+
+       if ((st.programInterface == GL_TESS_CONTROL_SUBROUTINE ||
+            st.programInterface == GL_TESS_EVALUATION_SUBROUTINE ||
+            st.programInterface == GL_TESS_CONTROL_SUBROUTINE_UNIFORM ||
+            st.programInterface == GL_TESS_EVALUATION_SUBROUTINE_UNIFORM ||
+            st.tcs_text || st.tes_text) &&
+            !piglit_is_extension_supported("GL_ARB_tessellation_shader")) {
+                return false;
+        }
+
+       if ((st.programInterface == GL_COMPUTE_SUBROUTINE ||
+            st.programInterface == GL_COMPUTE_SUBROUTINE_UNIFORM ||
+            st.cs_text) &&
+            !piglit_is_extension_supported("GL_ARB_compute_shader") &&
+            !piglit_is_extension_supported("GL_ARB_shader_image_load_store")) {
+                return false;
+        }
+
+       return true;
+}
+
+static void
+run_subtest(const struct subtest_t st, bool *pass)
+{
+       enum piglit_result result;
+       bool local_pass = true;
+       GLuint prog;
+
+       if (!check_extensions(st)) {
+               result = PIGLIT_SKIP;
+               goto report_result;
+       }
+
+       prog = piglit_build_simple_program_unlinked_multiple_shaders(
+                                       GL_VERTEX_SHADER,   st.vs_text,
+                                       GL_GEOMETRY_SHADER, st.gs_text,
+                                       GL_FRAGMENT_SHADER, st.fs_text,
+                                       GL_TESS_CONTROL_SHADER, st.tcs_text,
+                                       GL_TESS_EVALUATION_SHADER, st.tes_text,
+                                       GL_COMPUTE_SHADER, st.cs_text,
+                                       0);
+
+       if (st.programInterface == GL_TRANSFORM_FEEDBACK_VARYING) {
+               glTransformFeedbackVaryings(prog, 2, st_r_tf_varying,
+                                           GL_INTERLEAVED_ATTRIBS);
+               piglit_check_gl_error(GL_NO_ERROR);
+       }
+
+       /* force the compiler not to optimise away inputs/outputs */
+       glProgramParameteri(prog, GL_PROGRAM_SEPARABLE, GL_TRUE);
+       piglit_check_gl_error(GL_NO_ERROR);
+
+       glLinkProgram(prog);
+       if (!piglit_link_check_status(prog)) {
+               glDeleteProgram(prog);
+               result = PIGLIT_FAIL;
+               *pass = false;
+               goto report_result;
+       }
+
+       check_pname(prog, st.programInterface, GL_ACTIVE_RESOURCES,
+                   &local_pass, st.active_resources_str, st.active_resources);
+
+       check_pname(prog, st.programInterface, GL_MAX_NAME_LENGTH,
+                   &local_pass, st.max_length_name_str, st.max_length_name);
+
+       /* do not test fetching the names if the previous tests failed */
+       if (local_pass) {
+               validate_resources(st, prog, &local_pass);
+       }
+
+       check_pname(prog, st.programInterface, GL_MAX_NUM_ACTIVE_VARIABLES,
+                   &local_pass, st.max_num_active_str, st.max_num_active);
+
+       check_pname(prog, st.programInterface,
+                   GL_MAX_NUM_COMPATIBLE_SUBROUTINES, &local_pass,
+                   st.max_num_compat_sub_str, st.max_num_compat_sub);
+
+       glDeleteProgram(prog);
+
+       *pass = *pass && local_pass;
+       result = local_pass ? PIGLIT_PASS : PIGLIT_FAIL;
+
+report_result:
+       piglit_report_subtest_result(result, "%s", st.programInterface_str);
+}
+
+void
+piglit_init(int argc, char **argv)
+{
+       piglit_require_extension("GL_ARB_program_interface_query");
+}
+
+enum piglit_result
+piglit_display(void)
+{
+       bool pass = true;
+       int i;
+
+       /* run all the getprograminterfaceiv tests */
+       for (i = 0; i < sizeof(subtests) / sizeof(struct subtest_t); i++) {
+               run_subtest(subtests[i], &pass);
+       }
+
+       return pass ? PIGLIT_PASS : PIGLIT_FAIL;
+}

_______________________________________________
Piglit mailing list
Piglit@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/piglit

Reply via email to