diff options
author | Grigori Goronzy <greg@chown.ath.cx> | 2013-07-22 02:30:28 +0200 |
---|---|---|
committer | Grigori Goronzy <greg@chown.ath.cx> | 2013-07-22 05:05:48 +0200 |
commit | 4375a6e75e5d41139be7031a0dee58c057ecbd07 (patch) | |
tree | 90bb91b0354a4ac421fbc5c1924334930f6e5d4f | |
parent | 94d0d14914a025525a0766669b556eaa6681def7 (diff) |
EXA/evergreen/ni: accelerate PictOpOver with component alpha
Subpixel text rendering is typically done with a solid src and a
pixmap mask. Traditionally, this cannot be accelerated in a single
pass and requires two passes [1]. However, we can cheat a little
with a constant blend color.
We can use:
const.A = src.A / src.A
const.R = src.R / src.A
const.G = src.G / src.A
const.B = src.B / src.A
dst.A = const.A * (src.A * mask.A) + (1 - (src.A * mask.A)) * dst.A
dst.R = const.R * (src.A * mask.R) + (1 - (src.A * mask.R)) * dst.R
dst.G = const.G * (src.A * mask.G) + (1 - (src.A * mask.G)) * dst.G
dst.B = const.B * (src.A * mask.B) + (1 - (src.A * mask.B)) * dst.B
This only needs a single source value. src.A is cancelled down in
the right places.
[1] http://anholt.livejournal.com/32058.html
-rw-r--r-- | src/evergreen_accel.c | 12 | ||||
-rw-r--r-- | src/evergreen_exa.c | 22 | ||||
-rw-r--r-- | src/evergreen_state.h | 2 |
3 files changed, 34 insertions, 2 deletions
diff --git a/src/evergreen_accel.c b/src/evergreen_accel.c index 10f2e511..e25010b8 100644 --- a/src/evergreen_accel.c +++ b/src/evergreen_accel.c @@ -335,7 +335,19 @@ evergreen_set_render_target(ScrnInfoPtr pScrn, cb_config_t *cb_conf, uint32_t do (CB_NORMAL << CB_COLOR_CONTROL__MODE_shift))); EREG(CB_BLEND0_CONTROL, cb_conf->blendcntl); END_BATCH(); +} +void evergreen_set_blend_color(ScrnInfoPtr pScrn, float *color) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + + BEGIN_BATCH(2 + 4); + PACK0(CB_BLEND_RED, 4); + EFLOAT(color[0]); /* R */ + EFLOAT(color[1]); /* G */ + EFLOAT(color[2]); /* B */ + EFLOAT(color[3]); /* A */ + END_BATCH(); } static void diff --git a/src/evergreen_exa.c b/src/evergreen_exa.c index 5b8a6311..ee5b06bc 100644 --- a/src/evergreen_exa.c +++ b/src/evergreen_exa.c @@ -704,6 +704,14 @@ static uint32_t EVERGREENGetBlendCntl(int op, PicturePtr pMask, uint32_t dst_for } else if (dblend == (BLEND_ONE_MINUS_SRC_ALPHA << COLOR_DESTBLEND_shift)) { dblend = (BLEND_ONE_MINUS_SRC_COLOR << COLOR_DESTBLEND_shift); } + + /* With some tricks, we can still accelerate PictOpOver with solid src. + * This is commonly used for text rendering, so it's worth the extra + * effort. + */ + if (sblend == (BLEND_ONE << COLOR_SRCBLEND_shift)) { + sblend = (BLEND_CONSTANT_COLOR << COLOR_SRCBLEND_shift); + } } return sblend | dblend; @@ -1095,12 +1103,17 @@ static Bool EVERGREENCheckComposite(int op, PicturePtr pSrcPicture, /* Check if it's component alpha that relies on a source alpha and * on the source value. We can only get one of those into the * single source value that we get to blend with. + * + * We can cheat a bit if the src is solid, though. PictOpOver + * can use the constant blend color to sneak a second blend + * source in. */ if (EVERGREENBlendOp[op].src_alpha && (EVERGREENBlendOp[op].blend_cntl & COLOR_SRCBLEND_mask) != (BLEND_ZERO << COLOR_SRCBLEND_shift)) { - RADEON_FALLBACK(("Component alpha not supported with source " - "alpha and source value blending.\n")); + if (pSrcPicture->pDrawable || op != 3) + RADEON_FALLBACK(("Component alpha not supported with source " + "alpha and source value blending.\n")); } } @@ -1196,6 +1209,11 @@ static void EVERGREENSetSolidConsts(ScrnInfoPtr pScrn, float *buf, int format, u } else { if (accel_state->component_alpha) { if (accel_state->src_alpha) { + /* required for PictOpOver */ + float cblend[4] = { pix_r / pix_a, pix_g / pix_a, + pix_b / pix_a, pix_a / pix_a }; + evergreen_set_blend_color(pScrn, cblend); + if (PICT_FORMAT_A(format) == 0) { pix_r = 1.0; pix_g = 1.0; diff --git a/src/evergreen_state.h b/src/evergreen_state.h index 3ce2bf2b..795d4472 100644 --- a/src/evergreen_state.h +++ b/src/evergreen_state.h @@ -297,6 +297,8 @@ evergreen_start_3d(ScrnInfoPtr pScrn); void evergreen_set_render_target(ScrnInfoPtr pScrn, cb_config_t *cb_conf, uint32_t domain); void +evergreen_set_blend_color(ScrnInfoPtr pScrn, float *color); +void evergreen_cp_wait_vline_sync(ScrnInfoPtr pScrn, PixmapPtr pPix, xf86CrtcPtr crtc, int start, int stop); void evergreen_set_spi(ScrnInfoPtr pScrn, int vs_export_count, int num_interp); |