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