mesa: add new GLvertexformat entries for integer-valued attributes
[mesa.git] / src / mesa / main / state.c
index 51726461b6c7ab56b880c41a68408edfc0c292f5..05f4165c44a609d128b335424653bb1479e4c727 100644 (file)
@@ -27,7 +27,7 @@
  * \file state.c
  * State management.
  * 
- * This file manages recalculation of derived values in GLcontext.
+ * This file manages recalculation of derived values in struct gl_context.
  */
 
 
 #include "framebuffer.h"
 #include "light.h"
 #include "matrix.h"
-#if FEATURE_pixel_transfer
 #include "pixel.h"
-#endif
-#include "shader/program.h"
-#include "shader/prog_parameter.h"
+#include "program/program.h"
+#include "program/prog_parameter.h"
 #include "state.h"
 #include "stencil.h"
 #include "texenvprogram.h"
 #include "texobj.h"
 #include "texstate.h"
-#include "viewport.h"
 
 
 static void
-update_separate_specular(GLcontext *ctx)
+update_separate_specular(struct gl_context *ctx)
 {
    if (NEED_SECONDARY_COLOR(ctx))
       ctx->_TriangleCaps |= DD_SEPARATE_SPECULAR;
@@ -64,114 +61,153 @@ update_separate_specular(GLcontext *ctx)
 
 
 /**
- * Update state dependent on vertex arrays.
+ * Compute the index of the last array element that can be safely accessed
+ * in a vertex array.  We can really only do this when the array lives in
+ * a VBO.
+ * The array->_MaxElement field will be updated.
+ * Later in glDrawArrays/Elements/etc we can do some bounds checking.
+ */
+static void
+compute_max_element(struct gl_client_array *array)
+{
+   assert(array->Enabled);
+   if (array->BufferObj->Name) {
+      GLsizeiptrARB offset = (GLsizeiptrARB) array->Ptr;
+      GLsizeiptrARB obj_size = (GLsizeiptrARB) array->BufferObj->Size;
+
+      if (offset < obj_size) {
+        array->_MaxElement = (obj_size - offset +
+                              array->StrideB -
+                              array->_ElementSize) / array->StrideB;
+      } else {
+        array->_MaxElement = 0;
+      }
+   }
+   else {
+      /* user-space array, no idea how big it is */
+      array->_MaxElement = 2 * 1000 * 1000 * 1000; /* just a big number */
+   }
+}
+
+
+/**
+ * Helper for update_arrays().
+ * \return  min(current min, array->_MaxElement).
+ */
+static GLuint
+update_min(GLuint min, struct gl_client_array *array)
+{
+   compute_max_element(array);
+   return MIN2(min, array->_MaxElement);
+}
+
+
+/**
+ * Update ctx->Array._MaxElement (the max legal index into all enabled arrays).
+ * Need to do this upon new array state or new buffer object state.
  */
 static void
-update_arrays( GLcontext *ctx )
+update_arrays( struct gl_context *ctx )
 {
-   GLuint i, min;
+   struct gl_array_object *arrayObj = ctx->Array.ArrayObj;
+   GLuint i, min = ~0;
 
    /* find min of _MaxElement values for all enabled arrays */
 
    /* 0 */
    if (ctx->VertexProgram._Current
-       && ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_POS].Enabled) {
-      min = ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_POS]._MaxElement;
+       && arrayObj->VertexAttrib[VERT_ATTRIB_POS].Enabled) {
+      min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_POS]);
    }
-   else if (ctx->Array.ArrayObj->Vertex.Enabled) {
-      min = ctx->Array.ArrayObj->Vertex._MaxElement;
-   }
-   else {
-      /* can't draw anything without vertex positions! */
-      min = 0;
+   else if (arrayObj->Vertex.Enabled) {
+      min = update_min(min, &arrayObj->Vertex);
    }
 
    /* 1 */
    if (ctx->VertexProgram._Enabled
-       && ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_WEIGHT].Enabled) {
-      min = MIN2(min, ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_WEIGHT]._MaxElement);
+       && arrayObj->VertexAttrib[VERT_ATTRIB_WEIGHT].Enabled) {
+      min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_WEIGHT]);
    }
    /* no conventional vertex weight array */
 
    /* 2 */
    if (ctx->VertexProgram._Enabled
-       && ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_NORMAL].Enabled) {
-      min = MIN2(min, ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_NORMAL]._MaxElement);
+       && arrayObj->VertexAttrib[VERT_ATTRIB_NORMAL].Enabled) {
+      min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_NORMAL]);
    }
