38bacdb747bbe1515a3fe5042861eb5098c533b5
[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_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
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 || var->location < VERT_ATTRIB_GENERIC0)
112 continue;
113
114 if (current_index == desired_index) {
115 _mesa_copy_string(name, maxLength, length, var->name);
116
117 if (size)
118 *size = (var->type->is_array()) ? var->type->length : 1;
119
120 if (type)
121 *type = var->type->gl_type;
122
123 return;
124 }
125
126 current_index++;
127 }
128
129 /* If the loop did not return early, the caller must have asked for
130 * an index that did not exit. Set an error.
131 */
132 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
133 }
134
135 GLint GLAPIENTRY
136 _mesa_GetAttribLocationARB(GLhandleARB program, const GLcharARB * name)
137 {
138 GET_CURRENT_CONTEXT(ctx);
139 struct gl_shader_program *const shProg =
140 _mesa_lookup_shader_program_err(ctx, program, "glGetAttribLocation");
141
142 if (!shProg) {
143 return -1;
144 }
145
146 if (!shProg->LinkStatus) {
147 _mesa_error(ctx, GL_INVALID_OPERATION,
148 "glGetAttribLocation(program not linked)");
149 return -1;
150 }
151
152 if (!name)
153 return -1;
154
155 /* Not having a vertex shader is not an error.
156 */
157 if (shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL)
158 return -1;
159
160 exec_list *ir = shProg->_LinkedShaders[MESA_SHADER_VERTEX]->ir;
161 foreach_list(node, ir) {
162 const ir_variable *const var = ((ir_instruction *) node)->as_variable();
163
164 /* The extra check against VERT_ATTRIB_GENERIC0 is because
165 * glGetAttribLocation cannot be used on "conventional" attributes.
166 *
167 * From page 95 of the OpenGL 3.0 spec:
168 *
169 * "If name is not an active attribute, if name is a conventional
170 * attribute, or if an error occurs, -1 will be returned."
171 */
172 if (var == NULL
173 || var->mode != ir_var_in
174 || var->location == -1
175 || var->location < VERT_ATTRIB_GENERIC0)
176 continue;
177
178 if (strcmp(var->name, name) == 0)
179 return var->location - VERT_ATTRIB_GENERIC0;
180 }
181
182 return -1;
183 }
184
185
186 unsigned
187 _mesa_count_active_attribs(struct gl_shader_program *shProg)
188 {
189 if (!shProg->LinkStatus
190 || shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL) {
191 return 0;
192 }
193
194 exec_list *const ir = shProg->_LinkedShaders[MESA_SHADER_VERTEX]->ir;
195 unsigned i = 0;
196
197 foreach_list(node, ir) {
198 const ir_variable *const var = ((ir_instruction *) node)->as_variable();
199
200 if (var == NULL
201 || var->mode != ir_var_in
202 || var->location == -1
203 || var->location < VERT_ATTRIB_GENERIC0)
204 continue;
205
206 i++;
207 }
208
209 return i;
210 }
211
212
213 size_t
214 _mesa_longest_attribute_name_length(struct gl_shader_program *shProg)
215 {
216 if (!shProg->LinkStatus
217 || shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL) {
218 return 0;
219 }
220
221 exec_list *const ir = shProg->_LinkedShaders[MESA_SHADER_VERTEX]->ir;
222 size_t longest = 0;
223
224 foreach_list(node, ir) {
225 const ir_variable *const var = ((ir_instruction *) node)->as_variable();
226
227 if (var == NULL
228 || var->mode != ir_var_in
229 || var->location == -1
230 || var->location < VERT_ATTRIB_GENERIC0)
231 continue;
232
233 const size_t len = strlen(var->name);
234 if (len >= longest)
235 longest = len + 1;
236 }
237
238 return longest;
239 }
240
241 void GLAPIENTRY
242 _mesa_BindFragDataLocation(GLuint program, GLuint colorNumber,
243 const GLchar *name)
244 {
245 GET_CURRENT_CONTEXT(ctx);
246
247 struct gl_shader_program *const shProg =
248 _mesa_lookup_shader_program_err(ctx, program, "glBindFragDataLocation");
249 if (!shProg)
250 return;
251
252 if (!name)
253 return;
254
255 if (strncmp(name, "gl_", 3) == 0) {
256 _mesa_error(ctx, GL_INVALID_OPERATION,
257 "glBindFragDataLocation(illegal name)");
258 return;
259 }
260
261 if (colorNumber >= ctx->Const.MaxDrawBuffers) {
262 _mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocation(index)");
263 return;
264 }
265
266 /* Replace the current value if it's already in the list. Add
267 * FRAG_RESULT_DATA0 because that's how the linker differentiates
268 * between built-in attributes and user-defined attributes.
269 */
270 shProg->FragDataBindings->put(colorNumber + FRAG_RESULT_DATA0, name);
271
272 /*
273 * Note that this binding won't go into effect until
274 * glLinkProgram is called again.
275 */
276 }
277
278 GLint GLAPIENTRY
279 _mesa_GetFragDataLocation(GLuint program, const GLchar *name)
280 {
281 GET_CURRENT_CONTEXT(ctx);
282 struct gl_shader_program *const shProg =
283 _mesa_lookup_shader_program_err(ctx, program, "glGetFragDataLocation");
284
285 if (!shProg) {
286 return -1;
287 }
288
289 if (!shProg->LinkStatus) {
290 _mesa_error(ctx, GL_INVALID_OPERATION,
291 "glGetFragDataLocation(program not linked)");
292 return -1;
293 }
294
295 if (!name)
296 return -1;
297
298 if (strncmp(name, "gl_", 3) == 0) {
299 _mesa_error(ctx, GL_INVALID_OPERATION,
300 "glGetFragDataLocation(illegal name)");
301 return -1;
302 }
303
304 /* Not having a fragment shader is not an error.
305 */
306 if (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL)
307 return -1;
308
309 exec_list *ir = shProg->_LinkedShaders[MESA_SHADER_FRAGMENT]->ir;
310 foreach_list(node, ir) {
311 const ir_variable *const var = ((ir_instruction *) node)->as_variable();
312
313 /* The extra check against FRAG_RESULT_DATA0 is because
314 * glGetFragDataLocation cannot be used on "conventional" attributes.
315 *
316 * From page 95 of the OpenGL 3.0 spec:
317 *
318 * "If name is not an active attribute, if name is a conventional
319 * attribute, or if an error occurs, -1 will be returned."
320 */
321 if (var == NULL
322 || var->mode != ir_var_out
323 || var->location == -1
324 || var->location < FRAG_RESULT_DATA0)
325 continue;
326
327 if (strcmp(var->name, name) == 0)
328 return var->location - FRAG_RESULT_DATA0;
329 }
330
331 return -1;
332 }