mesa: Fix glGetUniform() type conversions.
authorEric Anholt <eric@anholt.net>
Tue, 23 Aug 2011 20:46:12 +0000 (13:46 -0700)
committerEric Anholt <eric@anholt.net>
Tue, 30 Aug 2011 19:09:40 +0000 (12:09 -0700)
We were primarily failing to convert in the NativeIntegers case, which
this fixes.  However, we were also just truncating float uniforms when
converting to integer, which does not appear to be the correct
behavior.  Note, however, that the NVIDIA drivers also truncate
instead of rounding.

GL_DOUBLE return type is dropped because it was never used and
completely broken.  It can be added when there's test code.

Fixes piglit ARB_shader_objects/getuniform

v2: This is a rewrite of my previous glGetUniform patch, which Ken
    pointed out missed storage_type-based conversions to integer,
    which was totally broken still thanks to a typo in the testcase.
v3: Quote the spec justifying the rounding behavior.

Acked-by: Kenneth Graunke <kenneth@whitecape.org>
Acked-by: Ian Romanick <ian.d.romanick@intel.com>
src/mesa/main/uniforms.c

index cda840fe2d201c78f00d67c4982c3db8f25e1acb..fe1ce6d7b2c8457990e40cf845d1deb9034c7675 100644 (file)
@@ -55,17 +55,24 @@ static GLenum
 base_uniform_type(GLenum type)
 {
    switch (type) {
-#if 0 /* not needed, for now */
    case GL_BOOL:
    case GL_BOOL_VEC2:
    case GL_BOOL_VEC3:
    case GL_BOOL_VEC4:
       return GL_BOOL;
-#endif
    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:
@@ -408,8 +415,12 @@ get_uniform(struct gl_context *ctx, GLuint program, GLint location,
    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);
 
@@ -421,62 +432,72 @@ get_uniform(struct gl_context *ctx, GLuint program, GLint location,
          return;
       }
 
-      switch (returnType) {
-      case GL_FLOAT:
-         {
-            GLfloat *params = (GLfloat *) paramsOut;
-            k = 0;
-            for (i = 0; i < rows; i++) {
-               const int base = paramPos + offset + i;
-               for (j = 0; j < cols; j++ ) {
-                  params[k++] = prog->Parameters->ParameterValues[base][j].f;
-               }
-            }
-         }
-         break;
-      case GL_DOUBLE:
-         {
-            GLfloat *params = (GLfloat *) paramsOut;
-            k = 0;
-            for (i = 0; i < rows; i++) {
-               const int base = paramPos + offset + i;
-               for (j = 0; j < cols; j++ ) {
-                  params[k++] = (GLdouble)
-                     prog->Parameters->ParameterValues[base][j].f;
-               }
-            }
-         }
-         break;
-      case GL_INT:
-         {
-            GLint *params = (GLint *) paramsOut;
-            k = 0;
-            for (i = 0; i < rows; i++) {
-               const int base = paramPos + offset + i;
-               for (j = 0; j < cols; j++ ) {
-                  params[k++] = ctx->Const.NativeIntegers ?
-                     prog->Parameters->ParameterValues[base][j].i :
-                     (GLint) prog->Parameters->ParameterValues[base][j].f;
-               }
-            }
-         }
-         break;
-      case GL_UNSIGNED_INT:
-         {
-            GLuint *params = (GLuint *) paramsOut;
-            k = 0;
-            for (i = 0; i < rows; i++) {
-               const int base = paramPos + offset + i;
-               for (j = 0; j < cols; j++ ) {
-                  params[k++] = ctx->Const.NativeIntegers ?
-                     prog->Parameters->ParameterValues[base][j].u :
-                     (GLuint) prog->Parameters->ParameterValues[base][j].f;
-               }
-            }
-         }
-         break;
-      default:
-         _mesa_problem(ctx, "bad returnType in get_uniform()");
+      if (ctx->Const.NativeIntegers) {
+        storage_type = base_uniform_type(p->DataType);
+      } else {
+        storage_type = GL_FLOAT;
+      }
+
+      k = 0;
+      for (i = 0; i < rows; i++) {
+        for (j = 0; j < cols; j++ ) {
+           void *out = (char *)paramsOut + 4 * k;
+
+           switch (returnType) {
+           case GL_FLOAT:
+              switch (storage_type) {
+              case GL_FLOAT:
+                 *(float *)out = values[i][j].f;
+                 break;
+              case GL_INT:
+              case GL_BOOL: /* boolean is just an integer 1 or 0. */
+                 *(float *)out = values[i][j].i;
+                 break;
+              case GL_UNSIGNED_INT:
+                 *(float *)out = values[i][j].u;
+                 break;
+              }
+              break;
+
+           case GL_INT:
+           case GL_UNSIGNED_INT:
+              switch (storage_type) {
+              case GL_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
+                  * page 267 it says:
+                  *
+                  *     "Unless otherwise specified, when floating
+                  *      point state is returned as integer values or
+                  *      integer state is returned as floating-point
+                  *      values it is converted in the fashion
+                  *      described in section 6.1.2"
+                  *
+                  * That section, on page 248, says:
+                  *
+                  *     "If GetIntegerv or GetInteger64v are called,
+                  *      a floating-point value is rounded to the
+                  *      nearest integer..."
+                  */
+                 *(int *)out = IROUND(values[i][j].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;
+                 break;
+                 break;
+              }
+              break;
+           }
+
+           k++;
+        }
       }
    }
 }