Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5564 | serge | 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 "program_resource.h" |
||
32 | |||
33 | static bool |
||
34 | supported_interface_enum(GLenum iface) |
||
35 | { |
||
36 | switch (iface) { |
||
37 | case GL_UNIFORM: |
||
38 | case GL_UNIFORM_BLOCK: |
||
39 | case GL_PROGRAM_INPUT: |
||
40 | case GL_PROGRAM_OUTPUT: |
||
41 | case GL_TRANSFORM_FEEDBACK_VARYING: |
||
42 | case GL_ATOMIC_COUNTER_BUFFER: |
||
43 | return true; |
||
44 | case GL_VERTEX_SUBROUTINE: |
||
45 | case GL_TESS_CONTROL_SUBROUTINE: |
||
46 | case GL_TESS_EVALUATION_SUBROUTINE: |
||
47 | case GL_GEOMETRY_SUBROUTINE: |
||
48 | case GL_FRAGMENT_SUBROUTINE: |
||
49 | case GL_COMPUTE_SUBROUTINE: |
||
50 | case GL_VERTEX_SUBROUTINE_UNIFORM: |
||
51 | case GL_TESS_CONTROL_SUBROUTINE_UNIFORM: |
||
52 | case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM: |
||
53 | case GL_GEOMETRY_SUBROUTINE_UNIFORM: |
||
54 | case GL_FRAGMENT_SUBROUTINE_UNIFORM: |
||
55 | case GL_COMPUTE_SUBROUTINE_UNIFORM: |
||
56 | case GL_BUFFER_VARIABLE: |
||
57 | case GL_SHADER_STORAGE_BLOCK: |
||
58 | default: |
||
59 | return false; |
||
60 | } |
||
61 | } |
||
62 | |||
63 | void GLAPIENTRY |
||
64 | _mesa_GetProgramInterfaceiv(GLuint program, GLenum programInterface, |
||
65 | GLenum pname, GLint *params) |
||
66 | { |
||
67 | GET_CURRENT_CONTEXT(ctx); |
||
68 | unsigned i; |
||
69 | struct gl_shader_program *shProg = |
||
70 | _mesa_lookup_shader_program_err(ctx, program, |
||
71 | "glGetProgramInterfaceiv"); |
||
72 | if (!shProg) |
||
73 | return; |
||
74 | |||
75 | if (!params) { |
||
76 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
77 | "glGetProgramInterfaceiv(params NULL)"); |
||
78 | return; |
||
79 | } |
||
80 | |||
81 | /* Validate interface. */ |
||
82 | if (!supported_interface_enum(programInterface)) { |
||
83 | _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramInterfaceiv(%s)", |
||
84 | _mesa_lookup_enum_by_nr(programInterface)); |
||
85 | return; |
||
86 | } |
||
87 | |||
88 | /* Validate pname against interface. */ |
||
89 | switch(pname) { |
||
90 | case GL_ACTIVE_RESOURCES: |
||
91 | for (i = 0, *params = 0; i < shProg->NumProgramResourceList; i++) |
||
92 | if (shProg->ProgramResourceList[i].Type == programInterface) |
||
93 | (*params)++; |
||
94 | break; |
||
95 | case GL_MAX_NAME_LENGTH: |
||
96 | if (programInterface == GL_ATOMIC_COUNTER_BUFFER) { |
||
97 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
98 | "glGetProgramInterfaceiv(%s pname %s)", |
||
99 | _mesa_lookup_enum_by_nr(programInterface), |
||
100 | _mesa_lookup_enum_by_nr(pname)); |
||
101 | return; |
||
102 | } |
||
103 | /* Name length consists of base name, 3 additional chars '[0]' if |
||
104 | * resource is an array and finally 1 char for string terminator. |
||
105 | */ |
||
106 | for (i = 0, *params = 0; i < shProg->NumProgramResourceList; i++) { |
||
107 | if (shProg->ProgramResourceList[i].Type != programInterface) |
||
108 | continue; |
||
109 | const char *name = |
||
110 | _mesa_program_resource_name(&shProg->ProgramResourceList[i]); |
||
111 | unsigned array_size = |
||
112 | _mesa_program_resource_array_size(&shProg->ProgramResourceList[i]); |
||
113 | *params = MAX2(*params, strlen(name) + (array_size ? 3 : 0) + 1); |
||
114 | } |
||
115 | break; |
||
116 | case GL_MAX_NUM_ACTIVE_VARIABLES: |
||
117 | switch (programInterface) { |
||
118 | case GL_UNIFORM_BLOCK: |
||
119 | for (i = 0, *params = 0; i < shProg->NumProgramResourceList; i++) { |
||
120 | if (shProg->ProgramResourceList[i].Type == programInterface) { |
||
121 | struct gl_uniform_block *block = |
||
122 | (struct gl_uniform_block *) |
||
123 | shProg->ProgramResourceList[i].Data; |
||
124 | *params = MAX2(*params, block->NumUniforms); |
||
125 | } |
||
126 | } |
||
127 | break; |
||
128 | case GL_ATOMIC_COUNTER_BUFFER: |
||
129 | for (i = 0, *params = 0; i < shProg->NumProgramResourceList; i++) { |
||
130 | if (shProg->ProgramResourceList[i].Type == programInterface) { |
||
131 | struct gl_active_atomic_buffer *buffer = |
||
132 | (struct gl_active_atomic_buffer *) |
||
133 | shProg->ProgramResourceList[i].Data; |
||
134 | *params = MAX2(*params, buffer->NumUniforms); |
||
135 | } |
||
136 | } |
||
137 | break; |
||
138 | default: |
||
139 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
140 | "glGetProgramInterfaceiv(%s pname %s)", |
||
141 | _mesa_lookup_enum_by_nr(programInterface), |
||
142 | _mesa_lookup_enum_by_nr(pname)); |
||
143 | }; |
||
144 | break; |
||
145 | case GL_MAX_NUM_COMPATIBLE_SUBROUTINES: |
||
146 | default: |
||
147 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
148 | "glGetProgramInterfaceiv(pname %s)", |
||
149 | _mesa_lookup_enum_by_nr(pname)); |
||
150 | } |
||
151 | } |
||
152 | |||
153 | static bool |
||
154 | is_xfb_marker(const char *str) |
||
155 | { |
||
156 | static const char *markers[] = { |
||
157 | "gl_NextBuffer", |
||
158 | "gl_SkipComponents1", |
||
159 | "gl_SkipComponents2", |
||
160 | "gl_SkipComponents3", |
||
161 | "gl_SkipComponents4", |
||
162 | NULL |
||
163 | }; |
||
164 | const char **m = markers; |
||
165 | |||
166 | if (strncmp(str, "gl_", 3) != 0) |
||
167 | return false; |
||
168 | |||
169 | for (; *m; m++) |
||
170 | if (strcmp(*m, str) == 0) |
||
171 | return true; |
||
172 | |||
173 | return false; |
||
174 | } |
||
175 | |||
176 | /** |
||
177 | * Checks if given name index is legal for GetProgramResourceIndex, |
||
178 | * check is written to be compatible with GL_ARB_array_of_arrays. |
||
179 | */ |
||
180 | static bool |
||
181 | valid_program_resource_index_name(const GLchar *name) |
||
182 | { |
||
183 | const char *array = strstr(name, "["); |
||
184 | const char *close = strrchr(name, ']'); |
||
185 | |||
186 | /* Not array, no need for the check. */ |
||
187 | if (!array) |
||
188 | return true; |
||
189 | |||
190 | /* Last array index has to be zero. */ |
||
191 | if (!close || *--close != '0') |
||
192 | return false; |
||
193 | |||
194 | return true; |
||
195 | } |
||
196 | |||
197 | GLuint GLAPIENTRY |
||
198 | _mesa_GetProgramResourceIndex(GLuint program, GLenum programInterface, |
||
199 | const GLchar *name) |
||
200 | { |
||
201 | GET_CURRENT_CONTEXT(ctx); |
||
202 | struct gl_program_resource *res; |
||
203 | struct gl_shader_program *shProg = |
||
204 | _mesa_lookup_shader_program_err(ctx, program, |
||
205 | "glGetProgramResourceIndex"); |
||
206 | if (!shProg || !name) |
||
207 | return GL_INVALID_INDEX; |
||
208 | |||
209 | /* |
||
210 | * For the interface TRANSFORM_FEEDBACK_VARYING, the value INVALID_INDEX |
||
211 | * should be returned when querying the index assigned to the special names |
||
212 | * "gl_NextBuffer", "gl_SkipComponents1", "gl_SkipComponents2", |
||
213 | * "gl_SkipComponents3", and "gl_SkipComponents4". |
||
214 | */ |
||
215 | if (programInterface == GL_TRANSFORM_FEEDBACK_VARYING && |
||
216 | is_xfb_marker(name)) |
||
217 | return GL_INVALID_INDEX; |
||
218 | |||
219 | switch (programInterface) { |
||
220 | case GL_PROGRAM_INPUT: |
||
221 | case GL_PROGRAM_OUTPUT: |
||
222 | case GL_UNIFORM: |
||
223 | case GL_UNIFORM_BLOCK: |
||
224 | case GL_TRANSFORM_FEEDBACK_VARYING: |
||
225 | /* Validate name syntax for arrays. */ |
||
226 | if (!valid_program_resource_index_name(name)) |
||
227 | return GL_INVALID_INDEX; |
||
228 | |||
229 | res = _mesa_program_resource_find_name(shProg, programInterface, name); |
||
230 | if (!res) |
||
231 | return GL_INVALID_INDEX; |
||
232 | |||
233 | return _mesa_program_resource_index(shProg, res); |
||
234 | case GL_ATOMIC_COUNTER_BUFFER: |
||
235 | default: |
||
236 | _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceIndex(%s)", |
||
237 | _mesa_lookup_enum_by_nr(programInterface)); |
||
238 | } |
||
239 | |||
240 | return GL_INVALID_INDEX; |
||
241 | } |
||
242 | |||
243 | void GLAPIENTRY |
||
244 | _mesa_GetProgramResourceName(GLuint program, GLenum programInterface, |
||
245 | GLuint index, GLsizei bufSize, GLsizei *length, |
||
246 | GLchar *name) |
||
247 | { |
||
248 | GET_CURRENT_CONTEXT(ctx); |
||
249 | struct gl_shader_program *shProg = |
||
250 | _mesa_lookup_shader_program_err(ctx, program, |
||
251 | "glGetProgramResourceName"); |
||
252 | |||
253 | /* Set user friendly return values in case of errors. */ |
||
254 | if (name) |
||
255 | *name = '\0'; |
||
256 | if (length) |
||
257 | *length = 0; |
||
258 | |||
259 | if (!shProg || !name) |
||
260 | return; |
||
261 | |||
262 | if (programInterface == GL_ATOMIC_COUNTER_BUFFER || |
||
263 | !supported_interface_enum(programInterface)) { |
||
264 | _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceName(%s)", |
||
265 | _mesa_lookup_enum_by_nr(programInterface)); |
||
266 | return; |
||
267 | } |
||
268 | |||
269 | _mesa_get_program_resource_name(shProg, programInterface, index, bufSize, |
||
270 | length, name, "glGetProgramResourceName"); |
||
271 | } |
||
272 | |||
273 | void GLAPIENTRY |
||
274 | _mesa_GetProgramResourceiv(GLuint program, GLenum programInterface, |
||
275 | GLuint index, GLsizei propCount, |
||
276 | const GLenum *props, GLsizei bufSize, |
||
277 | GLsizei *length, GLint *params) |
||
278 | { |
||
279 | GET_CURRENT_CONTEXT(ctx); |
||
280 | struct gl_shader_program *shProg = |
||
281 | _mesa_lookup_shader_program_err(ctx, program, "glGetProgramResourceiv"); |
||
282 | |||
283 | if (!shProg || !params) |
||
284 | return; |
||
285 | |||
286 | /* The error INVALID_VALUE is generated if |
||
287 | * Note that we check < 0 here because it makes sense to bail early. |
||
288 | */ |
||
289 | if (propCount <= 0) { |
||
290 | _mesa_error(ctx, GL_INVALID_VALUE, |
||
291 | "glGetProgramResourceiv(propCount <= 0)"); |
||
292 | return; |
||
293 | } |
||
294 | |||
295 | /* No need to write any properties, user requested none. */ |
||
296 | if (bufSize == 0) |
||
297 | return; |
||
298 | |||
299 | _mesa_get_program_resourceiv(shProg, programInterface, index, |
||
300 | propCount, props, bufSize, length, params); |
||
301 | } |
||
302 | |||
303 | /** |
||
304 | * Function verifies syntax of given name for GetProgramResourceLocation |
||
305 | * and GetProgramResourceLocationIndex for the following cases: |
||
306 | * |
||
307 | * "array element portion of a string passed to GetProgramResourceLocation |
||
308 | * or GetProgramResourceLocationIndex must not have, a "+" sign, extra |
||
309 | * leading zeroes, or whitespace". |
||
310 | * |
||
311 | * Check is written to be compatible with GL_ARB_array_of_arrays. |
||
312 | */ |
||
313 | static bool |
||
314 | invalid_array_element_syntax(const GLchar *name) |
||
315 | { |
||
316 | char *first = strchr(name, '['); |
||
317 | char *last = strrchr(name, '['); |
||
318 | |||
319 | if (!first) |
||
320 | return false; |
||
321 | |||
322 | /* No '+' or ' ' allowed anywhere. */ |
||
323 | if (strchr(first, '+') || strchr(first, ' ')) |
||
324 | return true; |
||
325 | |||
326 | /* Check that last array index is 0. */ |
||
327 | if (last[1] == '0' && last[2] != ']') |
||
328 | return true; |
||
329 | |||
330 | return false; |
||
331 | } |
||
332 | |||
333 | static struct gl_shader_program * |
||
334 | lookup_linked_program(GLuint program, const char *caller) |
||
335 | { |
||
336 | GET_CURRENT_CONTEXT(ctx); |
||
337 | struct gl_shader_program *prog = |
||
338 | _mesa_lookup_shader_program_err(ctx, program, caller); |
||
339 | |||
340 | if (!prog) |
||
341 | return NULL; |
||
342 | |||
343 | if (prog->LinkStatus == GL_FALSE) { |
||
344 | _mesa_error(ctx, GL_INVALID_OPERATION, "%s(program not linked)", |
||
345 | caller); |
||
346 | return NULL; |
||
347 | } |
||
348 | return prog; |
||
349 | } |
||
350 | |||
351 | GLint GLAPIENTRY |
||
352 | _mesa_GetProgramResourceLocation(GLuint program, GLenum programInterface, |
||
353 | const GLchar *name) |
||
354 | { |
||
355 | GET_CURRENT_CONTEXT(ctx); |
||
356 | struct gl_shader_program *shProg = |
||
357 | lookup_linked_program(program, "glGetProgramResourceLocation"); |
||
358 | |||
359 | if (!shProg || !name || invalid_array_element_syntax(name)) |
||
360 | return -1; |
||
361 | |||
362 | /* Validate programInterface. */ |
||
363 | switch (programInterface) { |
||
364 | case GL_UNIFORM: |
||
365 | case GL_PROGRAM_INPUT: |
||
366 | case GL_PROGRAM_OUTPUT: |
||
367 | break; |
||
368 | |||
369 | /* For reference valid cases requiring additional extension support: |
||
370 | * GL_ARB_shader_subroutine |
||
371 | * GL_ARB_tessellation_shader |
||
372 | * GL_ARB_compute_shader |
||
373 | */ |
||
374 | case GL_VERTEX_SUBROUTINE_UNIFORM: |
||
375 | case GL_TESS_CONTROL_SUBROUTINE_UNIFORM: |
||
376 | case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM: |
||
377 | case GL_GEOMETRY_SUBROUTINE_UNIFORM: |
||
378 | case GL_FRAGMENT_SUBROUTINE_UNIFORM: |
||
379 | case GL_COMPUTE_SUBROUTINE_UNIFORM: |
||
380 | |||
381 | default: |
||
382 | _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramResourceLocation(%s %s)", |
||
383 | _mesa_lookup_enum_by_nr(programInterface), name); |
||
384 | } |
||
385 | |||
386 | return _mesa_program_resource_location(shProg, programInterface, name); |
||
387 | } |
||
388 | |||
389 | /** |
||
390 | * Returns output index for dual source blending. |
||
391 | */ |
||
392 | GLint GLAPIENTRY |
||
393 | _mesa_GetProgramResourceLocationIndex(GLuint program, GLenum programInterface, |
||
394 | const GLchar *name) |
||
395 | { |
||
396 | GET_CURRENT_CONTEXT(ctx); |
||
397 | struct gl_shader_program *shProg = |
||
398 | lookup_linked_program(program, "glGetProgramResourceLocationIndex"); |
||
399 | |||
400 | if (!shProg || !name || invalid_array_element_syntax(name)) |
||
401 | return -1; |
||
402 | |||
403 | /* From the GL_ARB_program_interface_query spec: |
||
404 | * |
||
405 | * "For GetProgramResourceLocationIndex, |
||
406 | * PROGRAM_OUTPUT." |
||
407 | */ |
||
408 | if (programInterface != GL_PROGRAM_OUTPUT) { |
||
409 | _mesa_error(ctx, GL_INVALID_ENUM, |
||
410 | "glGetProgramResourceLocationIndex(%s)", |
||
411 | _mesa_lookup_enum_by_nr(programInterface)); |
||
412 | return -1; |
||
413 | } |
||
414 | |||
415 | return _mesa_program_resource_location_index(shProg, GL_PROGRAM_OUTPUT, |
||
416 | name); |
||
417 | }=>=>>>>>> |