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 static bool
supported_interface_enum(struct gl_context * ctx,GLenum iface)35 supported_interface_enum(struct gl_context *ctx, GLenum iface)
36 {
37 switch (iface) {
38 case GL_UNIFORM:
39 case GL_UNIFORM_BLOCK:
40 case GL_PROGRAM_INPUT:
41 case GL_PROGRAM_OUTPUT:
42 case GL_TRANSFORM_FEEDBACK_BUFFER:
43 case GL_TRANSFORM_FEEDBACK_VARYING:
44 case GL_ATOMIC_COUNTER_BUFFER:
45 case GL_BUFFER_VARIABLE:
46 case GL_SHADER_STORAGE_BLOCK:
47 return true;
48 case GL_VERTEX_SUBROUTINE:
49 case GL_FRAGMENT_SUBROUTINE:
50 case GL_VERTEX_SUBROUTINE_UNIFORM:
51 case GL_FRAGMENT_SUBROUTINE_UNIFORM:
52 return _mesa_has_ARB_shader_subroutine(ctx);
53 case GL_GEOMETRY_SUBROUTINE:
54 case GL_GEOMETRY_SUBROUTINE_UNIFORM:
55 return _mesa_has_geometry_shaders(ctx) && _mesa_has_ARB_shader_subroutine(ctx);
56 case GL_COMPUTE_SUBROUTINE:
57 case GL_COMPUTE_SUBROUTINE_UNIFORM:
58 return _mesa_has_compute_shaders(ctx) && _mesa_has_ARB_shader_subroutine(ctx);
59 case GL_TESS_CONTROL_SUBROUTINE:
60 case GL_TESS_EVALUATION_SUBROUTINE:
61 case GL_TESS_CONTROL_SUBROUTINE_UNIFORM:
62 case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM:
63 return _mesa_has_tessellation(ctx) && _mesa_has_ARB_shader_subroutine(ctx);
64 default:
65 return false;
66 }
67 }
68
69 static struct gl_shader_program *
lookup_linked_program(GLuint program,const char * caller)70 lookup_linked_program(GLuint program, const char *caller)
71 {
72 GET_CURRENT_CONTEXT(ctx);
73 struct gl_shader_program *prog =
74 _mesa_lookup_shader_program_err(ctx, program, caller);
75
76 if (!prog)
77 return NULL;
78
79 if (prog->data->LinkStatus == GL_FALSE) {
80 _mesa_error(ctx, GL_INVALID_OPERATION, "%s(program not linked)",
81 caller);
82 return NULL;
83 }
84 return prog;
85 }
86
87 void GLAPIENTRY
_mesa_GetProgramInterfaceiv(GLuint program,GLenum programInterface,GLenum pname,GLint * params)88 _mesa_GetProgramInterfaceiv(GLuint program, GLenum programInterface,
89 GLenum pname, GLint *params)
90 {
91 GET_CURRENT_CONTEXT(ctx);
92
93 if (MESA_VERBOSE & VERBOSE_API) {
94 _mesa_debug(ctx, "glGetProgramInterfaceiv(%u, %s, %s, %p)\n",
95 program, _mesa_enum_to_string(programInterface),
96 _mesa_enum_to_string(pname), params);
97 }
98
99 unsigned i;
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 /* Validate pname against interface. */
120 switch(pname) {
121 case GL_ACTIVE_RESOURCES:
122 for (i = 0, *params = 0; i < shProg->NumProgramResourceList; i++)
123 if (shProg->ProgramResourceList[i].Type == programInterface)
124 (*params)++;
125 break;
126 case GL_MAX_NAME_LENGTH:
127 if (programInterface == GL_ATOMIC_COUNTER_BUFFER ||
128 programInterface == GL_TRANSFORM_FEEDBACK_BUFFER) {
129 _mesa_error(ctx, GL_INVALID_OPERATION,
130 "glGetProgramInterfaceiv(%s pname %s)",
131 _mesa_enum_to_string(programInterface),
132 _mesa_enum_to_string(pname));
133 return;
134 }
135 /* Name length consists of base name, 3 additional chars '[0]' if
136 * resource is an array and finally 1 char for string terminator.
137 */
138 for (i = 0, *params = 0; i < shProg->NumProgramResourceList; i++) {
139 if (shProg->ProgramResourceList[i].Type != programInterface)
140 continue;
141 unsigned len =
142 _mesa_program_resource_name_len(&shProg->ProgramResourceList[i]);
143 *params = MAX2(*params, len + 1);
144 }
145 break;
146 case GL_MAX_NUM_ACTIVE_VARIABLES:
147 switch (programInterface) {
148 case GL_UNIFORM_BLOCK:
149 for (i = 0, *params = 0; i < shProg->NumProgramResourceList; i++) {
150 if (shProg->ProgramResourceList[i].Type == programInterface) {
151 struct gl_uniform_block *block =
152 (struct gl_uniform_block *)
153 shProg->ProgramResourceList[i].Data;
154 *params = MAX2(*params, block->NumUniforms);
155 }
156 }
157 break;
158 case GL_SHADER_STORAGE_BLOCK:
159 for (i = 0, *params = 0; i < shProg->NumProgramResourceList; i++) {
160 if (shProg->ProgramResourceList[i].Type == programInterface) {
161 struct gl_uniform_block *block =
162 (struct gl_uniform_block *)
163 shProg->ProgramResourceList[i].Data;
164 GLint block_params = 0;
165 for (unsigned j = 0; j < block->NumUniforms; j++) {
166 const char *iname = block->Uniforms[j].IndexName;
167 struct gl_program_resource *uni =
168 _mesa_program_resource_find_name(shProg, GL_BUFFER_VARIABLE,
169 iname, NULL);
170 if (!uni)
171 continue;
172 block_params++;
173 }
174 *params = MAX2(*params, block_params);
175 }
176 }
177 break;
178 case GL_ATOMIC_COUNTER_BUFFER:
179 for (i = 0, *params = 0; i < shProg->NumProgramResourceList; i++) {
180 if (shProg->ProgramResourceList[i].Type == programInterface) {
181 struct gl_active_atomic_buffer *buffer =
182 (struct gl_active_atomic_buffer *)
183 shProg->ProgramResourceList[i].Data;
184 *params = MAX2(*params, buffer->NumUniforms);
185 }
186 }
187 break;
188 case GL_TRANSFORM_FEEDBACK_BUFFER:
189 for (i = 0, *params = 0; i < shProg->NumProgramResourceList; i++) {
190 if (shProg->ProgramResourceList[i].Type == programInterface) {
191 struct gl_transform_feedback_buffer *buffer =
192 (struct gl_transform_feedback_buffer *)
193 shProg->ProgramResourceList[i].Data;
194 *params = MAX2(*params, buffer->NumVaryings);
195 }
196 }
197 break;
198 default:
199 _mesa_error(ctx, GL_INVALID_OPERATION,
200 "glGetProgramInterfaceiv(%s pname %s)",
201 _mesa_enum_to_string(programInterface),
202 _mesa_enum_to_string(pname));
203 };
204 break;
205 case GL_MAX_NUM_COMPATIBLE_SUBROUTINES:
206 switch (programInterface) {
207 case GL_VERTEX_SUBROUTINE_UNIFORM:
208 case GL_FRAGMENT_SUBROUTINE_UNIFORM:
209 case GL_GEOMETRY_SUBROUTINE_UNIFORM:
210 case GL_COMPUTE_SUBROUTINE_UNIFORM:
211 case GL_TESS_CONTROL_SUBROUTINE_UNIFORM:
212 case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM: {
213 for (i = 0, *params = 0; i < shProg->NumProgramResourceList; i++) {
214 if (shProg->ProgramResourceList[i].Type == programInterface) {
215 struct gl_uniform_storage *uni =
216 (struct gl_uniform_storage *)
217 shProg->ProgramResourceList[i].Data;
218 *params = MAX2(*params, uni->num_compatible_subroutines);
219 }
220 }
221 break;
222 }
223
224 default:
225 _mesa_error(ctx, GL_INVALID_OPERATION,
226 "glGetProgramInterfaceiv(%s pname %s)",
227 _mesa_enum_to_string(programInterface),
228 _mesa_enum_to_string(pname));
229 }
230 break;
231 default:
232 _mesa_error(ctx, GL_INVALID_OPERATION,
233 "glGetProgramInterfaceiv(pname %s)",
234 _mesa_enum_to_string(pname));
235 }
236 }
237
238 static bool
is_xfb_marker(const char * str)239 is_xfb_marker(const char *str)
240 {
241 static const char *markers[] = {
242 "gl_NextBuffer",
243 "gl_SkipComponents1",
244 "gl_SkipComponents2",
245 "gl_SkipComponents3",
246 "gl_SkipComponents4",
247 NULL
248 };
249 const char **m = markers;
250
251 if (strncmp(str, "gl_", 3) != 0)
252 return false;
253
254 for (; *m; m++)
255 if (strcmp(*m, str) == 0)
256 return true;
257
258 return false;
259 }
260
261 GLuint GLAPIENTRY
_mesa_GetProgramResourceIndex(GLuint program,GLenum programInterface,const GLchar * name)262 _mesa_GetProgramResourceIndex(GLuint program, GLenum programInterface,
263 const GLchar *name)
264 {
265 GET_CURRENT_CONTEXT(ctx);
266
267 if (MESA_VERBOSE & VERBOSE_API) {
268 _mesa_debug(ctx, "glGetProgramResourceIndex(%u, %s, %s)\n",
269 program, _mesa_enum_to_string(programInterface), name);
270 }
271
272 unsigned array_index = 0;
273 struct gl_program_resource *res;
274 struct gl_shader_program *shProg =
275 _mesa_lookup_shader_program_err(ctx, program,
276 "glGetProgramResourceIndex");
277 if (!shProg || !name)
278 return GL_INVALID_INDEX;
279
280 if (!supported_interface_enum(ctx, programInterface)) {
281 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceIndex(%s)",
282 _mesa_enum_to_string(programInterface));
283 return GL_INVALID_INDEX;
284 }
285 /*
286 * For the interface TRANSFORM_FEEDBACK_VARYING, the value INVALID_INDEX
287 * should be returned when querying the index assigned to the special names
288 * "gl_NextBuffer", "gl_SkipComponents1", "gl_SkipComponents2",
289 * "gl_SkipComponents3", and "gl_SkipComponents4".
290 */
291 if (programInterface == GL_TRANSFORM_FEEDBACK_VARYING &&
292 is_xfb_marker(name))
293 return GL_INVALID_INDEX;
294
295 switch (programInterface) {
296 case GL_TESS_CONTROL_SUBROUTINE:
297 case GL_TESS_CONTROL_SUBROUTINE_UNIFORM:
298 case GL_TESS_EVALUATION_SUBROUTINE:
299 case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM:
300 case GL_COMPUTE_SUBROUTINE:
301 case GL_COMPUTE_SUBROUTINE_UNIFORM:
302 case GL_GEOMETRY_SUBROUTINE:
303 case GL_GEOMETRY_SUBROUTINE_UNIFORM:
304 case GL_VERTEX_SUBROUTINE:
305 case GL_FRAGMENT_SUBROUTINE:
306 case GL_VERTEX_SUBROUTINE_UNIFORM:
307 case GL_FRAGMENT_SUBROUTINE_UNIFORM:
308 case GL_PROGRAM_INPUT:
309 case GL_PROGRAM_OUTPUT:
310 case GL_UNIFORM:
311 case GL_BUFFER_VARIABLE:
312 case GL_TRANSFORM_FEEDBACK_VARYING:
313 case GL_UNIFORM_BLOCK:
314 case GL_SHADER_STORAGE_BLOCK:
315 res = _mesa_program_resource_find_name(shProg, programInterface, name,
316 &array_index);
317 if (!res || array_index > 0)
318 return GL_INVALID_INDEX;
319
320 return _mesa_program_resource_index(shProg, res);
321 case GL_ATOMIC_COUNTER_BUFFER:
322 case GL_TRANSFORM_FEEDBACK_BUFFER:
323 default:
324 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceIndex(%s)",
325 _mesa_enum_to_string(programInterface));
326 }
327
328 return GL_INVALID_INDEX;
329 }
330
331 void GLAPIENTRY
_mesa_GetProgramResourceName(GLuint program,GLenum programInterface,GLuint index,GLsizei bufSize,GLsizei * length,GLchar * name)332 _mesa_GetProgramResourceName(GLuint program, GLenum programInterface,
333 GLuint index, GLsizei bufSize, GLsizei *length,
334 GLchar *name)
335 {
336 GET_CURRENT_CONTEXT(ctx);
337
338 if (MESA_VERBOSE & VERBOSE_API) {
339 _mesa_debug(ctx, "glGetProgramResourceName(%u, %s, %u, %d, %p, %p)\n",
340 program, _mesa_enum_to_string(programInterface), index,
341 bufSize, length, name);
342 }
343
344 struct gl_shader_program *shProg =
345 _mesa_lookup_shader_program_err(ctx, program,
346 "glGetProgramResourceName");
347
348 if (!shProg || !name)
349 return;
350
351 if (programInterface == GL_ATOMIC_COUNTER_BUFFER ||
352 programInterface == GL_TRANSFORM_FEEDBACK_BUFFER ||
353 !supported_interface_enum(ctx, programInterface)) {
354 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceName(%s)",
355 _mesa_enum_to_string(programInterface));
356 return;
357 }
358
359 _mesa_get_program_resource_name(shProg, programInterface, index, bufSize,
360 length, name, "glGetProgramResourceName");
361 }
362
363 void GLAPIENTRY
_mesa_GetProgramResourceiv(GLuint program,GLenum programInterface,GLuint index,GLsizei propCount,const GLenum * props,GLsizei bufSize,GLsizei * length,GLint * params)364 _mesa_GetProgramResourceiv(GLuint program, GLenum programInterface,
365 GLuint index, GLsizei propCount,
366 const GLenum *props, GLsizei bufSize,
367 GLsizei *length, GLint *params)
368 {
369 GET_CURRENT_CONTEXT(ctx);
370
371 if (MESA_VERBOSE & VERBOSE_API) {
372 _mesa_debug(ctx, "glGetProgramResourceiv(%u, %s, %u, %d, %p, %d, %p, %p)\n",
373 program, _mesa_enum_to_string(programInterface), index,
374 propCount, props, bufSize, length, params);
375 }
376
377 struct gl_shader_program *shProg =
378 _mesa_lookup_shader_program_err(ctx, program, "glGetProgramResourceiv");
379
380 if (!shProg || !params)
381 return;
382
383 /* The error INVALID_VALUE is generated if <propCount> is zero.
384 * Note that we check < 0 here because it makes sense to bail early.
385 */
386 if (propCount <= 0) {
387 _mesa_error(ctx, GL_INVALID_VALUE,
388 "glGetProgramResourceiv(propCount <= 0)");
389 return;
390 }
391
392 _mesa_get_program_resourceiv(shProg, programInterface, index,
393 propCount, props, bufSize, length, params);
394 }
395
396 GLint GLAPIENTRY
_mesa_GetProgramResourceLocation(GLuint program,GLenum programInterface,const GLchar * name)397 _mesa_GetProgramResourceLocation(GLuint program, GLenum programInterface,
398 const GLchar *name)
399 {
400 GET_CURRENT_CONTEXT(ctx);
401
402 if (MESA_VERBOSE & VERBOSE_API) {
403 _mesa_debug(ctx, "glGetProgramResourceLocation(%u, %s, %s)\n",
404 program, _mesa_enum_to_string(programInterface), name);
405 }
406
407 struct gl_shader_program *shProg =
408 lookup_linked_program(program, "glGetProgramResourceLocation");
409
410 if (!shProg || !name)
411 return -1;
412
413 /* Validate programInterface. */
414 switch (programInterface) {
415 case GL_UNIFORM:
416 case GL_PROGRAM_INPUT:
417 case GL_PROGRAM_OUTPUT:
418 break;
419
420 case GL_VERTEX_SUBROUTINE_UNIFORM:
421 case GL_FRAGMENT_SUBROUTINE_UNIFORM:
422 if (!_mesa_has_ARB_shader_subroutine(ctx))
423 goto fail;
424 break;
425 case GL_GEOMETRY_SUBROUTINE_UNIFORM:
426 if (!_mesa_has_geometry_shaders(ctx) || !_mesa_has_ARB_shader_subroutine(ctx))
427 goto fail;
428 break;
429 case GL_COMPUTE_SUBROUTINE_UNIFORM:
430 if (!_mesa_has_compute_shaders(ctx) || !_mesa_has_ARB_shader_subroutine(ctx))
431 goto fail;
432 break;
433 case GL_TESS_CONTROL_SUBROUTINE_UNIFORM:
434 case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM:
435 if (!_mesa_has_tessellation(ctx) || !_mesa_has_ARB_shader_subroutine(ctx))
436 goto fail;
437 break;
438 default:
439 goto fail;
440 }
441
442 return _mesa_program_resource_location(shProg, programInterface, name);
443 fail:
444 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceLocation(%s %s)",
445 _mesa_enum_to_string(programInterface), name);
446 return -1;
447 }
448
449 /**
450 * Returns output index for dual source blending.
451 */
452 GLint GLAPIENTRY
_mesa_GetProgramResourceLocationIndex(GLuint program,GLenum programInterface,const GLchar * name)453 _mesa_GetProgramResourceLocationIndex(GLuint program, GLenum programInterface,
454 const GLchar *name)
455 {
456 GET_CURRENT_CONTEXT(ctx);
457
458 if (MESA_VERBOSE & VERBOSE_API) {
459 _mesa_debug(ctx, "glGetProgramResourceLocationIndex(%u, %s, %s)\n",
460 program, _mesa_enum_to_string(programInterface), name);
461 }
462
463 struct gl_shader_program *shProg =
464 lookup_linked_program(program, "glGetProgramResourceLocationIndex");
465
466 if (!shProg || !name)
467 return -1;
468
469 /* From the GL_ARB_program_interface_query spec:
470 *
471 * "For GetProgramResourceLocationIndex, <programInterface> must be
472 * PROGRAM_OUTPUT."
473 */
474 if (programInterface != GL_PROGRAM_OUTPUT) {
475 _mesa_error(ctx, GL_INVALID_ENUM,
476 "glGetProgramResourceLocationIndex(%s)",
477 _mesa_enum_to_string(programInterface));
478 return -1;
479 }
480
481 return _mesa_program_resource_location_index(shProg, GL_PROGRAM_OUTPUT,
482 name);
483 }
484