• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 == linking_failure) {
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->data->NumProgramResourceList; i++)
123          if (shProg->data->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->data->NumProgramResourceList; i++) {
139          if (shProg->data->ProgramResourceList[i].Type != programInterface)
140             continue;
141          unsigned len =
142             _mesa_program_resource_name_len(&shProg->data->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->data->NumProgramResourceList; i++) {
150             if (shProg->data->ProgramResourceList[i].Type == programInterface) {
151                struct gl_uniform_block *block =
152                   (struct gl_uniform_block *)
153                   shProg->data->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->data->NumProgramResourceList; i++) {
160             if (shProg->data->ProgramResourceList[i].Type == programInterface) {
161                struct gl_uniform_block *block =
162                   (struct gl_uniform_block *)
163                   shProg->data->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->data->NumProgramResourceList; i++) {
180             if (shProg->data->ProgramResourceList[i].Type == programInterface) {
181                struct gl_active_atomic_buffer *buffer =
182                   (struct gl_active_atomic_buffer *)
183                   shProg->data->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->data->NumProgramResourceList; i++) {
190             if (shProg->data->ProgramResourceList[i].Type == programInterface) {
191                struct gl_transform_feedback_buffer *buffer =
192                   (struct gl_transform_feedback_buffer *)
193                   shProg->data->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->data->NumProgramResourceList; i++) {
214             if (shProg->data->ProgramResourceList[i].Type == programInterface) {
215                struct gl_uniform_storage *uni =
216                   (struct gl_uniform_storage *)
217                   shProg->data->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