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