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