From a0b4a1330be6a36ad095222d2ea83927cd33514d Mon Sep 17 00:00:00 2001 From: marha Date: Fri, 25 Nov 2011 08:22:48 +0100 Subject: mesa xserver pixman git update 25 nov 2011 --- xorg-server/exa/exa_render.c | 2512 +++++++++++++++++++++--------------------- 1 file changed, 1256 insertions(+), 1256 deletions(-) (limited to 'xorg-server/exa') diff --git a/xorg-server/exa/exa_render.c b/xorg-server/exa/exa_render.c index 026f5d16d..3974afe87 100644 --- a/xorg-server/exa/exa_render.c +++ b/xorg-server/exa/exa_render.c @@ -1,1256 +1,1256 @@ -/* - * Copyright © 2001 Keith Packard - * - * Partly based on code that is Copyright © The XFree86 Project Inc. - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of Keith Packard not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Keith Packard makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. - * - * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include - -#include "exa_priv.h" - -#include "mipict.h" - -#if DEBUG_TRACE_FALL -static void exaCompositeFallbackPictDesc(PicturePtr pict, char *string, int n) -{ - char format[20]; - char size[20]; - char loc; - int temp; - - if (!pict) { - snprintf(string, n, "None"); - return; - } - - switch (pict->format) - { - case PICT_a8r8g8b8: - snprintf(format, 20, "ARGB8888"); - break; - case PICT_x8r8g8b8: - snprintf(format, 20, "XRGB8888"); - break; - case PICT_b8g8r8a8: - snprintf(format, 20, "BGRA8888"); - break; - case PICT_b8g8r8x8: - snprintf(format, 20, "BGRX8888"); - break; - case PICT_r5g6b5: - snprintf(format, 20, "RGB565 "); - break; - case PICT_x1r5g5b5: - snprintf(format, 20, "RGB555 "); - break; - case PICT_a8: - snprintf(format, 20, "A8 "); - break; - case PICT_a1: - snprintf(format, 20, "A1 "); - break; - default: - snprintf(format, 20, "0x%x", (int)pict->format); - break; - } - - if (pict->pDrawable) { - loc = exaGetOffscreenPixmap(pict->pDrawable, &temp, &temp) ? 's' : 'm'; - - snprintf(size, 20, "%dx%d%s", pict->pDrawable->width, - pict->pDrawable->height, pict->repeat ? - " R" : ""); - } else { - loc = '-'; - - snprintf(size, 20, "%s", pict->repeat ? " R" : ""); - } - - snprintf(string, n, "%p:%c fmt %s (%s)", pict->pDrawable, loc, format, size); -} - -static void -exaPrintCompositeFallback(CARD8 op, - PicturePtr pSrc, - PicturePtr pMask, - PicturePtr pDst) -{ - char sop[20]; - char srcdesc[40], maskdesc[40], dstdesc[40]; - - switch(op) - { - case PictOpSrc: - sprintf(sop, "Src"); - break; - case PictOpOver: - sprintf(sop, "Over"); - break; - default: - sprintf(sop, "0x%x", (int)op); - break; - } - - exaCompositeFallbackPictDesc(pSrc, srcdesc, 40); - exaCompositeFallbackPictDesc(pMask, maskdesc, 40); - exaCompositeFallbackPictDesc(pDst, dstdesc, 40); - - ErrorF("Composite fallback: op %s, \n" - " src %s, \n" - " mask %s, \n" - " dst %s, \n", - sop, srcdesc, maskdesc, dstdesc); -} -#endif /* DEBUG_TRACE_FALL */ - -Bool -exaOpReadsDestination (CARD8 op) -{ - /* FALSE (does not read destination) is the list of ops in the protocol - * document with "0" in the "Fb" column and no "Ab" in the "Fa" column. - * That's just Clear and Src. ReduceCompositeOp() will already have - * converted con/disjoint clear/src to Clear or Src. - */ - switch (op) { - case PictOpClear: - case PictOpSrc: - return FALSE; - default: - return TRUE; - } -} - - -static Bool -exaGetPixelFromRGBA(CARD32 *pixel, - CARD16 red, - CARD16 green, - CARD16 blue, - CARD16 alpha, - PictFormatPtr pFormat) -{ - int rbits, bbits, gbits, abits; - int rshift, bshift, gshift, ashift; - - *pixel = 0; - - if (!PICT_FORMAT_COLOR(pFormat->format) && - PICT_FORMAT_TYPE(pFormat->format) != PICT_TYPE_A) - return FALSE; - - rbits = PICT_FORMAT_R(pFormat->format); - gbits = PICT_FORMAT_G(pFormat->format); - bbits = PICT_FORMAT_B(pFormat->format); - abits = PICT_FORMAT_A(pFormat->format); - - rshift = pFormat->direct.red; - gshift = pFormat->direct.green; - bshift = pFormat->direct.blue; - ashift = pFormat->direct.alpha; - - *pixel |= ( blue >> (16 - bbits)) << bshift; - *pixel |= ( red >> (16 - rbits)) << rshift; - *pixel |= (green >> (16 - gbits)) << gshift; - *pixel |= (alpha >> (16 - abits)) << ashift; - - return TRUE; -} - -static Bool -exaGetRGBAFromPixel(CARD32 pixel, - CARD16 *red, - CARD16 *green, - CARD16 *blue, - CARD16 *alpha, - PictFormatPtr pFormat, - PictFormatShort format) -{ - int rbits, bbits, gbits, abits; - int rshift, bshift, gshift, ashift; - - if (!PICT_FORMAT_COLOR(format) && PICT_FORMAT_TYPE(format) != PICT_TYPE_A) - return FALSE; - - rbits = PICT_FORMAT_R(format); - gbits = PICT_FORMAT_G(format); - bbits = PICT_FORMAT_B(format); - abits = PICT_FORMAT_A(format); - - if (pFormat) { - rshift = pFormat->direct.red; - gshift = pFormat->direct.green; - bshift = pFormat->direct.blue; - ashift = pFormat->direct.alpha; - } else if (format == PICT_a8r8g8b8) { - rshift = 16; - gshift = 8; - bshift = 0; - ashift = 24; - } else - FatalError("EXA bug: exaGetRGBAFromPixel() doesn't match " - "createSourcePicture()\n"); - - if (rbits) { - *red = ((pixel >> rshift ) & ((1 << rbits) - 1)) << (16 - rbits); - while (rbits < 16) { - *red |= *red >> rbits; - rbits <<= 1; - } - - *green = ((pixel >> gshift ) & ((1 << gbits) - 1)) << (16 - gbits); - while (gbits < 16) { - *green |= *green >> gbits; - gbits <<= 1; - } - - *blue = ((pixel >> bshift ) & ((1 << bbits) - 1)) << (16 - bbits); - while (bbits < 16) { - *blue |= *blue >> bbits; - bbits <<= 1; - } - } else { - *red = 0x0000; - *green = 0x0000; - *blue = 0x0000; - } - - if (abits) { - *alpha = ((pixel >> ashift ) & ((1 << abits) - 1)) << (16 - abits); - while (abits < 16) { - *alpha |= *alpha >> abits; - abits <<= 1; - } - } else - *alpha = 0xffff; - - return TRUE; -} - -static int -exaTryDriverSolidFill(PicturePtr pSrc, - PicturePtr pDst, - INT16 xSrc, - INT16 ySrc, - INT16 xDst, - INT16 yDst, - CARD16 width, - CARD16 height) -{ - ExaScreenPriv (pDst->pDrawable->pScreen); - RegionRec region; - BoxPtr pbox; - int nbox; - int dst_off_x, dst_off_y; - PixmapPtr pSrcPix, pDstPix; - ExaPixmapPrivPtr pDstExaPix; - CARD32 pixel; - CARD16 red, green, blue, alpha; - - pDstPix = exaGetDrawablePixmap (pDst->pDrawable); - pDstExaPix = ExaGetPixmapPriv(pDstPix); - - /* Check whether the accelerator can use the destination pixmap. - */ - if (pDstExaPix->accel_blocked) - { - return -1; - } - - xDst += pDst->pDrawable->x; - yDst += pDst->pDrawable->y; - if (pSrc->pDrawable) { - xSrc += pSrc->pDrawable->x; - ySrc += pSrc->pDrawable->y; - } - - if (!miComputeCompositeRegion (®ion, pSrc, NULL, pDst, - xSrc, ySrc, 0, 0, xDst, yDst, - width, height)) - return 1; - - exaGetDrawableDeltas (pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y); - - RegionTranslate(®ion, dst_off_x, dst_off_y); - - if (pSrc->pDrawable) { - pSrcPix = exaGetDrawablePixmap (pSrc->pDrawable); - pixel = exaGetPixmapFirstPixel (pSrcPix); - } else - pixel = pSrc->pSourcePict->solidFill.color; - - if (!exaGetRGBAFromPixel(pixel, &red, &green, &blue, &alpha, - pSrc->pFormat, pSrc->format) || - !exaGetPixelFromRGBA(&pixel, red, green, blue, alpha, - pDst->pFormat)) - { - RegionUninit(®ion); - return -1; - } - - if (pExaScr->do_migration) { - ExaMigrationRec pixmaps[1]; - - pixmaps[0].as_dst = TRUE; - pixmaps[0].as_src = FALSE; - pixmaps[0].pPix = pDstPix; - pixmaps[0].pReg = ®ion; - exaDoMigration(pixmaps, 1, TRUE); - } - - if (!exaPixmapHasGpuCopy(pDstPix)) { - RegionUninit(®ion); - return 0; - } - - if (!(*pExaScr->info->PrepareSolid) (pDstPix, GXcopy, 0xffffffff, pixel)) - { - RegionUninit(®ion); - return -1; - } - - nbox = RegionNumRects(®ion); - pbox = RegionRects(®ion); - - while (nbox--) - { - (*pExaScr->info->Solid) (pDstPix, pbox->x1, pbox->y1, pbox->x2, pbox->y2); - pbox++; - } - - (*pExaScr->info->DoneSolid) (pDstPix); - exaMarkSync(pDst->pDrawable->pScreen); - - RegionUninit(®ion); - return 1; -} - -static int -exaTryDriverCompositeRects(CARD8 op, - PicturePtr pSrc, - PicturePtr pMask, - PicturePtr pDst, - int nrect, - ExaCompositeRectPtr rects) -{ - ExaScreenPriv (pDst->pDrawable->pScreen); - int src_off_x = 0, src_off_y = 0, mask_off_x = 0, mask_off_y = 0; - int dst_off_x, dst_off_y; - PixmapPtr pSrcPix = NULL, pMaskPix = NULL, pDstPix; - ExaPixmapPrivPtr pSrcExaPix = NULL, pMaskExaPix = NULL, pDstExaPix; - - if (!pExaScr->info->PrepareComposite) - return -1; - - if (pSrc->pDrawable) { - pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable); - pSrcExaPix = ExaGetPixmapPriv(pSrcPix); - } - - if (pMask && pMask->pDrawable) { - pMaskPix = exaGetDrawablePixmap(pMask->pDrawable); - pMaskExaPix = ExaGetPixmapPriv(pMaskPix); - } - - pDstPix = exaGetDrawablePixmap(pDst->pDrawable); - pDstExaPix = ExaGetPixmapPriv(pDstPix); - - /* Check whether the accelerator can use these pixmaps. - * FIXME: If it cannot, use temporary pixmaps so that the drawing - * happens within limits. - */ - if (pDstExaPix->accel_blocked || - (pSrcExaPix && pSrcExaPix->accel_blocked) || - (pMaskExaPix && pMaskExaPix->accel_blocked)) - { - return -1; - } - - if (pExaScr->info->CheckComposite && - !(*pExaScr->info->CheckComposite) (op, pSrc, pMask, pDst)) - { - return -1; - } - - if (pExaScr->do_migration) { - ExaMigrationRec pixmaps[3]; - int i = 0; - - pixmaps[i].as_dst = TRUE; - pixmaps[i].as_src = exaOpReadsDestination(op); - pixmaps[i].pPix = pDstPix; - pixmaps[i].pReg = NULL; - i++; - - if (pSrcPix) { - pixmaps[i].as_dst = FALSE; - pixmaps[i].as_src = TRUE; - pixmaps[i].pPix = pSrcPix; - pixmaps[i].pReg = NULL; - i++; - } - - if (pMaskPix) { - pixmaps[i].as_dst = FALSE; - pixmaps[i].as_src = TRUE; - pixmaps[i].pPix = pMaskPix; - pixmaps[i].pReg = NULL; - i++; - } - - exaDoMigration(pixmaps, i, TRUE); - } - - pDstPix = exaGetOffscreenPixmap (pDst->pDrawable, &dst_off_x, &dst_off_y); - if (!pDstPix) - return 0; - - if (pSrcPix) { - pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y); - if (!pSrcPix) - return 0; - } - - if (pMaskPix) { - pMaskPix = exaGetOffscreenPixmap (pMask->pDrawable, &mask_off_x, &mask_off_y); - if (!pMaskPix) - return 0; - } - - if (!(*pExaScr->info->PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix, - pMaskPix, pDstPix)) - return -1; - - while (nrect--) - { - INT16 xDst = rects->xDst + pDst->pDrawable->x; - INT16 yDst = rects->yDst + pDst->pDrawable->y; - INT16 xMask = rects->xMask; - INT16 yMask = rects->yMask; - INT16 xSrc = rects->xSrc; - INT16 ySrc = rects->ySrc; - RegionRec region; - BoxPtr pbox; - int nbox; - - if (pMaskPix) { - xMask += pMask->pDrawable->x; - yMask += pMask->pDrawable->y; - } - - if (pSrcPix) { - xSrc += pSrc->pDrawable->x; - ySrc += pSrc->pDrawable->y; - } - - if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, - xSrc, ySrc, xMask, yMask, xDst, yDst, - rects->width, rects->height)) - goto next_rect; - - RegionTranslate(®ion, dst_off_x, dst_off_y); - - nbox = RegionNumRects(®ion); - pbox = RegionRects(®ion); - - xMask = xMask + mask_off_x - xDst - dst_off_x; - yMask = yMask + mask_off_y - yDst - dst_off_y; - xSrc = xSrc + src_off_x - xDst - dst_off_x; - ySrc = ySrc + src_off_y - yDst - dst_off_y; - - while (nbox--) - { - (*pExaScr->info->Composite) (pDstPix, - pbox->x1 + xSrc, - pbox->y1 + ySrc, - pbox->x1 + xMask, - pbox->y1 + yMask, - pbox->x1, - pbox->y1, - pbox->x2 - pbox->x1, - pbox->y2 - pbox->y1); - pbox++; - } - - next_rect: - RegionUninit(®ion); - - rects++; - } - - (*pExaScr->info->DoneComposite) (pDstPix); - exaMarkSync(pDst->pDrawable->pScreen); - - return 1; -} - -/** - * Copy a number of rectangles from source to destination in a single - * operation. This is specialized for glyph rendering: we don't have the - * special-case fallbacks found in exaComposite() - if the driver can support - * it, we use the driver functionality, otherwise we fall back straight to - * software. - */ -void -exaCompositeRects(CARD8 op, - PicturePtr pSrc, - PicturePtr pMask, - PicturePtr pDst, - int nrect, - ExaCompositeRectPtr rects) -{ - ExaScreenPriv (pDst->pDrawable->pScreen); - int n; - ExaCompositeRectPtr r; - int ret; - - /* If we get a mask, that means we're rendering to the exaGlyphs - * destination directly, so the damage layer takes care of this. - */ - if (!pMask) { - RegionRec region; - int x1 = MAXSHORT; - int y1 = MAXSHORT; - int x2 = MINSHORT; - int y2 = MINSHORT; - BoxRec box; - - /* We have to manage the damage ourselves, since CompositeRects isn't - * something in the screen that can be managed by the damage extension, - * and EXA depends on damage to track what needs to be migrated between - * the gpu and the cpu. - */ - - /* Compute the overall extents of the composited region - we're making - * the assumption here that we are compositing a bunch of glyphs that - * cluster closely together and damaging each glyph individually would - * be a loss compared to damaging the bounding box. - */ - n = nrect; - r = rects; - while (n--) { - int rect_x2 = r->xDst + r->width; - int rect_y2 = r->yDst + r->height; - - if (r->xDst < x1) x1 = r->xDst; - if (r->yDst < y1) y1 = r->yDst; - if (rect_x2 > x2) x2 = rect_x2; - if (rect_y2 > y2) y2 = rect_y2; - - r++; - } - - if (x2 <= x1 || y2 <= y1) - return; - - box.x1 = x1; - box.x2 = x2 < MAXSHORT ? x2 : MAXSHORT; - box.y1 = y1; - box.y2 = y2 < MAXSHORT ? y2 : MAXSHORT; - - /* The pixmap migration code relies on pendingDamage indicating - * the bounds of the current rendering, so we need to force - * the actual damage into that region before we do anything, and - * (see use of DamagePendingRegion in exaCopyDirty) - */ - - RegionInit(®ion, &box, 1); - - DamageRegionAppend(pDst->pDrawable, ®ion); - - RegionUninit(®ion); - } - - /************************************************************/ - - ValidatePicture (pSrc); - if (pMask) - ValidatePicture (pMask); - ValidatePicture (pDst); - - ret = exaTryDriverCompositeRects(op, pSrc, pMask, pDst, nrect, rects); - - if (ret != 1) { - if (ret == -1 && op == PictOpOver && pMask && pMask->componentAlpha && - (!pExaScr->info->CheckComposite || - ((*pExaScr->info->CheckComposite)(PictOpOutReverse, pSrc, pMask, - pDst) && - (*pExaScr->info->CheckComposite)(PictOpAdd, pSrc, pMask, pDst)))) { - ret = exaTryDriverCompositeRects(PictOpOutReverse, pSrc, pMask, - pDst, nrect, rects); - if (ret == 1) { - op = PictOpAdd; - ret = exaTryDriverCompositeRects(op, pSrc, pMask, pDst, nrect, - rects); - } - } - - if (ret != 1) { - n = nrect; - r = rects; - while (n--) { - ExaCheckComposite (op, pSrc, pMask, pDst, - r->xSrc, r->ySrc, - r->xMask, r->yMask, - r->xDst, r->yDst, - r->width, r->height); - r++; - } - } - } - - /************************************************************/ - - if (!pMask) { - /* Now we have to flush the damage out from pendingDamage => damage - * Calling DamageRegionProcessPending has that effect. - */ - - DamageRegionProcessPending(pDst->pDrawable); - } -} - -static int -exaTryDriverComposite(CARD8 op, - PicturePtr pSrc, - PicturePtr pMask, - PicturePtr pDst, - INT16 xSrc, - INT16 ySrc, - INT16 xMask, - INT16 yMask, - INT16 xDst, - INT16 yDst, - CARD16 width, - CARD16 height) -{ - ExaScreenPriv (pDst->pDrawable->pScreen); - RegionRec region; - BoxPtr pbox; - int nbox; - int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y; - PixmapPtr pSrcPix = NULL, pMaskPix = NULL, pDstPix; - ExaPixmapPrivPtr pSrcExaPix = NULL, pMaskExaPix = NULL, pDstExaPix; - - if (pSrc->pDrawable) { - pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable); - pSrcExaPix = ExaGetPixmapPriv(pSrcPix); - } - - pDstPix = exaGetDrawablePixmap(pDst->pDrawable); - pDstExaPix = ExaGetPixmapPriv(pDstPix); - - if (pMask && pMask->pDrawable) { - pMaskPix = exaGetDrawablePixmap(pMask->pDrawable); - pMaskExaPix = ExaGetPixmapPriv(pMaskPix); - } - - /* Check whether the accelerator can use these pixmaps. - * FIXME: If it cannot, use temporary pixmaps so that the drawing - * happens within limits. - */ - if (pDstExaPix->accel_blocked || - (pSrcExaPix && pSrcExaPix->accel_blocked) || - (pMaskExaPix && (pMaskExaPix->accel_blocked))) - { - return -1; - } - - xDst += pDst->pDrawable->x; - yDst += pDst->pDrawable->y; - - if (pMaskPix) { - xMask += pMask->pDrawable->x; - yMask += pMask->pDrawable->y; - } - - if (pSrcPix) { - xSrc += pSrc->pDrawable->x; - ySrc += pSrc->pDrawable->y; - } - - if (pExaScr->info->CheckComposite && - !(*pExaScr->info->CheckComposite) (op, pSrc, pMask, pDst)) - { - return -1; - } - - if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, - xSrc, ySrc, xMask, yMask, xDst, yDst, - width, height)) - return 1; - - exaGetDrawableDeltas (pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y); - - RegionTranslate(®ion, dst_off_x, dst_off_y); - - if (pExaScr->do_migration) { - ExaMigrationRec pixmaps[3]; - int i = 0; - - pixmaps[i].as_dst = TRUE; - pixmaps[i].as_src = exaOpReadsDestination(op); - pixmaps[i].pPix = pDstPix; - pixmaps[i].pReg = pixmaps[0].as_src ? NULL : ®ion; - i++; - - if (pSrcPix) { - pixmaps[i].as_dst = FALSE; - pixmaps[i].as_src = TRUE; - pixmaps[i].pPix = pSrcPix; - pixmaps[i].pReg = NULL; - i++; - } - - if (pMaskPix) { - pixmaps[i].as_dst = FALSE; - pixmaps[i].as_src = TRUE; - pixmaps[i].pPix = pMaskPix; - pixmaps[i].pReg = NULL; - i++; - } - - exaDoMigration(pixmaps, i, TRUE); - } - - if (pSrcPix) { - pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y); - if (!pSrcPix) { - RegionUninit(®ion); - return 0; - } - } - - if (pMaskPix) { - pMaskPix = exaGetOffscreenPixmap (pMask->pDrawable, &mask_off_x, - &mask_off_y); - if (!pMaskPix) { - RegionUninit(®ion); - return 0; - } - } - - if (!exaPixmapHasGpuCopy(pDstPix)) { - RegionUninit(®ion); - return 0; - } - - if (!(*pExaScr->info->PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix, - pMaskPix, pDstPix)) - { - RegionUninit(®ion); - return -1; - } - - nbox = RegionNumRects(®ion); - pbox = RegionRects(®ion); - - xMask = xMask + mask_off_x - xDst - dst_off_x; - yMask = yMask + mask_off_y - yDst - dst_off_y; - - xSrc = xSrc + src_off_x - xDst - dst_off_x; - ySrc = ySrc + src_off_y - yDst - dst_off_y; - - while (nbox--) - { - (*pExaScr->info->Composite) (pDstPix, - pbox->x1 + xSrc, - pbox->y1 + ySrc, - pbox->x1 + xMask, - pbox->y1 + yMask, - pbox->x1, - pbox->y1, - pbox->x2 - pbox->x1, - pbox->y2 - pbox->y1); - pbox++; - } - (*pExaScr->info->DoneComposite) (pDstPix); - exaMarkSync(pDst->pDrawable->pScreen); - - RegionUninit(®ion); - return 1; -} - -/** - * exaTryMagicTwoPassCompositeHelper implements PictOpOver using two passes of - * simpler operations PictOpOutReverse and PictOpAdd. Mainly used for component - * alpha and limited 1-tmu cards. - * - * From http://anholt.livejournal.com/32058.html: - * - * The trouble is that component-alpha rendering requires two different sources - * for blending: one for the source value to the blender, which is the - * per-channel multiplication of source and mask, and one for the source alpha - * for multiplying with the destination channels, which is the multiplication - * of the source channels by the mask alpha. So the equation for Over is: - * - * dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A - * dst.R = src.R * mask.R + (1 - (src.A * mask.R)) * dst.R - * dst.G = src.G * mask.G + (1 - (src.A * mask.G)) * dst.G - * dst.B = src.B * mask.B + (1 - (src.A * mask.B)) * dst.B - * - * But we can do some simpler operations, right? How about PictOpOutReverse, - * which has a source factor of 0 and dest factor of (1 - source alpha). We - * can get the source alpha value (srca.X = src.A * mask.X) out of the texture - * blenders pretty easily. So we can do a component-alpha OutReverse, which - * gets us: - * - * dst.A = 0 + (1 - (src.A * mask.A)) * dst.A - * dst.R = 0 + (1 - (src.A * mask.R)) * dst.R - * dst.G = 0 + (1 - (src.A * mask.G)) * dst.G - * dst.B = 0 + (1 - (src.A * mask.B)) * dst.B - * - * OK. And if an op doesn't use the source alpha value for the destination - * factor, then we can do the channel multiplication in the texture blenders - * to get the source value, and ignore the source alpha that we wouldn't use. - * We've supported this in the Radeon driver for a long time. An example would - * be PictOpAdd, which does: - * - * dst.A = src.A * mask.A + dst.A - * dst.R = src.R * mask.R + dst.R - * dst.G = src.G * mask.G + dst.G - * dst.B = src.B * mask.B + dst.B - * - * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right - * after it, we get: - * - * dst.A = src.A * mask.A + ((1 - (src.A * mask.A)) * dst.A) - * dst.R = src.R * mask.R + ((1 - (src.A * mask.R)) * dst.R) - * dst.G = src.G * mask.G + ((1 - (src.A * mask.G)) * dst.G) - * dst.B = src.B * mask.B + ((1 - (src.A * mask.B)) * dst.B) - */ - -static int -exaTryMagicTwoPassCompositeHelper(CARD8 op, - PicturePtr pSrc, - PicturePtr pMask, - PicturePtr pDst, - INT16 xSrc, - INT16 ySrc, - INT16 xMask, - INT16 yMask, - INT16 xDst, - INT16 yDst, - CARD16 width, - CARD16 height) -{ - ExaScreenPriv (pDst->pDrawable->pScreen); - - assert(op == PictOpOver); - - if (pExaScr->info->CheckComposite && - (!(*pExaScr->info->CheckComposite)(PictOpOutReverse, pSrc, pMask, - pDst) || - !(*pExaScr->info->CheckComposite)(PictOpAdd, pSrc, pMask, pDst))) - { - return -1; - } - - /* Now, we think we should be able to accelerate this operation. First, - * composite the destination to be the destination times the source alpha - * factors. - */ - exaComposite(PictOpOutReverse, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, - xDst, yDst, width, height); - - /* Then, add in the source value times the destination alpha factors (1.0). - */ - exaComposite(PictOpAdd, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, - xDst, yDst, width, height); - - return 1; -} - -void -exaComposite(CARD8 op, - PicturePtr pSrc, - PicturePtr pMask, - PicturePtr pDst, - INT16 xSrc, - INT16 ySrc, - INT16 xMask, - INT16 yMask, - INT16 xDst, - INT16 yDst, - CARD16 width, - CARD16 height) -{ - ExaScreenPriv (pDst->pDrawable->pScreen); - int ret = -1; - Bool saveSrcRepeat = pSrc->repeat; - Bool saveMaskRepeat = pMask ? pMask->repeat : 0; - RegionRec region; - - if (pExaScr->swappedOut) - goto fallback; - - /* Remove repeat in source if useless */ - if (pSrc->pDrawable && pSrc->repeat && !pSrc->transform && xSrc >= 0 && - (xSrc + width) <= pSrc->pDrawable->width && ySrc >= 0 && - (ySrc + height) <= pSrc->pDrawable->height) - pSrc->repeat = 0; - - if (!pMask && !pSrc->alphaMap && !pDst->alphaMap && - (op == PictOpSrc || (op == PictOpOver && !PICT_FORMAT_A(pSrc->format)))) - { - if (pSrc->pDrawable ? - (pSrc->pDrawable->width == 1 && pSrc->pDrawable->height == 1 && - pSrc->repeat) : - (pSrc->pSourcePict->type == SourcePictTypeSolidFill)) - { - ret = exaTryDriverSolidFill(pSrc, pDst, xSrc, ySrc, xDst, yDst, - width, height); - if (ret == 1) - goto done; - } else if (pSrc->pDrawable && !pSrc->transform && - ((op == PictOpSrc && - (pSrc->format == pDst->format || - (PICT_FORMAT_COLOR(pDst->format) && - PICT_FORMAT_COLOR(pSrc->format) && - pDst->format == PICT_FORMAT(PICT_FORMAT_BPP(pSrc->format), - PICT_FORMAT_TYPE(pSrc->format), - 0, - PICT_FORMAT_R(pSrc->format), - PICT_FORMAT_G(pSrc->format), - PICT_FORMAT_B(pSrc->format))))) || - (op == PictOpOver && pSrc->format == pDst->format && - !PICT_FORMAT_A(pSrc->format)))) - { - if (!pSrc->repeat && xSrc >= 0 && ySrc >= 0 && - (xSrc + width <= pSrc->pDrawable->width) && - (ySrc + height <= pSrc->pDrawable->height)) - { - Bool ret; - xDst += pDst->pDrawable->x; - yDst += pDst->pDrawable->y; - xSrc += pSrc->pDrawable->x; - ySrc += pSrc->pDrawable->y; - - if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, - xSrc, ySrc, xMask, yMask, xDst, - yDst, width, height)) - goto done; - - ret = exaHWCopyNtoN(pSrc->pDrawable, pDst->pDrawable, NULL, - RegionRects(®ion), RegionNumRects(®ion), - xSrc - xDst, ySrc - yDst, FALSE, FALSE); - RegionUninit(®ion); - - /* Reset values to their original values. */ - xDst -= pDst->pDrawable->x; - yDst -= pDst->pDrawable->y; - xSrc -= pSrc->pDrawable->x; - ySrc -= pSrc->pDrawable->y; - - if (!ret) - goto fallback; - - goto done; - } - - if (pSrc->repeat && pSrc->repeatType == RepeatNormal && - pSrc->pDrawable->type == DRAWABLE_PIXMAP) - { - DDXPointRec patOrg; - - /* Let's see if the driver can do the repeat in one go */ - if (pExaScr->info->PrepareComposite && !pSrc->alphaMap && - !pDst->alphaMap) - { - ret = exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc, - ySrc, xMask, yMask, xDst, yDst, - width, height); - if (ret == 1) - goto done; - } - - /* Now see if we can use exaFillRegionTiled() */ - xDst += pDst->pDrawable->x; - yDst += pDst->pDrawable->y; - xSrc += pSrc->pDrawable->x; - ySrc += pSrc->pDrawable->y; - - if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, xSrc, - ySrc, xMask, yMask, xDst, yDst, - width, height)) - goto done; - - /* pattern origin is the point in the destination drawable - * corresponding to (0,0) in the source */ - patOrg.x = xDst - xSrc; - patOrg.y = yDst - ySrc; - - ret = exaFillRegionTiled(pDst->pDrawable, ®ion, - (PixmapPtr)pSrc->pDrawable, - &patOrg, FB_ALLONES, GXcopy, CT_NONE); - - RegionUninit(®ion); - - if (ret) - goto done; - - /* Let's be correct and restore the variables to their original state. */ - xDst -= pDst->pDrawable->x; - yDst -= pDst->pDrawable->y; - xSrc -= pSrc->pDrawable->x; - ySrc -= pSrc->pDrawable->y; - } - } - } - - /* Remove repeat in mask if useless */ - if (pMask && pMask->pDrawable && pMask->repeat && !pMask->transform && - xMask >= 0 && (xMask + width) <= pMask->pDrawable->width && - yMask >= 0 && (yMask + height) <= pMask->pDrawable->height) - pMask->repeat = 0; - - if (pExaScr->info->PrepareComposite && - !pSrc->alphaMap && (!pMask || !pMask->alphaMap) && !pDst->alphaMap) - { - Bool isSrcSolid; - - ret = exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask, - yMask, xDst, yDst, width, height); - if (ret == 1) - goto done; - - /* For generic masks and solid src pictures, mach64 can do Over in two - * passes, similar to the component-alpha case. - */ - isSrcSolid = pSrc->pDrawable ? - (pSrc->pDrawable->width == 1 && pSrc->pDrawable->height == 1 && - pSrc->repeat) : - (pSrc->pSourcePict->type == SourcePictTypeSolidFill); - - /* If we couldn't do the Composite in a single pass, and it was a - * component-alpha Over, see if we can do it in two passes with - * an OutReverse and then an Add. - */ - if (ret == -1 && op == PictOpOver && pMask && - (pMask->componentAlpha || isSrcSolid)) { - ret = exaTryMagicTwoPassCompositeHelper(op, pSrc, pMask, pDst, - xSrc, ySrc, - xMask, yMask, xDst, yDst, - width, height); - if (ret == 1) - goto done; - } - } - -fallback: -#if DEBUG_TRACE_FALL - exaPrintCompositeFallback (op, pSrc, pMask, pDst); -#endif - - ExaCheckComposite (op, pSrc, pMask, pDst, xSrc, ySrc, - xMask, yMask, xDst, yDst, width, height); - -done: - pSrc->repeat = saveSrcRepeat; - if (pMask) - pMask->repeat = saveMaskRepeat; -} - -/** - * Same as miCreateAlphaPicture, except it uses ExaCheckPolyFillRect instead - * of PolyFillRect to initialize the pixmap after creating it, to prevent - * the pixmap from being migrated. - * - * See the comments about exaTrapezoids and exaTriangles. - */ -static PicturePtr -exaCreateAlphaPicture (ScreenPtr pScreen, - PicturePtr pDst, - PictFormatPtr pPictFormat, - CARD16 width, - CARD16 height) -{ - PixmapPtr pPixmap; - PicturePtr pPicture; - GCPtr pGC; - int error; - xRectangle rect; - - if (width > 32767 || height > 32767) - return 0; - - if (!pPictFormat) - { - if (pDst->polyEdge == PolyEdgeSharp) - pPictFormat = PictureMatchFormat (pScreen, 1, PICT_a1); - else - pPictFormat = PictureMatchFormat (pScreen, 8, PICT_a8); - if (!pPictFormat) - return 0; - } - - pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, - pPictFormat->depth, 0); - if (!pPixmap) - return 0; - pGC = GetScratchGC (pPixmap->drawable.depth, pScreen); - if (!pGC) - { - (*pScreen->DestroyPixmap) (pPixmap); - return 0; - } - ValidateGC (&pPixmap->drawable, pGC); - rect.x = 0; - rect.y = 0; - rect.width = width; - rect.height = height; - ExaCheckPolyFillRect (&pPixmap->drawable, pGC, 1, &rect); - exaPixmapDirty (pPixmap, 0, 0, width, height); - FreeScratchGC (pGC); - pPicture = CreatePicture (0, &pPixmap->drawable, pPictFormat, - 0, 0, serverClient, &error); - (*pScreen->DestroyPixmap) (pPixmap); - return pPicture; -} - -/** - * exaTrapezoids is essentially a copy of miTrapezoids that uses - * exaCreateAlphaPicture instead of miCreateAlphaPicture. - * - * The problem with miCreateAlphaPicture is that it calls PolyFillRect - * to initialize the contents after creating the pixmap, which - * causes the pixmap to be moved in for acceleration. The subsequent - * call to RasterizeTrapezoid won't be accelerated however, which - * forces the pixmap to be moved out again. - * - * exaCreateAlphaPicture avoids this roundtrip by using ExaCheckPolyFillRect - * to initialize the contents. - */ -void -exaTrapezoids (CARD8 op, PicturePtr pSrc, PicturePtr pDst, - PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, - int ntrap, xTrapezoid *traps) -{ - ScreenPtr pScreen = pDst->pDrawable->pScreen; - PictureScreenPtr ps = GetPictureScreen(pScreen); - BoxRec bounds; - - if (maskFormat) { - PicturePtr pPicture; - INT16 xDst, yDst; - INT16 xRel, yRel; - - miTrapezoidBounds (ntrap, traps, &bounds); - - if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) - return; - - xDst = traps[0].left.p1.x >> 16; - yDst = traps[0].left.p1.y >> 16; - - pPicture = exaCreateAlphaPicture (pScreen, pDst, maskFormat, - bounds.x2 - bounds.x1, - bounds.y2 - bounds.y1); - if (!pPicture) - return; - - exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST); - for (; ntrap; ntrap--, traps++) - (*ps->RasterizeTrapezoid) (pPicture, traps, - -bounds.x1, -bounds.y1); - exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST); - - xRel = bounds.x1 + xSrc - xDst; - yRel = bounds.y1 + ySrc - yDst; - CompositePicture (op, pSrc, pPicture, pDst, - xRel, yRel, 0, 0, bounds.x1, bounds.y1, - bounds.x2 - bounds.x1, - bounds.y2 - bounds.y1); - FreePicture (pPicture, 0); - } else { - if (pDst->polyEdge == PolyEdgeSharp) - maskFormat = PictureMatchFormat (pScreen, 1, PICT_a1); - else - maskFormat = PictureMatchFormat (pScreen, 8, PICT_a8); - for (; ntrap; ntrap--, traps++) - exaTrapezoids (op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, traps); - } -} - -/** - * exaTriangles is essentially a copy of miTriangles that uses - * exaCreateAlphaPicture instead of miCreateAlphaPicture. - * - * The problem with miCreateAlphaPicture is that it calls PolyFillRect - * to initialize the contents after creating the pixmap, which - * causes the pixmap to be moved in for acceleration. The subsequent - * call to AddTriangles won't be accelerated however, which forces the pixmap - * to be moved out again. - * - * exaCreateAlphaPicture avoids this roundtrip by using ExaCheckPolyFillRect - * to initialize the contents. - */ -void -exaTriangles (CARD8 op, PicturePtr pSrc, PicturePtr pDst, - PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, - int ntri, xTriangle *tris) -{ - ScreenPtr pScreen = pDst->pDrawable->pScreen; - PictureScreenPtr ps = GetPictureScreen(pScreen); - BoxRec bounds; - - if (maskFormat) { - PicturePtr pPicture; - INT16 xDst, yDst; - INT16 xRel, yRel; - - miTriangleBounds (ntri, tris, &bounds); - - if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) - return; - - xDst = tris[0].p1.x >> 16; - yDst = tris[0].p1.y >> 16; - - pPicture = exaCreateAlphaPicture (pScreen, pDst, maskFormat, - bounds.x2 - bounds.x1, - bounds.y2 - bounds.y1); - if (!pPicture) - return; - - exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST); - (*ps->AddTriangles) (pPicture, -bounds.x1, -bounds.y1, ntri, tris); - exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST); - - xRel = bounds.x1 + xSrc - xDst; - yRel = bounds.y1 + ySrc - yDst; - CompositePicture (op, pSrc, pPicture, pDst, - xRel, yRel, 0, 0, bounds.x1, bounds.y1, - bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); - FreePicture (pPicture, 0); - } else { - if (pDst->polyEdge == PolyEdgeSharp) - maskFormat = PictureMatchFormat (pScreen, 1, PICT_a1); - else - maskFormat = PictureMatchFormat (pScreen, 8, PICT_a8); - - for (; ntri; ntri--, tris++) - exaTriangles (op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, tris); - } -} +/* + * Copyright © 2001 Keith Packard + * + * Partly based on code that is Copyright © The XFree86 Project Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include + +#include "exa_priv.h" + +#include "mipict.h" + +#if DEBUG_TRACE_FALL +static void exaCompositeFallbackPictDesc(PicturePtr pict, char *string, int n) +{ + char format[20]; + char size[20]; + char loc; + int temp; + + if (!pict) { + snprintf(string, n, "None"); + return; + } + + switch (pict->format) + { + case PICT_a8r8g8b8: + snprintf(format, 20, "ARGB8888"); + break; + case PICT_x8r8g8b8: + snprintf(format, 20, "XRGB8888"); + break; + case PICT_b8g8r8a8: + snprintf(format, 20, "BGRA8888"); + break; + case PICT_b8g8r8x8: + snprintf(format, 20, "BGRX8888"); + break; + case PICT_r5g6b5: + snprintf(format, 20, "RGB565 "); + break; + case PICT_x1r5g5b5: + snprintf(format, 20, "RGB555 "); + break; + case PICT_a8: + snprintf(format, 20, "A8 "); + break; + case PICT_a1: + snprintf(format, 20, "A1 "); + break; + default: + snprintf(format, 20, "0x%x", (int)pict->format); + break; + } + + if (pict->pDrawable) { + loc = exaGetOffscreenPixmap(pict->pDrawable, &temp, &temp) ? 's' : 'm'; + + snprintf(size, 20, "%dx%d%s", pict->pDrawable->width, + pict->pDrawable->height, pict->repeat ? + " R" : ""); + } else { + loc = '-'; + + snprintf(size, 20, "%s", pict->repeat ? " R" : ""); + } + + snprintf(string, n, "%p:%c fmt %s (%s)", pict->pDrawable, loc, format, size); +} + +static void +exaPrintCompositeFallback(CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst) +{ + char sop[20]; + char srcdesc[40], maskdesc[40], dstdesc[40]; + + switch(op) + { + case PictOpSrc: + snprintf(sop, sizeof(sop), "Src"); + break; + case PictOpOver: + snprintf(sop, sizeof(sop), "Over"); + break; + default: + snprintf(sop, sizeof(sop), "0x%x", (int)op); + break; + } + + exaCompositeFallbackPictDesc(pSrc, srcdesc, 40); + exaCompositeFallbackPictDesc(pMask, maskdesc, 40); + exaCompositeFallbackPictDesc(pDst, dstdesc, 40); + + ErrorF("Composite fallback: op %s, \n" + " src %s, \n" + " mask %s, \n" + " dst %s, \n", + sop, srcdesc, maskdesc, dstdesc); +} +#endif /* DEBUG_TRACE_FALL */ + +Bool +exaOpReadsDestination (CARD8 op) +{ + /* FALSE (does not read destination) is the list of ops in the protocol + * document with "0" in the "Fb" column and no "Ab" in the "Fa" column. + * That's just Clear and Src. ReduceCompositeOp() will already have + * converted con/disjoint clear/src to Clear or Src. + */ + switch (op) { + case PictOpClear: + case PictOpSrc: + return FALSE; + default: + return TRUE; + } +} + + +static Bool +exaGetPixelFromRGBA(CARD32 *pixel, + CARD16 red, + CARD16 green, + CARD16 blue, + CARD16 alpha, + PictFormatPtr pFormat) +{ + int rbits, bbits, gbits, abits; + int rshift, bshift, gshift, ashift; + + *pixel = 0; + + if (!PICT_FORMAT_COLOR(pFormat->format) && + PICT_FORMAT_TYPE(pFormat->format) != PICT_TYPE_A) + return FALSE; + + rbits = PICT_FORMAT_R(pFormat->format); + gbits = PICT_FORMAT_G(pFormat->format); + bbits = PICT_FORMAT_B(pFormat->format); + abits = PICT_FORMAT_A(pFormat->format); + + rshift = pFormat->direct.red; + gshift = pFormat->direct.green; + bshift = pFormat->direct.blue; + ashift = pFormat->direct.alpha; + + *pixel |= ( blue >> (16 - bbits)) << bshift; + *pixel |= ( red >> (16 - rbits)) << rshift; + *pixel |= (green >> (16 - gbits)) << gshift; + *pixel |= (alpha >> (16 - abits)) << ashift; + + return TRUE; +} + +static Bool +exaGetRGBAFromPixel(CARD32 pixel, + CARD16 *red, + CARD16 *green, + CARD16 *blue, + CARD16 *alpha, + PictFormatPtr pFormat, + PictFormatShort format) +{ + int rbits, bbits, gbits, abits; + int rshift, bshift, gshift, ashift; + + if (!PICT_FORMAT_COLOR(format) && PICT_FORMAT_TYPE(format) != PICT_TYPE_A) + return FALSE; + + rbits = PICT_FORMAT_R(format); + gbits = PICT_FORMAT_G(format); + bbits = PICT_FORMAT_B(format); + abits = PICT_FORMAT_A(format); + + if (pFormat) { + rshift = pFormat->direct.red; + gshift = pFormat->direct.green; + bshift = pFormat->direct.blue; + ashift = pFormat->direct.alpha; + } else if (format == PICT_a8r8g8b8) { + rshift = 16; + gshift = 8; + bshift = 0; + ashift = 24; + } else + FatalError("EXA bug: exaGetRGBAFromPixel() doesn't match " + "createSourcePicture()\n"); + + if (rbits) { + *red = ((pixel >> rshift ) & ((1 << rbits) - 1)) << (16 - rbits); + while (rbits < 16) { + *red |= *red >> rbits; + rbits <<= 1; + } + + *green = ((pixel >> gshift ) & ((1 << gbits) - 1)) << (16 - gbits); + while (gbits < 16) { + *green |= *green >> gbits; + gbits <<= 1; + } + + *blue = ((pixel >> bshift ) & ((1 << bbits) - 1)) << (16 - bbits); + while (bbits < 16) { + *blue |= *blue >> bbits; + bbits <<= 1; + } + } else { + *red = 0x0000; + *green = 0x0000; + *blue = 0x0000; + } + + if (abits) { + *alpha = ((pixel >> ashift ) & ((1 << abits) - 1)) << (16 - abits); + while (abits < 16) { + *alpha |= *alpha >> abits; + abits <<= 1; + } + } else + *alpha = 0xffff; + + return TRUE; +} + +static int +exaTryDriverSolidFill(PicturePtr pSrc, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + ExaScreenPriv (pDst->pDrawable->pScreen); + RegionRec region; + BoxPtr pbox; + int nbox; + int dst_off_x, dst_off_y; + PixmapPtr pSrcPix, pDstPix; + ExaPixmapPrivPtr pDstExaPix; + CARD32 pixel; + CARD16 red, green, blue, alpha; + + pDstPix = exaGetDrawablePixmap (pDst->pDrawable); + pDstExaPix = ExaGetPixmapPriv(pDstPix); + + /* Check whether the accelerator can use the destination pixmap. + */ + if (pDstExaPix->accel_blocked) + { + return -1; + } + + xDst += pDst->pDrawable->x; + yDst += pDst->pDrawable->y; + if (pSrc->pDrawable) { + xSrc += pSrc->pDrawable->x; + ySrc += pSrc->pDrawable->y; + } + + if (!miComputeCompositeRegion (®ion, pSrc, NULL, pDst, + xSrc, ySrc, 0, 0, xDst, yDst, + width, height)) + return 1; + + exaGetDrawableDeltas (pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y); + + RegionTranslate(®ion, dst_off_x, dst_off_y); + + if (pSrc->pDrawable) { + pSrcPix = exaGetDrawablePixmap (pSrc->pDrawable); + pixel = exaGetPixmapFirstPixel (pSrcPix); + } else + pixel = pSrc->pSourcePict->solidFill.color; + + if (!exaGetRGBAFromPixel(pixel, &red, &green, &blue, &alpha, + pSrc->pFormat, pSrc->format) || + !exaGetPixelFromRGBA(&pixel, red, green, blue, alpha, + pDst->pFormat)) + { + RegionUninit(®ion); + return -1; + } + + if (pExaScr->do_migration) { + ExaMigrationRec pixmaps[1]; + + pixmaps[0].as_dst = TRUE; + pixmaps[0].as_src = FALSE; + pixmaps[0].pPix = pDstPix; + pixmaps[0].pReg = ®ion; + exaDoMigration(pixmaps, 1, TRUE); + } + + if (!exaPixmapHasGpuCopy(pDstPix)) { + RegionUninit(®ion); + return 0; + } + + if (!(*pExaScr->info->PrepareSolid) (pDstPix, GXcopy, 0xffffffff, pixel)) + { + RegionUninit(®ion); + return -1; + } + + nbox = RegionNumRects(®ion); + pbox = RegionRects(®ion); + + while (nbox--) + { + (*pExaScr->info->Solid) (pDstPix, pbox->x1, pbox->y1, pbox->x2, pbox->y2); + pbox++; + } + + (*pExaScr->info->DoneSolid) (pDstPix); + exaMarkSync(pDst->pDrawable->pScreen); + + RegionUninit(®ion); + return 1; +} + +static int +exaTryDriverCompositeRects(CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + int nrect, + ExaCompositeRectPtr rects) +{ + ExaScreenPriv (pDst->pDrawable->pScreen); + int src_off_x = 0, src_off_y = 0, mask_off_x = 0, mask_off_y = 0; + int dst_off_x, dst_off_y; + PixmapPtr pSrcPix = NULL, pMaskPix = NULL, pDstPix; + ExaPixmapPrivPtr pSrcExaPix = NULL, pMaskExaPix = NULL, pDstExaPix; + + if (!pExaScr->info->PrepareComposite) + return -1; + + if (pSrc->pDrawable) { + pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable); + pSrcExaPix = ExaGetPixmapPriv(pSrcPix); + } + + if (pMask && pMask->pDrawable) { + pMaskPix = exaGetDrawablePixmap(pMask->pDrawable); + pMaskExaPix = ExaGetPixmapPriv(pMaskPix); + } + + pDstPix = exaGetDrawablePixmap(pDst->pDrawable); + pDstExaPix = ExaGetPixmapPriv(pDstPix); + + /* Check whether the accelerator can use these pixmaps. + * FIXME: If it cannot, use temporary pixmaps so that the drawing + * happens within limits. + */ + if (pDstExaPix->accel_blocked || + (pSrcExaPix && pSrcExaPix->accel_blocked) || + (pMaskExaPix && pMaskExaPix->accel_blocked)) + { + return -1; + } + + if (pExaScr->info->CheckComposite && + !(*pExaScr->info->CheckComposite) (op, pSrc, pMask, pDst)) + { + return -1; + } + + if (pExaScr->do_migration) { + ExaMigrationRec pixmaps[3]; + int i = 0; + + pixmaps[i].as_dst = TRUE; + pixmaps[i].as_src = exaOpReadsDestination(op); + pixmaps[i].pPix = pDstPix; + pixmaps[i].pReg = NULL; + i++; + + if (pSrcPix) { + pixmaps[i].as_dst = FALSE; + pixmaps[i].as_src = TRUE; + pixmaps[i].pPix = pSrcPix; + pixmaps[i].pReg = NULL; + i++; + } + + if (pMaskPix) { + pixmaps[i].as_dst = FALSE; + pixmaps[i].as_src = TRUE; + pixmaps[i].pPix = pMaskPix; + pixmaps[i].pReg = NULL; + i++; + } + + exaDoMigration(pixmaps, i, TRUE); + } + + pDstPix = exaGetOffscreenPixmap (pDst->pDrawable, &dst_off_x, &dst_off_y); + if (!pDstPix) + return 0; + + if (pSrcPix) { + pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y); + if (!pSrcPix) + return 0; + } + + if (pMaskPix) { + pMaskPix = exaGetOffscreenPixmap (pMask->pDrawable, &mask_off_x, &mask_off_y); + if (!pMaskPix) + return 0; + } + + if (!(*pExaScr->info->PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix, + pMaskPix, pDstPix)) + return -1; + + while (nrect--) + { + INT16 xDst = rects->xDst + pDst->pDrawable->x; + INT16 yDst = rects->yDst + pDst->pDrawable->y; + INT16 xMask = rects->xMask; + INT16 yMask = rects->yMask; + INT16 xSrc = rects->xSrc; + INT16 ySrc = rects->ySrc; + RegionRec region; + BoxPtr pbox; + int nbox; + + if (pMaskPix) { + xMask += pMask->pDrawable->x; + yMask += pMask->pDrawable->y; + } + + if (pSrcPix) { + xSrc += pSrc->pDrawable->x; + ySrc += pSrc->pDrawable->y; + } + + if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, + xSrc, ySrc, xMask, yMask, xDst, yDst, + rects->width, rects->height)) + goto next_rect; + + RegionTranslate(®ion, dst_off_x, dst_off_y); + + nbox = RegionNumRects(®ion); + pbox = RegionRects(®ion); + + xMask = xMask + mask_off_x - xDst - dst_off_x; + yMask = yMask + mask_off_y - yDst - dst_off_y; + xSrc = xSrc + src_off_x - xDst - dst_off_x; + ySrc = ySrc + src_off_y - yDst - dst_off_y; + + while (nbox--) + { + (*pExaScr->info->Composite) (pDstPix, + pbox->x1 + xSrc, + pbox->y1 + ySrc, + pbox->x1 + xMask, + pbox->y1 + yMask, + pbox->x1, + pbox->y1, + pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1); + pbox++; + } + + next_rect: + RegionUninit(®ion); + + rects++; + } + + (*pExaScr->info->DoneComposite) (pDstPix); + exaMarkSync(pDst->pDrawable->pScreen); + + return 1; +} + +/** + * Copy a number of rectangles from source to destination in a single + * operation. This is specialized for glyph rendering: we don't have the + * special-case fallbacks found in exaComposite() - if the driver can support + * it, we use the driver functionality, otherwise we fall back straight to + * software. + */ +void +exaCompositeRects(CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + int nrect, + ExaCompositeRectPtr rects) +{ + ExaScreenPriv (pDst->pDrawable->pScreen); + int n; + ExaCompositeRectPtr r; + int ret; + + /* If we get a mask, that means we're rendering to the exaGlyphs + * destination directly, so the damage layer takes care of this. + */ + if (!pMask) { + RegionRec region; + int x1 = MAXSHORT; + int y1 = MAXSHORT; + int x2 = MINSHORT; + int y2 = MINSHORT; + BoxRec box; + + /* We have to manage the damage ourselves, since CompositeRects isn't + * something in the screen that can be managed by the damage extension, + * and EXA depends on damage to track what needs to be migrated between + * the gpu and the cpu. + */ + + /* Compute the overall extents of the composited region - we're making + * the assumption here that we are compositing a bunch of glyphs that + * cluster closely together and damaging each glyph individually would + * be a loss compared to damaging the bounding box. + */ + n = nrect; + r = rects; + while (n--) { + int rect_x2 = r->xDst + r->width; + int rect_y2 = r->yDst + r->height; + + if (r->xDst < x1) x1 = r->xDst; + if (r->yDst < y1) y1 = r->yDst; + if (rect_x2 > x2) x2 = rect_x2; + if (rect_y2 > y2) y2 = rect_y2; + + r++; + } + + if (x2 <= x1 || y2 <= y1) + return; + + box.x1 = x1; + box.x2 = x2 < MAXSHORT ? x2 : MAXSHORT; + box.y1 = y1; + box.y2 = y2 < MAXSHORT ? y2 : MAXSHORT; + + /* The pixmap migration code relies on pendingDamage indicating + * the bounds of the current rendering, so we need to force + * the actual damage into that region before we do anything, and + * (see use of DamagePendingRegion in exaCopyDirty) + */ + + RegionInit(®ion, &box, 1); + + DamageRegionAppend(pDst->pDrawable, ®ion); + + RegionUninit(®ion); + } + + /************************************************************/ + + ValidatePicture (pSrc); + if (pMask) + ValidatePicture (pMask); + ValidatePicture (pDst); + + ret = exaTryDriverCompositeRects(op, pSrc, pMask, pDst, nrect, rects); + + if (ret != 1) { + if (ret == -1 && op == PictOpOver && pMask && pMask->componentAlpha && + (!pExaScr->info->CheckComposite || + ((*pExaScr->info->CheckComposite)(PictOpOutReverse, pSrc, pMask, + pDst) && + (*pExaScr->info->CheckComposite)(PictOpAdd, pSrc, pMask, pDst)))) { + ret = exaTryDriverCompositeRects(PictOpOutReverse, pSrc, pMask, + pDst, nrect, rects); + if (ret == 1) { + op = PictOpAdd; + ret = exaTryDriverCompositeRects(op, pSrc, pMask, pDst, nrect, + rects); + } + } + + if (ret != 1) { + n = nrect; + r = rects; + while (n--) { + ExaCheckComposite (op, pSrc, pMask, pDst, + r->xSrc, r->ySrc, + r->xMask, r->yMask, + r->xDst, r->yDst, + r->width, r->height); + r++; + } + } + } + + /************************************************************/ + + if (!pMask) { + /* Now we have to flush the damage out from pendingDamage => damage + * Calling DamageRegionProcessPending has that effect. + */ + + DamageRegionProcessPending(pDst->pDrawable); + } +} + +static int +exaTryDriverComposite(CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + ExaScreenPriv (pDst->pDrawable->pScreen); + RegionRec region; + BoxPtr pbox; + int nbox; + int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y; + PixmapPtr pSrcPix = NULL, pMaskPix = NULL, pDstPix; + ExaPixmapPrivPtr pSrcExaPix = NULL, pMaskExaPix = NULL, pDstExaPix; + + if (pSrc->pDrawable) { + pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable); + pSrcExaPix = ExaGetPixmapPriv(pSrcPix); + } + + pDstPix = exaGetDrawablePixmap(pDst->pDrawable); + pDstExaPix = ExaGetPixmapPriv(pDstPix); + + if (pMask && pMask->pDrawable) { + pMaskPix = exaGetDrawablePixmap(pMask->pDrawable); + pMaskExaPix = ExaGetPixmapPriv(pMaskPix); + } + + /* Check whether the accelerator can use these pixmaps. + * FIXME: If it cannot, use temporary pixmaps so that the drawing + * happens within limits. + */ + if (pDstExaPix->accel_blocked || + (pSrcExaPix && pSrcExaPix->accel_blocked) || + (pMaskExaPix && (pMaskExaPix->accel_blocked))) + { + return -1; + } + + xDst += pDst->pDrawable->x; + yDst += pDst->pDrawable->y; + + if (pMaskPix) { + xMask += pMask->pDrawable->x; + yMask += pMask->pDrawable->y; + } + + if (pSrcPix) { + xSrc += pSrc->pDrawable->x; + ySrc += pSrc->pDrawable->y; + } + + if (pExaScr->info->CheckComposite && + !(*pExaScr->info->CheckComposite) (op, pSrc, pMask, pDst)) + { + return -1; + } + + if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, + xSrc, ySrc, xMask, yMask, xDst, yDst, + width, height)) + return 1; + + exaGetDrawableDeltas (pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y); + + RegionTranslate(®ion, dst_off_x, dst_off_y); + + if (pExaScr->do_migration) { + ExaMigrationRec pixmaps[3]; + int i = 0; + + pixmaps[i].as_dst = TRUE; + pixmaps[i].as_src = exaOpReadsDestination(op); + pixmaps[i].pPix = pDstPix; + pixmaps[i].pReg = pixmaps[0].as_src ? NULL : ®ion; + i++; + + if (pSrcPix) { + pixmaps[i].as_dst = FALSE; + pixmaps[i].as_src = TRUE; + pixmaps[i].pPix = pSrcPix; + pixmaps[i].pReg = NULL; + i++; + } + + if (pMaskPix) { + pixmaps[i].as_dst = FALSE; + pixmaps[i].as_src = TRUE; + pixmaps[i].pPix = pMaskPix; + pixmaps[i].pReg = NULL; + i++; + } + + exaDoMigration(pixmaps, i, TRUE); + } + + if (pSrcPix) { + pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y); + if (!pSrcPix) { + RegionUninit(®ion); + return 0; + } + } + + if (pMaskPix) { + pMaskPix = exaGetOffscreenPixmap (pMask->pDrawable, &mask_off_x, + &mask_off_y); + if (!pMaskPix) { + RegionUninit(®ion); + return 0; + } + } + + if (!exaPixmapHasGpuCopy(pDstPix)) { + RegionUninit(®ion); + return 0; + } + + if (!(*pExaScr->info->PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix, + pMaskPix, pDstPix)) + { + RegionUninit(®ion); + return -1; + } + + nbox = RegionNumRects(®ion); + pbox = RegionRects(®ion); + + xMask = xMask + mask_off_x - xDst - dst_off_x; + yMask = yMask + mask_off_y - yDst - dst_off_y; + + xSrc = xSrc + src_off_x - xDst - dst_off_x; + ySrc = ySrc + src_off_y - yDst - dst_off_y; + + while (nbox--) + { + (*pExaScr->info->Composite) (pDstPix, + pbox->x1 + xSrc, + pbox->y1 + ySrc, + pbox->x1 + xMask, + pbox->y1 + yMask, + pbox->x1, + pbox->y1, + pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1); + pbox++; + } + (*pExaScr->info->DoneComposite) (pDstPix); + exaMarkSync(pDst->pDrawable->pScreen); + + RegionUninit(®ion); + return 1; +} + +/** + * exaTryMagicTwoPassCompositeHelper implements PictOpOver using two passes of + * simpler operations PictOpOutReverse and PictOpAdd. Mainly used for component + * alpha and limited 1-tmu cards. + * + * From http://anholt.livejournal.com/32058.html: + * + * The trouble is that component-alpha rendering requires two different sources + * for blending: one for the source value to the blender, which is the + * per-channel multiplication of source and mask, and one for the source alpha + * for multiplying with the destination channels, which is the multiplication + * of the source channels by the mask alpha. So the equation for Over is: + * + * dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A + * dst.R = src.R * mask.R + (1 - (src.A * mask.R)) * dst.R + * dst.G = src.G * mask.G + (1 - (src.A * mask.G)) * dst.G + * dst.B = src.B * mask.B + (1 - (src.A * mask.B)) * dst.B + * + * But we can do some simpler operations, right? How about PictOpOutReverse, + * which has a source factor of 0 and dest factor of (1 - source alpha). We + * can get the source alpha value (srca.X = src.A * mask.X) out of the texture + * blenders pretty easily. So we can do a component-alpha OutReverse, which + * gets us: + * + * dst.A = 0 + (1 - (src.A * mask.A)) * dst.A + * dst.R = 0 + (1 - (src.A * mask.R)) * dst.R + * dst.G = 0 + (1 - (src.A * mask.G)) * dst.G + * dst.B = 0 + (1 - (src.A * mask.B)) * dst.B + * + * OK. And if an op doesn't use the source alpha value for the destination + * factor, then we can do the channel multiplication in the texture blenders + * to get the source value, and ignore the source alpha that we wouldn't use. + * We've supported this in the Radeon driver for a long time. An example would + * be PictOpAdd, which does: + * + * dst.A = src.A * mask.A + dst.A + * dst.R = src.R * mask.R + dst.R + * dst.G = src.G * mask.G + dst.G + * dst.B = src.B * mask.B + dst.B + * + * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right + * after it, we get: + * + * dst.A = src.A * mask.A + ((1 - (src.A * mask.A)) * dst.A) + * dst.R = src.R * mask.R + ((1 - (src.A * mask.R)) * dst.R) + * dst.G = src.G * mask.G + ((1 - (src.A * mask.G)) * dst.G) + * dst.B = src.B * mask.B + ((1 - (src.A * mask.B)) * dst.B) + */ + +static int +exaTryMagicTwoPassCompositeHelper(CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + ExaScreenPriv (pDst->pDrawable->pScreen); + + assert(op == PictOpOver); + + if (pExaScr->info->CheckComposite && + (!(*pExaScr->info->CheckComposite)(PictOpOutReverse, pSrc, pMask, + pDst) || + !(*pExaScr->info->CheckComposite)(PictOpAdd, pSrc, pMask, pDst))) + { + return -1; + } + + /* Now, we think we should be able to accelerate this operation. First, + * composite the destination to be the destination times the source alpha + * factors. + */ + exaComposite(PictOpOutReverse, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, + xDst, yDst, width, height); + + /* Then, add in the source value times the destination alpha factors (1.0). + */ + exaComposite(PictOpAdd, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, + xDst, yDst, width, height); + + return 1; +} + +void +exaComposite(CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + ExaScreenPriv (pDst->pDrawable->pScreen); + int ret = -1; + Bool saveSrcRepeat = pSrc->repeat; + Bool saveMaskRepeat = pMask ? pMask->repeat : 0; + RegionRec region; + + if (pExaScr->swappedOut) + goto fallback; + + /* Remove repeat in source if useless */ + if (pSrc->pDrawable && pSrc->repeat && !pSrc->transform && xSrc >= 0 && + (xSrc + width) <= pSrc->pDrawable->width && ySrc >= 0 && + (ySrc + height) <= pSrc->pDrawable->height) + pSrc->repeat = 0; + + if (!pMask && !pSrc->alphaMap && !pDst->alphaMap && + (op == PictOpSrc || (op == PictOpOver && !PICT_FORMAT_A(pSrc->format)))) + { + if (pSrc->pDrawable ? + (pSrc->pDrawable->width == 1 && pSrc->pDrawable->height == 1 && + pSrc->repeat) : + (pSrc->pSourcePict->type == SourcePictTypeSolidFill)) + { + ret = exaTryDriverSolidFill(pSrc, pDst, xSrc, ySrc, xDst, yDst, + width, height); + if (ret == 1) + goto done; + } else if (pSrc->pDrawable && !pSrc->transform && + ((op == PictOpSrc && + (pSrc->format == pDst->format || + (PICT_FORMAT_COLOR(pDst->format) && + PICT_FORMAT_COLOR(pSrc->format) && + pDst->format == PICT_FORMAT(PICT_FORMAT_BPP(pSrc->format), + PICT_FORMAT_TYPE(pSrc->format), + 0, + PICT_FORMAT_R(pSrc->format), + PICT_FORMAT_G(pSrc->format), + PICT_FORMAT_B(pSrc->format))))) || + (op == PictOpOver && pSrc->format == pDst->format && + !PICT_FORMAT_A(pSrc->format)))) + { + if (!pSrc->repeat && xSrc >= 0 && ySrc >= 0 && + (xSrc + width <= pSrc->pDrawable->width) && + (ySrc + height <= pSrc->pDrawable->height)) + { + Bool ret; + xDst += pDst->pDrawable->x; + yDst += pDst->pDrawable->y; + xSrc += pSrc->pDrawable->x; + ySrc += pSrc->pDrawable->y; + + if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, + xSrc, ySrc, xMask, yMask, xDst, + yDst, width, height)) + goto done; + + ret = exaHWCopyNtoN(pSrc->pDrawable, pDst->pDrawable, NULL, + RegionRects(®ion), RegionNumRects(®ion), + xSrc - xDst, ySrc - yDst, FALSE, FALSE); + RegionUninit(®ion); + + /* Reset values to their original values. */ + xDst -= pDst->pDrawable->x; + yDst -= pDst->pDrawable->y; + xSrc -= pSrc->pDrawable->x; + ySrc -= pSrc->pDrawable->y; + + if (!ret) + goto fallback; + + goto done; + } + + if (pSrc->repeat && pSrc->repeatType == RepeatNormal && + pSrc->pDrawable->type == DRAWABLE_PIXMAP) + { + DDXPointRec patOrg; + + /* Let's see if the driver can do the repeat in one go */ + if (pExaScr->info->PrepareComposite && !pSrc->alphaMap && + !pDst->alphaMap) + { + ret = exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc, + ySrc, xMask, yMask, xDst, yDst, + width, height); + if (ret == 1) + goto done; + } + + /* Now see if we can use exaFillRegionTiled() */ + xDst += pDst->pDrawable->x; + yDst += pDst->pDrawable->y; + xSrc += pSrc->pDrawable->x; + ySrc += pSrc->pDrawable->y; + + if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, xSrc, + ySrc, xMask, yMask, xDst, yDst, + width, height)) + goto done; + + /* pattern origin is the point in the destination drawable + * corresponding to (0,0) in the source */ + patOrg.x = xDst - xSrc; + patOrg.y = yDst - ySrc; + + ret = exaFillRegionTiled(pDst->pDrawable, ®ion, + (PixmapPtr)pSrc->pDrawable, + &patOrg, FB_ALLONES, GXcopy, CT_NONE); + + RegionUninit(®ion); + + if (ret) + goto done; + + /* Let's be correct and restore the variables to their original state. */ + xDst -= pDst->pDrawable->x; + yDst -= pDst->pDrawable->y; + xSrc -= pSrc->pDrawable->x; + ySrc -= pSrc->pDrawable->y; + } + } + } + + /* Remove repeat in mask if useless */ + if (pMask && pMask->pDrawable && pMask->repeat && !pMask->transform && + xMask >= 0 && (xMask + width) <= pMask->pDrawable->width && + yMask >= 0 && (yMask + height) <= pMask->pDrawable->height) + pMask->repeat = 0; + + if (pExaScr->info->PrepareComposite && + !pSrc->alphaMap && (!pMask || !pMask->alphaMap) && !pDst->alphaMap) + { + Bool isSrcSolid; + + ret = exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask, + yMask, xDst, yDst, width, height); + if (ret == 1) + goto done; + + /* For generic masks and solid src pictures, mach64 can do Over in two + * passes, similar to the component-alpha case. + */ + isSrcSolid = pSrc->pDrawable ? + (pSrc->pDrawable->width == 1 && pSrc->pDrawable->height == 1 && + pSrc->repeat) : + (pSrc->pSourcePict->type == SourcePictTypeSolidFill); + + /* If we couldn't do the Composite in a single pass, and it was a + * component-alpha Over, see if we can do it in two passes with + * an OutReverse and then an Add. + */ + if (ret == -1 && op == PictOpOver && pMask && + (pMask->componentAlpha || isSrcSolid)) { + ret = exaTryMagicTwoPassCompositeHelper(op, pSrc, pMask, pDst, + xSrc, ySrc, + xMask, yMask, xDst, yDst, + width, height); + if (ret == 1) + goto done; + } + } + +fallback: +#if DEBUG_TRACE_FALL + exaPrintCompositeFallback (op, pSrc, pMask, pDst); +#endif + + ExaCheckComposite (op, pSrc, pMask, pDst, xSrc, ySrc, + xMask, yMask, xDst, yDst, width, height); + +done: + pSrc->repeat = saveSrcRepeat; + if (pMask) + pMask->repeat = saveMaskRepeat; +} + +/** + * Same as miCreateAlphaPicture, except it uses ExaCheckPolyFillRect instead + * of PolyFillRect to initialize the pixmap after creating it, to prevent + * the pixmap from being migrated. + * + * See the comments about exaTrapezoids and exaTriangles. + */ +static PicturePtr +exaCreateAlphaPicture (ScreenPtr pScreen, + PicturePtr pDst, + PictFormatPtr pPictFormat, + CARD16 width, + CARD16 height) +{ + PixmapPtr pPixmap; + PicturePtr pPicture; + GCPtr pGC; + int error; + xRectangle rect; + + if (width > 32767 || height > 32767) + return 0; + + if (!pPictFormat) + { + if (pDst->polyEdge == PolyEdgeSharp) + pPictFormat = PictureMatchFormat (pScreen, 1, PICT_a1); + else + pPictFormat = PictureMatchFormat (pScreen, 8, PICT_a8); + if (!pPictFormat) + return 0; + } + + pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, + pPictFormat->depth, 0); + if (!pPixmap) + return 0; + pGC = GetScratchGC (pPixmap->drawable.depth, pScreen); + if (!pGC) + { + (*pScreen->DestroyPixmap) (pPixmap); + return 0; + } + ValidateGC (&pPixmap->drawable, pGC); + rect.x = 0; + rect.y = 0; + rect.width = width; + rect.height = height; + ExaCheckPolyFillRect (&pPixmap->drawable, pGC, 1, &rect); + exaPixmapDirty (pPixmap, 0, 0, width, height); + FreeScratchGC (pGC); + pPicture = CreatePicture (0, &pPixmap->drawable, pPictFormat, + 0, 0, serverClient, &error); + (*pScreen->DestroyPixmap) (pPixmap); + return pPicture; +} + +/** + * exaTrapezoids is essentially a copy of miTrapezoids that uses + * exaCreateAlphaPicture instead of miCreateAlphaPicture. + * + * The problem with miCreateAlphaPicture is that it calls PolyFillRect + * to initialize the contents after creating the pixmap, which + * causes the pixmap to be moved in for acceleration. The subsequent + * call to RasterizeTrapezoid won't be accelerated however, which + * forces the pixmap to be moved out again. + * + * exaCreateAlphaPicture avoids this roundtrip by using ExaCheckPolyFillRect + * to initialize the contents. + */ +void +exaTrapezoids (CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, + int ntrap, xTrapezoid *traps) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + PictureScreenPtr ps = GetPictureScreen(pScreen); + BoxRec bounds; + + if (maskFormat) { + PicturePtr pPicture; + INT16 xDst, yDst; + INT16 xRel, yRel; + + miTrapezoidBounds (ntrap, traps, &bounds); + + if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) + return; + + xDst = traps[0].left.p1.x >> 16; + yDst = traps[0].left.p1.y >> 16; + + pPicture = exaCreateAlphaPicture (pScreen, pDst, maskFormat, + bounds.x2 - bounds.x1, + bounds.y2 - bounds.y1); + if (!pPicture) + return; + + exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST); + for (; ntrap; ntrap--, traps++) + (*ps->RasterizeTrapezoid) (pPicture, traps, + -bounds.x1, -bounds.y1); + exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST); + + xRel = bounds.x1 + xSrc - xDst; + yRel = bounds.y1 + ySrc - yDst; + CompositePicture (op, pSrc, pPicture, pDst, + xRel, yRel, 0, 0, bounds.x1, bounds.y1, + bounds.x2 - bounds.x1, + bounds.y2 - bounds.y1); + FreePicture (pPicture, 0); + } else { + if (pDst->polyEdge == PolyEdgeSharp) + maskFormat = PictureMatchFormat (pScreen, 1, PICT_a1); + else + maskFormat = PictureMatchFormat (pScreen, 8, PICT_a8); + for (; ntrap; ntrap--, traps++) + exaTrapezoids (op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, traps); + } +} + +/** + * exaTriangles is essentially a copy of miTriangles that uses + * exaCreateAlphaPicture instead of miCreateAlphaPicture. + * + * The problem with miCreateAlphaPicture is that it calls PolyFillRect + * to initialize the contents after creating the pixmap, which + * causes the pixmap to be moved in for acceleration. The subsequent + * call to AddTriangles won't be accelerated however, which forces the pixmap + * to be moved out again. + * + * exaCreateAlphaPicture avoids this roundtrip by using ExaCheckPolyFillRect + * to initialize the contents. + */ +void +exaTriangles (CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, + int ntri, xTriangle *tris) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + PictureScreenPtr ps = GetPictureScreen(pScreen); + BoxRec bounds; + + if (maskFormat) { + PicturePtr pPicture; + INT16 xDst, yDst; + INT16 xRel, yRel; + + miTriangleBounds (ntri, tris, &bounds); + + if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) + return; + + xDst = tris[0].p1.x >> 16; + yDst = tris[0].p1.y >> 16; + + pPicture = exaCreateAlphaPicture (pScreen, pDst, maskFormat, + bounds.x2 - bounds.x1, + bounds.y2 - bounds.y1); + if (!pPicture) + return; + + exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST); + (*ps->AddTriangles) (pPicture, -bounds.x1, -bounds.y1, ntri, tris); + exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST); + + xRel = bounds.x1 + xSrc - xDst; + yRel = bounds.y1 + ySrc - yDst; + CompositePicture (op, pSrc, pPicture, pDst, + xRel, yRel, 0, 0, bounds.x1, bounds.y1, + bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); + FreePicture (pPicture, 0); + } else { + if (pDst->polyEdge == PolyEdgeSharp) + maskFormat = PictureMatchFormat (pScreen, 1, PICT_a1); + else + maskFormat = PictureMatchFormat (pScreen, 8, PICT_a8); + + for (; ntri; ntri--, tris++) + exaTriangles (op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, tris); + } +} -- cgit v1.2.3