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