Fix several bugs relating to uniforms and attributes in GLSL API
authorBruce Merry <bmerry@users.sourceforge.net>
Fri, 21 Dec 2007 12:41:45 +0000 (14:41 +0200)
committerBrian <brian.paul@tungstengraphics.com>
Tue, 1 Jan 2008 16:58:15 +0000 (09:58 -0700)
- fix sizes for GL_FLOAT_MAT2x3 and GL_FLOAT_MAT4x3 in sizeof_glsl_type
- fix size returns in _mesa_get_active_attrib
- fix out-of-bounds array access to vec_types in _mesa_get_active_attrib
- fix queries of matrix uniforms in _mesa_get_uniformfv
- fix _mesa_get_uniformfv to only return one base, even from an array
- allow location == -1 in _mesa_uniform
- validate types in _mesa_uniform
- allow array overruns in _mesa_uniform

src/mesa/shader/shader_api.c

index 82c2b857fff4bb63468f61cbd372ad3db0422531..4e039cba426b9bd321c0d70d1a110a2a84296fda 100644 (file)
@@ -399,7 +399,7 @@ sizeof_glsl_type(GLenum type)
    case GL_FLOAT_MAT4:
       return 16;
    case GL_FLOAT_MAT2x3:
-      return 6;
+      return 8;   /* 2 rows of 4, actually */
    case GL_FLOAT_MAT2x4:
       return 8;
    case GL_FLOAT_MAT3x2:
@@ -409,7 +409,7 @@ sizeof_glsl_type(GLenum type)
    case GL_FLOAT_MAT4x2:
       return 16;  /* 4 rows of 4, actually */
    case GL_FLOAT_MAT4x3:
-      return 12;
+      return 16;  /* 4 rows of 4, actually */
    default:
       return 0; /* error */
    }
@@ -680,9 +680,9 @@ _mesa_get_active_attrib(GLcontext *ctx, GLuint program, GLuint index,
                shProg->Attributes->Parameters[index].Name);
    sz = shProg->Attributes->Parameters[index].Size;
    if (size)
-      *size = sz;
-   if (type)
-      *type = vec_types[sz]; /* XXX this is a temporary hack */
+      *size = 1;   /* attributes may not be arrays */
+   if (type && sz > 0 && sz <= 4)  /* XXX this is a temporary hack */
+      *type = vec_types[sz - 1];
 }
 
 
@@ -954,9 +954,40 @@ _mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
    if (shProg) {
       GLint i;
       if (location >= 0 && location < shProg->Uniforms->NumParameters) {
-         for (i = 0; i < shProg->Uniforms->Parameters[location].Size; i++) {
-            params[i] = shProg->Uniforms->ParameterValues[location][i];
+         GLuint uSize;
+         GLenum uType;
+         GLint rows = 0;
+         uType = shProg->Uniforms->Parameters[location].DataType;
+         uSize = sizeof_glsl_type(uType);
+         /* Matrix types need special handling, because they span several
+          * parameters, and may also not be fully packed.
+          */
+         switch (shProg->Uniforms->Parameters[location].DataType) {
+            case GL_FLOAT_MAT2:
+            case GL_FLOAT_MAT3x2:
+            case GL_FLOAT_MAT4x2:
+               rows = 2;
+               break;
+            case GL_FLOAT_MAT2x3:
+            case GL_FLOAT_MAT3:
+            case GL_FLOAT_MAT4x3:
+               rows = 3;
+               break;
+            case GL_FLOAT_MAT2x4:
+            case GL_FLOAT_MAT3x4:
+            case GL_FLOAT_MAT4:
+               rows = 4;
+         }
+         if (rows != 0) {
+            GLint r, c;
+            for (c = 0, i = 0; c * 4 < uSize; c++)
+               for (r = 0; r < rows; r++, i++)
+                  params[i] = shProg->Uniforms->ParameterValues[location + c][r];
          }
+         else
+            for (i = 0; i < uSize; i++) {
+               params[i] = shProg->Uniforms->ParameterValues[location][i];
+            }
       }
       else {
          _mesa_error(ctx, GL_INVALID_VALUE, "glGetUniformfv(location)");
@@ -1110,12 +1141,17 @@ _mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
 {
    struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
    GLint elems, i, k;
+   GLenum uType;
+   GLsizei maxCount;
 
    if (!shProg || !shProg->LinkStatus) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
       return;
    }
 
+   if (location == -1)
+      return;   /* The standard specifies this as a no-op */
+
    if (location < 0 || location >= (GLint) shProg->Uniforms->NumParameters) {
       _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)");
       return;
@@ -1123,10 +1159,11 @@ _mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
 
    FLUSH_VERTICES(ctx, _NEW_PROGRAM);
 
+   uType = shProg->Uniforms->Parameters[location].Type;
    /*
     * If we're setting a sampler, we must use glUniformi1()!
     */
-   if (shProg->Uniforms->Parameters[location].Type == PROGRAM_SAMPLER) {
+   if (uType == PROGRAM_SAMPLER) {
       GLint unit;
       if (type != GL_INT || count != 1) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
@@ -1170,11 +1207,36 @@ _mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
       return;
    }
 
-   if (count * elems > shProg->Uniforms->Parameters[location].Size) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count too large)");
-      return;
+   /* OpenGL requires types to match exactly, except that one can convert
+    * float or int array to boolean array.
+    */
+   switch (uType)
+   {
+      case GL_BOOL:
+      case GL_BOOL_VEC2:
+      case GL_BOOL_VEC3:
+      case GL_BOOL_VEC4:
+         if (elems != sizeof_glsl_type(shProg->Uniforms->Parameters[location].DataType)) {
+            _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count mismatch)");
+         }
+         break;
+      case PROGRAM_SAMPLER:
+         break;
+      default:
+         if (uType != type) {
+            _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)");
+         }
+         break;
    }
 
+   /* XXX if this is a base type, then count must equal 1. However, we
+    * don't have enough information from the compiler to distinguish a
+    * base type from a 1-element array of that type. The standard allows
+    * count to overrun an array, in which case the overflow is ignored.
+    */
+   maxCount = shProg->Uniforms->Parameters[location].Size / elems;
+   if (count > maxCount) count = maxCount;
+
    for (k = 0; k < count; k++) {
       GLfloat *uniformVal = shProg->Uniforms->ParameterValues[location + k];
       if (type == GL_INT ||