mesa: Add gl_shader_program::AttributeBindings
[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
37 extern "C" {
38 #include "shaderapi.h"
39 }
40
41 void GLAPIENTRY
42 _mesa_BindAttribLocationARB(GLhandleARB program, GLuint index,
43 const GLcharARB *name)
44 {
45 GET_CURRENT_CONTEXT(ctx);
46
47 const GLint size = -1; /* unknown size */
48 GLint i;
49 GLenum datatype = GL_FLOAT_VEC4;
50
51 struct gl_shader_program *const shProg =
52 _mesa_lookup_shader_program_err(ctx, program, "glBindAttribLocation");
53 if (!shProg)
54 return;
55
56 if (!name)
57 return;
58
59 if (strncmp(name, "gl_", 3) == 0) {
60 _mesa_error(ctx, GL_INVALID_OPERATION,
61 "glBindAttribLocation(illegal name)");
62 return;
63 }
64
65 if (index >= ctx->Const.VertexProgram.MaxAttribs) {
66 _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(index)");
67 return;
68 }
69
70 /* this will replace the current value if it's already in the list */
71 /* Add VERT_ATTRIB_GENERIC0 because that's how the linker differentiates
72 * between built-in attributes and user-defined attributes.
73 */
74 shProg->AttributeBindings->put(index + VERT_ATTRIB_GENERIC0, name);
75 i = _mesa_add_attribute(shProg->Attributes, name, size, datatype, index);
76 if (i < 0) {
77 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindAttribLocation");
78 return;
79 }
80
81 /*
82 * Note that this attribute binding won't go into effect until
83 * glLinkProgram is called again.
84 */
85 }
86
87 GLint GLAPIENTRY
88 _mesa_GetAttribLocationARB(GLhandleARB program, const GLcharARB * name)
89 {
90 GET_CURRENT_CONTEXT(ctx);
91 struct gl_shader_program *const shProg =
92 _mesa_lookup_shader_program_err(ctx, program, "glGetAttribLocation");
93
94 if (!shProg) {
95 return -1;
96 }
97
98 if (!shProg->LinkStatus) {
99 _mesa_error(ctx, GL_INVALID_OPERATION,
100 "glGetAttribLocation(program not linked)");
101 return -1;
102 }
103
104 if (!name)
105 return -1;
106
107 /* Not having a vertex shader is not an error.
108 */
109 if (shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL)
110 return -1;
111
112 exec_list *ir = shProg->_LinkedShaders[MESA_SHADER_VERTEX]->ir;
113 foreach_list(node, ir) {
114 const ir_variable *const var = ((ir_instruction *) node)->as_variable();
115
116 /* The extra check against VERT_ATTRIB_GENERIC0 is because
117 * glGetAttribLocation cannot be used on "conventional" attributes.
118 *
119 * From page 95 of the OpenGL 3.0 spec:
120 *
121 * "If name is not an active attribute, if name is a conventional
122 * attribute, or if an error occurs, -1 will be returned."
123 */
124 if (var == NULL
125 || var->mode != ir_var_in
126 || var->location == -1
127 || var->location < VERT_ATTRIB_GENERIC0)
128 continue;
129
130 if (strcmp(var->name, name) == 0)
131 return var->location - VERT_ATTRIB_GENERIC0;
132 }
133
134 return -1;
135 }