fragment program execution
[mesa.git] / src / mesa / tnl / t_imm_api.c
index d19f6a6e0077205e116abbc4ca75de6974e6b4b6..462d8dbaf6e38f44b284c5d06ef7bacc7d05a51c 100644 (file)
@@ -1,10 +1,10 @@
-/* $Id: t_imm_api.c,v 1.25 2002/02/13 00:53:20 keithw Exp $ */
+/* $Id: t_imm_api.c,v 1.39 2003/01/14 04:55:47 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
- * Version:  4.1
+ * Version:  5.1
  *
- * Copyright (C) 1999-2001  Brian Paul   All Rights Reserved.
+ * Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -24,7 +24,7 @@
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  *
  * Authors:
- *    Keith Whitwell <keithw@valinux.com>
+ *    Keith Whitwell <keith@tungstengraphics.com>
  */
 
 
@@ -34,7 +34,7 @@
 #include "dlist.h"
 #include "enums.h"
 #include "light.h"
-#include "mem.h"
+#include "imports.h"
 #include "state.h"
 #include "colormac.h"
 #include "macros.h"
 
 /* A cassette is full or flushed on a statechange.
  */
-void _tnl_flush_immediate( struct immediate *IM )
+void _tnl_flush_immediate( GLcontext *ctx, struct immediate *IM )
 {
-   GLcontext *ctx = IM->backref;
+   if (!ctx) {
+      /* We were called by glVertex, glEvalCoord, glArrayElement, etc.
+       * The current context is corresponds to the IM structure.
+       */
+      GET_CURRENT_CONTEXT(context);
+      ctx = context;
+   }
+
+   if (MESA_VERBOSE & VERBOSE_IMMEDIATE)
+      _mesa_debug(ctx, "_tnl_flush_immediate IM: %d compiling: %d\n",
+                  IM->id, ctx->CompileFlag);
 
    if (IM->FlushElt == FLUSH_ELT_EAGER) {
       _tnl_translate_array_elts( ctx, IM, IM->LastPrimitive, IM->Count );
@@ -69,45 +79,63 @@ void _tnl_flush_immediate( struct immediate *IM )
 }
 
 
+/* Hook for ctx->Driver.FlushVertices:
+ */
 void _tnl_flush_vertices( GLcontext *ctx, GLuint flags )
 {
    struct immediate *IM = TNL_CURRENT_IM(ctx);
 
-   if (IM->Flag[IM->Start])
-      if ((flags & FLUSH_UPDATE_CURRENT) || IM->Count > IM->Start)
-        _tnl_flush_immediate( IM );
+   if (MESA_VERBOSE & VERBOSE_IMMEDIATE)
+      _mesa_debug(ctx,
+                  "_tnl_flush_vertices flags %x IM(%d) %d..%d Flag[%d]: %x\n", 
+                  flags, IM->id, IM->Start, IM->Count, IM->Start,
+                  IM->Flag[IM->Start]);
+
+   if (IM->Flag[IM->Start]) {
+      if ((flags & FLUSH_UPDATE_CURRENT) || 
+         IM->Count > IM->Start ||
+         (IM->Flag[IM->Start] & (VERT_BIT_BEGIN | VERT_BIT_END))) {
+        _tnl_flush_immediate( ctx, IM );
+      }
+   }
 }
 
 
-
-
-/* Note the ctx argument.  This function called only by _tnl_Begin,
- * _tnl_save_Begin and _tnl_hard_begin() in this file.  
- */
-static void
-_tnl_begin( GLcontext *ctx, GLenum p )
+void
+_tnl_save_Begin( GLenum mode )
 {
+   GET_CURRENT_CONTEXT(ctx);
    struct immediate *IM = TNL_CURRENT_IM(ctx);
    GLuint inflags, state;
 
-   if (MESA_VERBOSE&VERBOSE_API)
-      fprintf(stderr, "glBegin(IM %d) %s\n", IM->id, 
-             _mesa_lookup_enum_by_nr(p));
+/*     _mesa_debug(ctx, "%s: before: %x\n", __FUNCTION__, IM->BeginState); */
+
+   if (mode > GL_POLYGON) {
+      _mesa_compile_error( ctx, GL_INVALID_ENUM, "_tnl_Begin" );
+      return;
+   }
 
    if (ctx->NewState)
       _mesa_update_state(ctx);
 
+#if 000
    /* if only a very few slots left, might as well flush now
     */
    if (IM->Count > IMM_MAXDATA-8) {
-      _tnl_flush_immediate( IM );
+      _tnl_flush_immediate( ctx, IM );
+      IM = TNL_CURRENT_IM(ctx);
+   }
+#endif
+
+   if (IM->Count > IMM_MAXDATA-8) {
+      _tnl_flush_immediate( ctx, IM );
       IM = TNL_CURRENT_IM(ctx);
    }
 
    /* Check for and flush buffered vertices from internal operations.
     */
    if (IM->SavedBeginState) {
-      _tnl_flush_immediate( IM );
+      _tnl_flush_immediate( ctx, IM );
       IM = TNL_CURRENT_IM(ctx);
       IM->BeginState = IM->SavedBeginState;
       IM->SavedBeginState = 0;
@@ -124,7 +152,7 @@ _tnl_begin( GLcontext *ctx, GLenum p )
 
       state |= (VERT_BEGIN_0|VERT_BEGIN_1);
       IM->Flag[count] |= VERT_BIT_BEGIN;
-      IM->Primitive[count] = p | PRIM_BEGIN;
+      IM->Primitive[count] = mode | PRIM_BEGIN;
       IM->PrimitiveLength[IM->LastPrimitive] = count - IM->LastPrimitive;
       IM->LastPrimitive = count;
 
@@ -139,22 +167,10 @@ _tnl_begin( GLcontext *ctx, GLenum p )
 
    ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
    IM->BeginState = state;
-}
 
-
-void
-_tnl_save_Begin( GLenum mode )
-{
-   GET_CURRENT_CONTEXT(ctx);
-
-   if (mode > GL_POLYGON) {
-      _mesa_compile_error( ctx, GL_INVALID_ENUM, "glBegin" );
-      return;
-   }
-
-   _tnl_begin( ctx, mode );
-
-   /* Update save_primitive now.
+   /* Update save_primitive now.  Don't touch ExecPrimitive as this is
+    * updated in the replay of this cassette if we are in
+    * COMPILE_AND_EXECUTE mode.
     */
    if (ctx->Driver.CurrentSavePrimitive == PRIM_UNKNOWN)
       ctx->Driver.CurrentSavePrimitive = PRIM_INSIDE_UNKNOWN_PRIM;
@@ -167,18 +183,62 @@ void
 _tnl_Begin( GLenum mode )
 {
    GET_CURRENT_CONTEXT(ctx);
+   TNLcontext *tnl = TNL_CONTEXT(ctx);
+   ASSERT (!ctx->CompileFlag);
 
    if (mode > GL_POLYGON) {
-      _mesa_compile_error( ctx, GL_INVALID_ENUM, "glBegin" );
+      _mesa_error( ctx, GL_INVALID_ENUM, "_tnl_Begin(0x%x)", mode );
       return;
    }
 
-   _tnl_begin(ctx, mode);
+   if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
+      _mesa_error( ctx, GL_INVALID_OPERATION, "_tnl_Begin" );
+      return;
+   }
 
-   /* Update exec_primitive now.
-    */
-   ASSERT (!ctx->CompileFlag);
-   if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END) {
+   if (ctx->NewState)
+      _mesa_update_state(ctx);
+
+   {
+      struct immediate *IM = TNL_CURRENT_IM(ctx);
+      if (IM->Count > IMM_MAXDATA-8) {
+        _tnl_flush_immediate( ctx, IM );
+        IM = TNL_CURRENT_IM(ctx);
+      }
+   }
+
+
+   {
+      struct immediate *IM = TNL_CURRENT_IM(ctx);
+      GLuint count = IM->Count;
+      GLuint last = IM->LastPrimitive;
+
+      if (IM->Start == IM->Count &&
+         tnl->Driver.NotifyBegin &&
+         tnl->Driver.NotifyBegin( ctx, mode )) {
+        return;
+      }
+
+      assert( (IM->SavedBeginState & (VERT_BEGIN_0|VERT_BEGIN_1)) == 0 );
+      assert( (IM->BeginState & (VERT_BEGIN_0|VERT_BEGIN_1)) == 0 );
+
+      /* Not quite right.  Need to use the fallback '_aa_ArrayElement'
+       * when not known to be inside begin/end and arrays are
+       * unlocked.  
+       */
+      if (IM->FlushElt == FLUSH_ELT_EAGER) {
+        _tnl_translate_array_elts( ctx, IM, last, count );
+      }
+
+      IM->Flag[count] |= VERT_BIT_BEGIN;
+      IM->Primitive[count] = mode | PRIM_BEGIN;
+      IM->PrimitiveLength[last] = count - last;
+      IM->LastPrimitive = count;
+      IM->BeginState = (VERT_BEGIN_0|VERT_BEGIN_1);
+
+/*        _mesa_debug(ctx, "%s: %x\n", __FUNCTION__, IM->BeginState);  */
+
+      ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
       ctx->Driver.CurrentExecPrimitive = mode;
    }
 }
@@ -191,12 +251,13 @@ _tnl_Begin( GLenum mode )
 GLboolean
 _tnl_hard_begin( GLcontext *ctx, GLenum p )
 {
+/*     _mesa_debug(ctx, "%s\n", __FUNCTION__); */
+
    if (!ctx->CompileFlag) {
       /* If not compiling, treat as a normal begin().
        */
-      _tnl_begin( ctx, p );
-      ASSERT(ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END);
-      ctx->Driver.CurrentExecPrimitive = p;
+/*        _mesa_debug(ctx, "%s: treating as glBegin\n", __FUNCTION__); */
+      glBegin( p );
       return GL_TRUE;
    }
    else {
@@ -210,7 +271,7 @@ _tnl_hard_begin( GLcontext *ctx, GLenum p )
         _mesa_update_state(ctx);
 
       if (IM->Count > IMM_MAXDATA-8) {
-        _tnl_flush_immediate( IM );
+        _tnl_flush_immediate( ctx, IM );
         IM = TNL_CURRENT_IM(ctx);
       }
 
@@ -262,7 +323,7 @@ _tnl_hard_begin( GLcontext *ctx, GLenum p )
         return GL_TRUE;
 
       default:
-        ASSERT (0);
+        assert (0);
         return GL_TRUE;
       }
    }
@@ -285,6 +346,11 @@ _tnl_end( GLcontext *ctx )
    GLuint state = IM->BeginState;
    GLuint inflags = (~state) & (VERT_BEGIN_0|VERT_BEGIN_1);
 
+   /* Not the case if vertices emitted without calling glBegin first:
+    */
+/*   assert( ctx->Driver.NeedFlush & FLUSH_STORED_VERTICES ); */
+
+
    state |= inflags << 2;      /* errors */
 
    if (inflags != (VERT_BEGIN_0|VERT_BEGIN_1))
@@ -309,20 +375,24 @@ _tnl_end( GLcontext *ctx )
    IM->BeginState = state;
 
    if (!ctx->CompileFlag) {
-      ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
+      if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END) 
+        _mesa_error( ctx, GL_INVALID_OPERATION, "_tnl_End" );
+      else
+        ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
    }
 
    /* You can set this flag to get the old 'flush_vb on glEnd()'
     * behaviour.
     */
-   if (1 /*(MESA_DEBUG_FLAGS&DEBUG_ALWAYS_FLUSH)*/ )
-      _tnl_flush_immediate( IM );
+   if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH)
+      _tnl_flush_immediate( ctx, IM );
 }
 
 void
 _tnl_End(void)
 {
    GET_CURRENT_CONTEXT(ctx);
+
    _tnl_end( ctx );
 
    /* Need to keep save primitive uptodate in COMPILE and
@@ -686,7 +756,7 @@ _tnl_TexCoord4fv( const GLfloat *v )
    ASSIGN_4V(dest, x, y, 0, 1);                                \
 /*     ASSERT(IM->Flag[IM->Count]==0);          */     \
    if (count == IMM_MAXDATA - 1)                       \
-      _tnl_flush_immediate( IM );                      \
+      _tnl_flush_immediate( NULL, IM );                        \
 }
 
 #define VERTEX3(IM,x,y,z)                              \
