Esempio n. 1
0
/* KW: If are compiling, we don't know whether eval will produce a
 *     vertex when it is run in the future.  If this is pure immediate
 *     mode, eval is a noop if neither vertex map is enabled.
 *
 *     Thus we need to have a check in the display list code or
 *     elsewhere for eval(1,2) vertices in the case where
 *     map(1,2)_vertex is disabled, and to purge those vertices from
 *     the vb.
 */
void GLAPIENTRY _mesa_noop_EvalMesh1( GLenum mode, GLint i1, GLint i2 )
{
   GET_CURRENT_CONTEXT(ctx);
   GLint i;
   GLfloat u, du;
   GLenum prim;

   switch (mode) {
   case GL_POINT:
      prim = GL_POINTS;
      break;
   case GL_LINE:
      prim = GL_LINE_STRIP;
      break;
   default:
      _mesa_error( ctx, GL_INVALID_ENUM, "glEvalMesh1(mode)" );
      return;
   }

   /* No effect if vertex maps disabled.
    */
   if (!ctx->Eval.Map1Vertex4 && 
       !ctx->Eval.Map1Vertex3 &&
       !(ctx->VertexProgram._Enabled && ctx->Eval.Map1Attrib[VERT_ATTRIB_POS]))
      return;

   du = ctx->Eval.MapGrid1du;
   u = ctx->Eval.MapGrid1u1 + i1 * du;

   CALL_Begin(GET_DISPATCH(), (prim));
   for (i=i1;i<=i2;i++,u+=du) {
      CALL_EvalCoord1f(GET_DISPATCH(), (u));
   }
   CALL_End(GET_DISPATCH(), ());
}
Esempio n. 2
0
/**
 * Called via glBegin.
 */
static void GLAPIENTRY vbo_exec_Begin( GLenum mode )
{
   GET_CURRENT_CONTEXT( ctx ); 
   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
   int i;

   if (_mesa_inside_begin_end(ctx)) {
      _mesa_error(ctx, GL_INVALID_OPERATION, "glBegin");
      return;
   }

   if (!_mesa_valid_prim_mode(ctx, mode, "glBegin")) {
      return;
   }

   vbo_draw_method(vbo_context(ctx), DRAW_BEGIN_END);

   if (ctx->NewState) {
      _mesa_update_state( ctx );

      CALL_Begin(ctx->Exec, (mode));
      return;
   }

   if (!_mesa_valid_to_render(ctx, "glBegin")) {
      return;
   }

   /* Heuristic: attempt to isolate attributes occurring outside
    * begin/end pairs.
    */
   if (exec->vtx.vertex_size && !exec->vtx.attrsz[0])
      vbo_exec_FlushVertices_internal(exec, GL_FALSE);

   i = exec->vtx.prim_count++;
   exec->vtx.prim[i].mode = mode;
   exec->vtx.prim[i].begin = 1;
   exec->vtx.prim[i].end = 0;
   exec->vtx.prim[i].indexed = 0;
   exec->vtx.prim[i].weak = 0;
   exec->vtx.prim[i].pad = 0;
   exec->vtx.prim[i].start = exec->vtx.vert_count;
   exec->vtx.prim[i].count = 0;
   exec->vtx.prim[i].num_instances = 1;
   exec->vtx.prim[i].base_instance = 0;
   exec->vtx.prim[i].is_indirect = 0;

   ctx->Driver.CurrentExecPrimitive = mode;

   ctx->Exec = ctx->BeginEnd;
   /* We may have been called from a display list, in which case we should
    * leave dlist.c's dispatch table in place.
    */
   if (ctx->CurrentDispatch == ctx->OutsideBeginEnd) {
      ctx->CurrentDispatch = ctx->BeginEnd;
      _glapi_set_dispatch(ctx->CurrentDispatch);
   } else {
      assert(ctx->CurrentDispatch == ctx->Save);
   }
}
Esempio n. 3
0
void GLAPIENTRY _mesa_noop_DrawElements(GLenum mode, GLsizei count, GLenum type,
			     const GLvoid *indices)
{
   GET_CURRENT_CONTEXT(ctx);
   GLint i;

   if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices ))
      return;

   CALL_Begin(GET_DISPATCH(), (mode));

   switch (type) {
   case GL_UNSIGNED_BYTE:
      for (i = 0 ; i < count ; i++)
	  CALL_ArrayElement(GET_DISPATCH(), ( ((GLubyte *)indices)[i] ));
      break;
   case GL_UNSIGNED_SHORT:
      for (i = 0 ; i < count ; i++)
	  CALL_ArrayElement(GET_DISPATCH(), ( ((GLushort *)indices)[i] ));
      break;
   case GL_UNSIGNED_INT:
      for (i = 0 ; i < count ; i++)
	  CALL_ArrayElement(GET_DISPATCH(), ( ((GLuint *)indices)[i] ));
      break;
   default:
      _mesa_error( ctx, GL_INVALID_ENUM, "glDrawElements(type)" );
      break;
   }

   CALL_End(GET_DISPATCH(), ());
}
Esempio n. 4
0
/**
 * Called from glBegin.
 * ctx->Driver.CurrentExecPrimitive will be set to <mode>.
 */