-   else if (ctx->Array.ArrayObj->Normal.Enabled) {
-      min = MIN2(min, ctx->Array.ArrayObj->Normal._MaxElement);
+   else if (arrayObj->Normal.Enabled) {
+      min = update_min(min, &arrayObj->Normal);
    }
 
    /* 3 */
    if (ctx->VertexProgram._Enabled
-       && ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_COLOR0].Enabled) {
-      min = MIN2(min, ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_COLOR0]._MaxElement);
+       && arrayObj->VertexAttrib[VERT_ATTRIB_COLOR0].Enabled) {
+      min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_COLOR0]);
    }
-   else if (ctx->Array.ArrayObj->Color.Enabled) {
-      min = MIN2(min, ctx->Array.ArrayObj->Color._MaxElement);
+   else if (arrayObj->Color.Enabled) {
+      min = update_min(min, &arrayObj->Color);
    }
 
    /* 4 */
    if (ctx->VertexProgram._Enabled
-       && ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_COLOR1].Enabled) {
-      min = MIN2(min, ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_COLOR1]._MaxElement);
+       && arrayObj->VertexAttrib[VERT_ATTRIB_COLOR1].Enabled) {
+      min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_COLOR1]);
    }
-   else if (ctx->Array.ArrayObj->SecondaryColor.Enabled) {
-      min = MIN2(min, ctx->Array.ArrayObj->SecondaryColor._MaxElement);
+   else if (arrayObj->SecondaryColor.Enabled) {
+      min = update_min(min, &arrayObj->SecondaryColor);
    }
 
    /* 5 */
    if (ctx->VertexProgram._Enabled
-       && ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_FOG].Enabled) {
-      min = MIN2(min, ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_FOG]._MaxElement);
+       && arrayObj->VertexAttrib[VERT_ATTRIB_FOG].Enabled) {
+      min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_FOG]);
    }
-   else if (ctx->Array.ArrayObj->FogCoord.Enabled) {
-      min = MIN2(min, ctx->Array.ArrayObj->FogCoord._MaxElement);
+   else if (arrayObj->FogCoord.Enabled) {
+      min = update_min(min, &arrayObj->FogCoord);
    }
 
    /* 6 */
    if (ctx->VertexProgram._Enabled
-       && ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_COLOR_INDEX].Enabled) {
-      min = MIN2(min, ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_COLOR_INDEX]._MaxElement);
+       && arrayObj->VertexAttrib[VERT_ATTRIB_COLOR_INDEX].Enabled) {
+      min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_COLOR_INDEX]);
    }
