state.depth.range alpha value should be 1, not 0 (bug #14733)
[mesa.git] / src / mesa / shader / shader_api.c
index 64f2a9fa12682be847da004a57147aec6a122cec..e9c35fce71562ae090964aac8c83c5bfc5cb3208 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Mesa 3-D graphics library
- * Version:  6.5.3
+ * Version:  7.0
  *
  * Copyright (C) 2004-2007  Brian Paul   All Rights Reserved.
  *
 #include "prog_parameter.h"
 #include "prog_print.h"
 #include "prog_statevars.h"
-#include "shader_api.h"
-
-#include "slang_compile.h"
-#include "slang_link.h"
+#include "shader/shader_api.h"
+#include "shader/slang/slang_compile.h"
+#include "shader/slang/slang_link.h"
 
 
 
@@ -179,7 +178,7 @@ _mesa_reference_shader_program(GLcontext *ctx,
       deleteFlag = (old->RefCount == 0);
 
       if (deleteFlag) {
-         _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
+         _mesa_HashRemove(ctx->Shared->ShaderProgramObjects, old->Name);
          _mesa_free_shader_program(ctx, old);
       }
 
@@ -205,7 +204,7 @@ _mesa_lookup_shader_program(GLcontext *ctx, GLuint name)
    struct gl_shader_program *shProg;
    if (name) {
       shProg = (struct gl_shader_program *)
-         _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
+         _mesa_HashLookup(ctx->Shared->ShaderProgramObjects, name);
       /* Note that both gl_shader and gl_shader_program objects are kept
        * in the same hash table.  Check the object's type to be sure it's
        * what we're expecting.
@@ -369,6 +368,54 @@ copy_string(GLchar *dst, GLsizei maxLength, GLsizei *length, const GLchar *src)
 }
 
 
+/**
+ * Return size (in floats) of the given GLSL type.
+ * See also _slang_sizeof_type_specifier().
+ */
+static GLint
+sizeof_glsl_type(GLenum type)
+{
+   switch (type) {
+   case GL_BOOL:
+   case GL_FLOAT:
+   case GL_INT:
+      return 1;
+   case GL_BOOL_VEC2:
+   case GL_FLOAT_VEC2:
+   case GL_INT_VEC2:
+      return 2;
+   case GL_BOOL_VEC3:
+   case GL_FLOAT_VEC3:
+   case GL_INT_VEC3:
+      return 3;
+   case GL_BOOL_VEC4:
+   case GL_FLOAT_VEC4:
+   case GL_INT_VEC4:
+      return 4;
+   case GL_FLOAT_MAT2:
+      return 8;  /* 2 rows of 4, actually */
+   case GL_FLOAT_MAT3:
+      return 12;  /* 3 rows of 4, actually */
+   case GL_FLOAT_MAT4:
+      return 16;
+   case GL_FLOAT_MAT2x3:
+      return 8;   /* 2 rows of 4, actually */
+   case GL_FLOAT_MAT2x4:
+      return 8;
+   case GL_FLOAT_MAT3x2:
+      return 12;  /* 3 rows of 4, actually */
+   case GL_FLOAT_MAT3x4:
+      return 12;
+   case GL_FLOAT_MAT4x2:
+      return 16;  /* 4 rows of 4, actually */
+   case GL_FLOAT_MAT4x3:
+      return 16;  /* 4 rows of 4, actually */
+   default:
+      return 0; /* error */
+   }
+}
+
+
 /**
  * Called via ctx->Driver.AttachShader()
  */
@@ -378,7 +425,7 @@ _mesa_attach_shader(GLcontext *ctx, GLuint program, GLuint shader)
    struct gl_shader_program *shProg
       = _mesa_lookup_shader_program(ctx, program);
    struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
-   const GLuint n = shProg->NumShaders;
+   GLuint n;
    GLuint i;
 
    if (!shProg || !sh) {
@@ -387,6 +434,8 @@ _mesa_attach_shader(GLcontext *ctx, GLuint program, GLuint shader)
       return;
    }
 
+   n = shProg->NumShaders;
+
    for (i = 0; i < n; i++) {
       if (shProg->Shaders[i] == sh) {
          /* already attached */
@@ -487,10 +536,10 @@ _mesa_create_program(GLcontext *ctx)
    GLuint name;
    struct gl_shader_program *shProg;
 
-   name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
+   name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderProgramObjects, 1);
    shProg = _mesa_new_shader_program(ctx, name);
 
-   _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg);
+   _mesa_HashInsert(ctx->Shared->ShaderProgramObjects, name, shProg);
 
    assert(shProg->RefCount == 1);
 
@@ -548,7 +597,7 @@ _mesa_detach_shader(GLcontext *ctx, GLuint program, GLuint shader)
 {
    struct gl_shader_program *shProg
       = _mesa_lookup_shader_program(ctx, program);
-   const GLuint n = shProg->NumShaders;
+   GLuint n;
    GLuint i, j;
 
    if (!shProg) {
@@ -557,6 +606,8 @@ _mesa_detach_shader(GLcontext *ctx, GLuint program, GLuint shader)
       return;
    }
 
+   n = shProg->NumShaders;
+
    for (i = 0; i < n; i++) {
       if (shProg->Shaders[i]->Name == shader) {
          /* found it */
@@ -629,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];
 }
 
 
@@ -662,13 +713,17 @@ _mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index,
       if (shProg->Uniforms->Parameters[j].Type == PROGRAM_UNIFORM ||
           shProg->Uniforms->Parameters[j].Type == PROGRAM_SAMPLER) {
          if (ind == index) {
+            GLuint uSize = shProg->Uniforms->Parameters[j].Size;
+            GLenum uType = shProg->Uniforms->Parameters[j].DataType;
             /* found it */
             copy_string(nameOut, maxLength, length,
                         shProg->Uniforms->Parameters[j].Name);
-            if (size)
-               *size = shProg->Uniforms->Parameters[j].Size;
+            if (size) {
+               /* convert from floats to 'type' (eg: sizeof(mat4x4)=1) */
+               *size = uSize / sizeof_glsl_type(uType);
+            }
             if (type)
-               *type = shProg->Uniforms->Parameters[j].DataType;
+               *type = uType;
             return;
          }
          ind++;
@@ -780,7 +835,7 @@ _mesa_get_programiv(GLcontext *ctx, GLuint program,
       *params = shProg->Validated;
       break;
    case GL_INFO_LOG_LENGTH:
-      *params = shProg->InfoLog ? strlen(shProg->InfoLog) : 0;
+      *params = shProg->InfoLog ? strlen(shProg->InfoLog) + 1 : 0;
       break;
    case GL_ATTACHED_SHADERS:
       *params = shProg->NumShaders;
@@ -832,10 +887,10 @@ _mesa_get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params)
       *params = shader->CompileStatus;
       break;
    case GL_INFO_LOG_LENGTH:
-      *params = shader->InfoLog ? strlen(shader->InfoLog) : 0;
+      *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0;
       break;
    case GL_SHADER_SOURCE_LENGTH:
-      *params = shader->Source ? strlen((char *) shader->Source) : 0;
+      *params = shader->Source ? strlen((char *) shader->Source) + 1 : 0;
       break;
    default:
       _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)");
@@ -899,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)");
@@ -1055,29 +1141,46 @@ _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 */
+
+   /* The spec says this is GL_INVALID_OPERATION, although it seems like it
+    * ought to be GL_INVALID_VALUE
+    */
    if (location < 0 || location >= (GLint) shProg->Uniforms->NumParameters) {
-      _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)");
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(location)");
       return;
    }
 
    FLUSH_VERTICES(ctx, _NEW_PROGRAM);
 
+   uType = shProg->Uniforms->Parameters[location].DataType;
    /*
     * If we're setting a sampler, we must use glUniformi1()!
     */
    if (shProg->Uniforms->Parameters[location].Type == PROGRAM_SAMPLER) {
+      GLint unit;
       if (type != GL_INT || count != 1) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
                      "glUniform(only glUniform1i can be used "
                      "to set sampler uniforms)");
          return;
       }
+      /* check that the sampler (tex unit index) is legal */
+      unit = ((GLint *) values)[0];
+      if (unit >= ctx->Const.MaxTextureImageUnits) {
+         _mesa_error(ctx, GL_INVALID_VALUE,
+                     "glUniform1(invalid sampler/tex unit index)");
+         return;
+      }
    }
 
    if (count < 0) {
@@ -1107,11 +1210,37 @@ _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(uType)) {
+            _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count mismatch)");
+         }
+         break;
+      case PROGRAM_SAMPLER:
+         break;
+      default:
+         if (shProg->Uniforms->Parameters[location].Type != PROGRAM_SAMPLER 
+             && 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 ||
@@ -1129,6 +1258,13 @@ _mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
             uniformVal[i] = fValues[i];
          }
       }
