mesa: add query support for GL_TRANSFORM_FEEDBACK_BUFFER interface
[mesa.git] / src / mesa / main / program_resource.c
1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 2015 Intel Corporation. All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 *
24 */
25
26 #include "main/enums.h"
27 #include "main/macros.h"
28 #include "main/mtypes.h"
29 #include "main/shaderapi.h"
30 #include "main/shaderobj.h"
31 #include "main/context.h"
32 #include "program_resource.h"
33 #include "compiler/glsl/ir_uniform.h"
34 static bool
35 supported_interface_enum(struct gl_context *ctx, GLenum iface)
36 {
37 switch (iface) {
38 case GL_UNIFORM:
39 case GL_UNIFORM_BLOCK:
40 case GL_PROGRAM_INPUT:
41 case GL_PROGRAM_OUTPUT:
42 case GL_TRANSFORM_FEEDBACK_BUFFER:
43 case GL_TRANSFORM_FEEDBACK_VARYING:
44 case GL_ATOMIC_COUNTER_BUFFER:
45 case GL_BUFFER_VARIABLE:
46 case GL_SHADER_STORAGE_BLOCK:
47 return true;
48 case GL_VERTEX_SUBROUTINE:
49 case GL_FRAGMENT_SUBROUTINE:
50 case GL_VERTEX_SUBROUTINE_UNIFORM:
51 case GL_FRAGMENT_SUBROUTINE_UNIFORM:
52 return _mesa_has_shader_subroutine(ctx);
53 case GL_GEOMETRY_SUBROUTINE:
54 case GL_GEOMETRY_SUBROUTINE_UNIFORM:
55 return _mesa_has_geometry_shaders(ctx) && _mesa_has_shader_subroutine(ctx);
56 case GL_COMPUTE_SUBROUTINE:
57 case GL_COMPUTE_SUBROUTINE_UNIFORM:
58 return _mesa_has_compute_shaders(ctx) && _mesa_has_shader_subroutine(ctx);
59 case GL_TESS_CONTROL_SUBROUTINE:
60 case GL_TESS_EVALUATION_SUBROUTINE:
61 case GL_TESS_CONTROL_SUBROUTINE_UNIFORM:
62 case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM:
63 return _mesa_has_tessellation(ctx) && _mesa_has_shader_subroutine(ctx);
64 default:
65 return false;
66 }
67 }
68
69 void GLAPIENTRY
70 _mesa_GetProgramInterfaceiv(GLuint program, GLenum programInterface,
71 GLenum pname, GLint *params)
72 {
73 GET_CURRENT_CONTEXT(ctx);
74
75 if (MESA_VERBOSE & VERBOSE_API) {
76 _mesa_debug(ctx, "glGetProgramInterfaceiv(%u, %s, %s, %p)\n",
77 program, _mesa_enum_to_string(programInterface),
78 _mesa_enum_to_string(pname), params);
79 }
80
81 unsigned i;
82 struct gl_shader_program *shProg =
83 _mesa_lookup_shader_program_err(ctx, program,
84 "glGetProgramInterfaceiv");
85 if (!shProg)
86 return;
87
88 if (!params) {
89 _mesa_error(ctx, GL_INVALID_OPERATION,
90 "glGetProgramInterfaceiv(params NULL)");
91 return;
92 }
93
94 /* Validate interface. */
95 if (!supported_interface_enum(ctx, programInterface)) {
96 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramInterfaceiv(%s)",
97 _mesa_enum_to_string(programInterface));
98 return;
99 }
100
101 /* Validate pname against interface. */
102 switch(pname) {
103 case GL_ACTIVE_RESOURCES:
104 for (i = 0, *params = 0; i < shProg->NumProgramResourceList; i++)
105 if (shProg->ProgramResourceList[i].Type == programInterface)
106 (*params)++;
107 break;
108 case GL_MAX_NAME_LENGTH:
109 if (programInterface == GL_ATOMIC_COUNTER_BUFFER ||
110 programInterface == GL_TRANSFORM_FEEDBACK_BUFFER) {
111 _mesa_error(ctx, GL_INVALID_OPERATION,
112 "glGetProgramInterfaceiv(%s pname %s)",
113 _mesa_enum_to_string(programInterface),
114 _mesa_enum_to_string(pname));
115 return;
116 }
117 /* Name length consists of base name, 3 additional chars '[0]' if
118 * resource is an array and finally 1 char for string terminator.
119 */
120 for (i = 0, *params = 0; i < shProg->NumProgramResourceList; i++) {
121 if (shProg->ProgramResourceList[i].Type != programInterface)
122 continue;
123 unsigned len =
124 _mesa_program_resource_name_len(&shProg->ProgramResourceList[i]);
125 *params = MAX2(*params, len + 1);
126 }
127 break;
128 case GL_MAX_NUM_ACTIVE_VARIABLES:
129 switch (programInterface) {
130 case GL_UNIFORM_BLOCK:
131 for (i = 0, *params = 0; i < shProg->NumProgramResourceList; i++) {
132 if (shProg->ProgramResourceList[i].Type == programInterface) {
133 struct gl_uniform_block *block =
134 (struct gl_uniform_block *)
135 shProg->ProgramResourceList[i].Data;
136 *params = MAX2(*params, block->NumUniforms);
137 }
138 }
139 break;
140 case GL_SHADER_STORAGE_BLOCK:
141 for (i = 0, *params = 0; i < shProg->NumProgramResourceList; i++) {
142 if (shProg->ProgramResourceList[i].Type == programInterface) {
143 struct gl_uniform_block *block =
144 (struct gl_uniform_block *)
145 shProg->ProgramResourceList[i].Data;
146 GLint block_params = 0;
147 for (unsigned j = 0; j < block->NumUniforms; j++) {
148 const char *iname = block->Uniforms[j].IndexName;
149 struct gl_program_resource *uni =
150 _mesa_program_resource_find_name(shProg, GL_BUFFER_VARIABLE,
151 iname, NULL);
152 if (!uni)
153 continue;
154 block_params++;
155 }
156 *params = MAX2(*params, block_params);
157 }
158 }
159 break;
160 case GL_ATOMIC_COUNTER_BUFFER:
161 for (i = 0, *params = 0; i < shProg->NumProgramResourceList; i++) {
162 if (shProg->ProgramResourceList[i].Type == programInterface) {
163 struct gl_active_atomic_buffer *buffer =
164 (struct gl_active_atomic_buffer *)
165 shProg->ProgramResourceList[i].Data;
166 *params = MAX2(*params, buffer->NumUniforms);
167 }
168 }
169 break;
170 case GL_TRANSFORM_FEEDBACK_BUFFER:
171 for (i = 0, *params = 0; i < shProg->NumProgramResourceList; i++) {
172 if (shProg->ProgramResourceList[i].Type == programInterface) {
173 struct gl_transform_feedback_buffer *buffer =
174 (struct gl_transform_feedback_buffer *)
175 shProg->ProgramResourceList[i].Data;
176 *params = MAX2(*params, buffer->NumVaryings);
177 }
178 }
179 break;
180 default:
181 _mesa_error(ctx, GL_INVALID_OPERATION,
182 "glGetProgramInterfaceiv(%s pname %s)",
183 _mesa_enum_to_string(programInterface),
184 _mesa_enum_to_string(pname));
185 };
186 break;
187 case GL_MAX_NUM_COMPATIBLE_SUBROUTINES:
188 switch (programInterface) {
189 case GL_VERTEX_SUBROUTINE_UNIFORM:
190 case GL_FRAGMENT_SUBROUTINE_UNIFORM:
191 case GL_GEOMETRY_SUBROUTINE_UNIFORM:
192 case GL_COMPUTE_SUBROUTINE_UNIFORM:
193 case GL_TESS_CONTROL_SUBROUTINE_UNIFORM:
194 case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM: {
195 for (i = 0, *params = 0; i < shProg->NumProgramResourceList; i++) {
196 if (shProg->ProgramResourceList[i].Type == programInterface) {
197 struct gl_uniform_storage *uni =
198 (struct gl_uniform_storage *)
199 shProg->ProgramResourceList[i].Data;
200 *params = MAX2(*params, uni->num_compatible_subroutines);
201 }
202 }
203 break;
204 }
205
206 default:
207 _mesa_error(ctx, GL_INVALID_OPERATION,
208 "glGetProgramInterfaceiv(%s pname %s)",
209 _mesa_enum_to_string(programInterface),
210 _mesa_enum_to_string(pname));
211 }
212 break;
213 default:
214 _mesa_error(ctx, GL_INVALID_OPERATION,
215 "glGetProgramInterfaceiv(pname %s)",
216 _mesa_enum_to_string(pname));
217 }
218 }
219
220 static bool
221 is_xfb_marker(const char *str)
222 {
223 static const char *markers[] = {
224 "gl_NextBuffer",
225 "gl_SkipComponents1",
226 "gl_SkipComponents2",
227 "gl_SkipComponents3",
228 "gl_SkipComponents4",
229 NULL
230 };
231 const char **m = markers;
232
233 if (strncmp(str, "gl_", 3) != 0)
234 return false;
235
236 for (; *m; m++)
237 if (strcmp(*m, str) == 0)
238 return true;
239
240 return false;
241 }
242
243 GLuint GLAPIENTRY
244 _mesa_GetProgramResourceIndex(GLuint program, GLenum programInterface,
245 const GLchar *name)
246 {
247 GET_CURRENT_CONTEXT(ctx);
248
249 if (MESA_VERBOSE & VERBOSE_API) {
250 _mesa_debug(ctx, "glGetProgramResourceIndex(%u, %s, %s)\n",
251 program, _mesa_enum_to_string(programInterface), name);
252 }
253
254 unsigned array_index = 0;
255 struct gl_program_resource *res;
256 struct gl_shader_program *shProg =
257 _mesa_lookup_shader_program_err(ctx, program,
258 "glGetProgramResourceIndex");
259 if (!shProg || !name)
260 return GL_INVALID_INDEX;
261
262 if (!supported_interface_enum(ctx, programInterface)) {
263 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceIndex(%s)",
264 _mesa_enum_to_string(programInterface));
265 return GL_INVALID_INDEX;
266 }
267 /*
268 * For the interface TRANSFORM_FEEDBACK_VARYING, the value INVALID_INDEX
269 * should be returned when querying the index assigned to the special names
270 * "gl_NextBuffer", "gl_SkipComponents1", "gl_SkipComponents2",
271 * "gl_SkipComponents3", and "gl_SkipComponents4".
272 */
273 if (programInterface == GL_TRANSFORM_FEEDBACK_VARYING &&
274 is_xfb_marker(name))
275 return GL_INVALID_INDEX;
276
277 switch (programInterface) {
278 case GL_TESS_CONTROL_SUBROUTINE:
279 case GL_TESS_CONTROL_SUBROUTINE_UNIFORM:
280 case GL_TESS_EVALUATION_SUBROUTINE:
281 case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM:
282 case GL_COMPUTE_SUBROUTINE:
283 case GL_COMPUTE_SUBROUTINE_UNIFORM:
284 case GL_GEOMETRY_SUBROUTINE:
285 case GL_GEOMETRY_SUBROUTINE_UNIFORM:
286 case GL_VERTEX_SUBROUTINE:
287 case GL_FRAGMENT_SUBROUTINE:
288 case GL_VERTEX_SUBROUTINE_UNIFORM:
289 case GL_FRAGMENT_SUBROUTINE_UNIFORM:
290 case GL_PROGRAM_INPUT:
291 case GL_PROGRAM_OUTPUT:
292 case GL_UNIFORM:
293 case GL_BUFFER_VARIABLE:
294 case GL_TRANSFORM_FEEDBACK_VARYING:
295 case GL_UNIFORM_BLOCK:
296 case GL_SHADER_STORAGE_BLOCK:
297 res = _mesa_program_resource_find_name(shProg, programInterface, name,
298 &array_index);
299 if (!res || array_index > 0)
300 return GL_INVALID_INDEX;
301
302 return _mesa_program_resource_index(shProg, res);
303 case GL_ATOMIC_COUNTER_BUFFER:
304 case GL_TRANSFORM_FEEDBACK_BUFFER:
305 default:
306 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceIndex(%s)",
307 _mesa_enum_to_string(programInterface));
308 }
309
310 return GL_INVALID_INDEX;
311 }
312
313 void GLAPIENTRY
314 _mesa_GetProgramResourceName(GLuint program, GLenum programInterface,
315 GLuint index, GLsizei bufSize, GLsizei *length,
316 GLchar *name)
317 {
318 GET_CURRENT_CONTEXT(ctx);
319
320 if (MESA_VERBOSE & VERBOSE_API) {
321 _mesa_debug(ctx, "glGetProgramResourceName(%u, %s, %u, %d, %p, %p)\n",
322 program, _mesa_enum_to_string(programInterface), index,
323 bufSize, length, name);
324 }
325
326 struct gl_shader_program *shProg =
327 _mesa_lookup_shader_program_err(ctx, program,
328 "glGetProgramResourceName");
329
330 if (!shProg || !name)
331 return;
332
333 if (programInterface == GL_ATOMIC_COUNTER_BUFFER ||
334 programInterface == GL_TRANSFORM_FEEDBACK_BUFFER ||
335 !supported_interface_enum(ctx, programInterface)) {
336 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceName(%s)",
337 _mesa_enum_to_string(programInterface));
338 return;
339 }
340
341 _mesa_get_program_resource_name(shProg, programInterface, index, bufSize,
342 length, name, "glGetProgramResourceName");
343 }
344
345 void GLAPIENTRY
346 _mesa_GetProgramResourceiv(GLuint program, GLenum programInterface,
347 GLuint index, GLsizei propCount,
348 const GLenum *props, GLsizei bufSize,
349 GLsizei *length, GLint *params)
350 {
351 GET_CURRENT_CONTEXT(ctx);
352
353 if (MESA_VERBOSE & VERBOSE_API) {
354 _mesa_debug(ctx, "glGetProgramResourceiv(%u, %s, %u, %d, %p, %d, %p, %p)\n",
355 program, _mesa_enum_to_string(programInterface), index,
356 propCount, props, bufSize, length, params);
357 }
358
359 struct gl_shader_program *shProg =
360 _mesa_lookup_shader_program_err(ctx, program, "glGetProgramResourceiv");
361
362 if (!shProg || !params)
363 return;
364
365 /* The error INVALID_VALUE is generated if <propCount> is zero.
366 * Note that we check < 0 here because it makes sense to bail early.
367 */
368 if (propCount <= 0) {
369 _mesa_error(ctx, GL_INVALID_VALUE,
370 "glGetProgramResourceiv(propCount <= 0)");
371 return;
372 }
373
374 _mesa_get_program_resourceiv(shProg, programInterface, index,
375 propCount, props, bufSize, length, params);
376 }
377
378 static struct gl_shader_program *
379 lookup_linked_program(GLuint program, const char *caller)
380 {
381 GET_CURRENT_CONTEXT(ctx);
382 struct gl_shader_program *prog =
383 _mesa_lookup_shader_program_err(ctx, program, caller);
384
385 if (!prog)
386 return NULL;
387
388 if (prog->LinkStatus == GL_FALSE) {
389 _mesa_error(ctx, GL_INVALID_OPERATION, "%s(program not linked)",
390 caller);
391 return NULL;
392 }
393 return prog;
394 }
395
396 GLint GLAPIENTRY
397 _mesa_GetProgramResourceLocation(GLuint program, GLenum programInterface,
398 const GLchar *name)
399 {
400 GET_CURRENT_CONTEXT(ctx);
401
402 if (MESA_VERBOSE & VERBOSE_API) {
403 _mesa_debug(ctx, "glGetProgramResourceLocation(%u, %s, %s)\n",
404 program, _mesa_enum_to_string(programInterface), name);
405 }
406
407 struct gl_shader_program *shProg =
408 lookup_linked_program(program, "glGetProgramResourceLocation");
409
410 if (!shProg || !name)
411 return -1;
412
413 /* Validate programInterface. */
414 switch (programInterface) {
415 case GL_UNIFORM:
416 case GL_PROGRAM_INPUT:
417 case GL_PROGRAM_OUTPUT:
418 break;
419
420 case GL_VERTEX_SUBROUTINE_UNIFORM:
421 case GL_FRAGMENT_SUBROUTINE_UNIFORM:
422 if (!_mesa_has_shader_subroutine(ctx))
423 goto fail;
424 break;
425 case GL_GEOMETRY_SUBROUTINE_UNIFORM:
426 if (!_mesa_has_geometry_shaders(ctx) || !_mesa_has_shader_subroutine(ctx))
427 goto fail;
428 break;
429 case GL_COMPUTE_SUBROUTINE_UNIFORM:
430 if (!_mesa_has_compute_shaders(ctx) || !_mesa_has_shader_subroutine(ctx))
431 goto fail;
432 break;
433 case GL_TESS_CONTROL_SUBROUTINE_UNIFORM:
434 case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM:
435 if (!_mesa_has_tessellation(ctx) || !_mesa_has_shader_subroutine(ctx))
436 goto fail;
437 break;
438 default:
439 goto fail;
440 }
441
442 return _mesa_program_resource_location(shProg, programInterface, name);
443 fail:
444 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceLocation(%s %s)",
445 _mesa_enum_to_string(programInterface), name);
446 return -1;
447 }
448
449 /**
450 * Returns output index for dual source blending.
451 */
452 GLint GLAPIENTRY
453 _mesa_GetProgramResourceLocationIndex(GLuint program, GLenum programInterface,
454 const GLchar *name)
455 {
456 GET_CURRENT_CONTEXT(ctx);
457
458 if (MESA_VERBOSE & VERBOSE_API) {
459 _mesa_debug(ctx, "glGetProgramResourceLocationIndex(%u, %s, %s)\n",
460 program, _mesa_enum_to_string(programInterface), name);
461 }
462
463 struct gl_shader_program *shProg =
464 lookup_linked_program(program, "glGetProgramResourceLocationIndex");
465
466 if (!shProg || !name)
467 return -1;
468
469 /* From the GL_ARB_program_interface_query spec:
470 *
471 * "For GetProgramResourceLocationIndex, <programInterface> must be
472 * PROGRAM_OUTPUT."
473 */
474 if (programInterface != GL_PROGRAM_OUTPUT) {
475 _mesa_error(ctx, GL_INVALID_ENUM,
476 "glGetProgramResourceLocationIndex(%s)",
477 _mesa_enum_to_string(programInterface));
478 return -1;
479 }
480
481 return _mesa_program_resource_location_index(shProg, GL_PROGRAM_OUTPUT,
482 name);
483 }