Subject: [PATCH 4/5] Fix the PictOpOver operation

From: "Huang, FrankR" <[email-masked]>
Date: Fri, 2 Jul 2010 16:46:47 +0800

From: Frank Huang <[email-masked]>

*Fix the PictOpOver blend_ops struct. The PictOpOver operation is
Src + (1-a) * Dest. So change from CIMGP_ALPHA_A_PLUS_BETA_B to
CIMGP_A_PLUS_BETA_B. And add one pass operation to do the
Src * (alpha of Mask) if there is a mask
*Convert the source format in lx_prepare_composite if it is not
ARGB32 when doing the first pass
*Add a function lx_do_composite_mask_opover to handle the PictOpOver
operation, the first pass is to do the Src * (alpha of Mask), the
second pass is to do the Src + (1-a) * Dest.
*Due to our off-screen buffer is only 256KB, so split big Mask region
into several small region(256KB) to do the rendering.
*Progressbar, scrollbar and button display well with this patch
*See Free Desktop Bugzilla #28352

Signed-off-by: Frank Huang <[email-masked]>
---
 src/lx_exa.c |  123 +++++++++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 109 insertions(+), 14 deletions(-)

diff --git a/src/lx_exa.c b/src/lx_exa.c
index 9631a8d..eb35c89 100644
--- a/src/lx_exa.c
+++ b/src/lx_exa.c
@@ -409,13 +409,12 @@ struct blend_ops_t
     },
 	/* PictOpOver */
     {
-    CIMGP_ALPHA_A_PLUS_BETA_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_SOURCE},
-    {
-    },
+    CIMGP_A_PLUS_BETA_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_SOURCE}, {
+    CIMGP_ALPHA_TIMES_A, CIMGP_CONVERTED_ALPHA, CIMGP_CHANNEL_A_SOURCE},
 	/* PictOpOverReverse */
     {
-    CIMGP_ALPHA_A_PLUS_BETA_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_DEST}, {
-    },
+    CIMGP_A_PLUS_BETA_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_DEST}, {
+    CIMGP_ALPHA_TIMES_A, CIMGP_CONVERTED_ALPHA, CIMGP_CHANNEL_A_DEST},
 	/* PictOpIn */
     {
     CIMGP_ALPHA_TIMES_A, CIMGP_CHANNEL_B_ALPHA, CIMGP_CHANNEL_A_SOURCE}, {
@@ -676,13 +675,21 @@ lx_prepare_composite(int op, PicturePtr pSrc, PicturePtr pMsk,
 	int direction = (opPtr->channel == CIMGP_CHANNEL_A_SOURCE) ? 0 : 1;
 
 	/* Get the source color */
+	/* If the op is PictOpOver, we should get the ARGB32 source format */
 
-	if (direction == 0)
+	if (op == PictOpOver && (srcFmt->alphabits != 0))
+	    exaScratch.srcColor = exaGetPixmapFirstPixel(pxSrc);
+	else if (op == PictOpOver && (srcFmt->alphabits == 0))
 	    exaScratch.srcColor = lx_get_source_color(pxSrc, pSrc->format,
-		pDst->format);
-	else
-	    exaScratch.srcColor = lx_get_source_color(pxDst, pDst->format,
-		pSrc->format);
+		PICT_a8r8g8b8);
+	else {
+	    if (direction == 0)
+		exaScratch.srcColor = lx_get_source_color(pxSrc, pSrc->format,
+		    pDst->format);
+	    else
+		exaScratch.srcColor = lx_get_source_color(pxDst, pDst->format,
+		    pSrc->format);
+	}
 
 	/* Save off the info we need (reuse the source values to save space) */
 
@@ -935,6 +942,84 @@ lx_do_composite_mask(PixmapPtr pxDst, unsigned long dstOffset,
 			      ((_x) * exaScratch.srcBpp))
 
 static void
+lx_do_composite_mask_opover(PixmapPtr pxDst, unsigned long dstOffset,
+    unsigned int maskOffset, int width, int height, int opX, int opY,
+    xPointFixed srcPoint)
+{
+    int apply, type;
+    struct blend_ops_t *opPtr;
+    int opWidth, opHeight;
+    int opoverX, opoverY;
+
+    opoverX = opX;
+    opoverY = opY;
+
+    /* The rendering region should not be bigger than off-screen memory size
+     * which equals to DEFAULT_EXA_SCRATCH_BFRSZ. If that happens, we split
+     * the PictOpOver rendering region into several 256KB chunks. And because
+     * of the Pitch(stride) parameter, so we use maximun width of mask picture.
+     * that is to say it is a scanline rendering process */
+    if (width * height * 4 > DEFAULT_EXA_SCRATCH_BFRSZ) {
+	opWidth = width;
+	opHeight = DEFAULT_EXA_SCRATCH_BFRSZ / (width * 4);
+    } else {
+	opWidth = width;
+	opHeight = height;
+    }
+
+    while(1) {
+
+	/* Wait until the GP is idle - this will ensure that the scratch buffer
+	 * isn't occupied */
+
+	gp_wait_until_idle();
+
+	/* Copy the source to the scratch buffer, and do a src * mask raster
+	 * operation */
+
+	gp_declare_blt(0);
+	opPtr = &lx_alpha_ops[(exaScratch.op * 2) + 1];
+	gp_set_source_format(CIMGP_SOURCE_FMT_8_8_8_8);
+	gp_set_strides(opWidth * 4, exaScratch.srcPitch);
+	gp_set_bpp(lx_get_bpp_from_format(CIMGP_SOURCE_FMT_8_8_8_8));
+	gp_set_solid_source(exaScratch.srcColor);
+	gp_blend_mask_blt(exaScratch.bufferOffset, 0, opWidth, opHeight,
+	    maskOffset, exaScratch.srcPitch, opPtr->operation,
+	    exaScratch.fourBpp);
+
+	/* Do a PictOpOver operation(src + (1-a) * dst), and copy the operation
+	 * result to destination */
+
+	gp_declare_blt(CIMGP_BLTFLAGS_HAZARD);
+	opPtr = &lx_alpha_ops[exaScratch.op * 2];
+	apply = (exaScratch.dstFormat->alphabits == 0) ?
+	    CIMGP_APPLY_BLEND_TO_RGB : CIMGP_APPLY_BLEND_TO_ALL;
+	gp_set_source_format(CIMGP_SOURCE_FMT_8_8_8_8);
+	gp_set_strides(exaGetPixmapPitch(pxDst), opWidth * 4);
+	gp_set_bpp(lx_get_bpp_from_format(exaScratch.dstFormat->fmt));
+	type = CIMGP_CONVERTED_ALPHA;
+	gp_set_alpha_operation(opPtr->operation, type, opPtr->channel,
+	    apply, 0);
+	gp_screen_to_screen_convert(dstOffset, exaScratch.bufferOffset,
+	    opWidth, opHeight, 0);
+
+	if (width * height * 4 > DEFAULT_EXA_SCRATCH_BFRSZ) {
+	    /* Finish the rendering */
+	    if (opoverY + opHeight == opY + height)
+		break;
+	    /* Recalculate the Dest and Mask rendering start point */
+	    srcPoint.y = srcPoint.y + opHeight;
+	    opoverY = opoverY + opHeight;
+	    if (opoverY + opHeight > opY + height)
+		opHeight = opY + height - opoverY;
+	    dstOffset = GetPixmapOffset(pxDst, opoverX, opoverY);
+	    maskOffset = GetSrcOffset(srcPoint.x, srcPoint.y);
+	} else
+	    break;
+    }
+}
+
+static void
 transformPoint(PictTransform * t, xPointFixed * point)
 {
     PictVector v;
@@ -1058,11 +1143,21 @@ lx_do_composite(PixmapPtr pxDst, int srcX, int srcY, int maskX,
 		if (direction == 1) {
 		    dstOffset =
 			GetPixmapOffset(exaScratch.srcPixmap, opX, opY);
-		    lx_do_composite_mask(exaScratch.srcPixmap, dstOffset,
-			srcOffset, opWidth, opHeight);
+		    if (exaScratch.op == PictOpOver)
+			lx_do_composite_mask_opover(exaScratch.srcPixmap,
+			    dstOffset, srcOffset, opWidth, opHeight,
+			    opX, opY, srcPoint);
+		    else
+			lx_do_composite_mask(exaScratch.srcPixmap, dstOffset,
+			    srcOffset, opWidth, opHeight);
+
 		} else {
-		    lx_do_composite_mask(pxDst, dstOffset, srcOffset, opWidth,
-			opHeight);
+		    if (exaScratch.op == PictOpOver)
+			lx_do_composite_mask_opover(pxDst, dstOffset,
+			    srcOffset, opWidth, opHeight, opX, opY, srcPoint);
+		    else
+			lx_do_composite_mask(pxDst, dstOffset, srcOffset,
+			    opWidth, opHeight);
 		}
 	    }
 	    break;
-- 
1.7.1

_______________________________________________
Xorg-driver-geode mailing list
[email-masked]
http://lists.x.org/mailman/listinfo/xorg-driver-geode