[Piglit] [PATCH 1/4] program_interface_query: add tests for querying the resources
Tapani Pälli
tapani.palli at intel.com
Fri Mar 27 01:21:56 PDT 2015
On 03/27/2015 10:12 AM, Martin Peres wrote:
> On 27/03/15 09:58, Tapani Pälli wrote:
>> Huh, first of all thanks for taking time to add the 'crosschecking'
>> (consistency_check) .. this test has impressive amount of subtests and
>> validation of the results!
>>
>> I did not find any errors from the subtests (excluding that one that
>> should be PROGRAM_INPUT not OUTPUT but that you already fixed, right?).
>
> Yes, it is already fixed in my tree and on freedesktop.
>
>>
>> Some nitpicking and comments on the layout below; I'd give r-b but I
>> want to hear if you will address some of this;
>>
>>
>> On 03/25/2015 06:01 PM, 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.peres at 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.
>>> + */
>>
>> Did you consider bundling these variable lists to common.h somehow
>> along with the corresponding shaders? It's not necessary but it would
>> be easier to modify later if there would be any additions or changes
>> to the shaders.
>
> I thought about it. It makes a lot of sense for the INPUT/OUTPUT tests
> but a bit less for the ones that combine the result of multiple stages,
> such as st_r_buffer. Also, it felt weird to have those in common.h when
> they are only needed in this test.
>
> I can move them if you feel like I should.
>
>>
>>> +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) \
>>> +}
>>> +
>>
>> Now this is a *BIG* table. I used some time yesterday trying to
>> prettify it with sed and what not and make it smaller but all attempts
>> tend to lead to a solution that looks worse and becomes unreadable. I
>> guess we just have to live with it, in the end I think it is very
>> readable in this form compared to for example scattering it as many
>> structs.
>
> I think so too.
>>
>>> +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),
>>> + 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;
>>
>> Some nasty repetition here but not sure if helper func or such is
>> worth the trouble (?)
>
> Not sure how you would want me to do this. Can you give me an example?
One way would be to have a common case for these where subroutine is set
true and shader is set with a helper function that does the
GL_x_SUBROUTINE -> GL_x_SHADER trick, as example 'shader_from_enum()'
but I don't know if in the end it would make this any shorter or offer
better life for the end users.
>>
>>> +
>>> + default:
>>> + /* There are no old APIs for this program interface */
>>> + return true;
>>> + }
>>> +
>>> + if (subroutine) {
>>> + old_idx = glGetSubroutineIndex(prog, shader,
>>> + name);
>>
>> name fits previous line
>
> True, fixed!
>>
>>> + 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);
>>
>> index and old_idx git previous line
> index fits, but not old_idx. I move index to the previous line.
>
>>
>>> + 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);
>>
>> You'll need to require GL_ARB_separate_shader_objects for this test
>> (not part of OpenGL 3.2).
>
> Good catch! I fixed it by adding a require in piglit_init().
>>
>>> + 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;
>>> +}
>>>
>
More information about the Piglit
mailing list