r300g: fix texturing with negative lod bias
[mesa.git] / src / gallium / drivers / llvmpipe / lp_setup_tri.c
index 9e59a6602cc698a87e92d7f011a0c5fbaa1c0a43..4e2e17f77b1eb03b4a4a43c444f07fc8badb46bb 100644 (file)
@@ -34,6 +34,7 @@
 #include "lp_perf.h"
 #include "lp_setup_context.h"
 #include "lp_rast.h"
+#include "lp_state_fs.h"
 
 #define NUM_CHANNELS 4
 
@@ -41,7 +42,8 @@
 /**
  * Compute a0 for a constant-valued coefficient (GL_FLAT shading).
  */
-static void constant_coef( struct lp_rast_triangle *tri,
+static void constant_coef( struct lp_setup_context *setup,
+                           struct lp_rast_triangle *tri,
                            unsigned slot,
                           const float value,
                            unsigned i )
@@ -56,7 +58,8 @@ static void constant_coef( struct lp_rast_triangle *tri,
  * Compute a0, dadx and dady for a linearly interpolated coefficient,
  * for a triangle.
  */
-static void linear_coef( struct lp_rast_triangle *tri,
+static void linear_coef( struct lp_setup_context *setup,
+                         struct lp_rast_triangle *tri,
                          float oneoverarea,
                          unsigned slot,
                          const float (*v1)[4],
@@ -90,8 +93,8 @@ static void linear_coef( struct lp_rast_triangle *tri,
     * instead - i'll switch to this later.
     */
    tri->inputs.a0[slot][i] = (a1 -
-                              (dadx * (v1[0][0] - 0.5f) +
-                               dady * (v1[0][1] - 0.5f)));
+                              (dadx * (v1[0][0] - setup->pixel_offset) +
+                               dady * (v1[0][1] - setup->pixel_offset)));
 }
 
 
@@ -103,7 +106,8 @@ static void linear_coef( struct lp_rast_triangle *tri,
  * 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 perspective_coef( struct lp_rast_triangle *tri,
+static void perspective_coef( struct lp_setup_context *setup,
+                              struct lp_rast_triangle *tri,
                               float oneoverarea,
                               unsigned slot,
                              const float (*v1)[4],
@@ -125,8 +129,8 @@ static void perspective_coef( struct lp_rast_triangle *tri,
    tri->inputs.dadx[slot][i] = dadx;
    tri->inputs.dady[slot][i] = dady;
    tri->inputs.a0[slot][i] = (a1 -
-                              (dadx * (v1[0][0] - 0.5f) +
-                               dady * (v1[0][1] - 0.5f)));
+                              (dadx * (v1[0][0] - setup->pixel_offset) +
+                               dady * (v1[0][1] - setup->pixel_offset)));
 }
 
 
@@ -137,43 +141,70 @@ static void perspective_coef( struct lp_rast_triangle *tri,
  * We could do a bit less work if we'd examine gl_FragCoord's swizzle mask.
  */
 static void
-setup_fragcoord_coef(struct lp_rast_triangle *tri,
+setup_fragcoord_coef(struct lp_setup_context *setup,
+                     struct lp_rast_triangle *tri,
                      float oneoverarea,
                      unsigned slot,
                      const float (*v1)[4],
                      const float (*v2)[4],
-                     const float (*v3)[4])
+                     const float (*v3)[4],
+                     unsigned usage_mask)
 {
    /*X*/
-   tri->inputs.a0[slot][0] = 0.0;
-   tri->inputs.dadx[slot][0] = 1.0;
-   tri->inputs.dady[slot][0] = 0.0;
+   if (usage_mask & TGSI_WRITEMASK_X) {
+      tri->inputs.a0[slot][0] = 0.0;
+      tri->inputs.dadx[slot][0] = 1.0;
+      tri->inputs.dady[slot][0] = 0.0;
+   }
+
    /*Y*/
-   tri->inputs.a0[slot][1] = 0.0;
-   tri->inputs.dadx[slot][1] = 0.0;
-   tri->inputs.dady[slot][1] = 1.0;
+   if (usage_mask & TGSI_WRITEMASK_Y) {
+      tri->inputs.a0[slot][1] = 0.0;
+      tri->inputs.dadx[slot][1] = 0.0;
+      tri->inputs.dady[slot][1] = 1.0;
+   }
+
    /*Z*/
-   linear_coef(tri, oneoverarea, slot, v1, v2, v3, 0, 2);
+   if (usage_mask & TGSI_WRITEMASK_Z) {
+      linear_coef(setup, tri, oneoverarea, slot, v1, v2, v3, 0, 2);
+   }
+
    /*W*/
-   linear_coef(tri, oneoverarea, slot, v1, v2, v3, 0, 3);
+   if (usage_mask & TGSI_WRITEMASK_W) {
+      linear_coef(setup, tri, oneoverarea, slot, v1, v2, v3, 0, 3);
+   }
 }
 
 
-static void setup_facing_coef( struct lp_rast_triangle *tri,
+/**
+ * Setup the fragment input attribute with the front-facing value.
+ * \param frontface  is the triangle front facing?
+ */
+static void setup_facing_coef( struct lp_setup_context *setup,
+                               struct lp_rast_triangle *tri,
                                unsigned slot,
-                               boolean frontface )
+                               boolean frontface,
+                               unsigned usage_mask)
 {
-   constant_coef( tri, slot, 1.0f - frontface, 0 );
-   constant_coef( tri, slot, 0.0f, 1 ); /* wasted */
-   constant_coef( tri, slot, 0.0f, 2 ); /* wasted */
-   constant_coef( tri, slot, 0.0f, 3 ); /* wasted */
+   /* convert TRUE to 1.0 and FALSE to -1.0 */
+   if (usage_mask & TGSI_WRITEMASK_X)
+      constant_coef( setup, tri, slot, 2.0f * frontface - 1.0f, 0 );
+
+   if (usage_mask & TGSI_WRITEMASK_Y)
+      constant_coef( setup, tri, slot, 0.0f, 1 ); /* wasted */
+
+   if (usage_mask & TGSI_WRITEMASK_Z)
+      constant_coef( setup, tri, slot, 0.0f, 2 ); /* wasted */
+
+   if (usage_mask & TGSI_WRITEMASK_W)
+      constant_coef( setup, tri, slot, 0.0f, 3 ); /* wasted */
 }
 
 
 /**
  * Compute the tri->coef[] array dadx, dady, a0 values.
  */
-static void setup_tri_coefficients( struct setup_context *setup,
+static void setup_tri_coefficients( struct lp_setup_context *setup,
                                    struct lp_rast_triangle *tri,
                                     float oneoverarea,
                                    const float (*v1)[4],
@@ -181,48 +212,65 @@ static void setup_tri_coefficients( struct setup_context *setup,
                                    const float (*v3)[4],
                                    boolean frontface)
 {
+   unsigned fragcoord_usage_mask = TGSI_WRITEMASK_XYZ;
    unsigned slot;
 
-   /* The internal position input is in slot zero:
-    */
-   setup_fragcoord_coef(tri, oneoverarea, 0, v1, v2, v3);
-
    /* setup interpolation for all the remaining attributes:
     */
    for (slot = 0; slot < setup->fs.nr_inputs; slot++) {
       unsigned vert_attr = setup->fs.input[slot].src_index;
+      unsigned usage_mask = setup->fs.input[slot].usage_mask;
       unsigned i;
 
       switch (setup->fs.input[slot].interp) {
       case LP_INTERP_CONSTANT:
-         for (i = 0; i < NUM_CHANNELS; i++)
-            constant_coef(tri, slot+1, v3[vert_attr][i], i);
+         if (setup->flatshade_first) {
+            for (i = 0; i < NUM_CHANNELS; i++)
+               if (usage_mask & (1 << i))
+                  constant_coef(setup, tri, slot+1, v1[vert_attr][i], i);
+         }
+         else {
+            for (i = 0; i < NUM_CHANNELS; i++)
+               if (usage_mask & (1 << i))
+                  constant_coef(setup, tri, slot+1, v3[vert_attr][i], i);
+         }
          break;
 
       case LP_INTERP_LINEAR:
          for (i = 0; i < NUM_CHANNELS; i++)
-            linear_coef(tri, oneoverarea, slot+1, v1, v2, v3, vert_attr, i);
+            if (usage_mask & (1 << i))
+               linear_coef(setup, tri, oneoverarea, slot+1, v1, v2, v3, vert_attr, i);
          break;
 
       case LP_INTERP_PERSPECTIVE:
          for (i = 0; i < NUM_CHANNELS; i++)
-            perspective_coef(tri, oneoverarea, slot+1, v1, v2, v3, vert_attr, i);
+            if (usage_mask & (1 << i))
+               perspective_coef(setup, tri, oneoverarea, slot+1, v1, v2, v3, vert_attr, i);
+         fragcoord_usage_mask |= TGSI_WRITEMASK_W;
          break;
 
       case LP_INTERP_POSITION:
-         /* XXX: fix me - duplicates the values in slot zero.
+         /*
+          * The generated pixel interpolators will pick up the coeffs from
+          * slot 0, so all need to ensure that the usage mask is covers all
+          * usages.
           */
-         setup_fragcoord_coef(tri, oneoverarea, slot+1, v1, v2, v3);
+         fragcoord_usage_mask |= usage_mask;
          break;
 
       case LP_INTERP_FACING:
-         setup_facing_coef(tri, slot+1, frontface);
+         setup_facing_coef(setup, tri, slot+1, frontface, usage_mask);
          break;
 
       default:
          assert(0);
       }
    }
+
+   /* The internal position input is in slot zero:
+    */
+   setup_fragcoord_coef(setup, tri, oneoverarea, 0, v1, v2, v3,
+                        fragcoord_usage_mask);
 }
 
 
@@ -256,17 +304,45 @@ alloc_triangle(struct lp_scene *scene, unsigned nr_inputs, unsigned *tri_size)
 
    tri = lp_scene_alloc_aligned( scene, bytes, 16 );
 
-   inputs = (char *) (tri + 1);
-   tri->inputs.a0   = (float (*)[4]) inputs;
-   tri->inputs.dadx = (float (*)[4]) (inputs + input_array_sz);
-   tri->inputs.dady = (float (*)[4]) (inputs + 2 * input_array_sz);
+   if (tri) {
+      inputs = (char *) (tri + 1);
+      tri->inputs.a0   = (float (*)[4]) inputs;
+      tri->inputs.dadx = (float (*)[4]) (inputs + input_array_sz);
+      tri->inputs.dady = (float (*)[4]) (inputs + 2 * input_array_sz);
 
-   *tri_size = bytes;
+      *tri_size = bytes;
+   }
 
    return tri;
 }
 
 
+/**
+ * Print triangle vertex attribs (for debug).
+ */
+static void
+print_triangle(struct lp_setup_context *setup,
+               const float (*v1)[4],
+               const float (*v2)[4],
+               const float (*v3)[4])
+{
+   uint i;
+
+   debug_printf("llvmpipe triangle\n");
+   for (i = 0; i < setup->fs.nr_inputs; i++) {
+      debug_printf("  v1[%d]:  %f %f %f %f\n", i,
+                   v1[i][0], v1[i][1], v1[i][2], v1[i][3]);
+   }
+   for (i = 0; i < setup->fs.nr_inputs; i++) {
+      debug_printf("  v2[%d]:  %f %f %f %f\n", i,
+                   v2[i][0], v2[i][1], v2[i][2], v2[i][3]);
+   }
+   for (i = 0; i < setup->fs.nr_inputs; i++) {
+      debug_printf("  v3[%d]:  %f %f %f %f\n", i,
+                   v3[i][0], v3[i][1], v3[i][2], v3[i][3]);
+   }
+}
+
 
 /**
  * Do basic setup for triangle rasterization and determine which
@@ -274,19 +350,19 @@ alloc_triangle(struct lp_scene *scene, unsigned nr_inputs, unsigned *tri_size)
  * bins for the tiles which we overlap.
  */
 static void 
-do_triangle_ccw(struct setup_context *setup,
+do_triangle_ccw(struct lp_setup_context *setup,
                const float (*v1)[4],
                const float (*v2)[4],
                const float (*v3)[4],
                boolean frontfacing )
 {
    /* x/y positions in fixed point */
-   const int x1 = subpixel_snap(v1[0][0]);
-   const int x2 = subpixel_snap(v2[0][0]);
-   const int x3 = subpixel_snap(v3[0][0]);
-   const int y1 = subpixel_snap(v1[0][1]);
-   const int y2 = subpixel_snap(v2[0][1]);
-   const int y3 = subpixel_snap(v3[0][1]);
+   const int x1 = subpixel_snap(v1[0][0] + 0.5 - setup->pixel_offset);
+   const int x2 = subpixel_snap(v2[0][0] + 0.5 - setup->pixel_offset);
+   const int x3 = subpixel_snap(v3[0][0] + 0.5 - setup->pixel_offset);
+   const int y1 = subpixel_snap(v1[0][1] + 0.5 - setup->pixel_offset);
+   const int y2 = subpixel_snap(v2[0][1] + 0.5 - setup->pixel_offset);
+   const int y3 = subpixel_snap(v3[0][1] + 0.5 - setup->pixel_offset);
 
    struct lp_scene *scene = lp_setup_get_current_scene(setup);
    struct lp_rast_triangle *tri;
@@ -295,7 +371,21 @@ do_triangle_ccw(struct setup_context *setup,
    int minx, maxx, miny, maxy;
    unsigned tri_bytes;
 
+   if (0)
+      print_triangle(setup, v1, v2, v3);
+
    tri = alloc_triangle(scene, setup->fs.nr_inputs, &tri_bytes);
+   if (!tri)
+      return;
+
+#ifdef DEBUG
+   tri->v[0][0] = v1[0][0];
+   tri->v[1][0] = v2[0][0];
+   tri->v[2][0] = v3[0][0];
+   tri->v[0][1] = v1[0][1];
+   tri->v[1][1] = v2[0][1];
+   tri->v[2][1] = v3[0][1];
+#endif
 
    tri->dx12 = x1 - x2;
    tri->dx23 = x2 - x3;
@@ -347,6 +437,8 @@ do_triangle_ccw(struct setup_context *setup,
     */
    setup_tri_coefficients( setup, tri, oneoverarea, v1, v2, v3, frontfacing );
 
+   tri->inputs.facing = frontfacing ? 1.0F : -1.0F;
+
    /* half-edge constants, will be interated over the whole render target.
     */
    tri->c1 = tri->dy12 * x1 - tri->dx12 * y1;
@@ -442,8 +534,11 @@ do_triangle_ccw(struct setup_context *setup,
    maxx = maxx / TILE_SIZE;
    maxy = maxy / TILE_SIZE;
 
-   /* Clamp maxx, maxy to framebuffer size
+   /*
+    * Clamp to framebuffer size
     */
+   minx = MAX2(minx, 0);
+   miny = MAX2(miny, 0);
    maxx = MIN2(maxx, scene->tiles_x - 1);
    maxy = MIN2(maxy, scene->tiles_y - 1);
 
@@ -516,7 +611,8 @@ do_triangle_ccw(struct setup_context *setup,
                /* triangle covers the whole tile- shade whole tile */
                LP_COUNT(nr_fully_covered_64);
               in = TRUE;
-              if(setup->fs.current.opaque) {
+              if (setup->fs.current.variant->opaque &&
+                  !setup->fb.zsbuf) {
                  lp_scene_bin_reset( scene, x, y );
                  lp_scene_bin_command( scene, x, y,
                                        lp_rast_set_state,
@@ -553,7 +649,10 @@ do_triangle_ccw(struct setup_context *setup,
 }
 
 
-static void triangle_cw( struct setup_context *setup,
+/**
+ * Draw triangle if it's CW, cull otherwise.
+ */
+static void triangle_cw( struct lp_setup_context *setup,
                         const float (*v0)[4],
                         const float (*v1)[4],
                         const float (*v2)[4] )
@@ -562,7 +661,10 @@ static void triangle_cw( struct setup_context *setup,
 }
 
 
-static void triangle_ccw( struct setup_context *setup,
+/**
+ * Draw triangle if it's CCW, cull otherwise.
+ */
+static void triangle_ccw( struct lp_setup_context *setup,
                         const float (*v0)[4],
                         const float (*v1)[4],
                         const float (*v2)[4] )
@@ -571,7 +673,11 @@ static void triangle_ccw( struct setup_context *setup,
 }
 
 
-static void triangle_both( struct setup_context *setup,
+
+/**
+ * Draw triangle whether it's CW or CCW.
+ */
+static void triangle_both( struct lp_setup_context *setup,
                           const float (*v0)[4],
                           const float (*v1)[4],
                           const float (*v2)[4] )
@@ -590,7 +696,7 @@ static void triangle_both( struct setup_context *setup,
 }
 
 
-static void triangle_nop( struct setup_context *setup,
+static void triangle_nop( struct lp_setup_context *setup,
                          const float (*v0)[4],
                          const float (*v1)[4],
                          const float (*v2)[4] )
@@ -599,17 +705,17 @@ static void triangle_nop( struct setup_context *setup,
 
 
 void 
-lp_setup_choose_triangle( struct setup_context *setup )
+lp_setup_choose_triangle( struct lp_setup_context *setup )
 {
    switch (setup->cullmode) {
-   case PIPE_WINDING_NONE:
+   case PIPE_FACE_NONE:
       setup->triangle = triangle_both;
       break;
-   case PIPE_WINDING_CCW:
-      setup->triangle = triangle_cw;
+   case PIPE_FACE_BACK:
+      setup->triangle = setup->ccw_is_frontface ? triangle_ccw : triangle_cw;
       break;
-   case PIPE_WINDING_CW:
-      setup->triangle = triangle_ccw;
+   case PIPE_FACE_FRONT:
+      setup->triangle = setup->ccw_is_frontface ? triangle_cw : triangle_ccw;
       break;
    default:
       setup->triangle = triangle_nop;