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 71ef798cbbb718517b32538d1e329f96457972b5..2e27d00acfb02c4fec960caa3fbe63a67e38fd09 100644 (file)
  */
 
 
-//#include "imports.h"
-//#include "macros.h"
-
 #include "sp_context.h"
 #include "sp_headers.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"
 
+#define DEBUG_VERTS 0
 
 /**
  * Triangle edge info
@@ -80,7 +79,7 @@ struct setup_stage {
 
    float oneoverarea;
 
-   struct tgsi_interp_coef coef[FRAG_ATTRIB_MAX];
+   struct tgsi_interp_coef coef[PIPE_MAX_SHADER_INPUTS];
    struct quad_header quad; 
 
    struct {
@@ -110,21 +109,26 @@ static INLINE void
 quad_clip(struct setup_stage *setup)
 {
    const struct pipe_scissor_state *cliprect = &setup->softpipe->cliprect;
-   if (setup->quad.x0 >= cliprect->maxx ||
-       setup->quad.y0 >= cliprect->maxy ||
-       setup->quad.x0 + 1 < cliprect->minx ||
-       setup->quad.y0 + 1 < cliprect->miny) {
+   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 < cliprect->minx)
+   if (setup->quad.x0 < minx)
       setup->quad.mask &= (MASK_BOTTOM_RIGHT | MASK_TOP_RIGHT);
-   if (setup->quad.y0 < cliprect->miny)
+   if (setup->quad.y0 < miny)
       setup->quad.mask &= (MASK_TOP_LEFT | MASK_TOP_RIGHT);
-   if (setup->quad.x0 == cliprect->maxx - 1)
+   if (setup->quad.x0 == maxx - 1)
       setup->quad.mask &= (MASK_BOTTOM_LEFT | MASK_TOP_LEFT);
-   if (setup->quad.y0 == cliprect->maxy - 1)
+   if (setup->quad.y0 == maxy - 1)
       setup->quad.mask &= (MASK_BOTTOM_LEFT | MASK_BOTTOM_RIGHT);
 }
 
@@ -237,15 +241,15 @@ static void flush_spans( struct setup_stage *setup )
    setup->span.right[1] = 0;
 }
 
-#if 0
+#if DEBUG_VERTS
 static void print_vertex(const struct setup_stage *setup,
                          const struct vertex_header *v)
 {
    int i;
-   printf("Vertex:\n");
-   for (i = 0; i < setup->softpipe->nr_attrs; i++) {
-      printf("  %d: %f %f %f\n",  i, 
-          v->data[i][0], v->data[i][1], v->data[i][2]);
+   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
@@ -257,8 +261,8 @@ static boolean setup_sort_vertices( struct setup_stage *setup,
    const struct vertex_header *v1 = prim->v[1];
    const struct vertex_header *v2 = prim->v[2];
 
-#if 0
-   printf("Triangle:\n");
+#if DEBUG_VERTS
+   fprintf(stderr, "Triangle:\n");
    print_vertex(setup, v0);
    print_vertex(setup, v1);
    print_vertex(setup, v2);
@@ -334,7 +338,7 @@ static boolean setup_sort_vertices( struct setup_stage *setup,
       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 );
@@ -345,7 +349,7 @@ static boolean 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 TRUE;
 }
@@ -362,7 +366,7 @@ static void const_coeff( struct setup_stage *setup,
                         unsigned slot,
                         unsigned i )
 {
-   assert(slot < FRAG_ATTRIB_MAX);
+   assert(slot < PIPE_MAX_SHADER_INPUTS);
    assert(i <= 3);
 
    setup->coef[slot].dadx[i] = 0;
@@ -387,7 +391,7 @@ static void tri_linear_coeff( struct setup_stage *setup,
    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;
@@ -406,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",
@@ -422,6 +426,10 @@ 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,
                              unsigned slot,
@@ -438,14 +446,22 @@ static void tri_persp_coeff( struct setup_stage *setup,
    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)));
 }
 
 
@@ -455,7 +471,7 @@ static void tri_persp_coeff( struct setup_stage *setup,
  */
 static void setup_tri_coefficients( struct setup_stage *setup )
 {
-   const enum interp_mode *interp = setup->softpipe->interp;
+   const interp_mode *interp = setup->softpipe->vertex_info.interp_mode;
    unsigned slot, j;
 
    /* z and w are done by linear interpolation:
@@ -481,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);
       }
    }
 }
@@ -489,12 +509,12 @@ static void setup_tri_coefficients( struct setup_stage *setup )
 
 static void setup_tri_edges( struct setup_stage *setup )
 {
-   float vmin_x = setup->vmin->data[0][0] + 0.5;
-   float 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;
 
-   float vmin_y = setup->vmin->data[0][1] - 0.5;
-   float vmid_y = setup->vmid->data[0][1] - 0.5;
-   float 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 = (int) ceilf(vmax_y - setup->emaj.sy);
@@ -523,6 +543,10 @@ static void subtriangle( struct setup_stage *setup,
                         unsigned lines )
 {
    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;
 
@@ -532,11 +556,11 @@ static void subtriangle( struct setup_stage *setup,
    start_y = sy;
    finish_y = sy + lines;
 
-   if (start_y < cliprect->miny)
-      start_y = cliprect->miny;
+   if (start_y < miny)
+      start_y = miny;
 
-   if (finish_y > cliprect->maxy)
-      finish_y = cliprect->maxy;
+   if (finish_y > maxy)
+      finish_y = maxy;
 
    start_y -= sy;
    finish_y -= sy;
@@ -557,23 +581,22 @@ static void subtriangle( struct setup_stage *setup,
       int right = (int)(eright->sx + y * eright->dxdy);
 
       /* clip left/right */
-      if (left < cliprect->minx)
-         left = cliprect->minx;
-      if (right > cliprect->maxx)
-         right = cliprect->maxx;
+      if (left < minx)
+         left = minx;
+      if (right > maxx)
+         right = maxx;
 
       if (left < right) {
-        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);
+         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:
@@ -643,8 +666,8 @@ line_linear_coeff(struct setup_stage *setup, unsigned slot, unsigned i)
    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)));
 }
 
 
