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