vk/image: Add an explicit DestroyImage function
[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 * glGetAttribLocation
791 * glGetFragDataLocation
792 * glGetUniformLocation
793 */
794 GLint
795 _mesa_program_resource_location(struct gl_shader_program *shProg,
796 GLenum programInterface, const char *name)
797 {
798 struct gl_program_resource *res =
799 _mesa_program_resource_find_name(shProg, programInterface, name);
800
801 /* Resource not found. */
802 if (!res)
803 return -1;
804
805 return program_resource_location(shProg, res, name);
806 }
807
808 /**
809 * Function implements following index queries:
810 * glGetFragDataIndex
811 */
812 GLint
813 _mesa_program_resource_location_index(struct gl_shader_program *shProg,
814 GLenum programInterface, const char *name)
815 {
816 struct gl_program_resource *res =
817 _mesa_program_resource_find_name(shProg, programInterface, name);
818
819 /* Non-existent variable or resource is not referenced by fragment stage. */
820 if (!res || !(res->StageReferences & (1 << MESA_SHADER_FRAGMENT)))
821 return -1;
822
823 return RESOURCE_VAR(res)->data.index;
824 }
825
826 static uint8_t
827 stage_from_enum(GLenum ref)
828 {
829 switch (ref) {
830 case GL_REFERENCED_BY_VERTEX_SHADER:
831 return MESA_SHADER_VERTEX;
832 case GL_REFERENCED_BY_GEOMETRY_SHADER:
833 return MESA_SHADER_GEOMETRY;
834 case GL_REFERENCED_BY_FRAGMENT_SHADER:
835 return MESA_SHADER_FRAGMENT;
836 case GL_REFERENCED_BY_COMPUTE_SHADER:
837 return MESA_SHADER_COMPUTE;
838 default:
839 assert(!"shader stage not supported");
840 return MESA_SHADER_STAGES;
841 }
842 }
843
844 /**
845 * Check if resource is referenced by given 'referenced by' stage enum.
846 * ATC and UBO resources hold stage references of their own.
847 */
848 static bool
849 is_resource_referenced(struct gl_shader_program *shProg,
850 struct gl_program_resource *res,
851 GLuint index, uint8_t stage)
852 {
853 /* First, check if we even have such a stage active. */
854 if (!shProg->_LinkedShaders[stage])
855 return false;
856
857 if (res->Type == GL_ATOMIC_COUNTER_BUFFER)
858 return RESOURCE_ATC(res)->StageReferences[stage];
859
860 if (res->Type == GL_UNIFORM_BLOCK)
861 return shProg->UniformBlockStageIndex[stage][index] != -1;
862
863 return res->StageReferences & (1 << stage);
864 }
865
866 static unsigned
867 get_buffer_property(struct gl_shader_program *shProg,
868 struct gl_program_resource *res, const GLenum prop,
869 GLint *val, const char *caller)
870 {
871 GET_CURRENT_CONTEXT(ctx);
872 if (res->Type != GL_UNIFORM_BLOCK &&
873 res->Type != GL_ATOMIC_COUNTER_BUFFER)
874 goto invalid_operation;
875
876 if (res->Type == GL_UNIFORM_BLOCK) {
877 switch (prop) {
878 case GL_BUFFER_BINDING:
879 *val = RESOURCE_UBO(res)->Binding;
880 return 1;
881 case GL_BUFFER_DATA_SIZE:
882 *val = RESOURCE_UBO(res)->UniformBufferSize;
883 return 1;
884 case GL_NUM_ACTIVE_VARIABLES:
885 *val = 0;
886 for (unsigned i = 0; i < RESOURCE_UBO(res)->NumUniforms; i++) {
887 const char *iname = RESOURCE_UBO(res)->Uniforms[i].IndexName;
888 struct gl_program_resource *uni =
889 _mesa_program_resource_find_name(shProg, GL_UNIFORM, iname);
890 if (!uni)
891 continue;
892 (*val)++;
893 }
894 return 1;
895 case GL_ACTIVE_VARIABLES:
896 for (unsigned i = 0; i < RESOURCE_UBO(res)->NumUniforms; i++) {
897 const char *iname = RESOURCE_UBO(res)->Uniforms[i].IndexName;
898 struct gl_program_resource *uni =
899 _mesa_program_resource_find_name(shProg, GL_UNIFORM, iname);
900 if (!uni)
901 continue;
902 *val++ =
903 _mesa_program_resource_index(shProg, uni);
904 }
905 return RESOURCE_UBO(res)->NumUniforms;
906 }
907 } else if (res->Type == GL_ATOMIC_COUNTER_BUFFER) {
908 switch (prop) {
909 case GL_BUFFER_BINDING:
910 *val = RESOURCE_ATC(res)->Binding;
911 return 1;
912 case GL_BUFFER_DATA_SIZE:
913 *val = RESOURCE_ATC(res)->MinimumSize;
914 return 1;
915 case GL_NUM_ACTIVE_VARIABLES:
916 *val = RESOURCE_ATC(res)->NumUniforms;
917 return 1;
918 case GL_ACTIVE_VARIABLES:
919 for (unsigned i = 0; i < RESOURCE_ATC(res)->NumUniforms; i++)
920 *val++ = RESOURCE_ATC(res)->Uniforms[i];
921 return RESOURCE_ATC(res)->NumUniforms;
922 }
923 }
924 assert(!"support for property type not implemented");
925
926 invalid_operation:
927 _mesa_error(ctx, GL_INVALID_OPERATION, "%s(%s prop %s)", caller,
928 _mesa_lookup_enum_by_nr(res->Type),
929 _mesa_lookup_enum_by_nr(prop));
930
931 return 0;
932 }
933
934 unsigned
935 _mesa_program_resource_prop(struct gl_shader_program *shProg,
936 struct gl_program_resource *res, GLuint index,
937 const GLenum prop, GLint *val, const char *caller)
938 {
939 GET_CURRENT_CONTEXT(ctx);
940
941 #define VALIDATE_TYPE(type)\
942 if (res->Type != type)\
943 goto invalid_operation;
944
945 switch(prop) {
946 case GL_NAME_LENGTH:
947 if (res->Type == GL_ATOMIC_COUNTER_BUFFER)
948 goto invalid_operation;
949 /* Base name +3 if array '[0]' + terminator. */
950 *val = strlen(_mesa_program_resource_name(res)) +
951 (_mesa_program_resource_array_size(res) > 0 ? 3 : 0) + 1;
952 return 1;
953 case GL_TYPE:
954 switch (res->Type) {
955 case GL_UNIFORM:
956 *val = RESOURCE_UNI(res)->type->gl_type;
957 return 1;
958 case GL_PROGRAM_INPUT:
959 case GL_PROGRAM_OUTPUT:
960 *val = RESOURCE_VAR(res)->type->gl_type;
961 return 1;
962 case GL_TRANSFORM_FEEDBACK_VARYING:
963 *val = RESOURCE_XFB(res)->Type;
964 return 1;
965 default:
966 goto invalid_operation;
967 }
968 case GL_ARRAY_SIZE:
969 switch (res->Type) {
970 case GL_UNIFORM:
971 *val = MAX2(RESOURCE_UNI(res)->array_elements, 1);
972 return 1;
973 case GL_PROGRAM_INPUT:
974 case GL_PROGRAM_OUTPUT:
975 *val = MAX2(RESOURCE_VAR(res)->type->length, 1);
976 return 1;
977 case GL_TRANSFORM_FEEDBACK_VARYING:
978 *val = MAX2(RESOURCE_XFB(res)->Size, 1);
979 return 1;
980 default:
981 goto invalid_operation;
982 }
983 case GL_OFFSET:
984 VALIDATE_TYPE(GL_UNIFORM);
985 *val = RESOURCE_UNI(res)->offset;
986 return 1;
987 case GL_BLOCK_INDEX:
988 VALIDATE_TYPE(GL_UNIFORM);
989 *val = RESOURCE_UNI(res)->block_index;
990 return 1;
991 case GL_ARRAY_STRIDE:
992 VALIDATE_TYPE(GL_UNIFORM);
993 *val = RESOURCE_UNI(res)->array_stride;
994 return 1;
995 case GL_MATRIX_STRIDE:
996 VALIDATE_TYPE(GL_UNIFORM);
997 *val = RESOURCE_UNI(res)->matrix_stride;
998 return 1;
999 case GL_IS_ROW_MAJOR:
1000 VALIDATE_TYPE(GL_UNIFORM);
1001 *val = RESOURCE_UNI(res)->row_major;
1002 return 1;
1003 case GL_ATOMIC_COUNTER_BUFFER_INDEX:
1004 VALIDATE_TYPE(GL_UNIFORM);
1005 *val = RESOURCE_UNI(res)->atomic_buffer_index;
1006 return 1;
1007 case GL_BUFFER_BINDING:
1008 case GL_BUFFER_DATA_SIZE:
1009 case GL_NUM_ACTIVE_VARIABLES:
1010 case GL_ACTIVE_VARIABLES:
1011 return get_buffer_property(shProg, res, prop, val, caller);
1012 case GL_REFERENCED_BY_COMPUTE_SHADER:
1013 if (!_mesa_has_compute_shaders(ctx))
1014 goto invalid_enum;
1015 /* fallthrough */
1016 case GL_REFERENCED_BY_VERTEX_SHADER:
1017 case GL_REFERENCED_BY_GEOMETRY_SHADER:
1018 case GL_REFERENCED_BY_FRAGMENT_SHADER:
1019 switch (res->Type) {
1020 case GL_UNIFORM:
1021 case GL_PROGRAM_INPUT:
1022 case GL_PROGRAM_OUTPUT:
1023 case GL_UNIFORM_BLOCK:
1024 case GL_ATOMIC_COUNTER_BUFFER:
1025 *val = is_resource_referenced(shProg, res, index,
1026 stage_from_enum(prop));
1027 return 1;
1028 default:
1029 goto invalid_operation;
1030 }
1031 case GL_LOCATION:
1032 switch (res->Type) {
1033 case GL_UNIFORM:
1034 case GL_PROGRAM_INPUT:
1035 case GL_PROGRAM_OUTPUT:
1036 *val = program_resource_location(shProg, res,
1037 _mesa_program_resource_name(res));
1038 return 1;
1039 default:
1040 goto invalid_operation;
1041 }
1042 case GL_LOCATION_INDEX:
1043 if (res->Type != GL_PROGRAM_OUTPUT)
1044 goto invalid_operation;
1045 *val = RESOURCE_VAR(res)->data.index;
1046 return 1;
1047
1048 /* GL_ARB_tessellation_shader */
1049 case GL_IS_PER_PATCH:
1050 case GL_REFERENCED_BY_TESS_CONTROL_SHADER:
1051 case GL_REFERENCED_BY_TESS_EVALUATION_SHADER:
1052 default:
1053 goto invalid_enum;
1054 }
1055
1056 #undef VALIDATE_TYPE
1057
1058 invalid_enum:
1059 _mesa_error(ctx, GL_INVALID_ENUM, "%s(%s prop %s)", caller,
1060 _mesa_lookup_enum_by_nr(res->Type),
1061 _mesa_lookup_enum_by_nr(prop));
1062 return 0;
1063
1064 invalid_operation:
1065 _mesa_error(ctx, GL_INVALID_OPERATION, "%s(%s prop %s)", caller,
1066 _mesa_lookup_enum_by_nr(res->Type),
1067 _mesa_lookup_enum_by_nr(prop));
1068 return 0;
1069 }
1070
1071 extern void
1072 _mesa_get_program_resourceiv(struct gl_shader_program *shProg,
1073 GLenum programInterface, GLuint index, GLsizei propCount,
1074 const GLenum *props, GLsizei bufSize,
1075 GLsizei *length, GLint *params)
1076 {
1077 GET_CURRENT_CONTEXT(ctx);
1078 GLint *val = (GLint *) params;
1079 const GLenum *prop = props;
1080 GLsizei amount = 0;
1081
1082 struct gl_program_resource *res =
1083 _mesa_program_resource_find_index(shProg, programInterface, index);
1084
1085 /* No such resource found or bufSize negative. */
1086 if (!res || bufSize < 0) {
1087 _mesa_error(ctx, GL_INVALID_VALUE,
1088 "glGetProgramResourceiv(%s index %d bufSize %d)",
1089 _mesa_lookup_enum_by_nr(programInterface), index, bufSize);
1090 return;
1091 }
1092
1093 /* Write propCount values until error occurs or bufSize reached. */
1094 for (int i = 0; i < propCount && i < bufSize; i++, val++, prop++) {
1095 int props_written =
1096 _mesa_program_resource_prop(shProg, res, index, *prop, val,
1097 "glGetProgramResourceiv");
1098
1099 /* Error happened. */
1100 if (props_written == 0)
1101 return;
1102
1103 amount += props_written;
1104 }
1105
1106 /* If <length> is not NULL, the actual number of integer values
1107 * written to <params> will be written to <length>.
1108 */
1109 if (length)
1110 *length = amount;
1111 }