@@ -697,7 +767,7 @@ _tnl_TexCoord4fv( const GLfloat *v )
    ASSIGN_4V(dest, x, y, z, 1);                                \
 /*     ASSERT(IM->Flag[IM->Count]==0); */              \
    if (count == IMM_MAXDATA - 1)                       \
-      _tnl_flush_immediate( IM );                      \
+      _tnl_flush_immediate( NULL, IM );                        \
 }
 
 #define VERTEX4(IM, x,y,z,w)                           \
@@ -707,7 +777,7 @@ _tnl_TexCoord4fv( const GLfloat *v )
    IM->Flag[count] |= VERT_BITS_OBJ_234;               \
    ASSIGN_4V(dest, x, y, z, w);                                \
    if (count == IMM_MAXDATA - 1)                       \
-      _tnl_flush_immediate( IM );                      \
+      _tnl_flush_immediate( NULL, IM );                        \
 }
 
 #if defined(USE_IEEE)
@@ -722,7 +792,7 @@ _tnl_TexCoord4fv( const GLfloat *v )
    dest[3].i = IEEE_ONE;                                               \
 /*     ASSERT(IM->Flag[IM->Count]==0); */                              \
    if (count == IMM_MAXDATA - 1)                                       \
-      _tnl_flush_immediate( IM );                                      \
+      _tnl_flush_immediate( NULL, IM );                                        \
 }
 #else
 #define VERTEX2F VERTEX2
