r300g: fix texturing with negative lod bias
[mesa.git] / src / gallium / drivers / llvmpipe / lp_setup_tri.c
index 15534756c4a80818f346030ef536736204e28427..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,93 +212,180 @@ static void setup_tri_coefficients( struct setup_context *setup,
                                    const float (*v3)[4],
                                    boolean frontface)
 {
-   struct lp_scene *scene = lp_setup_get_current_scene(setup);
+   unsigned fragcoord_usage_mask = TGSI_WRITEMASK_XYZ;
    unsigned slot;
 
-   /* Allocate space for the a0, dadx and dady arrays
-    */
-   {
-      unsigned bytes = (setup->fs.nr_inputs + 1) * 4 * sizeof(float);
-      tri->inputs.a0   = lp_scene_alloc_aligned( scene, bytes, 16 );
-      tri->inputs.dadx = lp_scene_alloc_aligned( scene, bytes, 16 );
-      tri->inputs.dady = lp_scene_alloc_aligned( scene, bytes, 16 );
-   }
-
-   /* 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);
 }
 
 
 
-static inline int subpixel_snap( float a )
+static INLINE int subpixel_snap( float a )
 {
    return util_iround(FIXED_ONE * a - (FIXED_ONE / 2));
 }
 
 
+
+/**
+ * Alloc space for a new triangle plus the input.a0/dadx/dady arrays
+ * immediately after it.
+ * The memory is allocated from the per-scene pool, not per-tile.
+ * \param tri_size  returns number of bytes allocated
+ * \param nr_inputs  number of fragment shader inputs
+ * \return pointer to triangle space
+ */
+static INLINE struct lp_rast_triangle *
+alloc_triangle(struct lp_scene *scene, unsigned nr_inputs, unsigned *tri_size)
+{
+   unsigned input_array_sz = NUM_CHANNELS * (nr_inputs + 1) * sizeof(float);
+   struct lp_rast_triangle *tri;
+   unsigned bytes;
+   char *inputs;
+
+   assert(sizeof(*tri) % 16 == 0);
+
+   bytes = sizeof(*tri) + (3 * input_array_sz);
+
+   tri = lp_scene_alloc_aligned( scene, bytes, 16 );
+
+   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;
+   }
+
+   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
  * framebuffer tiles are touched.  Put the triangle in the scene's
  * 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 = lp_scene_alloc_aligned( scene, sizeof *tri, 16 );
+   struct lp_rast_triangle *tri;
    int area;
    float oneoverarea;
    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;
@@ -286,7 +404,7 @@ do_triangle_ccw(struct setup_context *setup,
     * XXX: subject to overflow??
     */
    if (area <= 0) {
-      lp_scene_putback_data( scene, sizeof *tri );
+      lp_scene_putback_data( scene, tri_bytes );
       LP_COUNT(nr_culled_tris);
       return;
    }
@@ -306,7 +424,7 @@ do_triangle_ccw(struct setup_context *setup,
 
    if (miny == maxy || 
        minx == maxx) {
-      lp_scene_putback_data( scene, sizeof *tri );
+      lp_scene_putback_data( scene, tri_bytes );
       LP_COUNT(nr_culled_tris);
       return;
    }
@@ -319,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;
@@ -414,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);
 
@@ -488,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,
@@ -525,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] )
@@ -534,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] )
@@ -543,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] )
@@ -562,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] )
@@ -571,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;