diff options
author | Chia-I Wu <[email protected]> | 2010-12-04 14:51:27 +0800 |
---|---|---|
committer | Chia-I Wu <[email protected]> | 2010-12-04 15:44:40 +0800 |
commit | e87a0cd260804a2488ef3eb1cf988fef1dd70e06 (patch) | |
tree | 0be006983b8f77721da910fb7eeed2f8727e5b3d | |
parent | e8ff3931f801dffdfd54832c298351e933688235 (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.
-rw-r--r-- | src/gallium/state_trackers/vega/asm_fill.h | 80 |
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 |