summaryrefslogtreecommitdiffstats
path: root/src/gallium/drivers
diff options
context:
space:
mode:
authorJosé Fonseca <[email protected]>2010-05-02 21:36:12 +0100
committerJosé Fonseca <[email protected]>2010-05-03 00:13:36 +0100
commit59253a79d823a4cfd1d65466c0a165d6d4c43a92 (patch)
tree1708b05a4d0b712bfd9291a0291173caed53c984 /src/gallium/drivers
parentb44c52870dc2eec9a41e984d4dceca22ea83d334 (diff)
llvmpipe: Fix alpha blending for formats without alpha channel.
Don't use the dst alpha channel from the swizzled tile when it does not exist in the true format.
Diffstat (limited to 'src/gallium/drivers')
-rw-r--r--src/gallium/drivers/llvmpipe/lp_state_fs.c53
1 files changed, 51 insertions, 2 deletions
diff --git a/src/gallium/drivers/llvmpipe/lp_state_fs.c b/src/gallium/drivers/llvmpipe/lp_state_fs.c
index 513e62e39e5..5f861d6ca4d 100644
--- a/src/gallium/drivers/llvmpipe/lp_state_fs.c
+++ b/src/gallium/drivers/llvmpipe/lp_state_fs.c
@@ -1062,6 +1062,34 @@ llvmpipe_set_constant_buffer(struct pipe_context *pipe,
/**
+ * Return the blend factor equivalent to a destination alpha of one.
+ */
+static INLINE unsigned
+force_dst_alpha_one(unsigned factor, boolean alpha)
+{
+ switch(factor) {
+ case PIPE_BLENDFACTOR_DST_ALPHA:
+ return PIPE_BLENDFACTOR_ONE;
+ case PIPE_BLENDFACTOR_INV_DST_ALPHA:
+ return PIPE_BLENDFACTOR_ZERO;
+ case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE:
+ return PIPE_BLENDFACTOR_ZERO;
+ }
+
+ if (alpha) {
+ switch(factor) {
+ case PIPE_BLENDFACTOR_DST_COLOR:
+ return PIPE_BLENDFACTOR_ONE;
+ case PIPE_BLENDFACTOR_INV_DST_COLOR:
+ return PIPE_BLENDFACTOR_ZERO;
+ }
+ }
+
+ return factor;
+}
+
+
+/**
* We need to generate several variants of the fragment pipeline to match
* all the combinations of the contributing state atoms.
*
@@ -1102,6 +1130,7 @@ make_variant_key(struct llvmpipe_context *lp,
key->nr_cbufs = lp->framebuffer.nr_cbufs;
for (i = 0; i < lp->framebuffer.nr_cbufs; i++) {
+ struct pipe_rt_blend_state *blend_rt = &key->blend.rt[i];
const struct util_format_description *format_desc;
unsigned chan;
@@ -1109,7 +1138,7 @@ make_variant_key(struct llvmpipe_context *lp,
assert(format_desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB ||
format_desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB);
- key->blend.rt[i].colormask = lp->blend->rt[i].colormask;
+ blend_rt->colormask = lp->blend->rt[i].colormask;
/* mask out color channels not present in the color buffer.
* Should be simple to incorporate per-cbuf writemasks:
@@ -1118,7 +1147,27 @@ make_variant_key(struct llvmpipe_context *lp,
enum util_format_swizzle swizzle = format_desc->swizzle[chan];
if(swizzle > UTIL_FORMAT_SWIZZLE_W)
- key->blend.rt[i].colormask &= ~(1 << chan);
+ blend_rt->colormask &= ~(1 << chan);
+ }
+
+ /*
+ * Our swizzled render tiles always have an alpha channel, but the linear
+ * render target format often does not, so force here the dst alpha to be
+ * one.
+ *
+ * This is not a mere optimization. Wrong results will be produced if the
+ * dst alpha is used, the dst format does not have alpha, and the previous
+ * rendering was not flushed from the swizzled to linear buffer. For
+ * example, NonPowTwo DCT.
+ *
+ * TODO: This should be generalized to all channels for better
+ * performance, but only alpha causes correctness issues.
+ */
+ if (format_desc->swizzle[3] > UTIL_FORMAT_SWIZZLE_W) {
+ blend_rt->rgb_src_factor = force_dst_alpha_one(blend_rt->rgb_src_factor, FALSE);
+ blend_rt->rgb_dst_factor = force_dst_alpha_one(blend_rt->rgb_dst_factor, FALSE);
+ blend_rt->alpha_src_factor = force_dst_alpha_one(blend_rt->alpha_src_factor, TRUE);
+ blend_rt->alpha_dst_factor = force_dst_alpha_one(blend_rt->alpha_dst_factor, TRUE);
}
}