@@ -740,7 +810,7 @@ _tnl_TexCoord4fv( const GLfloat *v )
    dest[3].i = IEEE_ONE;                                               \
 /*     ASSERT(IM->Flag[IM->Count]==0);  */                             \
    if (count == IMM_MAXDATA - 1)                                       \
-      _tnl_flush_immediate( IM );                                      \
+      _tnl_flush_immediate( NULL, IM );                                        \
 }
 #else
 #define VERTEX3F VERTEX3
@@ -757,7 +827,7 @@ _tnl_TexCoord4fv( const GLfloat *v )
    dest[2].i = ((fi_type *)&(z))->i;                                   \
    dest[3].i = ((fi_type *)&(w))->i;                                   \
    if (count == IMM_MAXDATA - 1)                                       \
-      _tnl_flush_immediate( IM );                                      \
+      _tnl_flush_immediate( NULL, IM );                                        \
 }
 #else
 #define VERTEX4F VERTEX4
@@ -817,7 +887,7 @@ _tnl_Vertex4fv( const GLfloat *v )
  * don't crash.  We no-op on invalid targets.
  */
 
-#define MAX_TARGET (GL_TEXTURE0_ARB + MAX_TEXTURE_UNITS)
+#define MAX_TARGET (GL_TEXTURE0_ARB + MAX_TEXTURE_COORD_UNITS)
 
 #define MULTI_TEXCOORD1(target, s)                     \
 {                                                      \
@@ -951,7 +1021,7 @@ _tnl_MultiTexCoord4fvARB(GLenum target, const GLfloat *v)
    IM->Flag[count] |= VERT_BIT_EVAL_C1;                        \
    ASSIGN_4V(dest, x, 0, 0, 1);                                \
    if (count == IMM_MAXDATA-1)                         \
-      _tnl_flush_immediate( IM );                      \
+      _tnl_flush_immediate( NULL, IM );                        \
 }
 
 #define EVALCOORD2(IM, x, y)                           \
