Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4358 | 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(GLhandleARB 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 | _mesa_lookup_shader_program_err(ctx, program, "glGetActiveUniform"); |
||
50 | |||
51 | if (!shProg) |
||
52 | return; |
||
53 | |||
54 | if (index >= shProg->NumUserUniformStorage) { |
||
55 | _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)"); |
||
56 | return; |
||
57 | } |
||
58 | |||
59 | const struct gl_uniform_storage *const uni = &shProg->UniformStorage[index]; |
||
60 | |||
61 | if (nameOut) { |
||
62 | _mesa_get_uniform_name(uni, maxLength, length, nameOut); |
||
63 | } |
||
64 | |||
65 | if (size) { |
||
66 | /* array_elements is zero for non-arrays, but the API requires that 1 be |
||
67 | * returned. |
||
68 | */ |
||
69 | *size = MAX2(1, uni->array_elements); |
||
70 | } |
||
71 | |||
72 | if (type) { |
||
73 | *type = uni->type->gl_type; |
||
74 | } |
||
75 | } |
||
76 | |||
77 | extern "C" void GLAPIENTRY |
||
78 | _mesa_GetActiveUniformsiv(GLuint program, |
||
79 | GLsizei uniformCount, |
||
80 | const GLuint *uniformIndices, |
||
81 | GLenum pname, |
||
82 | GLint *params) |
||
83 | { |
||
84 | GET_CURRENT_CONTEXT(ctx); |
||
85 | struct gl_shader_program *shProg; |
||
86 | GLsizei i; |
||
87 | |||
88 | shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveUniform"); |
||
89 | if (!shProg) |
||
90 | return; |
||
91 | |||
92 | if (uniformCount < 0) { |
||
93 | _mesa_error(ctx, GL_INVALID_VALUE, |
||
94 | "glGetUniformIndices(uniformCount < 0)"); |
||
95 | return; |
||
96 | } |
||
97 | |||
98 | for (i = 0; i < uniformCount; i++) { |
||
99 | GLuint index = uniformIndices[i]; |
||
100 | |||
101 | if (index >= shProg->NumUserUniformStorage) { |
||
102 | _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniformsiv(index)"); |
||
103 | return; |
||
104 | } |
||
105 | } |
||
106 | |||
107 | for (i = 0; i < uniformCount; i++) { |
||
108 | GLuint index = uniformIndices[i]; |
||
109 | const struct gl_uniform_storage *uni = &shProg->UniformStorage[index]; |
||
110 | |||
111 | switch (pname) { |
||
112 | case GL_UNIFORM_TYPE: |
||
113 | params[i] = uni->type->gl_type; |
||
114 | break; |
||
115 | |||
116 | case GL_UNIFORM_SIZE: |
||
117 | /* array_elements is zero for non-arrays, but the API requires that 1 be |
||
118 | * returned. |
||
119 | */ |
||
120 | params[i] = MAX2(1, uni->array_elements); |
||
121 | break; |
||
122 | |||
123 | case GL_UNIFORM_NAME_LENGTH: |
||
124 | params[i] = strlen(uni->name) + 1; |
||
125 | |||
126 | /* Page 61 (page 73 of the PDF) in section 2.11 of the OpenGL ES 3.0 |
||
127 | * spec says: |
||
128 | * |
||
129 | * "If the active uniform is an array, the uniform name returned |
||
130 | * in name will always be the name of the uniform array appended |
||
131 | * with "[0]"." |
||
132 | */ |
||
133 | if (uni->array_elements != 0) |
||
134 | params[i] += 3; |
||
135 | break; |
||
136 | |||
137 | case GL_UNIFORM_BLOCK_INDEX: |
||
138 | params[i] = uni->block_index; |
||
139 | break; |
||
140 | |||
141 | case GL_UNIFORM_OFFSET: |
||
142 | params[i] = uni->offset; |
||
143 | break; |
||
144 | |||
145 | case GL_UNIFORM_ARRAY_STRIDE: |
||
146 | params[i] = uni->array_stride; |
||
147 | break; |
||
148 | |||
149 | case GL_UNIFORM_MATRIX_STRIDE: |
||
150 | params[i] = uni->matrix_stride; |
||
151 | break; |
||
152 | |||
153 | case GL_UNIFORM_IS_ROW_MAJOR: |
||
154 | params[i] = uni->row_major; |
||
155 | break; |
||
156 | |||
157 | default: |
||
158 | _mesa_error(ctx, GL_INVALID_ENUM, "glGetActiveUniformsiv(pname)"); |
||
159 | return; |
||
160 | } |
||
161 | } |
||
162 | } |
||
163 | |||
164 | static bool |
||
165 | validate_uniform_parameters(struct gl_context *ctx, |
||
166 | struct gl_shader_program *shProg, |
||
167 | GLint location, GLsizei count, |
||
168 | unsigned *loc, |
||
169 | unsigned *array_index, |
||
170 | const char *caller, |
||
171 | bool negative_one_is_not_valid) |
||
172 | { |
||
173 | if (!shProg || !shProg->LinkStatus) { |
||
174 | _mesa_error(ctx, GL_INVALID_OPERATION, "%s(program not linked)", caller); |
||
175 | return false; |
||
176 | } |
||
177 | |||
178 | if (location == -1) { |
||
179 | /* For glGetUniform, page 264 (page 278 of the PDF) of the OpenGL 2.1 |
||
180 | * spec says: |
||
181 | * |
||
182 | * "The error INVALID_OPERATION is generated if program has not been |
||
183 | * linked successfully, or if location is not a valid location for |
||
184 | * program." |
||
185 | * |
||
186 | * For glUniform, page 82 (page 96 of the PDF) of the OpenGL 2.1 spec |
||
187 | * says: |
||
188 | * |
||
189 | * "If the value of location is -1, the Uniform* commands will |
||
190 | * silently ignore the data passed in, and the current uniform |
||
191 | * values will not be changed." |
||
192 | * |
||
193 | * Allowing -1 for the location parameter of glUniform allows |
||
194 | * applications to avoid error paths in the case that, for example, some |
||
195 | * uniform variable is removed by the compiler / linker after |
||
196 | * optimization. In this case, the new value of the uniform is dropped |
||
197 | * on the floor. For the case of glGetUniform, there is nothing |
||
198 | * sensible to do for a location of -1. |
||
199 | * |
||
200 | * The negative_one_is_not_valid flag selects between the two behaviors. |
||
201 | */ |
||
202 | if (negative_one_is_not_valid) { |
||
203 | _mesa_error(ctx, GL_INVALID_OPERATION, "%s(location=%d)", |
||
204 | caller, location); |
||
205 | } |
||
206 | |||
207 | return false; |
||
208 | } |
||
209 | |||
210 | /* From page 12 (page 26 of the PDF) of the OpenGL 2.1 spec: |
||
211 | * |
||
212 | * "If a negative number is provided where an argument of type sizei or |
||
213 | * sizeiptr is specified, the error INVALID_VALUE is generated." |
||
214 | */ |
||
215 | if (count < 0) { |
||
216 | _mesa_error(ctx, GL_INVALID_VALUE, "%s(count < 0)", caller); |
||
217 | return false; |
||
218 | } |
||
219 | |||
220 | /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says: |
||
221 | * |
||
222 | * "If any of the following conditions occur, an INVALID_OPERATION |
||
223 | * error is generated by the Uniform* commands, and no uniform values |
||
224 | * are changed: |
||
225 | * |
||
226 | * ... |
||
227 | * |
||
228 | * - if no variable with a location of location exists in the |
||
229 | * program object currently in use and location is not -1, |
||
230 | * - if count is greater than one, and the uniform declared in the |
||
231 | * shader is not an array variable, |
||
232 | */ |
||
233 | if (location < -1) { |
||
234 | _mesa_error(ctx, GL_INVALID_OPERATION, "%s(location=%d)", |
||
235 | caller, location); |
||
236 | return false; |
||
237 | } |
||
238 | |||
239 | _mesa_uniform_split_location_offset(shProg, location, loc, array_index); |
||
240 | |||
241 | if (*loc >= shProg->NumUserUniformStorage) { |
||
242 | _mesa_error(ctx, GL_INVALID_OPERATION, "%s(location=%d)", |
||
243 | caller, location); |
||
244 | return false; |
||
245 | } |
||
246 | |||
247 | if (shProg->UniformStorage[*loc].array_elements == 0 && count > 1) { |
||
248 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
249 | "%s(count > 1 for non-array, location=%d)", |
||
250 | caller, location); |
||
251 | return false; |
||
252 | } |
||
253 | |||
254 | /* If the uniform is an array, check that array_index is in bounds. |
||
255 | * If not an array, check that array_index is zero. |
||
256 | * array_index is unsigned so no need to check for less than zero. |
||
257 | */ |
||
258 | unsigned limit = shProg->UniformStorage[*loc].array_elements; |
||
259 | if (limit == 0) |
||
260 | limit = 1; |
||
261 | if (*array_index >= limit) { |
||
262 | _mesa_error(ctx, GL_INVALID_OPERATION, "%s(location=%d)", |
||
263 | caller, location); |
||
264 | return false; |
||
265 | } |
||
266 | return true; |
||
267 | } |
||
268 | |||
269 | /** |
||
270 | * Called via glGetUniform[fiui]v() to get the current value of a uniform. |
||
271 | */ |
||
272 | extern "C" void |
||
273 | _mesa_get_uniform(struct gl_context *ctx, GLuint program, GLint location, |
||
274 | GLsizei bufSize, enum glsl_base_type returnType, |
||
275 | GLvoid *paramsOut) |
||
276 | { |
||
277 | struct gl_shader_program *shProg = |
||
278 | _mesa_lookup_shader_program_err(ctx, program, "glGetUniformfv"); |
||
279 | struct gl_uniform_storage *uni; |
||
280 | unsigned loc, offset; |
||
281 | |||
282 | if (!validate_uniform_parameters(ctx, shProg, location, 1, |
||
283 | &loc, &offset, "glGetUniform", true)) |
||
284 | return; |
||
285 | |||
286 | uni = &shProg->UniformStorage[loc]; |
||
287 | |||
288 | { |
||
289 | unsigned elements = (uni->type->is_sampler()) |
||
290 | ? 1 : uni->type->components(); |
||
291 | |||
292 | /* Calculate the source base address *BEFORE* modifying elements to |
||
293 | * account for the size of the user's buffer. |
||
294 | */ |
||
295 | const union gl_constant_value *const src = |
||
296 | &uni->storage[offset * elements]; |
||
297 | |||
298 | assert(returnType == GLSL_TYPE_FLOAT || returnType == GLSL_TYPE_INT || |
||
299 | returnType == GLSL_TYPE_UINT); |
||
300 | /* The three (currently) supported types all have the same size, |
||
301 | * which is of course the same as their union. That'll change |
||
302 | * with glGetUniformdv()... |
||
303 | */ |
||
304 | unsigned bytes = sizeof(src[0]) * elements; |
||
305 | if (bufSize < 0 || bytes > (unsigned) bufSize) { |
||
306 | _mesa_error( ctx, GL_INVALID_OPERATION, |
||
307 | "glGetnUniform*vARB(out of bounds: bufSize is %d," |
||
308 | " but %u bytes are required)", bufSize, bytes ); |
||
309 | return; |
||
310 | } |
||
311 | |||
312 | /* If the return type and the uniform's native type are "compatible," |
||
313 | * just memcpy the data. If the types are not compatible, perform a |
||
314 | * slower convert-and-copy process. |
||
315 | */ |
||
316 | if (returnType == uni->type->base_type |
||
317 | || ((returnType == GLSL_TYPE_INT |
||
318 | || returnType == GLSL_TYPE_UINT |
||
319 | || returnType == GLSL_TYPE_SAMPLER) |
||
320 | && |
||
321 | (uni->type->base_type == GLSL_TYPE_INT |
||
322 | || uni->type->base_type == GLSL_TYPE_UINT |
||
323 | || uni->type->base_type == GLSL_TYPE_SAMPLER))) { |
||
324 | memcpy(paramsOut, src, bytes); |
||
325 | } else { |
||
326 | union gl_constant_value *const dst = |
||
327 | (union gl_constant_value *) paramsOut; |
||
328 | |||
329 | /* This code could be optimized by putting the loop inside the switch |
||
330 | * statements. However, this is not expected to be |
||
331 | * performance-critical code. |
||
332 | */ |
||
333 | for (unsigned i = 0; i < elements; i++) { |
||
334 | switch (returnType) { |
||
335 | case GLSL_TYPE_FLOAT: |
||
336 | switch (uni->type->base_type) { |
||
337 | case GLSL_TYPE_UINT: |
||
338 | dst[i].f = (float) src[i].u; |
||
339 | break; |
||
340 | case GLSL_TYPE_INT: |
||
341 | case GLSL_TYPE_SAMPLER: |
||
342 | dst[i].f = (float) src[i].i; |
||
343 | break; |
||
344 | case GLSL_TYPE_BOOL: |
||
345 | dst[i].f = src[i].i ? 1.0f : 0.0f; |
||
346 | break; |
||
347 | default: |
||
348 | assert(!"Should not get here."); |
||
349 | break; |
||
350 | } |
||
351 | break; |
||
352 | |||
353 | case GLSL_TYPE_INT: |
||
354 | case GLSL_TYPE_UINT: |
||
355 | switch (uni->type->base_type) { |
||
356 | case GLSL_TYPE_FLOAT: |
||
357 | /* While the GL 3.2 core spec doesn't explicitly |
||
358 | * state how conversion of float uniforms to integer |
||
359 | * values works, in section 6.2 "State Tables" on |
||
360 | * page 267 it says: |
||
361 | * |
||
362 | * "Unless otherwise specified, when floating |
||
363 | * point state is returned as integer values or |
||
364 | * integer state is returned as floating-point |
||
365 | * values it is converted in the fashion |
||
366 | * described in section 6.1.2" |
||
367 | * |
||
368 | * That section, on page 248, says: |
||
369 | * |
||
370 | * "If GetIntegerv or GetInteger64v are called, |
||
371 | * a floating-point value is rounded to the |
||
372 | * nearest integer..." |
||
373 | */ |
||
374 | dst[i].i = IROUND(src[i].f); |
||
375 | break; |
||
376 | case GLSL_TYPE_BOOL: |
||
377 | dst[i].i = src[i].i ? 1 : 0; |
||
378 | break; |
||
379 | default: |
||
380 | assert(!"Should not get here."); |
||
381 | break; |
||
382 | } |
||
383 | break; |
||
384 | |||
385 | default: |
||
386 | assert(!"Should not get here."); |
||
387 | break; |
||
388 | } |
||
389 | } |
||
390 | } |
||
391 | } |
||
392 | } |
||
393 | |||
394 | static void |
||
395 | log_uniform(const void *values, enum glsl_base_type basicType, |
||
396 | unsigned rows, unsigned cols, unsigned count, |
||
397 | bool transpose, |
||
398 | const struct gl_shader_program *shProg, |
||
399 | GLint location, |
||
400 | const struct gl_uniform_storage *uni) |
||
401 | { |
||
402 | |||
403 | const union gl_constant_value *v = (const union gl_constant_value *) values; |
||
404 | const unsigned elems = rows * cols * count; |
||
405 | const char *const extra = (cols == 1) ? "uniform" : "uniform matrix"; |
||
406 | |||
407 | printf("Mesa: set program %u %s \"%s\" (loc %d, type \"%s\", " |
||
408 | "transpose = %s) to: ", |
||
409 | shProg->Name, extra, uni->name, location, uni->type->name, |
||
410 | transpose ? "true" : "false"); |
||
411 | for (unsigned i = 0; i < elems; i++) { |
||
412 | if (i != 0 && ((i % rows) == 0)) |
||
413 | printf(", "); |
||
414 | |||
415 | switch (basicType) { |
||
416 | case GLSL_TYPE_UINT: |
||
417 | printf("%u ", v[i].u); |
||
418 | break; |
||
419 | case GLSL_TYPE_INT: |
||
420 | printf("%d ", v[i].i); |
||
421 | break; |
||
422 | case GLSL_TYPE_FLOAT: |
||
423 | printf("%g ", v[i].f); |
||
424 | break; |
||
425 | default: |
||
426 | assert(!"Should not get here."); |
||
427 | break; |
||
428 | } |
||
429 | } |
||
430 | printf("\n"); |
||
431 | fflush(stdout); |
||
432 | } |
||
433 | |||
434 | #if 0 |
||
435 | static void |
||
436 | log_program_parameters(const struct gl_shader_program *shProg) |
||
437 | { |
||
438 | for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) { |
||
439 | if (shProg->_LinkedShaders[i] == NULL) |
||
440 | continue; |
||
441 | |||
442 | const struct gl_program *const prog = shProg->_LinkedShaders[i]->Program; |
||
443 | |||
444 | printf("Program %d %s shader parameters:\n", |
||
445 | shProg->Name, _mesa_glsl_shader_target_name(prog->Target)); |
||
446 | for (unsigned j = 0; j < prog->Parameters->NumParameters; j++) { |
||
447 | printf("%s: %p %f %f %f %f\n", |
||
448 | prog->Parameters->Parameters[j].Name, |
||
449 | prog->Parameters->ParameterValues[j], |
||
450 | prog->Parameters->ParameterValues[j][0].f, |
||
451 | prog->Parameters->ParameterValues[j][1].f, |
||
452 | prog->Parameters->ParameterValues[j][2].f, |
||
453 | prog->Parameters->ParameterValues[j][3].f); |
||
454 | } |
||
455 | } |
||
456 | fflush(stdout); |
||
457 | } |
||
458 | #endif |
||
459 | |||
460 | /** |
||
461 | * Propagate some values from uniform backing storage to driver storage |
||
462 | * |
||
463 | * Values propagated from uniform backing storage to driver storage |
||
464 | * have all format / type conversions previously requested by the |
||
465 | * driver applied. This function is most often called by the |
||
466 | * implementations of \c glUniform1f, etc. and \c glUniformMatrix2f, |
||
467 | * etc. |
||
468 | * |
||
469 | * \param uni Uniform whose data is to be propagated to driver storage |
||
470 | * \param array_index If \c uni is an array, this is the element of |
||
471 | * the array to be propagated. |
||
472 | * \param count Number of array elements to propagate. |
||
473 | */ |
||
474 | extern "C" void |
||
475 | _mesa_propagate_uniforms_to_driver_storage(struct gl_uniform_storage *uni, |
||
476 | unsigned array_index, |
||
477 | unsigned count) |
||
478 | { |
||
479 | unsigned i; |
||
480 | |||
481 | /* vector_elements and matrix_columns can be 0 for samplers. |
||
482 | */ |
||
483 | const unsigned components = MAX2(1, uni->type->vector_elements); |
||
484 | const unsigned vectors = MAX2(1, uni->type->matrix_columns); |
||
485 | |||
486 | /* Store the data in the driver's requested type in the driver's storage |
||
487 | * areas. |
||
488 | */ |
||
489 | unsigned src_vector_byte_stride = components * 4; |
||
490 | |||
491 | for (i = 0; i < uni->num_driver_storage; i++) { |
||
492 | struct gl_uniform_driver_storage *const store = &uni->driver_storage[i]; |
||
493 | uint8_t *dst = (uint8_t *) store->data; |
||
494 | const unsigned extra_stride = |
||
495 | store->element_stride - (vectors * store->vector_stride); |
||
496 | const uint8_t *src = |
||
497 | (uint8_t *) (&uni->storage[array_index * (components * vectors)].i); |
||
498 | |||
499 | #if 0 |
||
500 | printf("%s: %p[%d] components=%u vectors=%u count=%u vector_stride=%u " |
||
501 | "extra_stride=%u\n", |
||
502 | __func__, dst, array_index, components, |
||
503 | vectors, count, store->vector_stride, extra_stride); |
||
504 | #endif |
||
505 | |||
506 | dst += array_index * store->element_stride; |
||
507 | |||
508 | switch (store->format) { |
||
509 | case uniform_native: |
||
510 | case uniform_bool_int_0_1: { |
||
511 | unsigned j; |
||
512 | unsigned v; |
||
513 | |||
514 | for (j = 0; j < count; j++) { |
||
515 | for (v = 0; v < vectors; v++) { |
||
516 | memcpy(dst, src, src_vector_byte_stride); |
||
517 | src += src_vector_byte_stride; |
||
518 | dst += store->vector_stride; |
||
519 | } |
||
520 | |||
521 | dst += extra_stride; |
||
522 | } |
||
523 | break; |
||
524 | } |
||
525 | |||
526 | case uniform_int_float: |
||
527 | case uniform_bool_float: { |
||
528 | const int *isrc = (const int *) src; |
||
529 | unsigned j; |
||
530 | unsigned v; |
||
531 | unsigned c; |
||
532 | |||
533 | for (j = 0; j < count; j++) { |
||
534 | for (v = 0; v < vectors; v++) { |
||
535 | for (c = 0; c < components; c++) { |
||
536 | ((float *) dst)[c] = (float) *isrc; |
||
537 | isrc++; |
||
538 | } |
||
539 | |||
540 | dst += store->vector_stride; |
||
541 | } |
||
542 | |||
543 | dst += extra_stride; |
||
544 | } |
||
545 | break; |
||
546 | } |
||
547 | |||
548 | case uniform_bool_int_0_not0: { |
||
549 | const int *isrc = (const int *) src; |
||
550 | unsigned j; |
||
551 | unsigned v; |
||
552 | unsigned c; |
||
553 | |||
554 | for (j = 0; j < count; j++) { |
||
555 | for (v = 0; v < vectors; v++) { |
||
556 | for (c = 0; c < components; c++) { |
||
557 | ((int *) dst)[c] = *isrc == 0 ? 0 : ~0; |
||
558 | isrc++; |
||
559 | } |
||
560 | |||
561 | dst += store->vector_stride; |
||
562 | } |
||
563 | |||
564 | dst += extra_stride; |
||
565 | } |
||
566 | break; |
||
567 | } |
||
568 | |||
569 | default: |
||
570 | assert(!"Should not get here."); |
||
571 | break; |
||
572 | } |
||
573 | } |
||
574 | } |
||
575 | |||
576 | /** |
||
577 | * Called via glUniform*() functions. |
||
578 | */ |
||
579 | extern "C" void |
||
580 | _mesa_uniform(struct gl_context *ctx, struct gl_shader_program *shProg, |
||
581 | GLint location, GLsizei count, |
||
582 | const GLvoid *values, GLenum type) |
||
583 | { |
||
584 | unsigned loc, offset; |
||
585 | unsigned components; |
||
586 | unsigned src_components; |
||
587 | enum glsl_base_type basicType; |
||
588 | struct gl_uniform_storage *uni; |
||
589 | |||
590 | if (!validate_uniform_parameters(ctx, shProg, location, count, |
||
591 | &loc, &offset, "glUniform", false)) |
||
592 | return; |
||
593 | |||
594 | uni = &shProg->UniformStorage[loc]; |
||
595 | |||
596 | /* Verify that the types are compatible. |
||
597 | */ |
||
598 | switch (type) { |
||
599 | case GL_FLOAT: |
||
600 | basicType = GLSL_TYPE_FLOAT; |
||
601 | src_components = 1; |
||
602 | break; |
||
603 | case GL_FLOAT_VEC2: |
||
604 | basicType = GLSL_TYPE_FLOAT; |
||
605 | src_components = 2; |
||
606 | break; |
||
607 | case GL_FLOAT_VEC3: |
||
608 | basicType = GLSL_TYPE_FLOAT; |
||
609 | src_components = 3; |
||
610 | break; |
||
611 | case GL_FLOAT_VEC4: |
||
612 | basicType = GLSL_TYPE_FLOAT; |
||
613 | src_components = 4; |
||
614 | break; |
||
615 | case GL_UNSIGNED_INT: |
||
616 | basicType = GLSL_TYPE_UINT; |
||
617 | src_components = 1; |
||
618 | break; |
||
619 | case GL_UNSIGNED_INT_VEC2: |
||
620 | basicType = GLSL_TYPE_UINT; |
||
621 | src_components = 2; |
||
622 | break; |
||
623 | case GL_UNSIGNED_INT_VEC3: |
||
624 | basicType = GLSL_TYPE_UINT; |
||
625 | src_components = 3; |
||
626 | break; |
||
627 | case GL_UNSIGNED_INT_VEC4: |
||
628 | basicType = GLSL_TYPE_UINT; |
||
629 | src_components = 4; |
||
630 | break; |
||
631 | case GL_INT: |
||
632 | basicType = GLSL_TYPE_INT; |
||
633 | src_components = 1; |
||
634 | break; |
||
635 | case GL_INT_VEC2: |
||
636 | basicType = GLSL_TYPE_INT; |
||
637 | src_components = 2; |
||
638 | break; |
||
639 | case GL_INT_VEC3: |
||
640 | basicType = GLSL_TYPE_INT; |
||
641 | src_components = 3; |
||
642 | break; |
||
643 | case GL_INT_VEC4: |
||
644 | basicType = GLSL_TYPE_INT; |
||
645 | src_components = 4; |
||
646 | break; |
||
647 | case GL_BOOL: |
||
648 | case GL_BOOL_VEC2: |
||
649 | case GL_BOOL_VEC3: |
||
650 | case GL_BOOL_VEC4: |
||
651 | case GL_FLOAT_MAT2: |
||
652 | case GL_FLOAT_MAT2x3: |
||
653 | case GL_FLOAT_MAT2x4: |
||
654 | case GL_FLOAT_MAT3x2: |
||
655 | case GL_FLOAT_MAT3: |
||
656 | case GL_FLOAT_MAT3x4: |
||
657 | case GL_FLOAT_MAT4x2: |
||
658 | case GL_FLOAT_MAT4x3: |
||
659 | case GL_FLOAT_MAT4: |
||
660 | default: |
||
661 | _mesa_problem(NULL, "Invalid type in %s", __func__); |
||
662 | return; |
||
663 | } |
||
664 | |||
665 | if (uni->type->is_sampler()) { |
||
666 | components = 1; |
||
667 | } else { |
||
668 | components = uni->type->vector_elements; |
||
669 | } |
||
670 | |||
671 | bool match; |
||
672 | switch (uni->type->base_type) { |
||
673 | case GLSL_TYPE_BOOL: |
||
674 | match = true; |
||
675 | break; |
||
676 | case GLSL_TYPE_SAMPLER: |
||
677 | match = (basicType == GLSL_TYPE_INT); |
||
678 | break; |
||
679 | default: |
||
680 | match = (basicType == uni->type->base_type); |
||
681 | break; |
||
682 | } |
||
683 | |||
684 | if (uni->type->is_matrix() || components != src_components || !match) { |
||
685 | _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)"); |
||
686 | return; |
||
687 | } |
||
688 | |||
689 | if (ctx->Shader.Flags & GLSL_UNIFORMS) { |
||
690 | log_uniform(values, basicType, components, 1, count, |
||
691 | false, shProg, location, uni); |
||
692 | } |
||
693 | |||
694 | /* Page 100 (page 116 of the PDF) of the OpenGL 3.0 spec says: |
||
695 | * |
||
696 | * "Setting a sampler's value to i selects texture image unit number |
||
697 | * i. The values of i range from zero to the implementation- dependent |
||
698 | * maximum supported number of texture image units." |
||
699 | * |
||
700 | * In addition, table 2.3, "Summary of GL errors," on page 17 (page 33 of |
||
701 | * the PDF) says: |
||
702 | * |
||
703 | * "Error Description Offending command |
||
704 | * ignored? |
||
705 | * ... |
||
706 | * INVALID_VALUE Numeric argument out of range Yes" |
||
707 | * |
||
708 | * Based on that, when an invalid sampler is specified, we generate a |
||
709 | * GL_INVALID_VALUE error and ignore the command. |
||
710 | */ |
||
711 | if (uni->type->is_sampler()) { |
||
712 | int i; |
||
713 | |||
714 | for (i = 0; i < count; i++) { |
||
715 | const unsigned texUnit = ((unsigned *) values)[i]; |
||
716 | |||
717 | /* check that the sampler (tex unit index) is legal */ |
||
718 | if (texUnit >= ctx->Const.MaxCombinedTextureImageUnits) { |
||
719 | _mesa_error(ctx, GL_INVALID_VALUE, |
||
720 | "glUniform1i(invalid sampler/tex unit index for " |
||
721 | "uniform %d)", |
||
722 | location); |
||
723 | return; |
||
724 | } |
||
725 | } |
||
726 | } |
||
727 | |||
728 | /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says: |
||
729 | * |
||
730 | * "When loading N elements starting at an arbitrary position k in a |
||
731 | * uniform declared as an array, elements k through k + N - 1 in the |
||
732 | * array will be replaced with the new values. Values for any array |
||
733 | * element that exceeds the highest array element index used, as |
||
734 | * reported by GetActiveUniform, will be ignored by the GL." |
||
735 | * |
||
736 | * Clamp 'count' to a valid value. Note that for non-arrays a count > 1 |
||
737 | * will have already generated an error. |
||
738 | */ |
||
739 | if (uni->array_elements != 0) { |
||
740 | count = MIN2(count, (int) (uni->array_elements - offset)); |
||
741 | } |
||
742 | |||
743 | FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); |
||
744 | |||
745 | /* Store the data in the "actual type" backing storage for the uniform. |
||
746 | */ |
||
747 | if (!uni->type->is_boolean()) { |
||
748 | memcpy(&uni->storage[components * offset], values, |
||
749 | sizeof(uni->storage[0]) * components * count); |
||
750 | } else { |
||
751 | const union gl_constant_value *src = |
||
752 | (const union gl_constant_value *) values; |
||
753 | union gl_constant_value *dst = &uni->storage[components * offset]; |
||
754 | const unsigned elems = components * count; |
||
755 | unsigned i; |
||
756 | |||
757 | for (i = 0; i < elems; i++) { |
||
758 | if (basicType == GLSL_TYPE_FLOAT) { |
||
759 | dst[i].i = src[i].f != 0.0f ? 1 : 0; |
||
760 | } else { |
||
761 | dst[i].i = src[i].i != 0 ? 1 : 0; |
||
762 | } |
||
763 | } |
||
764 | } |
||
765 | |||
766 | uni->initialized = true; |
||
767 | |||
768 | _mesa_propagate_uniforms_to_driver_storage(uni, offset, count); |
||
769 | |||
770 | /* If the uniform is a sampler, do the extra magic necessary to propagate |
||
771 | * the changes through. |
||
772 | */ |
||
773 | if (uni->type->is_sampler()) { |
||
774 | int i; |
||
775 | |||
776 | bool flushed = false; |
||
777 | for (i = 0; i < MESA_SHADER_TYPES; i++) { |
||
778 | struct gl_shader *const sh = shProg->_LinkedShaders[i]; |
||
779 | int j; |
||
780 | |||
781 | /* If the shader stage doesn't use the sampler uniform, skip this. |
||
782 | */ |
||
783 | if (sh == NULL || !uni->sampler[i].active) |
||
784 | continue; |
||
785 | |||
786 | for (j = 0; j < count; j++) { |
||
787 | sh->SamplerUnits[uni->sampler[i].index + offset + j] = |
||
788 | ((unsigned *) values)[j]; |
||
789 | } |
||
790 | |||
791 | struct gl_program *const prog = sh->Program; |
||
792 | |||
793 | assert(sizeof(prog->SamplerUnits) == sizeof(sh->SamplerUnits)); |
||
794 | |||
795 | /* Determine if any of the samplers used by this shader stage have |
||
796 | * been modified. |
||
797 | */ |
||
798 | bool changed = false; |
||
799 | for (unsigned j = 0; j < Elements(prog->SamplerUnits); j++) { |
||
800 | if ((sh->active_samplers & (1U << j)) != 0 |
||
801 | && (prog->SamplerUnits[j] != sh->SamplerUnits[j])) { |
||
802 | changed = true; |
||
803 | break; |
||
804 | } |
||
805 | } |
||
806 | |||
807 | if (changed) { |
||
808 | if (!flushed) { |
||
809 | FLUSH_VERTICES(ctx, _NEW_TEXTURE | _NEW_PROGRAM); |
||
810 | flushed = true; |
||
811 | } |
||
812 | |||
813 | memcpy(prog->SamplerUnits, |
||
814 | sh->SamplerUnits, |
||
815 | sizeof(sh->SamplerUnits)); |
||
816 | |||
817 | _mesa_update_shader_textures_used(shProg, prog); |
||
818 | if (ctx->Driver.SamplerUniformChange) |
||
819 | ctx->Driver.SamplerUniformChange(ctx, prog->Target, prog); |
||
820 | } |
||
821 | } |
||
822 | } |
||
823 | } |
||
824 | |||
825 | /** |
||
826 | * Called by glUniformMatrix*() functions. |
||
827 | * Note: cols=2, rows=4 ==> array[2] of vec4 |
||
828 | */ |
||
829 | extern "C" void |
||
830 | _mesa_uniform_matrix(struct gl_context *ctx, struct gl_shader_program *shProg, |
||
831 | GLuint cols, GLuint rows, |
||
832 | GLint location, GLsizei count, |
||
833 | GLboolean transpose, const GLfloat *values) |
||
834 | { |
||
835 | unsigned loc, offset; |
||
836 | unsigned vectors; |
||
837 | unsigned components; |
||
838 | unsigned elements; |
||
839 | struct gl_uniform_storage *uni; |
||
840 | |||
841 | if (!validate_uniform_parameters(ctx, shProg, location, count, |
||
842 | &loc, &offset, "glUniformMatrix", false)) |
||
843 | return; |
||
844 | |||
845 | uni = &shProg->UniformStorage[loc]; |
||
846 | if (!uni->type->is_matrix()) { |
||
847 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
848 | "glUniformMatrix(non-matrix uniform)"); |
||
849 | return; |
||
850 | } |
||
851 | |||
852 | assert(!uni->type->is_sampler()); |
||
853 | vectors = uni->type->matrix_columns; |
||
854 | components = uni->type->vector_elements; |
||
855 | |||
856 | /* Verify that the types are compatible. This is greatly simplified for |
||
857 | * matrices because they can only have a float base type. |
||
858 | */ |
||
859 | if (vectors != cols || components != rows) { |
||
860 | _mesa_error(ctx, GL_INVALID_OPERATION, |
||
861 | "glUniformMatrix(matrix size mismatch)"); |
||
862 | return; |
||
863 | } |
||
864 | |||
865 | /* GL_INVALID_VALUE is generated if `transpose' is not GL_FALSE. |
||
866 | * http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml */ |
||
867 | if (ctx->API == API_OPENGLES |
||
868 | || (ctx->API == API_OPENGLES2 && ctx->Version < 30)) { |
||
869 | if (transpose) { |
||
870 | _mesa_error(ctx, GL_INVALID_VALUE, |
||
871 | "glUniformMatrix(matrix transpose is not GL_FALSE)"); |
||
872 | return; |
||
873 | } |
||
874 | } |
||
875 | |||
876 | if (ctx->Shader.Flags & GLSL_UNIFORMS) { |
||
877 | log_uniform(values, GLSL_TYPE_FLOAT, components, vectors, count, |
||
878 | bool(transpose), shProg, location, uni); |
||
879 | } |
||
880 | |||
881 | /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says: |
||
882 | * |
||
883 | * "When loading N elements starting at an arbitrary position k in a |
||
884 | * uniform declared as an array, elements k through k + N - 1 in the |
||
885 | * array will be replaced with the new values. Values for any array |
||
886 | * element that exceeds the highest array element index used, as |
||
887 | * reported by GetActiveUniform, will be ignored by the GL." |
||
888 | * |
||
889 | * Clamp 'count' to a valid value. Note that for non-arrays a count > 1 |
||
890 | * will have already generated an error. |
||
891 | */ |
||
892 | if (uni->array_elements != 0) { |
||
893 | count = MIN2(count, (int) (uni->array_elements - offset)); |
||
894 | } |
||
895 | |||
896 | FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); |
||
897 | |||
898 | /* Store the data in the "actual type" backing storage for the uniform. |
||
899 | */ |
||
900 | elements = components * vectors; |
||
901 | |||
902 | if (!transpose) { |
||
903 | memcpy(&uni->storage[elements * offset], values, |
||
904 | sizeof(uni->storage[0]) * elements * count); |
||
905 | } else { |
||
906 | /* Copy and transpose the matrix. |
||
907 | */ |
||
908 | const float *src = values; |
||
909 | float *dst = &uni->storage[elements * offset].f; |
||
910 | |||
911 | for (int i = 0; i < count; i++) { |
||
912 | for (unsigned r = 0; r < rows; r++) { |
||
913 | for (unsigned c = 0; c < cols; c++) { |
||
914 | dst[(c * components) + r] = src[c + (r * vectors)]; |
||
915 | } |
||
916 | } |
||
917 | |||
918 | dst += elements; |
||
919 | src += elements; |
||
920 | } |
||
921 | } |
||
922 | |||
923 | uni->initialized = true; |
||
924 | |||
925 | _mesa_propagate_uniforms_to_driver_storage(uni, offset, count); |
||
926 | } |
||
927 | |||
928 | |||
929 | /** |
||
930 | * Called via glGetUniformLocation(). |
||
931 | * |
||
932 | * Returns the uniform index into UniformStorage (also the |
||
933 | * glGetActiveUniformsiv uniform index), and stores the referenced |
||
934 | * array offset in *offset, or GL_INVALID_INDEX (-1). Those two |
||
935 | * return values can be encoded into a uniform location for |
||
936 | * glUniform* using _mesa_uniform_merge_location_offset(index, offset). |
||
937 | */ |
||
938 | extern "C" unsigned |
||
939 | _mesa_get_uniform_location(struct gl_context *ctx, |
||
940 | struct gl_shader_program *shProg, |
||
941 | const GLchar *name, |
||
942 | unsigned *out_offset) |
||
943 | { |
||
944 | /* Page 80 (page 94 of the PDF) of the OpenGL 2.1 spec says: |
||
945 | * |
||
946 | * "The first element of a uniform array is identified using the |
||
947 | * name of the uniform array appended with "[0]". Except if the last |
||
948 | * part of the string name indicates a uniform array, then the |
||
949 | * location of the first element of that array can be retrieved by |
||
950 | * either using the name of the uniform array, or the name of the |
||
951 | * uniform array appended with "[0]"." |
||
952 | * |
||
953 | * Note: since uniform names are not allowed to use whitespace, and array |
||
954 | * indices within uniform names are not allowed to use "+", "-", or leading |
||
955 | * zeros, it follows that each uniform has a unique name up to the possible |
||
956 | * ambiguity with "[0]" noted above. Therefore we don't need to worry |
||
957 | * about mal-formed inputs--they will properly fail when we try to look up |
||
958 | * the uniform name in shProg->UniformHash. |
||
959 | */ |
||
960 | |||
961 | const GLchar *base_name_end; |
||
962 | long offset = parse_program_resource_name(name, &base_name_end); |
||
963 | bool array_lookup = offset >= 0; |
||
964 | char *name_copy; |
||
965 | |||
966 | if (array_lookup) { |
||
967 | name_copy = (char *) malloc(base_name_end - name + 1); |
||
968 | memcpy(name_copy, name, base_name_end - name); |
||
969 | name_copy[base_name_end - name] = '\0'; |
||
970 | } else { |
||
971 | name_copy = (char *) name; |
||
972 | offset = 0; |
||
973 | } |
||
974 | |||
975 | unsigned location = 0; |
||
976 | const bool found = shProg->UniformHash->get(location, name_copy); |
||
977 | |||
978 | assert(!found |
||
979 | || strcmp(name_copy, shProg->UniformStorage[location].name) == 0); |
||
980 | |||
981 | /* Free the temporary buffer *before* possibly returning an error. |
||
982 | */ |
||
983 | if (name_copy != name) |
||
984 | free(name_copy); |
||
985 | |||
986 | if (!found) |
||
987 | return GL_INVALID_INDEX; |
||
988 | |||
989 | /* If the uniform is an array, fail if the index is out of bounds. |
||
990 | * (A negative index is caught above.) This also fails if the uniform |
||
991 | * is not an array, but the user is trying to index it, because |
||
992 | * array_elements is zero and offset >= 0. |
||
993 | */ |
||
994 | if (array_lookup |
||
995 | && offset >= (long) shProg->UniformStorage[location].array_elements) { |
||
996 | return GL_INVALID_INDEX; |
||
997 | } |
||
998 | |||
999 | *out_offset = offset; |
||
1000 | return location; |
||
1001 | } |
||
1002 | |||
1003 | extern "C" bool |
||
1004 | _mesa_sampler_uniforms_are_valid(const struct gl_shader_program *shProg, |
||
1005 | char *errMsg, size_t errMsgLength) |
||
1006 | { |
||
1007 | const glsl_type *unit_types[MAX_COMBINED_TEXTURE_IMAGE_UNITS]; |
||
1008 | |||
1009 | memset(unit_types, 0, sizeof(unit_types)); |
||
1010 | |||
1011 | for (unsigned i = 0; i < shProg->NumUserUniformStorage; i++) { |
||
1012 | const struct gl_uniform_storage *const storage = |
||
1013 | &shProg->UniformStorage[i]; |
||
1014 | const glsl_type *const t = (storage->type->is_array()) |
||
1015 | ? storage->type->fields.array : storage->type; |
||
1016 | |||
1017 | if (!t->is_sampler()) |
||
1018 | continue; |
||
1019 | |||
1020 | const unsigned count = MAX2(1, storage->type->array_size()); |
||
1021 | for (unsigned j = 0; j < count; j++) { |
||
1022 | const unsigned unit = storage->storage[j].i; |
||
1023 | |||
1024 | /* The types of the samplers associated with a particular texture |
||
1025 | * unit must be an exact match. Page 74 (page 89 of the PDF) of the |
||
1026 | * OpenGL 3.3 core spec says: |
||
1027 | * |
||
1028 | * "It is not allowed to have variables of different sampler |
||
1029 | * types pointing to the same texture image unit within a program |
||
1030 | * object." |
||
1031 | */ |
||
1032 | if (unit_types[unit] == NULL) { |
||
1033 | unit_types[unit] = t; |
||
1034 | } else if (unit_types[unit] != t) { |
||
1035 | _mesa_snprintf(errMsg, errMsgLength, |
||
1036 | "Texture unit %d is accessed both as %s and %s", |
||
1037 | unit, unit_types[unit]->name, t->name); |
||
1038 | return false; |
||
1039 | } |
||
1040 | } |
||
1041 | } |
||
1042 | |||
1043 | return true; |
||
1044 | }>>>>>>><>>>>>>>>>>>>>>>>>>>>>>>>>>> |