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