Mesa (softpipe-opt): softpipe: fix glitch in texel lookups on fastpaths

Keith Whitwell keithw at kemper.freedesktop.org
Thu Aug 20 18:55:50 UTC 2009


Module: Mesa
Branch: softpipe-opt
Commit: 79a7ddb57a04cde5a4a0c27eb4a9b6889d12622a
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=79a7ddb57a04cde5a4a0c27eb4a9b6889d12622a

Author: Keith Whitwell <keithw at vmware.com>
Date:   Thu Aug 20 15:46:51 2009 +0100

softpipe: fix glitch in texel lookups on fastpaths

Fixes two issues - firstly for mipmap levels with one or more
dimensions smaller than tilesize, the code was sampling off the edge
of the texture (but still within the tile).

Secondly, in the linear_mipmap_linear case, both the default code and
new fastpath were incorrect.  This change fixes the fastpath and adds
a comment to the default path, which still needs to be fixed.
Basically the issue is that the coordinates in the smaller texture
level are/were being computed by just dividing thecoordinates from the
larger texture level by two, as in:

               x0[j] /= 2;
               y0[j] /= 2;
               x1[j] /= 2;
               y1[j] /= 2;

The issues with this are signficant.  Initially x1 is most often equal
to x0+1, but after this, it will likely be equal to x0, so we will not
actually be performing the linear blend within the smaller mipmap.

The fastpath code avoided this (recalculated x1), but was still using
the weighting factors from the larger mipmap level (xw, yw), which
were incorrect.

Change the fastpath code to do two full, independent linear samples of
the two mipmap levels before blending.  The default code needs to do
the same thing.

---

 src/gallium/drivers/softpipe/sp_tex_sample.c |   87 +++++++-------------------
 1 files changed, 23 insertions(+), 64 deletions(-)

diff --git a/src/gallium/drivers/softpipe/sp_tex_sample.c b/src/gallium/drivers/softpipe/sp_tex_sample.c
index b32ac9d..24f3311 100644
--- a/src/gallium/drivers/softpipe/sp_tex_sample.c
+++ b/src/gallium/drivers/softpipe/sp_tex_sample.c
@@ -894,6 +894,9 @@ sp_get_samples_2d_linear_repeat_POT(struct tgsi_sampler *tgsi_sampler,
    unsigned xpot = 1 << (samp->xpot - level);
    unsigned ypot = 1 << (samp->ypot - level);
 
+   unsigned xmax = MIN2(TILE_SIZE, xpot) - 1;
+   unsigned ymax = MIN2(TILE_SIZE, ypot) - 1;
+      
    for (j = 0; j < QUAD_SIZE; j++) {
       int c;
 
@@ -914,8 +917,7 @@ sp_get_samples_2d_linear_repeat_POT(struct tgsi_sampler *tgsi_sampler,
 
       /* Can we fetch all four at once:
        */
-      if (x0 % TILE_SIZE != TILE_SIZE-1 &&
-          y0 % TILE_SIZE != TILE_SIZE-1)
+      if (x0 < xmax && y0 < ymax)
       {
          get_texel_quad_2d(tgsi_sampler, 0, level, x0, y0, tx);
       }
@@ -1045,72 +1047,22 @@ sp_get_samples_2d_linear_mip_linear_repeat_POT(struct tgsi_sampler *tgsi_sampler
                                            s, t, p, 0, rgba );
    }
    else {
-      float levelBlend = lambda - level0;  /* blending weight between levels */
-      unsigned xpot = 1 << (samp->xpot - level0);
-      unsigned ypot = 1 << (samp->ypot - level0);
-      unsigned xpot1 = 1 << (samp->xpot - (level0+1));
-      unsigned ypot1 = 1 << (samp->ypot - (level0+1));
-      unsigned j;
-
-      for (j = 0; j < QUAD_SIZE; j++) {
-         int c;
-         
-         float u = s[j] * xpot - 0.5F;
-         float v = t[j] * ypot - 0.5F;
-
-         int uflr = util_ifloor(u);
-         int vflr = util_ifloor(v);
-
-         float xw = u - (float)uflr;
-         float yw = v - (float)vflr;
-
-         int x0 = uflr & (xpot - 1);
-         int y0 = vflr & (ypot - 1);
-
-         const float *tx0[4];
-         const float *tx1[4];
-      
-         if (x0 % TILE_SIZE != TILE_SIZE-1 &&
-             y0 % TILE_SIZE != TILE_SIZE-1)
-         {
-            get_texel_quad_2d(tgsi_sampler, 0, level0, x0, y0, tx0);
-         }
-         else 
-         {
-            unsigned x1 = (x0 + 1) & (xpot - 1);
-            unsigned y1 = (y0 + 1) & (ypot - 1);
-            get_texel_quad_2d_mt(tgsi_sampler, 0, level0, 
-                                 x0, y0, x1, y1, tx0);
-         }
+      float levelBlend = lambda - level0;
+      float rgba0[4][4];
+      float rgba1[4][4];
+      int c,j;
 
-         x0 /= 2;
-         y0 /= 2;
-         /* also need to adjust xw, yw?? */
+      samp->level = level0;
+      sp_get_samples_2d_linear_repeat_POT( tgsi_sampler,
+                                           s, t, p, 0, rgba0 );
 
-         if (x0 % TILE_SIZE != TILE_SIZE-1 &&
-             y0 % TILE_SIZE != TILE_SIZE-1)
-         {
-            get_texel_quad_2d(tgsi_sampler, 0, level0+1, x0, y0, tx1);
-         }
-         else 
-         {
-            unsigned x1 = (x0 + 1) & (xpot1 - 1);
-            unsigned y1 = (y0 + 1) & (ypot1 - 1);
-            get_texel_quad_2d_mt(tgsi_sampler, 0, level0+1, 
-                                 x0, y0, x1, y1, tx1);
-         }
+      samp->level = level0+1;
+      sp_get_samples_2d_linear_repeat_POT( tgsi_sampler,
+                                           s, t, p, 0, rgba1 );
 
-         /* interpolate R, G, B, A */
+      for (j = 0; j < QUAD_SIZE; j++) {
          for (c = 0; c < 4; c++) {
-            float rgba0 = lerp_2d(xw, yw, 
-                                  tx0[0][c], tx0[1][c], 
-                                  tx0[2][c], tx0[3][c]);
-
-            float rgba1 = lerp_2d(xw, yw, 
-                                  tx1[0][c], tx1[1][c], 
-                                  tx1[2][c], tx1[3][c]);
-
-            rgba[c][j] = lerp(levelBlend, rgba0, rgba1);
+            rgba[c][j] = lerp(levelBlend, rgba0[c][j], rgba1[c][j]);
          }
       }
    }
@@ -1209,6 +1161,13 @@ sp_get_samples_2d_common(const struct tgsi_sampler *tgsi_sampler,
             if (level0 != level1) {
                /* get texels from second mipmap level and blend */
                float rgba2[4][4];
+
+               /* XXX: This is incorrect -- will often end up with (x0
+                *  == x1 && y0 == y1), meaning that we fetch the same
+                *  texel four times and linearly interpolate between
+                *  identical values.  The correct approach would be to
+                *  call linear_texcoord again for the second level.
+                */
                x0[j] /= 2;
                y0[j] /= 2;
                x1[j] /= 2;




More information about the mesa-commit mailing list