Mesa (master): freedreno/a3xx: fix alpha-blending on RGBX formats
Ilia Mirkin
imirkin at kemper.freedesktop.org
Sat Dec 6 23:26:37 UTC 2014
Module: Mesa
Branch: master
Commit: 97fef2db5c2c6ec0b22bf5b7d968a4dc4b218363
URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=97fef2db5c2c6ec0b22bf5b7d968a4dc4b218363
Author: Ilia Mirkin <imirkin at alum.mit.edu>
Date: Tue Dec 2 21:32:01 2014 -0500
freedreno/a3xx: fix alpha-blending on RGBX formats
Expert debugging assistance provided by Chris Forbes.
Signed-off-by: Ilia Mirkin <imirkin at alum.mit.edu>
Reviewed-by: Rob Clark <robclark at freedesktop.org>
---
src/gallium/auxiliary/Makefile.sources | 1 +
src/gallium/auxiliary/util/u_blend.h | 25 ++++++++++++++++++++++++
src/gallium/drivers/freedreno/a3xx/fd3_blend.c | 12 ++++++++++--
src/gallium/drivers/freedreno/a3xx/fd3_blend.h | 7 ++++++-
src/gallium/drivers/freedreno/a3xx/fd3_emit.c | 18 ++++++++++++-----
5 files changed, 55 insertions(+), 8 deletions(-)
diff --git a/src/gallium/auxiliary/Makefile.sources b/src/gallium/auxiliary/Makefile.sources
index 8626264..ab794e1 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 0000000..2485c34
--- /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 329d304..9229556 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 d269d74..4f6eeb7 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 44f8ac4..f721303 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));
}
}
More information about the mesa-commit
mailing list