summaryrefslogtreecommitdiffstats
path: root/src/gallium/state_trackers
diff options
context:
space:
mode:
authorChia-I Wu <[email protected]>2010-12-04 14:51:27 +0800
committerChia-I Wu <[email protected]>2010-12-04 15:44:40 +0800
commite87a0cd260804a2488ef3eb1cf988fef1dd70e06 (patch)
tree0be006983b8f77721da910fb7eeed2f8727e5b3d /src/gallium/state_trackers
parente8ff3931f801dffdfd54832c298351e933688235 (diff)
st/vega: Blending should use premultiplied alpha.
Convert color values to and back from premultiplied form for blending. Finally the rendering result of the blend demo looks much closer to that of the reference implementation.
Diffstat (limited to 'src/gallium/state_trackers')
-rw-r--r--src/gallium/state_trackers/vega/asm_fill.h80
1 files changed, 72 insertions, 8 deletions
diff --git a/src/gallium/state_trackers/vega/asm_fill.h b/src/gallium/state_trackers/vega/asm_fill.h
index a95e4c9efcb..566f7c95f5b 100644
--- a/src/gallium/state_trackers/vega/asm_fill.h
+++ b/src/gallium/state_trackers/vega/asm_fill.h
@@ -273,21 +273,71 @@ alpha_per_channel( struct ureg_program *ureg,
}
/**
- * Emit instructions for the specified blend mode. Colors should be
- * premultiplied. Two temporary registers are required.
+ * Premultiply src and dst.
+ */
+static INLINE void
+blend_premultiply( struct ureg_program *ureg,
+ struct ureg_src src,
+ struct ureg_src src_channel_alpha,
+ struct ureg_src dst)
+{
+ /* premultiply src */
+ ureg_MUL(ureg,
+ ureg_writemask(ureg_dst(src), TGSI_WRITEMASK_XYZ),
+ src,
+ src_channel_alpha);
+ /* premultiply dst */
+ ureg_MUL(ureg,
+ ureg_writemask(ureg_dst(dst), TGSI_WRITEMASK_XYZ),
+ dst,
+ ureg_scalar(dst, TGSI_SWIZZLE_W));
+}
+
+/**
+ * Unpremultiply src.
+ */
+static INLINE void
+blend_unpremultiply( struct ureg_program *ureg,
+ struct ureg_src src,
+ struct ureg_src one,
+ struct ureg_dst temp[1])
+{
+ /* replace 0.0f by 1.0f before calculating reciprocal */
+ ureg_CMP(ureg,
+ temp[0],
+ ureg_negate(ureg_scalar(src, TGSI_SWIZZLE_W)),
+ ureg_scalar(src, TGSI_SWIZZLE_W),
+ one);
+ ureg_RCP(ureg, temp[0], ureg_src(temp[0]));
+
+ ureg_MUL(ureg,
+ ureg_writemask(ureg_dst(src), TGSI_WRITEMASK_XYZ),
+ src,
+ ureg_src(temp[0]));
+}
+
+/**
+ * Emit instructions for the specified blend mode. Colors will be
+ * unpremultiplied. Two temporary registers are required.
*
- * XXX callers do not pass premultiplied colors!
+ * The output is written back to src.
*/
static INLINE void
blend_generic(struct ureg_program *ureg,
VGBlendMode mode,
- struct ureg_dst out,
struct ureg_src src,
struct ureg_src src_channel_alpha,
struct ureg_src dst,
struct ureg_src one,
struct ureg_dst temp[2])
{
+ struct ureg_dst out;
+
+ blend_premultiply(ureg, src, src_channel_alpha, dst);
+
+ /* blend in-place */
+ out = ureg_dst(src);
+
switch (mode) {
case VG_BLEND_SRC:
ureg_MOV(ureg, out, src);
@@ -355,6 +405,8 @@ blend_generic(struct ureg_program *ureg,
assert(0);
break;
}
+
+ blend_unpremultiply(ureg, src, one, temp);
}
static INLINE void
@@ -366,12 +418,15 @@ blend_multiply( struct ureg_program *ureg,
struct ureg_src *constant)
{
ureg_TEX(ureg, temp[2], TGSI_TEXTURE_2D, in[0], sampler[2]);
- blend_generic(ureg, VG_BLEND_MULTIPLY, *out,
+
+ blend_generic(ureg, VG_BLEND_MULTIPLY,
ureg_src(temp[0]),
ureg_src(temp[1]),
ureg_src(temp[2]),
ureg_scalar(constant[3], TGSI_SWIZZLE_Y),
temp + 3);
+
+ ureg_MOV(ureg, *out, ureg_src(temp[0]));
}
static INLINE void
@@ -383,12 +438,15 @@ blend_screen( struct ureg_program *ureg,
struct ureg_src *constant)
{
ureg_TEX(ureg, temp[2], TGSI_TEXTURE_2D, in[0], sampler[2]);
- blend_generic(ureg, VG_BLEND_SCREEN, *out,
+
+ blend_generic(ureg, VG_BLEND_SCREEN,
ureg_src(temp[0]),
ureg_src(temp[1]),
ureg_src(temp[2]),
ureg_scalar(constant[3], TGSI_SWIZZLE_Y),
temp + 3);
+
+ ureg_MOV(ureg, *out, ureg_src(temp[0]));
}
static INLINE void
@@ -400,12 +458,15 @@ blend_darken( struct ureg_program *ureg,
struct ureg_src *constant)
{
ureg_TEX(ureg, temp[2], TGSI_TEXTURE_2D, in[0], sampler[2]);
- blend_generic(ureg, VG_BLEND_DARKEN, *out,
+
+ blend_generic(ureg, VG_BLEND_DARKEN,
ureg_src(temp[0]),
ureg_src(temp[1]),
ureg_src(temp[2]),
ureg_scalar(constant[3], TGSI_SWIZZLE_Y),
temp + 3);
+
+ ureg_MOV(ureg, *out, ureg_src(temp[0]));
}
static INLINE void
@@ -417,12 +478,15 @@ blend_lighten( struct ureg_program *ureg,
struct ureg_src *constant)
{
ureg_TEX(ureg, temp[2], TGSI_TEXTURE_2D, in[0], sampler[2]);
- blend_generic(ureg, VG_BLEND_LIGHTEN, *out,
+
+ blend_generic(ureg, VG_BLEND_LIGHTEN,
ureg_src(temp[0]),
ureg_src(temp[1]),
ureg_src(temp[2]),
ureg_scalar(constant[3], TGSI_SWIZZLE_Y),
temp + 3);
+
+ ureg_MOV(ureg, *out, ureg_src(temp[0]));
}
static INLINE void