program_resource.c revision 01e04c3f
1/* 2 * Mesa 3-D graphics library 3 * 4 * Copyright (C) 2015 Intel Corporation. All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included 14 * in all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * OTHER DEALINGS IN THE SOFTWARE. 23 * 24 */ 25 26#include "main/enums.h" 27#include "main/macros.h" 28#include "main/mtypes.h" 29#include "main/shaderapi.h" 30#include "main/shaderobj.h" 31#include "main/context.h" 32#include "program_resource.h" 33#include "compiler/glsl/ir_uniform.h" 34 35static bool 36supported_interface_enum(struct gl_context *ctx, GLenum iface) 37{ 38 switch (iface) { 39 case GL_UNIFORM: 40 case GL_UNIFORM_BLOCK: 41 case GL_PROGRAM_INPUT: 42 case GL_PROGRAM_OUTPUT: 43 case GL_TRANSFORM_FEEDBACK_BUFFER: 44 case GL_TRANSFORM_FEEDBACK_VARYING: 45 case GL_ATOMIC_COUNTER_BUFFER: 46 case GL_BUFFER_VARIABLE: 47 case GL_SHADER_STORAGE_BLOCK: 48 return true; 49 case GL_VERTEX_SUBROUTINE: 50 case GL_FRAGMENT_SUBROUTINE: 51 case GL_VERTEX_SUBROUTINE_UNIFORM: 52 case GL_FRAGMENT_SUBROUTINE_UNIFORM: 53 return _mesa_has_ARB_shader_subroutine(ctx); 54 case GL_GEOMETRY_SUBROUTINE: 55 case GL_GEOMETRY_SUBROUTINE_UNIFORM: 56 return _mesa_has_geometry_shaders(ctx) && _mesa_has_ARB_shader_subroutine(ctx); 57 case GL_COMPUTE_SUBROUTINE: 58 case GL_COMPUTE_SUBROUTINE_UNIFORM: 59 return _mesa_has_compute_shaders(ctx) && _mesa_has_ARB_shader_subroutine(ctx); 60 case GL_TESS_CONTROL_SUBROUTINE: 61 case GL_TESS_EVALUATION_SUBROUTINE: 62 case GL_TESS_CONTROL_SUBROUTINE_UNIFORM: 63 case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM: 64 return _mesa_has_tessellation(ctx) && _mesa_has_ARB_shader_subroutine(ctx); 65 default: 66 return false; 67 } 68} 69 70static struct gl_shader_program * 71lookup_linked_program(GLuint program, const char *caller) 72{ 73 GET_CURRENT_CONTEXT(ctx); 74 struct gl_shader_program *prog = 75 _mesa_lookup_shader_program_err(ctx, program, caller); 76 77 if (!prog) 78 return NULL; 79 80 if (prog->data->LinkStatus == LINKING_FAILURE) { 81 _mesa_error(ctx, GL_INVALID_OPERATION, "%s(program not linked)", 82 caller); 83 return NULL; 84 } 85 return prog; 86} 87 88void GLAPIENTRY 89_mesa_GetProgramInterfaceiv(GLuint program, GLenum programInterface, 90 GLenum pname, GLint *params) 91{ 92 GET_CURRENT_CONTEXT(ctx); 93 94 if (MESA_VERBOSE & VERBOSE_API) { 95 _mesa_debug(ctx, "glGetProgramInterfaceiv(%u, %s, %s, %p)\n", 96 program, _mesa_enum_to_string(programInterface), 97 _mesa_enum_to_string(pname), params); 98 } 99 100 unsigned i; 101 struct gl_shader_program *shProg = 102 _mesa_lookup_shader_program_err(ctx, program, 103 "glGetProgramInterfaceiv"); 104 if (!shProg) 105 return; 106 107 if (!params) { 108 _mesa_error(ctx, GL_INVALID_OPERATION, 109 "glGetProgramInterfaceiv(params NULL)"); 110 return; 111 } 112 113 /* Validate interface. */ 114 if (!supported_interface_enum(ctx, programInterface)) { 115 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramInterfaceiv(%s)", 116 _mesa_enum_to_string(programInterface)); 117 return; 118 } 119 120 /* Validate pname against interface. */ 121 switch(pname) { 122 case GL_ACTIVE_RESOURCES: 123 for (i = 0, *params = 0; i < shProg->data->NumProgramResourceList; i++) 124 if (shProg->data->ProgramResourceList[i].Type == programInterface) 125 (*params)++; 126 break; 127 case GL_MAX_NAME_LENGTH: 128 if (programInterface == GL_ATOMIC_COUNTER_BUFFER || 129 programInterface == GL_TRANSFORM_FEEDBACK_BUFFER) { 130 _mesa_error(ctx, GL_INVALID_OPERATION, 131 "glGetProgramInterfaceiv(%s pname %s)", 132 _mesa_enum_to_string(programInterface), 133 _mesa_enum_to_string(pname)); 134 return; 135 } 136 /* Name length consists of base name, 3 additional chars '[0]' if 137 * resource is an array and finally 1 char for string terminator. 138 */ 139 for (i = 0, *params = 0; i < shProg->data->NumProgramResourceList; i++) { 140 if (shProg->data->ProgramResourceList[i].Type != programInterface) 141 continue; 142 unsigned len = 143 _mesa_program_resource_name_len(&shProg->data->ProgramResourceList[i]); 144 *params = MAX2(*params, len + 1); 145 } 146 break; 147 case GL_MAX_NUM_ACTIVE_VARIABLES: 148 switch (programInterface) { 149 case GL_UNIFORM_BLOCK: 150 for (i = 0, *params = 0; i < shProg->data->NumProgramResourceList; i++) { 151 if (shProg->data->ProgramResourceList[i].Type == programInterface) { 152 struct gl_uniform_block *block = 153 (struct gl_uniform_block *) 154 shProg->data->ProgramResourceList[i].Data; 155 *params = MAX2(*params, block->NumUniforms); 156 } 157 } 158 break; 159 case GL_SHADER_STORAGE_BLOCK: 160 for (i = 0, *params = 0; i < shProg->data->NumProgramResourceList; i++) { 161 if (shProg->data->ProgramResourceList[i].Type == programInterface) { 162 struct gl_uniform_block *block = 163 (struct gl_uniform_block *) 164 shProg->data->ProgramResourceList[i].Data; 165 GLint block_params = 0; 166 for (unsigned j = 0; j < block->NumUniforms; j++) { 167 const char *iname = block->Uniforms[j].IndexName; 168 struct gl_program_resource *uni = 169 _mesa_program_resource_find_name(shProg, GL_BUFFER_VARIABLE, 170 iname, NULL); 171 if (!uni) 172 continue; 173 block_params++; 174 } 175 *params = MAX2(*params, block_params); 176 } 177 } 178 break; 179 case GL_ATOMIC_COUNTER_BUFFER: 180 for (i = 0, *params = 0; i < shProg->data->NumProgramResourceList; i++) { 181 if (shProg->data->ProgramResourceList[i].Type == programInterface) { 182 struct gl_active_atomic_buffer *buffer = 183 (struct gl_active_atomic_buffer *) 184 shProg->data->ProgramResourceList[i].Data; 185 *params = MAX2(*params, buffer->NumUniforms); 186 } 187 } 188 break; 189 case GL_TRANSFORM_FEEDBACK_BUFFER: 190 for (i = 0, *params = 0; i < shProg->data->NumProgramResourceList; i++) { 191 if (shProg->data->ProgramResourceList[i].Type == programInterface) { 192 struct gl_transform_feedback_buffer *buffer = 193 (struct gl_transform_feedback_buffer *) 194 shProg->data->ProgramResourceList[i].Data; 195 *params = MAX2(*params, buffer->NumVaryings); 196 } 197 } 198 break; 199 default: 200 _mesa_error(ctx, GL_INVALID_OPERATION, 201 "glGetProgramInterfaceiv(%s pname %s)", 202 _mesa_enum_to_string(programInterface), 203 _mesa_enum_to_string(pname)); 204 } 205 break; 206 case GL_MAX_NUM_COMPATIBLE_SUBROUTINES: 207 switch (programInterface) { 208 case GL_VERTEX_SUBROUTINE_UNIFORM: 209 case GL_FRAGMENT_SUBROUTINE_UNIFORM: 210 case GL_GEOMETRY_SUBROUTINE_UNIFORM: 211 case GL_COMPUTE_SUBROUTINE_UNIFORM: 212 case GL_TESS_CONTROL_SUBROUTINE_UNIFORM: 213 case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM: { 214 for (i = 0, *params = 0; i < shProg->data->NumProgramResourceList; i++) { 215 if (shProg->data->ProgramResourceList[i].Type == programInterface) { 216 struct gl_uniform_storage *uni = 217 (struct gl_uniform_storage *) 218 shProg->data->ProgramResourceList[i].Data; 219 *params = MAX2(*params, uni->num_compatible_subroutines); 220 } 221 } 222 break; 223 } 224 225 default: 226 _mesa_error(ctx, GL_INVALID_OPERATION, 227 "glGetProgramInterfaceiv(%s pname %s)", 228 _mesa_enum_to_string(programInterface), 229 _mesa_enum_to_string(pname)); 230 } 231 break; 232 default: 233 _mesa_error(ctx, GL_INVALID_OPERATION, 234 "glGetProgramInterfaceiv(pname %s)", 235 _mesa_enum_to_string(pname)); 236 } 237} 238 239static bool 240is_xfb_marker(const char *str) 241{ 242 static const char *markers[] = { 243 "gl_NextBuffer", 244 "gl_SkipComponents1", 245 "gl_SkipComponents2", 246 "gl_SkipComponents3", 247 "gl_SkipComponents4", 248 NULL 249 }; 250 const char **m = markers; 251 252 if (strncmp(str, "gl_", 3) != 0) 253 return false; 254 255 for (; *m; m++) 256 if (strcmp(*m, str) == 0) 257 return true; 258 259 return false; 260} 261 262GLuint GLAPIENTRY 263_mesa_GetProgramResourceIndex(GLuint program, GLenum programInterface, 264 const GLchar *name) 265{ 266 GET_CURRENT_CONTEXT(ctx); 267 268 if (MESA_VERBOSE & VERBOSE_API) { 269 _mesa_debug(ctx, "glGetProgramResourceIndex(%u, %s, %s)\n", 270 program, _mesa_enum_to_string(programInterface), name); 271 } 272 273 unsigned array_index = 0; 274 struct gl_program_resource *res; 275 struct gl_shader_program *shProg = 276 _mesa_lookup_shader_program_err(ctx, program, 277 "glGetProgramResourceIndex"); 278 if (!shProg || !name) 279 return GL_INVALID_INDEX; 280 281 if (!supported_interface_enum(ctx, programInterface)) { 282 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceIndex(%s)", 283 _mesa_enum_to_string(programInterface)); 284 return GL_INVALID_INDEX; 285 } 286 /* 287 * For the interface TRANSFORM_FEEDBACK_VARYING, the value INVALID_INDEX 288 * should be returned when querying the index assigned to the special names 289 * "gl_NextBuffer", "gl_SkipComponents1", "gl_SkipComponents2", 290 * "gl_SkipComponents3", and "gl_SkipComponents4". 291 */ 292 if (programInterface == GL_TRANSFORM_FEEDBACK_VARYING && 293 is_xfb_marker(name)) 294 return GL_INVALID_INDEX; 295 296 switch (programInterface) { 297 case GL_TESS_CONTROL_SUBROUTINE: 298 case GL_TESS_CONTROL_SUBROUTINE_UNIFORM: 299 case GL_TESS_EVALUATION_SUBROUTINE: 300 case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM: 301 case GL_COMPUTE_SUBROUTINE: 302 case GL_COMPUTE_SUBROUTINE_UNIFORM: 303 case GL_GEOMETRY_SUBROUTINE: 304 case GL_GEOMETRY_SUBROUTINE_UNIFORM: 305 case GL_VERTEX_SUBROUTINE: 306 case GL_FRAGMENT_SUBROUTINE: 307 case GL_VERTEX_SUBROUTINE_UNIFORM: 308 case GL_FRAGMENT_SUBROUTINE_UNIFORM: 309 case GL_PROGRAM_INPUT: 310 case GL_PROGRAM_OUTPUT: 311 case GL_UNIFORM: 312 case GL_BUFFER_VARIABLE: 313 case GL_TRANSFORM_FEEDBACK_VARYING: 314 case GL_UNIFORM_BLOCK: 315 case GL_SHADER_STORAGE_BLOCK: 316 res = _mesa_program_resource_find_name(shProg, programInterface, name, 317 &array_index); 318 if (!res || array_index > 0) 319 return GL_INVALID_INDEX; 320 321 return _mesa_program_resource_index(shProg, res); 322 case GL_ATOMIC_COUNTER_BUFFER: 323 case GL_TRANSFORM_FEEDBACK_BUFFER: 324 default: 325 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceIndex(%s)", 326 _mesa_enum_to_string(programInterface)); 327 } 328 329 return GL_INVALID_INDEX; 330} 331 332void GLAPIENTRY 333_mesa_GetProgramResourceName(GLuint program, GLenum programInterface, 334 GLuint index, GLsizei bufSize, GLsizei *length, 335 GLchar *name) 336{ 337 GET_CURRENT_CONTEXT(ctx); 338 339 if (MESA_VERBOSE & VERBOSE_API) { 340 _mesa_debug(ctx, "glGetProgramResourceName(%u, %s, %u, %d, %p, %p)\n", 341 program, _mesa_enum_to_string(programInterface), index, 342 bufSize, length, name); 343 } 344 345 struct gl_shader_program *shProg = 346 _mesa_lookup_shader_program_err(ctx, program, 347 "glGetProgramResourceName"); 348 349 if (!shProg || !name) 350 return; 351 352 if (programInterface == GL_ATOMIC_COUNTER_BUFFER || 353 programInterface == GL_TRANSFORM_FEEDBACK_BUFFER || 354 !supported_interface_enum(ctx, programInterface)) { 355 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceName(%s)", 356 _mesa_enum_to_string(programInterface)); 357 return; 358 } 359 360 _mesa_get_program_resource_name(shProg, programInterface, index, bufSize, 361 length, name, "glGetProgramResourceName"); 362} 363 364void GLAPIENTRY 365_mesa_GetProgramResourceiv(GLuint program, GLenum programInterface, 366 GLuint index, GLsizei propCount, 367 const GLenum *props, GLsizei bufSize, 368 GLsizei *length, GLint *params) 369{ 370 GET_CURRENT_CONTEXT(ctx); 371 372 if (MESA_VERBOSE & VERBOSE_API) { 373 _mesa_debug(ctx, "glGetProgramResourceiv(%u, %s, %u, %d, %p, %d, %p, %p)\n", 374 program, _mesa_enum_to_string(programInterface), index, 375 propCount, props, bufSize, length, params); 376 } 377 378 struct gl_shader_program *shProg = 379 _mesa_lookup_shader_program_err(ctx, program, "glGetProgramResourceiv"); 380 381 if (!shProg || !params) 382 return; 383 384 /* The error INVALID_VALUE is generated if <propCount> is zero. 385 * Note that we check < 0 here because it makes sense to bail early. 386 */ 387 if (propCount <= 0) { 388 _mesa_error(ctx, GL_INVALID_VALUE, 389 "glGetProgramResourceiv(propCount <= 0)"); 390 return; 391 } 392 393 _mesa_get_program_resourceiv(shProg, programInterface, index, 394 propCount, props, bufSize, length, params); 395} 396 397GLint GLAPIENTRY 398_mesa_GetProgramResourceLocation(GLuint program, GLenum programInterface, 399 const GLchar *name) 400{ 401 GET_CURRENT_CONTEXT(ctx); 402 403 if (MESA_VERBOSE & VERBOSE_API) { 404 _mesa_debug(ctx, "glGetProgramResourceLocation(%u, %s, %s)\n", 405 program, _mesa_enum_to_string(programInterface), name); 406 } 407 408 struct gl_shader_program *shProg = 409 lookup_linked_program(program, "glGetProgramResourceLocation"); 410 411 if (!shProg || !name) 412 return -1; 413 414 /* Validate programInterface. */ 415 switch (programInterface) { 416 case GL_UNIFORM: 417 case GL_PROGRAM_INPUT: 418 case GL_PROGRAM_OUTPUT: 419 break; 420 421 case GL_VERTEX_SUBROUTINE_UNIFORM: 422 case GL_FRAGMENT_SUBROUTINE_UNIFORM: 423 if (!_mesa_has_ARB_shader_subroutine(ctx)) 424 goto fail; 425 break; 426 case GL_GEOMETRY_SUBROUTINE_UNIFORM: 427 if (!_mesa_has_geometry_shaders(ctx) || !_mesa_has_ARB_shader_subroutine(ctx)) 428 goto fail; 429 break; 430 case GL_COMPUTE_SUBROUTINE_UNIFORM: 431 if (!_mesa_has_compute_shaders(ctx) || !_mesa_has_ARB_shader_subroutine(ctx)) 432 goto fail; 433 break; 434 case GL_TESS_CONTROL_SUBROUTINE_UNIFORM: 435 case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM: 436 if (!_mesa_has_tessellation(ctx) || !_mesa_has_ARB_shader_subroutine(ctx)) 437 goto fail; 438 break; 439 default: 440 goto fail; 441 } 442 443 return _mesa_program_resource_location(shProg, programInterface, name); 444fail: 445 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceLocation(%s %s)", 446 _mesa_enum_to_string(programInterface), name); 447 return -1; 448} 449 450/** 451 * Returns output index for dual source blending. 452 */ 453GLint GLAPIENTRY 454_mesa_GetProgramResourceLocationIndex(GLuint program, GLenum programInterface, 455 const GLchar *name) 456{ 457 GET_CURRENT_CONTEXT(ctx); 458 459 if (MESA_VERBOSE & VERBOSE_API) { 460 _mesa_debug(ctx, "glGetProgramResourceLocationIndex(%u, %s, %s)\n", 461 program, _mesa_enum_to_string(programInterface), name); 462 } 463 464 struct gl_shader_program *shProg = 465 lookup_linked_program(program, "glGetProgramResourceLocationIndex"); 466 467 if (!shProg || !name) 468 return -1; 469 470 /* From the GL_ARB_program_interface_query spec: 471 * 472 * "For GetProgramResourceLocationIndex, <programInterface> must be 473 * PROGRAM_OUTPUT." 474 */ 475 if (programInterface != GL_PROGRAM_OUTPUT) { 476 _mesa_error(ctx, GL_INVALID_ENUM, 477 "glGetProgramResourceLocationIndex(%s)", 478 _mesa_enum_to_string(programInterface)); 479 return -1; 480 } 481 482 return _mesa_program_resource_location_index(shProg, GL_PROGRAM_OUTPUT, 483 name); 484} 485