[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