static void GLAPIENTRY _tnl_Begin( GLenum mode )
{
   GET_CURRENT_CONTEXT( ctx ); 

   if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END) {
      /* we're not inside a glBegin/End pair */
      TNLcontext *tnl = TNL_CONTEXT(ctx); 
      GLuint i;

      if (ctx->NewState) {
	 _mesa_update_state( ctx );

         if ((ctx->VertexProgram.Enabled && !ctx->VertexProgram._Enabled) ||
            (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled)) {
            _mesa_error(ctx, GL_INVALID_OPERATION,
                        "glBegin (invalid vertex/fragment program)");
            tnl->DiscardPrimitive = GL_TRUE;
            return;
         }

         if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
            _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
                        "glBegin(incomplete framebuffer)");
            tnl->DiscardPrimitive = GL_TRUE;
            return;
         }

         tnl->DiscardPrimitive = GL_FALSE;

	 if (!(tnl->Driver.NotifyBegin && 
	       tnl->Driver.NotifyBegin( ctx, mode )))
	     CALL_Begin(ctx->Exec, (mode));
	 return;
      }

      /* Heuristic: attempt to isolate attributes occuring outside
       * begin/end pairs.
       */
      if (tnl->vtx.vertex_size && !tnl->vtx.attrsz[0]) 
	 _tnl_FlushVertices( ctx, ~0 );

      i = tnl->vtx.prim_count++;
      tnl->vtx.prim[i].mode = mode | PRIM_BEGIN;
      tnl->vtx.prim[i].start = tnl->vtx.initial_counter - tnl->vtx.counter;
      tnl->vtx.prim[i].count = 0;

      ctx->Driver.CurrentExecPrimitive = mode;
   }
   else {
      /* already inside glBegin/End */
      _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );
   }      
}
Esempio n. 5
0
/**
 * Called via glBegin.
 */
static void GLAPIENTRY vbo_exec_Begin( GLenum mode )
{
   GET_CURRENT_CONTEXT( ctx ); 

   if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END) {
      struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
      int i;

      if (!_mesa_valid_prim_mode(ctx, mode, "glBegin")) {
         return;
      }

      vbo_draw_method(vbo_context(ctx), DRAW_BEGIN_END);

      if (ctx->Driver.PrepareExecBegin)
	 ctx->Driver.PrepareExecBegin(ctx);

      if (ctx->NewState) {
	 _mesa_update_state( ctx );

	 CALL_Begin(ctx->Exec, (mode));
	 return;
      }

      if (!_mesa_valid_to_render(ctx, "glBegin")) {
         return;
      }

      /* Heuristic: attempt to isolate attributes occuring outside
       * begin/end pairs.
       */
      if (exec->vtx.vertex_size && !exec->vtx.attrsz[0]) 
	 vbo_exec_FlushVertices_internal(exec, GL_FALSE);

      i = exec->vtx.prim_count++;
      exec->vtx.prim[i].mode = mode;
      exec->vtx.prim[i].begin = 1;
      exec->vtx.prim[i].end = 0;
      exec->vtx.prim[i].indexed = 0;
      exec->vtx.prim[i].weak = 0;
      exec->vtx.prim[i].pad = 0;
      exec->vtx.prim[i].start = exec->vtx.vert_count;
      exec->vtx.prim[i].count = 0;
      exec->vtx.prim[i].num_instances = 1;
      exec->vtx.prim[i].base_instance = 0;

      ctx->Driver.CurrentExecPrimitive = mode;
   }
   else 
      _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );
      
}
Esempio n. 6
0
/* Some very basic support for arrays.  Drivers without explicit array
 * support can hook these in, but still need to supply an array-elt
 * implementation.
 */
