fix the spelling in whole piglit
[piglit.git] / tests / spec / arb_program_interface_query / resource-query.c
blob1ea96d97091d73f9fbb28dddc8672f5d6f210c12
1 /*
2 * Copyright © 2015 Intel Corporation
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
24 /**
25 * \file resource-query.c
27 * Tests querying resources.
29 * From the GL_ARB_program_interface_query spec:
30 * "The command
32 * void GetProgramInterfaceiv(uint program, enum programInterface,
33 * enum pname, int *params);
35 * queries a property of the interface <programInterface> in program
36 * <program>, returning its value in <params>. The property to return is
37 * specified by <pname>.
39 * If <pname> is ACTIVE_RESOURCES, the value returned is the number of
40 * resources in the active resource list for <programInterface>. If the
41 * list of active resources for <programInterface> is empty, zero is
42 * returned.
44 * If <pname> is MAX_NAME_LENGTH, the value returned is the length of the
45 * longest active name string for an active resource in <programInterface>.
46 * This length includes an extra character for the null terminator. If
47 * the list of active resources for <programInterface> is empty, zero is
48 * returned. The error INVALID_OPERATION is generated if
49 * <programInterface> is ATOMIC_COUNTER_BUFFER, since active atomic counter
50 * buffer resources are not assigned name strings.
52 * If <pname> is MAX_NUM_ACTIVE_VARIABLES, the value returned is the number
53 * of active variables belonging to the interface block or atomic counter
54 * buffer resource in <programInterface> with the most active variables.
55 * If the list of active resources for <programInterface> is empty, zero is
56 * returned. The error INVALID_OPERATION is generated if
57 * <programInterface> is not UNIFORM_BLOCK, ATOMIC_COUNTER_BUFFER, or
58 * SHADER_STORAGE_BLOCK.
60 * If <pname> is MAX_NUM_COMPATIBLE_SUBROUTINES, the value returned is the
61 * number of compatible subroutines belonging to the active subroutine
62 * uniform in <programInterface> with the most compatible subroutines. If
63 * the list of active resources for <programInterface> is empty, zero is
64 * returned. The error INVALID_OPERATION is generated unless
65 * <programInterface> is VERTEX_SUBROUTINE_UNIFORM,
66 * TESS_CONTROL_SUBROUTINE_UNIFORM, TESS_EVALUATION_SUBROUTINE_UNIFORM,
67 * GEOMETRY_SUBROUTINE_UNIFORM, FRAGMENT_SUBROUTINE_UNIFORM, or
68 * COMPUTE_SUBROUTINE_UNIFORM.
70 * The command
72 * uint GetProgramResourceIndex(uint program, enum programInterface,
73 * const char *name);
75 * returns the unsigned integer index assigned to a resource named <name>
76 * in the interface type <programInterface> of program object <program>.
77 * The error INVALID_ENUM is generated if <programInterface> is
78 * ATOMIC_COUNTER_BUFFER, since active atomic counter buffer resources are
79 * not assigned name strings.
81 * If <name> exactly matches the name string of one of the active resources
82 * for <programInterface>, the index of the matched resource is returned.
83 * Additionally, if <name> would exactly match the name string of an active
84 * resource if "[0]" were appended to <name>, the index of the matched
85 * resource is returned. Otherwise, <name> is considered not to be the
86 * name of an active resource, and INVALID_INDEX is returned. Note that if
87 * an interface enumerates a single active resource list entry for an array
88 * variable (e.g., "a[0]"), a <name> identifying any array element other
89 * than the first (e.g., "a[1]") is not considered to match.
91 * For the interface TRANSFORM_FEEDBACK_VARYING, the value INVALID_INDEX
92 * should be returned when querying the index assigned to the special names
93 * "gl_NextBuffer", "gl_SkipComponents1", "gl_SkipComponents2",
94 * "gl_SkipComponents3", and "gl_SkipComponents4".
96 * The command
98 * void GetProgramResourceName(uint program, enum programInterface,
99 * uint index, sizei bufSize, sizei *length,
100 * char *name);
102 * returns the name string assigned to the single active resource with an
103 * index of <index> in the interface <programInterface> of program object
104 * <program>. The error INVALID_VALUE is generated if <index> is greater
105 * than or equal to the number of entries in the active resource list for
106 * <programInterface>. The error INVALID_ENUM is generated if
107 * <programInterface> is ATOMIC_COUNTER_BUFFER, since active atomic counter
108 * buffer resources are not assigned name strings.
110 * The name string assigned to the active resource identified by <index> is
111 * returned as a null-terminated string in <name>. The actual number of
112 * characters written into <name>, excluding the null terminator, is
113 * returned in <length>. If <length> is NULL, no length is returned. The
114 * maximum number of characters that may be written into <name>, including
115 * the null terminator, is specified by <bufSize>. If the length of the
116 * name string (including the null terminator) is greater than <bufSize>,
117 * the first <bufSize>-1 characters of the name string will be written to
118 * <name>, followed by a null terminator. If <bufSize> is zero, no error
119 * will be generated but no characters will be written to <name>. The
120 * length of the longest name string for <programInterface>, including a
121 * null terminator, can be queried by calling GetProgramInterfaceiv with a
122 * <pname> of MAX_NAME_LENGTH.
125 #include "piglit-util-gl.h"
126 #include "common.h"
128 PIGLIT_GL_TEST_CONFIG_BEGIN
130 config.supports_gl_core_version = 32;
131 config.khr_no_error_support = PIGLIT_NO_ERRORS;
133 PIGLIT_GL_TEST_CONFIG_END
135 /* Naming conventions, from the GL_ARB_program_interface_query extension:
137 * "When building a list of active variable or interface blocks, resources
138 * with aggregate types (such as arrays or structures) may produce multiple
139 * entries in the active resource list for the corresponding interface.
140 * Additionally, each active variable, interface block, or subroutine in the
141 * list is assigned an associated name string that can be used by
142 * applications to refer to the resources. For interfaces involving
143 * variables, interface blocks, or subroutines, the entries of active
144 * resource lists are generated as follows:
146 * * For an active variable declared as a single instance of a basic type,
147 * a single entry will be generated, using the variable name from the
148 * shader source.
150 * * For an active variable declared as an array of basic types, a single
151 * entry will be generated, with its name string formed by concatenating
152 * the name of the array and the string "[0]".
154 * * For an active variable declared as a structure, a separate entry will
155 * be generated for each active structure member. The name of each entry
156 * is formed by concatenating the name of the structure, the "."
157 * character, and the name of the structure member. If a structure
158 * member to enumerate is itself a structure or array, these enumeration
159 * rules are applied recursively.
161 * * For an active variable declared as an array of an aggregate data type
162 * (structures or arrays), a separate entry will be generated for each
163 * active array element, unless noted immediately below. The name of
164 * each entry is formed by concatenating the name of the array, the "["
165 * character, an integer identifying the element number, and the "]"
166 * character. These enumeration rules are applied recursively, treating
167 * each enumerated array element as a separate active variable.
169 * * For an active shader storage block member declared as an array, an
170 * entry will be generated only for the first array element, regardless
171 * of its type. For arrays of aggregate types, the enumeration rules are
172 * applied recursively for the single enumerated array element.
174 * * For an active interface block not declared as an array of block
175 * instances, a single entry will be generated, using the block name from
176 * the shader source.
178 * * For an active interface block declared as an array of instances,
179 * separate entries will be generated for each active instance. The name
180 * of the instance is formed by concatenating the block name, the "["
181 * character, an integer identifying the instance number, and the "]"
182 * character.
184 * * For an active subroutine, a single entry will be generated, using the
185 * subroutine name from the shader source.
187 * When an integer array element or block instance number is part of the name
188 * string, it will be specified in decimal form without a "+" or "-" sign or
189 * any extra leading zeroes. Additionally, the name string will not include
190 * white space anywhere in the string.
192 static const char *st_r_uniform[] = {"vs_test", "gs_test", "fs_color",
193 "fs_array[0]",
194 "fs_array_uniform_block.fs_color",
195 "fs_array_uniform_block.fs_array[0]",
196 "sa[0].a[0]", "sa[1].a[0]",
197 NULL};
198 static const char *st_r_tess_uniform[] = {"tcs_test", "tes_test", NULL};
199 static const char *st_r_cs_uniform[] = {"cs_test", "tex", NULL};
200 static const char *st_r_uniform_block[] = {"vs_uniform_block",
201 "gs_uniform_block",
202 "fs_uniform_block",
203 "fs_array_uniform_block[0]",
204 "fs_array_uniform_block[1]",
205 "fs_array_uniform_block[2]",
206 "fs_array_uniform_block[3]",
207 NULL};
208 static const char *st_r_tess_uniform_block[] = {"tcs_uniform_block",
209 "tes_uniform_block", NULL};
210 static const char *st_r_cs_uniform_block[] = {"cs_uniform_block", NULL};
211 static const char *st_r_in_vs[] = {"vs_input0", "vs_input1", NULL};
212 static const char *st_r_in_gs[] = {"vs_output1[0]", "gl_PerVertex.gl_Position", NULL};
213 static const char *st_r_in_fs[] = {"fs_input1", NULL};
214 static const char *st_r_in_tes[] = {"tes_input1[0]", "gl_PerVertex.gl_Position", NULL};
215 static const char *st_r_in_tcs[] = {"vs_output1[0]",
216 "gl_InvocationID",
217 "gl_PerVertex.gl_Position",
218 NULL};
219 static const char *st_r_out_vs[] = {"vs_output1", "gl_Position", NULL};
220 static const char *st_r_out_gs[] = {"fs_input1", "gl_Position", NULL};
221 static const char *st_r_out_fs[] = {"fs_output0", "fs_output1", NULL};
222 static const char *st_r_out_tes[] = {"vs_output1", "gl_Position", NULL};
223 static const char *st_r_out_tcs[] = {"tes_input1[0]", "tcs_patch",
224 "gl_PerVertex.gl_Position",
225 NULL};
226 static const char *st_r_buffer[] = {"vs_buf_var", "gs_buf_var", "fs_buf_var",
227 NULL};
228 static const char *st_r_stor_block[] = {"vs_buffer_block", "gs_buffer_block",
229 "fs_buffer_block", NULL};
230 static const char *st_r_tf_varying[] = {"gl_Position", "fs_input1", NULL};
231 static const char *st_r_vs_sub[] = {"vss", "vss2", NULL};
232 static const char *st_r_gs_sub[] = {"gss", NULL};
233 static const char *st_r_fs_sub[] = {"fss", NULL};
234 static const char *st_r_cs_sub[] = {"css", NULL};
235 static const char *st_r_tcs_sub[] = {"tcss", NULL};
236 static const char *st_r_tes_sub[] = {"tess", NULL};
237 static const char *st_r_vs_sub_uni[] = {"VERTEX", NULL};
238 static const char *st_r_gs_sub_uni[] = {"GEOMETRY", NULL};
239 static const char *st_r_fs_sub_uni[] = {"FRAGMENT", NULL};
240 static const char *st_r_cs_sub_uni[] = {"COMPUTE", NULL};
241 static const char *st_r_tcs_sub_uni[] = {"TESS_CONTROL", NULL};
242 static const char *st_r_tes_sub_uni[] = {"TESS_EVALUATION", NULL};
244 /* From the GL_ARB_program_interface_query extension:
246 * "The GL provides a number of commands to query properties of the interfaces
247 * of a program object. Each such command accepts a <programInterface>
248 * token, identifying a specific interface. The supported values for
249 * <programInterface> are as follows:
250 * * UNIFORM corresponds to the set of active uniform variables (section
251 * 2.14.7) used by <program>.
253 * * UNIFORM_BLOCK corresponds to the set of active uniform blocks (section
254 * 2.14.7) used by <program>.
256 * * ATOMIC_COUNTER_BUFFER corresponds to the set of active atomic counter
257 * buffer binding points (section 2.14.7) used by <program>.
259 * * PROGRAM_INPUT corresponds to the set of active input variables used by
260 * the first shader stage of <program>. If <program> includes multiple
261 * shader stages, input variables from any shader stage other than the
262 * first will not be enumerated.
264 * * PROGRAM_OUTPUT corresponds to the set of active output variables
265 * (section 2.14.11) used by the last shader stage of <program>. If
266 * <program> includes multiple shader stages, output variables from any
267 * shader stage other than the last will not be enumerated.
269 * * VERTEX_SUBROUTINE, TESS_CONTROL_SUBROUTINE,
270 * TESS_EVALUATION_SUBROUTINE, GEOMETRY_SUBROUTINE, FRAGMENT_SUBROUTINE,
271 * and COMPUTE_SUBROUTINE correspond to the set of active subroutines for
272 * the vertex, tessellation control, tessellation evaluation, geometry,
273 * fragment, and compute shader stages of <program>, respectively
274 * (section 2.14.8).
276 * * VERTEX_SUBROUTINE_UNIFORM, TESS_CONTROL_SUBROUTINE_UNIFORM,
277 * TESS_EVALUATION_SUBROUTINE_UNIFORM, GEOMETRY_SUBROUTINE_UNIFORM,
278 * FRAGMENT_SUBROUTINE_UNIFORM, and COMPUTE_SUBROUTINE_UNIFORM correspond
279 * to the set of active subroutine uniform variables used by the vertex,
280 * tessellation control, tessellation evaluation, geometry, fragment, and
281 * compute shader stages of <program>, respectively (section 2.14.8).
283 * * TRANSFORM_FEEDBACK_VARYING corresponds to the set of output variables
284 * in the last non-fragment stage of <program> that would be captured
285 * when transform feedback is active (section 2.20.2).
287 * * BUFFER_VARIABLE corresponds to the set of active buffer variables (see
288 * the ARB_shader_storage_buffer_object extension) used by <program>.
290 * * SHADER_STORAGE_BLOCK corresponds to the set of active shader storage
291 * blocks (see the ARB_shader_storage_buffer_object extension) used by
292 * <program>."
294 * Additionally, from the GL_ARB_program_interface_query extension:
296 * "For the ATOMIC_COUNTER_BUFFER interface, the list of active buffer binding
297 * points is built by identifying each unique binding point associated with
298 * one or more active atomic counter uniform variables. Active atomic
299 * counter buffers do not have an associated name string.
301 * For the UNIFORM, PROGRAM_INPUT, PROGRAM_OUTPUT, and
302 * TRANSFORM_FEEDBACK_VARYING interfaces, the active resource list will
303 * include all active variables for the interface, including any active
304 * built-in variables.
306 * For PROGRAM_INPUT and PROGRAM_OUTPUT interfaces for shaders that receive
307 * or produce patch primitives, the active resource list will include both
308 * per-vertex and per-patch inputs and outputs.
310 * For the TRANSFORM_FEEDBACK_VARYING interface, the active resource list
311 * will entries for the special varying names gl_NextBuffer,
312 * gl_SkipComponents1, gl_SkipComponents2, gl_SkipComponents3, and
313 * gl_SkipComponents4 (section 2.14.11). These variables are used to control
314 * how varying values are written to transform feedback buffers. When
315 * enumerating the properties of such resources, these variables are
316 * considered to have a TYPE of NONE and an ARRAY_SIZE of 0 (gl_NextBuffer),
317 * 1, 2, 3, and 4, respectively."
320 struct subtest_t {
321 GLenum programInterface;
323 const char *programInterface_str;
324 const char *active_resources_str;
325 const char *max_length_name_str;
326 const char *max_num_active_str;
327 const char *max_num_compat_sub_str;
329 /* set to -1 to disable the test */
330 int active_resources;
331 int max_length_name;
332 int max_num_active;
333 int max_num_compat_sub;
335 const char *vs_text;
336 const char *gs_text;
337 const char *fs_text;
338 const char *tcs_text;
339 const char *tes_text;
340 const char *cs_text;
342 const char **resources;
345 #define ST(active_r, max_len, max_num_active, max_num_compat_sub, vs, tcs, \
346 tes, gs, fs, cs, name, suffix, resources) { \
347 (name), #name suffix, #name suffix " active resources", \
348 #name suffix " max length name", \
349 #name suffix " max num active", \
350 #name suffix " max num compat sub", \
351 (active_r), (max_len), (max_num_active), (max_num_compat_sub), \
352 (vs), (gs), (fs), (tcs), (tes), (cs), (resources) \
355 static const struct subtest_t subtests[] = {
356 ST( 8, 35, -1, -1, vs_std, NULL, NULL, gs_std, fs_in, NULL, GL_UNIFORM, "(vs,gs,fs)", st_r_uniform),
357 ST( 2, 9, -1, -1, NULL, tcs_sub, tes_in, NULL, NULL, NULL, GL_UNIFORM, "(tes,tcs)", st_r_tess_uniform),
358 ST( 2, 8, -1, -1, NULL, NULL, NULL, NULL, NULL, cs_sub, GL_UNIFORM, "(cs)", st_r_cs_uniform),
359 ST( 7, 26, 2, -1, vs_std, NULL, NULL, gs_std, fs_in, NULL, GL_UNIFORM_BLOCK, "(vs,gs,fs)", st_r_uniform_block),
360 ST( 2, 18, -1, -1, NULL, tcs_sub, tes_in, NULL, NULL, NULL, GL_UNIFORM_BLOCK, "(tcs,tes)", st_r_tess_uniform_block),
361 ST( 1, 17, -1, -1, NULL, NULL, NULL, NULL, NULL, cs_sub, GL_UNIFORM_BLOCK, "(cs)", st_r_cs_uniform_block),
362 ST( 2, 10, -1, -1, vs_std, NULL, NULL, NULL, NULL, NULL, GL_PROGRAM_INPUT, "(vs)", st_r_in_vs),
363 ST( 2, 25, -1, -1, NULL, NULL, NULL, gs_std, NULL, NULL, GL_PROGRAM_INPUT, "(gs)", st_r_in_gs),
364 ST( 1, 10, -1, -1, NULL, NULL, NULL, NULL, fs_in, NULL, GL_PROGRAM_INPUT, "(fs)", st_r_in_fs),
365 ST( 2, 10, -1, -1, vs_std, NULL, NULL, NULL, fs_std, NULL, GL_PROGRAM_INPUT, "(vs,fs)", st_r_in_vs),
366 ST( 2, 10, -1, -1, vs_std, NULL, NULL, gs_std, NULL, NULL, GL_PROGRAM_INPUT, "(vs,gs)", st_r_in_vs),
367 ST( 2, 25, -1, -1, NULL, NULL, NULL, gs_std, fs_in, NULL, GL_PROGRAM_INPUT, "(gs,fs)", st_r_in_gs),
368 ST( 2, 10, -1, -1, vs_std, NULL, NULL, gs_std, fs_in, NULL, GL_PROGRAM_INPUT, "(vs,gs,fs)", st_r_in_vs),
369 ST( 2, 25, -1, -1, NULL, NULL, tes_in, NULL, NULL, NULL, GL_PROGRAM_INPUT, "(tes)", st_r_in_tes),
370 ST( 3, 25, -1, -1, NULL, tcs_sub, NULL, NULL, NULL, NULL, GL_PROGRAM_INPUT, "(tcs)", st_r_in_tcs),
371 ST( 3, 25, -1, -1, NULL, tcs_sub, tes_in, NULL, NULL, NULL, GL_PROGRAM_INPUT, "(tcs,tes)", st_r_in_tcs),
372 ST( 2, 10, -1, -1, vs_std, tcs_sub, tes_in, NULL, NULL, NULL, GL_PROGRAM_INPUT, "(vs,tcs,tes)", st_r_in_vs),
373 ST( 0, 0, -1, -1, NULL, NULL, NULL, NULL, NULL, cs_sub, GL_PROGRAM_INPUT, "(cs)", NULL),
374 ST( 2, 12, -1, -1, vs_std, NULL, NULL, NULL, NULL, NULL, GL_PROGRAM_OUTPUT, "(vs)", st_r_out_vs),
375 ST( 2, 12, -1, -1, NULL, NULL, NULL, gs_std, NULL, NULL, GL_PROGRAM_OUTPUT, "(gs)", st_r_out_gs),
376 ST( 2, 11, -1, -1, NULL, NULL, NULL, NULL, fs_std, NULL, GL_PROGRAM_OUTPUT, "(fs)", st_r_out_fs),
377 ST( 2, 11, -1, -1, vs_std, NULL, NULL, NULL, fs_std, NULL, GL_PROGRAM_OUTPUT, "(vs,fs)", st_r_out_fs),
378 ST( 2, 12, -1, -1, vs_std, NULL, NULL, gs_std, NULL, NULL, GL_PROGRAM_OUTPUT, "(vs,gs)", st_r_out_gs),
379 ST( 2, 11, -1, -1, NULL, NULL, NULL, gs_std, fs_in, NULL, GL_PROGRAM_OUTPUT, "(gs,fs)", st_r_out_fs),
380 ST( 2, 11, -1, -1, vs_std, NULL, NULL, gs_std, fs_in, NULL, GL_PROGRAM_OUTPUT, "(vs,gs,fs)", st_r_out_fs),
381 ST( 2, 12, -1, -1, NULL, NULL, tes_in, NULL, NULL, NULL, GL_PROGRAM_OUTPUT, "(tes)", st_r_out_tes),
382 ST( 3, 25, -1, -1, NULL, tcs_sub, NULL, NULL, NULL, NULL, GL_PROGRAM_OUTPUT, "(tcs)", st_r_out_tcs),
383 ST( 2, 12, -1, -1, NULL, tcs_sub, tes_in, NULL, NULL, NULL, GL_PROGRAM_OUTPUT, "(tcs,tes)", st_r_out_tes),
384 ST( 2, 12, -1, -1, NULL, tcs_sub, tes_in, gs_std, NULL, NULL, GL_PROGRAM_OUTPUT, "(tcs,tes,gs)", st_r_out_gs),
385 ST( 0, 0, -1, -1, NULL, NULL, NULL, NULL, NULL, cs_sub, GL_PROGRAM_OUTPUT, "(cs)", st_r_cs_sub),
386 ST( 3, 11, -1, -1, vs_stor, NULL, NULL, gs_stor, fs_stor, NULL, GL_BUFFER_VARIABLE, "", st_r_buffer),
387 ST( 3, 16, 1, -1, vs_stor, NULL, NULL, gs_stor, fs_stor, NULL, GL_SHADER_STORAGE_BLOCK, "", st_r_stor_block),
388 ST( 3, -1, 1, -1, vs_atom, NULL, NULL, gs_atom, fs_atom, NULL, GL_ATOMIC_COUNTER_BUFFER, "", NULL),
389 ST( 2, 12, -1, -1, vs_std, NULL, NULL, gs_std, NULL, NULL, GL_TRANSFORM_FEEDBACK_VARYING, "", st_r_tf_varying),
390 ST( 2, 5, -1, -1, vs_sub, NULL, NULL, NULL, NULL, NULL, GL_VERTEX_SUBROUTINE, "", st_r_vs_sub),
391 ST( 1, 4, -1, -1, vs_sub, NULL, NULL, gs_sub, NULL, NULL, GL_GEOMETRY_SUBROUTINE, "", st_r_gs_sub),
392 ST( 1, 4, -1, -1, vs_sub, NULL, NULL, gs_sub, fs_sub, NULL, GL_FRAGMENT_SUBROUTINE, "", st_r_fs_sub),
393 ST( 1, 4, -1, -1, NULL, NULL, NULL, NULL, NULL, cs_sub, GL_COMPUTE_SUBROUTINE, "", st_r_cs_sub),
394 ST( 1, 5, -1, -1, vs_sub, tcs_sub, NULL, NULL, NULL, NULL, GL_TESS_CONTROL_SUBROUTINE, "", st_r_tcs_sub),
395 ST( 1, 5, -1, -1, vs_sub, NULL, tes_sub, NULL, NULL, NULL, GL_TESS_EVALUATION_SUBROUTINE, "", st_r_tes_sub),
396 ST( 1, 7, -1, 2, vs_sub, NULL, NULL, NULL, NULL, NULL, GL_VERTEX_SUBROUTINE_UNIFORM, "", st_r_vs_sub_uni),
397 ST( 1, 9, -1, 1, vs_sub, NULL, NULL, gs_sub, NULL, NULL, GL_GEOMETRY_SUBROUTINE_UNIFORM, "", st_r_gs_sub_uni),
398 ST( 1, 9, -1, 1, vs_sub, NULL, NULL, gs_sub, fs_sub, NULL, GL_FRAGMENT_SUBROUTINE_UNIFORM, "", st_r_fs_sub_uni),
399 ST( 1, 13, -1, 1, vs_sub, tcs_sub, NULL, NULL, NULL, NULL, GL_TESS_CONTROL_SUBROUTINE_UNIFORM, "", st_r_tcs_sub_uni),
400 ST( 1, 16, -1, 1, vs_sub, NULL, tes_sub, NULL, NULL, NULL, GL_TESS_EVALUATION_SUBROUTINE_UNIFORM, "", st_r_tes_sub_uni),
401 ST( 1, 8, -1, 1, NULL, NULL, NULL, NULL, NULL, cs_sub, GL_COMPUTE_SUBROUTINE_UNIFORM, "", st_r_cs_sub_uni),
404 static void
405 check_pname(GLuint prog, GLenum programInterface, GLenum pname, bool *pass,
406 const char *subtest, int expected_value)
408 int value;
410 if (expected_value < 0) {
411 return;
414 glGetProgramInterfaceiv(prog, programInterface, pname, &value);
415 if (!piglit_check_gl_error(GL_NO_ERROR)) {
416 printf(" Latest error generated while running '%s'\n",
417 subtest);
420 if (value != expected_value) {
421 fprintf(stderr, "'%s' expected %i but got %i\n", subtest,
422 expected_value, value);
423 *pass = false;
427 static bool
428 is_resource_in_list(const char **list, const char *resource, int index,
429 bool check_order)
431 int i = 0;
432 while (list && list[i]) {
433 if (strcmp(list[i], resource) == 0) {
434 return !check_order || index == i;
436 i++;
439 return false;
442 static bool
443 consistency_check(GLuint prog, GLenum programInterface, const char *name,
444 GLint index)
446 bool subroutine = false;
447 const GLchar *names[] = { name };
448 GLuint old_idx = 0xdeadcafe;
449 GLenum shader;
451 /* Validate result against old API. */
452 switch (programInterface) {
453 case GL_UNIFORM:
454 glGetUniformIndices(prog, 1, names, &old_idx);
455 piglit_check_gl_error(GL_NO_ERROR);
456 break;
458 case GL_UNIFORM_BLOCK:
459 old_idx = glGetUniformBlockIndex(prog, name);
460 piglit_check_gl_error(GL_NO_ERROR);
461 break;
463 case GL_VERTEX_SUBROUTINE:
464 shader = GL_VERTEX_SHADER;
465 subroutine = true;
466 break;
468 case GL_TESS_CONTROL_SUBROUTINE:
469 shader = GL_TESS_CONTROL_SHADER;
470 subroutine = true;
471 break;
473 case GL_TESS_EVALUATION_SUBROUTINE:
474 shader = GL_TESS_EVALUATION_SHADER;
475 subroutine = true;
476 break;
478 case GL_GEOMETRY_SUBROUTINE:
479 shader = GL_GEOMETRY_SHADER;
480 subroutine = true;
481 break;
483 case GL_FRAGMENT_SUBROUTINE:
484 shader = GL_FRAGMENT_SHADER;
485 subroutine = true;
486 break;
488 case GL_COMPUTE_SUBROUTINE:
489 shader = GL_COMPUTE_SHADER;
490 subroutine = true;
491 break;
493 default:
494 /* There are no old APIs for this program interface */
495 return true;
498 if (subroutine) {
499 old_idx = glGetSubroutineIndex(prog, shader, name);
500 piglit_check_gl_error(GL_NO_ERROR);
503 if (index != old_idx) {
504 printf("Index inconsistent with the old API: %i vs %i\n", index,
505 old_idx);
506 return false;
507 } else
508 return true;
512 static void
513 validate_resources(const struct subtest_t st, GLuint prog, bool *pass)
515 GLsizei max_size = 0, size, i;
516 char * name;
518 /* Do not run the test for GL_ATOMIC_COUNTER_BUFFER.
519 * From the GL_ARB_program_interface_query extension:
521 * "The error INVALID_OPERATION is generated if <programInterface>
522 * is ATOMIC_COUNTER_BUFFER, since active atomic counter buffer
523 * resources are not assigned name strings."
525 if (st.programInterface == GL_ATOMIC_COUNTER_BUFFER)
526 return;
528 name = (char *) malloc(st.max_length_name);
529 for (i = 0; i < st.active_resources; i++) {
530 GLuint index;
532 glGetProgramResourceName(prog, st.programInterface,
533 i, st.max_length_name,
534 &size, name);
535 piglit_check_gl_error(GL_NO_ERROR);
537 /* keep track of the maximum size */
538 if (size > max_size) {
539 max_size = size;
542 /* Check the names. Transform feedback requires the order to be
543 * the same as the one given in glTransformFeedbackVaryings.
544 * From the GL_ARB_program_interface_query extension:
546 * "The order of the active resource list is
547 * implementation-dependent for all interfaces except for
548 * TRANSFORM_FEEDBACK_VARYING. For TRANSFORM_FEEDBACK_VARYING,
549 * the active resource list will use the variable order
550 * specified in the the most recent call to
551 * TransformFeedbackVaryings before the last call to
552 * LinkProgram.
554 if (st.resources && !is_resource_in_list(st.resources, name, i,
555 st.programInterface == GL_TRANSFORM_FEEDBACK_VARYING)) {
556 fprintf(stderr, "Resource '%s' not found in '%s' "
557 "resource list or found at the wrong "
558 "index\n", name,
559 st.programInterface_str);
560 *pass = false;
563 /* Check the position of the arguments and see if it matches
564 * with the current position we are in.
566 index = glGetProgramResourceIndex(prog, st.programInterface,
567 name);
568 if (index != i) {
569 fprintf(stderr, "%s: Resource '%s' is not at the "
570 "position reported by "
571 "glGetProgramResourceIndex (%i instead "
572 "of %i)\n",
573 st.programInterface_str, name, index, i);
574 *pass = false;
577 /* check the equivalence with the old API */
578 if (!consistency_check(prog, st.programInterface, name,
579 index)) {
580 *pass = false;
583 free(name);
585 /* glGetProgramResourceName does not count the NULL terminator as part
586 * of the size contrarily to glGetProgramInterfaceiv.
587 * From the GL_ARB_program_interface_query extension:
589 * "void GetProgramInterfaceiv(uint program, enum programInterface,
590 * enum pname, int *params);
591 * [...]
592 * If <pname> is MAX_NAME_LENGTH, the value returned is the length of
593 * the longest active name string for an active resource in
594 * <programInterface>. This length includes an extra character for the
595 * null terminator."
597 * "void GetProgramResourceName(uint program, enum programInterface,
598 * uint index, sizei bufSize,
599 * sizei *length, char *name);
600 * [...]
601 * The actual number of characters written into <name>, excluding the
602 * null terminator, is returned in <length>."
604 if (max_size != MAX2(0, st.max_length_name - 1)) {
605 fprintf(stderr, "'%s actual max length' expected %i but got "
606 "%i\n", st.programInterface_str,
607 st.max_length_name - 1, max_size);
608 *pass = false;
612 static bool
613 check_extensions(const struct subtest_t st)
615 if (st.programInterface == GL_ATOMIC_COUNTER_BUFFER &&
616 !piglit_is_extension_supported("GL_ARB_shader_atomic_counters")) {
617 return false;
620 if ((st.programInterface == GL_BUFFER_VARIABLE ||
621 st.programInterface == GL_SHADER_STORAGE_BLOCK) &&
622 !piglit_is_extension_supported("GL_ARB_shader_storage_buffer_object")) {
623 return false;
626 if ((st.programInterface == GL_VERTEX_SUBROUTINE ||
627 st.programInterface == GL_GEOMETRY_SUBROUTINE ||
628 st.programInterface == GL_FRAGMENT_SUBROUTINE ||
629 st.programInterface == GL_COMPUTE_SUBROUTINE ||
630 st.programInterface == GL_VERTEX_SUBROUTINE_UNIFORM ||
631 st.programInterface == GL_GEOMETRY_SUBROUTINE_UNIFORM ||
632 st.programInterface == GL_FRAGMENT_SUBROUTINE_UNIFORM ||
633 st.programInterface == GL_COMPUTE_SUBROUTINE_UNIFORM ||
634 st.programInterface == GL_TESS_CONTROL_SUBROUTINE ||
635 st.programInterface == GL_TESS_EVALUATION_SUBROUTINE ||
636 st.programInterface == GL_TESS_CONTROL_SUBROUTINE_UNIFORM ||
637 st.programInterface == GL_TESS_EVALUATION_SUBROUTINE_UNIFORM ||
638 st.programInterface == GL_COMPUTE_SUBROUTINE_UNIFORM) &&
639 !piglit_is_extension_supported("GL_ARB_shader_subroutine")) {
640 return false;
643 if ((st.programInterface == GL_TESS_CONTROL_SUBROUTINE ||
644 st.programInterface == GL_TESS_EVALUATION_SUBROUTINE ||
645 st.programInterface == GL_TESS_CONTROL_SUBROUTINE_UNIFORM ||
646 st.programInterface == GL_TESS_EVALUATION_SUBROUTINE_UNIFORM ||
647 st.tcs_text || st.tes_text) &&
648 (!piglit_is_extension_supported("GL_ARB_shader_subroutine") ||
649 !piglit_is_extension_supported("GL_ARB_tessellation_shader"))) {
650 return false;
653 if ((st.programInterface == GL_COMPUTE_SUBROUTINE ||
654 st.programInterface == GL_COMPUTE_SUBROUTINE_UNIFORM ||
655 st.cs_text) &&
656 (!piglit_is_extension_supported("GL_ARB_compute_shader") ||
657 !piglit_is_extension_supported("GL_ARB_shader_image_load_store"))) {
658 return false;
661 return true;
664 static void
665 run_subtest(const struct subtest_t st, bool *pass)
667 enum piglit_result result;
668 bool local_pass = true;
669 GLuint prog;
671 if (!check_extensions(st)) {
672 result = PIGLIT_SKIP;
673 goto report_result;
676 prog = piglit_build_simple_program_unlinked_multiple_shaders(
677 GL_VERTEX_SHADER, st.vs_text,
678 GL_GEOMETRY_SHADER, st.gs_text,
679 GL_FRAGMENT_SHADER, st.fs_text,
680 GL_TESS_CONTROL_SHADER, st.tcs_text,
681 GL_TESS_EVALUATION_SHADER, st.tes_text,
682 GL_COMPUTE_SHADER, st.cs_text,
685 if (st.programInterface == GL_TRANSFORM_FEEDBACK_VARYING) {
686 glTransformFeedbackVaryings(prog, 2, st_r_tf_varying,
687 GL_INTERLEAVED_ATTRIBS);
688 piglit_check_gl_error(GL_NO_ERROR);
691 /* force the compiler not to optimise away inputs/outputs */
692 glProgramParameteri(prog, GL_PROGRAM_SEPARABLE, GL_TRUE);
693 piglit_check_gl_error(GL_NO_ERROR);
695 glLinkProgram(prog);
696 if (!piglit_link_check_status(prog)) {
697 glDeleteProgram(prog);
698 result = PIGLIT_FAIL;
699 *pass = false;
700 goto report_result;
703 check_pname(prog, st.programInterface, GL_ACTIVE_RESOURCES,
704 &local_pass, st.active_resources_str, st.active_resources);
705 if (!local_pass) {
706 GLint active;
707 glGetProgramInterfaceiv(prog, st.programInterface, GL_ACTIVE_RESOURCES, &active);
708 printf("Active resources:\n");
709 for (int i = 0; i < active; i++) {
710 char name[1024];
711 GLsizei len;
712 glGetProgramResourceName(prog, st.programInterface, i, ARRAY_SIZE(name), &len, name);
713 printf(" %s\n", name);
717 check_pname(prog, st.programInterface, GL_MAX_NAME_LENGTH,
718 &local_pass, st.max_length_name_str, st.max_length_name);
720 /* do not test fetching the names if the previous tests failed */
721 if (local_pass) {
722 validate_resources(st, prog, &local_pass);
725 check_pname(prog, st.programInterface, GL_MAX_NUM_ACTIVE_VARIABLES,
726 &local_pass, st.max_num_active_str, st.max_num_active);
728 check_pname(prog, st.programInterface,
729 GL_MAX_NUM_COMPATIBLE_SUBROUTINES, &local_pass,
730 st.max_num_compat_sub_str, st.max_num_compat_sub);
732 glDeleteProgram(prog);
734 *pass = *pass && local_pass;
735 result = local_pass ? PIGLIT_PASS : PIGLIT_FAIL;
737 report_result:
738 piglit_report_subtest_result(result, "%s", st.programInterface_str);
741 void
742 piglit_init(int argc, char **argv)
744 piglit_require_extension("GL_ARB_program_interface_query");
745 piglit_require_extension("GL_ARB_separate_shader_objects");
748 enum piglit_result
749 piglit_display(void)
751 bool pass = true;
752 int i;
754 /* run all the getprograminterfaceiv tests */
755 for (i = 0; i < sizeof(subtests) / sizeof(struct subtest_t); i++) {
756 run_subtest(subtests[i], &pass);
759 return pass ? PIGLIT_PASS : PIGLIT_FAIL;