shader_query.cpp revision e6c314f7d2ed99714376fec6b7509a55535fa3ff
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 38extern "C" { 39#include "shaderapi.h" 40} 41 42void 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 79void 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 134GLint 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 185unsigned 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 211size_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 238void GLAPIENTRY 239_mesa_BindFragDataLocation(GLuint program, GLuint colorNumber, 240 const GLchar *name) 241{ 242 GET_CURRENT_CONTEXT(ctx); 243 244 struct gl_shader_program *const shProg = 245 _mesa_lookup_shader_program_err(ctx, program, "glBindFragDataLocation"); 246 if (!shProg) 247 return; 248 249 if (!name) 250 return; 251 252 if (strncmp(name, "gl_", 3) == 0) { 253 _mesa_error(ctx, GL_INVALID_OPERATION, 254 "glBindFragDataLocation(illegal name)"); 255 return; 256 } 257 258 if (colorNumber >= ctx->Const.MaxDrawBuffers) { 259 _mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocation(index)"); 260 return; 261 } 262 263 /* Replace the current value if it's already in the list. Add 264 * FRAG_RESULT_DATA0 because that's how the linker differentiates 265 * between built-in attributes and user-defined attributes. 266 */ 267 shProg->FragDataBindings->put(colorNumber + FRAG_RESULT_DATA0, name); 268 269 /* 270 * Note that this binding won't go into effect until 271 * glLinkProgram is called again. 272 */ 273} 274 275GLint GLAPIENTRY 276_mesa_GetFragDataLocation(GLuint program, const GLchar *name) 277{ 278 GET_CURRENT_CONTEXT(ctx); 279 struct gl_shader_program *const shProg = 280 _mesa_lookup_shader_program_err(ctx, program, "glGetFragDataLocation"); 281 282 if (!shProg) { 283 return -1; 284 } 285 286 if (!shProg->LinkStatus) { 287 _mesa_error(ctx, GL_INVALID_OPERATION, 288 "glGetFragDataLocation(program not linked)"); 289 return -1; 290 } 291 292 if (!name) 293 return -1; 294 295 if (strncmp(name, "gl_", 3) == 0) { 296 _mesa_error(ctx, GL_INVALID_OPERATION, 297 "glGetFragDataLocation(illegal name)"); 298 return -1; 299 } 300 301 /* Not having a fragment shader is not an error. 302 */ 303 if (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL) 304 return -1; 305 306 exec_list *ir = shProg->_LinkedShaders[MESA_SHADER_FRAGMENT]->ir; 307 foreach_list(node, ir) { 308 const ir_variable *const var = ((ir_instruction *) node)->as_variable(); 309 310 /* The extra check against FRAG_RESULT_DATA0 is because 311 * glGetFragDataLocation cannot be used on "conventional" attributes. 312 * 313 * From page 95 of the OpenGL 3.0 spec: 314 * 315 * "If name is not an active attribute, if name is a conventional 316 * attribute, or if an error occurs, -1 will be returned." 317 */ 318 if (var == NULL 319 || var->mode != ir_var_out 320 || var->location == -1 321 || var->location < FRAG_RESULT_DATA0) 322 continue; 323 324 if (strcmp(var->name, name) == 0) 325 return var->location - FRAG_RESULT_DATA0; 326 } 327 328 return -1; 329} 330