Mesa (master): softpipe: implement seamless cubemap support. (v1.1)

Dave Airlie airlied at kemper.freedesktop.org
Wed Dec 12 03:11:40 UTC 2012


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

Author: Dave Airlie <airlied at gmail.com>
Date:   Tue Dec 11 19:52:48 2012 +1000

softpipe: implement seamless cubemap support. (v1.1)

This adds seamless sampling for cubemap boundaries if requested.

The corner case averaging is messy but seems like it should be spec
compliant.

The face direction stuff is also a bit messy, I've no idea if that could
or should be simpler, or even if all my directions are fully correct!

v1.1: update comments, drop unneeded seamless calls for nearest, fix
if statement layout.

Reviewed-by: Roland Scheidegger <sroland at vmware.com>
Reviewed-by: Brian Paul <brianp at vmware.com>
Signed-off-by: Dave Airlie <airlied at redhat.com>

---

 src/gallium/drivers/softpipe/sp_screen.c     |    2 +-
 src/gallium/drivers/softpipe/sp_tex_sample.c |  146 ++++++++++++++++++++++++--
 2 files changed, 139 insertions(+), 9 deletions(-)

diff --git a/src/gallium/drivers/softpipe/sp_screen.c b/src/gallium/drivers/softpipe/sp_screen.c
index f344814..564da5e 100644
--- a/src/gallium/drivers/softpipe/sp_screen.c
+++ b/src/gallium/drivers/softpipe/sp_screen.c
@@ -127,7 +127,7 @@ softpipe_get_param(struct pipe_screen *screen, enum pipe_cap param)
       return 1;
    case PIPE_CAP_SEAMLESS_CUBE_MAP:
    case PIPE_CAP_SEAMLESS_CUBE_MAP_PER_TEXTURE:
-      return 0;
+      return 1;
    case PIPE_CAP_SCALED_RESOLVE:
       return 0;
    case PIPE_CAP_MAX_TEXTURE_ARRAY_LAYERS:
diff --git a/src/gallium/drivers/softpipe/sp_tex_sample.c b/src/gallium/drivers/softpipe/sp_tex_sample.c
index 7558ef1..c0eaf45 100644
--- a/src/gallium/drivers/softpipe/sp_tex_sample.c
+++ b/src/gallium/drivers/softpipe/sp_tex_sample.c
@@ -607,6 +607,109 @@ get_texel_2d(const struct sp_sampler_variant *samp,
    }
 }
 
+/*
+ * seamless cubemap neighbour array.
+ * this array is used to find the adjacent face in each of 4 directions,
+ * left, right, up, down. (or -x, +x, -y, +y).
+ */
+static const unsigned face_array[PIPE_TEX_FACE_MAX][4] = {
+   /* pos X first then neg X is Z different, Y the same */
+   /* PIPE_TEX_FACE_POS_X,*/
+   { PIPE_TEX_FACE_POS_Z, PIPE_TEX_FACE_NEG_Z,
+     PIPE_TEX_FACE_NEG_Y, PIPE_TEX_FACE_POS_Y },
+   /* PIPE_TEX_FACE_NEG_X */
+   { PIPE_TEX_FACE_NEG_Z, PIPE_TEX_FACE_POS_Z,
+     PIPE_TEX_FACE_NEG_Y, PIPE_TEX_FACE_POS_Y },
+
+   /* pos Y first then neg Y is X different, X the same */
+   /* PIPE_TEX_FACE_POS_Y */
+   { PIPE_TEX_FACE_NEG_X, PIPE_TEX_FACE_POS_X,
+     PIPE_TEX_FACE_POS_Z, PIPE_TEX_FACE_NEG_Z },
+
+   /* PIPE_TEX_FACE_NEG_Y */
+   { PIPE_TEX_FACE_NEG_X, PIPE_TEX_FACE_POS_X,
+     PIPE_TEX_FACE_NEG_Z, PIPE_TEX_FACE_POS_Z },
+
+   /* pos Z first then neg Y is X different, X the same */
+   /* PIPE_TEX_FACE_POS_Z */
+   { PIPE_TEX_FACE_NEG_X, PIPE_TEX_FACE_POS_X,
+     PIPE_TEX_FACE_NEG_Y, PIPE_TEX_FACE_POS_Y },
+
+   /* PIPE_TEX_FACE_NEG_Z */
+   { PIPE_TEX_FACE_POS_X, PIPE_TEX_FACE_NEG_X,
+     PIPE_TEX_FACE_NEG_Y, PIPE_TEX_FACE_POS_Y }
+};
+
+static INLINE unsigned
+get_next_face(unsigned face, int x, int y)
+{
+   int idx = 0;
+
+   if (x == 0 && y == 0)
+      return face;
+   if (x == -1)
+      idx = 0;
+   else if (x == 1)
+      idx = 1;
+   else if (y == -1)
+      idx = 2;
+   else if (y == 1)
+      idx = 3;
+
+   return face_array[face][idx];
+}
+
+static INLINE const float *
+get_texel_cube_seamless(const struct sp_sampler_variant *samp,
+                        union tex_tile_address addr, int x, int y,
+                        float *corner)
+{
+   const struct pipe_resource *texture = samp->view->texture;
+   unsigned level = addr.bits.level;
+   unsigned face = addr.bits.face;
+   int new_x, new_y;
+   int max_x, max_y;
+   int c;
+
+   max_x = (int) u_minify(texture->width0, level);
+   max_y = (int) u_minify(texture->height0, level);
+   new_x = x;
+   new_y = y;
+
+   /* the corner case */
+   if ((x < 0 || x >= max_x) &&
+       (y < 0 || y >= max_y)) {
+      const float *c1, *c2, *c3;
+      int fx = x < 0 ? 0 : max_x - 1;
+      int fy = y < 0 ? 0 : max_y - 1;
+      c1 = get_texel_2d_no_border( samp, addr, fx, fy);
+      addr.bits.face = get_next_face(face, (x < 0) ? -1 : 1, 0);
+      c2 = get_texel_2d_no_border( samp, addr, (x < 0) ? max_x - 1 : 0, fy);
+      addr.bits.face = get_next_face(face, 0, (y < 0) ? -1 : 1);
+      c3 = get_texel_2d_no_border( samp, addr, fx, (y < 0) ?  max_y - 1 : 0);
+      for (c = 0; c < TGSI_QUAD_SIZE; c++)
+         corner[c] = CLAMP((c1[c] + c2[c] + c3[c]), 0.0F, 1.0F) / 3;
+
+      return corner;
+   }
+   /* change the face */
+   if (x < 0) {
+      new_x = max_x - 1;
+      face = get_next_face(face, -1, 0);
+   } else if (x >= max_x) {
+      new_x = 0;
+      face = get_next_face(face, 1, 0);
+   } else if (y < 0) {
+      new_y = max_y - 1;
+      face = get_next_face(face, 0, -1);
+   } else if (y >= max_y) {
+      new_y = 0;
+      face = get_next_face(face, 0, 1);
+   }
+
+   addr.bits.face = face;
+   return get_texel_2d_no_border( samp, addr, new_x, new_y );
+}
 
 /* Gather a quad of adjacent texels within a tile:
  */
