diff options
Diffstat (limited to 'xorg-server/exa/exa_render.c')
-rw-r--r-- | xorg-server/exa/exa_render.c | 2512 |
1 files changed, 1256 insertions, 1256 deletions
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 <dix-config.h>
-#endif
-
-#include <stdlib.h>
-
-#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 <dix-config.h> +#endif + +#include <stdlib.h> + +#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); + } +} |