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 "compiler/glsl/ir_uniform.h"
33#include "api_exec_decl.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   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   _mesa_get_program_interfaceiv(shProg, programInterface, pname, params);
120}
121
122static bool
123is_xfb_marker(const char *str)
124{
125   static const char *markers[] = {
126      "gl_NextBuffer",
127      "gl_SkipComponents1",
128      "gl_SkipComponents2",
129      "gl_SkipComponents3",
130      "gl_SkipComponents4",
131      NULL
132   };
133   const char **m = markers;
134
135   if (strncmp(str, "gl_", 3) != 0)
136      return false;
137
138   for (; *m; m++)
139      if (strcmp(*m, str) == 0)
140         return true;
141
142   return false;
143}
144
145GLuint GLAPIENTRY
146_mesa_GetProgramResourceIndex(GLuint program, GLenum programInterface,
147                              const GLchar *name)
148{
149   GET_CURRENT_CONTEXT(ctx);
150
151   if (MESA_VERBOSE & VERBOSE_API) {
152      _mesa_debug(ctx, "glGetProgramResourceIndex(%u, %s, %s)\n",
153                  program, _mesa_enum_to_string(programInterface), name);
154   }
155
156   unsigned array_index = 0;
157   struct gl_program_resource *res;
158   struct gl_shader_program *shProg =
159      _mesa_lookup_shader_program_err(ctx, program,
160                                      "glGetProgramResourceIndex");
161   if (!shProg || !name)
162      return GL_INVALID_INDEX;
163
164   if (!supported_interface_enum(ctx, programInterface)) {
165      _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceIndex(%s)",
166                  _mesa_enum_to_string(programInterface));
167      return GL_INVALID_INDEX;
168   }
169   /*
170    * For the interface TRANSFORM_FEEDBACK_VARYING, the value INVALID_INDEX
171    * should be returned when querying the index assigned to the special names
172    * "gl_NextBuffer", "gl_SkipComponents1", "gl_SkipComponents2",
173    * "gl_SkipComponents3", and "gl_SkipComponents4".
174    */
175   if (programInterface == GL_TRANSFORM_FEEDBACK_VARYING &&
176       is_xfb_marker(name))
177      return GL_INVALID_INDEX;
178
179   switch (programInterface) {
180   case GL_TESS_CONTROL_SUBROUTINE:
181   case GL_TESS_CONTROL_SUBROUTINE_UNIFORM:
182   case GL_TESS_EVALUATION_SUBROUTINE:
183   case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM:
184   case GL_COMPUTE_SUBROUTINE:
185   case GL_COMPUTE_SUBROUTINE_UNIFORM:
186   case GL_GEOMETRY_SUBROUTINE:
187   case GL_GEOMETRY_SUBROUTINE_UNIFORM:
188   case GL_VERTEX_SUBROUTINE:
189   case GL_FRAGMENT_SUBROUTINE:
190   case GL_VERTEX_SUBROUTINE_UNIFORM:
191   case GL_FRAGMENT_SUBROUTINE_UNIFORM:
192   case GL_PROGRAM_INPUT:
193   case GL_PROGRAM_OUTPUT:
194   case GL_UNIFORM:
195   case GL_BUFFER_VARIABLE:
196   case GL_TRANSFORM_FEEDBACK_VARYING:
197   case GL_UNIFORM_BLOCK:
198   case GL_SHADER_STORAGE_BLOCK:
199      res = _mesa_program_resource_find_name(shProg, programInterface, name,
200                                             &array_index);
201      if (!res || array_index > 0)
202         return GL_INVALID_INDEX;
203
204      return _mesa_program_resource_index(shProg, res);
205   case GL_ATOMIC_COUNTER_BUFFER:
206   case GL_TRANSFORM_FEEDBACK_BUFFER:
207   default:
208      _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceIndex(%s)",
209                  _mesa_enum_to_string(programInterface));
210   }
211
212   return GL_INVALID_INDEX;
213}
214
215void GLAPIENTRY
216_mesa_GetProgramResourceName(GLuint program, GLenum programInterface,
217                             GLuint index, GLsizei bufSize, GLsizei *length,
218                             GLchar *name)
219{
220   GET_CURRENT_CONTEXT(ctx);
221
222   if (MESA_VERBOSE & VERBOSE_API) {
223      _mesa_debug(ctx, "glGetProgramResourceName(%u, %s, %u, %d, %p, %p)\n",
224                  program, _mesa_enum_to_string(programInterface), index,
225                  bufSize, length, name);
226   }
227
228   struct gl_shader_program *shProg =
229      _mesa_lookup_shader_program_err(ctx, program,
230                                      "glGetProgramResourceName");
231
232   if (!shProg || !name)
233      return;
234
235   if (programInterface == GL_ATOMIC_COUNTER_BUFFER ||
236       programInterface == GL_TRANSFORM_FEEDBACK_BUFFER ||
237       !supported_interface_enum(ctx, programInterface)) {
238      _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceName(%s)",
239                  _mesa_enum_to_string(programInterface));
240      return;
241   }
242
243   _mesa_get_program_resource_name(shProg, programInterface, index, bufSize,
244                                   length, name, false,
245                                   "glGetProgramResourceName");
246}
247
248void GLAPIENTRY
249_mesa_GetProgramResourceiv(GLuint program, GLenum programInterface,
250                           GLuint index, GLsizei propCount,
251                           const GLenum *props, GLsizei bufSize,
252                           GLsizei *length, GLint *params)
253{
254   GET_CURRENT_CONTEXT(ctx);
255
256   if (MESA_VERBOSE & VERBOSE_API) {
257      _mesa_debug(ctx, "glGetProgramResourceiv(%u, %s, %u, %d, %p, %d, %p, %p)\n",
258                  program, _mesa_enum_to_string(programInterface), index,
259                  propCount, props, bufSize, length, params);
260   }
261
262   struct gl_shader_program *shProg =
263      _mesa_lookup_shader_program_err(ctx, program, "glGetProgramResourceiv");
264
265   if (!shProg || !params)
266      return;
267
268   /* The error INVALID_VALUE is generated if <propCount> is zero.
269    * Note that we check < 0 here because it makes sense to bail early.
270    */
271   if (propCount <= 0) {
272      _mesa_error(ctx, GL_INVALID_VALUE,
273                  "glGetProgramResourceiv(propCount <= 0)");
274      return;
275   }
276
277   _mesa_get_program_resourceiv(shProg, programInterface, index,
278                                propCount, props, bufSize, length, params);
279}
280
281GLint GLAPIENTRY
282_mesa_GetProgramResourceLocation(GLuint program, GLenum programInterface,
283                                 const GLchar *name)
284{
285   GET_CURRENT_CONTEXT(ctx);
286
287   if (MESA_VERBOSE & VERBOSE_API) {
288      _mesa_debug(ctx, "glGetProgramResourceLocation(%u, %s, %s)\n",
289                  program, _mesa_enum_to_string(programInterface), name);
290   }
291
292   struct gl_shader_program *shProg =
293      lookup_linked_program(program, "glGetProgramResourceLocation");
294
295   if (!shProg || !name)
296      return -1;
297
298   /* Validate programInterface. */
299   switch (programInterface) {
300   case GL_UNIFORM:
301   case GL_PROGRAM_INPUT:
302   case GL_PROGRAM_OUTPUT:
303      break;
304
305   case GL_VERTEX_SUBROUTINE_UNIFORM:
306   case GL_FRAGMENT_SUBROUTINE_UNIFORM:
307      if (!_mesa_has_ARB_shader_subroutine(ctx))
308         goto fail;
309      break;
310   case GL_GEOMETRY_SUBROUTINE_UNIFORM:
311      if (!_mesa_has_geometry_shaders(ctx) || !_mesa_has_ARB_shader_subroutine(ctx))
312         goto fail;
313      break;
314   case GL_COMPUTE_SUBROUTINE_UNIFORM:
315      if (!_mesa_has_compute_shaders(ctx) || !_mesa_has_ARB_shader_subroutine(ctx))
316         goto fail;
317      break;
318   case GL_TESS_CONTROL_SUBROUTINE_UNIFORM:
319   case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM:
320      if (!_mesa_has_tessellation(ctx) || !_mesa_has_ARB_shader_subroutine(ctx))
321         goto fail;
322      break;
323   default:
324         goto fail;
325   }
326
327   return _mesa_program_resource_location(shProg, programInterface, name);
328fail:
329   _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceLocation(%s %s)",
330               _mesa_enum_to_string(programInterface), name);
331   return -1;
332}
333
334/**
335 * Returns output index for dual source blending.
336 */
337GLint GLAPIENTRY
338_mesa_GetProgramResourceLocationIndex(GLuint program, GLenum programInterface,
339                                      const GLchar *name)
340{
341   GET_CURRENT_CONTEXT(ctx);
342
343   if (MESA_VERBOSE & VERBOSE_API) {
344      _mesa_debug(ctx, "glGetProgramResourceLocationIndex(%u, %s, %s)\n",
345                  program, _mesa_enum_to_string(programInterface), name);
346   }
347
348   struct gl_shader_program *shProg =
349      lookup_linked_program(program, "glGetProgramResourceLocationIndex");
350
351   if (!shProg || !name)
352      return -1;
353
354   /* From the GL_ARB_program_interface_query spec:
355    *
356    * "For GetProgramResourceLocationIndex, <programInterface> must be
357    * PROGRAM_OUTPUT."
358    */
359   if (programInterface != GL_PROGRAM_OUTPUT) {
360      _mesa_error(ctx, GL_INVALID_ENUM,
361                  "glGetProgramResourceLocationIndex(%s)",
362                  _mesa_enum_to_string(programInterface));
363      return -1;
364   }
365
366   return _mesa_program_resource_location_index(shProg, GL_PROGRAM_OUTPUT,
367                                                name);
368}
369