+      if (uType == GL_BOOL ||
+          uType == GL_BOOL_VEC2 ||
+          uType == GL_BOOL_VEC3 ||
+          uType == GL_BOOL_VEC4) {
+          for (i = 0; i < elems; i++)
+              uniformVal[i] = uniformVal[i] ? 1.0f : 0.0f;
+      }
    }
 
    if (shProg->Uniforms->Parameters[location].Type == PROGRAM_SAMPLER) {
@@ -1149,20 +1285,30 @@ _mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
                      GLenum matrixType, GLint location, GLsizei count,
                      GLboolean transpose, const GLfloat *values)
 {
+   GLsizei maxCount, i;
    struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
    if (!shProg || !shProg->LinkStatus) {
       _mesa_error(ctx, GL_INVALID_OPERATION,
          "glUniformMatrix(program not linked)");
       return;
    }
-   if (location < 0 || location >= shProg->Uniforms->NumParameters) {
-      _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
+   if (location == -1)
+      return;   /* The standard specifies this as a no-op */
+   /* The spec says this is GL_INVALID_OPERATION, although it seems like it
+    * ought to be GL_INVALID_VALUE
+    */
+   if (location < 0 || location >= (GLint) shProg->Uniforms->NumParameters) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glUniformMatrix(location)");
       return;
    }
    if (values == NULL) {
       _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
       return;
    }
+   if (count < 0) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(count < 0)");
+      return;
+   }
 
    FLUSH_VERTICES(ctx, _NEW_PROGRAM);
 
