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) 2004-2008 Brian Paul All Rights Reserved. |
||
5 | * Copyright (C) 2009-2010 VMware, Inc. All Rights Reserved. |
||
6 | * Copyright © 2010, 2011 Intel Corporation |
||
7 | * |
||
8 | * Permission is hereby granted, free of charge, to any person obtaining a |
||
9 | * copy of this software and associated documentation files (the "Software"), |
||
10 | * to deal in the Software without restriction, including without limitation |
||
11 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||
12 | * and/or sell copies of the Software, and to permit persons to whom the |
||
13 | * Software is furnished to do so, subject to the following conditions: |
||
14 | * |
||
15 | * The above copyright notice and this permission notice shall be included |
||
16 | * in all copies or substantial portions of the Software. |
||
17 | * |
||
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
||
19 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||
21 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR |
||
22 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
||
23 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
||
24 | * OTHER DEALINGS IN THE SOFTWARE. |
||
25 | */ |
||
26 | |||
27 | #include |
||
28 | |||
29 | #include "main/core.h" |
||
30 | #include "main/context.h" |
||
31 | #include "ir.h" |
||
32 | #include "ir_uniform.h" |
||
33 | #include "program/hash_table.h" |
||
34 | #include "../glsl/program.h" |
||
35 | #include "../glsl/ir_uniform.h" |
||
36 | #include "../glsl/glsl_parser_extras.h" |
||
37 | #include "main/shaderapi.h" |
||
38 | #include "main/shaderobj.h" |
||
39 | #include "uniforms.h" |
||
40 | |||
41 | |||
42 | extern "C" void GLAPIENTRY |
||
43 | _mesa_GetActiveUniform(GLuint program, GLuint index, |
||
44 | GLsizei maxLength, GLsizei *length, GLint *size, |
||
45 | GLenum *type, GLcharARB *nameOut) |
||
46 | { |
||
47 | GET_CURRENT_CONTEXT(ctx); |
||
48 | struct gl_shader_program *shProg; |
||
49 | struct gl_program_resource *res; |
||
50 | |||
51 | if (maxLength < 0) { |
||
52 | _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(maxLength < 0)"); |
||
53 | return; |
||
54 | } |
||
55 | |||
56 | shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveUniform"); |
||
57 | if (!shProg) |
||
58 | return; |
||
59 | |||
60 | res = _mesa_program_resource_find_index((struct gl_shader_program *) shProg, |
||
61 | GL_UNIFORM, index); |
||
62 | |||
63 | if (!res) { |
||
64 | _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)"); |
||
65 | return; |
||
66 | } |
||
67 | |||
68 | if (nameOut) |
||
69 | _mesa_get_program_resource_name(shProg, GL_UNIFORM, index, maxLength, |
||
70 | length, nameOut, "glGetActiveUniform"); |
||
71 | if (type) |
||
72 | _mesa_program_resource_prop((struct gl_shader_program *) shProg, |
||
73 | res, index, GL_TYPE, (GLint*) type, |
||
74 | "glGetActiveUniform"); |
||
75 | if (size) |
||
76 | _mesa_program_resource_prop((struct gl_shader_program *) shProg, |
||
77 | res, index, GL_ARRAY_SIZE, (GLint*) size, |
||
78 | "glGetActiveUniform"); |
||
79 | } |
||
80 | |||
81 | static GLenum |
||
82 | resource_prop_from_uniform_prop(GLenum uni_prop) |
||
83 | { |
||
84 | switch (uni_prop) { |
||
85 | case GL_UNIFORM_TYPE: |
||
86 | return GL_TYPE; |
||
87 | case GL_UNIFORM_SIZE: |
||
88 | return GL_ARRAY_SIZE; |
||
89 | case GL_UNIFORM_NAME_LENGTH: |
||
90 | return GL_NAME_LENGTH; |
||
91 | case GL_UNIFORM_BLOCK_INDEX: |
||
92 | return GL_BLOCK_INDEX; |
||
93 | case GL_UNIFORM_OFFSET: |
||
94 | return GL_OFFSET; |
||
95 | case GL_UNIFORM_ARRAY_STRIDE: |
||
96 | return GL_ARRAY_STRIDE; |
||
97 | case GL_UNIFORM_MATRIX_STRIDE: |
||
98 | return GL_MATRIX_STRIDE; |
||
99 | case GL_UNIFORM_IS_ROW_MAJOR: |
||
100 | return GL_IS_ROW_MAJOR; |
||
101 | case GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX: |
||
102 | return GL_ATOMIC_COUNTER_BUFFER_INDEX; |
||
103 | default: |
||
104 | return 0; |
||
105 | } |
||
106 | } |
||
107 | |||
108 | extern "C" void GLAPIENTRY |
||
109 | _mesa_GetActiveUniformsiv(GLuint program, |
||
110 | GLsizei uniformCount, |
||
111 | const GLuint *uniformIndices, |
||
112 | GLenum pname, |
||
113 | GLint *params) |
||
114 | { |
||
115 | GET_CURRENT_CONTEXT(ctx); |
||
116 | struct gl_shader_program *shProg; |
||
117 | struct gl_program_resource *res; |
||
118 | GLenum res_prop; |
||
119 | |||
120 | if (uniformCount < 0) { |
||
121 | _mesa_error(ctx, GL_INVALID_VALUE, |
||
122 | "glGetActiveUniformsiv(uniformCount < 0)"); |
||
123 | return; |
||
124 | } |
||
125 | |||
126 | shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveUniform"); |
||
127 | if (!shProg) |
||
128 | return; |
||
129 | |||
130 | res_prop = resource_prop_from_uniform_prop(pname); |
||
131 | |||
132 | /* We need to first verify that each entry exists as active uniform. If |
||
133 | * not, generate error and do not cause any other side effects. |
||
134 | * |
||
135 | * In the case of and error condition, Page 16 (section 2.3.1 Errors) |
||
136 | * of the OpenGL 4.5 spec says: |
||
137 | * |
||
138 | * "If the generating command modifies values through a pointer argu- |
||
139 | * ment, no change is made to these values." |
||
140 | */ |
||
141 | for (int i = 0; i < uniformCount; i++) { |
||
142 | if (!_mesa_program_resource_find_index(shProg, GL_UNIFORM, |
||
143 | uniformIndices[i])) { |
||
144 | _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniformsiv(index)"); |
||
145 | return; |
||
146 | } |
||
147 | } |
||
148 | |||
149 | for (int i = 0; i < uniformCount; i++) { |
||
150 | res = _mesa_program_resource_find_index(shProg, GL_UNIFORM, |
||
151 | uniformIndices[i]); |
||
152 | if (!_mesa_program_resource_prop(shProg, res, uniformIndices[i], |
||
153 | res_prop, ¶ms[i], |
||
154 | "glGetActiveUniformsiv")) |
||
155 | break; |
||
156 | } |
||
157 | } |
||
158 | |||
159 | static struct gl_uniform_storage * |
||
160 | validate_uniform_parameters(struct gl_context *ctx, |
||
161 | struct gl_shader_program *shProg, |
||
162 | GLint location, GLsizei count, |
||
163 | unsigned *array_index, |
||
164 | const char *caller) |
||
165 | { |
||
166 | if (shProg == NULL) { |
||
167 | _mesa_error(ctx, GL_INVALID_OPERATION, "%s(program not linked)", caller); |
||
168 | return NULL; |
||
169 | } |
||
170 | |||
171 | /* From page 12 (page 26 of the PDF) of the OpenGL 2.1 spec: |
||
172 | * |
||
173 | * "If a negative number is provided where an argument of type sizei or |
||
174 | * sizeiptr is specified, the error INVALID_VALUE is generated." |
||
175 | */ |
||
176 | if (count < 0) { |
||
177 | _mesa_error(ctx, GL_INVALID_VALUE, "%s(count < 0)", caller); |
||
178 | return NULL; |
||
179 | } |
||
180 | |||
181 | /* Check that the given location is in bounds of uniform remap table. |
||
182 | * Unlinked programs will have NumUniformRemapTable == 0, so we can take |
||
183 | * the shProg->LinkStatus check out of the main path. |
||
184 | */ |
||
185 | if (unlikely(location >= (GLint) shProg->NumUniformRemapTable)) { |
||
186 | if (!shProg->LinkStatus) |
||
187 | _mesa_error(ctx, GL_INVALID_OPERATION, "%s(program not linked)", |
||
188 | caller); |
||
189 | else |
||
190 | _mesa_error(ctx, GL_INVALID_OPERATION, "%s(location=%d)", |
||
191 | caller, location); |
||
192 | |||
193 | return NULL; |
||
194 | } |
||
195 | |||
196 | if (location == -1) { |
||
197 | if (!shProg->LinkStatus) |
||
198 | _mesa_error(ctx, GL_INVALID_OPERATION, "%s(program not linked)", |
||
199 | caller); |
||
200 | |||
201 | return NULL; |
||
202 | } |
||
203 | |||
204 | /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says: |
||
205 | * |
||
206 | * "If any of the following conditions occur, an INVALID_OPERATION |
||
207 | * error is generated by the Uniform* commands, and no uniform values |
||
208 | * are changed: |
||
209 | * |
||
210 | * ... |
||
211 | * |
||
212 | * - if no variable with a location of location exists in the |
||
213 | * program object currently in use and location is not -1, |
||
214 | * - if count is greater than one, and the uniform declared in the |
||
215 | * shader is not an array variable, |
||
216 | */ |
||
217 | if (location < -1 || !shProg->UniformRemapTable[location]) { |
||
218 | _mesa_error(ctx, GL_INVALID_OPERATION, "%s(location=%d)", |
||
219 | caller, location); |
||
220 | return NULL; |
||
221 | } |
||
222 | |||
223 | /* If the driver storage pointer in remap table is -1, we ignore silently. |
||
224 | * |
||
225 | * GL_ARB_explicit_uniform_location spec says: |
||
226 | * "What happens if Uniform* is called with an explicitly defined |
||
227 | * uniform location, but that uniform is deemed inactive by the |
||
228 | * linker? |
||
229 | * |
||
230 | * RESOLVED: The call is ignored for inactive uniform variables and |
||
231 | * no error is generated." |
||
232 | * |
||
233 | */ |
||
234 | if (shProg->UniformRemapTable[location] == |
||
235 | INACTIVE_UNIFORM_EXPLICIT_LOCATION) |
||
236 | return NULL; |
||
237 | |||
238 | struct gl_uniform_storage *const uni = shProg->UniformRemapTable[location]; |
||
239 | |||
240 | if (uni->array_elements == 0) { |
||
241 | if (count > 1) { |
||
242 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
243 | "%s(count = %u for non-array \"%s\"@%d)", |
||
244 | caller, count, uni->name, location); |
||
245 | return NULL; |
||
246 | } |
||
247 | |||
248 | assert((location - uni->remap_location) == 0); |
||
249 | *array_index = 0; |
||
250 | } else { |
||
251 | /* The array index specified by the uniform location is just the uniform |
||
252 | * location minus the base location of of the uniform. |
||
253 | */ |
||
254 | *array_index = location - uni->remap_location; |
||
255 | |||
256 | /* If the uniform is an array, check that array_index is in bounds. |
||
257 | * array_index is unsigned so no need to check for less than zero. |
||
258 | */ |
||
259 | if (*array_index >= uni->array_elements) { |
||
260 | _mesa_error(ctx, GL_INVALID_OPERATION, "%s(location=%d)", |
||
261 | caller, location); |
||
262 | return NULL; |
||
263 | } |
||
264 | } |
||
265 | return uni; |
||
266 | } |
||
267 | |||
268 | /** |
||
269 | * Called via glGetUniform[fiui]v() to get the current value of a uniform. |
||
270 | */ |
||
271 | extern "C" void |
||
272 | _mesa_get_uniform(struct gl_context *ctx, GLuint program, GLint location, |
||
273 | GLsizei bufSize, enum glsl_base_type returnType, |
||
274 | GLvoid *paramsOut) |
||
275 | { |
||
276 | struct gl_shader_program *shProg = |
||
277 | _mesa_lookup_shader_program_err(ctx, program, "glGetUniformfv"); |
||
278 | unsigned offset; |
||
279 | |||
280 | struct gl_uniform_storage *const uni = |
||
281 | validate_uniform_parameters(ctx, shProg, location, 1, |
||
282 | &offset, "glGetUniform"); |
||
283 | if (uni == NULL) { |
||
284 | /* For glGetUniform, page 264 (page 278 of the PDF) of the OpenGL 2.1 |
||
285 | * spec says: |
||
286 | * |
||
287 | * "The error INVALID_OPERATION is generated if program has not been |
||
288 | * linked successfully, or if location is not a valid location for |
||
289 | * program." |
||
290 | * |
||
291 | * For glUniform, page 82 (page 96 of the PDF) of the OpenGL 2.1 spec |
||
292 | * says: |
||
293 | * |
||
294 | * "If the value of location is -1, the Uniform* commands will |
||
295 | * silently ignore the data passed in, and the current uniform |
||
296 | * values will not be changed." |
||
297 | * |
||
298 | * Allowing -1 for the location parameter of glUniform allows |
||
299 | * applications to avoid error paths in the case that, for example, some |
||
300 | * uniform variable is removed by the compiler / linker after |
||
301 | * optimization. In this case, the new value of the uniform is dropped |
||
302 | * on the floor. For the case of glGetUniform, there is nothing |
||
303 | * sensible to do for a location of -1. |
||
304 | * |
||
305 | * If the location was -1, validate_unfirom_parameters will return NULL |
||
306 | * without raising an error. Raise the error here. |
||
307 | */ |
||
308 | if (location == -1) { |
||
309 | _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniform(location=%d)", |
||
310 | location); |
||
311 | } |
||
312 | |||
313 | return; |
||
314 | } |
||
315 | |||
316 | { |
||
317 | unsigned elements = (uni->type->is_sampler()) |
||
318 | ? 1 : uni->type->components(); |
||
319 | |||
320 | /* Calculate the source base address *BEFORE* modifying elements to |
||
321 | * account for the size of the user's buffer. |
||
322 | */ |
||
323 | const union gl_constant_value *const src = |
||
324 | &uni->storage[offset * elements]; |
||
325 | |||
326 | assert(returnType == GLSL_TYPE_FLOAT || returnType == GLSL_TYPE_INT || |
||
327 | returnType == GLSL_TYPE_UINT); |
||
328 | /* The three (currently) supported types all have the same size, |
||
329 | * which is of course the same as their union. That'll change |
||
330 | * with glGetUniformdv()... |
||
331 | */ |
||
332 | unsigned bytes = sizeof(src[0]) * elements; |
||
333 | if (bufSize < 0 || bytes > (unsigned) bufSize) { |
||
334 | _mesa_error( ctx, GL_INVALID_OPERATION, |
||
335 | "glGetnUniform*vARB(out of bounds: bufSize is %d," |
||
336 | " but %u bytes are required)", bufSize, bytes ); |
||
337 | return; |
||
338 | } |
||
339 | |||
340 | /* If the return type and the uniform's native type are "compatible," |
||
341 | * just memcpy the data. If the types are not compatible, perform a |
||
342 | * slower convert-and-copy process. |
||
343 | */ |
||
344 | if (returnType == uni->type->base_type |
||
345 | || ((returnType == GLSL_TYPE_INT |
||
346 | || returnType == GLSL_TYPE_UINT) |
||
347 | && |
||
348 | (uni->type->base_type == GLSL_TYPE_INT |
||
349 | || uni->type->base_type == GLSL_TYPE_UINT |
||
350 | || uni->type->base_type == GLSL_TYPE_SAMPLER |
||
351 | || uni->type->base_type == GLSL_TYPE_IMAGE))) { |
||
352 | memcpy(paramsOut, src, bytes); |
||
353 | } else { |
||
354 | union gl_constant_value *const dst = |
||
355 | (union gl_constant_value *) paramsOut; |
||
356 | |||
357 | /* This code could be optimized by putting the loop inside the switch |
||
358 | * statements. However, this is not expected to be |
||
359 | * performance-critical code. |
||
360 | */ |
||
361 | for (unsigned i = 0; i < elements; i++) { |
||
362 | switch (returnType) { |
||
363 | case GLSL_TYPE_FLOAT: |
||
364 | switch (uni->type->base_type) { |
||
365 | case GLSL_TYPE_UINT: |
||
366 | dst[i].f = (float) src[i].u; |
||
367 | break; |
||
368 | case GLSL_TYPE_INT: |
||
369 | case GLSL_TYPE_SAMPLER: |
||
370 | case GLSL_TYPE_IMAGE: |
||
371 | dst[i].f = (float) src[i].i; |
||
372 | break; |
||
373 | case GLSL_TYPE_BOOL: |
||
374 | dst[i].f = src[i].i ? 1.0f : 0.0f; |
||
375 | break; |
||
376 | default: |
||
377 | assert(!"Should not get here."); |
||
378 | break; |
||
379 | } |
||
380 | break; |
||
381 | |||
382 | case GLSL_TYPE_INT: |
||
383 | case GLSL_TYPE_UINT: |
||
384 | switch (uni->type->base_type) { |
||
385 | case GLSL_TYPE_FLOAT: |
||
386 | /* While the GL 3.2 core spec doesn't explicitly |
||
387 | * state how conversion of float uniforms to integer |
||
388 | * values works, in section 6.2 "State Tables" on |
||
389 | * page 267 it says: |
||
390 | * |
||
391 | * "Unless otherwise specified, when floating |
||
392 | * point state is returned as integer values or |
||
393 | * integer state is returned as floating-point |
||
394 | * values it is converted in the fashion |
||
395 | * described in section 6.1.2" |
||
396 | * |
||
397 | * That section, on page 248, says: |
||
398 | * |
||
399 | * "If GetIntegerv or GetInteger64v are called, |
||
400 | * a floating-point value is rounded to the |
||
401 | * nearest integer..." |
||
402 | */ |
||
403 | dst[i].i = IROUND(src[i].f); |
||
404 | break; |
||
405 | case GLSL_TYPE_BOOL: |
||
406 | dst[i].i = src[i].i ? 1 : 0; |
||
407 | break; |
||
408 | default: |
||
409 | assert(!"Should not get here."); |
||
410 | break; |
||
411 | } |
||
412 | break; |
||
413 | |||
414 | default: |
||
415 | assert(!"Should not get here."); |
||
416 | break; |
||
417 | } |
||
418 | } |
||
419 | } |
||
420 | } |
||
421 | } |
||
422 | |||
423 | static void |
||
424 | log_uniform(const void *values, enum glsl_base_type basicType, |
||
425 | unsigned rows, unsigned cols, unsigned count, |
||
426 | bool transpose, |
||
427 | const struct gl_shader_program *shProg, |
||
428 | GLint location, |
||
429 | const struct gl_uniform_storage *uni) |
||
430 | { |
||
431 | |||
432 | const union gl_constant_value *v = (const union gl_constant_value *) values; |
||
433 | const unsigned elems = rows * cols * count; |
||
434 | const char *const extra = (cols == 1) ? "uniform" : "uniform matrix"; |
||
435 | |||
436 | printf("Mesa: set program %u %s \"%s\" (loc %d, type \"%s\", " |
||
437 | "transpose = %s) to: ", |
||
438 | shProg->Name, extra, uni->name, location, uni->type->name, |
||
439 | transpose ? "true" : "false"); |
||
440 | for (unsigned i = 0; i < elems; i++) { |
||
441 | if (i != 0 && ((i % rows) == 0)) |
||
442 | printf(", "); |
||
443 | |||
444 | switch (basicType) { |
||
445 | case GLSL_TYPE_UINT: |
||
446 | printf("%u ", v[i].u); |
||
447 | break; |
||
448 | case GLSL_TYPE_INT: |
||
449 | printf("%d ", v[i].i); |
||
450 | break; |
||
451 | case GLSL_TYPE_FLOAT: |
||
452 | printf("%g ", v[i].f); |
||
453 | break; |
||
454 | case GLSL_TYPE_DOUBLE: |
||
455 | printf("%g ", *(double* )&v[i * 2].f); |
||
456 | break; |
||
457 | default: |
||
458 | assert(!"Should not get here."); |
||
459 | break; |
||
460 | } |
||
461 | } |
||
462 | printf("\n"); |
||
463 | fflush(stdout); |
||
464 | } |
||
465 | |||
466 | #if 0 |
||
467 | static void |
||
468 | log_program_parameters(const struct gl_shader_program *shProg) |
||
469 | { |
||
470 | for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { |
||
471 | if (shProg->_LinkedShaders[i] == NULL) |
||
472 | continue; |
||
473 | |||
474 | const struct gl_program *const prog = shProg->_LinkedShaders[i]->Program; |
||
475 | |||
476 | printf("Program %d %s shader parameters:\n", |
||
477 | shProg->Name, _mesa_shader_stage_to_string(i)); |
||
478 | for (unsigned j = 0; j < prog->Parameters->NumParameters; j++) { |
||
479 | printf("%s: %p %f %f %f %f\n", |
||
480 | prog->Parameters->Parameters[j].Name, |
||
481 | prog->Parameters->ParameterValues[j], |
||
482 | prog->Parameters->ParameterValues[j][0].f, |
||
483 | prog->Parameters->ParameterValues[j][1].f, |
||
484 | prog->Parameters->ParameterValues[j][2].f, |
||
485 | prog->Parameters->ParameterValues[j][3].f); |
||
486 | } |
||
487 | } |
||
488 | fflush(stdout); |
||
489 | } |
||
490 | #endif |
||
491 | |||
492 | /** |
||
493 | * Propagate some values from uniform backing storage to driver storage |
||
494 | * |
||
495 | * Values propagated from uniform backing storage to driver storage |
||
496 | * have all format / type conversions previously requested by the |
||
497 | * driver applied. This function is most often called by the |
||
498 | * implementations of \c glUniform1f, etc. and \c glUniformMatrix2f, |
||
499 | * etc. |
||
500 | * |
||
501 | * \param uni Uniform whose data is to be propagated to driver storage |
||
502 | * \param array_index If \c uni is an array, this is the element of |
||
503 | * the array to be propagated. |
||
504 | * \param count Number of array elements to propagate. |
||
505 | */ |
||
506 | extern "C" void |
||
507 | _mesa_propagate_uniforms_to_driver_storage(struct gl_uniform_storage *uni, |
||
508 | unsigned array_index, |
||
509 | unsigned count) |
||
510 | { |
||
511 | unsigned i; |
||
512 | |||
513 | /* vector_elements and matrix_columns can be 0 for samplers. |
||
514 | */ |
||
515 | const unsigned components = MAX2(1, uni->type->vector_elements); |
||
516 | const unsigned vectors = MAX2(1, uni->type->matrix_columns); |
||
517 | const int dmul = uni->type->base_type == GLSL_TYPE_DOUBLE ? 2 : 1; |
||
518 | |||
519 | /* Store the data in the driver's requested type in the driver's storage |
||
520 | * areas. |
||
521 | */ |
||
522 | unsigned src_vector_byte_stride = components * 4 * dmul; |
||
523 | |||
524 | for (i = 0; i < uni->num_driver_storage; i++) { |
||
525 | struct gl_uniform_driver_storage *const store = &uni->driver_storage[i]; |
||
526 | uint8_t *dst = (uint8_t *) store->data; |
||
527 | const unsigned extra_stride = |
||
528 | store->element_stride - (vectors * store->vector_stride); |
||
529 | const uint8_t *src = |
||
530 | (uint8_t *) (&uni->storage[array_index * (dmul * components * vectors)].i); |
||
531 | |||
532 | #if 0 |
||
533 | printf("%s: %p[%d] components=%u vectors=%u count=%u vector_stride=%u " |
||
534 | "extra_stride=%u\n", |
||
535 | __func__, dst, array_index, components, |
||
536 | vectors, count, store->vector_stride, extra_stride); |
||
537 | #endif |
||
538 | |||
539 | dst += array_index * store->element_stride; |
||
540 | |||
541 | switch (store->format) { |
||
542 | case uniform_native: { |
||
543 | unsigned j; |
||
544 | unsigned v; |
||
545 | |||
546 | for (j = 0; j < count; j++) { |
||
547 | for (v = 0; v < vectors; v++) { |
||
548 | memcpy(dst, src, src_vector_byte_stride); |
||
549 | src += src_vector_byte_stride; |
||
550 | dst += store->vector_stride; |
||
551 | } |
||
552 | |||
553 | dst += extra_stride; |
||
554 | } |
||
555 | break; |
||
556 | } |
||
557 | |||
558 | case uniform_int_float: { |
||
559 | const int *isrc = (const int *) src; |
||
560 | unsigned j; |
||
561 | unsigned v; |
||
562 | unsigned c; |
||
563 | |||
564 | for (j = 0; j < count; j++) { |
||
565 | for (v = 0; v < vectors; v++) { |
||
566 | for (c = 0; c < components; c++) { |
||
567 | ((float *) dst)[c] = (float) *isrc; |
||
568 | isrc++; |
||
569 | } |
||
570 | |||
571 | dst += store->vector_stride; |
||
572 | } |
||
573 | |||
574 | dst += extra_stride; |
||
575 | } |
||
576 | break; |
||
577 | } |
||
578 | |||
579 | default: |
||
580 | assert(!"Should not get here."); |
||
581 | break; |
||
582 | } |
||
583 | } |
||
584 | } |
||
585 | |||
586 | |||
587 | /** |
||
588 | * Return printable string for a given GLSL_TYPE_x |
||
589 | */ |
||
590 | static const char * |
||
591 | glsl_type_name(enum glsl_base_type type) |
||
592 | { |
||
593 | switch (type) { |
||
594 | case GLSL_TYPE_UINT: |
||
595 | return "uint"; |
||
596 | case GLSL_TYPE_INT: |
||
597 | return "int"; |
||
598 | case GLSL_TYPE_FLOAT: |
||
599 | return "float"; |
||
600 | case GLSL_TYPE_DOUBLE: |
||
601 | return "double"; |
||
602 | case GLSL_TYPE_BOOL: |
||
603 | return "bool"; |
||
604 | case GLSL_TYPE_SAMPLER: |
||
605 | return "sampler"; |
||
606 | case GLSL_TYPE_IMAGE: |
||
607 | return "image"; |
||
608 | case GLSL_TYPE_ATOMIC_UINT: |
||
609 | return "atomic_uint"; |
||
610 | case GLSL_TYPE_STRUCT: |
||
611 | return "struct"; |
||
612 | case GLSL_TYPE_INTERFACE: |
||
613 | return "interface"; |
||
614 | case GLSL_TYPE_ARRAY: |
||
615 | return "array"; |
||
616 | case GLSL_TYPE_VOID: |
||
617 | return "void"; |
||
618 | case GLSL_TYPE_ERROR: |
||
619 | return "error"; |
||
620 | default: |
||
621 | return "other"; |
||
622 | } |
||
623 | } |
||
624 | |||
625 | |||
626 | /** |
||
627 | * Called via glUniform*() functions. |
||
628 | */ |
||
629 | extern "C" void |
||
630 | _mesa_uniform(struct gl_context *ctx, struct gl_shader_program *shProg, |
||
631 | GLint location, GLsizei count, |
||
632 | const GLvoid *values, |
||
633 | enum glsl_base_type basicType, |
||
634 | unsigned src_components) |
||
635 | { |
||
636 | unsigned offset; |
||
637 | int size_mul = basicType == GLSL_TYPE_DOUBLE ? 2 : 1; |
||
638 | |||
639 | struct gl_uniform_storage *const uni = |
||
640 | validate_uniform_parameters(ctx, shProg, location, count, |
||
641 | &offset, "glUniform"); |
||
642 | if (uni == NULL) |
||
643 | return; |
||
644 | |||
645 | if (uni->type->is_matrix()) { |
||
646 | /* Can't set matrix uniforms (like mat4) with glUniform */ |
||
647 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
648 | "glUniform%u(uniform \"%s\"@%d is matrix)", |
||
649 | src_components, uni->name, location); |
||
650 | return; |
||
651 | } |
||
652 | |||
653 | /* Verify that the types are compatible. |
||
654 | */ |
||
655 | const unsigned components = uni->type->is_sampler() |
||
656 | ? 1 : uni->type->vector_elements; |
||
657 | |||
658 | if (components != src_components) { |
||
659 | /* glUniformN() must match float/vecN type */ |
||
660 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
661 | "glUniform%u(\"%s\"@%u has %u components, not %u)", |
||
662 | src_components, uni->name, location, |
||
663 | components, src_components); |
||
664 | return; |
||
665 | } |
||
666 | |||
667 | bool match; |
||
668 | switch (uni->type->base_type) { |
||
669 | case GLSL_TYPE_BOOL: |
||
670 | match = (basicType != GLSL_TYPE_DOUBLE); |
||
671 | break; |
||
672 | case GLSL_TYPE_SAMPLER: |
||
673 | case GLSL_TYPE_IMAGE: |
||
674 | match = (basicType == GLSL_TYPE_INT); |
||
675 | break; |
||
676 | default: |
||
677 | match = (basicType == uni->type->base_type); |
||
678 | break; |
||
679 | } |
||
680 | |||
681 | if (!match) { |
||
682 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
683 | "glUniform%u(\"%s\"@%d is %s, not %s)", |
||
684 | src_components, uni->name, location, |
||
685 | glsl_type_name(uni->type->base_type), |
||
686 | glsl_type_name(basicType)); |
||
687 | return; |
||
688 | } |
||
689 | |||
690 | if (unlikely(ctx->_Shader->Flags & GLSL_UNIFORMS)) { |
||
691 | log_uniform(values, basicType, components, 1, count, |
||
692 | false, shProg, location, uni); |
||
693 | } |
||
694 | |||
695 | /* Page 100 (page 116 of the PDF) of the OpenGL 3.0 spec says: |
||
696 | * |
||
697 | * "Setting a sampler's value to i selects texture image unit number |
||
698 | * i. The values of i range from zero to the implementation- dependent |
||
699 | * maximum supported number of texture image units." |
||
700 | * |
||
701 | * In addition, table 2.3, "Summary of GL errors," on page 17 (page 33 of |
||
702 | * the PDF) says: |
||
703 | * |
||
704 | * "Error Description Offending command |
||
705 | * ignored? |
||
706 | * ... |
||
707 | * INVALID_VALUE Numeric argument out of range Yes" |
||
708 | * |
||
709 | * Based on that, when an invalid sampler is specified, we generate a |
||
710 | * GL_INVALID_VALUE error and ignore the command. |
||
711 | */ |
||
712 | if (uni->type->is_sampler()) { |
||
713 | for (int i = 0; i < count; i++) { |
||
714 | const unsigned texUnit = ((unsigned *) values)[i]; |
||
715 | |||
716 | /* check that the sampler (tex unit index) is legal */ |
||
717 | if (texUnit >= ctx->Const.MaxCombinedTextureImageUnits) { |
||
718 | _mesa_error(ctx, GL_INVALID_VALUE, |
||
719 | "glUniform1i(invalid sampler/tex unit index for " |
||
720 | "uniform %d)", |
||
721 | location); |
||
722 | return; |
||
723 | } |
||
724 | } |
||
725 | } |
||
726 | |||
727 | if (uni->type->is_image()) { |
||
728 | for (int i = 0; i < count; i++) { |
||
729 | const int unit = ((GLint *) values)[i]; |
||
730 | |||
731 | /* check that the image unit is legal */ |
||
732 | if (unit < 0 || unit >= (int)ctx->Const.MaxImageUnits) { |
||
733 | _mesa_error(ctx, GL_INVALID_VALUE, |
||
734 | "glUniform1i(invalid image unit index for uniform %d)", |
||
735 | location); |
||
736 | return; |
||
737 | } |
||
738 | } |
||
739 | } |
||
740 | |||
741 | /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says: |
||
742 | * |
||
743 | * "When loading N elements starting at an arbitrary position k in a |
||
744 | * uniform declared as an array, elements k through k + N - 1 in the |
||
745 | * array will be replaced with the new values. Values for any array |
||
746 | * element that exceeds the highest array element index used, as |
||
747 | * reported by GetActiveUniform, will be ignored by the GL." |
||
748 | * |
||
749 | * Clamp 'count' to a valid value. Note that for non-arrays a count > 1 |
||
750 | * will have already generated an error. |
||
751 | */ |
||
752 | if (uni->array_elements != 0) { |
||
753 | count = MIN2(count, (int) (uni->array_elements - offset)); |
||
754 | } |
||
755 | |||
756 | FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); |
||
757 | |||
758 | /* Store the data in the "actual type" backing storage for the uniform. |
||
759 | */ |
||
760 | if (!uni->type->is_boolean()) { |
||
761 | memcpy(&uni->storage[size_mul * components * offset], values, |
||
762 | sizeof(uni->storage[0]) * components * count * size_mul); |
||
763 | } else { |
||
764 | const union gl_constant_value *src = |
||
765 | (const union gl_constant_value *) values; |
||
766 | union gl_constant_value *dst = &uni->storage[components * offset]; |
||
767 | const unsigned elems = components * count; |
||
768 | |||
769 | for (unsigned i = 0; i < elems; i++) { |
||
770 | if (basicType == GLSL_TYPE_FLOAT) { |
||
771 | dst[i].i = src[i].f != 0.0f ? ctx->Const.UniformBooleanTrue : 0; |
||
772 | } else { |
||
773 | dst[i].i = src[i].i != 0 ? ctx->Const.UniformBooleanTrue : 0; |
||
774 | } |
||
775 | } |
||
776 | } |
||
777 | |||
778 | uni->initialized = true; |
||
779 | |||
780 | _mesa_propagate_uniforms_to_driver_storage(uni, offset, count); |
||
781 | |||
782 | /* If the uniform is a sampler, do the extra magic necessary to propagate |
||
783 | * the changes through. |
||
784 | */ |
||
785 | if (uni->type->is_sampler()) { |
||
786 | bool flushed = false; |
||
787 | for (int i = 0; i < MESA_SHADER_STAGES; i++) { |
||
788 | struct gl_shader *const sh = shProg->_LinkedShaders[i]; |
||
789 | |||
790 | /* If the shader stage doesn't use the sampler uniform, skip this. |
||
791 | */ |
||
792 | if (sh == NULL || !uni->sampler[i].active) |
||
793 | continue; |
||
794 | |||
795 | for (int j = 0; j < count; j++) { |
||
796 | sh->SamplerUnits[uni->sampler[i].index + offset + j] = |
||
797 | ((unsigned *) values)[j]; |
||
798 | } |
||
799 | |||
800 | struct gl_program *const prog = sh->Program; |
||
801 | |||
802 | assert(sizeof(prog->SamplerUnits) == sizeof(sh->SamplerUnits)); |
||
803 | |||
804 | /* Determine if any of the samplers used by this shader stage have |
||
805 | * been modified. |
||
806 | */ |
||
807 | bool changed = false; |
||
808 | for (unsigned j = 0; j < ARRAY_SIZE(prog->SamplerUnits); j++) { |
||
809 | if ((sh->active_samplers & (1U << j)) != 0 |
||
810 | && (prog->SamplerUnits[j] != sh->SamplerUnits[j])) { |
||
811 | changed = true; |
||
812 | break; |
||
813 | } |
||
814 | } |
||
815 | |||
816 | if (changed) { |
||
817 | if (!flushed) { |
||
818 | FLUSH_VERTICES(ctx, _NEW_TEXTURE | _NEW_PROGRAM); |
||
819 | flushed = true; |
||
820 | } |
||
821 | |||
822 | memcpy(prog->SamplerUnits, |
||
823 | sh->SamplerUnits, |
||
824 | sizeof(sh->SamplerUnits)); |
||
825 | |||
826 | _mesa_update_shader_textures_used(shProg, prog); |
||
827 | if (ctx->Driver.SamplerUniformChange) |
||
828 | ctx->Driver.SamplerUniformChange(ctx, prog->Target, prog); |
||
829 | } |
||
830 | } |
||
831 | } |
||
832 | |||
833 | /* If the uniform is an image, update the mapping from image |
||
834 | * uniforms to image units present in the shader data structure. |
||
835 | */ |
||
836 | if (uni->type->is_image()) { |
||
837 | for (int i = 0; i < MESA_SHADER_STAGES; i++) { |
||
838 | if (uni->image[i].active) { |
||
839 | struct gl_shader *sh = shProg->_LinkedShaders[i]; |
||
840 | |||
841 | for (int j = 0; j < count; j++) |
||
842 | sh->ImageUnits[uni->image[i].index + offset + j] = |
||
843 | ((GLint *) values)[j]; |
||
844 | } |
||
845 | } |
||
846 | |||
847 | ctx->NewDriverState |= ctx->DriverFlags.NewImageUnits; |
||
848 | } |
||
849 | } |
||
850 | |||
851 | /** |
||
852 | * Called by glUniformMatrix*() functions. |
||
853 | * Note: cols=2, rows=4 ==> array[2] of vec4 |
||
854 | */ |
||
855 | extern "C" void |
||
856 | _mesa_uniform_matrix(struct gl_context *ctx, struct gl_shader_program *shProg, |
||
857 | GLuint cols, GLuint rows, |
||
858 | GLint location, GLsizei count, |
||
859 | GLboolean transpose, |
||
860 | const GLvoid *values, GLenum type) |
||
861 | { |
||
862 | unsigned offset; |
||
863 | unsigned vectors; |
||
864 | unsigned components; |
||
865 | unsigned elements; |
||
866 | int size_mul; |
||
867 | struct gl_uniform_storage *const uni = |
||
868 | validate_uniform_parameters(ctx, shProg, location, count, |
||
869 | &offset, "glUniformMatrix"); |
||
870 | if (uni == NULL) |
||
871 | return; |
||
872 | |||
873 | if (!uni->type->is_matrix()) { |
||
874 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
875 | "glUniformMatrix(non-matrix uniform)"); |
||
876 | return; |
||
877 | } |
||
878 | |||
879 | assert(type == GL_FLOAT || type == GL_DOUBLE); |
||
880 | size_mul = type == GL_DOUBLE ? 2 : 1; |
||
881 | |||
882 | assert(!uni->type->is_sampler()); |
||
883 | vectors = uni->type->matrix_columns; |
||
884 | components = uni->type->vector_elements; |
||
885 | |||
886 | /* Verify that the types are compatible. This is greatly simplified for |
||
887 | * matrices because they can only have a float base type. |
||
888 | */ |
||
889 | if (vectors != cols || components != rows) { |
||
890 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
891 | "glUniformMatrix(matrix size mismatch)"); |
||
892 | return; |
||
893 | } |
||
894 | |||
895 | /* GL_INVALID_VALUE is generated if `transpose' is not GL_FALSE. |
||
896 | * http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml |
||
897 | */ |
||
898 | if (transpose) { |
||
899 | if (ctx->API == API_OPENGLES2 && ctx->Version < 30) { |
||
900 | _mesa_error(ctx, GL_INVALID_VALUE, |
||
901 | "glUniformMatrix(matrix transpose is not GL_FALSE)"); |
||
902 | return; |
||
903 | } |
||
904 | } |
||
905 | |||
906 | if (unlikely(ctx->_Shader->Flags & GLSL_UNIFORMS)) { |
||
907 | log_uniform(values, uni->type->base_type, components, vectors, count, |
||
908 | bool(transpose), shProg, location, uni); |
||
909 | } |
||
910 | |||
911 | /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says: |
||
912 | * |
||
913 | * "When loading N elements starting at an arbitrary position k in a |
||
914 | * uniform declared as an array, elements k through k + N - 1 in the |
||
915 | * array will be replaced with the new values. Values for any array |
||
916 | * element that exceeds the highest array element index used, as |
||
917 | * reported by GetActiveUniform, will be ignored by the GL." |
||
918 | * |
||
919 | * Clamp 'count' to a valid value. Note that for non-arrays a count > 1 |
||
920 | * will have already generated an error. |
||
921 | */ |
||
922 | if (uni->array_elements != 0) { |
||
923 | count = MIN2(count, (int) (uni->array_elements - offset)); |
||
924 | } |
||
925 | |||
926 | FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); |
||
927 | |||
928 | /* Store the data in the "actual type" backing storage for the uniform. |
||
929 | */ |
||
930 | elements = components * vectors; |
||
931 | |||
932 | if (!transpose) { |
||
933 | memcpy(&uni->storage[elements * offset], values, |
||
934 | sizeof(uni->storage[0]) * elements * count * size_mul); |
||
935 | } else if (type == GL_FLOAT) { |
||
936 | /* Copy and transpose the matrix. |
||
937 | */ |
||
938 | const float *src = (const float *)values; |
||
939 | float *dst = &uni->storage[elements * offset].f; |
||
940 | |||
941 | for (int i = 0; i < count; i++) { |
||
942 | for (unsigned r = 0; r < rows; r++) { |
||
943 | for (unsigned c = 0; c < cols; c++) { |
||
944 | dst[(c * components) + r] = src[c + (r * vectors)]; |
||
945 | } |
||
946 | } |
||
947 | |||
948 | dst += elements; |
||
949 | src += elements; |
||
950 | } |
||
951 | } else { |
||
952 | assert(type == GL_DOUBLE); |
||
953 | const double *src = (const double *)values; |
||
954 | double *dst = (double *)&uni->storage[elements * offset].f; |
||
955 | |||
956 | for (int i = 0; i < count; i++) { |
||
957 | for (unsigned r = 0; r < rows; r++) { |
||
958 | for (unsigned c = 0; c < cols; c++) { |
||
959 | dst[(c * components) + r] = src[c + (r * vectors)]; |
||
960 | } |
||
961 | } |
||
962 | |||
963 | dst += elements; |
||
964 | src += elements; |
||
965 | } |
||
966 | } |
||
967 | |||
968 | uni->initialized = true; |
||
969 | |||
970 | _mesa_propagate_uniforms_to_driver_storage(uni, offset, count); |
||
971 | } |
||
972 | |||
973 | |||
974 | /** |
||
975 | * Called via glGetUniformLocation(). |
||
976 | * |
||
977 | * Returns the uniform index into UniformStorage (also the |
||
978 | * glGetActiveUniformsiv uniform index), and stores the referenced |
||
979 | * array offset in *offset, or GL_INVALID_INDEX (-1). |
||
980 | */ |
||
981 | extern "C" unsigned |
||
982 | _mesa_get_uniform_location(struct gl_shader_program *shProg, |
||
983 | const GLchar *name, |
||
984 | unsigned *out_offset) |
||
985 | { |
||
986 | /* Page 80 (page 94 of the PDF) of the OpenGL 2.1 spec says: |
||
987 | * |
||
988 | * "The first element of a uniform array is identified using the |
||
989 | * name of the uniform array appended with "[0]". Except if the last |
||
990 | * part of the string name indicates a uniform array, then the |
||
991 | * location of the first element of that array can be retrieved by |
||
992 | * either using the name of the uniform array, or the name of the |
||
993 | * uniform array appended with "[0]"." |
||
994 | * |
||
995 | * Note: since uniform names are not allowed to use whitespace, and array |
||
996 | * indices within uniform names are not allowed to use "+", "-", or leading |
||
997 | * zeros, it follows that each uniform has a unique name up to the possible |
||
998 | * ambiguity with "[0]" noted above. Therefore we don't need to worry |
||
999 | * about mal-formed inputs--they will properly fail when we try to look up |
||
1000 | * the uniform name in shProg->UniformHash. |
||
1001 | */ |
||
1002 | |||
1003 | const GLchar *base_name_end; |
||
1004 | long offset = parse_program_resource_name(name, &base_name_end); |
||
1005 | bool array_lookup = offset >= 0; |
||
1006 | char *name_copy; |
||
1007 | |||
1008 | if (array_lookup) { |
||
1009 | name_copy = (char *) malloc(base_name_end - name + 1); |
||
1010 | memcpy(name_copy, name, base_name_end - name); |
||
1011 | name_copy[base_name_end - name] = '\0'; |
||
1012 | } else { |
||
1013 | name_copy = (char *) name; |
||
1014 | offset = 0; |
||
1015 | } |
||
1016 | |||
1017 | unsigned location = 0; |
||
1018 | const bool found = shProg->UniformHash->get(location, name_copy); |
||
1019 | |||
1020 | assert(!found |
||
1021 | || strcmp(name_copy, shProg->UniformStorage[location].name) == 0); |
||
1022 | |||
1023 | /* Free the temporary buffer *before* possibly returning an error. |
||
1024 | */ |
||
1025 | if (name_copy != name) |
||
1026 | free(name_copy); |
||
1027 | |||
1028 | if (!found) |
||
1029 | return GL_INVALID_INDEX; |
||
1030 | |||
1031 | /* If the uniform is an array, fail if the index is out of bounds. |
||
1032 | * (A negative index is caught above.) This also fails if the uniform |
||
1033 | * is not an array, but the user is trying to index it, because |
||
1034 | * array_elements is zero and offset >= 0. |
||
1035 | */ |
||
1036 | if (array_lookup |
||
1037 | && offset >= (long) shProg->UniformStorage[location].array_elements) { |
||
1038 | return GL_INVALID_INDEX; |
||
1039 | } |
||
1040 | |||
1041 | *out_offset = offset; |
||
1042 | return location; |
||
1043 | } |
||
1044 | |||
1045 | extern "C" bool |
||
1046 | _mesa_sampler_uniforms_are_valid(const struct gl_shader_program *shProg, |
||
1047 | char *errMsg, size_t errMsgLength) |
||
1048 | { |
||
1049 | /* Shader does not have samplers. */ |
||
1050 | if (shProg->NumUserUniformStorage == 0) |
||
1051 | return true; |
||
1052 | |||
1053 | if (!shProg->SamplersValidated) { |
||
1054 | _mesa_snprintf(errMsg, errMsgLength, |
||
1055 | "active samplers with a different type " |
||
1056 | "refer to the same texture image unit"); |
||
1057 | return false; |
||
1058 | } |
||
1059 | return true; |
||
1060 | } |
||
1061 | |||
1062 | extern "C" bool |
||
1063 | _mesa_sampler_uniforms_pipeline_are_valid(struct gl_pipeline_object *pipeline) |
||
1064 | { |
||
1065 | /* Section 2.11.11 (Shader Execution), subheading "Validation," of the |
||
1066 | * OpenGL 4.1 spec says: |
||
1067 | * |
||
1068 | * "[INVALID_OPERATION] is generated by any command that transfers |
||
1069 | * vertices to the GL if: |
||
1070 | * |
||
1071 | * ... |
||
1072 | * |
||
1073 | * - Any two active samplers in the current program object are of |
||
1074 | * different types, but refer to the same texture image unit. |
||
1075 | * |
||
1076 | * - The number of active samplers in the program exceeds the |
||
1077 | * maximum number of texture image units allowed." |
||
1078 | */ |
||
1079 | unsigned active_samplers = 0; |
||
1080 | const struct gl_shader_program **shProg = |
||
1081 | (const struct gl_shader_program **) pipeline->CurrentProgram; |
||
1082 | |||
1083 | const glsl_type *unit_types[MAX_COMBINED_TEXTURE_IMAGE_UNITS]; |
||
1084 | memset(unit_types, 0, sizeof(unit_types)); |
||
1085 | |||
1086 | for (unsigned idx = 0; idx < ARRAY_SIZE(pipeline->CurrentProgram); idx++) { |
||
1087 | if (!shProg[idx]) |
||
1088 | continue; |
||
1089 | |||
1090 | for (unsigned i = 0; i < shProg[idx]->NumUserUniformStorage; i++) { |
||
1091 | const struct gl_uniform_storage *const storage = |
||
1092 | &shProg[idx]->UniformStorage[i]; |
||
1093 | const glsl_type *const t = (storage->type->is_array()) |
||
1094 | ? storage->type->fields.array : storage->type; |
||
1095 | |||
1096 | if (!t->is_sampler()) |
||
1097 | continue; |
||
1098 | |||
1099 | active_samplers++; |
||
1100 | |||
1101 | const unsigned count = MAX2(1, storage->type->array_size()); |
||
1102 | for (unsigned j = 0; j < count; j++) { |
||
1103 | const unsigned unit = storage->storage[j].i; |
||
1104 | |||
1105 | /* The types of the samplers associated with a particular texture |
||
1106 | * unit must be an exact match. Page 74 (page 89 of the PDF) of |
||
1107 | * the OpenGL 3.3 core spec says: |
||
1108 | * |
||
1109 | * "It is not allowed to have variables of different sampler |
||
1110 | * types pointing to the same texture image unit within a |
||
1111 | * program object." |
||
1112 | */ |
||
1113 | if (unit_types[unit] == NULL) { |
||
1114 | unit_types[unit] = t; |
||
1115 | } else if (unit_types[unit] != t) { |
||
1116 | pipeline->InfoLog = |
||
1117 | ralloc_asprintf(pipeline, |
||
1118 | "Texture unit %d is accessed both as %s " |
||
1119 | "and %s", |
||
1120 | unit, unit_types[unit]->name, t->name); |
||
1121 | return false; |
||
1122 | } |
||
1123 | } |
||
1124 | } |
||
1125 | } |
||
1126 | |||
1127 | if (active_samplers > MAX_COMBINED_TEXTURE_IMAGE_UNITS) { |
||
1128 | pipeline->InfoLog = |
||
1129 | ralloc_asprintf(pipeline, |
||
1130 | "the number of active samplers %d exceed the " |
||
1131 | "maximum %d", |
||
1132 | active_samplers, MAX_COMBINED_TEXTURE_IMAGE_UNITS); |
||
1133 | return false; |
||
1134 | } |
||
1135 | |||
1136 | return true; |
||
1137 | }>>>>>>>>>>>>><>>>>>>>>>>>>>>>>>>>>>>>>>>>> |