fix softpipe_clear() to handle ps->offset!=0 (such as when rendering to texture and...
[mesa.git] / src / mesa / pipe / softpipe / sp_prim_setup.c
index 091a2343a9cb588862ecc59d982994607324592f..2e27d00acfb02c4fec960caa3fbe63a67e38fd09 100644 (file)
  */
 
 
-#include "imports.h"
-#include "macros.h"
-
 #include "sp_context.h"
 #include "sp_headers.h"
-#include "pipe/draw/draw_private.h"
 #include "sp_quad.h"
 #include "sp_prim_setup.h"
+#include "pipe/draw/draw_private.h"
+#include "pipe/draw/draw_vertex.h"
+#include "pipe/p_util.h"
 
-
-
-/**
- * Emit/render a quad.
- * This passes the quad to the first stage of per-fragment operations.
- */
-static INLINE void
-quad_emit(struct softpipe_context *sp, struct quad_header *quad)
-{
-   sp->quad.first->run(sp->quad.first, quad);
-}
-
+#define DEBUG_VERTS 0
 
 /**
  * Triangle edge info
  */
 struct edge {
-   GLfloat dx;                 /* X(v1) - X(v0), used only during setup */
-   GLfloat dy;                 /* Y(v1) - Y(v0), used only during setup */
-   GLfloat dxdy;               /* dx/dy */
-   GLfloat sx;                 /* first sample point x coord */
-   GLfloat sy;
-   GLint lines;                        /* number of lines  on this edge */
+   float dx;                   /**< X(v1) - X(v0), used only during setup */
+   float dy;                   /**< Y(v1) - Y(v0), used only during setup */
+   float dxdy;         /**< dx/dy */
+   float sx, sy;               /**< first sample point coord */
+   int lines;                  /**< number of lines on this edge */
 };
 
 
@@ -75,7 +62,6 @@ struct edge {
 struct setup_stage {
    struct draw_stage stage; /**< This must be first (base class) */
 
-   /*XXX NEW */
    struct softpipe_context *softpipe;
 
    /* Vertices are just an array of floats making up each attribute in
@@ -91,17 +77,17 @@ struct setup_stage {
    struct edge etop;
    struct edge emaj;
 
-   GLfloat oneoverarea;
+   float oneoverarea;
 
-   struct setup_coefficient coef[FRAG_ATTRIB_MAX];
+   struct tgsi_interp_coef coef[PIPE_MAX_SHADER_INPUTS];
    struct quad_header quad; 
 
    struct {
-      GLint left[2];   /**< [0] = row0, [1] = row1 */
-      GLint right[2];
-      GLint y;
-      GLuint y_flags;
-      GLuint mask;     /**< mask of MASK_BOTTOM/TOP_LEFT/RIGHT bits */
+      int left[2];   /**< [0] = row0, [1] = row1 */
+      int right[2];
+      int y;
+      unsigned y_flags;
+      unsigned mask;     /**< mask of MASK_BOTTOM/TOP_LEFT/RIGHT bits */
    } span;
 };
 
@@ -110,34 +96,78 @@ struct setup_stage {
 /**
  * Basically a cast wrapper.
  */
-static inline struct setup_stage *setup_stage( struct draw_stage *stage )
+static INLINE struct setup_stage *setup_stage( struct draw_stage *stage )
 {
    return (struct setup_stage *)stage;
 }
 
 
 /**
- * Given an X or Y coordinate, return the block/quad coordinate that it
- * belongs to.
+ * Clip setup->quad against the scissor/surface bounds.
  */
-static inline GLint block( GLint x )
+static INLINE void
+quad_clip(struct setup_stage *setup)
 {
-   return x & ~1;
+   const struct pipe_scissor_state *cliprect = &setup->softpipe->cliprect;
+   const int minx = (int) cliprect->minx;
+   const int maxx = (int) cliprect->maxx;
+   const int miny = (int) cliprect->miny;
+   const int maxy = (int) cliprect->maxy;
+
+   if (setup->quad.x0 >= maxx ||
+       setup->quad.y0 >= maxy ||
+       setup->quad.x0 + 1 < minx ||
+       setup->quad.y0 + 1 < miny) {
+      /* totally clipped */
+      setup->quad.mask = 0x0;
+      return;
+   }
+   if (setup->quad.x0 < minx)
+      setup->quad.mask &= (MASK_BOTTOM_RIGHT | MASK_TOP_RIGHT);
+   if (setup->quad.y0 < miny)
+      setup->quad.mask &= (MASK_TOP_LEFT | MASK_TOP_RIGHT);
+   if (setup->quad.x0 == maxx - 1)
+      setup->quad.mask &= (MASK_BOTTOM_LEFT | MASK_TOP_LEFT);
+   if (setup->quad.y0 == maxy - 1)
+      setup->quad.mask &= (MASK_BOTTOM_LEFT | MASK_BOTTOM_RIGHT);
 }
 
 
+/**
+ * Emit a quad (pass to next stage) with clipping.
+ */
+static INLINE void
+clip_emit_quad(struct setup_stage *setup)
+{
+   quad_clip(setup);
+   if (setup->quad.mask) {
+      struct softpipe_context *sp = setup->softpipe;
+      sp->quad.first->run(sp->quad.first, &setup->quad);
+   }
+}
+
 
 /**
- * Run shader on a quad/block.
+ * Emit a quad (pass to next stage).  No clipping is done.
  */
-static void run_shader_block( struct setup_stage *setup, 
-                             GLint x, GLint y, GLuint mask )
+static INLINE void
+emit_quad( struct setup_stage *setup, int x, int y, unsigned mask )
 {
+   struct softpipe_context *sp = setup->softpipe;
    setup->quad.x0 = x;
    setup->quad.y0 = y;
    setup->quad.mask = mask;
+   sp->quad.first->run(sp->quad.first, &setup->quad);
+}
+
 
-   quad_emit(setup->softpipe, &setup->quad);
+/**
+ * Given an X or Y coordinate, return the block/quad coordinate that it
+ * belongs to.
+ */
+static INLINE int block( int x )
+{
+   return x & ~1;
 }
 
 
@@ -148,10 +178,10 @@ static void run_shader_block( struct setup_stage *setup,
  * this is pretty nasty...  may need to rework flush_spans again to
  * fix it, if possible.
  */
-static GLuint calculate_mask( struct setup_stage *setup,
-                           GLint x )
+static unsigned calculate_mask( struct setup_stage *setup,
+                           int x )
 {
-   GLuint mask = 0;
+   unsigned mask = 0;
 
    if (x >= setup->span.left[0] && x < setup->span.right[0]) 
       mask |= MASK_BOTTOM_LEFT;
@@ -174,8 +204,8 @@ static GLuint calculate_mask( struct setup_stage *setup,
  */
 static void flush_spans( struct setup_stage *setup )
 {
-   GLint minleft, maxright;
-   GLint x;
+   int minleft, maxright;
+   int x;
 
    switch (setup->span.y_flags) {      
    case 3:
@@ -200,9 +230,8 @@ static void flush_spans( struct setup_stage *setup )
 
    for (x = block(minleft); x <= block(maxright); )
    {
-      run_shader_block( setup, x,
-                       setup->span.y, 
-                       calculate_mask( setup, x ) );
+      emit_quad( setup, x, setup->span.y, 
+                 calculate_mask( setup, x ) );
       x += 2;
    }
 
@@ -212,21 +241,40 @@ static void flush_spans( struct setup_stage *setup )
    setup->span.right[1] = 0;
 }
 
+#if DEBUG_VERTS
+static void print_vertex(const struct setup_stage *setup,
+                         const struct vertex_header *v)
+{
+   int i;
+   fprintf(stderr, "Vertex: (%p)\n", v);
+   for (i = 0; i < setup->quad.nr_attrs; i++) {
+      fprintf(stderr, "  %d: %f %f %f %f\n",  i, 
+              v->data[i][0], v->data[i][1], v->data[i][2], v->data[i][3]);
+   }
+}
+#endif
 
-static GLboolean setup_sort_vertices( struct setup_stage *setup,
+static boolean setup_sort_vertices( struct setup_stage *setup,
                                      const struct prim_header *prim )
 {
    const struct vertex_header *v0 = prim->v[0];
    const struct vertex_header *v1 = prim->v[1];
    const struct vertex_header *v2 = prim->v[2];
 
+#if DEBUG_VERTS
+   fprintf(stderr, "Triangle:\n");
+   print_vertex(setup, v0);
+   print_vertex(setup, v1);
+   print_vertex(setup, v2);
+#endif
+
    setup->vprovoke = v2;
 
    /* determine bottom to top order of vertices */
    {
-      GLfloat y0 = v0->data[0][1];
-      GLfloat y1 = v1->data[0][1];
-      GLfloat y2 = v2->data[0][1];
+      float y0 = v0->data[0][1];
+      float y1 = v1->data[0][1];
+      float y2 = v2->data[0][1];
       if (y0 <= y1) {
         if (y1 <= y2) {
            /* y0<=y1<=y2 */
@@ -287,10 +335,10 @@ static GLboolean setup_sort_vertices( struct setup_stage *setup,
     * use the prim->det value because its sign is correct.
     */
    {
-      const GLfloat area = (setup->emaj.dx * setup->ebot.dy - 
+      const float area = (setup->emaj.dx * setup->ebot.dy - 
                            setup->ebot.dx * setup->emaj.dy);
 
-      setup->oneoverarea = 1.0 / area;
+      setup->oneoverarea = 1.0f / area;
       /*
       _mesa_printf("%s one-over-area %f  area %f  det %f\n",
                    __FUNCTION__, setup->oneoverarea, area, prim->det );
@@ -301,9 +349,9 @@ static GLboolean setup_sort_vertices( struct setup_stage *setup,
     *  - the GLSL gl_FrontFacing fragment attribute (bool)
     *  - two-sided stencil test
     */
-   setup->quad.facing = (prim->det > 0.0) ^ (setup->softpipe->setup.front_winding == PIPE_WINDING_CW);
+   setup->quad.facing = (prim->det > 0.0) ^ (setup->softpipe->rasterizer->front_winding == PIPE_WINDING_CW);
 
-   return GL_TRUE;
+   return TRUE;
 }
 
 
@@ -315,10 +363,10 @@ static GLboolean setup_sort_vertices( struct setup_stage *setup,
  * \param i  which component of the slot (0..3)
  */
 static void const_coeff( struct setup_stage *setup,
-                        GLuint slot,
-                        GLuint i )
+                        unsigned slot,
+                        unsigned i )
 {
-   assert(slot < FRAG_ATTRIB_MAX);
+   assert(slot < PIPE_MAX_SHADER_INPUTS);
    assert(i <= 3);
 
    setup->coef[slot].dadx[i] = 0;
@@ -335,15 +383,15 @@ static void const_coeff( struct setup_stage *setup,
  * for a triangle.
  */
 static void tri_linear_coeff( struct setup_stage *setup,
-                              GLuint slot,
-                              GLuint i)
+                              unsigned slot,
+                              unsigned i)
 {
-   GLfloat botda = setup->vmid->data[slot][i] - setup->vmin->data[slot][i];
-   GLfloat majda = setup->vmax->data[slot][i] - setup->vmin->data[slot][i];
-   GLfloat a = setup->ebot.dy * majda - botda * setup->emaj.dy;
-   GLfloat b = setup->emaj.dx * botda - majda * setup->ebot.dx;
+   float botda = setup->vmid->data[slot][i] - setup->vmin->data[slot][i];
+   float majda = setup->vmax->data[slot][i] - setup->vmin->data[slot][i];
+   float a = setup->ebot.dy * majda - botda * setup->emaj.dy;
+   float b = setup->emaj.dx * botda - majda * setup->ebot.dx;
    
-   assert(slot < FRAG_ATTRIB_MAX);
+   assert(slot < PIPE_MAX_SHADER_INPUTS);
    assert(i <= 3);
 
    setup->coef[slot].dadx[i] = a * setup->oneoverarea;
@@ -362,8 +410,8 @@ static void tri_linear_coeff( struct setup_stage *setup,
     * instead - i'll switch to this later.
     */
    setup->coef[slot].a0[i] = (setup->vmin->data[slot][i] - 
-                           (setup->coef[slot].dadx[i] * (setup->vmin->data[0][0] - 0.5) + 
-                            setup->coef[slot].dady[i] * (setup->vmin->data[0][1] - 0.5)));
+                           (setup->coef[slot].dadx[i] * (setup->vmin->data[0][0] - 0.5f) + 
+                            setup->coef[slot].dady[i] * (setup->vmin->data[0][1] - 0.5f)));
 
    /*
    _mesa_printf("attr[%d].%c: %f dx:%f dy:%f\n",
@@ -378,42 +426,53 @@ static void tri_linear_coeff( struct setup_stage *setup,
 /**
  * Compute a0, dadx and dady for a perspective-corrected interpolant,
  * for a triangle.
+ * We basically multiply the vertex value by 1/w before computing
+ * the plane coefficients (a0, dadx, dady).
+ * Later, when we compute the value at a particular fragment position we'll
+ * divide the interpolated value by the interpolated W at that fragment.
  */
 static void tri_persp_coeff( struct setup_stage *setup,
-                             GLuint slot,
-                             GLuint i )
+                             unsigned slot,
+                             unsigned i )
 {
    /* premultiply by 1/w:
     */
-   GLfloat mina = setup->vmin->data[slot][i] * setup->vmin->data[0][3];
-   GLfloat mida = setup->vmid->data[slot][i] * setup->vmid->data[0][3];
-   GLfloat maxa = setup->vmax->data[slot][i] * setup->vmax->data[0][3];
-
-   GLfloat botda = mida - mina;
-   GLfloat majda = maxa - mina;
-   GLfloat a = setup->ebot.dy * majda - botda * setup->emaj.dy;
-   GLfloat b = setup->emaj.dx * botda - majda * setup->ebot.dx;
+   float mina = setup->vmin->data[slot][i] * setup->vmin->data[0][3];
+   float mida = setup->vmid->data[slot][i] * setup->vmid->data[0][3];
+   float maxa = setup->vmax->data[slot][i] * setup->vmax->data[0][3];
+
+   float botda = mida - mina;
+   float majda = maxa - mina;
+   float a = setup->ebot.dy * majda - botda * setup->emaj.dy;
+   float b = setup->emaj.dx * botda - majda * setup->ebot.dx;
       
-   assert(slot < FRAG_ATTRIB_MAX);
+   /*
+   printf("tri persp %d,%d: %f %f %f\n", slot, i,
+          setup->vmin->data[slot][i],
+          setup->vmid->data[slot][i],
+          setup->vmax->data[slot][i]
+          );
+   */
+
+   assert(slot < PIPE_MAX_SHADER_INPUTS);
    assert(i <= 3);
 
    setup->coef[slot].dadx[i] = a * setup->oneoverarea;
    setup->coef[slot].dady[i] = b * setup->oneoverarea;
    setup->coef[slot].a0[i] = (mina - 
-                           (setup->coef[slot].dadx[i] * (setup->vmin->data[0][0] - 0.5) + 
-                            setup->coef[slot].dady[i] * (setup->vmin->data[0][1] - 0.5)));
+                           (setup->coef[slot].dadx[i] * (setup->vmin->data[0][0] - 0.5f) + 
+                            setup->coef[slot].dady[i] * (setup->vmin->data[0][1] - 0.5f)));
 }
 
 
-
 /**
  * Compute the setup->coef[] array dadx, dady, a0 values.
  * Must be called after setup->vmin,vmid,vmax,vprovoke are initialized.
  */
 static void setup_tri_coefficients( struct setup_stage *setup )
 {
-   const enum interp_mode *interp = setup->softpipe->interp;
-   GLuint slot, j;
+   const interp_mode *interp = setup->softpipe->vertex_info.interp_mode;
+   unsigned slot, j;
 
    /* z and w are done by linear interpolation:
     */
@@ -438,6 +497,10 @@ static void setup_tri_coefficients( struct setup_stage *setup )
         for (j = 0; j < NUM_CHANNELS; j++)
            tri_persp_coeff(setup, slot, j);
         break;
+
+      default:
+         /* invalid interp mode */
+         assert(0);
       }
    }
 }
@@ -446,25 +509,25 @@ static void setup_tri_coefficients( struct setup_stage *setup )
 
 static void setup_tri_edges( struct setup_stage *setup )
 {
-   GLfloat vmin_x = setup->vmin->data[0][0] + 0.5;
-   GLfloat vmid_x = setup->vmid->data[0][0] + 0.5;
+   float vmin_x = setup->vmin->data[0][0] + 0.5f;
+   float vmid_x = setup->vmid->data[0][0] + 0.5f;
 
-   GLfloat vmin_y = setup->vmin->data[0][1] - 0.5;
-   GLfloat vmid_y = setup->vmid->data[0][1] - 0.5;
-   GLfloat vmax_y = setup->vmax->data[0][1] - 0.5;
+   float vmin_y = setup->vmin->data[0][1] - 0.5f;
+   float vmid_y = setup->vmid->data[0][1] - 0.5f;
+   float vmax_y = setup->vmax->data[0][1] - 0.5f;
 
    setup->emaj.sy = ceilf(vmin_y);
-   setup->emaj.lines = (GLint) ceilf(vmax_y - setup->emaj.sy);
+   setup->emaj.lines = (int) ceilf(vmax_y - setup->emaj.sy);
    setup->emaj.dxdy = setup->emaj.dx / setup->emaj.dy;
    setup->emaj.sx = vmin_x + (setup->emaj.sy - vmin_y) * setup->emaj.dxdy;
 
    setup->etop.sy = ceilf(vmid_y);
-   setup->etop.lines = (GLint) ceilf(vmax_y - setup->etop.sy);
+   setup->etop.lines = (int) ceilf(vmax_y - setup->etop.sy);
    setup->etop.dxdy = setup->etop.dx / setup->etop.dy;
    setup->etop.sx = vmid_x + (setup->etop.sy - vmid_y) * setup->etop.dxdy;
 
    setup->ebot.sy = ceilf(vmin_y);
-   setup->ebot.lines = (GLint) ceilf(vmid_y - setup->ebot.sy);
+   setup->ebot.lines = (int) ceilf(vmid_y - setup->ebot.sy);
    setup->ebot.dxdy = setup->ebot.dx / setup->ebot.dy;
    setup->ebot.sx = vmin_x + (setup->ebot.sy - vmin_y) * setup->ebot.dxdy;
 }
@@ -472,38 +535,35 @@ static void setup_tri_edges( struct setup_stage *setup )
 
 /**
  * Render the upper or lower half of a triangle.
- * Scissoring is applied here too.
+ * Scissoring/cliprect is applied here too.
  */
 static void subtriangle( struct setup_stage *setup,
                         struct edge *eleft,
                         struct edge *eright,
-                        GLuint lines )
+                        unsigned lines )
 {
-   GLint y, start_y, finish_y;
-   GLint sy = (GLint)eleft->sy;
+   const struct pipe_scissor_state *cliprect = &setup->softpipe->cliprect;
+   const int minx = (int) cliprect->minx;
+   const int maxx = (int) cliprect->maxx;
+   const int miny = (int) cliprect->miny;
+   const int maxy = (int) cliprect->maxy;
+   int y, start_y, finish_y;
+   int sy = (int)eleft->sy;
 
-   assert((GLint)eleft->sy == (GLint) eright->sy);
-   assert((GLint)eleft->sy >= 0);      /* catch bug in x64? */
+   assert((int)eleft->sy == (int) eright->sy);
 
-   /* scissor y:
-    */
-   if (setup->softpipe->setup.scissor) {
-      start_y = sy;
-      finish_y = start_y + lines;
+   /* clip top/bottom */
+   start_y = sy;
+   finish_y = sy + lines;
 
-      if (start_y < setup->softpipe->scissor.miny) 
-        start_y = setup->softpipe->scissor.miny;
+   if (start_y < miny)
+      start_y = miny;
 
-      if (finish_y > setup->softpipe->scissor.maxy) 
-        finish_y = setup->softpipe->scissor.maxy;
+   if (finish_y > maxy)
+      finish_y = maxy;
 
-      start_y -= sy;
-      finish_y -= sy;
-   }
-   else {
-      start_y = 0;
-      finish_y = lines;
-   }
+   start_y -= sy;
+   finish_y -= sy;
 
    /*
    _mesa_printf("%s %d %d\n", __FUNCTION__, start_y, finish_y);  
@@ -517,31 +577,26 @@ static void subtriangle( struct setup_stage *setup,
        *
        * this is all drowned out by the attribute interpolation anyway.
        */
-      GLint left = (GLint)(eleft->sx + y * eleft->dxdy);
-      GLint right = (GLint)(eright->sx + y * eright->dxdy);
+      int left = (int)(eleft->sx + y * eleft->dxdy);
+      int right = (int)(eright->sx + y * eright->dxdy);
 
-      /* scissor x: 
-       */
-      if (setup->softpipe->setup.scissor) {
-        if (left  < setup->softpipe->scissor.minx) 
-           left  = setup->softpipe->scissor.minx;
-
-        if (right > setup->softpipe->scissor.maxx) 
-           right = setup->softpipe->scissor.maxx;
-      }
+      /* clip left/right */
+      if (left < minx)
+         left = minx;
+      if (right > maxx)
+         right = maxx;
 
       if (left < right) {
-        GLint _y = sy+y;
-        if (block(_y) != setup->span.y) {
-           flush_spans(setup);
-           setup->span.y = block(_y);
-        }
-   
-        setup->span.left[_y&1] = left;
-        setup->span.right[_y&1] = right;
-        setup->span.y_flags |= 1<<(_y&1);
+         int _y = sy + y;
+         if (block(_y) != setup->span.y) {
+            flush_spans(setup);
+            setup->span.y = block(_y);
+         }
+
+         setup->span.left[_y&1] = left;setup->span.right[_y&1] = right;
+         setup->span.y_flags |= 1<<(_y&1);
       }
-   } 
+   }
 
 
    /* save the values so that emaj can be restarted:
@@ -602,17 +657,17 @@ static void setup_tri( struct draw_stage *stage,
  * for a line.
  */
 static void
-line_linear_coeff(struct setup_stage *setup, GLuint slot, GLuint i)
+line_linear_coeff(struct setup_stage *setup, unsigned slot, unsigned i)
 {
-   const GLfloat dz = setup->vmax->data[slot][i] - setup->vmin->data[slot][i];
-   const GLfloat dadx = dz * setup->emaj.dx * setup->oneoverarea;
-   const GLfloat dady = dz * setup->emaj.dy * setup->oneoverarea;
+   const float dz = setup->vmax->data[slot][i] - setup->vmin->data[slot][i];
+   const float dadx = dz * setup->emaj.dx * setup->oneoverarea;
+   const float dady = dz * setup->emaj.dy * setup->oneoverarea;
    setup->coef[slot].dadx[i] = dadx;
    setup->coef[slot].dady[i] = dady;
    setup->coef[slot].a0[i]
       = (setup->vmin->data[slot][i] - 
-         (dadx * (setup->vmin->data[0][0] - 0.5) + 
-          dady * (setup->vmin->data[0][1] - 0.5)));
+         (dadx * (setup->vmin->data[0][0] - 0.5f) + 
+          dady * (setup->vmin->data[0][1] - 0.5f)));
 }
 
 
@@ -621,7 +676,7 @@ line_linear_coeff(struct setup_stage *setup, GLuint slot, GLuint i)
  * for a line.
  */
 static void
-line_persp_coeff(struct setup_stage *setup, GLuint slot, GLuint i)
+line_persp_coeff(struct setup_stage *setup, unsigned slot, unsigned i)
 {
    /* XXX to do */
    line_linear_coeff(setup, slot, i); /* XXX temporary */
@@ -635,8 +690,8 @@ line_persp_coeff(struct setup_stage *setup, GLuint slot, GLuint i)
 static INLINE void
 setup_line_coefficients(struct setup_stage *setup, struct prim_header *prim)
 {
-   const enum interp_mode *interp = setup->softpipe->interp;
-   GLuint slot, j;
+   const interp_mode *interp = setup->softpipe->vertex_info.interp_mode;
+   unsigned slot, j;
 
    /* use setup->vmin, vmax to point to vertices */
    setup->vprovoke = prim->v[1];
@@ -646,8 +701,8 @@ setup_line_coefficients(struct setup_stage *setup, struct prim_header *prim)
    setup->emaj.dx = setup->vmax->data[0][0] - setup->vmin->data[0][0];
    setup->emaj.dy = setup->vmax->data[0][1] - setup->vmin->data[0][1];
    /* NOTE: this is not really 1/area */
-   setup->oneoverarea = 1.0 / (setup->emaj.dx * setup->emaj.dx +
-                               setup->emaj.dy * setup->emaj.dy);
+   setup->oneoverarea = 1.0f / (setup->emaj.dx * setup->emaj.dx +
+                                setup->emaj.dy * setup->emaj.dy);
 
    /* z and w are done by linear interpolation:
     */
@@ -672,6 +727,10 @@ setup_line_coefficients(struct setup_stage *setup, struct prim_header *prim)
         for (j = 0; j < NUM_CHANNELS; j++)
            line_persp_coeff(setup, slot, j);
         break;
+
+      default:
+         /* invalid interp mode */
+         assert(0);
       }
    }
 }
@@ -681,21 +740,21 @@ setup_line_coefficients(struct setup_stage *setup, struct prim_header *prim)
  * Plot a pixel in a line segment.
  */
 static INLINE void
-plot(struct setup_stage *setup, GLint x, GLint y)
+plot(struct setup_stage *setup, int x, int y)
 {
-   const GLint iy = y & 1;
-   const GLint ix = x & 1;
-   const GLint quadX = x - ix;
-   const GLint quadY = y - iy;
-   const GLint mask = (1 << ix) << (2 * iy);
+   const int iy = y & 1;
+   const int ix = x & 1;
+   const int quadX = x - ix;
+   const int quadY = y - iy;
+   const int mask = (1 << ix) << (2 * iy);
 
    if (quadX != setup->quad.x0 || 
        quadY != setup->quad.y0) 
    {
       /* flush prev quad, start new quad */
 
-      if (setup->quad.x0 != -1) 
-        quad_emit(setup->softpipe, &setup->quad);
+      if (setup->quad.x0 != -1)
+         clip_emit_quad(setup);
 
       setup->quad.x0 = quadX;
       setup->quad.y0 = quadY;
@@ -710,10 +769,10 @@ plot(struct setup_stage *setup, GLint x, GLint y)
  * Determine whether or not to emit a line fragment by checking
  * line stipple pattern.
  */
-static INLINE GLuint
-stipple_test(GLint counter, GLushort pattern, GLint factor)
+static INLINE unsigned
+stipple_test(int counter, ushort pattern, int factor)
 {
-   GLint b = (counter / factor) & 0xf;
+   int b = (counter / factor) & 0xf;
    return (1 << b) & pattern;
 }
 
@@ -721,7 +780,6 @@ stipple_test(GLint counter, GLushort pattern, GLint factor)
 /**
  * Do setup for line rasterization, then render the line.
  * XXX single-pixel width, no stipple, etc
- * XXX no scissoring yet.
  */
 static void
 setup_line(struct draw_stage *stage, struct prim_header *prim)
@@ -731,13 +789,13 @@ setup_line(struct draw_stage *stage, struct prim_header *prim)
    struct setup_stage *setup = setup_stage( stage );
    struct softpipe_context *sp = setup->softpipe;
 
-   GLint x0 = (GLint) v0->data[0][0];
-   GLint x1 = (GLint) v1->data[0][0];
-   GLint y0 = (GLint) v0->data[0][1];
-   GLint y1 = (GLint) v1->data[0][1];
-   GLint dx = x1 - x0;
-   GLint dy = y1 - y0;
-   GLint xstep, ystep;
+   int x0 = (int) v0->data[0][0];
+   int x1 = (int) v1->data[0][0];
+   int y0 = (int) v0->data[0][1];
+   int y1 = (int) v1->data[0][1];
+   int dx = x1 - x0;
+   int dy = y1 - y0;
+   int xstep, ystep;
 
    if (dx == 0 && dy == 0)
       return;
@@ -766,19 +824,26 @@ setup_line(struct draw_stage *stage, struct prim_header *prim)
    setup->quad.x0 = setup->quad.y0 = -1;
    setup->quad.mask = 0x0;
    setup->quad.prim = PRIM_LINE;
+   /* XXX temporary: set coverage to 1.0 so the line appears
+    * if AA mode happens to be enabled.
+    */
+   setup->quad.coverage[0] =
+   setup->quad.coverage[1] =
+   setup->quad.coverage[2] =
+   setup->quad.coverage[3] = 1.0;
 
    if (dx > dy) {
       /*** X-major line ***/
-      GLint i;
-      const GLint errorInc = dy + dy;
-      GLint error = errorInc - dx;
-      const GLint errorDec = error - dx;
+      int i;
+      const int errorInc = dy + dy;
+      int error = errorInc - dx;
+      const int errorDec = error - dx;
 
       for (i = 0; i < dx; i++) {
-         if (!sp->setup.line_stipple_enable ||
+         if (!sp->rasterizer->line_stipple_enable ||
              stipple_test(sp->line_stipple_counter,
-                          sp->setup.line_stipple_pattern,
-                          sp->setup.line_stipple_factor + 1)) {
+                          sp->rasterizer->line_stipple_pattern,
+                          sp->rasterizer->line_stipple_factor + 1)) {
              plot(setup, x0, y0);
          }
 
@@ -796,16 +861,16 @@ setup_line(struct draw_stage *stage, struct prim_header *prim)
    }
    else {
       /*** Y-major line ***/
-      GLint i;
-      const GLint errorInc = dx + dx;
-      GLint error = errorInc - dy;
-      const GLint errorDec = error - dy;
+      int i;
+      const int errorInc = dx + dx;
+      int error = errorInc - dy;
+      const int errorDec = error - dy;
 
       for (i = 0; i < dy; i++) {
-         if (!sp->setup.line_stipple_enable ||
+         if (!sp->rasterizer->line_stipple_enable ||
              stipple_test(sp->line_stipple_counter,
-                          sp->setup.line_stipple_pattern,
-                          sp->setup.line_stipple_factor + 1)) {
+                          sp->rasterizer->line_stipple_pattern,
+                          sp->rasterizer->line_stipple_factor + 1)) {
             plot(setup, x0, y0);
          }
 
@@ -825,7 +890,7 @@ setup_line(struct draw_stage *stage, struct prim_header *prim)
 
    /* draw final quad */
    if (setup->quad.mask) {
-      quad_emit(setup->softpipe, &setup->quad);
+      clip_emit_quad(setup);
    }
 }
 
@@ -839,13 +904,15 @@ static void
 setup_point(struct draw_stage *stage, struct prim_header *prim)
 {
    struct setup_stage *setup = setup_stage( stage );
-   /*XXX this should be a vertex attrib! */
-   GLfloat halfSize = 0.5 * setup->softpipe->setup.point_size;
-   GLboolean round = setup->softpipe->setup.point_smooth;
    const struct vertex_header *v0 = prim->v[0];
-   const GLfloat x = v0->data[FRAG_ATTRIB_WPOS][0];
-   const GLfloat y = v0->data[FRAG_ATTRIB_WPOS][1];
-   GLuint slot, j;
+   const int sizeAttr = setup->softpipe->psize_slot;
+   const float halfSize
+      = sizeAttr > 0 ? (0.5f * v0->data[sizeAttr][0])
+        : (0.5f * setup->softpipe->rasterizer->point_size);
+   const boolean round = setup->softpipe->rasterizer->point_smooth;
+   const float x = v0->data[0][0];  /* Note: data[0] is always position */
+   const float y = v0->data[0][1];
+   unsigned slot, j;
 
    /* For points, all interpolants are constant-valued.
     * However, for point sprites, we'll need to setup texcoords appropriately.
@@ -873,78 +940,76 @@ setup_point(struct draw_stage *stage, struct prim_header *prim)
 
    setup->quad.prim = PRIM_POINT;
 
-   /* XXX need to clip against scissor bounds too */
-
    if (halfSize <= 0.5 && !round) {
       /* special case for 1-pixel points */
-      const GLint ix = ((GLint) x) & 1;
-      const GLint iy = ((GLint) y) & 1;
-      setup->quad.x0 = x - ix;
-      setup->quad.y0 = y - iy;
+      const int ix = ((int) x) & 1;
+      const int iy = ((int) y) & 1;
+      setup->quad.x0 = (int) x - ix;
+      setup->quad.y0 = (int) y - iy;
       setup->quad.mask = (1 << ix) << (2 * iy);
-      quad_emit(setup->softpipe, &setup->quad);
+      clip_emit_quad(setup);
    }
    else {
-      const GLint ixmin = block((GLint) (x - halfSize));
-      const GLint ixmax = block((GLint) (x + halfSize));
-      const GLint iymin = block((GLint) (y - halfSize));
-      const GLint iymax = block((GLint) (y + halfSize));
-      GLint ix, iy;
+      const int ixmin = block((int) (x - halfSize));
+      const int ixmax = block((int) (x + halfSize));
+      const int iymin = block((int) (y - halfSize));
+      const int iymax = block((int) (y + halfSize));
+      int ix, iy;
 
       if (round) {
          /* rounded points */
-         const GLfloat rmin = halfSize - 0.7071F;  /* 0.7071 = sqrt(2)/2 */
-         const GLfloat rmax = halfSize + 0.7071F;
-         const GLfloat rmin2 = MAX2(0.0F, rmin * rmin);
-         const GLfloat rmax2 = rmax * rmax;
-         const GLfloat cscale = 1.0F / (rmax2 - rmin2);
+         const float rmin = halfSize - 0.7071F;  /* 0.7071 = sqrt(2)/2 */
+         const float rmax = halfSize + 0.7071F;
+         const float rmin2 = MAX2(0.0F, rmin * rmin);
+         const float rmax2 = rmax * rmax;
+         const float cscale = 1.0F / (rmax2 - rmin2);
 
          for (iy = iymin; iy <= iymax; iy += 2) {
             for (ix = ixmin; ix <= ixmax; ix += 2) {
-               GLfloat dx, dy, dist2, cover;
+               float dx, dy, dist2, cover;
 
                setup->quad.mask = 0x0;
 
-               dx = (ix + 0.5) - x;
-               dy = (iy + 0.5) - y;
+               dx = (ix + 0.5f) - x;
+               dy = (iy + 0.5f) - y;
                dist2 = dx * dx + dy * dy;
                if (dist2 <= rmax2) {
                   cover = 1.0F - (dist2 - rmin2) * cscale;
-                  setup->quad.coverage[QUAD_BOTTOM_LEFT] = MIN2(cover, 1.0);
+                  setup->quad.coverage[QUAD_BOTTOM_LEFT] = MIN2(cover, 1.0f);
                   setup->quad.mask |= MASK_BOTTOM_LEFT;
                }
 
-               dx = (ix + 1.5) - x;
-               dy = (iy + 0.5) - y;
+               dx = (ix + 1.5f) - x;
+               dy = (iy + 0.5f) - y;
                dist2 = dx * dx + dy * dy;
                if (dist2 <= rmax2) {
                   cover = 1.0F - (dist2 - rmin2) * cscale;
-                  setup->quad.coverage[QUAD_BOTTOM_RIGHT] = MIN2(cover, 1.0);
+                  setup->quad.coverage[QUAD_BOTTOM_RIGHT] = MIN2(cover, 1.0f);
                   setup->quad.mask |= MASK_BOTTOM_RIGHT;
                }
 
-               dx = (ix + 0.5) - x;
-               dy = (iy + 1.5) - y;
+               dx = (ix + 0.5f) - x;
+               dy = (iy + 1.5f) - y;
                dist2 = dx * dx + dy * dy;
                if (dist2 <= rmax2) {
                   cover = 1.0F - (dist2 - rmin2) * cscale;
-                  setup->quad.coverage[QUAD_TOP_LEFT] = MIN2(cover, 1.0);
+                  setup->quad.coverage[QUAD_TOP_LEFT] = MIN2(cover, 1.0f);
                   setup->quad.mask |= MASK_TOP_LEFT;
                }
 
-               dx = (ix + 1.5) - x;
-               dy = (iy + 1.5) - y;
+               dx = (ix + 1.5f) - x;
+               dy = (iy + 1.5f) - y;
                dist2 = dx * dx + dy * dy;
                if (dist2 <= rmax2) {
                   cover = 1.0F - (dist2 - rmin2) * cscale;
-                  setup->quad.coverage[QUAD_TOP_RIGHT] = MIN2(cover, 1.0);
+                  setup->quad.coverage[QUAD_TOP_RIGHT] = MIN2(cover, 1.0f);
                   setup->quad.mask |= MASK_TOP_RIGHT;
                }
 
                if (setup->quad.mask) {
                   setup->quad.x0 = ix;
                   setup->quad.y0 = iy;
-                  quad_emit( setup->softpipe, &setup->quad );
+                  clip_emit_quad(setup);
                }
             }
          }
@@ -978,7 +1043,7 @@ setup_point(struct draw_stage *stage, struct prim_header *prim)
                if (setup->quad.mask) {
                   setup->quad.x0 = ix;
                   setup->quad.y0 = iy;
-                  quad_emit( setup->softpipe, &setup->quad );
+                  clip_emit_quad(setup);
                }
             }
          }
@@ -991,22 +1056,16 @@ setup_point(struct draw_stage *stage, struct prim_header *prim)
 static void setup_begin( struct draw_stage *stage )
 {
    struct setup_stage *setup = setup_stage(stage);
+   struct softpipe_context *sp = setup->softpipe;
 
    setup->quad.nr_attrs = setup->softpipe->nr_frag_attrs;
 
-   /*
-    * XXX this is where we might map() the renderbuffers to begin
-    * s/w rendering.
-    */
+   sp->quad.first->begin(sp->quad.first);
 }
 
 
 static void setup_end( struct draw_stage *stage )
 {
-   /*
-    * XXX this is where we might unmap() the renderbuffers after
-    * s/w rendering.
-    */
 }
 
 
@@ -1037,3 +1096,85 @@ struct draw_stage *sp_draw_render_stage( struct softpipe_context *softpipe )
 
    return &setup->stage;
 }
+
+
+/* Recalculate det.  This is only used in the test harness below:
+ */
+static void calc_det( struct prim_header *header )
+{
+   /* Window coords: */
+   const float *v0 = header->v[0]->data[0];
+   const float *v1 = header->v[1]->data[0];
+   const float *v2 = header->v[2]->data[0];
+
+   /* edge vectors e = v0 - v2, f = v1 - v2 */
+   const float ex = v0[0] - v2[0];
+   const float ey = v0[1] - v2[1];
+   const float fx = v1[0] - v2[0];
+   const float fy = v1[1] - v2[1];
+   
+   /* det = cross(e,f).z */
+   header->det = ex * fy - ey * fx;
+}
+
+
+
+/* Test harness - feed vertex buffer back into prim pipeline.
+ *
+ * The big issue at this point is that reset_stipple doesn't make it
+ * through the interface.  Probably need to split primitives at reset
+ * stipple, perhaps using the ~0 index marker.
+ */
+void sp_vbuf_setup_draw( struct pipe_context *pipe,
+                         unsigned primitive,
+                         const ushort *elements,
+                         unsigned nr_elements,
+                         const void *vertex_buffer,
+                         unsigned nr_vertices )
+{
+   struct softpipe_context *softpipe = softpipe_context( pipe );
+   struct setup_stage *setup = setup_stage( softpipe->setup );
+   struct prim_header prim;
+   unsigned vertex_size = setup->stage.draw->vertex_info.size * sizeof(float);
+   int i, j;
+
+   prim.det = 0;
+   prim.reset_line_stipple = 0;
+   prim.edgeflags = 0;
+   prim.pad = 0;
+
+   setup->stage.begin( &setup->stage );
+
+   switch (primitive) {
+   case PIPE_PRIM_TRIANGLES:
+      for (i = 0; i < nr_elements; i += 3) {
+         for (j = 0; j < 3; j++) 
+            prim.v[j] = (struct vertex_header *)((char *)vertex_buffer + 
+                                                 elements[i+j] * vertex_size);
+         
+         calc_det(&prim);
+         setup->stage.tri( &setup->stage, &prim );
+      }
+      break;
+
+   case PIPE_PRIM_LINES:
+      for (i = 0; i < nr_elements; i += 2) {
+         for (j = 0; j < 2; j++) 
+            prim.v[j] = (struct vertex_header *)((char *)vertex_buffer + 
+                                                 elements[i+j] * vertex_size);
+         
+         setup->stage.line( &setup->stage, &prim );
+      }
+      break;
+
+   case PIPE_PRIM_POINTS:
+      for (i = 0; i < nr_elements; i += 2) {
+         prim.v[i] = (struct vertex_header *)((char *)vertex_buffer + 
+                                              elements[i] * vertex_size);         
+         setup->stage.point( &setup->stage, &prim );
+      }
+      break;
+   }
+
+   setup->stage.end( &setup->stage );
+}