@@ -1171,23 +1317,30 @@ _mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
     * the rows.
     */
    /* XXXX need to test 3x3 and 2x2 matrices... */
-   if (transpose) {
-      GLuint row, col;
-      for (col = 0; col < cols; col++) {
-         GLfloat *v = shProg->Uniforms->ParameterValues[location + col];
-         for (row = 0; row < rows; row++) {
-            v[row] = values[row * cols + col];
+   maxCount = shProg->Uniforms->Parameters[location].Size / (4 * cols);
+   if (count > maxCount)
+      count = maxCount;
+   for (i = 0; i < count; i++) {
+      if (transpose) {
+         GLuint row, col;
+         for (col = 0; col < cols; col++) {
+            GLfloat *v = shProg->Uniforms->ParameterValues[location + col];
+            for (row = 0; row < rows; row++) {
+               v[row] = values[row * cols + col];
+            }
          }
       }
-   }
-   else {
-      GLuint row, col;
-      for (col = 0; col < cols; col++) {
-         GLfloat *v = shProg->Uniforms->ParameterValues[location + col];
-         for (row = 0; row < rows; row++) {
-            v[row] = values[col * rows + row];
+      else {
+         GLuint row, col;
+         for (col = 0; col < cols; col++) {
+            GLfloat *v = shProg->Uniforms->ParameterValues[location + col];
+            for (row = 0; row < rows; row++) {
+               v[row] = values[col * rows + row];
+            }
          }
       }
+      location += cols;
+      values += rows * cols;
    }
 }