mesa: add view classes for 3d astc formats
[mesa.git] / src / mesa / main / uniform_query.cpp
index 3df9a848f9a446072c3990882c223377f83c8eb3..997b0cb1c7e6fa52705b0eb875035288b0dd3f74 100644 (file)
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
  */
+
+#include <stdlib.h>
+
 #include "main/core.h"
 #include "main/context.h"
-#include "ir.h"
-#include "ir_uniform.h"
-#include "../glsl/program.h"
-#include "../glsl/ir_uniform.h"
-
-extern "C" {
-#include "main/image.h"
 #include "main/shaderapi.h"
 #include "main/shaderobj.h"
-#include "uniforms.h"
-}
+#include "main/uniforms.h"
+#include "compiler/glsl/ir.h"
+#include "compiler/glsl/ir_uniform.h"
+#include "compiler/glsl/glsl_parser_extras.h"
+#include "compiler/glsl/program.h"
+#include "program/hash_table.h"
+
 
 extern "C" void GLAPIENTRY
-_mesa_GetActiveUniformARB(GLhandleARB program, GLuint index,
-                          GLsizei maxLength, GLsizei *length, GLint *size,
-                          GLenum *type, GLcharARB *nameOut)
+_mesa_GetActiveUniform(GLuint program, GLuint index,
+                       GLsizei maxLength, GLsizei *length, GLint *size,
+                       GLenum *type, GLcharARB *nameOut)
 {
    GET_CURRENT_CONTEXT(ctx);
-   struct gl_shader_program *shProg =
-      _mesa_lookup_shader_program_err(ctx, program, "glGetActiveUniform");
-   const struct gl_program_parameter *param;
-
-   if (!shProg)
-      return;
+   struct gl_shader_program *shProg;
+   struct gl_program_resource *res;
 
-   if (!shProg->Uniforms || index >= shProg->Uniforms->NumUniforms) {
-      _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
+   if (maxLength < 0) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(maxLength < 0)");
       return;
    }
 
-   param = get_uniform_parameter(shProg, index);
-   if (!param)
+   shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveUniform");
+   if (!shProg)
       return;
 
-   const struct gl_uniform *const uni = &shProg->Uniforms->Uniforms[index];
+   res = _mesa_program_resource_find_index((struct gl_shader_program *) shProg,
+                                           GL_UNIFORM, index);
 
-   if (nameOut) {
-      _mesa_copy_string(nameOut, maxLength, length, param->Name);
-   }
-
-   if (size) {
-      GLint typeSize = _mesa_sizeof_glsl_type(uni->Type->gl_type);
-      if ((GLint) param->Size > typeSize) {
-         /* This is an array.
-          * Array elements are placed on vector[4] boundaries so they're
-          * a multiple of four floats.  We round typeSize up to next multiple
-          * of four to get the right size below.
-          */
-         typeSize = (typeSize + 3) & ~3;
-      }
-      /* Note that the returned size is in units of the <type>, not bytes */
-      *size = param->Size / typeSize;
+   if (!res) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
+      return;
    }
 
-   if (type) {
-      *type = uni->Type->gl_type;
-   }
+   if (nameOut)
+      _mesa_get_program_resource_name(shProg, GL_UNIFORM, index, maxLength,
+                                      length, nameOut, "glGetActiveUniform");
+   if (type)
+      _mesa_program_resource_prop((struct gl_shader_program *) shProg,
+                                  res, index, GL_TYPE, (GLint*) type,
+                                  "glGetActiveUniform");
+   if (size)
+      _mesa_program_resource_prop((struct gl_shader_program *) shProg,
+                                  res, index, GL_ARRAY_SIZE, (GLint*) size,
+                                  "glGetActiveUniform");
 }
 
 static GLenum
