[Mesa-dev] [PATCH] softpipe: implement seamless cubemap support.

Brian Paul brianp at vmware.com
Tue Dec 11 07:09:47 PST 2012


Just a few minor things below.


On 12/11/2012 02:52 AM, Dave Airlie wrote:
> 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!
>
> 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 | 143 +++++++++++++++++++++++++--
>   2 files changed, 135 insertions(+), 10 deletions(-)
>
> diff --git a/src/gallium/drivers/softpipe/sp_screen.c b/src/gallium/drivers/softpipe/sp_screen.c
> index 909fa1c..7ca259e 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..9500a03 100644
> --- a/src/gallium/drivers/softpipe/sp_tex_sample.c
> +++ b/src/gallium/drivers/softpipe/sp_tex_sample.c
> @@ -607,6 +607,100 @@ get_texel_2d(const struct sp_sampler_variant *samp,
>      }
>   }
>

Maybe add a comment on this array explaining what it's for.


> +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;

Please put the "idx = ..." assignments on separate lines.  The problem 
with "if (c) expr;" is it's a PITA if you want to set a breakpoint on 
expr.


> +
> +   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 +1215,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,10 +1226,23 @@ 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);
> +   if (samp->sampler->seamless_cube_map) {
> +      out = get_texel_cube_seamless(samp, face(addr, face_id), x, y, corner0);
> +   } else {
> +      out = get_texel_2d(samp, face(addr, face_id), x, y);
> +   }
>      for (c = 0; c<  TGSI_QUAD_SIZE; c++)
>         rgba[TGSI_NUM_CHANNELS*c] = out[c];
>
> @@ -1403,6 +1511,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 +1523,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.
> +    */

I think that comment could be rewrapped to fit on two lines.


> +   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,


Thanks for working on this, Dave!

Reviewed-by: Brian Paul <brianp at vmware.com>



More information about the mesa-dev mailing list