void GLAPIENTRY _mesa_noop_DrawArrays(GLenum mode, GLint start, GLsizei count)
{
   GET_CURRENT_CONTEXT(ctx);
   GLint i;

   if (!_mesa_validate_DrawArrays( ctx, mode, start, count ))
      return;

   CALL_Begin(GET_DISPATCH(), (mode));
   for (i = 0; i < count; i++)
       CALL_ArrayElement(GET_DISPATCH(), (start + i));
   CALL_End(GET_DISPATCH(), ());
}
Esempio n. 7
0
/**
 * Execute a glRectf() function.
 */
static void GLAPIENTRY
vbo_exec_Rectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
{
   GET_CURRENT_CONTEXT(ctx);
   ASSERT_OUTSIDE_BEGIN_END(ctx);

   CALL_Begin(GET_DISPATCH(), (GL_QUADS));
   CALL_Vertex2f(GET_DISPATCH(), (x1, y1));
   CALL_Vertex2f(GET_DISPATCH(), (x2, y1));
   CALL_Vertex2f(GET_DISPATCH(), (x2, y2));
   CALL_Vertex2f(GET_DISPATCH(), (x1, y2));
   CALL_End(GET_DISPATCH(), ());
}
Esempio n. 8
0
/* Build a list of primitives on the fly.  Keep
 * ctx->Driver.CurrentExecPrimitive uptodate as well.
 */