@@ -667,7 +690,7 @@ line_persp_coeff(struct setup_stage *setup, unsigned slot, unsigned i)
 static INLINE void
 setup_line_coefficients(struct setup_stage *setup, struct prim_header *prim)
 {
-   const enum interp_mode *interp = setup->softpipe->interp;
+   const interp_mode *interp = setup->softpipe->vertex_info.interp_mode;
    unsigned slot, j;
 
    /* use setup->vmin, vmax to point to vertices */
@@ -678,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:
     */
@@ -704,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);
       }
    }
 }
@@ -813,10 +840,10 @@ setup_line(struct draw_stage *stage, struct prim_header *prim)
       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);
          }
 
@@ -840,10 +867,10 @@ setup_line(struct draw_stage *stage, struct prim_header *prim)
       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);
          }
 
@@ -877,12 +904,14 @@ 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! */
-   const float halfSize = 0.5 * setup->softpipe->setup.point_size;
-   const boolean round = setup->softpipe->setup.point_smooth;
    const struct vertex_header *v0 = prim->v[0];
-   const float x = v0->data[FRAG_ATTRIB_WPOS][0];
-   const float y = v0->data[FRAG_ATTRIB_WPOS][1];
+   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.
@@ -915,8 +944,8 @@ setup_point(struct draw_stage *stage, struct prim_header *prim)
       /* special case for 1-pixel points */
       const int ix = ((int) x) & 1;
       const int iy = ((int) y) & 1;
-      setup->quad.x0 = x - ix;
-      setup->quad.y0 = y - iy;
+      setup->quad.x0 = (int) x - ix;
+      setup->quad.y0 = (int) y - iy;
       setup->quad.mask = (1 << ix) << (2 * iy);
       clip_emit_quad(setup);
    }
@@ -941,39 +970,39 @@ setup_point(struct draw_stage *stage, struct prim_header *prim)
 
                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;
                }
 
@@ -1067,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 );
+}