From 97fef2db5c2c6ec0b22bf5b7d968a4dc4b218363 Mon Sep 17 00:00:00 2001 From: Ilia Mirkin Date: Tue, 2 Dec 2014 21:32:01 -0500 Subject: [PATCH] freedreno/a3xx: fix alpha-blending on RGBX formats Expert debugging assistance provided by Chris Forbes. Signed-off-by: Ilia Mirkin Reviewed-by: Rob Clark --- src/gallium/auxiliary/Makefile.sources | 1 + src/gallium/auxiliary/util/u_blend.h | 25 +++++++++++++++++++ .../drivers/freedreno/a3xx/fd3_blend.c | 12 +++++++-- .../drivers/freedreno/a3xx/fd3_blend.h | 7 +++++- src/gallium/drivers/freedreno/a3xx/fd3_emit.c | 18 +++++++++---- 5 files changed, 55 insertions(+), 8 deletions(-) create mode 100644 src/gallium/auxiliary/util/u_blend.h diff --git a/src/gallium/auxiliary/Makefile.sources b/src/gallium/auxiliary/Makefile.sources index 862626461b1..ab794e16441 100644 --- a/src/gallium/auxiliary/Makefile.sources +++ b/src/gallium/auxiliary/Makefile.sources @@ -168,6 +168,7 @@ C_SOURCES := \ util/u_atomic.h \ util/u_bitmask.c \ util/u_bitmask.h \ + util/u_blend.h \ util/u_blit.c \ util/u_blit.h \ util/u_blitter.c \ diff --git a/src/gallium/auxiliary/util/u_blend.h b/src/gallium/auxiliary/util/u_blend.h new file mode 100644 index 00000000000..2485c34d418 --- /dev/null +++ b/src/gallium/auxiliary/util/u_blend.h @@ -0,0 +1,25 @@ +#ifndef U_BLEND_H +#define U_BLEND_H + +#include "pipe/p_state.h" + +/** + * When faking RGBX render target formats with RGBA ones, the blender is still + * supposed to treat the destination's alpha channel as 1 instead of the + * garbage that's there. Return a blend factor that will take that into + * account. + */ +static INLINE int +util_blend_dst_alpha_to_one(int factor) +{ + switch (factor) { + case PIPE_BLENDFACTOR_DST_ALPHA: + return PIPE_BLENDFACTOR_ONE; + case PIPE_BLENDFACTOR_INV_DST_ALPHA: + return PIPE_BLENDFACTOR_ZERO; + default: + return factor; + } +} + +#endif /* U_BLEND_H */ diff --git a/src/gallium/drivers/freedreno/a3xx/fd3_blend.c b/src/gallium/drivers/freedreno/a3xx/fd3_blend.c index 329d304694c..92295566147 100644 --- a/src/gallium/drivers/freedreno/a3xx/fd3_blend.c +++ b/src/gallium/drivers/freedreno/a3xx/fd3_blend.c @@ -27,6 +27,7 @@ */ #include "pipe/p_state.h" +#include "util/u_blend.h" #include "util/u_string.h" #include "util/u_memory.h" @@ -99,14 +100,21 @@ fd3_blend_state_create(struct pipe_context *pctx, for (i = 0; i < ARRAY_SIZE(so->rb_mrt); i++) { const struct pipe_rt_blend_state *rt = &cso->rt[i]; - so->rb_mrt[i].blend_control = + so->rb_mrt[i].blend_control_rgb = A3XX_RB_MRT_BLEND_CONTROL_RGB_SRC_FACTOR(fd_blend_factor(rt->rgb_src_factor)) | A3XX_RB_MRT_BLEND_CONTROL_RGB_BLEND_OPCODE(blend_func(rt->rgb_func)) | - A3XX_RB_MRT_BLEND_CONTROL_RGB_DEST_FACTOR(fd_blend_factor(rt->rgb_dst_factor)) | + A3XX_RB_MRT_BLEND_CONTROL_RGB_DEST_FACTOR(fd_blend_factor(rt->rgb_dst_factor)); + + so->rb_mrt[i].blend_control_alpha = A3XX_RB_MRT_BLEND_CONTROL_ALPHA_SRC_FACTOR(fd_blend_factor(rt->alpha_src_factor)) | A3XX_RB_MRT_BLEND_CONTROL_ALPHA_BLEND_OPCODE(blend_func(rt->alpha_func)) | A3XX_RB_MRT_BLEND_CONTROL_ALPHA_DEST_FACTOR(fd_blend_factor(rt->alpha_dst_factor)); + so->rb_mrt[i].blend_control_no_alpha_rgb = + A3XX_RB_MRT_BLEND_CONTROL_RGB_SRC_FACTOR(fd_blend_factor(util_blend_dst_alpha_to_one(rt->rgb_src_factor))) | + A3XX_RB_MRT_BLEND_CONTROL_RGB_BLEND_OPCODE(blend_func(rt->rgb_func)) | + A3XX_RB_MRT_BLEND_CONTROL_RGB_DEST_FACTOR(fd_blend_factor(util_blend_dst_alpha_to_one(rt->rgb_dst_factor))); + so->rb_mrt[i].control = A3XX_RB_MRT_CONTROL_ROP_CODE(rop) | A3XX_RB_MRT_CONTROL_COMPONENT_ENABLE(rt->colormask); diff --git a/src/gallium/drivers/freedreno/a3xx/fd3_blend.h b/src/gallium/drivers/freedreno/a3xx/fd3_blend.h index d269d74dd74..4f6eeb74481 100644 --- a/src/gallium/drivers/freedreno/a3xx/fd3_blend.h +++ b/src/gallium/drivers/freedreno/a3xx/fd3_blend.h @@ -35,7 +35,12 @@ struct fd3_blend_stateobj { struct pipe_blend_state base; struct { - uint32_t blend_control; + /* Blend control bits for color if there is an alpha channel */ + uint32_t blend_control_rgb; + /* Blend control bits for color if there is no alpha channel */ + uint32_t blend_control_no_alpha_rgb; + /* Blend control bits for alpha channel */ + uint32_t blend_control_alpha; uint32_t control; } rb_mrt[4]; }; diff --git a/src/gallium/drivers/freedreno/a3xx/fd3_emit.c b/src/gallium/drivers/freedreno/a3xx/fd3_emit.c index 44f8ac4bb40..f721303cefe 100644 --- a/src/gallium/drivers/freedreno/a3xx/fd3_emit.c +++ b/src/gallium/drivers/freedreno/a3xx/fd3_emit.c @@ -571,11 +571,12 @@ fd3_emit_state(struct fd_context *ctx, struct fd_ringbuffer *ring, uint32_t i; for (i = 0; i < ARRAY_SIZE(blend->rb_mrt); i++) { - bool is_float = util_format_is_float( - pipe_surface_format(ctx->framebuffer.cbufs[i])); - bool is_int = util_format_is_pure_integer( - pipe_surface_format(ctx->framebuffer.cbufs[i])); + enum pipe_format format = pipe_surface_format(ctx->framebuffer.cbufs[i]); + bool is_float = util_format_is_float(format); + bool is_int = util_format_is_pure_integer(format); + bool has_alpha = util_format_has_alpha(format); uint32_t control = blend->rb_mrt[i].control; + uint32_t blend_control = blend->rb_mrt[i].blend_control_alpha; if (is_int) { control &= (A3XX_RB_MRT_CONTROL_COMPONENT_ENABLE__MASK | @@ -583,11 +584,18 @@ fd3_emit_state(struct fd_context *ctx, struct fd_ringbuffer *ring, control |= A3XX_RB_MRT_CONTROL_ROP_CODE(ROP_COPY); } + if (has_alpha) { + blend_control |= blend->rb_mrt[i].blend_control_rgb; + } else { + blend_control |= blend->rb_mrt[i].blend_control_no_alpha_rgb; + control &= ~A3XX_RB_MRT_CONTROL_BLEND2; + } + OUT_PKT0(ring, REG_A3XX_RB_MRT_CONTROL(i), 1); OUT_RING(ring, control); OUT_PKT0(ring, REG_A3XX_RB_MRT_BLEND_CONTROL(i), 1); - OUT_RING(ring, blend->rb_mrt[i].blend_control | + OUT_RING(ring, blend_control | COND(!is_float, A3XX_RB_MRT_BLEND_CONTROL_CLAMP_ENABLE)); } } -- 2.30.2