-   else if (ctx->Array.ArrayObj->Index.Enabled) {
-      min = MIN2(min, ctx->Array.ArrayObj->Index._MaxElement);
+   else if (arrayObj->Index.Enabled) {
+      min = update_min(min, &arrayObj->Index);
    }
 
-
    /* 7 */
    if (ctx->VertexProgram._Enabled
-       && ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_EDGEFLAG].Enabled) {
-      min = MIN2(min, ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_EDGEFLAG]._MaxElement);
+       && arrayObj->VertexAttrib[VERT_ATTRIB_EDGEFLAG].Enabled) {
+      min = update_min(min, &arrayObj->VertexAttrib[VERT_ATTRIB_EDGEFLAG]);
    }
 
    /* 8..15 */
    for (i = VERT_ATTRIB_TEX0; i <= VERT_ATTRIB_TEX7; i++) {
       if (ctx->VertexProgram._Enabled
-          && ctx->Array.ArrayObj->VertexAttrib[i].Enabled) {
-         min = MIN2(min, ctx->Array.ArrayObj->VertexAttrib[i]._MaxElement);
+          && arrayObj->VertexAttrib[i].Enabled) {
+         min = update_min(min, &arrayObj->VertexAttrib[i]);
       }
       else if (i - VERT_ATTRIB_TEX0 < ctx->Const.MaxTextureCoordUnits
-               && ctx->Array.ArrayObj->TexCoord[i - VERT_ATTRIB_TEX0].Enabled) {
-         min = MIN2(min, ctx->Array.ArrayObj->TexCoord[i - VERT_ATTRIB_TEX0]._MaxElement);
+               && arrayObj->TexCoord[i - VERT_ATTRIB_TEX0].Enabled) {
+         min = update_min(min, &arrayObj->TexCoord[i - VERT_ATTRIB_TEX0]);
       }
    }
 
    /* 16..31 */
    if (ctx->VertexProgram._Current) {
-      for (i = 0; i < Elements(ctx->Array.ArrayObj->VertexAttrib); i++) {
-         if (ctx->Array.ArrayObj->VertexAttrib[i].Enabled) {
-            min = MIN2(min, ctx->Array.ArrayObj->VertexAttrib[i]._MaxElement);
+      for (i = 0; i < Elements(arrayObj->VertexAttrib); i++) {
+         if (arrayObj->VertexAttrib[i].Enabled) {
+            min = update_min(min, &arrayObj->VertexAttrib[i]);
          }
       }
    }
 
-   if (ctx->Array.ArrayObj->EdgeFlag.Enabled) {
-      min = MIN2(min, ctx->Array.ArrayObj->EdgeFlag._MaxElement);
+   if (arrayObj->EdgeFlag.Enabled) {
+      min = update_min(min, &arrayObj->EdgeFlag);
    }
 
    /* _MaxElement is one past the last legal array element */
-   ctx->Array._MaxElement = min;
+   arrayObj->_MaxElement = min;
 }
 
 
@@ -183,7 +219,7 @@ update_arrays( GLcontext *ctx )
  * This needs to be done before texture state validation.
  */
 static void
-update_program_enables(GLcontext *ctx)
+update_program_enables(struct gl_context *ctx)
 {
    /* These _Enabled flags indicate if the program is enabled AND valid. */
    ctx->VertexProgram._Enabled = ctx->VertexProgram.Enabled
@@ -209,11 +245,14 @@ update_program_enables(GLcontext *ctx)
  * or fragment program is being used.
  */
 static GLbitfield
-update_program(GLcontext *ctx)
+update_program(struct gl_context *ctx)
 {
-   const struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
+   const struct gl_shader_program *vsProg = ctx->Shader.CurrentVertexProgram;
+   const struct gl_shader_program *gsProg = ctx->Shader.CurrentGeometryProgram;
+   const struct gl_shader_program *fsProg = ctx->Shader.CurrentFragmentProgram;
    const struct gl_vertex_program *prevVP = ctx->VertexProgram._Current;
    const struct gl_fragment_program *prevFP = ctx->FragmentProgram._Current;
+   const struct gl_geometry_program *prevGP = ctx->GeometryProgram._Current;
    GLbitfield new_state = 0x0;
 
    /*
@@ -232,10 +271,10 @@ update_program(GLcontext *ctx)
     * come up, or matter.
     */
 
-   if (shProg && shProg->LinkStatus && shProg->FragmentProgram) {
+   if (fsProg && fsProg->LinkStatus && fsProg->FragmentProgram) {
       /* Use shader programs */
       _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._Current,
-                               shProg->FragmentProgram);
+                               fsProg->FragmentProgram);
    }
    else if (ctx->FragmentProgram._Enabled) {
       /* use user-defined vertex program */
@@ -255,14 +294,23 @@ update_program(GLcontext *ctx)
       _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._Current, NULL);
    }
 
+   if (gsProg && gsProg->LinkStatus && gsProg->GeometryProgram) {
+      /* Use shader programs */
+      _mesa_reference_geomprog(ctx, &ctx->GeometryProgram._Current,
+                               gsProg->GeometryProgram);
+   } else {
+      /* no fragment program */
+      _mesa_reference_geomprog(ctx, &ctx->GeometryProgram._Current, NULL);
+   }
+
    /* Examine vertex program after fragment program as
     * _mesa_get_fixed_func_vertex_program() needs to know active
     * fragprog inputs.
     */
-   if (shProg && shProg->LinkStatus && shProg->VertexProgram) {
+   if (vsProg && vsProg->LinkStatus && vsProg->VertexProgram) {
       /* Use shader programs */
       _mesa_reference_vertprog(ctx, &ctx->VertexProgram._Current,
-                            shProg->VertexProgram);
+                            vsProg->VertexProgram);
    }
    else if (ctx->VertexProgram._Enabled) {
       /* use user-defined vertex program */
@@ -291,7 +339,15 @@ update_program(GLcontext *ctx)
                           (struct gl_program *) ctx->FragmentProgram._Current);
       }
    }
