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