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 (at) 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 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 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 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 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 239 _mesa_BindFragDataLocation(GLuint program, GLuint colorNumber, 240 const GLchar *name) 241 { 242 _mesa_BindFragDataLocationIndexed(program, colorNumber, 0, name); 243 } 244 245 void GLAPIENTRY 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 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 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