-   
+
+   if (ctx->GeometryProgram._Current != prevGP) {
+      new_state |= _NEW_PROGRAM;
+      if (ctx->Driver.BindProgram) {
+         ctx->Driver.BindProgram(ctx, MESA_GEOMETRY_PROGRAM,
+                            (struct gl_program *) ctx->GeometryProgram._Current);
+      }
+   }
+
    if (ctx->VertexProgram._Current != prevVP) {
       new_state |= _NEW_PROGRAM;
       if (ctx->Driver.BindProgram) {
@@ -308,7 +364,7 @@ update_program(GLcontext *ctx)
  * Examine shader constants and return either _NEW_PROGRAM_CONSTANTS or 0.
  */
 static GLbitfield
-update_program_constants(GLcontext *ctx)
+update_program_constants(struct gl_context *ctx)
 {
    GLbitfield new_state = 0x0;
 
@@ -320,6 +376,16 @@ update_program_constants(GLcontext *ctx)
       }
    }
 
+   if (ctx->GeometryProgram._Current) {
+      const struct gl_program_parameter_list *params =
+         ctx->GeometryProgram._Current->Base.Parameters;
+      /*FIXME: StateFlags is always 0 because we have unnamed constant
+       *       not state changes */
+      if (params /*&& params->StateFlags & ctx->NewState*/) {
+         new_state |= _NEW_PROGRAM_CONSTANTS;
+      }
+   }
+
    if (ctx->VertexProgram._Current) {
       const struct gl_program_parameter_list *params =
          ctx->VertexProgram._Current->Base.Parameters;
@@ -335,7 +401,7 @@ update_program_constants(GLcontext *ctx)
 
 
 static void
-update_viewport_matrix(GLcontext *ctx)
+update_viewport_matrix(struct gl_context *ctx)
 {
    const GLfloat depthMax = ctx->DrawBuffer->_DepthMaxF;
 
@@ -357,7 +423,7 @@ update_viewport_matrix(GLcontext *ctx)
  * Update derived multisample state.
  */
 static void
-update_multisample(GLcontext *ctx)
+update_multisample(struct gl_context *ctx)
 {
    ctx->Multisample._Enabled = GL_FALSE;
    if (ctx->Multisample.Enabled &&
@@ -371,7 +437,7 @@ update_multisample(GLcontext *ctx)
  * Update derived color/blend/logicop state.
  */
 static void
-update_color(GLcontext *ctx)
+update_color(struct gl_context *ctx)
 {
    /* This is needed to support 1.1's RGB logic ops AND
     * 1.0's blending logicops.
@@ -385,7 +451,7 @@ update_color(GLcontext *ctx)
  * in ctx->_TriangleCaps if needed.
  */
 static void
-update_polygon(GLcontext *ctx)
+update_polygon(struct gl_context *ctx)
 {
    ctx->_TriangleCaps &= ~(DD_TRI_CULL_FRONT_BACK | DD_TRI_OFFSET);
 
@@ -407,7 +473,7 @@ update_polygon(GLcontext *ctx)
  */
 #if 0
 static void
-update_tricaps(GLcontext *ctx, GLbitfield new_state)
+update_tricaps(struct gl_context *ctx, GLbitfield new_state)
 {
    ctx->_TriangleCaps = 0;
 
@@ -476,7 +542,7 @@ update_tricaps(GLcontext *ctx, GLbitfield new_state)
 
 /**
  * Compute derived GL state.
- * If __GLcontextRec::NewState is non-zero then this function \b must
+ * If __struct gl_contextRec::NewState is non-zero then this function \b must
  * be called before rendering anything.
  *
  * Calls dd_function_table::UpdateState to perform any internal state
@@ -487,7 +553,7 @@ update_tricaps(GLcontext *ctx, GLbitfield new_state)
  * _mesa_update_lighting() and _mesa_update_tnl_spaces().
  */
 void
-_mesa_update_state_locked( GLcontext *ctx )
+_mesa_update_state_locked( struct gl_context *ctx )
 {
    GLbitfield new_state = ctx->NewState;
    GLbitfield prog_flags = _NEW_PROGRAM;
@@ -501,7 +567,7 @@ _mesa_update_state_locked( GLcontext *ctx )
 
    /* Determine which state flags effect vertex/fragment program state */
    if (ctx->FragmentProgram._MaintainTexEnvProgram) {
-      prog_flags |= (_NEW_TEXTURE | _NEW_FOG | _DD_NEW_SEPARATE_SPECULAR |
+      prog_flags |= (_NEW_BUFFERS | _NEW_TEXTURE | _NEW_FOG |
                     _NEW_ARRAY | _NEW_LIGHT | _NEW_POINT | _NEW_RENDERMODE |
                     _NEW_PROGRAM);
    }
@@ -540,17 +606,12 @@ _mesa_update_state_locked( GLcontext *ctx )
    if (new_state & (_NEW_STENCIL | _NEW_BUFFERS))
       _mesa_update_stencil( ctx );
 
-#if FEATURE_pixel_transfer
    if (new_state & _MESA_NEW_TRANSFER_STATE)
       _mesa_update_pixel( ctx, new_state );
-#endif
 
    if (new_state & _DD_NEW_SEPARATE_SPECULAR)
       update_separate_specular( ctx );
 
-   if (new_state & (_NEW_ARRAY | _NEW_PROGRAM))
-      update_arrays( ctx );
-
    if (new_state & (_NEW_BUFFERS | _NEW_VIEWPORT))
       update_viewport_matrix(ctx);
 
@@ -586,6 +647,8 @@ _mesa_update_state_locked( GLcontext *ctx )
       new_prog_state |= update_program( ctx );
    }
 
+   if (new_state & (_NEW_ARRAY | _NEW_PROGRAM | _NEW_BUFFER_OBJECT))
+      update_arrays( ctx );
 
  out:
    new_prog_state |= update_program_constants(ctx);
@@ -609,7 +672,7 @@ _mesa_update_state_locked( GLcontext *ctx )
 /* This is the usual entrypoint for state updates:
  */
 void
-_mesa_update_state( GLcontext *ctx )
+_mesa_update_state( struct gl_context *ctx )
 {
    _mesa_lock_context_textures(ctx);
    _mesa_update_state_locked(ctx);
@@ -642,13 +705,13 @@ _mesa_update_state( GLcontext *ctx )
  * Otherwise, the fp should track them as state values instead.
  */
 void
-_mesa_set_varying_vp_inputs( GLcontext *ctx,
+_mesa_set_varying_vp_inputs( struct gl_context *ctx,
                              GLbitfield varying_inputs )
 {
    if (ctx->varying_vp_inputs != varying_inputs) {
       ctx->varying_vp_inputs = varying_inputs;
       ctx->NewState |= _NEW_ARRAY;
-      /*_mesa_printf("%s %x\n", __FUNCTION__, varying_inputs);*/
+      /*printf("%s %x\n", __FUNCTION__, varying_inputs);*/
    }
 }
 
@@ -660,7 +723,7 @@ _mesa_set_varying_vp_inputs( GLcontext *ctx,
  * of ordinary varyings/inputs.
  */
 void
-_mesa_set_vp_override(GLcontext *ctx, GLboolean flag)
+_mesa_set_vp_override(struct gl_context *ctx, GLboolean flag)
 {
    if (ctx->VertexProgram._Overriden != flag) {
       ctx->VertexProgram._Overriden = flag;
@@ -668,6 +731,6 @@ _mesa_set_vp_override(GLcontext *ctx, GLboolean flag)
       /* Set one of the bits which will trigger fragment program
        * regeneration:
        */
-      ctx->NewState |= _NEW_ARRAY; 
+      ctx->NewState |= _NEW_PROGRAM;
    }
 }