static void GLAPIENTRY vbo_exec_Begin( GLenum mode )
{
   GET_CURRENT_CONTEXT( ctx ); 

   if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END) {
      struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
      int i;

      if (ctx->NewState) {
	 _mesa_update_state( ctx );

	 CALL_Begin(ctx->Exec, (mode));
	 return;
      }

      if (!vbo_validate_shaders(ctx)) {
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "glBegin (invalid vertex/fragment program)");
         return;
      }

      /* Heuristic: attempt to isolate attributes occuring outside
       * begin/end pairs.
       */
      if (exec->vtx.vertex_size && !exec->vtx.attrsz[0]) 
	 vbo_exec_FlushVertices_internal( ctx, GL_FALSE );

      i = exec->vtx.prim_count++;
      exec->vtx.prim[i].mode = mode;
      exec->vtx.prim[i].begin = 1;
      exec->vtx.prim[i].end = 0;
      exec->vtx.prim[i].indexed = 0;
      exec->vtx.prim[i].weak = 0;
      exec->vtx.prim[i].pad = 0;
      exec->vtx.prim[i].start = exec->vtx.vert_count;
      exec->vtx.prim[i].count = 0;

      ctx->Driver.CurrentExecPrimitive = mode;
   }
   else 
      _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );
      
}
Esempio n. 9
0
static void GLAPIENTRY
vbo_exec_EvalMesh1(GLenum mode, GLint i1, GLint i2)
{
   GET_CURRENT_CONTEXT(ctx);
   GLint i;
   GLfloat u, du;
   GLenum prim;

   ASSERT_OUTSIDE_BEGIN_END(ctx);

   switch (mode) {
   case GL_POINT:
      prim = GL_POINTS;
      break;
   case GL_LINE:
      prim = GL_LINE_STRIP;
      break;
   default:
      _mesa_error( ctx, GL_INVALID_ENUM, "glEvalMesh1(mode)" );
      return;
   }

   /* No effect if vertex maps disabled.
    */
   if (!ctx->Eval.Map1Vertex4 && 
       !ctx->Eval.Map1Vertex3)
      return;

   du = ctx->Eval.MapGrid1du;
   u = ctx->Eval.MapGrid1u1 + i1 * du;

   CALL_Begin(GET_DISPATCH(), (prim));
   for (i=i1;i<=i2;i++,u+=du) {
      CALL_EvalCoord1f(GET_DISPATCH(), (u));
   }
   CALL_End(GET_DISPATCH(), ());
}
Esempio n. 10
0
void GLAPIENTRY _mesa_noop_EvalMesh2( GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2 )
{
   GET_CURRENT_CONTEXT(ctx);
   GLfloat u, du, v, dv, v1, u1;
   GLint i, j;

   switch (mode) {
   case GL_POINT:
   case GL_LINE:
   case GL_FILL:
      break;
   default:
      _mesa_error( ctx, GL_INVALID_ENUM, "glEvalMesh2(mode)" );
      return;
   }

   /* No effect if vertex maps disabled.
    */
   if (!ctx->Eval.Map2Vertex4 && 
       !ctx->Eval.Map2Vertex3 &&
       !(ctx->VertexProgram._Enabled && ctx->Eval.Map2Attrib[VERT_ATTRIB_POS]))
      return;

   du = ctx->Eval.MapGrid2du;
   dv = ctx->Eval.MapGrid2dv;
   v1 = ctx->Eval.MapGrid2v1 + j1 * dv;
   u1 = ctx->Eval.MapGrid2u1 + i1 * du;

   switch (mode) {
   case GL_POINT:
      CALL_Begin(GET_DISPATCH(), (GL_POINTS));
      for (v=v1,j=j1;j<=j2;j++,v+=dv) {
	 for (u=u1,i=i1;i<=i2;i++,u+=du) {
	    CALL_EvalCoord2f(GET_DISPATCH(), (u, v));
	 }
      }
      CALL_End(GET_DISPATCH(), ());
      break;
   case GL_LINE:
      for (v=v1,j=j1;j<=j2;j++,v+=dv) {
	 CALL_Begin(GET_DISPATCH(), (GL_LINE_STRIP));
	 for (u=u1,i=i1;i<=i2;i++,u+=du) {
	    CALL_EvalCoord2f(GET_DISPATCH(), (u, v));
	 }
	 CALL_End(GET_DISPATCH(), ());
      }
      for (u=u1,i=i1;i<=i2;i++,u+=du) {
	 CALL_Begin(GET_DISPATCH(), (GL_LINE_STRIP));
	 for (v=v1,j=j1;j<=j2;j++,v+=dv) {
	    CALL_EvalCoord2f(GET_DISPATCH(), (u, v));
	 }
	 CALL_End(GET_DISPATCH(), ());
      }
      break;
   case GL_FILL:
      for (v=v1,j=j1;j<j2;j++,v+=dv) {
	 CALL_Begin(GET_DISPATCH(), (GL_TRIANGLE_STRIP));
	 for (u=u1,i=i1;i<=i2;i++,u+=du) {
	    CALL_EvalCoord2f(GET_DISPATCH(), (u, v));
	    CALL_EvalCoord2f(GET_DISPATCH(), (u, v+dv));
	 }
	 CALL_End(GET_DISPATCH(), ());
      }
      break;
   default:
      _mesa_error( ctx, GL_INVALID_ENUM, "glEvalMesh2(mode)" );
      return;
   }
}
Esempio n. 11
0
/* Begin/End
 */
