implement full reference counting for vertex/fragment programs
[mesa.git] / src / mesa / shader / prog_statevars.c
index d6c552a71ff47e106d978ae815e6912454acd852..4ae74c1d42b0aa8869ef2c397d44c306a583235d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Mesa 3-D graphics library
- * Version:  6.5.3
+ * Version:  7.1
  *
  * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
  *
@@ -116,19 +116,22 @@ _mesa_fetch_state(GLcontext *ctx, const gl_state_index state[],
             COPY_3V(value, ctx->Light.Light[ln].EyeDirection);
             value[3] = ctx->Light.Light[ln]._CosCutoff;
             return;
-         case STATE_HALF:
+         case STATE_SPOT_CUTOFF:
+            value[0] = ctx->Light.Light[ln].SpotCutoff;
+            return;
+         case STATE_HALF_VECTOR:
             {
-               GLfloat eye_z[] = {0, 0, 1};
-                                       
+               static const GLfloat eye_z[] = {0, 0, 1};
+               GLfloat p[3];
                /* Compute infinite half angle vector:
-                *   half-vector = light_position + (0, 0, 1) 
-                * and then normalize.  w = 0
-               *
+                *   halfVector = normalize(normalize(lightPos) + (0, 0, 1))
                * light.EyePosition.w should be 0 for infinite lights.
                 */
-              ADD_3V(value, eye_z, ctx->Light.Light[ln].EyePosition);
+               COPY_3V(p, ctx->Light.Light[ln].EyePosition);
+               NORMALIZE_3FV(p);
+              ADD_3V(value, p, eye_z);
               NORMALIZE_3FV(value);
-              value[3] = 0;
+              value[3] = 1.0;
             }                                            
             return;
         case STATE_POSITION_NORMALIZED:
@@ -178,7 +181,7 @@ _mesa_fetch_state(GLcontext *ctx, const gl_state_index state[],
                      ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_AMBIENT+face][i];
                }
                /* [3] = material alpha */
-               value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE+face][3];
+               value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_AMBIENT+face][3];
                return;
             case STATE_DIFFUSE:
                for (i = 0; i < 3; i++) {
@@ -194,7 +197,7 @@ _mesa_fetch_state(GLcontext *ctx, const gl_state_index state[],
                      ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SPECULAR+face][i];
                }
                /* [3] = material alpha */
-               value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE+face][3];
+               value[3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_SPECULAR+face][3];
                return;
             default:
                _mesa_problem(ctx, "Invalid lightprod state in fetch_state");
@@ -243,17 +246,14 @@ _mesa_fetch_state(GLcontext *ctx, const gl_state_index state[],
          COPY_4V(value, ctx->Texture.Unit[unit].EnvColor);
       }                        
       return;
