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
_mesa_BindAttribLocationARB(GLhandleARB program,GLuint index,const GLcharARB * name)43 _mesa_BindAttribLocationARB(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.VertexProgram.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 void GLAPIENTRY
_mesa_GetActiveAttribARB(GLhandleARB program,GLuint desired_index,GLsizei maxLength,GLsizei * length,GLint * size,GLenum * type,GLcharARB * name)80 _mesa_GetActiveAttribARB(GLhandleARB program, GLuint desired_index,
81 GLsizei maxLength, GLsizei * length, GLint * size,
82 GLenum * type, GLcharARB * name)
83 {
84 GET_CURRENT_CONTEXT(ctx);
85 struct gl_shader_program *shProg;
86
87 shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveAttrib");
88 if (!shProg)
89 return;
90
91 if (!shProg->LinkStatus) {
92 _mesa_error(ctx, GL_INVALID_VALUE,
93 "glGetActiveAttrib(program not linked)");
94 return;
95 }
96
97 if (shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL) {
98 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(no vertex shader)");
99 return;
100 }
101
102 exec_list *const ir = shProg->_LinkedShaders[MESA_SHADER_VERTEX]->ir;
103 unsigned current_index = 0;
104
105 foreach_list(node, ir) {
106 const ir_variable *const var = ((ir_instruction *) node)->as_variable();
107
108 if (var == NULL
109 || var->mode != ir_var_in
110 || var->location == -1)
111 continue;
112
113 if (current_index == desired_index) {
114 _mesa_copy_string(name, maxLength, length, var->name);
115
116 if (size)
117 *size = (var->type->is_array()) ? var->type->length : 1;
118
119 if (type)
120 *type = var->type->gl_type;
121
122 return;
123 }
124
125 current_index++;
126 }
127
128 /* If the loop did not return early, the caller must have asked for
129 * an index that did not exit. Set an error.
130 */
131 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
132 }
133
134 GLint GLAPIENTRY
_mesa_GetAttribLocationARB(GLhandleARB program,const GLcharARB * name)135 _mesa_GetAttribLocationARB(GLhandleARB program, const GLcharARB * name)
136 {
137 GET_CURRENT_CONTEXT(ctx);
138 struct gl_shader_program *const shProg =
139 _mesa_lookup_shader_program_err(ctx, program, "glGetAttribLocation");
140
141 if (!shProg) {
142 return -1;
143 }
144
145 if (!shProg->LinkStatus) {
146 _mesa_error(ctx, GL_INVALID_OPERATION,
147 "glGetAttribLocation(program not linked)");
148 return -1;
149 }
150
151 if (!name)
152 return -1;
153
154 /* Not having a vertex shader is not an error.
155 */
156 if (shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL)
157 return -1;
158
159 exec_list *ir = shProg->_LinkedShaders[MESA_SHADER_VERTEX]->ir;
160 foreach_list(node, ir) {
161 const ir_variable *const var = ((ir_instruction *) node)->as_variable();
162
163 /* The extra check against VERT_ATTRIB_GENERIC0 is because
164 * glGetAttribLocation cannot be used on "conventional" attributes.
165 *
166 * From page 95 of the OpenGL 3.0 spec:
167 *
168 * "If name is not an active attribute, if name is a conventional
169 * attribute, or if an error occurs, -1 will be returned."
170 */
171 if (var == NULL
172 || var->mode != ir_var_in
173 || var->location == -1
174 || var->location < VERT_ATTRIB_GENERIC0)
175 continue;
176
177 if (strcmp(var->name, name) == 0)
178 return var->location - VERT_ATTRIB_GENERIC0;
179 }
180
181 return -1;
182 }
183
184
185 unsigned
_mesa_count_active_attribs(struct gl_shader_program * shProg)186 _mesa_count_active_attribs(struct gl_shader_program *shProg)
187 {
188 if (!shProg->LinkStatus
189 || shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL) {
190 return 0;
191 }
192
193 exec_list *const ir = shProg->_LinkedShaders[MESA_SHADER_VERTEX]->ir;
194 unsigned i = 0;
195
196 foreach_list(node, ir) {
197 const ir_variable *const var = ((ir_instruction *) node)->as_variable();
198
199 if (var == NULL
200 || var->mode != ir_var_in
201 || var->location == -1)
202 continue;
203
204 i++;
205 }
206
207 return i;
208 }
209
210
211 size_t
_mesa_longest_attribute_name_length(struct gl_shader_program * shProg)212 _mesa_longest_attribute_name_length(struct gl_shader_program *shProg)
213 {
214 if (!shProg->LinkStatus
215 || shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL) {
216 return 0;
217 }
218
219 exec_list *const ir = shProg->_LinkedShaders[MESA_SHADER_VERTEX]->ir;
220 size_t longest = 0;
221
222 foreach_list(node, ir) {
223 const ir_variable *const var = ((ir_instruction *) node)->as_variable();
224
225 if (var == NULL
226 || var->mode != ir_var_in
227 || var->location == -1)
228 continue;
229
230 const size_t len = strlen(var->name);
231 if (len >= longest)
232 longest = len + 1;
233 }
234
235 return longest;
236 }
237
238 void GLAPIENTRY
_mesa_BindFragDataLocation(GLuint program,GLuint colorNumber,const GLchar * name)239 _mesa_BindFragDataLocation(GLuint program, GLuint colorNumber,
240 const GLchar *name)
241 {
242 _mesa_BindFragDataLocationIndexed(program, colorNumber, 0, name);
243 }
244
245 void GLAPIENTRY
_mesa_BindFragDataLocationIndexed(GLuint program,GLuint colorNumber,GLuint index,const GLchar * name)246 _mesa_BindFragDataLocationIndexed(GLuint program, GLuint colorNumber,
247 GLuint index, const GLchar *name)
248 {
249 GET_CURRENT_CONTEXT(ctx);
250
251 struct gl_shader_program *const shProg =
252 _mesa_lookup_shader_program_err(ctx, program, "glBindFragDataLocationIndexed");
253 if (!shProg)
254 return;
255
256 if (!name)
257 return;
258
259 if (strncmp(name, "gl_", 3) == 0) {
260 _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFragDataLocationIndexed(illegal name)");
261 return;
262 }
263
264 if (index > 1) {
265 _mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocationIndexed(index)");
266 return;
267 }
268
269 if (index == 0 && colorNumber >= ctx->Const.MaxDrawBuffers) {
270 _mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocationIndexed(colorNumber)");
271 return;
272 }
273
274 if (index == 1 && colorNumber >= ctx->Const.MaxDualSourceDrawBuffers) {
275 _mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocationIndexed(colorNumber)");
276 return;
277 }
278
279 /* Replace the current value if it's already in the list. Add
280 * FRAG_RESULT_DATA0 because that's how the linker differentiates
281 * between built-in attributes and user-defined attributes.
282 */
283 shProg->FragDataBindings->put(colorNumber + FRAG_RESULT_DATA0, name);
284 shProg->FragDataIndexBindings->put(index, name);
285 /*
286 * Note that this binding won't go into effect until
287 * glLinkProgram is called again.
288 */
289
290 }
291
292 GLint GLAPIENTRY
_mesa_GetFragDataIndex(GLuint program,const GLchar * name)293 _mesa_GetFragDataIndex(GLuint program, const GLchar *name)
294 {
295 GET_CURRENT_CONTEXT(ctx);
296 struct gl_shader_program *const shProg =
297 _mesa_lookup_shader_program_err(ctx, program, "glGetFragDataIndex");
298
299 if (!shProg) {
300 return -1;
301 }
302
303 if (!shProg->LinkStatus) {
304 _mesa_error(ctx, GL_INVALID_OPERATION,
305 "glGetFragDataIndex(program not linked)");
306 return -1;
307 }
308
309 if (!name)
310 return -1;
311
312 if (strncmp(name, "gl_", 3) == 0) {
313 _mesa_error(ctx, GL_INVALID_OPERATION,
314 "glGetFragDataIndex(illegal name)");
315 return -1;
316 }
317
318 /* Not having a fragment shader is not an error.
319 */
320 if (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL)
321 return -1;
322
323 exec_list *ir = shProg->_LinkedShaders[MESA_SHADER_FRAGMENT]->ir;
324 foreach_list(node, ir) {
325 const ir_variable *const var = ((ir_instruction *) node)->as_variable();
326
327 /* The extra check against FRAG_RESULT_DATA0 is because
328 * glGetFragDataLocation cannot be used on "conventional" attributes.
329 *
330 * From page 95 of the OpenGL 3.0 spec:
331 *
332 * "If name is not an active attribute, if name is a conventional
333 * attribute, or if an error occurs, -1 will be returned."
334 */
335 if (var == NULL
336 || var->mode != ir_var_out
337 || var->location == -1
338 || var->location < FRAG_RESULT_DATA0)
339 continue;
340
341 if (strcmp(var->name, name) == 0)
342 return var->index;
343 }
344
345 return -1;
346 }
347
348 GLint GLAPIENTRY
_mesa_GetFragDataLocation(GLuint program,const GLchar * name)349 _mesa_GetFragDataLocation(GLuint program, const GLchar *name)
350 {
351 GET_CURRENT_CONTEXT(ctx);
352 struct gl_shader_program *const shProg =
353 _mesa_lookup_shader_program_err(ctx, program, "glGetFragDataLocation");
354
355 if (!shProg) {
356 return -1;
357 }
358
359 if (!shProg->LinkStatus) {
360 _mesa_error(ctx, GL_INVALID_OPERATION,
361 "glGetFragDataLocation(program not linked)");
362 return -1;
363 }
364
365 if (!name)
366 return -1;
367
368 if (strncmp(name, "gl_", 3) == 0) {
369 _mesa_error(ctx, GL_INVALID_OPERATION,
370 "glGetFragDataLocation(illegal name)");
371 return -1;
372 }
373
374 /* Not having a fragment shader is not an error.
375 */
376 if (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL)
377 return -1;
378
379 exec_list *ir = shProg->_LinkedShaders[MESA_SHADER_FRAGMENT]->ir;
380 foreach_list(node, ir) {
381 const ir_variable *const var = ((ir_instruction *) node)->as_variable();
382
383 /* The extra check against FRAG_RESULT_DATA0 is because
384 * glGetFragDataLocation cannot be used on "conventional" attributes.
385 *
386 * From page 95 of the OpenGL 3.0 spec:
387 *
388 * "If name is not an active attribute, if name is a conventional
389 * attribute, or if an error occurs, -1 will be returned."
390 */
391 if (var == NULL
392 || var->mode != ir_var_out
393 || var->location == -1
394 || var->location < FRAG_RESULT_DATA0)
395 continue;
396
397 if (strcmp(var->name, name) == 0)
398 return var->location - FRAG_RESULT_DATA0;
399 }
400
401 return -1;
402 }
403