static void radeon_Begin( GLenum mode )
{
   GET_CURRENT_CONTEXT(ctx);
   radeonContextPtr rmesa = RADEON_CONTEXT(ctx);

   if (RADEON_DEBUG & DEBUG_VFMT)
      fprintf(stderr, "%s( %s )\n", __FUNCTION__,
	      _mesa_lookup_enum_by_nr( mode ));

   if (mode > GL_POLYGON) {
      _mesa_error( ctx, GL_INVALID_ENUM, "glBegin" );
      return;
   }

   if (rmesa->vb.prim[0] != GL_POLYGON+1) {
      _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );
      return;
   }
   
   if (ctx->NewState) 
      _mesa_update_state( ctx );

   if (rmesa->NewGLState)
      radeonValidateState( ctx );

   if (rmesa->vb.recheck) 
      radeonVtxfmtValidate( ctx );

   if (!rmesa->vb.installed) {
      CALL_Begin(GET_DISPATCH(), (mode));
      return;
   }


   if (rmesa->dma.flush && rmesa->vb.counter < 12) {
      if (RADEON_DEBUG & DEBUG_VFMT)
	 fprintf(stderr, "%s: flush almost-empty buffers\n", __FUNCTION__);
      flush_prims( rmesa );
   }

   /* Need to arrange to save vertices here?  Or always copy from dma (yuk)?
    */
   if (!rmesa->dma.flush) {
/* FIXME: what are these constants? */
      if (rmesa->dma.current.ptr + 12*rmesa->vb.vertex_size*4 > 
	  rmesa->dma.current.end) {
	 RADEON_NEWPRIM( rmesa );
	 radeonRefillCurrentDmaRegion( rmesa );
      }

      rmesa->vb.dmaptr = (int *)(rmesa->dma.current.address + rmesa->dma.current.ptr);
      rmesa->vb.counter = (rmesa->dma.current.end - rmesa->dma.current.ptr) / 
	 (rmesa->vb.vertex_size * 4);
      rmesa->vb.counter--;
      rmesa->vb.initial_counter = rmesa->vb.counter;
      rmesa->vb.notify = wrap_buffer;
      rmesa->dma.flush = flush_prims;
      ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
   }
   
   
   rmesa->vb.prim[0] = mode;
   start_prim( rmesa, mode | PRIM_BEGIN );
}
Esempio n. 12
0
static void VFMT_FALLBACK( const char *caller )
{
   GET_CURRENT_CONTEXT(ctx);
   radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
   GLfloat tmp[3][RADEON_MAX_VERTEX_SIZE];
   GLuint i, prim;
   GLuint ind = rmesa->vb.vertex_format;
   GLuint nrverts;
   GLfloat alpha = 1.0;
   GLuint unit;

   if (RADEON_DEBUG & (DEBUG_FALLBACKS|DEBUG_VFMT))
      fprintf(stderr, "%s from %s\n", __FUNCTION__, caller);

   if (rmesa->vb.prim[0] == GL_POLYGON+1) {
      VFMT_FALLBACK_OUTSIDE_BEGIN_END( __FUNCTION__ );
      return;
   }

   /* Copy vertices out of dma:
    */
   nrverts = copy_dma_verts( rmesa, tmp );

   /* Finish the prim at this point:
    */
   note_last_prim( rmesa, 0 );
   flush_prims( rmesa );

   /* Update ctx->Driver.CurrentExecPrimitive and swap in swtnl. 
    */
   prim = rmesa->vb.prim[0];
   ctx->Driver.CurrentExecPrimitive = GL_POLYGON+1;
   _tnl_wakeup_exec( ctx );
   ctx->Driver.FlushVertices = radeonFlushVertices;

   assert(rmesa->dma.flush == 0);
   rmesa->vb.fell_back = GL_TRUE;
   rmesa->vb.installed = GL_FALSE;
   CALL_Begin(GET_DISPATCH(), (prim));
   
   if (rmesa->vb.installed_color_3f_sz == 4)
      alpha = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][3];

   /* Replay saved vertices
    */
   for (i = 0 ; i < nrverts; i++) {
      GLuint offset = 3;
      if (ind & RADEON_CP_VC_FRMT_N0) {
	 CALL_Normal3fv(GET_DISPATCH(), (&tmp[i][offset]));
	 offset += 3;
      }

      if (ind & RADEON_CP_VC_FRMT_PKCOLOR) {
	 radeon_color_t *col = (radeon_color_t *)&tmp[i][offset];
	 CALL_Color4ub(GET_DISPATCH(), (col->red, col->green, col->blue, col->alpha));
	 offset++;
      }
      else if (ind & RADEON_CP_VC_FRMT_FPALPHA) {
	 CALL_Color4fv(GET_DISPATCH(), (&tmp[i][offset]));
	 offset+=4;
      } 
      else if (ind & RADEON_CP_VC_FRMT_FPCOLOR) {
	 CALL_Color3fv(GET_DISPATCH(), (&tmp[i][offset]));
	 offset+=3;
      }

      if (ind & RADEON_CP_VC_FRMT_PKSPEC) {
	 radeon_color_t *spec = (radeon_color_t *)&tmp[i][offset];
	 CALL_SecondaryColor3ubEXT(GET_DISPATCH(), (spec->red, spec->green, spec->blue));
	 offset++;
      }

      for (unit = 0 ; unit < ctx->Const.MaxTextureUnits; unit++) {
	 if (ind & RADEON_ST_BIT(unit)) {
	    CALL_MultiTexCoord2fvARB(GET_DISPATCH(), ((GL_TEXTURE0 + unit), &tmp[i][offset]));
	    offset += 2;
	 }
      }
      CALL_Vertex3fv(GET_DISPATCH(), (&tmp[i][0]));
   }

   /* Replay current vertex
    */
   if (ind & RADEON_CP_VC_FRMT_N0) 
      CALL_Normal3fv(GET_DISPATCH(), (rmesa->vb.normalptr));

   if (ind & RADEON_CP_VC_FRMT_PKCOLOR)
      CALL_Color4ub(GET_DISPATCH(), (rmesa->vb.colorptr->red, rmesa->vb.colorptr->green,
      				     rmesa->vb.colorptr->blue, rmesa->vb.colorptr->alpha));
   else if (ind & RADEON_CP_VC_FRMT_FPALPHA)
      CALL_Color4fv(GET_DISPATCH(), (rmesa->vb.floatcolorptr));
   else if (ind & RADEON_CP_VC_FRMT_FPCOLOR) {
      if (rmesa->vb.installed_color_3f_sz == 4 && alpha != 1.0)
	 CALL_Color4f(GET_DISPATCH(), (rmesa->vb.floatcolorptr[0],
				       rmesa->vb.floatcolorptr[1],
				       rmesa->vb.floatcolorptr[2],
				       alpha));
      else
	 CALL_Color3fv(GET_DISPATCH(), (rmesa->vb.floatcolorptr));
   }

   if (ind & RADEON_CP_VC_FRMT_PKSPEC) 
       CALL_SecondaryColor3ubEXT(GET_DISPATCH(), (rmesa->vb.specptr->red,
       						  rmesa->vb.specptr->green,
						  rmesa->vb.specptr->blue));

   for (unit = 0 ; unit < ctx->Const.MaxTextureUnits; unit++) {
      if (ind & RADEON_ST_BIT(unit)) {
	 CALL_MultiTexCoord2fvARB(GET_DISPATCH(), ((GL_TEXTURE0 + unit),
	 			  rmesa->vb.texcoordptr[unit]));
      }
   }
}
Esempio n. 13
0
void VFMT_FALLBACK( const char *caller )
{
    GET_CURRENT_CONTEXT(ctx);
    r200ContextPtr rmesa = R200_CONTEXT(ctx);
    GLfloat tmp[3][R200_MAX_VERTEX_SIZE];
    GLuint i, prim;
    GLuint ind0 = rmesa->vb.vtxfmt_0;
    GLuint ind1 = rmesa->vb.vtxfmt_1;
    GLuint nrverts;
    GLfloat alpha = 1.0;
    GLuint count;
    GLuint unit;

    if (R200_DEBUG & (DEBUG_FALLBACKS|DEBUG_VFMT))
        fprintf(stderr, "%s from %s\n", __FUNCTION__, caller);

    if (rmesa->vb.prim[0] == GL_POLYGON+1) {
        VFMT_FALLBACK_OUTSIDE_BEGIN_END( __FUNCTION__ );
        return;
    }

    /* Copy vertices out of dma:
     */
    nrverts = copy_dma_verts( rmesa, tmp );

    /* Finish the prim at this point:
     */
    note_last_prim( rmesa, 0 );
    flush_prims( rmesa );

    /* Update ctx->Driver.CurrentExecPrimitive and swap in swtnl.
     */
    prim = rmesa->vb.prim[0];
    ctx->Driver.CurrentExecPrimitive = GL_POLYGON+1;
    _tnl_wakeup_exec( ctx );
    ctx->Driver.FlushVertices = r200FlushVertices;

    assert(rmesa->dma.flush == 0);
    rmesa->vb.fell_back = GL_TRUE;
    rmesa->vb.installed = GL_FALSE;
    CALL_Begin(GET_DISPATCH(), (prim));

    if (rmesa->vb.installed_color_3f_sz == 4)
        alpha = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][3];

    /* Replay saved vertices
     */
    for (i = 0 ; i < nrverts; i++) {
        GLuint offset = 3;

        if (ind0 & R200_VTX_N0) {
            CALL_Normal3fv(GET_DISPATCH(), (&tmp[i][offset]));
            offset += 3;
        }

        if (ind0 & R200_VTX_DISCRETE_FOG) {
            CALL_FogCoordfvEXT(GET_DISPATCH(), (&tmp[i][offset]));
            offset++;
        }

        if (VTX_COLOR(ind0, 0) == R200_VTX_PK_RGBA) {
            CALL_Color4ubv(GET_DISPATCH(), ((GLubyte *)&tmp[i][offset]));
            offset++;
        }
        else if (VTX_COLOR(ind0, 0) == R200_VTX_FP_RGBA) {
            CALL_Color4fv(GET_DISPATCH(), (&tmp[i][offset]));
            offset+=4;
        }
        else if (VTX_COLOR(ind0, 0) == R200_VTX_FP_RGB) {
            CALL_Color3fv(GET_DISPATCH(), (&tmp[i][offset]));
            offset+=3;
        }

        if (VTX_COLOR(ind0, 1) == R200_VTX_PK_RGBA) {
            CALL_SecondaryColor3ubvEXT(GET_DISPATCH(), ((GLubyte *)&tmp[i][offset]));
            offset++;
        }

        for ( unit = 0 ; unit < ctx->Const.MaxTextureUnits ; unit++ ) {
            count = VTX_TEXn_COUNT( ind1, unit );
            dispatch_multitexcoord( count, unit, &tmp[i][offset] );
            offset += count;
        }

        CALL_Vertex3fv(GET_DISPATCH(), (&tmp[i][0]));
    }

    /* Replay current vertex
     */
    if (ind0 & R200_VTX_N0)
        CALL_Normal3fv(GET_DISPATCH(), (rmesa->vb.normalptr));
    if (ind0 & R200_VTX_DISCRETE_FOG) {
        CALL_FogCoordfvEXT(GET_DISPATCH(), (rmesa->vb.fogptr));
    }

    if (VTX_COLOR(ind0, 0) == R200_VTX_PK_RGBA) {
        CALL_Color4ub(GET_DISPATCH(), (rmesa->vb.colorptr->red,
                                       rmesa->vb.colorptr->green,
                                       rmesa->vb.colorptr->blue,
                                       rmesa->vb.colorptr->alpha));
    }
    else if (VTX_COLOR(ind0, 0) == R200_VTX_FP_RGBA) {
        CALL_Color4fv(GET_DISPATCH(), (rmesa->vb.floatcolorptr));
    }
    else if (VTX_COLOR(ind0, 0) == R200_VTX_FP_RGB) {
        if (rmesa->vb.installed_color_3f_sz == 4 && alpha != 1.0) {
            CALL_Color4f(GET_DISPATCH(), (rmesa->vb.floatcolorptr[0],
                                          rmesa->vb.floatcolorptr[1],
                                          rmesa->vb.floatcolorptr[2],
                                          alpha));
        }
        else {
            CALL_Color3fv(GET_DISPATCH(), (rmesa->vb.floatcolorptr));
        }
    }

    if (VTX_COLOR(ind0, 1) == R200_VTX_PK_RGBA)
        CALL_SecondaryColor3ubEXT(GET_DISPATCH(), (rmesa->vb.specptr->red,
                                  rmesa->vb.specptr->green,
                                  rmesa->vb.specptr->blue));

    for ( unit = 0 ; unit < ctx->Const.MaxTextureUnits ; unit++ ) {
        count = VTX_TEXn_COUNT( ind1, unit );
        dispatch_multitexcoord( count, unit, rmesa->vb.texcoordptr[unit] );
    }
}