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