@@ -961,7 +1031,7 @@ _tnl_MultiTexCoord4fvARB(GLenum target, const GLfloat *v)
    IM->Flag[count] |= VERT_BIT_EVAL_C2;                        \
    ASSIGN_4V(dest, x, y, 0, 1);                                \
    if (count == IMM_MAXDATA-1)                         \
-      _tnl_flush_immediate( IM );                      \
+      _tnl_flush_immediate( NULL, IM );                        \
 }
 
 #define EVALPOINT1(IM, x)                              \
@@ -971,7 +1041,7 @@ _tnl_MultiTexCoord4fvARB(GLenum target, const GLfloat *v)
    IM->Flag[count] |= VERT_BIT_EVAL_P1;                        \
    ASSIGN_4V(dest, x, 0, 0, 1);                                \
    if (count == IMM_MAXDATA-1)                         \
-      _tnl_flush_immediate( IM );                      \
+      _tnl_flush_immediate( NULL, IM );                        \
 }
 
 #define EVALPOINT2(IM, x, y)                           \
@@ -981,7 +1051,7 @@ _tnl_MultiTexCoord4fvARB(GLenum target, const GLfloat *v)
    IM->Flag[count] |= VERT_BIT_EVAL_P2;                        \
    ASSIGN_4V(dest, x, y, 0, 1);                                \
    if (count == IMM_MAXDATA-1)                         \
