freedreno/a3xx: fix alpha-blending on RGBX formats
authorIlia Mirkin <imirkin@alum.mit.edu>
Wed, 3 Dec 2014 02:32:01 +0000 (21:32 -0500)
committerIlia Mirkin <imirkin@alum.mit.edu>
Sat, 6 Dec 2014 23:18:20 +0000 (18:18 -0500)
Expert debugging assistance provided by Chris Forbes.

Signed-off-by: Ilia Mirkin <imirkin@alum.mit.edu>
Reviewed-by: Rob Clark <robclark@freedesktop.org>
src/gallium/auxiliary/Makefile.sources
src/gallium/auxiliary/util/u_blend.h [new file with mode: 0644]
src/gallium/drivers/freedreno/a3xx/fd3_blend.c
src/gallium/drivers/freedreno/a3xx/fd3_blend.h
src/gallium/drivers/freedreno/a3xx/fd3_emit.c

index 862626461b135c602fbb42d22e49388366f42b5c..ab794e164415a44437c6f44ca8bf533170868f6c 100644 (file)
@@ -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 (file)
index 0000000..2485c34
--- /dev/null
@@ -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 */
index 329d304694c6f370648b4cbc587d6111349094fc..922955661472635990ce9da5d535dd09570b549c 100644 (file)
@@ -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);
index d269d74dd744e1a16091b747d74c17d0e207a207..4f6eeb74481bd126cce1004972dd9dc109fca85c 100644 (file)
 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];
 };
index 44f8ac4bb40da63388daacf596db14087ef4b460..f721303cefe4d15e75983a7c455c7bfbd662ebfd 100644 (file)
@@ -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));
                }
        }