mesa: remove THREADS check, printf calls in debug.c
[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
38 extern "C" {
39 #include "shaderapi.h"
40 }
41
42 void GLAPIENTRY
43 _mesa_BindAttribLocation(GLhandleARB program, GLuint index,
44 const GLcharARB *name)
45 {
46 GET_CURRENT_CONTEXT(ctx);
47
48 struct gl_shader_program *const shProg =
49 _mesa_lookup_shader_program_err(ctx, program, "glBindAttribLocation");
50 if (!shProg)
51 return;
52
53 if (!name)
54 return;
55
56 if (strncmp(name, "gl_", 3) == 0) {
57 _mesa_error(ctx, GL_INVALID_OPERATION,
58 "glBindAttribLocation(illegal name)");
59 return;
60 }
61
62 if (index >= ctx->Const.Program[MESA_SHADER_VERTEX].MaxAttribs) {
63 _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(index)");
64 return;
65 }
66
67 /* Replace the current value if it's already in the list. Add
68 * VERT_ATTRIB_GENERIC0 because that's how the linker differentiates
69 * between built-in attributes and user-defined attributes.
70 */
71 shProg->AttributeBindings->put(index + VERT_ATTRIB_GENERIC0, name);
72
73 /*
74 * Note that this attribute binding won't go into effect until
75 * glLinkProgram is called again.
76 */
77 }
78
79 static bool
80 is_active_attrib(const ir_variable *var)
81 {
82 if (!var)
83 return false;
84
85 switch (var->data.mode) {
86 case ir_var_shader_in:
87 return var->data.location != -1;
88
89 case ir_var_system_value:
90 /* From GL 4.3 core spec, section 11.1.1 (Vertex Attributes):
91 * "For GetActiveAttrib, all active vertex shader input variables
92 * are enumerated, including the special built-in inputs gl_VertexID
93 * and gl_InstanceID."
94 */
95 return var->data.location == SYSTEM_VALUE_VERTEX_ID ||
96 var->data.location == SYSTEM_VALUE_VERTEX_ID_ZERO_BASE ||
97 var->data.location == SYSTEM_VALUE_INSTANCE_ID;
98
99 default:
100 return false;
101 }
102 }
103
104 void GLAPIENTRY
105 _mesa_GetActiveAttrib(GLhandleARB program, GLuint desired_index,
106 GLsizei maxLength, GLsizei * length, GLint * size,
107 GLenum * type, GLcharARB * name)
108 {
109 GET_CURRENT_CONTEXT(ctx);
110 struct gl_shader_program *shProg;
111
112 if (maxLength < 0) {
113 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(maxLength < 0)");
114 return;
115 }
116
117 shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveAttrib");
118 if (!shProg)
119 return;
120
121 if (!shProg->LinkStatus) {
122 _mesa_error(ctx, GL_INVALID_VALUE,
123 "glGetActiveAttrib(program not linked)");
124 return;
125 }
126
127 if (shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL) {
128 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(no vertex shader)");
129 return;
130 }
131
132 exec_list *const ir = shProg->_LinkedShaders[MESA_SHADER_VERTEX]->ir;
133 unsigned current_index = 0;
134
135 foreach_in_list(ir_instruction, node, ir) {
136 const ir_variable *const var = node->as_variable();
137
138 if (!is_active_attrib(var))
139 continue;
140
141 if (current_index == desired_index) {
142 const char *var_name = var->name;
143
144 /* Since gl_VertexID may be lowered to gl_VertexIDMESA, we need to
145 * consider gl_VertexIDMESA as gl_VertexID for purposes of checking
146 * active attributes.
147 */
148 if (var->data.mode == ir_var_system_value &&
149 var->data.location == SYSTEM_VALUE_VERTEX_ID_ZERO_BASE) {
150 var_name = "gl_VertexID";
151 }
152
153 _mesa_copy_string(name, maxLength, length, var_name);
154
155 if (size)
156 *size = (var->type->is_array()) ? var->type->length : 1;
157
158 if (type)
159 *type = var->type->gl_type;
160
161 return;
162 }
163
164 current_index++;
165 }
166
167 /* If the loop did not return early, the caller must have asked for
168 * an index that did not exit. Set an error.
169 */
170 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
171 }
172
173 /* Locations associated with shader variables (array or non-array) can be
174 * queried using its base name or using the base name appended with the
175 * valid array index. For example, in case of below vertex shader, valid
176 * queries can be made to know the location of "xyz", "array", "array[0]",
177 * "array[1]", "array[2]" and "array[3]". In this example index reurned
178 * will be 0, 0, 0, 1, 2, 3 respectively.
179 *
180 * [Vertex Shader]
181 * layout(location=0) in vec4 xyz;
182 * layout(location=1) in vec4[4] array;
183 * void main()
184 * { }
185 *
186 * This requirement came up with the addition of ARB_program_interface_query
187 * to OpenGL 4.3 specification. See page 101 (page 122 of the PDF) for details.
188 *
189 * This utility function is used by:
190 * _mesa_GetAttribLocation
191 * _mesa_GetFragDataLocation
192 * _mesa_GetFragDataIndex
193 *
194 * Returns 0:
195 * if the 'name' string matches var->name.
196 * Returns 'matched index':
197 * if the 'name' string matches var->name appended with valid array index.
198 */
199 int static inline
200 get_matching_index(const ir_variable *const var, const char *name) {
201 unsigned idx = 0;
202 const char *const paren = strchr(name, '[');
203 const unsigned len = (paren != NULL) ? paren - name : strlen(name);
204
205 if (paren != NULL) {
206 if (!var->type->is_array())
207 return -1;
208
209 char *endptr;
210 idx = (unsigned) strtol(paren + 1, &endptr, 10);
211 const unsigned idx_len = endptr != (paren + 1) ? endptr - paren - 1 : 0;
212
213 /* Validate the sub string representing index in 'name' string */
214 if ((idx > 0 && paren[1] == '0') /* leading zeroes */
215 || (idx == 0 && idx_len > 1) /* all zeroes */
216 || paren[1] == ' ' /* whitespace */
217 || endptr[0] != ']' /* closing brace */
218 || endptr[1] != '\0' /* null char */
219 || idx_len == 0 /* missing index */
220 || idx >= var->type->length) /* exceeding array bound */
221 return -1;
222 }
223
224 if (strncmp(var->name, name, len) == 0 && var->name[len] == '\0')
225 return idx;
226
227 return -1;
228 }
229
230 GLint GLAPIENTRY
231 _mesa_GetAttribLocation(GLhandleARB program, const GLcharARB * name)
232 {
233 GET_CURRENT_CONTEXT(ctx);
234 struct gl_shader_program *const shProg =
235 _mesa_lookup_shader_program_err(ctx, program, "glGetAttribLocation");
236
237 if (!shProg) {
238 return -1;
239 }
240
241 if (!shProg->LinkStatus) {
242 _mesa_error(ctx, GL_INVALID_OPERATION,
243 "glGetAttribLocation(program not linked)");
244 return -1;
245 }
246
247 if (!name)
248 return -1;
249
250 /* Not having a vertex shader is not an error.
251 */
252 if (shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL)
253 return -1;
254
255 exec_list *ir = shProg->_LinkedShaders[MESA_SHADER_VERTEX]->ir;
256 foreach_in_list(ir_instruction, node, ir) {
257 const ir_variable *const var = node->as_variable();
258
259 /* The extra check against VERT_ATTRIB_GENERIC0 is because
260 * glGetAttribLocation cannot be used on "conventional" attributes.
261 *
262 * From page 95 of the OpenGL 3.0 spec:
263 *
264 * "If name is not an active attribute, if name is a conventional
265 * attribute, or if an error occurs, -1 will be returned."
266 */
267 if (var == NULL
268 || var->data.mode != ir_var_shader_in
269 || var->data.location == -1
270 || var->data.location < VERT_ATTRIB_GENERIC0)
271 continue;
272
273 int index = get_matching_index(var, (const char *) name);
274
275 if (index >= 0)
276 return var->data.location + index - VERT_ATTRIB_GENERIC0;
277 }
278
279 return -1;
280 }
281
282
283 unsigned
284 _mesa_count_active_attribs(struct gl_shader_program *shProg)
285 {
286 if (!shProg->LinkStatus
287 || shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL) {
288 return 0;
289 }
290
291 exec_list *const ir = shProg->_LinkedShaders[MESA_SHADER_VERTEX]->ir;
292 unsigned i = 0;
293
294 foreach_in_list(ir_instruction, node, ir) {
295 const ir_variable *const var = node->as_variable();
296
297 if (!is_active_attrib(var))
298 continue;
299
300 i++;
301 }
302
303 return i;
304 }
305
306
307 size_t
308 _mesa_longest_attribute_name_length(struct gl_shader_program *shProg)
309 {
310 if (!shProg->LinkStatus
311 || shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL) {
312 return 0;
313 }
314
315 exec_list *const ir = shProg->_LinkedShaders[MESA_SHADER_VERTEX]->ir;
316 size_t longest = 0;
317
318 foreach_in_list(ir_instruction, node, ir) {
319 const ir_variable *const var = node->as_variable();
320
321 if (var == NULL
322 || var->data.mode != ir_var_shader_in
323 || var->data.location == -1)
324 continue;
325
326 const size_t len = strlen(var->name);
327 if (len >= longest)
328 longest = len + 1;
329 }
330
331 return longest;
332 }
333
334 void GLAPIENTRY
335 _mesa_BindFragDataLocation(GLuint program, GLuint colorNumber,
336 const GLchar *name)
337 {
338 _mesa_BindFragDataLocationIndexed(program, colorNumber, 0, name);
339 }
340
341 void GLAPIENTRY
342 _mesa_BindFragDataLocationIndexed(GLuint program, GLuint colorNumber,
343 GLuint index, const GLchar *name)
344 {
345 GET_CURRENT_CONTEXT(ctx);
346
347 struct gl_shader_program *const shProg =
348 _mesa_lookup_shader_program_err(ctx, program, "glBindFragDataLocationIndexed");
349 if (!shProg)
350 return;
351
352 if (!name)
353 return;
354
355 if (strncmp(name, "gl_", 3) == 0) {
356 _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFragDataLocationIndexed(illegal name)");
357 return;
358 }
359
360 if (index > 1) {
361 _mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocationIndexed(index)");
362 return;
363 }
364
365 if (index == 0 && colorNumber >= ctx->Const.MaxDrawBuffers) {
366 _mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocationIndexed(colorNumber)");
367 return;
368 }
369
370 if (index == 1 && colorNumber >= ctx->Const.MaxDualSourceDrawBuffers) {
371 _mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocationIndexed(colorNumber)");
372 return;
373 }
374
375 /* Replace the current value if it's already in the list. Add
376 * FRAG_RESULT_DATA0 because that's how the linker differentiates
377 * between built-in attributes and user-defined attributes.
378 */
379 shProg->FragDataBindings->put(colorNumber + FRAG_RESULT_DATA0, name);
380 shProg->FragDataIndexBindings->put(index, name);
381 /*
382 * Note that this binding won't go into effect until
383 * glLinkProgram is called again.
384 */
385
386 }
387
388 GLint GLAPIENTRY
389 _mesa_GetFragDataIndex(GLuint program, const GLchar *name)
390 {
391 GET_CURRENT_CONTEXT(ctx);
392 struct gl_shader_program *const shProg =
393 _mesa_lookup_shader_program_err(ctx, program, "glGetFragDataIndex");
394
395 if (!shProg) {
396 return -1;
397 }
398
399 if (!shProg->LinkStatus) {
400 _mesa_error(ctx, GL_INVALID_OPERATION,
401 "glGetFragDataIndex(program not linked)");
402 return -1;
403 }
404
405 if (!name)
406 return -1;
407
408 if (strncmp(name, "gl_", 3) == 0) {
409 _mesa_error(ctx, GL_INVALID_OPERATION,
410 "glGetFragDataIndex(illegal name)");
411 return -1;
412 }
413
414 /* Not having a fragment shader is not an error.
415 */
416 if (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL)
417 return -1;
418
419 exec_list *ir = shProg->_LinkedShaders[MESA_SHADER_FRAGMENT]->ir;
420 foreach_in_list(ir_instruction, node, ir) {
421 const ir_variable *const var = node->as_variable();
422
423 /* The extra check against FRAG_RESULT_DATA0 is because
424 * glGetFragDataLocation cannot be used on "conventional" attributes.
425 *
426 * From page 95 of the OpenGL 3.0 spec:
427 *
428 * "If name is not an active attribute, if name is a conventional
429 * attribute, or if an error occurs, -1 will be returned."
430 */
431 if (var == NULL
432 || var->data.mode != ir_var_shader_out
433 || var->data.location == -1
434 || var->data.location < FRAG_RESULT_DATA0)
435 continue;
436
437 if (get_matching_index(var, (const char *) name) >= 0)
438 return var->data.index;
439 }
440
441 return -1;
442 }
443
444 GLint GLAPIENTRY
445 _mesa_GetFragDataLocation(GLuint program, const GLchar *name)
446 {
447 GET_CURRENT_CONTEXT(ctx);
448 struct gl_shader_program *const shProg =
449 _mesa_lookup_shader_program_err(ctx, program, "glGetFragDataLocation");
450
451 if (!shProg) {
452 return -1;
453 }
454
455 if (!shProg->LinkStatus) {
456 _mesa_error(ctx, GL_INVALID_OPERATION,
457 "glGetFragDataLocation(program not linked)");
458 return -1;
459 }
460
461 if (!name)
462 return -1;
463
464 if (strncmp(name, "gl_", 3) == 0) {
465 _mesa_error(ctx, GL_INVALID_OPERATION,
466 "glGetFragDataLocation(illegal name)");
467 return -1;
468 }
469
470 /* Not having a fragment shader is not an error.
471 */
472 if (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL)
473 return -1;
474
475 exec_list *ir = shProg->_LinkedShaders[MESA_SHADER_FRAGMENT]->ir;
476 foreach_in_list(ir_instruction, node, ir) {
477 const ir_variable *const var = node->as_variable();
478
479 /* The extra check against FRAG_RESULT_DATA0 is because
480 * glGetFragDataLocation cannot be used on "conventional" attributes.
481 *
482 * From page 95 of the OpenGL 3.0 spec:
483 *
484 * "If name is not an active attribute, if name is a conventional
485 * attribute, or if an error occurs, -1 will be returned."
486 */
487 if (var == NULL
488 || var->data.mode != ir_var_shader_out
489 || var->data.location == -1
490 || var->data.location < FRAG_RESULT_DATA0)
491 continue;
492
493 int index = get_matching_index(var, (const char *) name);
494
495 if (index >= 0)
496 return var->data.location + index - FRAG_RESULT_DATA0;
497 }
498
499 return -1;
500 }