-      _tnl_flush_immediate( IM );                      \
+      _tnl_flush_immediate( NULL, IM );                        \
 }
 
 static void
@@ -1041,7 +1111,7 @@ _tnl_EvalPoint2( GLint i, GLint j )
    IM->FlushElt = IM->ArrayEltFlush;           \
    IM->Count += IM->ArrayEltIncr;              \
    if (IM->Count == IMM_MAXDATA)               \
-      _tnl_flush_immediate( IM );              \
+      _tnl_flush_immediate( NULL, IM );                \
 }
 
 
@@ -1076,19 +1146,6 @@ _tnl_eval_coord2f( GLcontext *CC, GLfloat u, GLfloat v )
    EVALCOORD2( i, u, v );
 }
 
-void
-_tnl_array_element( GLcontext *CC, GLint i )
-{
-   struct immediate *im = TNL_CURRENT_IM(CC);
-   ARRAY_ELT( im, i );
-}
-
-void
-_tnl_vertex2f( GLcontext *ctx, GLfloat x, GLfloat y )
-{
-   struct immediate *im = TNL_CURRENT_IM(ctx);
-   VERTEX2( im, x, y );
-}
 
 
 
@@ -1108,9 +1165,13 @@ _tnl_VertexAttrib4fNV( GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w
       if (index == 0) {
          IM->Count++;
          if (count == IMM_MAXDATA - 1)
-            _tnl_flush_immediate( IM );
+            _tnl_flush_immediate( NULL, IM );
       }
    }
+   else {
+      GET_CURRENT_CONTEXT(ctx);
+      _mesa_error(ctx, GL_INVALID_VALUE, "glVertexAttribNV(index > 15)");
+   }
 }   
 
 static void
@@ -1125,9 +1186,13 @@ _tnl_VertexAttrib4fvNV( GLuint index, const GLfloat *v )
       if (index == 0) {
          IM->Count++;
          if (count == IMM_MAXDATA - 1)
-            _tnl_flush_immediate( IM );
+            _tnl_flush_immediate( NULL, IM );
       }
    }
+   else {
+      GET_CURRENT_CONTEXT(ctx);
+      _mesa_error(ctx, GL_INVALID_VALUE, "glVertexAttribNV(index > 15)");
+   }
 }   
 
 
@@ -1141,14 +1206,12 @@ _tnl_Rectf( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 )
 {
    GET_CURRENT_CONTEXT(ctx);
 
-/*     fprintf(stderr, "%s\n", __FUNCTION__); */
-
    if (_tnl_hard_begin( ctx, GL_QUADS )) {
-      _tnl_vertex2f( ctx, x1, y1 );
-      _tnl_vertex2f( ctx, x2, y1 );
-      _tnl_vertex2f( ctx, x2, y2 );
-      _tnl_vertex2f( ctx, x1, y2 );
-      _tnl_end( ctx );
+      glVertex2f( x1, y1 );
+      glVertex2f( x2, y1 );
+      glVertex2f( x2, y2 );
+      glVertex2f( x1, y2 );
+      glEnd();
    }
 }
 
@@ -1164,11 +1227,14 @@ _tnl_Materialfv( GLenum face, GLenum pname, const GLfloat *params )
 
    if (bitmask == 0)
       return;
+   
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "_tnl_Materialfv\n");
 
    if (tnl->IsolateMaterials &&
        !(IM->BeginState & VERT_BEGIN_1)) /* heuristic */
    {
-      _tnl_flush_immediate( IM );      
+      _tnl_flush_immediate( ctx, IM );      
       IM = TNL_CURRENT_IM(ctx);
       count = IM->Count;
    }
@@ -1242,7 +1308,7 @@ _tnl_Materialfv( GLenum face, GLenum pname, const GLfloat *params )
    if (tnl->IsolateMaterials && 
        !(IM->BeginState & VERT_BEGIN_1)) /* heuristic */
    {
-      _tnl_flush_immediate( IM );
+      _tnl_flush_immediate( ctx, IM );
    }
 }