mesa: refactor active attrib queries for glGetProgramiv
[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 unsigned
295 _mesa_count_active_attribs(struct gl_shader_program *shProg)
296 {
297 if (!shProg->LinkStatus
298 || shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL) {
299 return 0;
300 }
301
302 struct gl_program_resource *res = shProg->ProgramResourceList;
303 unsigned count = 0;
304 for (unsigned j = 0; j < shProg->NumProgramResourceList; j++, res++) {
305 if (is_active_attrib(RESOURCE_VAR(res)))
306 count++;
307 }
308 return count;
309 }
310
311
312 size_t
313 _mesa_longest_attribute_name_length(struct gl_shader_program *shProg)
314 {
315 if (!shProg->LinkStatus
316 || shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL) {
317 return 0;
318 }
319
320 struct gl_program_resource *res = shProg->ProgramResourceList;
321 size_t longest = 0;
322 for (unsigned j = 0; j < shProg->NumProgramResourceList; j++, res++) {
323 if (res->Type == GL_PROGRAM_INPUT &&
324 res->StageReferences & (1 << MESA_SHADER_VERTEX)) {
325
326 const size_t length = strlen(RESOURCE_VAR(res)->name);
327 if (length >= longest)
328 longest = length + 1;
329 }
330 }
331
332 return longest;
333 }
334
335 void GLAPIENTRY
336 _mesa_BindFragDataLocation(GLuint program, GLuint colorNumber,
337 const GLchar *name)
338 {
339 _mesa_BindFragDataLocationIndexed(program, colorNumber, 0, name);
340 }
341
342 void GLAPIENTRY
343 _mesa_BindFragDataLocationIndexed(GLuint program, GLuint colorNumber,
344 GLuint index, const GLchar *name)
345 {
346 GET_CURRENT_CONTEXT(ctx);
347
348 struct gl_shader_program *const shProg =
349 _mesa_lookup_shader_program_err(ctx, program, "glBindFragDataLocationIndexed");
350 if (!shProg)
351 return;
352
353 if (!name)
354 return;
355
356 if (strncmp(name, "gl_", 3) == 0) {
357 _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFragDataLocationIndexed(illegal name)");
358 return;
359 }
360
361 if (index > 1) {
362 _mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocationIndexed(index)");
363 return;
364 }
365
366 if (index == 0 && colorNumber >= ctx->Const.MaxDrawBuffers) {
367 _mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocationIndexed(colorNumber)");
368 return;
369 }
370
371 if (index == 1 && colorNumber >= ctx->Const.MaxDualSourceDrawBuffers) {
372 _mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocationIndexed(colorNumber)");
373 return;
374 }
375
376 /* Replace the current value if it's already in the list. Add
377 * FRAG_RESULT_DATA0 because that's how the linker differentiates
378 * between built-in attributes and user-defined attributes.
379 */
380 shProg->FragDataBindings->put(colorNumber + FRAG_RESULT_DATA0, name);
381 shProg->FragDataIndexBindings->put(index, name);
382 /*
383 * Note that this binding won't go into effect until
384 * glLinkProgram is called again.
385 */
386
387 }
388
389 GLint GLAPIENTRY
390 _mesa_GetFragDataIndex(GLuint program, const GLchar *name)
391 {
392 GET_CURRENT_CONTEXT(ctx);
393 struct gl_shader_program *const shProg =
394 _mesa_lookup_shader_program_err(ctx, program, "glGetFragDataIndex");
395
396 if (!shProg) {
397 return -1;
398 }
399
400 if (!shProg->LinkStatus) {
401 _mesa_error(ctx, GL_INVALID_OPERATION,
402 "glGetFragDataIndex(program not linked)");
403 return -1;
404 }
405
406 if (!name)
407 return -1;
408
409 if (strncmp(name, "gl_", 3) == 0) {
410 _mesa_error(ctx, GL_INVALID_OPERATION,
411 "glGetFragDataIndex(illegal name)");
412 return -1;
413 }
414
415 /* Not having a fragment shader is not an error.
416 */
417 if (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL)
418 return -1;
419
420 return _mesa_program_resource_location_index(shProg, GL_PROGRAM_OUTPUT,
421 name);
422 }
423
424 GLint GLAPIENTRY
425 _mesa_GetFragDataLocation(GLuint program, const GLchar *name)
426 {
427 GET_CURRENT_CONTEXT(ctx);
428 struct gl_shader_program *const shProg =
429 _mesa_lookup_shader_program_err(ctx, program, "glGetFragDataLocation");
430
431 if (!shProg) {
432 return -1;
433 }
434
435 if (!shProg->LinkStatus) {
436 _mesa_error(ctx, GL_INVALID_OPERATION,
437 "glGetFragDataLocation(program not linked)");
438 return -1;
439 }
440
441 if (!name)
442 return -1;
443
444 if (strncmp(name, "gl_", 3) == 0) {
445 _mesa_error(ctx, GL_INVALID_OPERATION,
446 "glGetFragDataLocation(illegal name)");
447 return -1;
448 }
449
450 /* Not having a fragment shader is not an error.
451 */
452 if (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL)
453 return -1;
454
455 struct gl_program_resource *res =
456 _mesa_program_resource_find_name(shProg, GL_PROGRAM_OUTPUT, name);
457
458 if (!res)
459 return -1;
460
461 GLint loc = program_resource_location(shProg, res, name);
462
463 /* The extra check against against 0 is made because of builtin-attribute
464 * locations that have offset applied. Function program_resource_location
465 * can return built-in attribute locations < 0 and glGetFragDataLocation
466 * cannot be used on "conventional" attributes.
467 *
468 * From page 95 of the OpenGL 3.0 spec:
469 *
470 * "If name is not an active attribute, if name is a conventional
471 * attribute, or if an error occurs, -1 will be returned."
472 */
473 return (loc >= 0) ? loc : -1;
474 }
475
476 const char*
477 _mesa_program_resource_name(struct gl_program_resource *res)
478 {
479 switch (res->Type) {
480 case GL_UNIFORM_BLOCK:
481 return RESOURCE_UBO(res)->Name;
482 case GL_TRANSFORM_FEEDBACK_VARYING:
483 return RESOURCE_XFB(res)->Name;
484 case GL_PROGRAM_INPUT:
485 case GL_PROGRAM_OUTPUT:
486 return RESOURCE_VAR(res)->name;
487 case GL_UNIFORM:
488 return RESOURCE_UNI(res)->name;
489 default:
490 assert(!"support for resource type not implemented");
491 }
492 return NULL;
493 }
494
495
496 unsigned
497 _mesa_program_resource_array_size(struct gl_program_resource *res)
498 {
499 switch (res->Type) {
500 case GL_TRANSFORM_FEEDBACK_VARYING:
501 return RESOURCE_XFB(res)->Size > 1 ?
502 RESOURCE_XFB(res)->Size : 0;
503 case GL_PROGRAM_INPUT:
504 case GL_PROGRAM_OUTPUT:
505 return RESOURCE_VAR(res)->data.max_array_access;
506 case GL_UNIFORM:
507 return RESOURCE_UNI(res)->array_elements;
508 case GL_ATOMIC_COUNTER_BUFFER:
509 case GL_UNIFORM_BLOCK:
510 return 0;
511 default:
512 assert(!"support for resource type not implemented");
513 }
514 return 0;
515 }
516
517 static int
518 array_index_of_resource(struct gl_program_resource *res,
519 const char *name)
520 {
521 assert(res->Data);
522
523 switch (res->Type) {
524 case GL_PROGRAM_INPUT:
525 case GL_PROGRAM_OUTPUT:
526 return get_matching_index(RESOURCE_VAR(res), name);
527 default:
528 assert(!"support for resource type not implemented");
529 return -1;
530 }
531 }
532
533 /* Find a program resource with specific name in given interface.
534 */
535 struct gl_program_resource *
536 _mesa_program_resource_find_name(struct gl_shader_program *shProg,
537 GLenum programInterface, const char *name)
538 {
539 struct gl_program_resource *res = shProg->ProgramResourceList;
540 for (unsigned i = 0; i < shProg->NumProgramResourceList; i++, res++) {
541 if (res->Type != programInterface)
542 continue;
543
544 /* Resource basename. */
545 const char *rname = _mesa_program_resource_name(res);
546 unsigned baselen = strlen(rname);
547
548 switch (programInterface) {
549 case GL_TRANSFORM_FEEDBACK_VARYING:
550 case GL_UNIFORM_BLOCK:
551 case GL_UNIFORM:
552 if (strncmp(rname, name, baselen) == 0) {
553 /* Basename match, check if array or struct. */
554 if (name[baselen] == '\0' ||
555 name[baselen] == '[' ||
556 name[baselen] == '.') {
557 return res;
558 }
559 }
560 break;
561 case GL_PROGRAM_INPUT:
562 case GL_PROGRAM_OUTPUT:
563 if (array_index_of_resource(res, name) >= 0)
564 return res;
565 break;
566 default:
567 assert(!"not implemented for given interface");
568 }
569 }
570 return NULL;
571 }
572
573 static GLuint
574 calc_resource_index(struct gl_shader_program *shProg,
575 struct gl_program_resource *res)
576 {
577 unsigned i;
578 GLuint index = 0;
579 for (i = 0; i < shProg->NumProgramResourceList; i++) {
580 if (&shProg->ProgramResourceList[i] == res)
581 return index;
582 if (shProg->ProgramResourceList[i].Type == res->Type)
583 index++;
584 }
585 return GL_INVALID_INDEX;
586 }
587
588 /**
589 * Calculate index for the given resource.
590 */
591 GLuint
592 _mesa_program_resource_index(struct gl_shader_program *shProg,
593 struct gl_program_resource *res)
594 {
595 if (!res)
596 return GL_INVALID_INDEX;
597
598 switch (res->Type) {
599 case GL_UNIFORM_BLOCK:
600 return RESOURCE_UBO(res)- shProg->UniformBlocks;
601 case GL_ATOMIC_COUNTER_BUFFER:
602 return RESOURCE_ATC(res) - shProg->AtomicBuffers;
603 case GL_TRANSFORM_FEEDBACK_VARYING:
604 default:
605 return calc_resource_index(shProg, res);
606 }
607 }
608
609 /* Find a program resource with specific index in given interface.
610 */
611 struct gl_program_resource *
612 _mesa_program_resource_find_index(struct gl_shader_program *shProg,
613 GLenum programInterface, GLuint index)
614 {
615 struct gl_program_resource *res = shProg->ProgramResourceList;
616 int idx = -1;
617
618 for (unsigned i = 0; i < shProg->NumProgramResourceList; i++, res++) {
619 if (res->Type != programInterface)
620 continue;
621
622 switch (res->Type) {
623 case GL_UNIFORM_BLOCK:
624 case GL_ATOMIC_COUNTER_BUFFER:
625 if (_mesa_program_resource_index(shProg, res) == index)
626 return res;
627 break;
628 case GL_TRANSFORM_FEEDBACK_VARYING:
629 case GL_PROGRAM_INPUT:
630 case GL_PROGRAM_OUTPUT:
631 case GL_UNIFORM:
632 if (++idx == (int) index)
633 return res;
634 break;
635 default:
636 assert(!"not implemented for given interface");
637 }
638 }
639 return NULL;
640 }
641
642 /* Get full name of a program resource.
643 */
644 bool
645 _mesa_get_program_resource_name(struct gl_shader_program *shProg,
646 GLenum programInterface, GLuint index,
647 GLsizei bufSize, GLsizei *length,
648 GLchar *name, const char *caller)
649 {
650 GET_CURRENT_CONTEXT(ctx);
651
652 /* Find resource with given interface and index. */
653 struct gl_program_resource *res =
654 _mesa_program_resource_find_index(shProg, programInterface, index);
655
656 /* The error INVALID_VALUE is generated if <index> is greater than
657 * or equal to the number of entries in the active resource list for
658 * <programInterface>.
659 */
660 if (!res) {
661 _mesa_error(ctx, GL_INVALID_VALUE, "%s(index %u)", caller, index);
662 return false;
663 }
664
665 if (bufSize < 0) {
666 _mesa_error(ctx, GL_INVALID_VALUE, "%s(bufSize %d)", caller, bufSize);
667 return false;
668 }
669
670 GLsizei localLength;
671
672 if (length == NULL)
673 length = &localLength;
674
675 _mesa_copy_string(name, bufSize, length, _mesa_program_resource_name(res));
676
677 /* Page 61 (page 73 of the PDF) in section 2.11 of the OpenGL ES 3.0
678 * spec says:
679 *
680 * "If the active uniform is an array, the uniform name returned in
681 * name will always be the name of the uniform array appended with
682 * "[0]"."
683 *
684 * The same text also appears in the OpenGL 4.2 spec. It does not,
685 * however, appear in any previous spec. Previous specifications are
686 * ambiguous in this regard. However, either name can later be passed
687 * to glGetUniformLocation (and related APIs), so there shouldn't be any
688 * harm in always appending "[0]" to uniform array names.
689 *
690 * Geometry shader stage has different naming convention where the 'normal'
691 * condition is an array, therefore for variables referenced in geometry
692 * stage we do not add '[0]'.
693 *
694 * Note, that TCS outputs and TES inputs should not have index appended
695 * either.
696 */
697 bool add_index = !(((programInterface == GL_PROGRAM_INPUT) &&
698 res->StageReferences & (1 << MESA_SHADER_GEOMETRY)));
699
700 if (add_index && _mesa_program_resource_array_size(res)) {
701 int i;
702
703 /* The comparison is strange because *length does *NOT* include the
704 * terminating NUL, but maxLength does.
705 */
706 for (i = 0; i < 3 && (*length + i + 1) < bufSize; i++)
707 name[*length + i] = "[0]"[i];
708
709 name[*length + i] = '\0';
710 *length += i;
711 }
712 return true;
713 }
714
715 static GLint
716 program_resource_location(struct gl_shader_program *shProg,
717 struct gl_program_resource *res, const char *name)
718 {
719 unsigned index, offset;
720 int array_index = -1;
721
722 if (res->Type == GL_PROGRAM_INPUT || res->Type == GL_PROGRAM_OUTPUT) {
723 array_index = array_index_of_resource(res, name);
724 if (array_index < 0)
725 return -1;
726 }
727
728 /* VERT_ATTRIB_GENERIC0 and FRAG_RESULT_DATA0 are decremented as these
729 * offsets are used internally to differentiate between built-in attributes
730 * and user-defined attributes.
731 */
732 switch (res->Type) {
733 case GL_PROGRAM_INPUT:
734 return RESOURCE_VAR(res)->data.location + array_index - VERT_ATTRIB_GENERIC0;
735 case GL_PROGRAM_OUTPUT:
736 return RESOURCE_VAR(res)->data.location + array_index - FRAG_RESULT_DATA0;
737 case GL_UNIFORM:
738 index = _mesa_get_uniform_location(shProg, name, &offset);
739
740 if (index == GL_INVALID_INDEX)
741 return -1;
742
743 /* From the GL_ARB_uniform_buffer_object spec:
744 *
745 * "The value -1 will be returned if <name> does not correspond to an
746 * active uniform variable name in <program>, if <name> is associated
747 * with a named uniform block, or if <name> starts with the reserved
748 * prefix "gl_"."
749 */
750 if (RESOURCE_UNI(res)->block_index != -1 ||
751 RESOURCE_UNI(res)->atomic_buffer_index != -1)
752 return -1;
753
754 /* location in remap table + array element offset */
755 return RESOURCE_UNI(res)->remap_location + offset;
756
757 default:
758 return -1;
759 }
760 }
761
762 /**
763 * Function implements following location queries:
764 * glGetAttribLocation
765 * glGetFragDataLocation
766 * glGetUniformLocation
767 */
768 GLint
769 _mesa_program_resource_location(struct gl_shader_program *shProg,
770 GLenum programInterface, const char *name)
771 {
772 struct gl_program_resource *res =
773 _mesa_program_resource_find_name(shProg, programInterface, name);
774
775 /* Resource not found. */
776 if (!res)
777 return -1;
778
779 return program_resource_location(shProg, res, name);
780 }
781
782 /**
783 * Function implements following index queries:
784 * glGetFragDataIndex
785 */
786 GLint
787 _mesa_program_resource_location_index(struct gl_shader_program *shProg,
788 GLenum programInterface, const char *name)
789 {
790 struct gl_program_resource *res =
791 _mesa_program_resource_find_name(shProg, programInterface, name);
792
793 /* Non-existent variable or resource is not referenced by fragment stage. */
794 if (!res || !(res->StageReferences & (1 << MESA_SHADER_FRAGMENT)))
795 return -1;
796
797 return RESOURCE_VAR(res)->data.index;
798 }
799
800 static uint8_t
801 stage_from_enum(GLenum ref)
802 {
803 switch (ref) {
804 case GL_REFERENCED_BY_VERTEX_SHADER:
805 return MESA_SHADER_VERTEX;
806 case GL_REFERENCED_BY_GEOMETRY_SHADER:
807 return MESA_SHADER_GEOMETRY;
808 case GL_REFERENCED_BY_FRAGMENT_SHADER:
809 return MESA_SHADER_FRAGMENT;
810 default:
811 assert(!"shader stage not supported");
812 return MESA_SHADER_STAGES;
813 }
814 }
815
816 /**
817 * Check if resource is referenced by given 'referenced by' stage enum.
818 * ATC and UBO resources hold stage references of their own.
819 */
820 static bool
821 is_resource_referenced(struct gl_shader_program *shProg,
822 struct gl_program_resource *res,
823 GLuint index, uint8_t stage)
824 {
825 if (res->Type == GL_ATOMIC_COUNTER_BUFFER)
826 return RESOURCE_ATC(res)->StageReferences[stage];
827
828 if (res->Type == GL_UNIFORM_BLOCK)
829 return shProg->UniformBlockStageIndex[stage][index] != -1;
830
831 return res->StageReferences & (1 << stage);
832 }
833
834 static unsigned
835 get_buffer_property(struct gl_shader_program *shProg,
836 struct gl_program_resource *res, const GLenum prop,
837 GLint *val, const char *caller)
838 {
839 GET_CURRENT_CONTEXT(ctx);
840 if (res->Type != GL_UNIFORM_BLOCK &&
841 res->Type != GL_ATOMIC_COUNTER_BUFFER)
842 goto invalid_operation;
843
844 if (res->Type == GL_UNIFORM_BLOCK) {
845 switch (prop) {
846 case GL_BUFFER_BINDING:
847 *val = RESOURCE_UBO(res)->Binding;
848 return 1;
849 case GL_BUFFER_DATA_SIZE:
850 *val = RESOURCE_UBO(res)->UniformBufferSize;
851 return 1;
852 case GL_NUM_ACTIVE_VARIABLES:
853 *val = 0;
854 for (unsigned i = 0; i < RESOURCE_UBO(res)->NumUniforms; i++) {
855 const char *iname = RESOURCE_UBO(res)->Uniforms[i].IndexName;
856 struct gl_program_resource *uni =
857 _mesa_program_resource_find_name(shProg, GL_UNIFORM, iname);
858 if (!uni)
859 continue;
860 (*val)++;
861 }
862 return 1;
863 case GL_ACTIVE_VARIABLES:
864 for (unsigned i = 0; i < RESOURCE_UBO(res)->NumUniforms; i++) {
865 const char *iname = RESOURCE_UBO(res)->Uniforms[i].IndexName;
866 struct gl_program_resource *uni =
867 _mesa_program_resource_find_name(shProg, GL_UNIFORM, iname);
868 if (!uni)
869 continue;
870 *val++ =
871 _mesa_program_resource_index(shProg, uni);
872 }
873 return RESOURCE_UBO(res)->NumUniforms;
874 }
875 } else if (res->Type == GL_ATOMIC_COUNTER_BUFFER) {
876 switch (prop) {
877 case GL_BUFFER_BINDING:
878 *val = RESOURCE_ATC(res)->Binding;
879 return 1;
880 case GL_BUFFER_DATA_SIZE:
881 *val = RESOURCE_ATC(res)->MinimumSize;
882 return 1;
883 case GL_NUM_ACTIVE_VARIABLES:
884 *val = RESOURCE_ATC(res)->NumUniforms;
885 return 1;
886 case GL_ACTIVE_VARIABLES:
887 for (unsigned i = 0; i < RESOURCE_ATC(res)->NumUniforms; i++)
888 *val++ = RESOURCE_ATC(res)->Uniforms[i];
889 return RESOURCE_ATC(res)->NumUniforms;
890 }
891 }
892 assert(!"support for property type not implemented");
893
894 invalid_operation:
895 _mesa_error(ctx, GL_INVALID_OPERATION, "%s(%s prop %s)", caller,
896 _mesa_lookup_enum_by_nr(res->Type),
897 _mesa_lookup_enum_by_nr(prop));
898
899 return 0;
900 }
901
902 unsigned
903 _mesa_program_resource_prop(struct gl_shader_program *shProg,
904 struct gl_program_resource *res, GLuint index,
905 const GLenum prop, GLint *val, const char *caller)
906 {
907 GET_CURRENT_CONTEXT(ctx);
908
909 #define VALIDATE_TYPE(type)\
910 if (res->Type != type)\
911 goto invalid_operation;
912
913 switch(prop) {
914 case GL_NAME_LENGTH:
915 if (res->Type == GL_ATOMIC_COUNTER_BUFFER)
916 goto invalid_operation;
917 /* Base name +3 if array '[0]' + terminator. */
918 *val = strlen(_mesa_program_resource_name(res)) +
919 (_mesa_program_resource_array_size(res) > 0 ? 3 : 0) + 1;
920 return 1;
921 case GL_TYPE:
922 switch (res->Type) {
923 case GL_UNIFORM:
924 *val = RESOURCE_UNI(res)->type->gl_type;
925 return 1;
926 case GL_PROGRAM_INPUT:
927 case GL_PROGRAM_OUTPUT:
928 *val = RESOURCE_VAR(res)->type->gl_type;
929 return 1;
930 case GL_TRANSFORM_FEEDBACK_VARYING:
931 *val = RESOURCE_XFB(res)->Type;
932 return 1;
933 default:
934 goto invalid_operation;
935 }
936 case GL_ARRAY_SIZE:
937 switch (res->Type) {
938 case GL_UNIFORM:
939 *val = MAX2(RESOURCE_UNI(res)->array_elements, 1);
940 return 1;
941 case GL_PROGRAM_INPUT:
942 case GL_PROGRAM_OUTPUT:
943 *val = MAX2(RESOURCE_VAR(res)->type->length, 1);
944 return 1;
945 case GL_TRANSFORM_FEEDBACK_VARYING:
946 *val = MAX2(RESOURCE_XFB(res)->Size, 1);
947 return 1;
948 default:
949 goto invalid_operation;
950 }
951 case GL_OFFSET:
952 VALIDATE_TYPE(GL_UNIFORM);
953 *val = RESOURCE_UNI(res)->offset;
954 return 1;
955 case GL_BLOCK_INDEX:
956 VALIDATE_TYPE(GL_UNIFORM);
957 *val = RESOURCE_UNI(res)->block_index;
958 return 1;
959 case GL_ARRAY_STRIDE:
960 VALIDATE_TYPE(GL_UNIFORM);
961 *val = RESOURCE_UNI(res)->array_stride;
962 return 1;
963 case GL_MATRIX_STRIDE:
964 VALIDATE_TYPE(GL_UNIFORM);
965 *val = RESOURCE_UNI(res)->matrix_stride;
966 return 1;
967 case GL_IS_ROW_MAJOR:
968 VALIDATE_TYPE(GL_UNIFORM);
969 *val = RESOURCE_UNI(res)->row_major;
970 return 1;
971 case GL_ATOMIC_COUNTER_BUFFER_INDEX:
972 VALIDATE_TYPE(GL_UNIFORM);
973 *val = RESOURCE_UNI(res)->atomic_buffer_index;
974 return 1;
975 case GL_BUFFER_BINDING:
976 case GL_BUFFER_DATA_SIZE:
977 case GL_NUM_ACTIVE_VARIABLES:
978 case GL_ACTIVE_VARIABLES:
979 return get_buffer_property(shProg, res, prop, val, caller);
980 case GL_REFERENCED_BY_VERTEX_SHADER:
981 case GL_REFERENCED_BY_GEOMETRY_SHADER:
982 case GL_REFERENCED_BY_FRAGMENT_SHADER:
983 switch (res->Type) {
984 case GL_UNIFORM:
985 case GL_PROGRAM_INPUT:
986 case GL_PROGRAM_OUTPUT:
987 case GL_UNIFORM_BLOCK:
988 case GL_ATOMIC_COUNTER_BUFFER:
989 *val = is_resource_referenced(shProg, res, index,
990 stage_from_enum(prop));
991 return 1;
992 default:
993 goto invalid_operation;
994 }
995 case GL_LOCATION:
996 switch (res->Type) {
997 case GL_UNIFORM:
998 case GL_PROGRAM_INPUT:
999 case GL_PROGRAM_OUTPUT:
1000 *val = program_resource_location(shProg, res,
1001 _mesa_program_resource_name(res));
1002 return 1;
1003 default:
1004 goto invalid_operation;
1005 }
1006 case GL_LOCATION_INDEX:
1007 if (res->Type != GL_PROGRAM_OUTPUT)
1008 goto invalid_operation;
1009 *val = RESOURCE_VAR(res)->data.index;
1010 return 1;
1011
1012 /* GL_ARB_tessellation_shader */
1013 case GL_IS_PER_PATCH:
1014 case GL_REFERENCED_BY_TESS_CONTROL_SHADER:
1015 case GL_REFERENCED_BY_TESS_EVALUATION_SHADER:
1016 /* GL_ARB_compute_shader */
1017 case GL_REFERENCED_BY_COMPUTE_SHADER:
1018 default:
1019 _mesa_error(ctx, GL_INVALID_ENUM, "%s(%s prop %s)", caller,
1020 _mesa_lookup_enum_by_nr(res->Type),
1021 _mesa_lookup_enum_by_nr(prop));
1022 return 0;
1023 }
1024
1025 #undef VALIDATE_TYPE
1026
1027 invalid_operation:
1028 _mesa_error(ctx, GL_INVALID_OPERATION, "%s(%s prop %s)", caller,
1029 _mesa_lookup_enum_by_nr(res->Type),
1030 _mesa_lookup_enum_by_nr(prop));
1031 return 0;
1032 }
1033
1034 extern void
1035 _mesa_get_program_resourceiv(struct gl_shader_program *shProg,
1036 GLenum programInterface, GLuint index, GLsizei propCount,
1037 const GLenum *props, GLsizei bufSize,
1038 GLsizei *length, GLint *params)
1039 {
1040 GET_CURRENT_CONTEXT(ctx);
1041 GLint *val = (GLint *) params;
1042 const GLenum *prop = props;
1043 GLsizei amount = 0;
1044
1045 struct gl_program_resource *res =
1046 _mesa_program_resource_find_index(shProg, programInterface, index);
1047
1048 /* No such resource found or bufSize negative. */
1049 if (!res || bufSize < 0) {
1050 _mesa_error(ctx, GL_INVALID_VALUE,
1051 "glGetProgramResourceiv(%s index %d bufSize %d)",
1052 _mesa_lookup_enum_by_nr(programInterface), index, bufSize);
1053 return;
1054 }
1055
1056 /* Write propCount values until error occurs or bufSize reached. */
1057 for (int i = 0; i < propCount && i < bufSize; i++, val++, prop++) {
1058 int props_written =
1059 _mesa_program_resource_prop(shProg, res, index, *prop, val,
1060 "glGetProgramResourceiv");
1061
1062 /* Error happened. */
1063 if (props_written == 0)
1064 return;
1065
1066 amount += props_written;
1067 }
1068
1069 /* If <length> is not NULL, the actual number of integer values
1070 * written to <params> will be written to <length>.
1071 */
1072 if (length)
1073 *length = amount;
1074 }