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 <airl...@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, } } +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 +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. + */ + 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, -- 1.8.0.1 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev