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