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