@@ -1121,6 +1224,7 @@ img_filter_cube_nearest(struct tgsi_sampler *tgsi_sampler,
    union tex_tile_address addr;
    const float *out;
    int c;
+   float corner0[TGSI_QUAD_SIZE];
 
    width = u_minify(texture->width0, level);
    height = u_minify(texture->height0, level);
@@ -1131,8 +1235,17 @@ img_filter_cube_nearest(struct tgsi_sampler *tgsi_sampler,
    addr.value = 0;
    addr.bits.level = level;
 
-   samp->nearest_texcoord_s(s, width, &x);
-   samp->nearest_texcoord_t(t, height, &y);
+   /*
+    * If NEAREST filtering is done within a miplevel, always apply wrap
+    * mode CLAMP_TO_EDGE.
+    */
+   if (samp->sampler->seamless_cube_map) {
+      wrap_nearest_clamp_to_edge(s, width, &x);
+      wrap_nearest_clamp_to_edge(t, height, &y);
+   } else {
+      samp->nearest_texcoord_s(s, width, &x);
+      samp->nearest_texcoord_t(t, height, &y);
+   }
 
    out = get_texel_2d(samp, face(addr, face_id), x, y);
    for (c = 0; c < TGSI_QUAD_SIZE; c++)
@@ -1403,6 +1516,7 @@ img_filter_cube_linear(struct tgsi_sampler *tgsi_sampler,
    float xw, yw; /* weights */
    union tex_tile_address addr, addrj;
    const float *tx0, *tx1, *tx2, *tx3;
+   float corner0[TGSI_QUAD_SIZE], corner1[TGSI_QUAD_SIZE], corner2[TGSI_QUAD_SIZE], corner3[TGSI_QUAD_SIZE];
    int c;
 
    width = u_minify(texture->width0, level);
@@ -1414,15 +1528,31 @@ img_filter_cube_linear(struct tgsi_sampler *tgsi_sampler,
    addr.value = 0;
    addr.bits.level = level;
 
-   samp->linear_texcoord_s(s, width,  &x0, &x1, &xw);
-   samp->linear_texcoord_t(t, height, &y0, &y1, &yw);
+   /*
+    * For seamless if LINEAR filtering is done within a miplevel,
+    * always apply wrap mode CLAMP_TO_BORDER.
+    */
+   if (samp->sampler->seamless_cube_map) {
+      wrap_linear_clamp_to_border(s, width, &x0, &x1, &xw);
+      wrap_linear_clamp_to_border(t, height, &y0, &y1, &yw);
+   } else {
+      samp->linear_texcoord_s(s, width,  &x0, &x1, &xw);
+      samp->linear_texcoord_t(t, height, &y0, &y1, &yw);
+   }
 
    addrj = face(addr, face_id);
-   tx0 = get_texel_2d(samp, addrj, x0, y0);
-   tx1 = get_texel_2d(samp, addrj, x1, y0);
-   tx2 = get_texel_2d(samp, addrj, x0, y1);
-   tx3 = get_texel_2d(samp, addrj, x1, y1);
 
+   if (samp->sampler->seamless_cube_map) {
+      tx0 = get_texel_cube_seamless(samp, addrj, x0, y0, corner0);
+      tx1 = get_texel_cube_seamless(samp, addrj, x1, y0, corner1);
+      tx2 = get_texel_cube_seamless(samp, addrj, x0, y1, corner2);
+      tx3 = get_texel_cube_seamless(samp, addrj, x1, y1, corner3);
+   } else {
+      tx0 = get_texel_2d(samp, addrj, x0, y0);
+      tx1 = get_texel_2d(samp, addrj, x1, y0);
+      tx2 = get_texel_2d(samp, addrj, x0, y1);
+      tx3 = get_texel_2d(samp, addrj, x1, y1);
+   }
    /* interpolate R, G, B, A */
    for (c = 0; c < TGSI_QUAD_SIZE; c++)
       rgba[TGSI_NUM_CHANNELS*c] = lerp_2d(xw, yw,




More information about the mesa-commit mailing list