uniform_query.cpp revision 2f45ed393a40e914749ddb86d41e0f77b2cea3da
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 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25#include "main/core.h"
26#include "main/context.h"
27#include "ir.h"
28#include "../glsl/program.h"
29
30extern "C" {
31#include "main/image.h"
32#include "main/shaderapi.h"
33#include "main/shaderobj.h"
34#include "uniforms.h"
35}
36
37extern "C" void GLAPIENTRY
38_mesa_GetActiveUniformARB(GLhandleARB program, GLuint index,
39                          GLsizei maxLength, GLsizei *length, GLint *size,
40                          GLenum *type, GLcharARB *nameOut)
41{
42   GET_CURRENT_CONTEXT(ctx);
43   struct gl_shader_program *shProg =
44      _mesa_lookup_shader_program_err(ctx, program, "glGetActiveUniform");
45   const struct gl_program_parameter *param;
46
47   if (!shProg)
48      return;
49
50   if (!shProg->Uniforms || index >= shProg->Uniforms->NumUniforms) {
51      _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
52      return;
53   }
54
55   param = get_uniform_parameter(shProg, index);
56   if (!param)
57      return;
58
59   const struct gl_uniform *const uni = &shProg->Uniforms->Uniforms[index];
60
61   if (nameOut) {
62      _mesa_copy_string(nameOut, maxLength, length, param->Name);
63   }
64
65   if (size) {
66      GLint typeSize = _mesa_sizeof_glsl_type(uni->Type->gl_type);
67      if ((GLint) param->Size > typeSize) {
68         /* This is an array.
69          * Array elements are placed on vector[4] boundaries so they're
70          * a multiple of four floats.  We round typeSize up to next multiple
71          * of four to get the right size below.
72          */
73         typeSize = (typeSize + 3) & ~3;
74      }
75      /* Note that the returned size is in units of the <type>, not bytes */
76      *size = param->Size / typeSize;
77   }
78
79   if (type) {
80      *type = uni->Type->gl_type;
81   }
82}
83
84static GLenum
85base_uniform_type(GLenum type)
86{
87   switch (type) {
88   case GL_BOOL:
89   case GL_BOOL_VEC2:
90   case GL_BOOL_VEC3:
91   case GL_BOOL_VEC4:
92      return GL_BOOL;
93   case GL_FLOAT:
94   case GL_FLOAT_VEC2:
95   case GL_FLOAT_VEC3:
96   case GL_FLOAT_VEC4:
97   case GL_FLOAT_MAT2:
98   case GL_FLOAT_MAT2x3:
99   case GL_FLOAT_MAT2x4:
100   case GL_FLOAT_MAT3x2:
101   case GL_FLOAT_MAT3:
102   case GL_FLOAT_MAT3x4:
103   case GL_FLOAT_MAT4x2:
104   case GL_FLOAT_MAT4x3:
105   case GL_FLOAT_MAT4:
106      return GL_FLOAT;
107   case GL_UNSIGNED_INT:
108   case GL_UNSIGNED_INT_VEC2:
109   case GL_UNSIGNED_INT_VEC3:
110   case GL_UNSIGNED_INT_VEC4:
111      return GL_UNSIGNED_INT;
112   case GL_INT:
113   case GL_INT_VEC2:
114   case GL_INT_VEC3:
115   case GL_INT_VEC4:
116      return GL_INT;
117   default:
118      _mesa_problem(NULL, "Invalid type in base_uniform_type()");
119      return GL_FLOAT;
120   }
121}
122
123static GLboolean
124is_boolean_type(GLenum type)
125{
126   switch (type) {
127   case GL_BOOL:
128   case GL_BOOL_VEC2:
129   case GL_BOOL_VEC3:
130   case GL_BOOL_VEC4:
131      return GL_TRUE;
132   default:
133      return GL_FALSE;
134   }
135}
136
137static GLboolean
138is_sampler_type(GLenum type)
139{
140   switch (type) {
141   case GL_SAMPLER_1D:
142   case GL_INT_SAMPLER_1D:
143   case GL_UNSIGNED_INT_SAMPLER_1D:
144   case GL_SAMPLER_2D:
145   case GL_INT_SAMPLER_2D:
146   case GL_UNSIGNED_INT_SAMPLER_2D:
147   case GL_SAMPLER_3D:
148   case GL_INT_SAMPLER_3D:
149   case GL_UNSIGNED_INT_SAMPLER_3D:
150   case GL_SAMPLER_CUBE:
151   case GL_INT_SAMPLER_CUBE:
152   case GL_UNSIGNED_INT_SAMPLER_CUBE:
153   case GL_SAMPLER_1D_SHADOW:
154   case GL_SAMPLER_2D_SHADOW:
155   case GL_SAMPLER_CUBE_SHADOW:
156   case GL_SAMPLER_2D_RECT_ARB:
157   case GL_INT_SAMPLER_2D_RECT:
158   case GL_UNSIGNED_INT_SAMPLER_2D_RECT:
159   case GL_SAMPLER_2D_RECT_SHADOW_ARB:
160   case GL_SAMPLER_1D_ARRAY_EXT:
161   case GL_INT_SAMPLER_1D_ARRAY:
162   case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
163   case GL_SAMPLER_2D_ARRAY_EXT:
164   case GL_INT_SAMPLER_2D_ARRAY:
165   case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
166   case GL_SAMPLER_1D_ARRAY_SHADOW_EXT:
167   case GL_SAMPLER_2D_ARRAY_SHADOW_EXT:
168   case GL_SAMPLER_CUBE_MAP_ARRAY:
169   case GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW:
170   case GL_SAMPLER_BUFFER:
171   case GL_INT_SAMPLER_BUFFER:
172   case GL_UNSIGNED_INT_SAMPLER_BUFFER:
173   case GL_SAMPLER_2D_MULTISAMPLE:
174   case GL_INT_SAMPLER_2D_MULTISAMPLE:
175   case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
176   case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
177   case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
178   case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
179   case GL_SAMPLER_EXTERNAL_OES:
180      return GL_TRUE;
181   default:
182      return GL_FALSE;
183   }
184}
185
186/**
187 * Given a uniform index, return the vertex/geometry/fragment program
188 * that has that parameter, plus the position of the parameter in the
189 * parameter/constant buffer.
190 * \param shProg  the shader program
191 * \param index  the uniform index in [0, NumUniforms-1]
192 * \param progOut  returns containing program
193 * \param posOut  returns position of the uniform in the param/const buffer
194 * \return GL_TRUE for success, GL_FALSE for invalid index
195 */
196static GLboolean
197find_uniform_parameter_pos(struct gl_shader_program *shProg, GLint index,
198                           struct gl_program **progOut, GLint *posOut)
199{
200   struct gl_program *prog = NULL;
201   GLint pos;
202
203   if (!shProg->Uniforms ||
204       index < 0 ||
205       index >= (GLint) shProg->Uniforms->NumUniforms) {
206      return GL_FALSE;
207   }
208
209   pos = shProg->Uniforms->Uniforms[index].VertPos;
210   if (pos >= 0) {
211      prog = shProg->_LinkedShaders[MESA_SHADER_VERTEX]->Program;
212   }
213   else {
214      pos = shProg->Uniforms->Uniforms[index].FragPos;
215      if (pos >= 0) {
216         prog = shProg->_LinkedShaders[MESA_SHADER_FRAGMENT]->Program;
217      }
218      else {
219         pos = shProg->Uniforms->Uniforms[index].GeomPos;
220         if (pos >= 0) {
221            prog = shProg->_LinkedShaders[MESA_SHADER_GEOMETRY]->Program;
222         }
223      }
224   }
225
226   if (!prog || pos < 0)
227      return GL_FALSE; /* should really never happen */
228
229   *progOut = prog;
230   *posOut = pos;
231
232   return GL_TRUE;
233}
234
235/**
236 * Return pointer to a gl_program_parameter which corresponds to a uniform.
237 * \param shProg  the shader program
238 * \param index  the uniform index in [0, NumUniforms-1]
239 * \return gl_program_parameter point or NULL if index is invalid
240 */
241const struct gl_program_parameter *
242get_uniform_parameter(struct gl_shader_program *shProg, GLint index)
243{
244   struct gl_program *prog;
245   GLint progPos;
246
247   if (find_uniform_parameter_pos(shProg, index, &prog, &progPos))
248      return &prog->Parameters->Parameters[progPos];
249   else
250      return NULL;
251}
252
253static unsigned
254get_vector_elements(GLenum type)
255{
256   switch (type) {
257   case GL_FLOAT:
258   case GL_INT:
259   case GL_BOOL:
260   case GL_UNSIGNED_INT:
261   default: /* Catch all the various sampler types. */
262      return 1;
263
264   case GL_FLOAT_VEC2:
265   case GL_INT_VEC2:
266   case GL_BOOL_VEC2:
267   case GL_UNSIGNED_INT_VEC2:
268      return 2;
269
270   case GL_FLOAT_VEC3:
271   case GL_INT_VEC3:
272   case GL_BOOL_VEC3:
273   case GL_UNSIGNED_INT_VEC3:
274      return 3;
275
276   case GL_FLOAT_VEC4:
277   case GL_INT_VEC4:
278   case GL_BOOL_VEC4:
279   case GL_UNSIGNED_INT_VEC4:
280      return 4;
281   }
282}
283
284static void
285get_matrix_dims(GLenum type, GLint *rows, GLint *cols)
286{
287   switch (type) {
288   case GL_FLOAT_MAT2:
289      *rows = *cols = 2;
290      break;
291   case GL_FLOAT_MAT2x3:
292      *rows = 3;
293      *cols = 2;
294      break;
295   case GL_FLOAT_MAT2x4:
296      *rows = 4;
297      *cols = 2;
298      break;
299   case GL_FLOAT_MAT3:
300      *rows = 3;
301      *cols = 3;
302      break;
303   case GL_FLOAT_MAT3x2:
304      *rows = 2;
305      *cols = 3;
306      break;
307   case GL_FLOAT_MAT3x4:
308      *rows = 4;
309      *cols = 3;
310      break;
311   case GL_FLOAT_MAT4:
312      *rows = 4;
313      *cols = 4;
314      break;
315   case GL_FLOAT_MAT4x2:
316      *rows = 2;
317      *cols = 4;
318      break;
319   case GL_FLOAT_MAT4x3:
320      *rows = 3;
321      *cols = 4;
322      break;
323   default:
324      *rows = *cols = 0;
325   }
326}
327
328/**
329 * Determine the number of rows and columns occupied by a uniform
330 * according to its datatype.  For non-matrix types (such as GL_FLOAT_VEC4),
331 * the number of rows = 1 and cols = number of elements in the vector.
332 */
333static void
334get_uniform_rows_cols(const struct gl_program_parameter *p,
335                      GLint *rows, GLint *cols)
336{
337   get_matrix_dims(p->DataType, rows, cols);
338   if (*rows == 0 && *cols == 0) {
339      /* not a matrix type, probably a float or vector */
340      *rows = 1;
341      *cols = get_vector_elements(p->DataType);
342   }
343}
344
345static bool
346validate_uniform_parameters(struct gl_context *ctx,
347			    struct gl_shader_program *shProg,
348			    GLint location, GLsizei count,
349			    unsigned *loc,
350			    unsigned *array_index,
351			    const char *caller,
352			    bool negative_one_is_not_valid)
353{
354   if (!shProg || !shProg->LinkStatus) {
355      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(program not linked)", caller);
356      return false;
357   }
358
359   if (location == -1) {
360      /* For glGetUniform, page 264 (page 278 of the PDF) of the OpenGL 2.1
361       * spec says:
362       *
363       *     "The error INVALID_OPERATION is generated if program has not been
364       *     linked successfully, or if location is not a valid location for
365       *     program."
366       *
367       * For glUniform, page 82 (page 96 of the PDF) of the OpenGL 2.1 spec
368       * says:
369       *
370       *     "If the value of location is -1, the Uniform* commands will
371       *     silently ignore the data passed in, and the current uniform
372       *     values will not be changed."
373       *
374       * Allowing -1 for the location parameter of glUniform allows
375       * applications to avoid error paths in the case that, for example, some
376       * uniform variable is removed by the compiler / linker after
377       * optimization.  In this case, the new value of the uniform is dropped
378       * on the floor.  For the case of glGetUniform, there is nothing
379       * sensible to do for a location of -1.
380       *
381       * The negative_one_is_not_valid flag selects between the two behaviors.
382       */
383      if (negative_one_is_not_valid) {
384	 _mesa_error(ctx, GL_INVALID_OPERATION, "%s(location=%d)",
385		     caller, location);
386      }
387
388      return false;
389   }
390
391   /* From page 12 (page 26 of the PDF) of the OpenGL 2.1 spec:
392    *
393    *     "If a negative number is provided where an argument of type sizei or
394    *     sizeiptr is specified, the error INVALID_VALUE is generated."
395    */
396   if (count < 0) {
397      _mesa_error(ctx, GL_INVALID_VALUE, "%s(count < 0)", caller);
398      return false;
399   }
400
401   /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says:
402    *
403    *     "If any of the following conditions occur, an INVALID_OPERATION
404    *     error is generated by the Uniform* commands, and no uniform values
405    *     are changed:
406    *
407    *     ...
408    *
409    *         - if no variable with a location of location exists in the
410    *           program object currently in use and location is not -1,
411    */
412   if (location < -1) {
413      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(location=%d)",
414                  caller, location);
415      return false;
416   }
417
418   _mesa_uniform_split_location_offset(location, loc, array_index);
419
420   if (*loc >= shProg->Uniforms->NumUniforms) {
421      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(location=%d)",
422		  caller, location);
423      return false;
424   }
425
426   return true;
427}
428
429/**
430 * Called via glGetUniform[fiui]v() to get the current value of a uniform.
431 */
432extern "C" void
433_mesa_get_uniform(struct gl_context *ctx, GLuint program, GLint location,
434		  GLsizei bufSize, GLenum returnType, GLvoid *paramsOut)
435{
436   struct gl_shader_program *shProg =
437      _mesa_lookup_shader_program_err(ctx, program, "glGetUniformfv");
438   struct gl_program *prog;
439   GLint paramPos;
440   unsigned loc, offset;
441
442   if (!validate_uniform_parameters(ctx, shProg, location, 1,
443				    &loc, &offset, "glGetUniform", true))
444      return;
445
446   if (!find_uniform_parameter_pos(shProg, loc, &prog, &paramPos)) {
447      _mesa_error(ctx, GL_INVALID_OPERATION,  "glGetUniformfv(location)");
448   }
449   else {
450      const struct gl_program_parameter *p =
451         &prog->Parameters->Parameters[paramPos];
452      gl_constant_value (*values)[4];
453      GLint rows, cols, i, j, k;
454      GLsizei numBytes;
455      GLenum storage_type;
456
457      values = prog->Parameters->ParameterValues + paramPos + offset;
458
459      get_uniform_rows_cols(p, &rows, &cols);
460
461      numBytes = rows * cols * _mesa_sizeof_type(returnType);
462      if (bufSize < numBytes) {
463         _mesa_error( ctx, GL_INVALID_OPERATION,
464                     "glGetnUniformfvARB(out of bounds: bufSize is %d,"
465                     " but %d bytes are required)", bufSize, numBytes );
466         return;
467      }
468
469      if (ctx->Const.NativeIntegers) {
470	 storage_type = base_uniform_type(p->DataType);
471      } else {
472	 storage_type = GL_FLOAT;
473      }
474
475      k = 0;
476      for (i = 0; i < rows; i++) {
477	 for (j = 0; j < cols; j++ ) {
478	    void *out = (char *)paramsOut + 4 * k;
479
480	    switch (returnType) {
481	    case GL_FLOAT:
482	       switch (storage_type) {
483	       case GL_FLOAT:
484		  *(float *)out = values[i][j].f;
485		  break;
486	       case GL_INT:
487	       case GL_BOOL: /* boolean is just an integer 1 or 0. */
488		  *(float *)out = values[i][j].i;
489		  break;
490	       case GL_UNSIGNED_INT:
491		  *(float *)out = values[i][j].u;
492		  break;
493	       }
494	       break;
495
496	    case GL_INT:
497	    case GL_UNSIGNED_INT:
498	       switch (storage_type) {
499	       case GL_FLOAT:
500		  /* While the GL 3.2 core spec doesn't explicitly
501		   * state how conversion of float uniforms to integer
502		   * values works, in section 6.2 "State Tables" on
503		   * page 267 it says:
504		   *
505		   *     "Unless otherwise specified, when floating
506		   *      point state is returned as integer values or
507		   *      integer state is returned as floating-point
508		   *      values it is converted in the fashion
509		   *      described in section 6.1.2"
510		   *
511		   * That section, on page 248, says:
512		   *
513		   *     "If GetIntegerv or GetInteger64v are called,
514		   *      a floating-point value is rounded to the
515		   *      nearest integer..."
516		   */
517		  *(int *)out = IROUND(values[i][j].f);
518		  break;
519
520	       case GL_INT:
521	       case GL_UNSIGNED_INT:
522	       case GL_BOOL:
523		  /* type conversions for these to int/uint are just
524		   * copying the data.
525		   */
526		  *(int *)out = values[i][j].i;
527		  break;
528		  break;
529	       }
530	       break;
531	    }
532
533	    k++;
534	 }
535      }
536   }
537}
538
539/**
540 * Check if the type given by userType is allowed to set a uniform of the
541 * target type.  Generally, equivalence is required, but setting Boolean
542 * uniforms can be done with glUniformiv or glUniformfv.
543 */
544static GLboolean
545compatible_types(GLenum userType, GLenum targetType)
546{
547   if (userType == targetType)
548      return GL_TRUE;
549
550   if (targetType == GL_BOOL && (userType == GL_FLOAT ||
551                                 userType == GL_UNSIGNED_INT ||
552                                 userType == GL_INT))
553      return GL_TRUE;
554
555   if (targetType == GL_BOOL_VEC2 && (userType == GL_FLOAT_VEC2 ||
556                                      userType == GL_UNSIGNED_INT_VEC2 ||
557                                      userType == GL_INT_VEC2))
558      return GL_TRUE;
559
560   if (targetType == GL_BOOL_VEC3 && (userType == GL_FLOAT_VEC3 ||
561                                      userType == GL_UNSIGNED_INT_VEC3 ||
562                                      userType == GL_INT_VEC3))
563      return GL_TRUE;
564
565   if (targetType == GL_BOOL_VEC4 && (userType == GL_FLOAT_VEC4 ||
566                                      userType == GL_UNSIGNED_INT_VEC4 ||
567                                      userType == GL_INT_VEC4))
568      return GL_TRUE;
569
570   if (is_sampler_type(targetType) && userType == GL_INT)
571      return GL_TRUE;
572
573   return GL_FALSE;
574}
575
576/**
577 * Set the value of a program's uniform variable.
578 * \param program  the program whose uniform to update
579 * \param index  the index of the program parameter for the uniform
580 * \param offset  additional parameter slot offset (for arrays)
581 * \param type  the incoming datatype of 'values'
582 * \param count  the number of uniforms to set
583 * \param elems  number of elements per uniform (1, 2, 3 or 4)
584 * \param values  the new values, of datatype 'type'
585 */
586static void
587set_program_uniform(struct gl_context *ctx, struct gl_program *program,
588                    GLint index, GLint offset,
589                    GLenum type, GLsizei count, GLint elems,
590                    const void *values)
591{
592   const struct gl_program_parameter *param =
593      &program->Parameters->Parameters[index];
594
595   assert(offset >= 0);
596   assert(elems >= 1);
597   assert(elems <= 4);
598
599   if (!compatible_types(type, param->DataType)) {
600      _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)");
601      return;
602   }
603
604   if (index + offset > (GLint) program->Parameters->Size) {
605      /* out of bounds! */
606      return;
607   }
608
609   if (param->Type == PROGRAM_SAMPLER) {
610      /* This controls which texture unit which is used by a sampler */
611      GLboolean changed = GL_FALSE;
612      GLint i;
613
614      /* this should have been caught by the compatible_types() check */
615      ASSERT(type == GL_INT);
616
617      /* loop over number of samplers to change */
618      for (i = 0; i < count; i++) {
619         GLuint sampler = (GLuint)
620            program->Parameters->ParameterValues[index+offset + i][0].f;
621         GLuint texUnit = ((GLuint *) values)[i];
622
623         /* check that the sampler (tex unit index) is legal */
624         if (texUnit >= ctx->Const.MaxCombinedTextureImageUnits) {
625            _mesa_error(ctx, GL_INVALID_VALUE,
626                        "glUniform1(invalid sampler/tex unit index for '%s')",
627                        param->Name);
628            return;
629         }
630
631         /* This maps a sampler to a texture unit: */
632         if (sampler < MAX_SAMPLERS) {
633#if 0
634            printf("Set program %p sampler %d '%s' to unit %u\n",
635		   program, sampler, param->Name, texUnit);
636#endif
637            if (program->SamplerUnits[sampler] != texUnit) {
638               program->SamplerUnits[sampler] = texUnit;
639               changed = GL_TRUE;
640            }
641         }
642      }
643
644      if (changed) {
645         /* When a sampler's value changes it usually requires rewriting
646          * a GPU program's TEX instructions since there may not be a
647          * sampler->texture lookup table.  We signal this with the
648          * ProgramStringNotify() callback.
649          */
650         FLUSH_VERTICES(ctx, _NEW_TEXTURE | _NEW_PROGRAM);
651         _mesa_update_shader_textures_used(program);
652         /* Do we need to care about the return value here?
653          * This should not be the first time the driver was notified of
654          * this program.
655          */
656         (void) ctx->Driver.ProgramStringNotify(ctx, program->Target, program);
657      }
658   }
659   else {
660      /* ordinary uniform variable */
661      const GLboolean isUniformBool = is_boolean_type(param->DataType);
662      const GLenum basicType = base_uniform_type(type);
663      const GLint slots = (param->Size + 3) / 4;
664      const GLint typeSize = _mesa_sizeof_glsl_type(param->DataType);
665      GLsizei k, i;
666
667      if ((GLint) param->Size > typeSize) {
668         /* an array */
669         /* we'll ignore extra data below */
670      }
671      else {
672         /* non-array: count must be at most one; count == 0 is handled
673          * by the loop below
674          */
675         if (count > 1) {
676            _mesa_error(ctx, GL_INVALID_OPERATION,
677                        "glUniform(uniform '%s' is not an array)",
678                        param->Name);
679            return;
680         }
681      }
682
683      /* loop over number of array elements */
684      for (k = 0; k < count; k++) {
685         gl_constant_value *uniformVal;
686
687         if (offset + k >= slots) {
688            /* Extra array data is ignored */
689            break;
690         }
691
692         /* uniformVal (the destination) is always gl_constant_value[4] */
693         uniformVal = program->Parameters->ParameterValues[index + offset + k];
694
695         if (basicType == GL_INT) {
696            const GLint *iValues = ((const GLint *) values) + k * elems;
697            for (i = 0; i < elems; i++) {
698               if (!ctx->Const.NativeIntegers)
699                  uniformVal[i].f = (GLfloat) iValues[i];
700               else
701                  uniformVal[i].i = iValues[i];
702            }
703         }
704         else if (basicType == GL_UNSIGNED_INT) {
705            const GLuint *iValues = ((const GLuint *) values) + k * elems;
706            for (i = 0; i < elems; i++) {
707               if (!ctx->Const.NativeIntegers)
708                  uniformVal[i].f = (GLfloat)(GLuint) iValues[i];
709               else
710                  uniformVal[i].u = iValues[i];
711            }
712         }
713         else {
714            const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
715            assert(basicType == GL_FLOAT);
716            for (i = 0; i < elems; i++) {
717               uniformVal[i].f = fValues[i];
718            }
719         }
720
721         /* if the uniform is bool-valued, convert to 1 or 0 */
722         if (isUniformBool) {
723            for (i = 0; i < elems; i++) {
724               if (basicType == GL_FLOAT)
725                  uniformVal[i].b = uniformVal[i].f != 0.0f ? 1 : 0;
726               else
727                  uniformVal[i].b = uniformVal[i].u ? 1 : 0;
728
729               if (ctx->Const.NativeIntegers)
730                  uniformVal[i].u =
731                        uniformVal[i].b ? ctx->Const.UniformBooleanTrue : 0;
732               else
733                  uniformVal[i].f = uniformVal[i].b ? 1.0f : 0.0f;
734            }
735         }
736      }
737   }
738}
739
740/**
741 * Called via glUniform*() functions.
742 */
743extern "C" void
744_mesa_uniform(struct gl_context *ctx, struct gl_shader_program *shProg,
745	      GLint location, GLsizei count,
746              const GLvoid *values, GLenum type)
747{
748   struct gl_uniform *uniform;
749   GLint elems;
750   unsigned loc, offset;
751
752   ASSERT_OUTSIDE_BEGIN_END(ctx);
753
754   if (!validate_uniform_parameters(ctx, shProg, location, count,
755				    &loc, &offset, "glUniform", false))
756      return;
757
758   elems = _mesa_sizeof_glsl_type(type);
759
760   FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
761
762   uniform = &shProg->Uniforms->Uniforms[loc];
763
764   if (ctx->Shader.Flags & GLSL_UNIFORMS) {
765      const GLenum basicType = base_uniform_type(type);
766      GLint i;
767      printf("Mesa: set program %u uniform %s (loc %d) to: ",
768	     shProg->Name, uniform->Name, location);
769      if (basicType == GL_INT) {
770         const GLint *v = (const GLint *) values;
771         for (i = 0; i < count * elems; i++) {
772            printf("%d ", v[i]);
773         }
774      }
775      else if (basicType == GL_UNSIGNED_INT) {
776         const GLuint *v = (const GLuint *) values;
777         for (i = 0; i < count * elems; i++) {
778            printf("%u ", v[i]);
779         }
780      }
781      else {
782         const GLfloat *v = (const GLfloat *) values;
783         assert(basicType == GL_FLOAT);
784         for (i = 0; i < count * elems; i++) {
785            printf("%g ", v[i]);
786         }
787      }
788      printf("\n");
789   }
790
791   /* A uniform var may be used by both a vertex shader and a fragment
792    * shader.  We may need to update one or both shader's uniform here:
793    */
794   if (shProg->_LinkedShaders[MESA_SHADER_VERTEX]) {
795      /* convert uniform location to program parameter index */
796      GLint index = uniform->VertPos;
797      if (index >= 0) {
798         set_program_uniform(ctx,
799                             shProg->_LinkedShaders[MESA_SHADER_VERTEX]->Program,
800                             index, offset, type, count, elems, values);
801      }
802   }
803
804   if (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT]) {
805      /* convert uniform location to program parameter index */
806      GLint index = uniform->FragPos;
807      if (index >= 0) {
808         set_program_uniform(ctx,
809			     shProg->_LinkedShaders[MESA_SHADER_FRAGMENT]->Program,
810                             index, offset, type, count, elems, values);
811      }
812   }
813
814   if (shProg->_LinkedShaders[MESA_SHADER_GEOMETRY]) {
815      /* convert uniform location to program parameter index */
816      GLint index = uniform->GeomPos;
817      if (index >= 0) {
818         set_program_uniform(ctx,
819			     shProg->_LinkedShaders[MESA_SHADER_GEOMETRY]->Program,
820                             index, offset, type, count, elems, values);
821      }
822   }
823
824   uniform->Initialized = GL_TRUE;
825}
826
827/**
828 * Set a matrix-valued program parameter.
829 */
830static void
831set_program_uniform_matrix(struct gl_context *ctx, struct gl_program *program,
832                           GLuint index, GLuint offset,
833                           GLuint count, GLuint rows, GLuint cols,
834                           GLboolean transpose, const GLfloat *values)
835{
836   GLuint mat, row, col;
837   GLuint src = 0;
838   const struct gl_program_parameter *param =
839      &program->Parameters->Parameters[index];
840   const GLuint slots = (param->Size + 3) / 4;
841   const GLint typeSize = _mesa_sizeof_glsl_type(param->DataType);
842   GLint nr, nc;
843
844   /* check that the number of rows, columns is correct */
845   get_matrix_dims(param->DataType, &nr, &nc);
846   if (rows != nr || cols != nc) {
847      _mesa_error(ctx, GL_INVALID_OPERATION,
848                  "glUniformMatrix(matrix size mismatch)");
849      return;
850   }
851
852   if ((GLint) param->Size <= typeSize) {
853      /* non-array: count must be at most one; count == 0 is handled
854       * by the loop below
855       */
856      if (count > 1) {
857         _mesa_error(ctx, GL_INVALID_OPERATION,
858                     "glUniformMatrix(uniform is not an array)");
859         return;
860      }
861   }
862
863   /*
864    * Note: the _columns_ of a matrix are stored in program registers, not
865    * the rows.  So, the loops below look a little funny.
866    * XXX could optimize this a bit...
867    */
868
869   /* loop over matrices */
870   for (mat = 0; mat < count; mat++) {
871
872      /* each matrix: */
873      for (col = 0; col < cols; col++) {
874         GLfloat *v;
875         if (offset >= slots) {
876            /* Ignore writes beyond the end of (the used part of) an array */
877            return;
878         }
879         v = (GLfloat *) program->Parameters->ParameterValues[index + offset];
880         for (row = 0; row < rows; row++) {
881            if (transpose) {
882               v[row] = values[src + row * cols + col];
883            }
884            else {
885               v[row] = values[src + col * rows + row];
886            }
887         }
888
889         offset++;
890      }
891
892      src += rows * cols;  /* next matrix */
893   }
894}
895
896/**
897 * Called by glUniformMatrix*() functions.
898 * Note: cols=2, rows=4  ==>  array[2] of vec4
899 */
900extern "C" void
901_mesa_uniform_matrix(struct gl_context *ctx, struct gl_shader_program *shProg,
902		     GLint cols, GLint rows,
903                     GLint location, GLsizei count,
904                     GLboolean transpose, const GLfloat *values)
905{
906   struct gl_uniform *uniform;
907   unsigned loc, offset;
908
909   ASSERT_OUTSIDE_BEGIN_END(ctx);
910
911   if (!validate_uniform_parameters(ctx, shProg, location, count,
912				    &loc, &offset, "glUniformMatrix", false))
913      return;
914
915   if (values == NULL) {
916      _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
917      return;
918   }
919
920   FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
921
922   uniform = &shProg->Uniforms->Uniforms[loc];
923
924   if (shProg->_LinkedShaders[MESA_SHADER_VERTEX]) {
925      /* convert uniform location to program parameter index */
926      GLint index = uniform->VertPos;
927      if (index >= 0) {
928         set_program_uniform_matrix(ctx,
929				    shProg->_LinkedShaders[MESA_SHADER_VERTEX]->Program,
930                                    index, offset,
931                                    count, rows, cols, transpose, values);
932      }
933   }
934
935   if (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT]) {
936      /* convert uniform location to program parameter index */
937      GLint index = uniform->FragPos;
938      if (index >= 0) {
939         set_program_uniform_matrix(ctx,
940				    shProg->_LinkedShaders[MESA_SHADER_FRAGMENT]->Program,
941                                    index, offset,
942                                    count, rows, cols, transpose, values);
943      }
944   }
945
946   if (shProg->_LinkedShaders[MESA_SHADER_GEOMETRY]) {
947      /* convert uniform location to program parameter index */
948      GLint index = uniform->GeomPos;
949      if (index >= 0) {
950         set_program_uniform_matrix(ctx,
951                                    shProg->_LinkedShaders[MESA_SHADER_GEOMETRY]->Program,
952                                    index, offset,
953                                    count, rows, cols, transpose, values);
954      }
955   }
956
957   uniform->Initialized = GL_TRUE;
958}
959
960/**
961 * Called via glGetUniformLocation().
962 *
963 * The return value will encode two values, the uniform location and an
964 * offset (used for arrays, structs).
965 */
966extern "C" GLint
967_mesa_get_uniform_location(struct gl_context *ctx,
968                           struct gl_shader_program *shProg,
969			   const GLchar *name)
970{
971   GLint offset = 0, location = -1;
972
973   /* XXX we should return -1 if the uniform was declared, but not
974    * actually used.
975    */
976
977   /* XXX we need to be able to parse uniform names for structs and arrays
978    * such as:
979    *   mymatrix[1]
980    *   mystruct.field1
981    */
982
983   {
984      /* handle 1-dimension arrays here... */
985      char *c = strchr((char *)name, '[');
986      if (c) {
987         /* truncate name at [ */
988         const GLint len = c - name;
989         GLchar *newName = (GLchar *) malloc(len + 1);
990         if (!newName)
991            return -1; /* out of mem */
992         memcpy(newName, name, len);
993         newName[len] = 0;
994
995         location = _mesa_lookup_uniform(shProg->Uniforms, newName);
996         if (location >= 0) {
997            const GLint element = atoi(c + 1);
998            if (element > 0) {
999               /* get type of the uniform array element */
1000               const struct gl_program_parameter *p =
1001                  get_uniform_parameter(shProg, location);
1002               if (p) {
1003                  GLint rows, cols;
1004                  get_matrix_dims(p->DataType, &rows, &cols);
1005                  if (rows < 1)
1006                     rows = 1;
1007                  offset = element * rows;
1008               }
1009            }
1010         }
1011
1012         free(newName);
1013      }
1014   }
1015
1016   if (location < 0) {
1017      location = _mesa_lookup_uniform(shProg->Uniforms, name);
1018   }
1019
1020   if (location < 0) {
1021      return -1;
1022   }
1023
1024   return _mesa_uniform_merge_location_offset(location, offset);
1025}
1026