-   case STATE_FOG:
-      if (state[1] == STATE_FOG_COLOR) {
-         COPY_4V(value, ctx->Fog.Color);
-      }
-      else {
-         ASSERT(state[1] == STATE_FOG_PARAMS);
-         value[0] = ctx->Fog.Density;
-         value[1] = ctx->Fog.Start;
-         value[2] = ctx->Fog.End;
-         value[3] = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
-      }
+   case STATE_FOG_COLOR:
+      COPY_4V(value, ctx->Fog.Color);
+      return;
+   case STATE_FOG_PARAMS:
+      value[0] = ctx->Fog.Density;
+      value[1] = ctx->Fog.Start;
+      value[2] = ctx->Fog.End;
+      value[3] = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
       return;
    case STATE_CLIPPLANE:
       {
@@ -278,28 +278,18 @@ _mesa_fetch_state(GLcontext *ctx, const gl_state_index state[],
    case STATE_MVP_MATRIX:
    case STATE_TEXTURE_MATRIX:
    case STATE_PROGRAM_MATRIX:
-      /*case STATE_MATRIX:*/
       {
-         /* state[1] = modelview, projection, texture, etc. */
-         /* state[2] = which texture matrix or program matrix */
-         /* state[3] = first row to fetch */
-         /* state[4] = last row to fetch */
-         /* state[5] = transpose, inverse or invtrans */
-
+         /* state[0] = modelview, projection, texture, etc. */
+         /* state[1] = which texture matrix or program matrix */
+         /* state[2] = first row to fetch */
+         /* state[3] = last row to fetch */
+         /* state[4] = transpose, inverse or invtrans */
          const GLmatrix *matrix;
-#if 0
-         const gl_state_index mat = state[1];
-         const GLuint index = (GLuint) state[2];
-         const GLuint firstRow = (GLuint) state[3];
-         const GLuint lastRow = (GLuint) state[4];
-         const gl_state_index modifier = state[5];
-#else
          const gl_state_index mat = state[0];
          const GLuint index = (GLuint) state[1];
          const GLuint firstRow = (GLuint) state[2];
          const GLuint lastRow = (GLuint) state[3];
          const gl_state_index modifier = state[4];
-#endif
          const GLfloat *m;
          GLuint row, i;
          ASSERT(firstRow >= 0);
@@ -359,7 +349,7 @@ _mesa_fetch_state(GLcontext *ctx, const gl_state_index state[],
       value[0] = ctx->Viewport.Near;                     /* near       */
       value[1] = ctx->Viewport.Far;                      /* far        */
       value[2] = ctx->Viewport.Far - ctx->Viewport.Near; /* far - near */
-      value[3] = 0;
+      value[3] = 1.0;
       return;
    case STATE_FRAGMENT_PROGRAM:
       {
@@ -399,27 +389,56 @@ _mesa_fetch_state(GLcontext *ctx, const gl_state_index state[],
       }
       return;
 
+   case STATE_NORMAL_SCALE:
+      ASSIGN_4V(value, ctx->_ModelViewInvScale, 0, 0, 1);
+      return;
+
    case STATE_INTERNAL:
-      {
-         switch (state[1]) {
-           case STATE_NORMAL_SCALE:
-               ASSIGN_4V(value, ctx->_ModelViewInvScale, 0, 0, 1);
-               break;
-           case STATE_TEXRECT_SCALE: {
-              const int unit = (int) state[2];
-              const struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current;
-              if (texObj) {
-                 struct gl_texture_image *texImage = texObj->Image[0][0];
-                 ASSIGN_4V(value, 1.0 / texImage->Width, 1.0 / texImage->Height, 0, 1);
-              }
-               break;
-           }
-           default:
-              /* unknown state indexes are silently ignored
-              *  should be handled by the driver.
-              */
-               return;
+      switch (state[1]) {
+      case STATE_NORMAL_SCALE:
+         ASSIGN_4V(value, ctx->_ModelViewInvScale, 0, 0, 1);
+         return;
+      case STATE_TEXRECT_SCALE:
+         {
+            const int unit = (int) state[2];
+            const struct gl_texture_object *texObj
+               = ctx->Texture.Unit[unit]._Current;
+            if (texObj) {
+               struct gl_texture_image *texImage = texObj->Image[0][0];
+               ASSIGN_4V(value, 1.0 / texImage->Width,
+                         1.0 / texImage->Height,
+                         0.0, 1.0);
+            }
          }
+         return;
+      case STATE_FOG_PARAMS_OPTIMIZED:
+         /* for simpler per-vertex/pixel fog calcs. POW (for EXP/EXP2 fog)
+          * might be more expensive than EX2 on some hw, plus it needs
+          * another constant (e) anyway. Linear fog can now be done with a
+          * single MAD.
+          * linear: fogcoord * -1/(end-start) + end/(end-start)
+          * exp: 2^-(density/ln(2) * fogcoord)
+          * exp2: 2^-((density/(ln(2)^2) * fogcoord)^2)
+          */
+         value[0] = -1.0F / (ctx->Fog.End - ctx->Fog.Start);
+         value[1] = ctx->Fog.End / (ctx->Fog.End - ctx->Fog.Start);
+         value[2] = ctx->Fog.Density * ONE_DIV_LN2;
+         value[3] = ctx->Fog.Density * ONE_DIV_SQRT_LN2;
+         return;
+      case STATE_SPOT_DIR_NORMALIZED: {
+         /* here, state[2] is the light number */
+         /* pre-normalize spot dir */
+         const GLuint ln = (GLuint) state[2];
+         COPY_3V(value, ctx->Light.Light[ln].EyeDirection);
+         NORMALIZE_3FV(value);
+         value[3] = ctx->Light.Light[ln]._CosCutoff;
+         return;
+      }
+      default:
+         /* unknown state indexes are silently ignored
+          *  should be handled by the driver.
+          */
+         return;
       }
       return;
 
@@ -438,7 +457,7 @@ _mesa_fetch_state(GLcontext *ctx, const gl_state_index state[],
  * some GL state has changed.
  */
 GLbitfield
-_mesa_program_state_flags(const GLint state[STATE_LENGTH])
+_mesa_program_state_flags(const gl_state_index state[STATE_LENGTH])
 {
    switch (state[0]) {
    case STATE_MATERIAL:
@@ -452,11 +471,8 @@ _mesa_program_state_flags(const GLint state[STATE_LENGTH])
    case STATE_TEXENV_COLOR:
       return _NEW_TEXTURE;
 
-   case STATE_FOG:
-#if 0
    case STATE_FOG_COLOR:
    case STATE_FOG_PARAMS:
-#endif
       return _NEW_FOG;
 
    case STATE_CLIPPLANE:
@@ -484,12 +500,15 @@ _mesa_program_state_flags(const GLint state[STATE_LENGTH])
    case STATE_VERTEX_PROGRAM:
       return _NEW_PROGRAM;
 
+   case STATE_NORMAL_SCALE:
+      return _NEW_MODELVIEW;
+
    case STATE_INTERNAL:
       switch (state[1]) {
-      case STATE_NORMAL_SCALE:
-        return _NEW_MODELVIEW;
       case STATE_TEXRECT_SCALE:
         return _NEW_TEXTURE;
+      case STATE_FOG_PARAMS_OPTIMIZED:
+        return _NEW_FOG;
       default:
          /* unknown state indexes are silently ignored and
          *  no flag set, since it is handled by the driver.
@@ -520,7 +539,7 @@ append_token(char *dst, gl_state_index k)
 {
    switch (k) {
    case STATE_MATERIAL:
-      append(dst, "material.");
+      append(dst, "material");
       break;
    case STATE_LIGHT:
       append(dst, "light");
@@ -536,14 +555,11 @@ append_token(char *dst, gl_state_index k)
    case STATE_TEXGEN:
       append(dst, "texgen");
       break;
-   case STATE_FOG:
-      append(dst, "fog");
-      break;
    case STATE_FOG_COLOR:
-      append(dst, ".color");
+      append(dst, "fog.color");
       break;
    case STATE_FOG_PARAMS:
-      append(dst, ".params");
+      append(dst, "fog.params");
       break;
    case STATE_CLIPPLANE:
       append(dst, "clip");
@@ -555,19 +571,19 @@ append_token(char *dst, gl_state_index k)
       append(dst, "point.attenuation");
       break;
    case STATE_MODELVIEW_MATRIX:
-      append(dst, "modelview");
+      append(dst, "matrix.modelview");
       break;
    case STATE_PROJECTION_MATRIX:
-      append(dst, "projection");
+      append(dst, "matrix.projection");
       break;
    case STATE_MVP_MATRIX:
-      append(dst, "mvp");
+      append(dst, "matrix.mvp");
       break;
    case STATE_TEXTURE_MATRIX:
-      append(dst, "texture");
+      append(dst, "matrix.texture");
       break;
    case STATE_PROGRAM_MATRIX:
-      append(dst, "program");
+      append(dst, "matrix.program");
       break;
    case STATE_MATRIX_INVERSE:
       append(dst, ".inverse");
@@ -579,22 +595,22 @@ append_token(char *dst, gl_state_index k)
       append(dst, ".invtrans");
       break;
    case STATE_AMBIENT:
-      append(dst, "ambient");
+      append(dst, ".ambient");
       break;
    case STATE_DIFFUSE:
-      append(dst, "diffuse");
+      append(dst, ".diffuse");
       break;
    case STATE_SPECULAR:
-      append(dst, "specular");
+      append(dst, ".specular");
       break;
    case STATE_EMISSION:
-      append(dst, "emission");
+      append(dst, ".emission");
       break;
    case STATE_SHININESS:
-      append(dst, "shininess");
+      append(dst, "lshininess");
       break;
-   case STATE_HALF:
-      append(dst, "half");
+   case STATE_HALF_VECTOR:
+      append(dst, ".half");
       break;
    case STATE_POSITION:
       append(dst, ".position");
@@ -605,6 +621,9 @@ append_token(char *dst, gl_state_index k)
    case STATE_SPOT_DIRECTION:
       append(dst, ".spot.direction");
       break;
+   case STATE_SPOT_CUTOFF:
+      append(dst, ".spot.cutoff");
+      break;
    case STATE_TEXGEN_EYE_S:
       append(dst, "eye.s");
       break;
@@ -644,8 +663,10 @@ append_token(char *dst, gl_state_index k)
    case STATE_LOCAL:
       append(dst, "local");
       break;
-   case STATE_INTERNAL:
    case STATE_NORMAL_SCALE:
+      append(dst, "normalScale");
+      break;
+   case STATE_INTERNAL:
    case STATE_POSITION_NORMALIZED:
       append(dst, "(internal)");
       break;
@@ -667,7 +688,7 @@ static void
 append_index(char *dst, GLint index)
 {
    char s[20];
-   _mesa_sprintf(s, "[%d].", index);
+   _mesa_sprintf(s, "[%d]", index);
    append(dst, s);
 }
 
@@ -677,7 +698,7 @@ append_index(char *dst, GLint index)
  * Use _mesa_free() to deallocate the string.
  */
 const char *
-_mesa_program_state_string(const GLint state[STATE_LENGTH])
+_mesa_program_state_string(const gl_state_index state[STATE_LENGTH])
 {
    char str[1000] = "";
    char tmp[30];
@@ -691,7 +712,6 @@ _mesa_program_state_string(const GLint state[STATE_LENGTH])
       append_token(str, (gl_state_index) state[2]);
       break;
    case STATE_LIGHT:
-      append(str, "light");
       append_index(str, state[1]); /* light number [i]. */
       append_token(str, (gl_state_index) state[2]); /* coefficients */
       break;
@@ -719,16 +739,9 @@ _mesa_program_state_string(const GLint state[STATE_LENGTH])
       append_index(str, state[1]); /* tex unit [i] */
       append(str, "color");
       break;
-   case STATE_FOG:
-      append(str, "fog");
-      append_token(str, (gl_state_index) state[1]); /* color or params */
-      break;
    case STATE_CLIPPLANE:
       append_index(str, state[1]); /* plane [i] */
-      append(str, "plane");
-      break;
-   case STATE_POINT_SIZE:
-   case STATE_POINT_ATTENUATION:
+      append(str, ".plane");
       break;
    case STATE_MODELVIEW_MATRIX:
    case STATE_PROJECTION_MATRIX:
@@ -746,8 +759,9 @@ _mesa_program_state_string(const GLint state[STATE_LENGTH])
          const GLuint firstRow = (GLuint) state[2];
          const GLuint lastRow = (GLuint) state[3];
          const gl_state_index modifier = (gl_state_index) state[4];
-         append_token(str, mat);
-         if (index)
+         if (index ||
+             mat == STATE_TEXTURE_MATRIX ||
+             mat == STATE_PROGRAM_MATRIX)
             append_index(str, index);
          if (modifier)
             append_token(str, modifier);
@@ -758,6 +772,14 @@ _mesa_program_state_string(const GLint state[STATE_LENGTH])
          append(str, tmp);
       }
       break;
+   case STATE_POINT_SIZE:
+      break;
+   case STATE_POINT_ATTENUATION:
+      break;
+   case STATE_FOG_PARAMS:
+      break;
+   case STATE_FOG_COLOR:
+      break;
    case STATE_DEPTH_RANGE:
       break;
    case STATE_FRAGMENT_PROGRAM:
@@ -796,9 +818,100 @@ _mesa_load_state_parameters(GLcontext *ctx,
    for (i = 0; i < paramList->NumParameters; i++) {
       if (paramList->Parameters[i].Type == PROGRAM_STATE_VAR) {
          _mesa_fetch_state(ctx, 
-                          (gl_state_index *) paramList->Parameters[i].StateIndexes,
+                          paramList->Parameters[i].StateIndexes,
                            paramList->ParameterValues[i]);
       }
    }
 }
 
+
+/**
+ * Copy the 16 elements of a matrix into four consecutive program
+ * registers starting at 'pos'.
+ */
+static void
+load_matrix(GLfloat registers[][4], GLuint pos, const GLfloat mat[16])
+{
+   GLuint i;
+   for (i = 0; i < 4; i++) {
+      registers[pos + i][0] = mat[0 + i];
+      registers[pos + i][1] = mat[4 + i];
+      registers[pos + i][2] = mat[8 + i];
+      registers[pos + i][3] = mat[12 + i];
+   }
+}
+
+
+/**
+ * As above, but transpose the matrix.
+ */
+static void
+load_transpose_matrix(GLfloat registers[][4], GLuint pos,
+                      const GLfloat mat[16])
+{
+   MEMCPY(registers[pos], mat, 16 * sizeof(GLfloat));
+}
+
+
+/**
+ * Load current vertex program's parameter registers with tracked
+ * matrices (if NV program).  This only needs to be done per
+ * glBegin/glEnd, not per-vertex.
+ */
+void
+_mesa_load_tracked_matrices(GLcontext *ctx)
+{
+   GLuint i;
+
+   for (i = 0; i < MAX_NV_VERTEX_PROGRAM_PARAMS / 4; i++) {
+      /* point 'mat' at source matrix */
+      GLmatrix *mat;
+      if (ctx->VertexProgram.TrackMatrix[i] == GL_MODELVIEW) {
+         mat = ctx->ModelviewMatrixStack.Top;
+      }
+      else if (ctx->VertexProgram.TrackMatrix[i] == GL_PROJECTION) {
+         mat = ctx->ProjectionMatrixStack.Top;
+      }
+      else if (ctx->VertexProgram.TrackMatrix[i] == GL_TEXTURE) {
+         mat = ctx->TextureMatrixStack[ctx->Texture.CurrentUnit].Top;
+      }
+      else if (ctx->VertexProgram.TrackMatrix[i] == GL_COLOR) {
+         mat = ctx->ColorMatrixStack.Top;
+      }
+      else if (ctx->VertexProgram.TrackMatrix[i]==GL_MODELVIEW_PROJECTION_NV) {
+         /* XXX verify the combined matrix is up to date */
+         mat = &ctx->_ModelProjectMatrix;
+      }
+      else if (ctx->VertexProgram.TrackMatrix[i] >= GL_MATRIX0_NV &&
+               ctx->VertexProgram.TrackMatrix[i] <= GL_MATRIX7_NV) {
+         GLuint n = ctx->VertexProgram.TrackMatrix[i] - GL_MATRIX0_NV;
+         ASSERT(n < MAX_PROGRAM_MATRICES);
+         mat = ctx->ProgramMatrixStack[n].Top;
+      }
+      else {
+         /* no matrix is tracked, but we leave the register values as-is */
+         assert(ctx->VertexProgram.TrackMatrix[i] == GL_NONE);
+         continue;
+      }
+
+      /* load the matrix values into sequential registers */
+      if (ctx->VertexProgram.TrackMatrixTransform[i] == GL_IDENTITY_NV) {
+         load_matrix(ctx->VertexProgram.Parameters, i*4, mat->m);
+      }
+      else if (ctx->VertexProgram.TrackMatrixTransform[i] == GL_INVERSE_NV) {
+         _math_matrix_analyse(mat); /* update the inverse */
+         ASSERT(!_math_matrix_is_dirty(mat));
+         load_matrix(ctx->VertexProgram.Parameters, i*4, mat->inv);
+      }
+      else if (ctx->VertexProgram.TrackMatrixTransform[i] == GL_TRANSPOSE_NV) {
+         load_transpose_matrix(ctx->VertexProgram.Parameters, i*4, mat->m);
+      }
+      else {
+         assert(ctx->VertexProgram.TrackMatrixTransform[i]
+                == GL_INVERSE_TRANSPOSE_NV);
+         _math_matrix_analyse(mat); /* update the inverse */
+         ASSERT(!_math_matrix_is_dirty(mat));
+         load_transpose_matrix(ctx->VertexProgram.Parameters, i*4, mat->inv);
+      }
+   }
+}