Mesa (master): softpipe: fix broken cubemap / mipmap selection code

Brian Paul brianp at kemper.freedesktop.org
Sun Feb 14 00:48:48 UTC 2010


Module: Mesa
Branch: master
Commit: 85425b3b609c480cd024b217b1efd0b9153bed58
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=85425b3b609c480cd024b217b1efd0b9153bed58

Author: Brian Paul <brianp at vmware.com>
Date:   Sat Feb 13 17:47:23 2010 -0700

softpipe: fix broken cubemap / mipmap selection code

This is a quick-fix for the time being...

The per-face mipmap LOD computation was invalid at cube edges.  In
mip_filter_nearest/linear() we were trying to compute LOD using
texcoords that were sometimes indexes into different cube faces.
The subtraction used to compute the partial derivatives basically
gave random values, so the LOD was unpredictable.  This fix simply
uses the same cube face for all four pixels in the quad.  The per-
face texcoords all reference the same cube face so the partial
deriviates are computed properly.

A more elaborate fix would involve computing the LOD at the same
time as we choose the cube faces.  But for now, this solution works
well and allows the piglit/cubemap test to pass.

(cherry picked from commit 1ff9cd5079b095d7050edb8dc6a7e5b8cad36e1e)

---

 src/gallium/drivers/softpipe/sp_tex_sample.c |   99 ++++++++++++++++++-------
 1 files changed, 71 insertions(+), 28 deletions(-)

diff --git a/src/gallium/drivers/softpipe/sp_tex_sample.c b/src/gallium/drivers/softpipe/sp_tex_sample.c
index 473ec3e..824d8d1 100644
--- a/src/gallium/drivers/softpipe/sp_tex_sample.c
+++ b/src/gallium/drivers/softpipe/sp_tex_sample.c
@@ -1327,6 +1327,11 @@ mip_filter_linear(struct tgsi_sampler *tgsi_sampler,
 }
 
 
+/**
+ * Compute nearest mipmap level from texcoords.
+ * Then sample the texture level for four elements of a quad.
+ * \param c0  the LOD bias factors, or absolute LODs (depending on control)
+ */
 static void
 mip_filter_nearest(struct tgsi_sampler *tgsi_sampler,
                    const float s[QUAD_SIZE],
@@ -1563,8 +1568,8 @@ sample_compare(struct tgsi_sampler *tgsi_sampler,
 
 
 /**
- * Compute which cube face is referenced by each texcoord and put that
- * info into the sampler faces[] array.  Then sample the cube faces
+ * Use 3D texcoords to choose a cube face, then sample the 2D cube faces.
+ * Put face info into the sampler faces[] array.
  */
 static void
 sample_cube(struct tgsi_sampler *tgsi_sampler,
@@ -1578,11 +1583,12 @@ sample_cube(struct tgsi_sampler *tgsi_sampler,
    struct sp_sampler_varient *samp = sp_sampler_varient(tgsi_sampler);
    unsigned j;
    float ssss[4], tttt[4];
+   unsigned face;
 
    /*
      major axis
-     direction     target                             sc     tc    ma
-     ----------    -------------------------------    ---    ---   ---
+     direction    target                             sc     tc    ma
+     ----------   -------------------------------    ---    ---   ---
      +rx          TEXTURE_CUBE_MAP_POSITIVE_X_EXT    -rz    -ry   rx
      -rx          TEXTURE_CUBE_MAP_NEGATIVE_X_EXT    +rz    -ry   rx
      +ry          TEXTURE_CUBE_MAP_POSITIVE_Y_EXT    +rx    +rz   ry
@@ -1590,56 +1596,93 @@ sample_cube(struct tgsi_sampler *tgsi_sampler,
      +rz          TEXTURE_CUBE_MAP_POSITIVE_Z_EXT    +rx    -ry   rz
      -rz          TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT    -rx    -ry   rz
    */
-   for (j = 0; j < QUAD_SIZE; j++) {
-      float rx = s[j];
-      float ry = t[j];
-      float rz = p[j];
+
+   /* First choose the cube face.
+    * Use the same cube face for all four pixels in the quad.
+    *
+    * This isn't ideal, but if we want to use a different cube face
+    * per pixel in the quad, we'd have to also compute the per-face
+    * LOD here too.  That's because the four post-face-selection
+    * texcoords are no longer related to each other (they're
+    * per-face!)  so we can't use subtraction to compute the partial
+    * deriviates to compute the LOD.  Doing so (near cube edges
+    * anyway) gives us pretty much random values.
+    */
+   {
+      /* use the average of the four pixel's texcoords to choose the face */
+      const float rx = 0.25 * (s[0] + s[1] + s[2] + s[3]);
+      const float ry = 0.25 * (t[0] + t[1] + t[2] + t[3]);
+      const float rz = 0.25 * (p[0] + p[1] + p[2] + p[3]);
       const float arx = fabsf(rx), ary = fabsf(ry), arz = fabsf(rz);
-      unsigned face;
-      float sc, tc, ma;
 
       if (arx >= ary && arx >= arz) {
          if (rx >= 0.0F) {
             face = PIPE_TEX_FACE_POS_X;
-            sc = -rz;
-            tc = -ry;
-            ma = arx;
          }
          else {
             face = PIPE_TEX_FACE_NEG_X;
-            sc = rz;
-            tc = -ry;
-            ma = arx;
          }
       }
       else if (ary >= arx && ary >= arz) {
          if (ry >= 0.0F) {
             face = PIPE_TEX_FACE_POS_Y;
-            sc = rx;
-            tc = rz;
-            ma = ary;
          }
          else {
             face = PIPE_TEX_FACE_NEG_Y;
-            sc = rx;
-            tc = -rz;
-            ma = ary;
          }
       }
       else {
          if (rz > 0.0F) {
             face = PIPE_TEX_FACE_POS_Z;
-            sc = rx;
-            tc = -ry;
-            ma = arz;
          }
          else {
             face = PIPE_TEX_FACE_NEG_Z;
-            sc = -rx;
-            tc = -ry;
-            ma = arz;
          }
       }
+   }
+
+   /* Now compute the 2D _face_ texture coords from the
+    * 3D _cube_ texture coords.
+    */
+   for (j = 0; j < QUAD_SIZE; j++) {
+      const float rx = s[j], ry = t[j], rz = p[j];
+      const float arx = fabsf(rx), ary = fabsf(ry), arz = fabsf(rz);
+      float sc, tc, ma;
+
+      switch (face) {
+      case PIPE_TEX_FACE_POS_X:
+         sc = -rz;
+         tc = -ry;
+         ma = arx;
+         break;
+      case PIPE_TEX_FACE_NEG_X:
+         sc = rz;
+         tc = -ry;
+         ma = arx;
+         break;
+      case PIPE_TEX_FACE_POS_Y:
+         sc = rx;
+         tc = rz;
+         ma = ary;
+         break;
+      case PIPE_TEX_FACE_NEG_Y:
+         sc = rx;
+         tc = -rz;
+         ma = ary;
+         break;
+      case PIPE_TEX_FACE_POS_Z:
+         sc = rx;
+         tc = -ry;
+         ma = arz;
+         break;
+      case PIPE_TEX_FACE_NEG_Z:
+         sc = -rx;
+         tc = -ry;
+         ma = arz;
+         break;
+      default:
+         assert(0 && "bad cube face");
+      }
 
       {
 	 const float ima = 1.0 / ma;




More information about the mesa-commit mailing list