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
35 static bool
supported_interface_enum(struct gl_context * ctx,GLenum iface)36 supported_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
70 static struct gl_shader_program *
lookup_linked_program(GLuint program,const char * caller)71 lookup_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
88 void GLAPIENTRY
_mesa_GetProgramInterfaceiv(GLuint program,GLenum programInterface,GLenum pname,GLint * params)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 struct gl_program_resource *uni =
168 _mesa_program_resource_find_active_variable(
169 shProg,
170 GL_BUFFER_VARIABLE,
171 block,
172 j);
173 if (!uni)
174 continue;
175 block_params++;
176 }
177 *params = MAX2(*params, block_params);
178 }
179 }
180 break;
181 case GL_ATOMIC_COUNTER_BUFFER:
182 for (i = 0, *params = 0; i < shProg->data->NumProgramResourceList; i++) {
183 if (shProg->data->ProgramResourceList[i].Type == programInterface) {
184 struct gl_active_atomic_buffer *buffer =
185 (struct gl_active_atomic_buffer *)
186 shProg->data->ProgramResourceList[i].Data;
187 *params = MAX2(*params, buffer->NumUniforms);
188 }
189 }
190 break;
191 case GL_TRANSFORM_FEEDBACK_BUFFER:
192 for (i = 0, *params = 0; i < shProg->data->NumProgramResourceList; i++) {
193 if (shProg->data->ProgramResourceList[i].Type == programInterface) {
194 struct gl_transform_feedback_buffer *buffer =
195 (struct gl_transform_feedback_buffer *)
196 shProg->data->ProgramResourceList[i].Data;
197 *params = MAX2(*params, buffer->NumVaryings);
198 }
199 }
200 break;
201 default:
202 _mesa_error(ctx, GL_INVALID_OPERATION,
203 "glGetProgramInterfaceiv(%s pname %s)",
204 _mesa_enum_to_string(programInterface),
205 _mesa_enum_to_string(pname));
206 }
207 break;
208 case GL_MAX_NUM_COMPATIBLE_SUBROUTINES:
209 switch (programInterface) {
210 case GL_VERTEX_SUBROUTINE_UNIFORM:
211 case GL_FRAGMENT_SUBROUTINE_UNIFORM:
212 case GL_GEOMETRY_SUBROUTINE_UNIFORM:
213 case GL_COMPUTE_SUBROUTINE_UNIFORM:
214 case GL_TESS_CONTROL_SUBROUTINE_UNIFORM:
215 case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM: {
216 for (i = 0, *params = 0; i < shProg->data->NumProgramResourceList; i++) {
217 if (shProg->data->ProgramResourceList[i].Type == programInterface) {
218 struct gl_uniform_storage *uni =
219 (struct gl_uniform_storage *)
220 shProg->data->ProgramResourceList[i].Data;
221 *params = MAX2(*params, uni->num_compatible_subroutines);
222 }
223 }
224 break;
225 }
226
227 default:
228 _mesa_error(ctx, GL_INVALID_OPERATION,
229 "glGetProgramInterfaceiv(%s pname %s)",
230 _mesa_enum_to_string(programInterface),
231 _mesa_enum_to_string(pname));
232 }
233 break;
234 default:
235 _mesa_error(ctx, GL_INVALID_OPERATION,
236 "glGetProgramInterfaceiv(pname %s)",
237 _mesa_enum_to_string(pname));
238 }
239 }
240
241 static bool
is_xfb_marker(const char * str)242 is_xfb_marker(const char *str)
243 {
244 static const char *markers[] = {
245 "gl_NextBuffer",
246 "gl_SkipComponents1",
247 "gl_SkipComponents2",
248 "gl_SkipComponents3",
249 "gl_SkipComponents4",
250 NULL
251 };
252 const char **m = markers;
253
254 if (strncmp(str, "gl_", 3) != 0)
255 return false;
256
257 for (; *m; m++)
258 if (strcmp(*m, str) == 0)
259 return true;
260
261 return false;
262 }
263
264 GLuint GLAPIENTRY
_mesa_GetProgramResourceIndex(GLuint program,GLenum programInterface,const GLchar * name)265 _mesa_GetProgramResourceIndex(GLuint program, GLenum programInterface,
266 const GLchar *name)
267 {
268 GET_CURRENT_CONTEXT(ctx);
269
270 if (MESA_VERBOSE & VERBOSE_API) {
271 _mesa_debug(ctx, "glGetProgramResourceIndex(%u, %s, %s)\n",
272 program, _mesa_enum_to_string(programInterface), name);
273 }
274
275 unsigned array_index = 0;
276 struct gl_program_resource *res;
277 struct gl_shader_program *shProg =
278 _mesa_lookup_shader_program_err(ctx, program,
279 "glGetProgramResourceIndex");
280 if (!shProg || !name)
281 return GL_INVALID_INDEX;
282
283 if (!supported_interface_enum(ctx, programInterface)) {
284 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceIndex(%s)",
285 _mesa_enum_to_string(programInterface));
286 return GL_INVALID_INDEX;
287 }
288 /*
289 * For the interface TRANSFORM_FEEDBACK_VARYING, the value INVALID_INDEX
290 * should be returned when querying the index assigned to the special names
291 * "gl_NextBuffer", "gl_SkipComponents1", "gl_SkipComponents2",
292 * "gl_SkipComponents3", and "gl_SkipComponents4".
293 */
294 if (programInterface == GL_TRANSFORM_FEEDBACK_VARYING &&
295 is_xfb_marker(name))
296 return GL_INVALID_INDEX;
297
298 switch (programInterface) {
299 case GL_TESS_CONTROL_SUBROUTINE:
300 case GL_TESS_CONTROL_SUBROUTINE_UNIFORM:
301 case GL_TESS_EVALUATION_SUBROUTINE:
302 case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM:
303 case GL_COMPUTE_SUBROUTINE:
304 case GL_COMPUTE_SUBROUTINE_UNIFORM:
305 case GL_GEOMETRY_SUBROUTINE:
306 case GL_GEOMETRY_SUBROUTINE_UNIFORM:
307 case GL_VERTEX_SUBROUTINE:
308 case GL_FRAGMENT_SUBROUTINE:
309 case GL_VERTEX_SUBROUTINE_UNIFORM:
310 case GL_FRAGMENT_SUBROUTINE_UNIFORM:
311 case GL_PROGRAM_INPUT:
312 case GL_PROGRAM_OUTPUT:
313 case GL_UNIFORM:
314 case GL_BUFFER_VARIABLE:
315 case GL_TRANSFORM_FEEDBACK_VARYING:
316 case GL_UNIFORM_BLOCK:
317 case GL_SHADER_STORAGE_BLOCK:
318 res = _mesa_program_resource_find_name(shProg, programInterface, name,
319 &array_index);
320 if (!res || array_index > 0)
321 return GL_INVALID_INDEX;
322
323 return _mesa_program_resource_index(shProg, res);
324 case GL_ATOMIC_COUNTER_BUFFER:
325 case GL_TRANSFORM_FEEDBACK_BUFFER:
326 default:
327 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceIndex(%s)",
328 _mesa_enum_to_string(programInterface));
329 }
330
331 return GL_INVALID_INDEX;
332 }
333
334 void GLAPIENTRY
_mesa_GetProgramResourceName(GLuint program,GLenum programInterface,GLuint index,GLsizei bufSize,GLsizei * length,GLchar * name)335 _mesa_GetProgramResourceName(GLuint program, GLenum programInterface,
336 GLuint index, GLsizei bufSize, GLsizei *length,
337 GLchar *name)
338 {
339 GET_CURRENT_CONTEXT(ctx);
340
341 if (MESA_VERBOSE & VERBOSE_API) {
342 _mesa_debug(ctx, "glGetProgramResourceName(%u, %s, %u, %d, %p, %p)\n",
343 program, _mesa_enum_to_string(programInterface), index,
344 bufSize, length, name);
345 }
346
347 struct gl_shader_program *shProg =
348 _mesa_lookup_shader_program_err(ctx, program,
349 "glGetProgramResourceName");
350
351 if (!shProg || !name)
352 return;
353
354 if (programInterface == GL_ATOMIC_COUNTER_BUFFER ||
355 programInterface == GL_TRANSFORM_FEEDBACK_BUFFER ||
356 !supported_interface_enum(ctx, programInterface)) {
357 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceName(%s)",
358 _mesa_enum_to_string(programInterface));
359 return;
360 }
361
362 _mesa_get_program_resource_name(shProg, programInterface, index, bufSize,
363 length, name, "glGetProgramResourceName");
364 }
365
366 void GLAPIENTRY
_mesa_GetProgramResourceiv(GLuint program,GLenum programInterface,GLuint index,GLsizei propCount,const GLenum * props,GLsizei bufSize,GLsizei * length,GLint * params)367 _mesa_GetProgramResourceiv(GLuint program, GLenum programInterface,
368 GLuint index, GLsizei propCount,
369 const GLenum *props, GLsizei bufSize,
370 GLsizei *length, GLint *params)
371 {
372 GET_CURRENT_CONTEXT(ctx);
373
374 if (MESA_VERBOSE & VERBOSE_API) {
375 _mesa_debug(ctx, "glGetProgramResourceiv(%u, %s, %u, %d, %p, %d, %p, %p)\n",
376 program, _mesa_enum_to_string(programInterface), index,
377 propCount, props, bufSize, length, params);
378 }
379
380 struct gl_shader_program *shProg =
381 _mesa_lookup_shader_program_err(ctx, program, "glGetProgramResourceiv");
382
383 if (!shProg || !params)
384 return;
385
386 /* The error INVALID_VALUE is generated if <propCount> is zero.
387 * Note that we check < 0 here because it makes sense to bail early.
388 */
389 if (propCount <= 0) {
390 _mesa_error(ctx, GL_INVALID_VALUE,
391 "glGetProgramResourceiv(propCount <= 0)");
392 return;
393 }
394
395 _mesa_get_program_resourceiv(shProg, programInterface, index,
396 propCount, props, bufSize, length, params);
397 }
398
399 GLint GLAPIENTRY
_mesa_GetProgramResourceLocation(GLuint program,GLenum programInterface,const GLchar * name)400 _mesa_GetProgramResourceLocation(GLuint program, GLenum programInterface,
401 const GLchar *name)
402 {
403 GET_CURRENT_CONTEXT(ctx);
404
405 if (MESA_VERBOSE & VERBOSE_API) {
406 _mesa_debug(ctx, "glGetProgramResourceLocation(%u, %s, %s)\n",
407 program, _mesa_enum_to_string(programInterface), name);
408 }
409
410 struct gl_shader_program *shProg =
411 lookup_linked_program(program, "glGetProgramResourceLocation");
412
413 if (!shProg || !name)
414 return -1;
415
416 /* Validate programInterface. */
417 switch (programInterface) {
418 case GL_UNIFORM:
419 case GL_PROGRAM_INPUT:
420 case GL_PROGRAM_OUTPUT:
421 break;
422
423 case GL_VERTEX_SUBROUTINE_UNIFORM:
424 case GL_FRAGMENT_SUBROUTINE_UNIFORM:
425 if (!_mesa_has_ARB_shader_subroutine(ctx))
426 goto fail;
427 break;
428 case GL_GEOMETRY_SUBROUTINE_UNIFORM:
429 if (!_mesa_has_geometry_shaders(ctx) || !_mesa_has_ARB_shader_subroutine(ctx))
430 goto fail;
431 break;
432 case GL_COMPUTE_SUBROUTINE_UNIFORM:
433 if (!_mesa_has_compute_shaders(ctx) || !_mesa_has_ARB_shader_subroutine(ctx))
434 goto fail;
435 break;
436 case GL_TESS_CONTROL_SUBROUTINE_UNIFORM:
437 case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM:
438 if (!_mesa_has_tessellation(ctx) || !_mesa_has_ARB_shader_subroutine(ctx))
439 goto fail;
440 break;
441 default:
442 goto fail;
443 }
444
445 return _mesa_program_resource_location(shProg, programInterface, name);
446 fail:
447 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceLocation(%s %s)",
448 _mesa_enum_to_string(programInterface), name);
449 return -1;
450 }
451
452 /**
453 * Returns output index for dual source blending.
454 */
455 GLint GLAPIENTRY
_mesa_GetProgramResourceLocationIndex(GLuint program,GLenum programInterface,const GLchar * name)456 _mesa_GetProgramResourceLocationIndex(GLuint program, GLenum programInterface,
457 const GLchar *name)
458 {
459 GET_CURRENT_CONTEXT(ctx);
460
461 if (MESA_VERBOSE & VERBOSE_API) {
462 _mesa_debug(ctx, "glGetProgramResourceLocationIndex(%u, %s, %s)\n",
463 program, _mesa_enum_to_string(programInterface), name);
464 }
465
466 struct gl_shader_program *shProg =
467 lookup_linked_program(program, "glGetProgramResourceLocationIndex");
468
469 if (!shProg || !name)
470 return -1;
471
472 /* From the GL_ARB_program_interface_query spec:
473 *
474 * "For GetProgramResourceLocationIndex, <programInterface> must be
475 * PROGRAM_OUTPUT."
476 */
477 if (programInterface != GL_PROGRAM_OUTPUT) {
478 _mesa_error(ctx, GL_INVALID_ENUM,
479 "glGetProgramResourceLocationIndex(%s)",
480 _mesa_enum_to_string(programInterface));
481 return -1;
482 }
483
484 return _mesa_program_resource_location_index(shProg, GL_PROGRAM_OUTPUT,
485 name);
486 }
487