[PATCH 4/4] EXA/evergreen/ni: accelerate PictOpOver with component alpha

Grigori Goronzy greg at chown.ath.cx
Sun Jul 21 21:06:06 PDT 2013


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
---
 src/evergreen_accel.c | 12 ++++++++++++
 src/evergreen_exa.c   | 22 ++++++++++++++++++++--
 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 10f2e51..e25010b 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 5b8a631..ee5b06b 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 3ce2bf2..795d447 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);
-- 
1.8.1.2



More information about the xorg-driver-ati mailing list