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 "compiler/glsl/ir_uniform.h" 33#include "api_exec_decl.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 struct gl_shader_program *shProg = 101 _mesa_lookup_shader_program_err(ctx, program, 102 "glGetProgramInterfaceiv"); 103 if (!shProg) 104 return; 105 106 if (!params) { 107 _mesa_error(ctx, GL_INVALID_OPERATION, 108 "glGetProgramInterfaceiv(params NULL)"); 109 return; 110 } 111 112 /* Validate interface. */ 113 if (!supported_interface_enum(ctx, programInterface)) { 114 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramInterfaceiv(%s)", 115 _mesa_enum_to_string(programInterface)); 116 return; 117 } 118 119 _mesa_get_program_interfaceiv(shProg, programInterface, pname, params); 120} 121 122static bool 123is_xfb_marker(const char *str) 124{ 125 static const char *markers[] = { 126 "gl_NextBuffer", 127 "gl_SkipComponents1", 128 "gl_SkipComponents2", 129 "gl_SkipComponents3", 130 "gl_SkipComponents4", 131 NULL 132 }; 133 const char **m = markers; 134 135 if (strncmp(str, "gl_", 3) != 0) 136 return false; 137 138 for (; *m; m++) 139 if (strcmp(*m, str) == 0) 140 return true; 141 142 return false; 143} 144 145GLuint GLAPIENTRY 146_mesa_GetProgramResourceIndex(GLuint program, GLenum programInterface, 147 const GLchar *name) 148{ 149 GET_CURRENT_CONTEXT(ctx); 150 151 if (MESA_VERBOSE & VERBOSE_API) { 152 _mesa_debug(ctx, "glGetProgramResourceIndex(%u, %s, %s)\n", 153 program, _mesa_enum_to_string(programInterface), name); 154 } 155 156 unsigned array_index = 0; 157 struct gl_program_resource *res; 158 struct gl_shader_program *shProg = 159 _mesa_lookup_shader_program_err(ctx, program, 160 "glGetProgramResourceIndex"); 161 if (!shProg || !name) 162 return GL_INVALID_INDEX; 163 164 if (!supported_interface_enum(ctx, programInterface)) { 165 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceIndex(%s)", 166 _mesa_enum_to_string(programInterface)); 167 return GL_INVALID_INDEX; 168 } 169 /* 170 * For the interface TRANSFORM_FEEDBACK_VARYING, the value INVALID_INDEX 171 * should be returned when querying the index assigned to the special names 172 * "gl_NextBuffer", "gl_SkipComponents1", "gl_SkipComponents2", 173 * "gl_SkipComponents3", and "gl_SkipComponents4". 174 */ 175 if (programInterface == GL_TRANSFORM_FEEDBACK_VARYING && 176 is_xfb_marker(name)) 177 return GL_INVALID_INDEX; 178 179 switch (programInterface) { 180 case GL_TESS_CONTROL_SUBROUTINE: 181 case GL_TESS_CONTROL_SUBROUTINE_UNIFORM: 182 case GL_TESS_EVALUATION_SUBROUTINE: 183 case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM: 184 case GL_COMPUTE_SUBROUTINE: 185 case GL_COMPUTE_SUBROUTINE_UNIFORM: 186 case GL_GEOMETRY_SUBROUTINE: 187 case GL_GEOMETRY_SUBROUTINE_UNIFORM: 188 case GL_VERTEX_SUBROUTINE: 189 case GL_FRAGMENT_SUBROUTINE: 190 case GL_VERTEX_SUBROUTINE_UNIFORM: 191 case GL_FRAGMENT_SUBROUTINE_UNIFORM: 192 case GL_PROGRAM_INPUT: 193 case GL_PROGRAM_OUTPUT: 194 case GL_UNIFORM: 195 case GL_BUFFER_VARIABLE: 196 case GL_TRANSFORM_FEEDBACK_VARYING: 197 case GL_UNIFORM_BLOCK: 198 case GL_SHADER_STORAGE_BLOCK: 199 res = _mesa_program_resource_find_name(shProg, programInterface, name, 200 &array_index); 201 if (!res || array_index > 0) 202 return GL_INVALID_INDEX; 203 204 return _mesa_program_resource_index(shProg, res); 205 case GL_ATOMIC_COUNTER_BUFFER: 206 case GL_TRANSFORM_FEEDBACK_BUFFER: 207 default: 208 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceIndex(%s)", 209 _mesa_enum_to_string(programInterface)); 210 } 211 212 return GL_INVALID_INDEX; 213} 214 215void GLAPIENTRY 216_mesa_GetProgramResourceName(GLuint program, GLenum programInterface, 217 GLuint index, GLsizei bufSize, GLsizei *length, 218 GLchar *name) 219{ 220 GET_CURRENT_CONTEXT(ctx); 221 222 if (MESA_VERBOSE & VERBOSE_API) { 223 _mesa_debug(ctx, "glGetProgramResourceName(%u, %s, %u, %d, %p, %p)\n", 224 program, _mesa_enum_to_string(programInterface), index, 225 bufSize, length, name); 226 } 227 228 struct gl_shader_program *shProg = 229 _mesa_lookup_shader_program_err(ctx, program, 230 "glGetProgramResourceName"); 231 232 if (!shProg || !name) 233 return; 234 235 if (programInterface == GL_ATOMIC_COUNTER_BUFFER || 236 programInterface == GL_TRANSFORM_FEEDBACK_BUFFER || 237 !supported_interface_enum(ctx, programInterface)) { 238 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceName(%s)", 239 _mesa_enum_to_string(programInterface)); 240 return; 241 } 242 243 _mesa_get_program_resource_name(shProg, programInterface, index, bufSize, 244 length, name, false, 245 "glGetProgramResourceName"); 246} 247 248void GLAPIENTRY 249_mesa_GetProgramResourceiv(GLuint program, GLenum programInterface, 250 GLuint index, GLsizei propCount, 251 const GLenum *props, GLsizei bufSize, 252 GLsizei *length, GLint *params) 253{ 254 GET_CURRENT_CONTEXT(ctx); 255 256 if (MESA_VERBOSE & VERBOSE_API) { 257 _mesa_debug(ctx, "glGetProgramResourceiv(%u, %s, %u, %d, %p, %d, %p, %p)\n", 258 program, _mesa_enum_to_string(programInterface), index, 259 propCount, props, bufSize, length, params); 260 } 261 262 struct gl_shader_program *shProg = 263 _mesa_lookup_shader_program_err(ctx, program, "glGetProgramResourceiv"); 264 265 if (!shProg || !params) 266 return; 267 268 /* The error INVALID_VALUE is generated if <propCount> is zero. 269 * Note that we check < 0 here because it makes sense to bail early. 270 */ 271 if (propCount <= 0) { 272 _mesa_error(ctx, GL_INVALID_VALUE, 273 "glGetProgramResourceiv(propCount <= 0)"); 274 return; 275 } 276 277 _mesa_get_program_resourceiv(shProg, programInterface, index, 278 propCount, props, bufSize, length, params); 279} 280 281GLint GLAPIENTRY 282_mesa_GetProgramResourceLocation(GLuint program, GLenum programInterface, 283 const GLchar *name) 284{ 285 GET_CURRENT_CONTEXT(ctx); 286 287 if (MESA_VERBOSE & VERBOSE_API) { 288 _mesa_debug(ctx, "glGetProgramResourceLocation(%u, %s, %s)\n", 289 program, _mesa_enum_to_string(programInterface), name); 290 } 291 292 struct gl_shader_program *shProg = 293 lookup_linked_program(program, "glGetProgramResourceLocation"); 294 295 if (!shProg || !name) 296 return -1; 297 298 /* Validate programInterface. */ 299 switch (programInterface) { 300 case GL_UNIFORM: 301 case GL_PROGRAM_INPUT: 302 case GL_PROGRAM_OUTPUT: 303 break; 304 305 case GL_VERTEX_SUBROUTINE_UNIFORM: 306 case GL_FRAGMENT_SUBROUTINE_UNIFORM: 307 if (!_mesa_has_ARB_shader_subroutine(ctx)) 308 goto fail; 309 break; 310 case GL_GEOMETRY_SUBROUTINE_UNIFORM: 311 if (!_mesa_has_geometry_shaders(ctx) || !_mesa_has_ARB_shader_subroutine(ctx)) 312 goto fail; 313 break; 314 case GL_COMPUTE_SUBROUTINE_UNIFORM: 315 if (!_mesa_has_compute_shaders(ctx) || !_mesa_has_ARB_shader_subroutine(ctx)) 316 goto fail; 317 break; 318 case GL_TESS_CONTROL_SUBROUTINE_UNIFORM: 319 case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM: 320 if (!_mesa_has_tessellation(ctx) || !_mesa_has_ARB_shader_subroutine(ctx)) 321 goto fail; 322 break; 323 default: 324 goto fail; 325 } 326 327 return _mesa_program_resource_location(shProg, programInterface, name); 328fail: 329 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceLocation(%s %s)", 330 _mesa_enum_to_string(programInterface), name); 331 return -1; 332} 333 334/** 335 * Returns output index for dual source blending. 336 */ 337GLint GLAPIENTRY 338_mesa_GetProgramResourceLocationIndex(GLuint program, GLenum programInterface, 339 const GLchar *name) 340{ 341 GET_CURRENT_CONTEXT(ctx); 342 343 if (MESA_VERBOSE & VERBOSE_API) { 344 _mesa_debug(ctx, "glGetProgramResourceLocationIndex(%u, %s, %s)\n", 345 program, _mesa_enum_to_string(programInterface), name); 346 } 347 348 struct gl_shader_program *shProg = 349 lookup_linked_program(program, "glGetProgramResourceLocationIndex"); 350 351 if (!shProg || !name) 352 return -1; 353 354 /* From the GL_ARB_program_interface_query spec: 355 * 356 * "For GetProgramResourceLocationIndex, <programInterface> must be 357 * PROGRAM_OUTPUT." 358 */ 359 if (programInterface != GL_PROGRAM_OUTPUT) { 360 _mesa_error(ctx, GL_INVALID_ENUM, 361 "glGetProgramResourceLocationIndex(%s)", 362 _mesa_enum_to_string(programInterface)); 363 return -1; 364 } 365 366 return _mesa_program_resource_location_index(shProg, GL_PROGRAM_OUTPUT, 367 name); 368} 369