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    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 
122 static bool
is_xfb_marker(const char * str)123 is_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 
145 GLuint GLAPIENTRY
_mesa_GetProgramResourceIndex(GLuint program,GLenum programInterface,const GLchar * name)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 
215 void GLAPIENTRY
_mesa_GetProgramResourceName(GLuint program,GLenum programInterface,GLuint index,GLsizei bufSize,GLsizei * length,GLchar * name)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 
248 void GLAPIENTRY
_mesa_GetProgramResourceiv(GLuint program,GLenum programInterface,GLuint index,GLsizei propCount,const GLenum * props,GLsizei bufSize,GLsizei * length,GLint * params)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 
281 GLint GLAPIENTRY
_mesa_GetProgramResourceLocation(GLuint program,GLenum programInterface,const GLchar * name)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);
328 fail:
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  */
337 GLint GLAPIENTRY
_mesa_GetProgramResourceLocationIndex(GLuint program,GLenum programInterface,const GLchar * name)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