• 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 
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