glsl: move to compiler/
[mesa.git] / src / mesa / main / program_resource.c
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 static bool
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_VARYING:
43 case GL_ATOMIC_COUNTER_BUFFER:
44 case GL_BUFFER_VARIABLE:
45 case GL_SHADER_STORAGE_BLOCK:
46 return true;
47 case GL_VERTEX_SUBROUTINE:
48 case GL_FRAGMENT_SUBROUTINE:
49 case GL_VERTEX_SUBROUTINE_UNIFORM:
50 case GL_FRAGMENT_SUBROUTINE_UNIFORM:
51 return _mesa_has_shader_subroutine(ctx);
52 case GL_GEOMETRY_SUBROUTINE:
53 case GL_GEOMETRY_SUBROUTINE_UNIFORM:
54 return _mesa_has_geometry_shaders(ctx) && _mesa_has_shader_subroutine(ctx);
55 case GL_COMPUTE_SUBROUTINE:
56 case GL_COMPUTE_SUBROUTINE_UNIFORM:
57 return _mesa_has_compute_shaders(ctx) && _mesa_has_shader_subroutine(ctx);
58 case GL_TESS_CONTROL_SUBROUTINE:
59 case GL_TESS_EVALUATION_SUBROUTINE:
60 case GL_TESS_CONTROL_SUBROUTINE_UNIFORM:
61 case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM:
62 return _mesa_has_tessellation(ctx) && _mesa_has_shader_subroutine(ctx);
63 default:
64 return false;
65 }
66 }
67
68 void GLAPIENTRY
69 _mesa_GetProgramInterfaceiv(GLuint program, GLenum programInterface,
70 GLenum pname, GLint *params)
71 {
72 GET_CURRENT_CONTEXT(ctx);
73
74 if (MESA_VERBOSE & VERBOSE_API) {
75 _mesa_debug(ctx, "glGetProgramInterfaceiv(%u, %s, %s, %p)\n",
76 program, _mesa_enum_to_string(programInterface),
77 _mesa_enum_to_string(pname), params);
78 }
79
80 unsigned i;
81 struct gl_shader_program *shProg =
82 _mesa_lookup_shader_program_err(ctx, program,
83 "glGetProgramInterfaceiv");
84 if (!shProg)
85 return;
86
87 if (!params) {
88 _mesa_error(ctx, GL_INVALID_OPERATION,
89 "glGetProgramInterfaceiv(params NULL)");
90 return;
91 }
92
93 /* Validate interface. */
94 if (!supported_interface_enum(ctx, programInterface)) {
95 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramInterfaceiv(%s)",
96 _mesa_enum_to_string(programInterface));
97 return;
98 }
99
100 /* Validate pname against interface. */
101 switch(pname) {
102 case GL_ACTIVE_RESOURCES:
103 for (i = 0, *params = 0; i < shProg->NumProgramResourceList; i++)
104 if (shProg->ProgramResourceList[i].Type == programInterface)
105 (*params)++;
106 break;
107 case GL_MAX_NAME_LENGTH:
108 if (programInterface == GL_ATOMIC_COUNTER_BUFFER) {
109 _mesa_error(ctx, GL_INVALID_OPERATION,
110 "glGetProgramInterfaceiv(%s pname %s)",
111 _mesa_enum_to_string(programInterface),
112 _mesa_enum_to_string(pname));
113 return;
114 }
115 /* Name length consists of base name, 3 additional chars '[0]' if
116 * resource is an array and finally 1 char for string terminator.
117 */
118 for (i = 0, *params = 0; i < shProg->NumProgramResourceList; i++) {
119 if (shProg->ProgramResourceList[i].Type != programInterface)
120 continue;
121 unsigned len =
122 _mesa_program_resource_name_len(&shProg->ProgramResourceList[i]);
123 *params = MAX2(*params, len + 1);
124 }
125 break;
126 case GL_MAX_NUM_ACTIVE_VARIABLES:
127 switch (programInterface) {
128 case GL_UNIFORM_BLOCK:
129 for (i = 0, *params = 0; i < shProg->NumProgramResourceList; i++) {
130 if (shProg->ProgramResourceList[i].Type == programInterface) {
131 struct gl_uniform_block *block =
132 (struct gl_uniform_block *)
133 shProg->ProgramResourceList[i].Data;
134 *params = MAX2(*params, block->NumUniforms);
135 }
136 }
137 break;
138 case GL_SHADER_STORAGE_BLOCK:
139 for (i = 0, *params = 0; i < shProg->NumProgramResourceList; i++) {
140 if (shProg->ProgramResourceList[i].Type == programInterface) {
141 struct gl_uniform_block *block =
142 (struct gl_uniform_block *)
143 shProg->ProgramResourceList[i].Data;
144 GLint block_params = 0;
145 for (unsigned j = 0; j < block->NumUniforms; j++) {
146 const char *iname = block->Uniforms[j].IndexName;
147 struct gl_program_resource *uni =
148 _mesa_program_resource_find_name(shProg, GL_BUFFER_VARIABLE,
149 iname, NULL);
150 if (!uni)
151 continue;
152 block_params++;
153 }
154 *params = MAX2(*params, block_params);
155 }
156 }
157 break;
158 case GL_ATOMIC_COUNTER_BUFFER:
159 for (i = 0, *params = 0; i < shProg->NumProgramResourceList; i++) {
160 if (shProg->ProgramResourceList[i].Type == programInterface) {
161 struct gl_active_atomic_buffer *buffer =
162 (struct gl_active_atomic_buffer *)
163 shProg->ProgramResourceList[i].Data;
164 *params = MAX2(*params, buffer->NumUniforms);
165 }
166 }
167 break;
168 default:
169 _mesa_error(ctx, GL_INVALID_OPERATION,
170 "glGetProgramInterfaceiv(%s pname %s)",
171 _mesa_enum_to_string(programInterface),
172 _mesa_enum_to_string(pname));
173 };
174 break;
175 case GL_MAX_NUM_COMPATIBLE_SUBROUTINES:
176 switch (programInterface) {
177 case GL_VERTEX_SUBROUTINE_UNIFORM:
178 case GL_FRAGMENT_SUBROUTINE_UNIFORM:
179 case GL_GEOMETRY_SUBROUTINE_UNIFORM:
180 case GL_COMPUTE_SUBROUTINE_UNIFORM:
181 case GL_TESS_CONTROL_SUBROUTINE_UNIFORM:
182 case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM: {
183 for (i = 0, *params = 0; i < shProg->NumProgramResourceList; i++) {
184 if (shProg->ProgramResourceList[i].Type == programInterface) {
185 struct gl_uniform_storage *uni =
186 (struct gl_uniform_storage *)
187 shProg->ProgramResourceList[i].Data;
188 *params = MAX2(*params, uni->num_compatible_subroutines);
189 }
190 }
191 break;
192 }
193
194 default:
195 _mesa_error(ctx, GL_INVALID_OPERATION,
196 "glGetProgramInterfaceiv(%s pname %s)",
197 _mesa_enum_to_string(programInterface),
198 _mesa_enum_to_string(pname));
199 }
200 break;
201 default:
202 _mesa_error(ctx, GL_INVALID_OPERATION,
203 "glGetProgramInterfaceiv(pname %s)",
204 _mesa_enum_to_string(pname));
205 }
206 }
207
208 static bool
209 is_xfb_marker(const char *str)
210 {
211 static const char *markers[] = {
212 "gl_NextBuffer",
213 "gl_SkipComponents1",
214 "gl_SkipComponents2",
215 "gl_SkipComponents3",
216 "gl_SkipComponents4",
217 NULL
218 };
219 const char **m = markers;
220
221 if (strncmp(str, "gl_", 3) != 0)
222 return false;
223
224 for (; *m; m++)
225 if (strcmp(*m, str) == 0)
226 return true;
227
228 return false;
229 }
230
231 GLuint GLAPIENTRY
232 _mesa_GetProgramResourceIndex(GLuint program, GLenum programInterface,
233 const GLchar *name)
234 {
235 GET_CURRENT_CONTEXT(ctx);
236
237 if (MESA_VERBOSE & VERBOSE_API) {
238 _mesa_debug(ctx, "glGetProgramResourceIndex(%u, %s, %s)\n",
239 program, _mesa_enum_to_string(programInterface), name);
240 }
241
242 unsigned array_index = 0;
243 struct gl_program_resource *res;
244 struct gl_shader_program *shProg =
245 _mesa_lookup_shader_program_err(ctx, program,
246 "glGetProgramResourceIndex");
247 if (!shProg || !name)
248 return GL_INVALID_INDEX;
249
250 if (!supported_interface_enum(ctx, programInterface)) {
251 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceIndex(%s)",
252 _mesa_enum_to_string(programInterface));
253 return GL_INVALID_INDEX;
254 }
255 /*
256 * For the interface TRANSFORM_FEEDBACK_VARYING, the value INVALID_INDEX
257 * should be returned when querying the index assigned to the special names
258 * "gl_NextBuffer", "gl_SkipComponents1", "gl_SkipComponents2",
259 * "gl_SkipComponents3", and "gl_SkipComponents4".
260 */
261 if (programInterface == GL_TRANSFORM_FEEDBACK_VARYING &&
262 is_xfb_marker(name))
263 return GL_INVALID_INDEX;
264
265 switch (programInterface) {
266 case GL_TESS_CONTROL_SUBROUTINE:
267 case GL_TESS_CONTROL_SUBROUTINE_UNIFORM:
268 case GL_TESS_EVALUATION_SUBROUTINE:
269 case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM:
270 case GL_COMPUTE_SUBROUTINE:
271 case GL_COMPUTE_SUBROUTINE_UNIFORM:
272 case GL_GEOMETRY_SUBROUTINE:
273 case GL_GEOMETRY_SUBROUTINE_UNIFORM:
274 case GL_VERTEX_SUBROUTINE:
275 case GL_FRAGMENT_SUBROUTINE:
276 case GL_VERTEX_SUBROUTINE_UNIFORM:
277 case GL_FRAGMENT_SUBROUTINE_UNIFORM:
278 case GL_PROGRAM_INPUT:
279 case GL_PROGRAM_OUTPUT:
280 case GL_UNIFORM:
281 case GL_BUFFER_VARIABLE:
282 case GL_TRANSFORM_FEEDBACK_VARYING:
283 case GL_UNIFORM_BLOCK:
284 case GL_SHADER_STORAGE_BLOCK:
285 res = _mesa_program_resource_find_name(shProg, programInterface, name,
286 &array_index);
287 if (!res || array_index > 0)
288 return GL_INVALID_INDEX;
289
290 return _mesa_program_resource_index(shProg, res);
291 case GL_ATOMIC_COUNTER_BUFFER:
292 default:
293 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceIndex(%s)",
294 _mesa_enum_to_string(programInterface));
295 }
296
297 return GL_INVALID_INDEX;
298 }
299
300 void GLAPIENTRY
301 _mesa_GetProgramResourceName(GLuint program, GLenum programInterface,
302 GLuint index, GLsizei bufSize, GLsizei *length,
303 GLchar *name)
304 {
305 GET_CURRENT_CONTEXT(ctx);
306
307 if (MESA_VERBOSE & VERBOSE_API) {
308 _mesa_debug(ctx, "glGetProgramResourceName(%u, %s, %u, %d, %p, %p)\n",
309 program, _mesa_enum_to_string(programInterface), index,
310 bufSize, length, name);
311 }
312
313 struct gl_shader_program *shProg =
314 _mesa_lookup_shader_program_err(ctx, program,
315 "glGetProgramResourceName");
316
317 if (!shProg || !name)
318 return;
319
320 if (programInterface == GL_ATOMIC_COUNTER_BUFFER ||
321 !supported_interface_enum(ctx, programInterface)) {
322 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceName(%s)",
323 _mesa_enum_to_string(programInterface));
324 return;
325 }
326
327 _mesa_get_program_resource_name(shProg, programInterface, index, bufSize,
328 length, name, "glGetProgramResourceName");
329 }
330
331 void GLAPIENTRY
332 _mesa_GetProgramResourceiv(GLuint program, GLenum programInterface,
333 GLuint index, GLsizei propCount,
334 const GLenum *props, GLsizei bufSize,
335 GLsizei *length, GLint *params)
336 {
337 GET_CURRENT_CONTEXT(ctx);
338
339 if (MESA_VERBOSE & VERBOSE_API) {
340 _mesa_debug(ctx, "glGetProgramResourceiv(%u, %s, %u, %d, %p, %d, %p, %p)\n",
341 program, _mesa_enum_to_string(programInterface), index,
342 propCount, props, bufSize, length, params);
343 }
344
345 struct gl_shader_program *shProg =
346 _mesa_lookup_shader_program_err(ctx, program, "glGetProgramResourceiv");
347
348 if (!shProg || !params)
349 return;
350
351 /* The error INVALID_VALUE is generated if <propCount> is zero.
352 * Note that we check < 0 here because it makes sense to bail early.
353 */
354 if (propCount <= 0) {
355 _mesa_error(ctx, GL_INVALID_VALUE,
356 "glGetProgramResourceiv(propCount <= 0)");
357 return;
358 }
359
360 /* No need to write any properties, user requested none. */
361 if (bufSize == 0)
362 return;
363
364 _mesa_get_program_resourceiv(shProg, programInterface, index,
365 propCount, props, bufSize, length, params);
366 }
367
368 static struct gl_shader_program *
369 lookup_linked_program(GLuint program, const char *caller)
370 {
371 GET_CURRENT_CONTEXT(ctx);
372 struct gl_shader_program *prog =
373 _mesa_lookup_shader_program_err(ctx, program, caller);
374
375 if (!prog)
376 return NULL;
377
378 if (prog->LinkStatus == GL_FALSE) {
379 _mesa_error(ctx, GL_INVALID_OPERATION, "%s(program not linked)",
380 caller);
381 return NULL;
382 }
383 return prog;
384 }
385
386 GLint GLAPIENTRY
387 _mesa_GetProgramResourceLocation(GLuint program, GLenum programInterface,
388 const GLchar *name)
389 {
390 GET_CURRENT_CONTEXT(ctx);
391
392 if (MESA_VERBOSE & VERBOSE_API) {
393 _mesa_debug(ctx, "glGetProgramResourceLocation(%u, %s, %s)\n",
394 program, _mesa_enum_to_string(programInterface), name);
395 }
396
397 struct gl_shader_program *shProg =
398 lookup_linked_program(program, "glGetProgramResourceLocation");
399
400 if (!shProg || !name)
401 return -1;
402
403 /* Validate programInterface. */
404 switch (programInterface) {
405 case GL_UNIFORM:
406 case GL_PROGRAM_INPUT:
407 case GL_PROGRAM_OUTPUT:
408 break;
409
410 case GL_VERTEX_SUBROUTINE_UNIFORM:
411 case GL_FRAGMENT_SUBROUTINE_UNIFORM:
412 if (!_mesa_has_shader_subroutine(ctx))
413 goto fail;
414 break;
415 case GL_GEOMETRY_SUBROUTINE_UNIFORM:
416 if (!_mesa_has_geometry_shaders(ctx) || !_mesa_has_shader_subroutine(ctx))
417 goto fail;
418 break;
419 case GL_COMPUTE_SUBROUTINE_UNIFORM:
420 if (!_mesa_has_compute_shaders(ctx) || !_mesa_has_shader_subroutine(ctx))
421 goto fail;
422 break;
423 case GL_TESS_CONTROL_SUBROUTINE_UNIFORM:
424 case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM:
425 if (!_mesa_has_tessellation(ctx) || !_mesa_has_shader_subroutine(ctx))
426 goto fail;
427 break;
428 default:
429 goto fail;
430 }
431
432 return _mesa_program_resource_location(shProg, programInterface, name);
433 fail:
434 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceLocation(%s %s)",
435 _mesa_enum_to_string(programInterface), name);
436 return -1;
437 }
438
439 /**
440 * Returns output index for dual source blending.
441 */
442 GLint GLAPIENTRY
443 _mesa_GetProgramResourceLocationIndex(GLuint program, GLenum programInterface,
444 const GLchar *name)
445 {
446 GET_CURRENT_CONTEXT(ctx);
447
448 if (MESA_VERBOSE & VERBOSE_API) {
449 _mesa_debug(ctx, "glGetProgramResourceLocationIndex(%u, %s, %s)\n",
450 program, _mesa_enum_to_string(programInterface), name);
451 }
452
453 struct gl_shader_program *shProg =
454 lookup_linked_program(program, "glGetProgramResourceLocationIndex");
455
456 if (!shProg || !name)
457 return -1;
458
459 /* From the GL_ARB_program_interface_query spec:
460 *
461 * "For GetProgramResourceLocationIndex, <programInterface> must be
462 * PROGRAM_OUTPUT."
463 */
464 if (programInterface != GL_PROGRAM_OUTPUT) {
465 _mesa_error(ctx, GL_INVALID_ENUM,
466 "glGetProgramResourceLocationIndex(%s)",
467 _mesa_enum_to_string(programInterface));
468 return -1;
469 }
470
471 return _mesa_program_resource_location_index(shProg, GL_PROGRAM_OUTPUT,
472 name);
473 }