mesa: fix misleading comment
[mesa.git] / src / mesa / main / shader_query.cpp
1 /*
2 * Copyright © 2011 Intel Corporation
3 *
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:
10 *
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.
14 *
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
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24 /**
25 * \file shader_query.cpp
26 * C-to-C++ bridge functions to query GLSL shader data
27 *
28 * \author Ian Romanick <ian.d.romanick@intel.com>
29 */
30
31 #include "main/context.h"
32 #include "main/core.h"
33 #include "glsl_symbol_table.h"
34 #include "ir.h"
35 #include "shaderobj.h"
36 #include "program/hash_table.h"
37 #include "../glsl/program.h"
38 #include "uniforms.h"
39 #include "main/enums.h"
40
41 extern "C" {
42 #include "shaderapi.h"
43 }
44
45 static GLint
46 program_resource_location(struct gl_shader_program *shProg,
47 struct gl_program_resource *res, const char *name);
48
49 /**
50 * Declare convenience functions to return resource data in a given type.
51 * Warning! this is not type safe so be *very* careful when using these.
52 */
53 #define DECL_RESOURCE_FUNC(name, type) \
54 const type * RESOURCE_ ## name (gl_program_resource *res) { \
55 assert(res->Data); \
56 return (type *) res->Data; \
57 }
58
59 DECL_RESOURCE_FUNC(VAR, ir_variable);
60 DECL_RESOURCE_FUNC(UBO, gl_uniform_block);
61 DECL_RESOURCE_FUNC(UNI, gl_uniform_storage);
62 DECL_RESOURCE_FUNC(ATC, gl_active_atomic_buffer);
63 DECL_RESOURCE_FUNC(XFB, gl_transform_feedback_varying_info);
64
65 void GLAPIENTRY
66 _mesa_BindAttribLocation(GLhandleARB program, GLuint index,
67 const GLcharARB *name)
68 {
69 GET_CURRENT_CONTEXT(ctx);
70
71 struct gl_shader_program *const shProg =
72 _mesa_lookup_shader_program_err(ctx, program, "glBindAttribLocation");
73 if (!shProg)
74 return;
75
76 if (!name)
77 return;
78
79 if (strncmp(name, "gl_", 3) == 0) {
80 _mesa_error(ctx, GL_INVALID_OPERATION,
81 "glBindAttribLocation(illegal name)");
82 return;
83 }
84
85 if (index >= ctx->Const.Program[MESA_SHADER_VERTEX].MaxAttribs) {
86 _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(index)");
87 return;
88 }
89
90 /* Replace the current value if it's already in the list. Add
91 * VERT_ATTRIB_GENERIC0 because that's how the linker differentiates
92 * between built-in attributes and user-defined attributes.
93 */
94 shProg->AttributeBindings->put(index + VERT_ATTRIB_GENERIC0, name);
95
96 /*
97 * Note that this attribute binding won't go into effect until
98 * glLinkProgram is called again.
99 */
100 }
101
102 static bool
103 is_active_attrib(const ir_variable *var)
104 {
105 if (!var)
106 return false;
107
108 switch (var->data.mode) {
109 case ir_var_shader_in:
110 return var->data.location != -1;
111
112 case ir_var_system_value:
113 /* From GL 4.3 core spec, section 11.1.1 (Vertex Attributes):
114 * "For GetActiveAttrib, all active vertex shader input variables
115 * are enumerated, including the special built-in inputs gl_VertexID
116 * and gl_InstanceID."
117 */
118 return var->data.location == SYSTEM_VALUE_VERTEX_ID ||
119 var->data.location == SYSTEM_VALUE_VERTEX_ID_ZERO_BASE ||
120 var->data.location == SYSTEM_VALUE_INSTANCE_ID;
121
122 default:
123 return false;
124 }
125 }
126
127 void GLAPIENTRY
128 _mesa_GetActiveAttrib(GLhandleARB program, GLuint desired_index,
129 GLsizei maxLength, GLsizei * length, GLint * size,
130 GLenum * type, GLcharARB * name)
131 {
132 GET_CURRENT_CONTEXT(ctx);
133 struct gl_shader_program *shProg;
134
135 if (maxLength < 0) {
136 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(maxLength < 0)");
137 return;
138 }
139
140 shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveAttrib");
141 if (!shProg)
142 return;
143
144 if (!shProg->LinkStatus) {
145 _mesa_error(ctx, GL_INVALID_VALUE,
146 "glGetActiveAttrib(program not linked)");
147 return;
148 }
149
150 if (shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL) {
151 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(no vertex shader)");
152 return;
153 }
154
155 struct gl_program_resource *res =
156 _mesa_program_resource_find_index(shProg, GL_PROGRAM_INPUT,
157 desired_index);
158
159 /* User asked for index that does not exist. */
160 if (!res) {
161 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
162 return;
163 }
164
165 const ir_variable *const var = RESOURCE_VAR(res);
166
167 if (!is_active_attrib(var))
168 return;
169
170 const char *var_name = var->name;
171
172 /* Since gl_VertexID may be lowered to gl_VertexIDMESA, we need to
173 * consider gl_VertexIDMESA as gl_VertexID for purposes of checking
174 * active attributes.
175 */
176 if (var->data.mode == ir_var_system_value &&
177 var->data.location == SYSTEM_VALUE_VERTEX_ID_ZERO_BASE) {
178 var_name = "gl_VertexID";
179 }
180
181 _mesa_copy_string(name, maxLength, length, var_name);
182
183 if (size)
184 _mesa_program_resource_prop(shProg, res, desired_index, GL_ARRAY_SIZE,
185 size, "glGetActiveAttrib");
186
187 if (type)
188 _mesa_program_resource_prop(shProg, res, desired_index, GL_TYPE,
189 (GLint *) type, "glGetActiveAttrib");
190 }
191
192 /* Locations associated with shader variables (array or non-array) can be
193 * queried using its base name or using the base name appended with the
194 * valid array index. For example, in case of below vertex shader, valid
195 * queries can be made to know the location of "xyz", "array", "array[0]",
196 * "array[1]", "array[2]" and "array[3]". In this example index reurned
197 * will be 0, 0, 0, 1, 2, 3 respectively.
198 *
199 * [Vertex Shader]
200 * layout(location=0) in vec4 xyz;
201 * layout(location=1) in vec4[4] array;
202 * void main()
203 * { }
204 *
205 * This requirement came up with the addition of ARB_program_interface_query
206 * to OpenGL 4.3 specification. See page 101 (page 122 of the PDF) for details.
207 *
208 * This utility function is used by:
209 * _mesa_GetAttribLocation
210 * _mesa_GetFragDataLocation
211 * _mesa_GetFragDataIndex
212 *
213 * Returns 0:
214 * if the 'name' string matches var->name.
215 * Returns 'matched index':
216 * if the 'name' string matches var->name appended with valid array index.
217 */
218 int static inline
219 get_matching_index(const ir_variable *const var, const char *name) {
220 unsigned idx = 0;
221 const char *const paren = strchr(name, '[');
222 const unsigned len = (paren != NULL) ? paren - name : strlen(name);
223
224 if (paren != NULL) {
225 if (!var->type->is_array())
226 return -1;
227
228 char *endptr;
229 idx = (unsigned) strtol(paren + 1, &endptr, 10);
230 const unsigned idx_len = endptr != (paren + 1) ? endptr - paren - 1 : 0;
231
232 /* Validate the sub string representing index in 'name' string */
233 if ((idx > 0 && paren[1] == '0') /* leading zeroes */
234 || (idx == 0 && idx_len > 1) /* all zeroes */
235 || paren[1] == ' ' /* whitespace */
236 || endptr[0] != ']' /* closing brace */
237 || endptr[1] != '\0' /* null char */
238 || idx_len == 0 /* missing index */
239 || idx >= var->type->length) /* exceeding array bound */
240 return -1;
241 }
242
243 if (strncmp(var->name, name, len) == 0 && var->name[len] == '\0')
244 return idx;
245
246 return -1;
247 }
248
249 GLint GLAPIENTRY
250 _mesa_GetAttribLocation(GLhandleARB program, const GLcharARB * name)
251 {
252 GET_CURRENT_CONTEXT(ctx);
253 struct gl_shader_program *const shProg =
254 _mesa_lookup_shader_program_err(ctx, program, "glGetAttribLocation");
255
256 if (!shProg) {
257 return -1;
258 }
259
260 if (!shProg->LinkStatus) {
261 _mesa_error(ctx, GL_INVALID_OPERATION,
262 "glGetAttribLocation(program not linked)");
263 return -1;
264 }
265
266 if (!name)
267 return -1;
268
269 /* Not having a vertex shader is not an error.
270 */
271 if (shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL)
272 return -1;
273
274 struct gl_program_resource *res =
275 _mesa_program_resource_find_name(shProg, GL_PROGRAM_INPUT, name);
276
277 if (!res)
278 return -1;
279
280 GLint loc = program_resource_location(shProg, res, name);
281
282 /* The extra check against against 0 is made because of builtin-attribute
283 * locations that have offset applied. Function program_resource_location
284 * can return built-in attribute locations < 0 and glGetAttribLocation
285 * cannot be used on "conventional" attributes.
286 *
287 * From page 95 of the OpenGL 3.0 spec:
288 *
289 * "If name is not an active attribute, if name is a conventional
290 * attribute, or if an error occurs, -1 will be returned."
291 */
292 return (loc >= 0) ? loc : -1;
293 }
294
295 unsigned
296 _mesa_count_active_attribs(struct gl_shader_program *shProg)
297 {
298 if (!shProg->LinkStatus
299 || shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL) {
300 return 0;
301 }
302
303 struct gl_program_resource *res = shProg->ProgramResourceList;
304 unsigned count = 0;
305 for (unsigned j = 0; j < shProg->NumProgramResourceList; j++, res++) {
306 if (res->Type == GL_PROGRAM_INPUT &&
307 res->StageReferences & (1 << MESA_SHADER_VERTEX) &&
308 is_active_attrib(RESOURCE_VAR(res)))
309 count++;
310 }
311 return count;
312 }
313
314
315 size_t
316 _mesa_longest_attribute_name_length(struct gl_shader_program *shProg)
317 {
318 if (!shProg->LinkStatus
319 || shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL) {
320 return 0;
321 }
322
323 struct gl_program_resource *res = shProg->ProgramResourceList;
324 size_t longest = 0;
325 for (unsigned j = 0; j < shProg->NumProgramResourceList; j++, res++) {
326 if (res->Type == GL_PROGRAM_INPUT &&
327 res->StageReferences & (1 << MESA_SHADER_VERTEX)) {
328
329 const size_t length = strlen(RESOURCE_VAR(res)->name);
330 if (length >= longest)
331 longest = length + 1;
332 }
333 }
334
335 return longest;
336 }
337
338 void GLAPIENTRY
339 _mesa_BindFragDataLocation(GLuint program, GLuint colorNumber,
340 const GLchar *name)
341 {
342 _mesa_BindFragDataLocationIndexed(program, colorNumber, 0, name);
343 }
344
345 void GLAPIENTRY
346 _mesa_BindFragDataLocationIndexed(GLuint program, GLuint colorNumber,
347 GLuint index, const GLchar *name)
348 {
349 GET_CURRENT_CONTEXT(ctx);
350
351 struct gl_shader_program *const shProg =
352 _mesa_lookup_shader_program_err(ctx, program, "glBindFragDataLocationIndexed");
353 if (!shProg)
354 return;
355
356 if (!name)
357 return;
358
359 if (strncmp(name, "gl_", 3) == 0) {
360 _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFragDataLocationIndexed(illegal name)");
361 return;
362 }
363
364 if (index > 1) {
365 _mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocationIndexed(index)");
366 return;
367 }
368
369 if (index == 0 && colorNumber >= ctx->Const.MaxDrawBuffers) {
370 _mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocationIndexed(colorNumber)");
371 return;
372 }
373
374 if (index == 1 && colorNumber >= ctx->Const.MaxDualSourceDrawBuffers) {
375 _mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocationIndexed(colorNumber)");
376 return;
377 }
378
379 /* Replace the current value if it's already in the list. Add
380 * FRAG_RESULT_DATA0 because that's how the linker differentiates
381 * between built-in attributes and user-defined attributes.
382 */
383 shProg->FragDataBindings->put(colorNumber + FRAG_RESULT_DATA0, name);
384 shProg->FragDataIndexBindings->put(index, name);
385 /*
386 * Note that this binding won't go into effect until
387 * glLinkProgram is called again.
388 */
389
390 }
391
392 GLint GLAPIENTRY
393 _mesa_GetFragDataIndex(GLuint program, const GLchar *name)
394 {
395 GET_CURRENT_CONTEXT(ctx);
396 struct gl_shader_program *const shProg =
397 _mesa_lookup_shader_program_err(ctx, program, "glGetFragDataIndex");
398
399 if (!shProg) {
400 return -1;
401 }
402
403 if (!shProg->LinkStatus) {
404 _mesa_error(ctx, GL_INVALID_OPERATION,
405 "glGetFragDataIndex(program not linked)");
406 return -1;
407 }
408
409 if (!name)
410 return -1;
411
412 if (strncmp(name, "gl_", 3) == 0) {
413 _mesa_error(ctx, GL_INVALID_OPERATION,
414 "glGetFragDataIndex(illegal name)");
415 return -1;
416 }
417
418 /* Not having a fragment shader is not an error.
419 */
420 if (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL)
421 return -1;
422
423 return _mesa_program_resource_location_index(shProg, GL_PROGRAM_OUTPUT,
424 name);
425 }
426
427 GLint GLAPIENTRY
428 _mesa_GetFragDataLocation(GLuint program, const GLchar *name)
429 {
430 GET_CURRENT_CONTEXT(ctx);
431 struct gl_shader_program *const shProg =
432 _mesa_lookup_shader_program_err(ctx, program, "glGetFragDataLocation");
433
434 if (!shProg) {
435 return -1;
436 }
437
438 if (!shProg->LinkStatus) {
439 _mesa_error(ctx, GL_INVALID_OPERATION,
440 "glGetFragDataLocation(program not linked)");
441 return -1;
442 }
443
444 if (!name)
445 return -1;
446
447 if (strncmp(name, "gl_", 3) == 0) {
448 _mesa_error(ctx, GL_INVALID_OPERATION,
449 "glGetFragDataLocation(illegal name)");
450 return -1;
451 }
452
453 /* Not having a fragment shader is not an error.
454 */
455 if (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL)
456 return -1;
457
458 struct gl_program_resource *res =
459 _mesa_program_resource_find_name(shProg, GL_PROGRAM_OUTPUT, name);
460
461 if (!res)
462 return -1;
463
464 GLint loc = program_resource_location(shProg, res, name);
465
466 /* The extra check against against 0 is made because of builtin-attribute
467 * locations that have offset applied. Function program_resource_location
468 * can return built-in attribute locations < 0 and glGetFragDataLocation
469 * cannot be used on "conventional" attributes.
470 *
471 * From page 95 of the OpenGL 3.0 spec:
472 *
473 * "If name is not an active attribute, if name is a conventional
474 * attribute, or if an error occurs, -1 will be returned."
475 */
476 return (loc >= 0) ? loc : -1;
477 }
478
479 const char*
480 _mesa_program_resource_name(struct gl_program_resource *res)
481 {
482 const ir_variable *var;
483 switch (res->Type) {
484 case GL_UNIFORM_BLOCK:
485 return RESOURCE_UBO(res)->Name;
486 case GL_TRANSFORM_FEEDBACK_VARYING:
487 return RESOURCE_XFB(res)->Name;
488 case GL_PROGRAM_INPUT:
489 var = RESOURCE_VAR(res);
490 /* Special case gl_VertexIDMESA -> gl_VertexID. */
491 if (var->data.mode == ir_var_system_value &&
492 var->data.location == SYSTEM_VALUE_VERTEX_ID_ZERO_BASE) {
493 return "gl_VertexID";
494 }
495 /* fallthrough */
496 case GL_PROGRAM_OUTPUT:
497 return RESOURCE_VAR(res)->name;
498 case GL_UNIFORM:
499 return RESOURCE_UNI(res)->name;
500 default:
501 assert(!"support for resource type not implemented");
502 }
503 return NULL;
504 }
505
506
507 unsigned
508 _mesa_program_resource_array_size(struct gl_program_resource *res)
509 {
510 switch (res->Type) {
511 case GL_TRANSFORM_FEEDBACK_VARYING:
512 return RESOURCE_XFB(res)->Size > 1 ?
513 RESOURCE_XFB(res)->Size : 0;
514 case GL_PROGRAM_INPUT:
515 case GL_PROGRAM_OUTPUT:
516 return RESOURCE_VAR(res)->data.max_array_access;
517 case GL_UNIFORM:
518 return RESOURCE_UNI(res)->array_elements;
519 case GL_ATOMIC_COUNTER_BUFFER:
520 case GL_UNIFORM_BLOCK:
521 return 0;
522 default:
523 assert(!"support for resource type not implemented");
524 }
525 return 0;
526 }
527
528 static int
529 array_index_of_resource(struct gl_program_resource *res,
530 const char *name)
531 {
532 assert(res->Data);
533
534 switch (res->Type) {
535 case GL_PROGRAM_INPUT:
536 case GL_PROGRAM_OUTPUT:
537 return get_matching_index(RESOURCE_VAR(res), name);
538 default:
539 assert(!"support for resource type not implemented");
540 return -1;
541 }
542 }
543
544 /* Find a program resource with specific name in given interface.
545 */
546 struct gl_program_resource *
547 _mesa_program_resource_find_name(struct gl_shader_program *shProg,
548 GLenum programInterface, const char *name)
549 {
550 GET_CURRENT_CONTEXT(ctx);
551 const char *full_name = name;
552
553 /* When context has 'VertexID_is_zero_based' set, gl_VertexID has been
554 * lowered to gl_VertexIDMESA.
555 */
556 if (name && ctx->Const.VertexID_is_zero_based) {
557 if (strcmp(name, "gl_VertexID") == 0)
558 full_name = "gl_VertexIDMESA";
559 }
560
561 struct gl_program_resource *res = shProg->ProgramResourceList;
562 for (unsigned i = 0; i < shProg->NumProgramResourceList; i++, res++) {
563 if (res->Type != programInterface)
564 continue;
565
566 /* Resource basename. */
567 const char *rname = _mesa_program_resource_name(res);
568 unsigned baselen = strlen(rname);
569
570 switch (programInterface) {
571 case GL_TRANSFORM_FEEDBACK_VARYING:
572 case GL_UNIFORM_BLOCK:
573 case GL_UNIFORM:
574 if (strncmp(rname, name, baselen) == 0) {
575 /* Basename match, check if array or struct. */
576 if (name[baselen] == '\0' ||
577 name[baselen] == '[' ||
578 name[baselen] == '.') {
579 return res;
580 }
581 }
582 break;
583 case GL_PROGRAM_INPUT:
584 case GL_PROGRAM_OUTPUT:
585 if (array_index_of_resource(res, full_name) >= 0)
586 return res;
587 break;
588 default:
589 assert(!"not implemented for given interface");
590 }
591 }
592 return NULL;
593 }
594
595 static GLuint
596 calc_resource_index(struct gl_shader_program *shProg,
597 struct gl_program_resource *res)
598 {
599 unsigned i;
600 GLuint index = 0;
601 for (i = 0; i < shProg->NumProgramResourceList; i++) {
602 if (&shProg->ProgramResourceList[i] == res)
603 return index;
604 if (shProg->ProgramResourceList[i].Type == res->Type)
605 index++;
606 }
607 return GL_INVALID_INDEX;
608 }
609
610 /**
611 * Calculate index for the given resource.
612 */
613 GLuint
614 _mesa_program_resource_index(struct gl_shader_program *shProg,
615 struct gl_program_resource *res)
616 {
617 if (!res)
618 return GL_INVALID_INDEX;
619
620 switch (res->Type) {
621 case GL_UNIFORM_BLOCK:
622 return RESOURCE_UBO(res)- shProg->UniformBlocks;
623 case GL_ATOMIC_COUNTER_BUFFER:
624 return RESOURCE_ATC(res) - shProg->AtomicBuffers;
625 case GL_TRANSFORM_FEEDBACK_VARYING:
626 default:
627 return calc_resource_index(shProg, res);
628 }
629 }
630
631 /* Find a program resource with specific index in given interface.
632 */
633 struct gl_program_resource *
634 _mesa_program_resource_find_index(struct gl_shader_program *shProg,
635 GLenum programInterface, GLuint index)
636 {
637 struct gl_program_resource *res = shProg->ProgramResourceList;
638 int idx = -1;
639
640 for (unsigned i = 0; i < shProg->NumProgramResourceList; i++, res++) {
641 if (res->Type != programInterface)
642 continue;
643
644 switch (res->Type) {
645 case GL_UNIFORM_BLOCK:
646 case GL_ATOMIC_COUNTER_BUFFER:
647 if (_mesa_program_resource_index(shProg, res) == index)
648 return res;
649 break;
650 case GL_TRANSFORM_FEEDBACK_VARYING:
651 case GL_PROGRAM_INPUT:
652 case GL_PROGRAM_OUTPUT:
653 case GL_UNIFORM:
654 if (++idx == (int) index)
655 return res;
656 break;
657 default:
658 assert(!"not implemented for given interface");
659 }
660 }
661 return NULL;
662 }
663
664 /* Get full name of a program resource.
665 */
666 bool
667 _mesa_get_program_resource_name(struct gl_shader_program *shProg,
668 GLenum programInterface, GLuint index,
669 GLsizei bufSize, GLsizei *length,
670 GLchar *name, const char *caller)
671 {
672 GET_CURRENT_CONTEXT(ctx);
673
674 /* Find resource with given interface and index. */
675 struct gl_program_resource *res =
676 _mesa_program_resource_find_index(shProg, programInterface, index);
677
678 /* The error INVALID_VALUE is generated if <index> is greater than
679 * or equal to the number of entries in the active resource list for
680 * <programInterface>.
681 */
682 if (!res) {
683 _mesa_error(ctx, GL_INVALID_VALUE, "%s(index %u)", caller, index);
684 return false;
685 }
686
687 if (bufSize < 0) {
688 _mesa_error(ctx, GL_INVALID_VALUE, "%s(bufSize %d)", caller, bufSize);
689 return false;
690 }
691
692 GLsizei localLength;
693
694 if (length == NULL)
695 length = &localLength;
696
697 _mesa_copy_string(name, bufSize, length, _mesa_program_resource_name(res));
698
699 /* Page 61 (page 73 of the PDF) in section 2.11 of the OpenGL ES 3.0
700 * spec says:
701 *
702 * "If the active uniform is an array, the uniform name returned in
703 * name will always be the name of the uniform array appended with
704 * "[0]"."
705 *
706 * The same text also appears in the OpenGL 4.2 spec. It does not,
707 * however, appear in any previous spec. Previous specifications are
708 * ambiguous in this regard. However, either name can later be passed
709 * to glGetUniformLocation (and related APIs), so there shouldn't be any
710 * harm in always appending "[0]" to uniform array names.
711 *
712 * Geometry shader stage has different naming convention where the 'normal'
713 * condition is an array, therefore for variables referenced in geometry
714 * stage we do not add '[0]'.
715 *
716 * Note, that TCS outputs and TES inputs should not have index appended
717 * either.
718 */
719 bool add_index = !(((programInterface == GL_PROGRAM_INPUT) &&
720 res->StageReferences & (1 << MESA_SHADER_GEOMETRY)));
721
722 if (add_index && _mesa_program_resource_array_size(res)) {
723 int i;
724
725 /* The comparison is strange because *length does *NOT* include the
726 * terminating NUL, but maxLength does.
727 */
728 for (i = 0; i < 3 && (*length + i + 1) < bufSize; i++)
729 name[*length + i] = "[0]"[i];
730
731 name[*length + i] = '\0';
732 *length += i;
733 }
734 return true;
735 }
736
737 static GLint
738 program_resource_location(struct gl_shader_program *shProg,
739 struct gl_program_resource *res, const char *name)
740 {
741 unsigned index, offset;
742 int array_index = -1;
743
744 if (res->Type == GL_PROGRAM_INPUT || res->Type == GL_PROGRAM_OUTPUT) {
745 array_index = array_index_of_resource(res, name);
746 if (array_index < 0)
747 return -1;
748 }
749
750 /* Built-in locations should report GL_INVALID_INDEX. */
751 if (is_gl_identifier(name))
752 return GL_INVALID_INDEX;
753
754 /* VERT_ATTRIB_GENERIC0 and FRAG_RESULT_DATA0 are decremented as these
755 * offsets are used internally to differentiate between built-in attributes
756 * and user-defined attributes.
757 */
758 switch (res->Type) {
759 case GL_PROGRAM_INPUT:
760 return RESOURCE_VAR(res)->data.location + array_index - VERT_ATTRIB_GENERIC0;
761 case GL_PROGRAM_OUTPUT:
762 return RESOURCE_VAR(res)->data.location + array_index - FRAG_RESULT_DATA0;
763 case GL_UNIFORM:
764 index = _mesa_get_uniform_location(shProg, name, &offset);
765
766 if (index == GL_INVALID_INDEX)
767 return -1;
768
769 /* From the GL_ARB_uniform_buffer_object spec:
770 *
771 * "The value -1 will be returned if <name> does not correspond to an
772 * active uniform variable name in <program>, if <name> is associated
773 * with a named uniform block, or if <name> starts with the reserved
774 * prefix "gl_"."
775 */
776 if (RESOURCE_UNI(res)->block_index != -1 ||
777 RESOURCE_UNI(res)->atomic_buffer_index != -1)
778 return -1;
779
780 /* location in remap table + array element offset */
781 return RESOURCE_UNI(res)->remap_location + offset;
782
783 default:
784 return -1;
785 }
786 }
787
788 /**
789 * Function implements following location queries:
790 * glGetUniformLocation
791 */
792 GLint
793 _mesa_program_resource_location(struct gl_shader_program *shProg,
794 GLenum programInterface, const char *name)
795 {
796 struct gl_program_resource *res =
797 _mesa_program_resource_find_name(shProg, programInterface, name);
798
799 /* Resource not found. */
800 if (!res)
801 return -1;
802
803 return program_resource_location(shProg, res, name);
804 }
805
806 /**
807 * Function implements following index queries:
808 * glGetFragDataIndex
809 */
810 GLint
811 _mesa_program_resource_location_index(struct gl_shader_program *shProg,
812 GLenum programInterface, const char *name)
813 {
814 struct gl_program_resource *res =
815 _mesa_program_resource_find_name(shProg, programInterface, name);
816
817 /* Non-existent variable or resource is not referenced by fragment stage. */
818 if (!res || !(res->StageReferences & (1 << MESA_SHADER_FRAGMENT)))
819 return -1;
820
821 return RESOURCE_VAR(res)->data.index;
822 }
823
824 static uint8_t
825 stage_from_enum(GLenum ref)
826 {
827 switch (ref) {
828 case GL_REFERENCED_BY_VERTEX_SHADER:
829 return MESA_SHADER_VERTEX;
830 case GL_REFERENCED_BY_GEOMETRY_SHADER:
831 return MESA_SHADER_GEOMETRY;
832 case GL_REFERENCED_BY_FRAGMENT_SHADER:
833 return MESA_SHADER_FRAGMENT;
834 case GL_REFERENCED_BY_COMPUTE_SHADER:
835 return MESA_SHADER_COMPUTE;
836 default:
837 assert(!"shader stage not supported");
838 return MESA_SHADER_STAGES;
839 }
840 }
841
842 /**
843 * Check if resource is referenced by given 'referenced by' stage enum.
844 * ATC and UBO resources hold stage references of their own.
845 */
846 static bool
847 is_resource_referenced(struct gl_shader_program *shProg,
848 struct gl_program_resource *res,
849 GLuint index, uint8_t stage)
850 {
851 /* First, check if we even have such a stage active. */
852 if (!shProg->_LinkedShaders[stage])
853 return false;
854
855 if (res->Type == GL_ATOMIC_COUNTER_BUFFER)
856 return RESOURCE_ATC(res)->StageReferences[stage];
857
858 if (res->Type == GL_UNIFORM_BLOCK)
859 return shProg->UniformBlockStageIndex[stage][index] != -1;
860
861 return res->StageReferences & (1 << stage);
862 }
863
864 static unsigned
865 get_buffer_property(struct gl_shader_program *shProg,
866 struct gl_program_resource *res, const GLenum prop,
867 GLint *val, const char *caller)
868 {
869 GET_CURRENT_CONTEXT(ctx);
870 if (res->Type != GL_UNIFORM_BLOCK &&
871 res->Type != GL_ATOMIC_COUNTER_BUFFER)
872 goto invalid_operation;
873
874 if (res->Type == GL_UNIFORM_BLOCK) {
875 switch (prop) {
876 case GL_BUFFER_BINDING:
877 *val = RESOURCE_UBO(res)->Binding;
878 return 1;
879 case GL_BUFFER_DATA_SIZE:
880 *val = RESOURCE_UBO(res)->UniformBufferSize;
881 return 1;
882 case GL_NUM_ACTIVE_VARIABLES:
883 *val = 0;
884 for (unsigned i = 0; i < RESOURCE_UBO(res)->NumUniforms; i++) {
885 const char *iname = RESOURCE_UBO(res)->Uniforms[i].IndexName;
886 struct gl_program_resource *uni =
887 _mesa_program_resource_find_name(shProg, GL_UNIFORM, iname);
888 if (!uni)
889 continue;
890 (*val)++;
891 }
892 return 1;
893 case GL_ACTIVE_VARIABLES:
894 for (unsigned i = 0; i < RESOURCE_UBO(res)->NumUniforms; i++) {
895 const char *iname = RESOURCE_UBO(res)->Uniforms[i].IndexName;
896 struct gl_program_resource *uni =
897 _mesa_program_resource_find_name(shProg, GL_UNIFORM, iname);
898 if (!uni)
899 continue;
900 *val++ =
901 _mesa_program_resource_index(shProg, uni);
902 }
903 return RESOURCE_UBO(res)->NumUniforms;
904 }
905 } else if (res->Type == GL_ATOMIC_COUNTER_BUFFER) {
906 switch (prop) {
907 case GL_BUFFER_BINDING:
908 *val = RESOURCE_ATC(res)->Binding;
909 return 1;
910 case GL_BUFFER_DATA_SIZE:
911 *val = RESOURCE_ATC(res)->MinimumSize;
912 return 1;
913 case GL_NUM_ACTIVE_VARIABLES:
914 *val = RESOURCE_ATC(res)->NumUniforms;
915 return 1;
916 case GL_ACTIVE_VARIABLES:
917 for (unsigned i = 0; i < RESOURCE_ATC(res)->NumUniforms; i++)
918 *val++ = RESOURCE_ATC(res)->Uniforms[i];
919 return RESOURCE_ATC(res)->NumUniforms;
920 }
921 }
922 assert(!"support for property type not implemented");
923
924 invalid_operation:
925 _mesa_error(ctx, GL_INVALID_OPERATION, "%s(%s prop %s)", caller,
926 _mesa_enum_to_string(res->Type),
927 _mesa_enum_to_string(prop));
928
929 return 0;
930 }
931
932 unsigned
933 _mesa_program_resource_prop(struct gl_shader_program *shProg,
934 struct gl_program_resource *res, GLuint index,
935 const GLenum prop, GLint *val, const char *caller)
936 {
937 GET_CURRENT_CONTEXT(ctx);
938
939 #define VALIDATE_TYPE(type)\
940 if (res->Type != type)\
941 goto invalid_operation;
942
943 switch(prop) {
944 case GL_NAME_LENGTH:
945 if (res->Type == GL_ATOMIC_COUNTER_BUFFER)
946 goto invalid_operation;
947 /* Base name +3 if array '[0]' + terminator. */
948 *val = strlen(_mesa_program_resource_name(res)) +
949 (_mesa_program_resource_array_size(res) > 0 ? 3 : 0) + 1;
950 return 1;
951 case GL_TYPE:
952 switch (res->Type) {
953 case GL_UNIFORM:
954 *val = RESOURCE_UNI(res)->type->gl_type;
955 return 1;
956 case GL_PROGRAM_INPUT:
957 case GL_PROGRAM_OUTPUT:
958 *val = RESOURCE_VAR(res)->type->gl_type;
959 return 1;
960 case GL_TRANSFORM_FEEDBACK_VARYING:
961 *val = RESOURCE_XFB(res)->Type;
962 return 1;
963 default:
964 goto invalid_operation;
965 }
966 case GL_ARRAY_SIZE:
967 switch (res->Type) {
968 case GL_UNIFORM:
969 *val = MAX2(RESOURCE_UNI(res)->array_elements, 1);
970 return 1;
971 case GL_PROGRAM_INPUT:
972 case GL_PROGRAM_OUTPUT:
973 *val = MAX2(RESOURCE_VAR(res)->type->length, 1);
974 return 1;
975 case GL_TRANSFORM_FEEDBACK_VARYING:
976 *val = MAX2(RESOURCE_XFB(res)->Size, 1);
977 return 1;
978 default:
979 goto invalid_operation;
980 }
981 case GL_OFFSET:
982 VALIDATE_TYPE(GL_UNIFORM);
983 *val = RESOURCE_UNI(res)->offset;
984 return 1;
985 case GL_BLOCK_INDEX:
986 VALIDATE_TYPE(GL_UNIFORM);
987 *val = RESOURCE_UNI(res)->block_index;
988 return 1;
989 case GL_ARRAY_STRIDE:
990 VALIDATE_TYPE(GL_UNIFORM);
991 *val = RESOURCE_UNI(res)->array_stride;
992 return 1;
993 case GL_MATRIX_STRIDE:
994 VALIDATE_TYPE(GL_UNIFORM);
995 *val = RESOURCE_UNI(res)->matrix_stride;
996 return 1;
997 case GL_IS_ROW_MAJOR:
998 VALIDATE_TYPE(GL_UNIFORM);
999 *val = RESOURCE_UNI(res)->row_major;
1000 return 1;
1001 case GL_ATOMIC_COUNTER_BUFFER_INDEX:
1002 VALIDATE_TYPE(GL_UNIFORM);
1003 *val = RESOURCE_UNI(res)->atomic_buffer_index;
1004 return 1;
1005 case GL_BUFFER_BINDING:
1006 case GL_BUFFER_DATA_SIZE:
1007 case GL_NUM_ACTIVE_VARIABLES:
1008 case GL_ACTIVE_VARIABLES:
1009 return get_buffer_property(shProg, res, prop, val, caller);
1010 case GL_REFERENCED_BY_COMPUTE_SHADER:
1011 if (!_mesa_has_compute_shaders(ctx))
1012 goto invalid_enum;
1013 /* fallthrough */
1014 case GL_REFERENCED_BY_VERTEX_SHADER:
1015 case GL_REFERENCED_BY_GEOMETRY_SHADER:
1016 case GL_REFERENCED_BY_FRAGMENT_SHADER:
1017 switch (res->Type) {
1018 case GL_UNIFORM:
1019 case GL_PROGRAM_INPUT:
1020 case GL_PROGRAM_OUTPUT:
1021 case GL_UNIFORM_BLOCK:
1022 case GL_ATOMIC_COUNTER_BUFFER:
1023 *val = is_resource_referenced(shProg, res, index,
1024 stage_from_enum(prop));
1025 return 1;
1026 default:
1027 goto invalid_operation;
1028 }
1029 case GL_LOCATION:
1030 switch (res->Type) {
1031 case GL_UNIFORM:
1032 case GL_PROGRAM_INPUT:
1033 case GL_PROGRAM_OUTPUT:
1034 *val = program_resource_location(shProg, res,
1035 _mesa_program_resource_name(res));
1036 return 1;
1037 default:
1038 goto invalid_operation;
1039 }
1040 case GL_LOCATION_INDEX:
1041 if (res->Type != GL_PROGRAM_OUTPUT)
1042 goto invalid_operation;
1043 *val = RESOURCE_VAR(res)->data.index;
1044 return 1;
1045
1046 /* GL_ARB_tessellation_shader */
1047 case GL_IS_PER_PATCH:
1048 case GL_REFERENCED_BY_TESS_CONTROL_SHADER:
1049 case GL_REFERENCED_BY_TESS_EVALUATION_SHADER:
1050 default:
1051 goto invalid_enum;
1052 }
1053
1054 #undef VALIDATE_TYPE
1055
1056 invalid_enum:
1057 _mesa_error(ctx, GL_INVALID_ENUM, "%s(%s prop %s)", caller,
1058 _mesa_enum_to_string(res->Type),
1059 _mesa_enum_to_string(prop));
1060 return 0;
1061
1062 invalid_operation:
1063 _mesa_error(ctx, GL_INVALID_OPERATION, "%s(%s prop %s)", caller,
1064 _mesa_enum_to_string(res->Type),
1065 _mesa_enum_to_string(prop));
1066 return 0;
1067 }
1068
1069 extern void
1070 _mesa_get_program_resourceiv(struct gl_shader_program *shProg,
1071 GLenum programInterface, GLuint index, GLsizei propCount,
1072 const GLenum *props, GLsizei bufSize,
1073 GLsizei *length, GLint *params)
1074 {
1075 GET_CURRENT_CONTEXT(ctx);
1076 GLint *val = (GLint *) params;
1077 const GLenum *prop = props;
1078 GLsizei amount = 0;
1079
1080 struct gl_program_resource *res =
1081 _mesa_program_resource_find_index(shProg, programInterface, index);
1082
1083 /* No such resource found or bufSize negative. */
1084 if (!res || bufSize < 0) {
1085 _mesa_error(ctx, GL_INVALID_VALUE,
1086 "glGetProgramResourceiv(%s index %d bufSize %d)",
1087 _mesa_enum_to_string(programInterface), index, bufSize);
1088 return;
1089 }
1090
1091 /* Write propCount values until error occurs or bufSize reached. */
1092 for (int i = 0; i < propCount && i < bufSize; i++, val++, prop++) {
1093 int props_written =
1094 _mesa_program_resource_prop(shProg, res, index, *prop, val,
1095 "glGetProgramResourceiv");
1096
1097 /* Error happened. */
1098 if (props_written == 0)
1099 return;
1100
1101 amount += props_written;
1102 }
1103
1104 /* If <length> is not NULL, the actual number of integer values
1105 * written to <params> will be written to <length>.
1106 */
1107 if (length)
1108 *length = amount;
1109 }