mesa: glGetProgramInterfaceiv
[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 /**
45 * Declare convenience functions to return resource data in a given type.
46 * Warning! this is not type safe so be *very* careful when using these.
47 */
48 #define DECL_RESOURCE_FUNC(name, type) \
49 const type * RESOURCE_ ## name (gl_program_resource *res) { \
50 assert(res->Data); \
51 return (type *) res->Data; \
52 }
53
54 DECL_RESOURCE_FUNC(VAR, ir_variable);
55 DECL_RESOURCE_FUNC(UBO, gl_uniform_block);
56 DECL_RESOURCE_FUNC(UNI, gl_uniform_storage);
57 DECL_RESOURCE_FUNC(ATC, gl_active_atomic_buffer);
58 DECL_RESOURCE_FUNC(XFB, gl_transform_feedback_varying_info);
59
60 void GLAPIENTRY
61 _mesa_BindAttribLocation(GLhandleARB program, GLuint index,
62 const GLcharARB *name)
63 {
64 GET_CURRENT_CONTEXT(ctx);
65
66 struct gl_shader_program *const shProg =
67 _mesa_lookup_shader_program_err(ctx, program, "glBindAttribLocation");
68 if (!shProg)
69 return;
70
71 if (!name)
72 return;
73
74 if (strncmp(name, "gl_", 3) == 0) {
75 _mesa_error(ctx, GL_INVALID_OPERATION,
76 "glBindAttribLocation(illegal name)");
77 return;
78 }
79
80 if (index >= ctx->Const.Program[MESA_SHADER_VERTEX].MaxAttribs) {
81 _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(index)");
82 return;
83 }
84
85 /* Replace the current value if it's already in the list. Add
86 * VERT_ATTRIB_GENERIC0 because that's how the linker differentiates
87 * between built-in attributes and user-defined attributes.
88 */
89 shProg->AttributeBindings->put(index + VERT_ATTRIB_GENERIC0, name);
90
91 /*
92 * Note that this attribute binding won't go into effect until
93 * glLinkProgram is called again.
94 */
95 }
96
97 static bool
98 is_active_attrib(const ir_variable *var)
99 {
100 if (!var)
101 return false;
102
103 switch (var->data.mode) {
104 case ir_var_shader_in:
105 return var->data.location != -1;
106
107 case ir_var_system_value:
108 /* From GL 4.3 core spec, section 11.1.1 (Vertex Attributes):
109 * "For GetActiveAttrib, all active vertex shader input variables
110 * are enumerated, including the special built-in inputs gl_VertexID
111 * and gl_InstanceID."
112 */
113 return var->data.location == SYSTEM_VALUE_VERTEX_ID ||
114 var->data.location == SYSTEM_VALUE_VERTEX_ID_ZERO_BASE ||
115 var->data.location == SYSTEM_VALUE_INSTANCE_ID;
116
117 default:
118 return false;
119 }
120 }
121
122 void GLAPIENTRY
123 _mesa_GetActiveAttrib(GLhandleARB program, GLuint desired_index,
124 GLsizei maxLength, GLsizei * length, GLint * size,
125 GLenum * type, GLcharARB * name)
126 {
127 GET_CURRENT_CONTEXT(ctx);
128 struct gl_shader_program *shProg;
129
130 if (maxLength < 0) {
131 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(maxLength < 0)");
132 return;
133 }
134
135 shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveAttrib");
136 if (!shProg)
137 return;
138
139 if (!shProg->LinkStatus) {
140 _mesa_error(ctx, GL_INVALID_VALUE,
141 "glGetActiveAttrib(program not linked)");
142 return;
143 }
144
145 if (shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL) {
146 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(no vertex shader)");
147 return;
148 }
149
150 exec_list *const ir = shProg->_LinkedShaders[MESA_SHADER_VERTEX]->ir;
151 unsigned current_index = 0;
152
153 foreach_in_list(ir_instruction, node, ir) {
154 const ir_variable *const var = node->as_variable();
155
156 if (!is_active_attrib(var))
157 continue;
158
159 if (current_index == desired_index) {
160 const char *var_name = var->name;
161
162 /* Since gl_VertexID may be lowered to gl_VertexIDMESA, we need to
163 * consider gl_VertexIDMESA as gl_VertexID for purposes of checking
164 * active attributes.
165 */
166 if (var->data.mode == ir_var_system_value &&
167 var->data.location == SYSTEM_VALUE_VERTEX_ID_ZERO_BASE) {
168 var_name = "gl_VertexID";
169 }
170
171 _mesa_copy_string(name, maxLength, length, var_name);
172
173 if (size)
174 *size = (var->type->is_array()) ? var->type->length : 1;
175
176 if (type)
177 *type = var->type->gl_type;
178
179 return;
180 }
181
182 current_index++;
183 }
184
185 /* If the loop did not return early, the caller must have asked for
186 * an index that did not exit. Set an error.
187 */
188 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
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 exec_list *ir = shProg->_LinkedShaders[MESA_SHADER_VERTEX]->ir;
274 foreach_in_list(ir_instruction, node, ir) {
275 const ir_variable *const var = node->as_variable();
276
277 /* The extra check against VERT_ATTRIB_GENERIC0 is because
278 * glGetAttribLocation cannot be used on "conventional" attributes.
279 *
280 * From page 95 of the OpenGL 3.0 spec:
281 *
282 * "If name is not an active attribute, if name is a conventional
283 * attribute, or if an error occurs, -1 will be returned."
284 */
285 if (var == NULL
286 || var->data.mode != ir_var_shader_in
287 || var->data.location == -1
288 || var->data.location < VERT_ATTRIB_GENERIC0)
289 continue;
290
291 int index = get_matching_index(var, (const char *) name);
292
293 if (index >= 0)
294 return var->data.location + index - VERT_ATTRIB_GENERIC0;
295 }
296
297 return -1;
298 }
299
300
301 unsigned
302 _mesa_count_active_attribs(struct gl_shader_program *shProg)
303 {
304 if (!shProg->LinkStatus
305 || shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL) {
306 return 0;
307 }
308
309 exec_list *const ir = shProg->_LinkedShaders[MESA_SHADER_VERTEX]->ir;
310 unsigned i = 0;
311
312 foreach_in_list(ir_instruction, node, ir) {
313 const ir_variable *const var = node->as_variable();
314
315 if (!is_active_attrib(var))
316 continue;
317
318 i++;
319 }
320
321 return i;
322 }
323
324
325 size_t
326 _mesa_longest_attribute_name_length(struct gl_shader_program *shProg)
327 {
328 if (!shProg->LinkStatus
329 || shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL) {
330 return 0;
331 }
332
333 exec_list *const ir = shProg->_LinkedShaders[MESA_SHADER_VERTEX]->ir;
334 size_t longest = 0;
335
336 foreach_in_list(ir_instruction, node, ir) {
337 const ir_variable *const var = node->as_variable();
338
339 if (var == NULL
340 || var->data.mode != ir_var_shader_in
341 || var->data.location == -1)
342 continue;
343
344 const size_t len = strlen(var->name);
345 if (len >= longest)
346 longest = len + 1;
347 }
348
349 return longest;
350 }
351
352 void GLAPIENTRY
353 _mesa_BindFragDataLocation(GLuint program, GLuint colorNumber,
354 const GLchar *name)
355 {
356 _mesa_BindFragDataLocationIndexed(program, colorNumber, 0, name);
357 }
358
359 void GLAPIENTRY
360 _mesa_BindFragDataLocationIndexed(GLuint program, GLuint colorNumber,
361 GLuint index, const GLchar *name)
362 {
363 GET_CURRENT_CONTEXT(ctx);
364
365 struct gl_shader_program *const shProg =
366 _mesa_lookup_shader_program_err(ctx, program, "glBindFragDataLocationIndexed");
367 if (!shProg)
368 return;
369
370 if (!name)
371 return;
372
373 if (strncmp(name, "gl_", 3) == 0) {
374 _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFragDataLocationIndexed(illegal name)");
375 return;
376 }
377
378 if (index > 1) {
379 _mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocationIndexed(index)");
380 return;
381 }
382
383 if (index == 0 && colorNumber >= ctx->Const.MaxDrawBuffers) {
384 _mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocationIndexed(colorNumber)");
385 return;
386 }
387
388 if (index == 1 && colorNumber >= ctx->Const.MaxDualSourceDrawBuffers) {
389 _mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocationIndexed(colorNumber)");
390 return;
391 }
392
393 /* Replace the current value if it's already in the list. Add
394 * FRAG_RESULT_DATA0 because that's how the linker differentiates
395 * between built-in attributes and user-defined attributes.
396 */
397 shProg->FragDataBindings->put(colorNumber + FRAG_RESULT_DATA0, name);
398 shProg->FragDataIndexBindings->put(index, name);
399 /*
400 * Note that this binding won't go into effect until
401 * glLinkProgram is called again.
402 */
403
404 }
405
406 GLint GLAPIENTRY
407 _mesa_GetFragDataIndex(GLuint program, const GLchar *name)
408 {
409 GET_CURRENT_CONTEXT(ctx);
410 struct gl_shader_program *const shProg =
411 _mesa_lookup_shader_program_err(ctx, program, "glGetFragDataIndex");
412
413 if (!shProg) {
414 return -1;
415 }
416
417 if (!shProg->LinkStatus) {
418 _mesa_error(ctx, GL_INVALID_OPERATION,
419 "glGetFragDataIndex(program not linked)");
420 return -1;
421 }
422
423 if (!name)
424 return -1;
425
426 if (strncmp(name, "gl_", 3) == 0) {
427 _mesa_error(ctx, GL_INVALID_OPERATION,
428 "glGetFragDataIndex(illegal name)");
429 return -1;
430 }
431
432 /* Not having a fragment shader is not an error.
433 */
434 if (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL)
435 return -1;
436
437 exec_list *ir = shProg->_LinkedShaders[MESA_SHADER_FRAGMENT]->ir;
438 foreach_in_list(ir_instruction, node, ir) {
439 const ir_variable *const var = node->as_variable();
440
441 /* The extra check against FRAG_RESULT_DATA0 is because
442 * glGetFragDataLocation cannot be used on "conventional" attributes.
443 *
444 * From page 95 of the OpenGL 3.0 spec:
445 *
446 * "If name is not an active attribute, if name is a conventional
447 * attribute, or if an error occurs, -1 will be returned."
448 */
449 if (var == NULL
450 || var->data.mode != ir_var_shader_out
451 || var->data.location == -1
452 || var->data.location < FRAG_RESULT_DATA0)
453 continue;
454
455 if (get_matching_index(var, (const char *) name) >= 0)
456 return var->data.index;
457 }
458
459 return -1;
460 }
461
462 GLint GLAPIENTRY
463 _mesa_GetFragDataLocation(GLuint program, const GLchar *name)
464 {
465 GET_CURRENT_CONTEXT(ctx);
466 struct gl_shader_program *const shProg =
467 _mesa_lookup_shader_program_err(ctx, program, "glGetFragDataLocation");
468
469 if (!shProg) {
470 return -1;
471 }
472
473 if (!shProg->LinkStatus) {
474 _mesa_error(ctx, GL_INVALID_OPERATION,
475 "glGetFragDataLocation(program not linked)");
476 return -1;
477 }
478
479 if (!name)
480 return -1;
481
482 if (strncmp(name, "gl_", 3) == 0) {
483 _mesa_error(ctx, GL_INVALID_OPERATION,
484 "glGetFragDataLocation(illegal name)");
485 return -1;
486 }
487
488 /* Not having a fragment shader is not an error.
489 */
490 if (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL)
491 return -1;
492
493 exec_list *ir = shProg->_LinkedShaders[MESA_SHADER_FRAGMENT]->ir;
494 foreach_in_list(ir_instruction, node, ir) {
495 const ir_variable *const var = node->as_variable();
496
497 /* The extra check against FRAG_RESULT_DATA0 is because
498 * glGetFragDataLocation cannot be used on "conventional" attributes.
499 *
500 * From page 95 of the OpenGL 3.0 spec:
501 *
502 * "If name is not an active attribute, if name is a conventional
503 * attribute, or if an error occurs, -1 will be returned."
504 */
505 if (var == NULL
506 || var->data.mode != ir_var_shader_out
507 || var->data.location == -1
508 || var->data.location < FRAG_RESULT_DATA0)
509 continue;
510
511 int index = get_matching_index(var, (const char *) name);
512
513 if (index >= 0)
514 return var->data.location + index - FRAG_RESULT_DATA0;
515 }
516
517 return -1;
518 }
519
520 const char*
521 _mesa_program_resource_name(struct gl_program_resource *res)
522 {
523 switch (res->Type) {
524 case GL_UNIFORM_BLOCK:
525 return RESOURCE_UBO(res)->Name;
526 case GL_TRANSFORM_FEEDBACK_VARYING:
527 return RESOURCE_XFB(res)->Name;
528 case GL_PROGRAM_INPUT:
529 case GL_PROGRAM_OUTPUT:
530 return RESOURCE_VAR(res)->name;
531 case GL_UNIFORM:
532 return RESOURCE_UNI(res)->name;
533 default:
534 assert(!"support for resource type not implemented");
535 }
536 return NULL;
537 }
538
539
540 unsigned
541 _mesa_program_resource_array_size(struct gl_program_resource *res)
542 {
543 switch (res->Type) {
544 case GL_TRANSFORM_FEEDBACK_VARYING:
545 return RESOURCE_XFB(res)->Size > 1 ?
546 RESOURCE_XFB(res)->Size : 0;
547 case GL_PROGRAM_INPUT:
548 case GL_PROGRAM_OUTPUT:
549 return RESOURCE_VAR(res)->data.max_array_access;
550 case GL_UNIFORM:
551 return RESOURCE_UNI(res)->array_elements;
552 case GL_ATOMIC_COUNTER_BUFFER:
553 case GL_UNIFORM_BLOCK:
554 return 0;
555 default:
556 assert(!"support for resource type not implemented");
557 }
558 return 0;
559 }