From 7cdd4679943a72b97aad1c584da4bcb0e1f003f2 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Mon, 29 Sep 2014 10:44:46 -0400 Subject: [PATCH] freedreno/a3xx: add support to emulate GL_CLAMP Signed-off-by: Rob Clark --- .../drivers/freedreno/a3xx/fd3_context.h | 10 +++ src/gallium/drivers/freedreno/a3xx/fd3_draw.c | 8 ++ .../drivers/freedreno/a3xx/fd3_texture.c | 73 +++++++++++++++---- .../drivers/freedreno/a3xx/fd3_texture.h | 1 + .../drivers/freedreno/ir3/ir3_compiler.c | 16 +++- .../drivers/freedreno/ir3/ir3_compiler_old.c | 16 +++- .../drivers/freedreno/ir3/ir3_shader.c | 6 ++ .../drivers/freedreno/ir3/ir3_shader.h | 15 ++++ 8 files changed, 129 insertions(+), 16 deletions(-) diff --git a/src/gallium/drivers/freedreno/a3xx/fd3_context.h b/src/gallium/drivers/freedreno/a3xx/fd3_context.h index 7d7663a28bc..48bbb47e9ca 100644 --- a/src/gallium/drivers/freedreno/a3xx/fd3_context.h +++ b/src/gallium/drivers/freedreno/a3xx/fd3_context.h @@ -76,6 +76,16 @@ struct fd3_context { struct u_upload_mgr *border_color_uploader; struct pipe_resource *border_color_buf; + + /* bitmask of sampler which needs coords clamped for vertex + * shader: + */ + unsigned vsaturate_s, vsaturate_t, vsaturate_r; + + /* bitmask of sampler which needs coords clamped for frag + * shader: + */ + unsigned fsaturate_s, fsaturate_t, fsaturate_r; }; static INLINE struct fd3_context * diff --git a/src/gallium/drivers/freedreno/a3xx/fd3_draw.c b/src/gallium/drivers/freedreno/a3xx/fd3_draw.c index 15d2ce4a943..f7a5fcafd9a 100644 --- a/src/gallium/drivers/freedreno/a3xx/fd3_draw.c +++ b/src/gallium/drivers/freedreno/a3xx/fd3_draw.c @@ -100,6 +100,7 @@ static void fd3_draw(struct fd_context *ctx, const struct pipe_draw_info *info) { unsigned dirty = ctx->dirty; + struct fd3_context *fd3_ctx = fd3_context(ctx); struct ir3_shader_key key = { /* do binning pass first: */ .binning_pass = true, @@ -108,7 +109,14 @@ fd3_draw(struct fd_context *ctx, const struct pipe_draw_info *info) // TODO set .half_precision based on render target format, // ie. float16 and smaller use half, float32 use full.. .half_precision = !!(fd_mesa_debug & FD_DBG_FRAGHALF), + .vsaturate_s = fd3_ctx->vsaturate_s, + .vsaturate_t = fd3_ctx->vsaturate_t, + .vsaturate_r = fd3_ctx->vsaturate_r, + .fsaturate_s = fd3_ctx->fsaturate_s, + .fsaturate_t = fd3_ctx->fsaturate_t, + .fsaturate_r = fd3_ctx->fsaturate_r, }; + draw_impl(ctx, info, ctx->binning_ring, dirty & ~(FD_DIRTY_BLEND), key); /* and now regular (non-binning) pass: */ diff --git a/src/gallium/drivers/freedreno/a3xx/fd3_texture.c b/src/gallium/drivers/freedreno/a3xx/fd3_texture.c index 918dcc491f2..d70b39e2114 100644 --- a/src/gallium/drivers/freedreno/a3xx/fd3_texture.c +++ b/src/gallium/drivers/freedreno/a3xx/fd3_texture.c @@ -36,30 +36,31 @@ #include "fd3_util.h" static enum a3xx_tex_clamp -tex_clamp(unsigned wrap) +tex_clamp(unsigned wrap, bool clamp_to_edge) { - /* hardware probably supports more, but we can't coax all the - * wrap/clamp modes out of the GLESv2 blob driver. - * - * TODO once we have basics working, go back and just try - * different values and see what happens - */ + /* Hardware does not support _CLAMP, but we emulate it: */ + if (wrap == PIPE_TEX_WRAP_CLAMP) { + wrap = (clamp_to_edge) ? + PIPE_TEX_WRAP_CLAMP_TO_EDGE : PIPE_TEX_WRAP_CLAMP_TO_BORDER; + } + switch (wrap) { case PIPE_TEX_WRAP_REPEAT: return A3XX_TEX_REPEAT; - case PIPE_TEX_WRAP_CLAMP: case PIPE_TEX_WRAP_CLAMP_TO_EDGE: return A3XX_TEX_CLAMP_TO_EDGE; case PIPE_TEX_WRAP_CLAMP_TO_BORDER: return A3XX_TEX_CLAMP_TO_BORDER; - case PIPE_TEX_WRAP_MIRROR_CLAMP: - case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: - /* these two we should emulate! */ case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: /* only works for PoT.. need to emulate otherwise! */ return A3XX_TEX_MIRROR_CLAMP; case PIPE_TEX_WRAP_MIRROR_REPEAT: return A3XX_TEX_MIRROR_REPEAT; + case PIPE_TEX_WRAP_MIRROR_CLAMP: + case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: + /* these two we could perhaps emulate, but we currently + * just don't advertise PIPE_CAP_TEXTURE_MIRROR_CLAMP + */ default: DBG("invalid wrap: %u", wrap); return 0; @@ -86,6 +87,7 @@ fd3_sampler_state_create(struct pipe_context *pctx, { struct fd3_sampler_stateobj *so = CALLOC_STRUCT(fd3_sampler_stateobj); bool miplinear = false; + bool clamp_to_edge; if (!so) return NULL; @@ -95,14 +97,29 @@ fd3_sampler_state_create(struct pipe_context *pctx, so->base = *cso; + /* + * For nearest filtering, _CLAMP means _CLAMP_TO_EDGE; for linear + * filtering, _CLAMP means _CLAMP_TO_BORDER while additionally + * clamping the texture coordinates to [0.0, 1.0]. + * + * The clamping will be taken care of in the shaders. There are two + * filters here, but let the minification one has a say. + */ + clamp_to_edge = (cso->min_img_filter == PIPE_TEX_FILTER_NEAREST); + if (!clamp_to_edge) { + so->saturate_s = (cso->wrap_s == PIPE_TEX_WRAP_CLAMP); + so->saturate_t = (cso->wrap_t == PIPE_TEX_WRAP_CLAMP); + so->saturate_r = (cso->wrap_r == PIPE_TEX_WRAP_CLAMP); + } + so->texsamp0 = COND(!cso->normalized_coords, A3XX_TEX_SAMP_0_UNNORM_COORDS) | COND(miplinear, A3XX_TEX_SAMP_0_MIPFILTER_LINEAR) | A3XX_TEX_SAMP_0_XY_MAG(tex_filter(cso->mag_img_filter)) | A3XX_TEX_SAMP_0_XY_MIN(tex_filter(cso->min_img_filter)) | - A3XX_TEX_SAMP_0_WRAP_S(tex_clamp(cso->wrap_s)) | - A3XX_TEX_SAMP_0_WRAP_T(tex_clamp(cso->wrap_t)) | - A3XX_TEX_SAMP_0_WRAP_R(tex_clamp(cso->wrap_r)); + A3XX_TEX_SAMP_0_WRAP_S(tex_clamp(cso->wrap_s, clamp_to_edge)) | + A3XX_TEX_SAMP_0_WRAP_T(tex_clamp(cso->wrap_t, clamp_to_edge)) | + A3XX_TEX_SAMP_0_WRAP_R(tex_clamp(cso->wrap_r, clamp_to_edge)); if (cso->compare_mode) so->texsamp0 |= A3XX_TEX_SAMP_0_COMPARE_FUNC(cso->compare_func); /* maps 1:1 */ @@ -124,7 +141,35 @@ fd3_sampler_states_bind(struct pipe_context *pctx, unsigned shader, unsigned start, unsigned nr, void **hwcso) { + struct fd_context *ctx = fd_context(pctx); + struct fd3_context *fd3_ctx = fd3_context(ctx); + unsigned saturate_s = 0, saturate_t = 0, saturate_r = 0; + unsigned i; + + for (i = 0; i < nr; i++) { + if (hwcso[i]) { + struct fd3_sampler_stateobj *sampler = + fd3_sampler_stateobj(hwcso[i]); + if (sampler->saturate_s) + saturate_s |= (1 << i); + if (sampler->saturate_t) + saturate_t |= (1 << i); + if (sampler->saturate_r) + saturate_r |= (1 << i); + } + } + fd_sampler_states_bind(pctx, shader, start, nr, hwcso); + + if (shader == PIPE_SHADER_FRAGMENT) { + fd3_ctx->fsaturate_s = saturate_s; + fd3_ctx->fsaturate_t = saturate_t; + fd3_ctx->fsaturate_r = saturate_r; + } else if (shader == PIPE_SHADER_VERTEX) { + fd3_ctx->vsaturate_s = saturate_s; + fd3_ctx->vsaturate_t = saturate_t; + fd3_ctx->vsaturate_r = saturate_r; + } } static enum a3xx_tex_type diff --git a/src/gallium/drivers/freedreno/a3xx/fd3_texture.h b/src/gallium/drivers/freedreno/a3xx/fd3_texture.h index a83f527366b..0434df37413 100644 --- a/src/gallium/drivers/freedreno/a3xx/fd3_texture.h +++ b/src/gallium/drivers/freedreno/a3xx/fd3_texture.h @@ -40,6 +40,7 @@ struct fd3_sampler_stateobj { struct pipe_sampler_state base; uint32_t texsamp0, texsamp1; + bool saturate_s, saturate_t, saturate_r; }; static INLINE struct fd3_sampler_stateobj * diff --git a/src/gallium/drivers/freedreno/ir3/ir3_compiler.c b/src/gallium/drivers/freedreno/ir3/ir3_compiler.c index c2d4942b66d..07b57b8d049 100644 --- a/src/gallium/drivers/freedreno/ir3/ir3_compiler.c +++ b/src/gallium/drivers/freedreno/ir3/ir3_compiler.c @@ -135,7 +135,7 @@ compile_init(struct ir3_compile_context *ctx, struct ir3_shader_variant *so, { unsigned ret; struct tgsi_shader_info *info = &ctx->info; - const struct fd_lowering_config lconfig = { + struct fd_lowering_config lconfig = { .color_two_side = so->key.color_two_side, .lower_DST = true, .lower_XPD = true, @@ -153,6 +153,20 @@ compile_init(struct ir3_compile_context *ctx, struct ir3_shader_variant *so, .lower_DP2A = true, }; + switch (so->type) { + case SHADER_FRAGMENT: + case SHADER_COMPUTE: + lconfig.saturate_s = so->key.fsaturate_s; + lconfig.saturate_t = so->key.fsaturate_t; + lconfig.saturate_r = so->key.fsaturate_r; + break; + case SHADER_VERTEX: + lconfig.saturate_s = so->key.vsaturate_s; + lconfig.saturate_t = so->key.vsaturate_t; + lconfig.saturate_r = so->key.vsaturate_r; + break; + } + ctx->tokens = fd_transform_lowering(&lconfig, tokens, &ctx->info); ctx->free_tokens = !!ctx->tokens; if (!ctx->tokens) { diff --git a/src/gallium/drivers/freedreno/ir3/ir3_compiler_old.c b/src/gallium/drivers/freedreno/ir3/ir3_compiler_old.c index 1e1ca7ad813..4267feb351f 100644 --- a/src/gallium/drivers/freedreno/ir3/ir3_compiler_old.c +++ b/src/gallium/drivers/freedreno/ir3/ir3_compiler_old.c @@ -125,7 +125,7 @@ compile_init(struct ir3_compile_context *ctx, struct ir3_shader_variant *so, { unsigned ret, base = 0; struct tgsi_shader_info *info = &ctx->info; - const struct fd_lowering_config lconfig = { + struct fd_lowering_config lconfig = { .color_two_side = so->key.color_two_side, .lower_DST = true, .lower_XPD = true, @@ -143,6 +143,20 @@ compile_init(struct ir3_compile_context *ctx, struct ir3_shader_variant *so, .lower_DP2A = true, }; + switch (so->type) { + case SHADER_FRAGMENT: + case SHADER_COMPUTE: + lconfig.saturate_s = so->key.fsaturate_s; + lconfig.saturate_t = so->key.fsaturate_t; + lconfig.saturate_r = so->key.fsaturate_r; + break; + case SHADER_VERTEX: + lconfig.saturate_s = so->key.vsaturate_s; + lconfig.saturate_t = so->key.vsaturate_t; + lconfig.saturate_r = so->key.vsaturate_r; + break; + } + ctx->tokens = fd_transform_lowering(&lconfig, tokens, &ctx->info); ctx->free_tokens = !!ctx->tokens; if (!ctx->tokens) { diff --git a/src/gallium/drivers/freedreno/ir3/ir3_shader.c b/src/gallium/drivers/freedreno/ir3/ir3_shader.c index 6d45597886b..ed7c639c930 100644 --- a/src/gallium/drivers/freedreno/ir3/ir3_shader.c +++ b/src/gallium/drivers/freedreno/ir3/ir3_shader.c @@ -185,11 +185,17 @@ ir3_shader_variant(struct ir3_shader *shader, struct ir3_shader_key key) */ if (shader->type == SHADER_FRAGMENT) { key.binning_pass = false; + key.vsaturate_s = 0; + key.vsaturate_t = 0; + key.vsaturate_r = 0; } if (shader->type == SHADER_VERTEX) { key.color_two_side = false; key.half_precision = false; key.alpha = false; + key.fsaturate_s = 0; + key.fsaturate_t = 0; + key.fsaturate_r = 0; } for (v = shader->variants; v; v = v->next) diff --git a/src/gallium/drivers/freedreno/ir3/ir3_shader.h b/src/gallium/drivers/freedreno/ir3/ir3_shader.h index ea861649176..04a737ef19d 100644 --- a/src/gallium/drivers/freedreno/ir3/ir3_shader.h +++ b/src/gallium/drivers/freedreno/ir3/ir3_shader.h @@ -52,8 +52,23 @@ static inline uint16_t sem2idx(ir3_semantic sem) /* Configuration key used to identify a shader variant.. different * shader variants can be used to implement features not supported * in hw (two sided color), binning-pass vertex shader, etc. + * + * TODO since shader key is starting to get larger (than 32bit) + * we probably should pass it around by ptr rather than value more + * of the places.. but watch out in ir3_shader_variant() where the + * key gets normalized, we need to make a copy there. */ struct ir3_shader_key { + /* bitmask of sampler which needs coords clamped for vertex + * shader: + */ + unsigned vsaturate_s, vsaturate_t, vsaturate_r; + + /* bitmask of sampler which needs coords clamped for frag + * shader: + */ + unsigned fsaturate_s, fsaturate_t, fsaturate_r; + /* * Vertex shader variant parameters: */ -- 2.30.2