summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Peres <martin.peres@linux.intel.com>2015-03-18 06:47:15 -0400
committerMartin Peres <martin.peres@linux.intel.com>2015-04-07 12:08:04 +0300
commit8c1d2e8bac5d3526091ca911dd5d4ed0f859d392 (patch)
tree4b8c8981572572761cce801c1d1612c5da8ca0e5
parent2f47987bc8f40c46fc061cd34cabe92033e68201 (diff)
program_interface_query: add tests for querying the resources
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 Tested on NVIDIA's proprietary driver version 346.35. v2: Martin Peres - Fix the cs subtest to test PROGRAM_INPUT and not two times the OUTPUT v3: Review from Tapani - require GL_ARB_separate_shader_objects - cosmetic changes - add a comment in common.h to warn about the existence of strings in resource-query.c v4: Martin Peres - add a second subroutine in vs_sub v5: Martin Peres - introduce a patch output in the TCS outputs Signed-off-by: Martin Peres <martin.peres@linux.intel.com>
-rwxr-xr-xtests/all.py1
-rwxr-xr-x[-rw-r--r--]tests/spec/arb_program_interface_query/CMakeLists.gl.txt1
-rwxr-xr-xtests/spec/arb_program_interface_query/common.h278
-rwxr-xr-xtests/spec/arb_program_interface_query/resource-query.c741
4 files changed, 1021 insertions, 0 deletions
diff --git a/tests/all.py b/tests/all.py
index 8f5d11728..267cec1ef 100755
--- a/tests/all.py
+++ b/tests/all.py
@@ -2284,6 +2284,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
index 2028553cb..953579803 100644..100755
--- 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 000000000..8c6965c9a
--- /dev/null
+++ b/tests/spec/arb_program_interface_query/common.h
@@ -0,0 +1,278 @@
+/*
+ * 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__
+
+
+/* /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\
+ * If you modify any of these shaders, you need to modify the resources names in
+ * resource-query.c.
+ * /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\
+ */
+
+static const char vs_empty[] =
+ "#version 150\n"
+ "void main() {\n"
+ "}";
+
+static const char fs_empty[] =
+ "#version 150\n"
+ "void main() {\n"
+ "}";
+
+static const char vs_array[] =
+ "#version 150\n"
+ "in vec4 vs_input[2];\n"
+ "struct vs_struct {\n"
+ " vec4 hello;\n"
+ " vec4 world[2];\n"
+ "};\n"
+ "uniform vs_struct sa[2];\n"
+ "void main() {\n"
+ " gl_Position = vs_input[0] + sa[0].hello + sa[0].world[0];\n"
+ "}";
+
+static const char vs_aofa[] =
+ "#version 150\n"
+ "#extension GL_ARB_arrays_of_arrays : require\n"
+ "in vec4 vs_input2[2][2];\n"
+ "in vec4 vs_input3[2][2][2];\n"
+ "void main() {\n"
+ " gl_Position = vs_input2[0][0] + vs_input3[0][0][0];\n"
+ "}";
+
+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"
+ "subroutine (vs_offset) vec4 vss2() { 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[gl_MaxPatchVertices];\n"
+ "in vec4 tcs_input[gl_MaxPatchVertices];\n"
+ "patch out vec4 tcs_patch;\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 000000000..92b8cd83c
--- /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", "tcs_patch", "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", "vss2", 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_INPUT, "(cs)", NULL),
+ 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(15, 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( 2, 5, -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, 2, 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");
+ piglit_require_extension("GL_ARB_separate_shader_objects");
+}
+
+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;
+}