-base_uniform_type(GLenum type)
+resource_prop_from_uniform_prop(GLenum uni_prop)
 {
-   switch (type) {
-   case GL_BOOL:
-   case GL_BOOL_VEC2:
-   case GL_BOOL_VEC3:
-   case GL_BOOL_VEC4:
-      return GL_BOOL;
-   case GL_FLOAT:
-   case GL_FLOAT_VEC2:
-   case GL_FLOAT_VEC3:
-   case GL_FLOAT_VEC4:
-   case GL_FLOAT_MAT2:
-   case GL_FLOAT_MAT2x3:
-   case GL_FLOAT_MAT2x4:
-   case GL_FLOAT_MAT3x2:
-   case GL_FLOAT_MAT3:
-   case GL_FLOAT_MAT3x4:
-   case GL_FLOAT_MAT4x2:
-   case GL_FLOAT_MAT4x3:
-   case GL_FLOAT_MAT4:
-      return GL_FLOAT;
-   case GL_UNSIGNED_INT:
-   case GL_UNSIGNED_INT_VEC2:
-   case GL_UNSIGNED_INT_VEC3:
-   case GL_UNSIGNED_INT_VEC4:
-      return GL_UNSIGNED_INT;
-   case GL_INT:
-   case GL_INT_VEC2:
-   case GL_INT_VEC3:
-   case GL_INT_VEC4:
-      return GL_INT;
+   switch (uni_prop) {
+   case GL_UNIFORM_TYPE:
+      return GL_TYPE;
+   case GL_UNIFORM_SIZE:
+      return GL_ARRAY_SIZE;
+   case GL_UNIFORM_NAME_LENGTH:
+      return GL_NAME_LENGTH;
+   case GL_UNIFORM_BLOCK_INDEX:
+      return GL_BLOCK_INDEX;
+   case GL_UNIFORM_OFFSET:
+      return GL_OFFSET;
+   case GL_UNIFORM_ARRAY_STRIDE:
+      return GL_ARRAY_STRIDE;
+   case GL_UNIFORM_MATRIX_STRIDE:
+      return GL_MATRIX_STRIDE;
+   case GL_UNIFORM_IS_ROW_MAJOR:
+      return GL_IS_ROW_MAJOR;
+   case GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX:
+      return GL_ATOMIC_COUNTER_BUFFER_INDEX;
    default:
-      _mesa_problem(NULL, "Invalid type in base_uniform_type()");
-      return GL_FLOAT;
+      return 0;
    }
 }
 
-static GLboolean
-is_boolean_type(GLenum type)
+extern "C" void GLAPIENTRY
+_mesa_GetActiveUniformsiv(GLuint program,
+                         GLsizei uniformCount,
+                         const GLuint *uniformIndices,
+                         GLenum pname,
+                         GLint *params)
 {
-   switch (type) {
-   case GL_BOOL:
-   case GL_BOOL_VEC2:
-   case GL_BOOL_VEC3:
-   case GL_BOOL_VEC4:
-      return GL_TRUE;
-   default:
-      return GL_FALSE;
-   }
-}
+   GET_CURRENT_CONTEXT(ctx);
+   struct gl_shader_program *shProg;
+   struct gl_program_resource *res;
+   GLenum res_prop;
 
-static GLboolean
-is_sampler_type(GLenum type)
-{
-   switch (type) {
-   case GL_SAMPLER_1D:
-   case GL_INT_SAMPLER_1D:
-   case GL_UNSIGNED_INT_SAMPLER_1D:
-   case GL_SAMPLER_2D:
-   case GL_INT_SAMPLER_2D:
-   case GL_UNSIGNED_INT_SAMPLER_2D:
-   case GL_SAMPLER_3D:
-   case GL_INT_SAMPLER_3D:
-   case GL_UNSIGNED_INT_SAMPLER_3D:
-   case GL_SAMPLER_CUBE:
-   case GL_INT_SAMPLER_CUBE:
-   case GL_UNSIGNED_INT_SAMPLER_CUBE:
-   case GL_SAMPLER_1D_SHADOW:
-   case GL_SAMPLER_2D_SHADOW:
-   case GL_SAMPLER_CUBE_SHADOW:
-   case GL_SAMPLER_2D_RECT_ARB:
-   case GL_INT_SAMPLER_2D_RECT:
-   case GL_UNSIGNED_INT_SAMPLER_2D_RECT:
-   case GL_SAMPLER_2D_RECT_SHADOW_ARB:
-   case GL_SAMPLER_1D_ARRAY_EXT:
-   case GL_INT_SAMPLER_1D_ARRAY:
-   case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
-   case GL_SAMPLER_2D_ARRAY_EXT:
-   case GL_INT_SAMPLER_2D_ARRAY:
-   case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
-   case GL_SAMPLER_1D_ARRAY_SHADOW_EXT:
-   case GL_SAMPLER_2D_ARRAY_SHADOW_EXT:
-   case GL_SAMPLER_CUBE_MAP_ARRAY:
-   case GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW:
-   case GL_SAMPLER_BUFFER:
-   case GL_INT_SAMPLER_BUFFER:
-   case GL_UNSIGNED_INT_SAMPLER_BUFFER:
-   case GL_SAMPLER_2D_MULTISAMPLE:
-   case GL_INT_SAMPLER_2D_MULTISAMPLE:
-   case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
-   case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
-   case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
-   case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
-   case GL_SAMPLER_EXTERNAL_OES:
-      return GL_TRUE;
-   default:
-      return GL_FALSE;
+   if (uniformCount < 0) {
+      _mesa_error(ctx, GL_INVALID_VALUE,
+                 "glGetActiveUniformsiv(uniformCount < 0)");
+      return;
    }
-}
 
-/**
- * Given a uniform index, return the vertex/geometry/fragment program
- * that has that parameter, plus the position of the parameter in the
- * parameter/constant buffer.
- * \param shProg  the shader program
- * \param index  the uniform index in [0, NumUniforms-1]
- * \param progOut  returns containing program
- * \param posOut  returns position of the uniform in the param/const buffer
- * \return GL_TRUE for success, GL_FALSE for invalid index
- */
-static GLboolean
-find_uniform_parameter_pos(struct gl_shader_program *shProg, GLint index,
-                           struct gl_program **progOut, GLint *posOut)
-{
-   struct gl_program *prog = NULL;
-   GLint pos;
+   shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveUniform");
+   if (!shProg)
+      return;
 
-   if (!shProg->Uniforms ||
-       index < 0 ||
-       index >= (GLint) shProg->Uniforms->NumUniforms) {
-      return GL_FALSE;
-   }
+   res_prop = resource_prop_from_uniform_prop(pname);
 
-   pos = shProg->Uniforms->Uniforms[index].VertPos;
-   if (pos >= 0) {
-      prog = shProg->_LinkedShaders[MESA_SHADER_VERTEX]->Program;
-   }
-   else {
-      pos = shProg->Uniforms->Uniforms[index].FragPos;
-      if (pos >= 0) {
-         prog = shProg->_LinkedShaders[MESA_SHADER_FRAGMENT]->Program;
-      }
-      else {
-         pos = shProg->Uniforms->Uniforms[index].GeomPos;
-         if (pos >= 0) {
-            prog = shProg->_LinkedShaders[MESA_SHADER_GEOMETRY]->Program;
-         }
+   /* We need to first verify that each entry exists as active uniform. If
+    * not, generate error and do not cause any other side effects.
+    *
+    * In the case of and error condition, Page 16 (section 2.3.1 Errors)
+    * of the OpenGL 4.5 spec says:
+    *
+    *     "If the generating command modifies values through a pointer argu-
+    *     ment, no change is made to these values."
+    */
+   for (int i = 0; i < uniformCount; i++) {
+      if (!_mesa_program_resource_find_index(shProg, GL_UNIFORM,
+                                              uniformIndices[i])) {
+         _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniformsiv(index)");
+         return;
       }
    }
 
-   if (!prog || pos < 0)
-      return GL_FALSE; /* should really never happen */
-
-   *progOut = prog;
-   *posOut = pos;
-
-   return GL_TRUE;
-}
-
-/**
- * Return pointer to a gl_program_parameter which corresponds to a uniform.
- * \param shProg  the shader program
- * \param index  the uniform index in [0, NumUniforms-1]
- * \return gl_program_parameter point or NULL if index is invalid
- */
-const struct gl_program_parameter *
-get_uniform_parameter(struct gl_shader_program *shProg, GLint index)
-{
-   struct gl_program *prog;
-   GLint progPos;
-
-   if (find_uniform_parameter_pos(shProg, index, &prog, &progPos))
-      return &prog->Parameters->Parameters[progPos];
-   else
-      return NULL;
-}
-
-static unsigned
-get_vector_elements(GLenum type)
-{
-   switch (type) {
-   case GL_FLOAT:
-   case GL_INT:
-   case GL_BOOL:
-   case GL_UNSIGNED_INT:
-   default: /* Catch all the various sampler types. */
-      return 1;
-
-   case GL_FLOAT_VEC2:
-   case GL_INT_VEC2:
-   case GL_BOOL_VEC2:
-   case GL_UNSIGNED_INT_VEC2:
-      return 2;
-
-   case GL_FLOAT_VEC3:
-   case GL_INT_VEC3:
-   case GL_BOOL_VEC3:
-   case GL_UNSIGNED_INT_VEC3:
-      return 3;
-
-   case GL_FLOAT_VEC4:
-   case GL_INT_VEC4:
-   case GL_BOOL_VEC4:
-   case GL_UNSIGNED_INT_VEC4:
-      return 4;
+   for (int i = 0; i < uniformCount; i++) {
+      res = _mesa_program_resource_find_index(shProg, GL_UNIFORM,
+                                              uniformIndices[i]);
+      if (!_mesa_program_resource_prop(shProg, res, uniformIndices[i],
+                                       res_prop, &params[i],
+                                       "glGetActiveUniformsiv"))
+         break;
    }
 }
 
-static void
-get_matrix_dims(GLenum type, GLint *rows, GLint *cols)
-{
-   switch (type) {
-   case GL_FLOAT_MAT2:
-      *rows = *cols = 2;
-      break;
-   case GL_FLOAT_MAT2x3:
-      *rows = 3;
-      *cols = 2;
-      break;
-   case GL_FLOAT_MAT2x4:
-      *rows = 4;
-      *cols = 2;
-      break;
-   case GL_FLOAT_MAT3:
-      *rows = 3;
-      *cols = 3;
-      break;
-   case GL_FLOAT_MAT3x2:
-      *rows = 2;
-      *cols = 3;
-      break;
-   case GL_FLOAT_MAT3x4:
-      *rows = 4;
-      *cols = 3;
-      break;
-   case GL_FLOAT_MAT4:
-      *rows = 4;
-      *cols = 4;
-      break;
-   case GL_FLOAT_MAT4x2:
-      *rows = 2;
-      *cols = 4;
-      break;
-   case GL_FLOAT_MAT4x3:
-      *rows = 3;
-      *cols = 4;
-      break;
-   default:
-      *rows = *cols = 0;
-   }
-}
-
-/**
- * Determine the number of rows and columns occupied by a uniform
- * according to its datatype.  For non-matrix types (such as GL_FLOAT_VEC4),
- * the number of rows = 1 and cols = number of elements in the vector.
- */
-static void
-get_uniform_rows_cols(const struct gl_program_parameter *p,
-                      GLint *rows, GLint *cols)
-{
-   get_matrix_dims(p->DataType, rows, cols);
-   if (*rows == 0 && *cols == 0) {
-      /* not a matrix type, probably a float or vector */
-      *rows = 1;
-      *cols = get_vector_elements(p->DataType);
-   }
-}
-
-static bool
+static struct gl_uniform_storage *
 validate_uniform_parameters(struct gl_context *ctx,
                            struct gl_shader_program *shProg,
                            GLint location, GLsizei count,
-                           unsigned *loc,
                            unsigned *array_index,
-                           const char *caller,
-                           bool negative_one_is_not_valid)
+                           const char *caller)
 {
-   if (!shProg || !shProg->LinkStatus) {
+   if (shProg == NULL) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "%s(program not linked)", caller);
-      return false;
-   }
-
-   if (location == -1) {
-      /* For glGetUniform, page 264 (page 278 of the PDF) of the OpenGL 2.1
-       * spec says:
-       *
-       *     "The error INVALID_OPERATION is generated if program has not been
-       *     linked successfully, or if location is not a valid location for
-       *     program."
-       *
-       * For glUniform, page 82 (page 96 of the PDF) of the OpenGL 2.1 spec
-       * says:
-       *
-       *     "If the value of location is -1, the Uniform* commands will
-       *     silently ignore the data passed in, and the current uniform
-       *     values will not be changed."
-       *
-       * Allowing -1 for the location parameter of glUniform allows
-       * applications to avoid error paths in the case that, for example, some
-       * uniform variable is removed by the compiler / linker after
-       * optimization.  In this case, the new value of the uniform is dropped
-       * on the floor.  For the case of glGetUniform, there is nothing
-       * sensible to do for a location of -1.
-       *
-       * The negative_one_is_not_valid flag selects between the two behaviors.
-       */
-      if (negative_one_is_not_valid) {
-        _mesa_error(ctx, GL_INVALID_OPERATION, "%s(location=%d)",
-                    caller, location);
-      }
-
-      return false;
+      return NULL;
    }
 
    /* From page 12 (page 26 of the PDF) of the OpenGL 2.1 spec:
@@ -397,7 +174,30 @@ validate_uniform_parameters(struct gl_context *ctx,
     */
    if (count < 0) {
       _mesa_error(ctx, GL_INVALID_VALUE, "%s(count < 0)", caller);
-      return false;
+      return NULL;
+   }
+
+   /* Check that the given location is in bounds of uniform remap table.
+    * Unlinked programs will have NumUniformRemapTable == 0, so we can take
+    * the shProg->LinkStatus check out of the main path.
+    */
+   if (unlikely(location >= (GLint) shProg->NumUniformRemapTable)) {
+      if (!shProg->LinkStatus)
+         _mesa_error(ctx, GL_INVALID_OPERATION, "%s(program not linked)",
+                     caller);
+      else
+         _mesa_error(ctx, GL_INVALID_OPERATION, "%s(location=%d)",
+                     caller, location);
+
+      return NULL;
+   }
+
+   if (location == -1) {
+      if (!shProg->LinkStatus)
+         _mesa_error(ctx, GL_INVALID_OPERATION, "%s(program not linked)",
+                     caller);
+
+      return NULL;
    }
 
    /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says:
@@ -410,22 +210,65 @@ validate_uniform_parameters(struct gl_context *ctx,
     *
     *         - if no variable with a location of location exists in the
     *           program object currently in use and location is not -1,
+    *         - if count is greater than one, and the uniform declared in the
+    *           shader is not an array variable,
     */
-   if (location < -1) {
+   if (location < -1 || !shProg->UniformRemapTable[location]) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "%s(location=%d)",
                   caller, location);
-      return false;
+      return NULL;
    }
 
-   _mesa_uniform_split_location_offset(location, loc, array_index);
+   /* If the driver storage pointer in remap table is -1, we ignore silently.
+    *
+    * GL_ARB_explicit_uniform_location spec says:
+    *     "What happens if Uniform* is called with an explicitly defined
+    *     uniform location, but that uniform is deemed inactive by the
+    *     linker?
+    *
+    *     RESOLVED: The call is ignored for inactive uniform variables and
+    *     no error is generated."
+    *
+    */
+   if (shProg->UniformRemapTable[location] ==
+       INACTIVE_UNIFORM_EXPLICIT_LOCATION)
+      return NULL;
 
-   if (*loc >= shProg->Uniforms->NumUniforms) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(location=%d)",
-                 caller, location);
-      return false;
-   }
+   struct gl_uniform_storage *const uni = shProg->UniformRemapTable[location];
 
-   return true;
+   /* Even though no location is assigned to a built-in uniform and this
+    * function should already have returned NULL, this test makes it explicit
+    * that we are not allowing to update the value of a built-in.
+    */
+   if (uni->builtin)
+      return NULL;
+
+   if (uni->array_elements == 0) {
+      if (count > 1) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "%s(count = %u for non-array \"%s\"@%d)",
+                     caller, count, uni->name, location);
+         return NULL;
+      }
+
+      assert((location - uni->remap_location) == 0);
+      *array_index = 0;
+   } else {
+      /* The array index specified by the uniform location is just the uniform
+       * location minus the base location of of the uniform.
+       */
+      *array_index = location - uni->remap_location;
+
+      /* If the uniform is an array, check that array_index is in bounds.
+       * array_index is unsigned so no need to check for less than zero.
+       */
+      if (*array_index >= uni->array_elements) {
+         _mesa_error(ctx, GL_INVALID_OPERATION, "%s(location=%d)",
+                     caller, location);
+         return NULL;
+      }
+   }
+   return uni;
 }
 
 /**
@@ -433,72 +276,144 @@ validate_uniform_parameters(struct gl_context *ctx,
  */
 extern "C" void
 _mesa_get_uniform(struct gl_context *ctx, GLuint program, GLint location,
-                 GLsizei bufSize, GLenum returnType, GLvoid *paramsOut)
+                 GLsizei bufSize, enum glsl_base_type returnType,
+                 GLvoid *paramsOut)
 {
    struct gl_shader_program *shProg =
       _mesa_lookup_shader_program_err(ctx, program, "glGetUniformfv");
-   struct gl_program *prog;
-   GLint paramPos;
-   unsigned loc, offset;
+   unsigned offset;
 
-   if (!validate_uniform_parameters(ctx, shProg, location, 1,
-                                   &loc, &offset, "glGetUniform", true))
-      return;
+   struct gl_uniform_storage *const uni =
+      validate_uniform_parameters(ctx, shProg, location, 1,
+                                  &offset, "glGetUniform");
+   if (uni == NULL) {
+      /* For glGetUniform, page 264 (page 278 of the PDF) of the OpenGL 2.1
+       * spec says:
+       *
+       *     "The error INVALID_OPERATION is generated if program has not been
+       *     linked successfully, or if location is not a valid location for
+       *     program."
+       *
+       * For glUniform, page 82 (page 96 of the PDF) of the OpenGL 2.1 spec
+       * says:
+       *
+       *     "If the value of location is -1, the Uniform* commands will
+       *     silently ignore the data passed in, and the current uniform
+       *     values will not be changed."
+       *
+       * Allowing -1 for the location parameter of glUniform allows
+       * applications to avoid error paths in the case that, for example, some
+       * uniform variable is removed by the compiler / linker after
+       * optimization.  In this case, the new value of the uniform is dropped
+       * on the floor.  For the case of glGetUniform, there is nothing
+       * sensible to do for a location of -1.
+       *
+       * If the location was -1, validate_unfirom_parameters will return NULL
+       * without raising an error.  Raise the error here.
+       */
+      if (location == -1) {
+         _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniform(location=%d)",
+                     location);
+      }
 
-   if (!find_uniform_parameter_pos(shProg, loc, &prog, &paramPos)) {
-      _mesa_error(ctx, GL_INVALID_OPERATION,  "glGetUniformfv(location)");
+      return;
    }
-   else {
-      const struct gl_program_parameter *p =
-         &prog->Parameters->Parameters[paramPos];
-      gl_constant_value (*values)[4];
-      GLint rows, cols, i, j, k;
-      GLsizei numBytes;
-      GLenum storage_type;
-
-      values = prog->Parameters->ParameterValues + paramPos + offset;
-
-      get_uniform_rows_cols(p, &rows, &cols);
-
-      numBytes = rows * cols * _mesa_sizeof_type(returnType);
-      if (bufSize < numBytes) {
-         _mesa_error( ctx, GL_INVALID_OPERATION,
-                     "glGetnUniformfvARB(out of bounds: bufSize is %d,"
-                     " but %d bytes are required)", bufSize, numBytes );
-         return;
-      }
 
-      if (ctx->Const.NativeIntegers) {
-        storage_type = base_uniform_type(p->DataType);
-      } else {
-        storage_type = GL_FLOAT;
+   {
+      unsigned elements = (uni->type->is_sampler())
+        ? 1 : uni->type->components();
+      const int dmul = uni->type->base_type == GLSL_TYPE_DOUBLE ? 2 : 1;
+      const int rmul = returnType == GLSL_TYPE_DOUBLE ? 2 : 1;
+
+      /* Calculate the source base address *BEFORE* modifying elements to
+       * account for the size of the user's buffer.
+       */
+      const union gl_constant_value *const src =
+        &uni->storage[offset * elements * dmul];
+
+      assert(returnType == GLSL_TYPE_FLOAT || returnType == GLSL_TYPE_INT ||
+             returnType == GLSL_TYPE_UINT || returnType == GLSL_TYPE_DOUBLE);
+
+      /* doubles have a different size than the other 3 types */
+      unsigned bytes = sizeof(src[0]) * elements * rmul;
+      if (bufSize < 0 || bytes > (unsigned) bufSize) {
+        _mesa_error( ctx, GL_INVALID_OPERATION,
+                    "glGetnUniform*vARB(out of bounds: bufSize is %d,"
+                    " but %u bytes are required)", bufSize, bytes );
+        return;
       }
 
-      k = 0;
-      for (i = 0; i < rows; i++) {
-        for (j = 0; j < cols; j++ ) {
-           void *out = (char *)paramsOut + 4 * k;
+      /* If the return type and the uniform's native type are "compatible,"
+       * just memcpy the data.  If the types are not compatible, perform a
+       * slower convert-and-copy process.
+       */
+      if (returnType == uni->type->base_type
+         || ((returnType == GLSL_TYPE_INT
+              || returnType == GLSL_TYPE_UINT)
+             &&
+             (uni->type->base_type == GLSL_TYPE_INT
+              || uni->type->base_type == GLSL_TYPE_UINT
+               || uni->type->base_type == GLSL_TYPE_SAMPLER
+               || uni->type->base_type == GLSL_TYPE_IMAGE))) {
+        memcpy(paramsOut, src, bytes);
+      } else {
+        union gl_constant_value *const dst =
+           (union gl_constant_value *) paramsOut;
+        /* This code could be optimized by putting the loop inside the switch
+         * statements.  However, this is not expected to be
+         * performance-critical code.
+         */
+        for (unsigned i = 0; i < elements; i++) {
+          int sidx = i * dmul;
+          int didx = i * rmul;
 
            switch (returnType) {
-           case GL_FLOAT:
-              switch (storage_type) {
-              case GL_FLOAT:
-                 *(float *)out = values[i][j].f;
+           case GLSL_TYPE_FLOAT:
+              switch (uni->type->base_type) {
+              case GLSL_TYPE_UINT:
+                 dst[didx].f = (float) src[sidx].u;
+                 break;
+              case GLSL_TYPE_INT:
+              case GLSL_TYPE_SAMPLER:
+               case GLSL_TYPE_IMAGE:
+                 dst[didx].f = (float) src[sidx].i;
                  break;
-              case GL_INT:
-              case GL_BOOL: /* boolean is just an integer 1 or 0. */
-                 *(float *)out = values[i][j].i;
+              case GLSL_TYPE_BOOL:
+                 dst[didx].f = src[sidx].i ? 1.0f : 0.0f;
                  break;
-              case GL_UNSIGNED_INT:
-                 *(float *)out = values[i][j].u;
+              case GLSL_TYPE_DOUBLE:
+                 dst[didx].f = *(double *)&src[sidx].f;
+                 break;
+              default:
+                 assert(!"Should not get here.");
                  break;
               }
               break;
-
-           case GL_INT:
-           case GL_UNSIGNED_INT:
-              switch (storage_type) {
-              case GL_FLOAT:
+           case GLSL_TYPE_DOUBLE:
+              switch (uni->type->base_type) {
+              case GLSL_TYPE_UINT:
+                 *(double *)&dst[didx].f = (double) src[sidx].u;
+                 break;
+              case GLSL_TYPE_INT:
+              case GLSL_TYPE_SAMPLER:
+              case GLSL_TYPE_IMAGE:
+                 *(double *)&dst[didx].f = (double) src[sidx].i;
+                 break;
+              case GLSL_TYPE_BOOL:
+                 *(double *)&dst[didx].f = src[sidx].i ? 1.0f : 0.0f;
+                 break;
+              case GLSL_TYPE_FLOAT:
+                 *(double *)&dst[didx].f = (double) src[sidx].f;
+                 break;
+              default:
+                 assert(!"Should not get here.");
+                 break;
+              }
+              break;
+           case GLSL_TYPE_INT:
+           case GLSL_TYPE_UINT:
+              switch (uni->type->base_type) {
+              case GLSL_TYPE_FLOAT:
                  /* While the GL 3.2 core spec doesn't explicitly
                   * state how conversion of float uniforms to integer
                   * values works, in section 6.2 "State Tables" on
@@ -516,23 +431,24 @@ _mesa_get_uniform(struct gl_context *ctx, GLuint program, GLint location,
                   *      a floating-point value is rounded to the
                   *      nearest integer..."
                   */
-                 *(int *)out = IROUND(values[i][j].f);
+                 dst[didx].i = IROUND(src[sidx].f);
                  break;
-
-              case GL_INT:
-              case GL_UNSIGNED_INT:
-              case GL_BOOL:
-                 /* type conversions for these to int/uint are just
-                  * copying the data.
-                  */
-                 *(int *)out = values[i][j].i;
+              case GLSL_TYPE_BOOL:
+                 dst[didx].i = src[sidx].i ? 1 : 0;
                  break;
+              case GLSL_TYPE_DOUBLE:
+                 dst[didx].i = IROUNDD(*(double *)&src[sidx].f);
+                 break;
+              default:
+                 assert(!"Should not get here.");
                  break;
               }
               break;
-           }
 
-           k++;
+           default:
+              assert(!"Should not get here.");
+              break;
+           }
         }
       }
    }
@@ -569,6 +485,9 @@ log_uniform(const void *values, enum glsl_base_type basicType,
       case GLSL_TYPE_FLOAT:
         printf("%g ", v[i].f);
         break;
+      case GLSL_TYPE_DOUBLE:
+         printf("%g ", *(double* )&v[i * 2].f);
+         break;
       default:
         assert(!"Should not get here.");
         break;
@@ -582,20 +501,14 @@ log_uniform(const void *values, enum glsl_base_type basicType,
 static void
 log_program_parameters(const struct gl_shader_program *shProg)
 {
-   static const char *stages[] = {
-      "vertex", "fragment", "geometry"
-   };
-
-   assert(Elements(stages) == MESA_SHADER_TYPES);
-
-   for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) {
+   for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
       if (shProg->_LinkedShaders[i] == NULL)
         continue;
 
       const struct gl_program *const prog = shProg->_LinkedShaders[i]->Program;
 
       printf("Program %d %s shader parameters:\n",
-            shProg->Name, stages[i]);
+             shProg->Name, _mesa_shader_stage_to_string(i));
       for (unsigned j = 0; j < prog->Parameters->NumParameters; j++) {
         printf("%s: %p %f %f %f %f\n",
                prog->Parameters->Parameters[j].Name,
@@ -610,207 +523,6 @@ log_program_parameters(const struct gl_shader_program *shProg)
 }
 #endif
 
-/**
- * Check if the type given by userType is allowed to set a uniform of the
- * target type.  Generally, equivalence is required, but setting Boolean
- * uniforms can be done with glUniformiv or glUniformfv.
- */
-static GLboolean
-compatible_types(GLenum userType, GLenum targetType)
-{
-   if (userType == targetType)
-      return GL_TRUE;
-
-   if (targetType == GL_BOOL && (userType == GL_FLOAT ||
-                                 userType == GL_UNSIGNED_INT ||
-                                 userType == GL_INT))
-      return GL_TRUE;
-
-   if (targetType == GL_BOOL_VEC2 && (userType == GL_FLOAT_VEC2 ||
-                                      userType == GL_UNSIGNED_INT_VEC2 ||
-                                      userType == GL_INT_VEC2))
-      return GL_TRUE;
-
-   if (targetType == GL_BOOL_VEC3 && (userType == GL_FLOAT_VEC3 ||
-                                      userType == GL_UNSIGNED_INT_VEC3 ||
-                                      userType == GL_INT_VEC3))
-      return GL_TRUE;
-
-   if (targetType == GL_BOOL_VEC4 && (userType == GL_FLOAT_VEC4 ||
-                                      userType == GL_UNSIGNED_INT_VEC4 ||
-                                      userType == GL_INT_VEC4))
-      return GL_TRUE;
-
-   if (is_sampler_type(targetType) && userType == GL_INT)
-      return GL_TRUE;
-
-   return GL_FALSE;
-}
-
-/**
- * Set the value of a program's uniform variable.
- * \param program  the program whose uniform to update
- * \param index  the index of the program parameter for the uniform
- * \param offset  additional parameter slot offset (for arrays)
- * \param type  the incoming datatype of 'values'
- * \param count  the number of uniforms to set
- * \param elems  number of elements per uniform (1, 2, 3 or 4)
- * \param values  the new values, of datatype 'type'
- */
-static void
-set_program_uniform(struct gl_context *ctx, struct gl_program *program,
-                    GLint index, GLint offset,
-                    GLenum type, GLsizei count, GLint elems,
-                    const void *values)
-{
-   const struct gl_program_parameter *param =
-      &program->Parameters->Parameters[index];
-
-   assert(offset >= 0);
-   assert(elems >= 1);
-   assert(elems <= 4);
-
-   if (!compatible_types(type, param->DataType)) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)");
-      return;
-   }
-
-   if (index + offset > (GLint) program->Parameters->Size) {
-      /* out of bounds! */
-      return;
-   }
-
-   if (param->Type == PROGRAM_SAMPLER) {
-      /* This controls which texture unit which is used by a sampler */
-      GLboolean changed = GL_FALSE;
-      GLint i;
-
-      /* this should have been caught by the compatible_types() check */
-      ASSERT(type == GL_INT);
-
-      /* loop over number of samplers to change */
-      for (i = 0; i < count; i++) {
-         GLuint sampler = (GLuint)
-            program->Parameters->ParameterValues[index+offset + i][0].f;
-         GLuint texUnit = ((GLuint *) values)[i];
-
-         /* check that the sampler (tex unit index) is legal */
-         if (texUnit >= ctx->Const.MaxCombinedTextureImageUnits) {
-            _mesa_error(ctx, GL_INVALID_VALUE,
-                        "glUniform1(invalid sampler/tex unit index for '%s')",
-                        param->Name);
-            return;
-         }
-
-         /* This maps a sampler to a texture unit: */
-         if (sampler < MAX_SAMPLERS) {
-#if 0
-            printf("Set program %p sampler %d '%s' to unit %u\n",
-                  program, sampler, param->Name, texUnit);
-#endif
-            if (program->SamplerUnits[sampler] != texUnit) {
-               program->SamplerUnits[sampler] = texUnit;
-               changed = GL_TRUE;
-            }
-         }
-      }
-
-      if (changed) {
-         /* When a sampler's value changes it usually requires rewriting
-          * a GPU program's TEX instructions since there may not be a
-          * sampler->texture lookup table.  We signal this with the
-          * ProgramStringNotify() callback.
-          */
-         FLUSH_VERTICES(ctx, _NEW_TEXTURE | _NEW_PROGRAM);
-         _mesa_update_shader_textures_used(program);
-         /* Do we need to care about the return value here?
-          * This should not be the first time the driver was notified of
-          * this program.
-          */
-         (void) ctx->Driver.ProgramStringNotify(ctx, program->Target, program);
-      }
-   }
-   else {
-      /* ordinary uniform variable */
-      const GLboolean isUniformBool = is_boolean_type(param->DataType);
-      const GLenum basicType = base_uniform_type(type);
-      const GLint slots = (param->Size + 3) / 4;
-      const GLint typeSize = _mesa_sizeof_glsl_type(param->DataType);
-      GLsizei k, i;
-
-      if ((GLint) param->Size > typeSize) {
-         /* an array */
-         /* we'll ignore extra data below */
-      }
-      else {
-         /* non-array: count must be at most one; count == 0 is handled
-          * by the loop below
-          */
-         if (count > 1) {
-            _mesa_error(ctx, GL_INVALID_OPERATION,
-                        "glUniform(uniform '%s' is not an array)",
-                        param->Name);
-            return;
-         }
-      }
-
-      /* loop over number of array elements */
-      for (k = 0; k < count; k++) {
-         gl_constant_value *uniformVal;
-
-         if (offset + k >= slots) {
-            /* Extra array data is ignored */
-            break;
-         }
-
-         /* uniformVal (the destination) is always gl_constant_value[4] */
-         uniformVal = program->Parameters->ParameterValues[index + offset + k];
-
-         if (basicType == GL_INT) {
-            const GLint *iValues = ((const GLint *) values) + k * elems;
-            for (i = 0; i < elems; i++) {
-               if (!ctx->Const.NativeIntegers)
-                  uniformVal[i].f = (GLfloat) iValues[i];
-               else
-                  uniformVal[i].i = iValues[i];
-            }
-         }
-         else if (basicType == GL_UNSIGNED_INT) {
-            const GLuint *iValues = ((const GLuint *) values) + k * elems;
-            for (i = 0; i < elems; i++) {
-               if (!ctx->Const.NativeIntegers)
-                  uniformVal[i].f = (GLfloat)(GLuint) iValues[i];
-               else
-                  uniformVal[i].u = iValues[i];
-            }
-         }
-         else {
-            const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
-            assert(basicType == GL_FLOAT);
-            for (i = 0; i < elems; i++) {
-               uniformVal[i].f = fValues[i];
-            }
-         }
-
-         /* if the uniform is bool-valued, convert to 1 or 0 */
-         if (isUniformBool) {
-            for (i = 0; i < elems; i++) {
-               if (basicType == GL_FLOAT)
-                  uniformVal[i].b = uniformVal[i].f != 0.0f ? 1 : 0;
-               else
-                  uniformVal[i].b = uniformVal[i].u ? 1 : 0;
-
-               if (ctx->Const.NativeIntegers)
-                  uniformVal[i].u =
-                        uniformVal[i].b ? ctx->Const.UniformBooleanTrue : 0;
-               else
-                  uniformVal[i].f = uniformVal[i].b ? 1.0f : 0.0f;
-            }
-         }
-      }
-   }
-}
-
 /**
  * Propagate some values from uniform backing storage to driver storage
  *
@@ -836,11 +548,12 @@ _mesa_propagate_uniforms_to_driver_storage(struct gl_uniform_storage *uni,
     */
    const unsigned components = MAX2(1, uni->type->vector_elements);
    const unsigned vectors = MAX2(1, uni->type->matrix_columns);
+   const int dmul = uni->type->base_type == GLSL_TYPE_DOUBLE ? 2 : 1;
 
    /* Store the data in the driver's requested type in the driver's storage
     * areas.
     */
-   unsigned src_vector_byte_stride = components * 4;
+   unsigned src_vector_byte_stride = components * 4 * dmul;
 
    for (i = 0; i < uni->num_driver_storage; i++) {
       struct gl_uniform_driver_storage *const store = &uni->driver_storage[i];
@@ -848,7 +561,7 @@ _mesa_propagate_uniforms_to_driver_storage(struct gl_uniform_storage *uni,
       const unsigned extra_stride =
         store->element_stride - (vectors * store->vector_stride);
       const uint8_t *src =
-        (uint8_t *) (&uni->storage[array_index * (components * vectors)].i);
+        (uint8_t *) (&uni->storage[array_index * (dmul * components * vectors)].i);
 
 #if 0
       printf("%s: %p[%d] components=%u vectors=%u count=%u vector_stride=%u "
@@ -860,8 +573,7 @@ _mesa_propagate_uniforms_to_driver_storage(struct gl_uniform_storage *uni,
       dst += array_index * store->element_stride;
 
       switch (store->format) {
-      case uniform_native:
-      case uniform_bool_int_0_1: {
+      case uniform_native: {
         unsigned j;
         unsigned v;
 
@@ -877,8 +589,7 @@ _mesa_propagate_uniforms_to_driver_storage(struct gl_uniform_storage *uni,
         break;
       }
 
-      case uniform_int_float:
-      case uniform_bool_float: {
+      case uniform_int_float: {
         const int *isrc = (const int *) src;
         unsigned j;
         unsigned v;
@@ -899,27 +610,6 @@ _mesa_propagate_uniforms_to_driver_storage(struct gl_uniform_storage *uni,
         break;
       }
 
-      case uniform_bool_int_0_not0: {
-        const int *isrc = (const int *) src;
-        unsigned j;
-        unsigned v;
-        unsigned c;
-
-        for (j = 0; j < count; j++) {
-           for (v = 0; v < vectors; v++) {
-              for (c = 0; c < components; c++) {
-                 ((int *) dst)[c] = *isrc == 0 ? 0 : ~0;
-                 isrc++;
-              }
-
-              dst += store->vector_stride;
-           }
-
-           dst += extra_stride;
-        }
-        break;
-      }
-
       default:
         assert(!"Should not get here.");
         break;
@@ -927,159 +617,272 @@ _mesa_propagate_uniforms_to_driver_storage(struct gl_uniform_storage *uni,
    }
 }
 
+
+/**
+ * Return printable string for a given GLSL_TYPE_x
+ */
+static const char *
+glsl_type_name(enum glsl_base_type type)
+{
+   switch (type) {
+   case GLSL_TYPE_UINT:
+      return "uint";
+   case GLSL_TYPE_INT:
+      return "int";
+   case GLSL_TYPE_FLOAT:
+      return "float";
+   case GLSL_TYPE_DOUBLE:
+      return "double";
+   case GLSL_TYPE_BOOL:
+      return "bool";
+   case GLSL_TYPE_SAMPLER:
+      return "sampler";
+   case GLSL_TYPE_IMAGE:
+      return "image";
+   case GLSL_TYPE_ATOMIC_UINT:
+      return "atomic_uint";
+   case GLSL_TYPE_STRUCT:
+      return "struct";
+   case GLSL_TYPE_INTERFACE:
+      return "interface";
+   case GLSL_TYPE_ARRAY:
+      return "array";
+   case GLSL_TYPE_VOID:
+      return "void";
+   case GLSL_TYPE_ERROR:
+      return "error";
+   default:
+      return "other";
+   }
+}
+
+
 /**
  * Called via glUniform*() functions.
  */
 extern "C" void
 _mesa_uniform(struct gl_context *ctx, struct gl_shader_program *shProg,
              GLint location, GLsizei count,
-              const GLvoid *values, GLenum type)
+              const GLvoid *values,
+              enum glsl_base_type basicType,
+              unsigned src_components)
 {
-   struct gl_uniform *uniform;
-   GLint elems;
-   unsigned loc, offset;
+   unsigned offset;
+   int size_mul = basicType == GLSL_TYPE_DOUBLE ? 2 : 1;
 
-   ASSERT_OUTSIDE_BEGIN_END(ctx);
+   struct gl_uniform_storage *const uni =
+      validate_uniform_parameters(ctx, shProg, location, count,
+                                  &offset, "glUniform");
+   if (uni == NULL)
+      return;
 
-   if (!validate_uniform_parameters(ctx, shProg, location, count,
-                                   &loc, &offset, "glUniform", false))
+   if (uni->type->is_matrix()) {
+      /* Can't set matrix uniforms (like mat4) with glUniform */
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glUniform%u(uniform \"%s\"@%d is matrix)",
+                  src_components, uni->name, location);
       return;
+   }
 
-   elems = _mesa_sizeof_glsl_type(type);
+   /* Verify that the types are compatible.
+    */
+   const unsigned components = uni->type->is_sampler()
+      ? 1 : uni->type->vector_elements;
 
-   FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
+   if (components != src_components) {
+      /* glUniformN() must match float/vecN type */
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glUniform%u(\"%s\"@%u has %u components, not %u)",
+                  src_components, uni->name, location,
+                  components, src_components);
+      return;
+   }
 
-   uniform = &shProg->Uniforms->Uniforms[loc];
-
-   if (ctx->Shader.Flags & GLSL_UNIFORMS) {
-      const GLenum basicType = base_uniform_type(type);
-      GLint i;
-      printf("Mesa: set program %u uniform %s (loc %d) to: ",
-            shProg->Name, uniform->Name, location);
-      if (basicType == GL_INT) {
-         const GLint *v = (const GLint *) values;
-         for (i = 0; i < count * elems; i++) {
-            printf("%d ", v[i]);
-         }
-      }
-      else if (basicType == GL_UNSIGNED_INT) {
-         const GLuint *v = (const GLuint *) values;
-         for (i = 0; i < count * elems; i++) {
-            printf("%u ", v[i]);
+   bool match;
+   switch (uni->type->base_type) {
+   case GLSL_TYPE_BOOL:
+      match = (basicType != GLSL_TYPE_DOUBLE);
+      break;
+   case GLSL_TYPE_SAMPLER:
+      match = (basicType == GLSL_TYPE_INT);
+      break;
+   case GLSL_TYPE_IMAGE:
+      match = (basicType == GLSL_TYPE_INT && _mesa_is_desktop_gl(ctx));
+      break;
+   default:
+      match = (basicType == uni->type->base_type);
+      break;
+   }
+
+   if (!match) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glUniform%u(\"%s\"@%d is %s, not %s)",
+                  src_components, uni->name, location,
+                  glsl_type_name(uni->type->base_type),
+                  glsl_type_name(basicType));
+      return;
+   }
+
+   if (unlikely(ctx->_Shader->Flags & GLSL_UNIFORMS)) {
+      log_uniform(values, basicType, components, 1, count,
+                 false, shProg, location, uni);
+   }
+
+   /* Page 100 (page 116 of the PDF) of the OpenGL 3.0 spec says:
+    *
+    *     "Setting a sampler's value to i selects texture image unit number
+    *     i. The values of i range from zero to the implementation- dependent
+    *     maximum supported number of texture image units."
+    *
+    * In addition, table 2.3, "Summary of GL errors," on page 17 (page 33 of
+    * the PDF) says:
+    *
+    *     "Error         Description                    Offending command
+    *                                                   ignored?
+    *     ...
+    *     INVALID_VALUE  Numeric argument out of range  Yes"
+    *
+    * Based on that, when an invalid sampler is specified, we generate a
+    * GL_INVALID_VALUE error and ignore the command.
+    */
+   if (uni->type->is_sampler()) {
+      for (int i = 0; i < count; i++) {
+        const unsigned texUnit = ((unsigned *) values)[i];
+
+         /* check that the sampler (tex unit index) is legal */
+         if (texUnit >= ctx->Const.MaxCombinedTextureImageUnits) {
+            _mesa_error(ctx, GL_INVALID_VALUE,
+                        "glUniform1i(invalid sampler/tex unit index for "
+                       "uniform %d)",
+                        location);
+            return;
          }
       }
-      else {
-         const GLfloat *v = (const GLfloat *) values;
-         assert(basicType == GL_FLOAT);
-         for (i = 0; i < count * elems; i++) {
-            printf("%g ", v[i]);
+      /* We need to reset the validate flag on changes to samplers in case
+       * two different sampler types are set to the same texture unit.
+       */
+      ctx->_Shader->Validated = GL_FALSE;
+   }
+
+   if (uni->type->is_image()) {
+      for (int i = 0; i < count; i++) {
+         const int unit = ((GLint *) values)[i];
+
+         /* check that the image unit is legal */
+         if (unit < 0 || unit >= (int)ctx->Const.MaxImageUnits) {
+            _mesa_error(ctx, GL_INVALID_VALUE,
+                        "glUniform1i(invalid image unit index for uniform %d)",
+                        location);
+            return;
          }
       }
-      printf("\n");
    }
 
-   /* A uniform var may be used by both a vertex shader and a fragment
-    * shader.  We may need to update one or both shader's uniform here:
+   /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says:
+    *
+    *     "When loading N elements starting at an arbitrary position k in a
+    *     uniform declared as an array, elements k through k + N - 1 in the
+    *     array will be replaced with the new values. Values for any array
+    *     element that exceeds the highest array element index used, as
+    *     reported by GetActiveUniform, will be ignored by the GL."
+    *
+    * Clamp 'count' to a valid value.  Note that for non-arrays a count > 1
+    * will have already generated an error.
     */
-   if (shProg->_LinkedShaders[MESA_SHADER_VERTEX]) {
-      /* convert uniform location to program parameter index */
-      GLint index = uniform->VertPos;
-      if (index >= 0) {
-         set_program_uniform(ctx,
-                             shProg->_LinkedShaders[MESA_SHADER_VERTEX]->Program,
-                             index, offset, type, count, elems, values);
-      }
+   if (uni->array_elements != 0) {
+      count = MIN2(count, (int) (uni->array_elements - offset));
    }
 
-   if (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT]) {
-      /* convert uniform location to program parameter index */
-      GLint index = uniform->FragPos;
-      if (index >= 0) {
-         set_program_uniform(ctx,
-                            shProg->_LinkedShaders[MESA_SHADER_FRAGMENT]->Program,
-                             index, offset, type, count, elems, values);
-      }
-   }
+   FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
 
-   if (shProg->_LinkedShaders[MESA_SHADER_GEOMETRY]) {
-      /* convert uniform location to program parameter index */
-      GLint index = uniform->GeomPos;
-      if (index >= 0) {
-         set_program_uniform(ctx,
-                            shProg->_LinkedShaders[MESA_SHADER_GEOMETRY]->Program,
-                             index, offset, type, count, elems, values);
+   /* Store the data in the "actual type" backing storage for the uniform.
+    */
+   if (!uni->type->is_boolean()) {
+      memcpy(&uni->storage[size_mul * components * offset], values,
+            sizeof(uni->storage[0]) * components * count * size_mul);
+   } else {
+      const union gl_constant_value *src =
+        (const union gl_constant_value *) values;
+      union gl_constant_value *dst = &uni->storage[components * offset];
+      const unsigned elems = components * count;
+
+      for (unsigned i = 0; i < elems; i++) {
+        if (basicType == GLSL_TYPE_FLOAT) {
+            dst[i].i = src[i].f != 0.0f ? ctx->Const.UniformBooleanTrue : 0;
+        } else {
+            dst[i].i = src[i].i != 0    ? ctx->Const.UniformBooleanTrue : 0;
+        }
       }
    }
 
-   uniform->Initialized = GL_TRUE;
-}
+   _mesa_propagate_uniforms_to_driver_storage(uni, offset, count);
 
-/**
- * Set a matrix-valued program parameter.
- */
-static void
-set_program_uniform_matrix(struct gl_context *ctx, struct gl_program *program,
-                           GLuint index, GLuint offset,
-                           GLuint count, GLuint rows, GLuint cols,
-                           GLboolean transpose, const GLfloat *values)
-{
-   GLuint mat, row, col;
-   GLuint src = 0;
-   const struct gl_program_parameter *param =
-      &program->Parameters->Parameters[index];
-   const GLuint slots = (param->Size + 3) / 4;
-   const GLint typeSize = _mesa_sizeof_glsl_type(param->DataType);
-   GLint nr, nc;
-
-   /* check that the number of rows, columns is correct */
-   get_matrix_dims(param->DataType, &nr, &nc);
-   if (rows != nr || cols != nc) {
-      _mesa_error(ctx, GL_INVALID_OPERATION,
-                  "glUniformMatrix(matrix size mismatch)");
-      return;
-   }
+   /* If the uniform is a sampler, do the extra magic necessary to propagate
+    * the changes through.
+    */
+   if (uni->type->is_sampler()) {
+      bool flushed = false;
+      for (int i = 0; i < MESA_SHADER_STAGES; i++) {
+        struct gl_shader *const sh = shProg->_LinkedShaders[i];
+
+        /* If the shader stage doesn't use the sampler uniform, skip this.
+         */
+        if (sh == NULL || !uni->opaque[i].active)
+           continue;
+
+         for (int j = 0; j < count; j++) {
+            sh->SamplerUnits[uni->opaque[i].index + offset + j] =
+               ((unsigned *) values)[j];
+         }
 
-   if ((GLint) param->Size <= typeSize) {
-      /* non-array: count must be at most one; count == 0 is handled
-       * by the loop below
-       */
-      if (count > 1) {
-         _mesa_error(ctx, GL_INVALID_OPERATION,
-                     "glUniformMatrix(uniform is not an array)");
-         return;
+        struct gl_program *const prog = sh->Program;
+
+        assert(sizeof(prog->SamplerUnits) == sizeof(sh->SamplerUnits));
+
+        /* Determine if any of the samplers used by this shader stage have
+         * been modified.
+         */
+        bool changed = false;
+        for (unsigned j = 0; j < ARRAY_SIZE(prog->SamplerUnits); j++) {
+           if ((sh->active_samplers & (1U << j)) != 0
+               && (prog->SamplerUnits[j] != sh->SamplerUnits[j])) {
+              changed = true;
+              break;
+           }
+        }
+
+        if (changed) {
+           if (!flushed) {
+              FLUSH_VERTICES(ctx, _NEW_TEXTURE | _NEW_PROGRAM);
+              flushed = true;
+           }
+
+           memcpy(prog->SamplerUnits,
+                  sh->SamplerUnits,
+                  sizeof(sh->SamplerUnits));
+
+           _mesa_update_shader_textures_used(shProg, prog);
+            if (ctx->Driver.SamplerUniformChange)
+              ctx->Driver.SamplerUniformChange(ctx, prog->Target, prog);
+        }
       }
    }
 
-   /*
-    * Note: the _columns_ of a matrix are stored in program registers, not
-    * the rows.  So, the loops below look a little funny.
-    * XXX could optimize this a bit...
+   /* If the uniform is an image, update the mapping from image
+    * uniforms to image units present in the shader data structure.
     */
-
-   /* loop over matrices */
-   for (mat = 0; mat < count; mat++) {
-
-      /* each matrix: */
-      for (col = 0; col < cols; col++) {
-         GLfloat *v;
-         if (offset >= slots) {
-            /* Ignore writes beyond the end of (the used part of) an array */
-            return;
+   if (uni->type->is_image()) {
+      for (int i = 0; i < MESA_SHADER_STAGES; i++) {
+        if (uni->opaque[i].active) {
+            struct gl_shader *sh = shProg->_LinkedShaders[i];
+
+            for (int j = 0; j < count; j++)
+               sh->ImageUnits[uni->opaque[i].index + offset + j] =
+                  ((GLint *) values)[j];
          }
-         v = (GLfloat *) program->Parameters->ParameterValues[index + offset];
-         for (row = 0; row < rows; row++) {
-            if (transpose) {
-               v[row] = values[src + row * cols + col];
-            }
-            else {
-               v[row] = values[src + col * rows + row];
-            }
-         }
-
-         offset++;
       }
 
-      src += rows * cols;  /* next matrix */
+      ctx->NewDriverState |= ctx->DriverFlags.NewImageUnits;
    }
 }
 
@@ -1089,127 +892,242 @@ set_program_uniform_matrix(struct gl_context *ctx, struct gl_program *program,
  */
 extern "C" void
 _mesa_uniform_matrix(struct gl_context *ctx, struct gl_shader_program *shProg,
-                    GLint cols, GLint rows,
+                    GLuint cols, GLuint rows,
                      GLint location, GLsizei count,
-                     GLboolean transpose, const GLfloat *values)
+                     GLboolean transpose,
+                     const GLvoid *values, enum glsl_base_type basicType)
 {
-   struct gl_uniform *uniform;
-   unsigned loc, offset;
+   unsigned offset;
+   unsigned vectors;
+   unsigned components;
+   unsigned elements;
+   int size_mul;
+   struct gl_uniform_storage *const uni =
+      validate_uniform_parameters(ctx, shProg, location, count,
+                                  &offset, "glUniformMatrix");
+   if (uni == NULL)
+      return;
 
-   ASSERT_OUTSIDE_BEGIN_END(ctx);
+   if (!uni->type->is_matrix()) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                 "glUniformMatrix(non-matrix uniform)");
+      return;
+   }
 
-   if (!validate_uniform_parameters(ctx, shProg, location, count,
-                                   &loc, &offset, "glUniformMatrix", false))
+   assert(basicType == GLSL_TYPE_FLOAT || basicType == GLSL_TYPE_DOUBLE);
+   size_mul = basicType == GLSL_TYPE_DOUBLE ? 2 : 1;
+
+   assert(!uni->type->is_sampler());
+   vectors = uni->type->matrix_columns;
+   components = uni->type->vector_elements;
+
+   /* Verify that the types are compatible.  This is greatly simplified for
+    * matrices because they can only have a float base type.
+    */
+   if (vectors != cols || components != rows) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                 "glUniformMatrix(matrix size mismatch)");
       return;
+   }
 
-   if (values == NULL) {
-      _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
+   /* GL_INVALID_VALUE is generated if `transpose' is not GL_FALSE.
+    * http://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml
+    */
+   if (transpose) {
+      if (ctx->API == API_OPENGLES2 && ctx->Version < 30) {
+        _mesa_error(ctx, GL_INVALID_VALUE,
+                    "glUniformMatrix(matrix transpose is not GL_FALSE)");
+        return;
+      }
+   }
+
+   /* Section 2.11.7 (Uniform Variables) of the OpenGL 4.2 Core Profile spec
+    * says:
+    *
+    *     "If any of the following conditions occur, an INVALID_OPERATION
+    *     error is generated by the Uniform* commands, and no uniform values
+    *     are changed:
+    *
+    *     ...
+    *
+    *     - if the uniform declared in the shader is not of type boolean and
+    *       the type indicated in the name of the Uniform* command used does
+    *       not match the type of the uniform"
+    *
+    * There are no Boolean matrix types, so we do not need to allow
+    * GLSL_TYPE_BOOL here (as _mesa_uniform does).
+    */
+   if (uni->type->base_type != basicType) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glUniformMatrix%ux%u(\"%s\"@%d is %s, not %s)",
+                  cols, rows, uni->name, location,
+                  glsl_type_name(uni->type->base_type),
+                  glsl_type_name(basicType));
       return;
    }
 
+   if (unlikely(ctx->_Shader->Flags & GLSL_UNIFORMS)) {
+      log_uniform(values, uni->type->base_type, components, vectors, count,
+                 bool(transpose), shProg, location, uni);
+   }
+
+   /* Page 82 (page 96 of the PDF) of the OpenGL 2.1 spec says:
+    *
+    *     "When loading N elements starting at an arbitrary position k in a
+    *     uniform declared as an array, elements k through k + N - 1 in the
+    *     array will be replaced with the new values. Values for any array
+    *     element that exceeds the highest array element index used, as
+    *     reported by GetActiveUniform, will be ignored by the GL."
+    *
+    * Clamp 'count' to a valid value.  Note that for non-arrays a count > 1
+    * will have already generated an error.
+    */
+   if (uni->array_elements != 0) {
+      count = MIN2(count, (int) (uni->array_elements - offset));
+   }
+
    FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
 
-   uniform = &shProg->Uniforms->Uniforms[loc];
+   /* Store the data in the "actual type" backing storage for the uniform.
+    */
+   elements = components * vectors;
 
-   if (shProg->_LinkedShaders[MESA_SHADER_VERTEX]) {
-      /* convert uniform location to program parameter index */
-      GLint index = uniform->VertPos;
-      if (index >= 0) {
-         set_program_uniform_matrix(ctx,
-                                   shProg->_LinkedShaders[MESA_SHADER_VERTEX]->Program,
-                                    index, offset,
-                                    count, rows, cols, transpose, values);
-      }
-   }
+   if (!transpose) {
+      memcpy(&uni->storage[size_mul * elements * offset], values,
+            sizeof(uni->storage[0]) * elements * count * size_mul);
+   } else if (basicType == GLSL_TYPE_FLOAT) {
+      /* Copy and transpose the matrix.
+       */
+      const float *src = (const float *)values;
+      float *dst = &uni->storage[elements * offset].f;
 
-   if (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT]) {
-      /* convert uniform location to program parameter index */
-      GLint index = uniform->FragPos;
-      if (index >= 0) {
-         set_program_uniform_matrix(ctx,
-                                   shProg->_LinkedShaders[MESA_SHADER_FRAGMENT]->Program,
-                                    index, offset,
-                                    count, rows, cols, transpose, values);
+      for (int i = 0; i < count; i++) {
+        for (unsigned r = 0; r < rows; r++) {
+           for (unsigned c = 0; c < cols; c++) {
+              dst[(c * components) + r] = src[c + (r * vectors)];
+           }
+        }
+
+        dst += elements;
+        src += elements;
       }
-   }
+   } else {
+      assert(basicType == GLSL_TYPE_DOUBLE);
+      const double *src = (const double *)values;
+      double *dst = (double *)&uni->storage[elements * offset].f;
+
+      for (int i = 0; i < count; i++) {
+        for (unsigned r = 0; r < rows; r++) {
+           for (unsigned c = 0; c < cols; c++) {
+              dst[(c * components) + r] = src[c + (r * vectors)];
+           }
+        }
 
-   if (shProg->_LinkedShaders[MESA_SHADER_GEOMETRY]) {
-      /* convert uniform location to program parameter index */
-      GLint index = uniform->GeomPos;
-      if (index >= 0) {
-         set_program_uniform_matrix(ctx,
-                                    shProg->_LinkedShaders[MESA_SHADER_GEOMETRY]->Program,
-                                    index, offset,
-                                    count, rows, cols, transpose, values);
+        dst += elements;
+        src += elements;
       }
    }
 
-   uniform->Initialized = GL_TRUE;
+   _mesa_propagate_uniforms_to_driver_storage(uni, offset, count);
 }
 
-/**
- * Called via glGetUniformLocation().
- *
- * The return value will encode two values, the uniform location and an
- * offset (used for arrays, structs).
- */
-extern "C" GLint
-_mesa_get_uniform_location(struct gl_context *ctx,
-                           struct gl_shader_program *shProg,
-                          const GLchar *name)
-{
-   GLint offset = 0, location = -1;
 
-   /* XXX we should return -1 if the uniform was declared, but not
-    * actually used.
-    */
+extern "C" bool
+_mesa_sampler_uniforms_are_valid(const struct gl_shader_program *shProg,
+                                char *errMsg, size_t errMsgLength)
+{
+   /* Shader does not have samplers. */
+   if (shProg->NumUniformStorage == 0)
+      return true;
+
+   if (!shProg->SamplersValidated) {
+      _mesa_snprintf(errMsg, errMsgLength,
+                     "active samplers with a different type "
+                     "refer to the same texture image unit");
+      return false;
+   }
+   return true;
+}
 
-   /* XXX we need to be able to parse uniform names for structs and arrays
-    * such as:
-    *   mymatrix[1]
-    *   mystruct.field1
+extern "C" bool
+_mesa_sampler_uniforms_pipeline_are_valid(struct gl_pipeline_object *pipeline)
+{
+   /* Section 2.11.11 (Shader Execution), subheading "Validation," of the
+    * OpenGL 4.1 spec says:
+    *
+    *     "[INVALID_OPERATION] is generated by any command that transfers
+    *     vertices to the GL if:
+    *
+    *         ...
+    *
+    *         - Any two active samplers in the current program object are of
+    *           different types, but refer to the same texture image unit.
+    *
+    *         - The number of active samplers in the program exceeds the
+    *           maximum number of texture image units allowed."
     */
-
-   {
-      /* handle 1-dimension arrays here... */
-      char *c = strchr((char *)name, '[');
-      if (c) {
-         /* truncate name at [ */
-         const GLint len = c - name;
-         GLchar *newName = (GLchar *) malloc(len + 1);
-         if (!newName)
-            return -1; /* out of mem */
-         memcpy(newName, name, len);
-         newName[len] = 0;
-
-         location = _mesa_lookup_uniform(shProg->Uniforms, newName);
-         if (location >= 0) {
-            const GLint element = atoi(c + 1);
-            if (element > 0) {
-               /* get type of the uniform array element */
-               const struct gl_program_parameter *p =
-                  get_uniform_parameter(shProg, location);
-               if (p) {
-                  GLint rows, cols;
-                  get_matrix_dims(p->DataType, &rows, &cols);
-                  if (rows < 1)
-                     rows = 1;
-                  offset = element * rows;
-               }
+   unsigned active_samplers = 0;
+   const struct gl_shader_program **shProg =
+      (const struct gl_shader_program **) pipeline->CurrentProgram;
+
+   const glsl_type *unit_types[MAX_COMBINED_TEXTURE_IMAGE_UNITS];
+   memset(unit_types, 0, sizeof(unit_types));
+
+   for (unsigned idx = 0; idx < ARRAY_SIZE(pipeline->CurrentProgram); idx++) {
+      if (!shProg[idx])
+         continue;
+
+      for (unsigned i = 0; i < shProg[idx]->NumUniformStorage; i++) {
+         const struct gl_uniform_storage *const storage =
+            &shProg[idx]->UniformStorage[i];
+
+         if (!storage->type->is_sampler())
+            continue;
+
+         active_samplers++;
+
+         const unsigned count = MAX2(1, storage->array_elements);
+         for (unsigned j = 0; j < count; j++) {
+            const unsigned unit = storage->storage[j].i;
+
+            /* FIXME: Samplers are initialized to 0 and Mesa doesn't do a
+             * great job of eliminating unused uniforms currently so for now
+             * don't throw an error if two sampler types both point to 0.
+             */
+            if (unit == 0)
+               continue;
+
+            /* The types of the samplers associated with a particular texture
+             * unit must be an exact match.  Page 74 (page 89 of the PDF) of
+             * the OpenGL 3.3 core spec says:
+             *
+             *     "It is not allowed to have variables of different sampler
+             *     types pointing to the same texture image unit within a
+             *     program object."
+             */
+            if (unit_types[unit] == NULL) {
+               unit_types[unit] = storage->type;
+            } else if (unit_types[unit] != storage->type) {
+               pipeline->InfoLog =
+                  ralloc_asprintf(pipeline,
+                                  "Texture unit %d is accessed both as %s "
+                                  "and %s",
+                                  unit, unit_types[unit]->name,
+                                  storage->type->name);
+               return false;
             }
          }
-
-         free(newName);
       }
    }
 
-   if (location < 0) {
-      location = _mesa_lookup_uniform(shProg->Uniforms, name);
-   }
-
-   if (location < 0) {
-      return -1;
+   if (active_samplers > MAX_COMBINED_TEXTURE_IMAGE_UNITS) {
+      pipeline->InfoLog =
+         ralloc_asprintf(pipeline,
+                         "the number of active samplers %d exceed the "
+                         "maximum %d",
+                         active_samplers, MAX_COMBINED_TEXTURE_IMAGE_UNITS);
+      return false;
    }
 
-   return _mesa_uniform_merge_location_offset(location, offset);
+   return true;
 }