exa_render.c revision 05b261ec
105b261ecSmrg/* 205b261ecSmrg * Copyright © 2001 Keith Packard 305b261ecSmrg * 405b261ecSmrg * Partly based on code that is Copyright © The XFree86 Project Inc. 505b261ecSmrg * 605b261ecSmrg * Permission to use, copy, modify, distribute, and sell this software and its 705b261ecSmrg * documentation for any purpose is hereby granted without fee, provided that 805b261ecSmrg * the above copyright notice appear in all copies and that both that 905b261ecSmrg * copyright notice and this permission notice appear in supporting 1005b261ecSmrg * documentation, and that the name of Keith Packard not be used in 1105b261ecSmrg * advertising or publicity pertaining to distribution of the software without 1205b261ecSmrg * specific, written prior permission. Keith Packard makes no 1305b261ecSmrg * representations about the suitability of this software for any purpose. It 1405b261ecSmrg * is provided "as is" without express or implied warranty. 1505b261ecSmrg * 1605b261ecSmrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 1705b261ecSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 1805b261ecSmrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 1905b261ecSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 2005b261ecSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 2105b261ecSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 2205b261ecSmrg * PERFORMANCE OF THIS SOFTWARE. 2305b261ecSmrg */ 2405b261ecSmrg 2505b261ecSmrg#ifdef HAVE_DIX_CONFIG_H 2605b261ecSmrg#include <dix-config.h> 2705b261ecSmrg#endif 2805b261ecSmrg 2905b261ecSmrg#include <stdlib.h> 3005b261ecSmrg 3105b261ecSmrg#include "exa_priv.h" 3205b261ecSmrg 3305b261ecSmrg#ifdef RENDER 3405b261ecSmrg#include "mipict.h" 3505b261ecSmrg 3605b261ecSmrg#if DEBUG_TRACE_FALL 3705b261ecSmrgstatic void exaCompositeFallbackPictDesc(PicturePtr pict, char *string, int n) 3805b261ecSmrg{ 3905b261ecSmrg char format[20]; 4005b261ecSmrg char size[20]; 4105b261ecSmrg char loc; 4205b261ecSmrg int temp; 4305b261ecSmrg 4405b261ecSmrg if (!pict) { 4505b261ecSmrg snprintf(string, n, "None"); 4605b261ecSmrg return; 4705b261ecSmrg } 4805b261ecSmrg 4905b261ecSmrg switch (pict->format) 5005b261ecSmrg { 5105b261ecSmrg case PICT_a8r8g8b8: 5205b261ecSmrg snprintf(format, 20, "ARGB8888"); 5305b261ecSmrg break; 5405b261ecSmrg case PICT_r5g6b5: 5505b261ecSmrg snprintf(format, 20, "RGB565 "); 5605b261ecSmrg break; 5705b261ecSmrg case PICT_x1r5g5b5: 5805b261ecSmrg snprintf(format, 20, "RGB555 "); 5905b261ecSmrg break; 6005b261ecSmrg case PICT_a8: 6105b261ecSmrg snprintf(format, 20, "A8 "); 6205b261ecSmrg break; 6305b261ecSmrg case PICT_a1: 6405b261ecSmrg snprintf(format, 20, "A1 "); 6505b261ecSmrg break; 6605b261ecSmrg default: 6705b261ecSmrg snprintf(format, 20, "0x%x", (int)pict->format); 6805b261ecSmrg break; 6905b261ecSmrg } 7005b261ecSmrg 7105b261ecSmrg loc = exaGetOffscreenPixmap(pict->pDrawable, &temp, &temp) ? 's' : 'm'; 7205b261ecSmrg 7305b261ecSmrg snprintf(size, 20, "%dx%d%s", pict->pDrawable->width, 7405b261ecSmrg pict->pDrawable->height, pict->repeat ? 7505b261ecSmrg " R" : ""); 7605b261ecSmrg 7705b261ecSmrg snprintf(string, n, "%p:%c fmt %s (%s)", pict->pDrawable, loc, format, size); 7805b261ecSmrg} 7905b261ecSmrg 8005b261ecSmrgstatic void 8105b261ecSmrgexaPrintCompositeFallback(CARD8 op, 8205b261ecSmrg PicturePtr pSrc, 8305b261ecSmrg PicturePtr pMask, 8405b261ecSmrg PicturePtr pDst) 8505b261ecSmrg{ 8605b261ecSmrg char sop[20]; 8705b261ecSmrg char srcdesc[40], maskdesc[40], dstdesc[40]; 8805b261ecSmrg 8905b261ecSmrg switch(op) 9005b261ecSmrg { 9105b261ecSmrg case PictOpSrc: 9205b261ecSmrg sprintf(sop, "Src"); 9305b261ecSmrg break; 9405b261ecSmrg case PictOpOver: 9505b261ecSmrg sprintf(sop, "Over"); 9605b261ecSmrg break; 9705b261ecSmrg default: 9805b261ecSmrg sprintf(sop, "0x%x", (int)op); 9905b261ecSmrg break; 10005b261ecSmrg } 10105b261ecSmrg 10205b261ecSmrg exaCompositeFallbackPictDesc(pSrc, srcdesc, 40); 10305b261ecSmrg exaCompositeFallbackPictDesc(pMask, maskdesc, 40); 10405b261ecSmrg exaCompositeFallbackPictDesc(pDst, dstdesc, 40); 10505b261ecSmrg 10605b261ecSmrg ErrorF("Composite fallback: op %s, \n" 10705b261ecSmrg " src %s, \n" 10805b261ecSmrg " mask %s, \n" 10905b261ecSmrg " dst %s, \n", 11005b261ecSmrg sop, srcdesc, maskdesc, dstdesc); 11105b261ecSmrg} 11205b261ecSmrg#endif /* DEBUG_TRACE_FALL */ 11305b261ecSmrg 11405b261ecSmrgstatic Bool 11505b261ecSmrgexaOpReadsDestination (CARD8 op) 11605b261ecSmrg{ 11705b261ecSmrg /* FALSE (does not read destination) is the list of ops in the protocol 11805b261ecSmrg * document with "0" in the "Fb" column and no "Ab" in the "Fa" column. 11905b261ecSmrg * That's just Clear and Src. ReduceCompositeOp() will already have 12005b261ecSmrg * converted con/disjoint clear/src to Clear or Src. 12105b261ecSmrg */ 12205b261ecSmrg switch (op) { 12305b261ecSmrg case PictOpClear: 12405b261ecSmrg case PictOpSrc: 12505b261ecSmrg return FALSE; 12605b261ecSmrg default: 12705b261ecSmrg return TRUE; 12805b261ecSmrg } 12905b261ecSmrg} 13005b261ecSmrg 13105b261ecSmrg 13205b261ecSmrgstatic Bool 13305b261ecSmrgexaGetPixelFromRGBA(CARD32 *pixel, 13405b261ecSmrg CARD16 red, 13505b261ecSmrg CARD16 green, 13605b261ecSmrg CARD16 blue, 13705b261ecSmrg CARD16 alpha, 13805b261ecSmrg CARD32 format) 13905b261ecSmrg{ 14005b261ecSmrg int rbits, bbits, gbits, abits; 14105b261ecSmrg int rshift, bshift, gshift, ashift; 14205b261ecSmrg 14305b261ecSmrg *pixel = 0; 14405b261ecSmrg 14505b261ecSmrg if (!PICT_FORMAT_COLOR(format)) 14605b261ecSmrg return FALSE; 14705b261ecSmrg 14805b261ecSmrg rbits = PICT_FORMAT_R(format); 14905b261ecSmrg gbits = PICT_FORMAT_G(format); 15005b261ecSmrg bbits = PICT_FORMAT_B(format); 15105b261ecSmrg abits = PICT_FORMAT_A(format); 15205b261ecSmrg 15305b261ecSmrg if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) { 15405b261ecSmrg bshift = 0; 15505b261ecSmrg gshift = bbits; 15605b261ecSmrg rshift = gshift + gbits; 15705b261ecSmrg ashift = rshift + rbits; 15805b261ecSmrg } else { /* PICT_TYPE_ABGR */ 15905b261ecSmrg rshift = 0; 16005b261ecSmrg gshift = rbits; 16105b261ecSmrg bshift = gshift + gbits; 16205b261ecSmrg ashift = bshift + bbits; 16305b261ecSmrg } 16405b261ecSmrg 16505b261ecSmrg *pixel |= ( blue >> (16 - bbits)) << bshift; 16605b261ecSmrg *pixel |= ( red >> (16 - rbits)) << rshift; 16705b261ecSmrg *pixel |= (green >> (16 - gbits)) << gshift; 16805b261ecSmrg *pixel |= (alpha >> (16 - abits)) << ashift; 16905b261ecSmrg 17005b261ecSmrg return TRUE; 17105b261ecSmrg} 17205b261ecSmrg 17305b261ecSmrgstatic Bool 17405b261ecSmrgexaGetRGBAFromPixel(CARD32 pixel, 17505b261ecSmrg CARD16 *red, 17605b261ecSmrg CARD16 *green, 17705b261ecSmrg CARD16 *blue, 17805b261ecSmrg CARD16 *alpha, 17905b261ecSmrg CARD32 format) 18005b261ecSmrg{ 18105b261ecSmrg int rbits, bbits, gbits, abits; 18205b261ecSmrg int rshift, bshift, gshift, ashift; 18305b261ecSmrg 18405b261ecSmrg if (!PICT_FORMAT_COLOR(format)) 18505b261ecSmrg return FALSE; 18605b261ecSmrg 18705b261ecSmrg rbits = PICT_FORMAT_R(format); 18805b261ecSmrg gbits = PICT_FORMAT_G(format); 18905b261ecSmrg bbits = PICT_FORMAT_B(format); 19005b261ecSmrg abits = PICT_FORMAT_A(format); 19105b261ecSmrg 19205b261ecSmrg if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) { 19305b261ecSmrg bshift = 0; 19405b261ecSmrg gshift = bbits; 19505b261ecSmrg rshift = gshift + gbits; 19605b261ecSmrg ashift = rshift + rbits; 19705b261ecSmrg } else { /* PICT_TYPE_ABGR */ 19805b261ecSmrg rshift = 0; 19905b261ecSmrg gshift = rbits; 20005b261ecSmrg bshift = gshift + gbits; 20105b261ecSmrg ashift = bshift + bbits; 20205b261ecSmrg } 20305b261ecSmrg 20405b261ecSmrg *red = ((pixel >> rshift ) & ((1 << rbits) - 1)) << (16 - rbits); 20505b261ecSmrg while (rbits < 16) { 20605b261ecSmrg *red |= *red >> rbits; 20705b261ecSmrg rbits <<= 1; 20805b261ecSmrg } 20905b261ecSmrg 21005b261ecSmrg *green = ((pixel >> gshift ) & ((1 << gbits) - 1)) << (16 - gbits); 21105b261ecSmrg while (gbits < 16) { 21205b261ecSmrg *green |= *green >> gbits; 21305b261ecSmrg gbits <<= 1; 21405b261ecSmrg } 21505b261ecSmrg 21605b261ecSmrg *blue = ((pixel >> bshift ) & ((1 << bbits) - 1)) << (16 - bbits); 21705b261ecSmrg while (bbits < 16) { 21805b261ecSmrg *blue |= *blue >> bbits; 21905b261ecSmrg bbits <<= 1; 22005b261ecSmrg } 22105b261ecSmrg 22205b261ecSmrg if (abits) { 22305b261ecSmrg *alpha = ((pixel >> ashift ) & ((1 << abits) - 1)) << (16 - abits); 22405b261ecSmrg while (abits < 16) { 22505b261ecSmrg *alpha |= *alpha >> abits; 22605b261ecSmrg abits <<= 1; 22705b261ecSmrg } 22805b261ecSmrg } else 22905b261ecSmrg *alpha = 0xffff; 23005b261ecSmrg 23105b261ecSmrg return TRUE; 23205b261ecSmrg} 23305b261ecSmrg 23405b261ecSmrgstatic int 23505b261ecSmrgexaTryDriverSolidFill(PicturePtr pSrc, 23605b261ecSmrg PicturePtr pDst, 23705b261ecSmrg INT16 xSrc, 23805b261ecSmrg INT16 ySrc, 23905b261ecSmrg INT16 xDst, 24005b261ecSmrg INT16 yDst, 24105b261ecSmrg CARD16 width, 24205b261ecSmrg CARD16 height) 24305b261ecSmrg{ 24405b261ecSmrg ExaScreenPriv (pDst->pDrawable->pScreen); 24505b261ecSmrg RegionRec region; 24605b261ecSmrg BoxPtr pbox; 24705b261ecSmrg int nbox; 24805b261ecSmrg int dst_off_x, dst_off_y; 24905b261ecSmrg PixmapPtr pSrcPix, pDstPix; 25005b261ecSmrg CARD32 pixel; 25105b261ecSmrg CARD16 red, green, blue, alpha; 25205b261ecSmrg ExaMigrationRec pixmaps[1]; 25305b261ecSmrg 25405b261ecSmrg xDst += pDst->pDrawable->x; 25505b261ecSmrg yDst += pDst->pDrawable->y; 25605b261ecSmrg xSrc += pSrc->pDrawable->x; 25705b261ecSmrg ySrc += pSrc->pDrawable->y; 25805b261ecSmrg 25905b261ecSmrg if (!miComputeCompositeRegion (®ion, pSrc, NULL, pDst, 26005b261ecSmrg xSrc, ySrc, 0, 0, xDst, yDst, 26105b261ecSmrg width, height)) 26205b261ecSmrg return 1; 26305b261ecSmrg 26405b261ecSmrg pSrcPix = exaGetDrawablePixmap (pSrc->pDrawable); 26505b261ecSmrg pixel = exaGetPixmapFirstPixel (pSrcPix); 26605b261ecSmrg 26705b261ecSmrg pixmaps[0].as_dst = TRUE; 26805b261ecSmrg pixmaps[0].as_src = FALSE; 26905b261ecSmrg pixmaps[0].pPix = exaGetDrawablePixmap (pDst->pDrawable); 27005b261ecSmrg exaDoMigration(pixmaps, 1, TRUE); 27105b261ecSmrg 27205b261ecSmrg pDstPix = exaGetOffscreenPixmap (pDst->pDrawable, &dst_off_x, &dst_off_y); 27305b261ecSmrg if (!pDstPix) { 27405b261ecSmrg REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); 27505b261ecSmrg return 0; 27605b261ecSmrg } 27705b261ecSmrg 27805b261ecSmrg if (!exaGetRGBAFromPixel(pixel, &red, &green, &blue, &alpha, 27905b261ecSmrg pSrc->format)) 28005b261ecSmrg { 28105b261ecSmrg REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); 28205b261ecSmrg return -1; 28305b261ecSmrg } 28405b261ecSmrg 28505b261ecSmrg if (!exaGetPixelFromRGBA(&pixel, red, green, blue, alpha, 28605b261ecSmrg pDst->format)) 28705b261ecSmrg { 28805b261ecSmrg REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); 28905b261ecSmrg return -1; 29005b261ecSmrg } 29105b261ecSmrg 29205b261ecSmrg if (!(*pExaScr->info->PrepareSolid) (pDstPix, GXcopy, 0xffffffff, pixel)) 29305b261ecSmrg { 29405b261ecSmrg REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); 29505b261ecSmrg return -1; 29605b261ecSmrg } 29705b261ecSmrg 29805b261ecSmrg nbox = REGION_NUM_RECTS(®ion); 29905b261ecSmrg pbox = REGION_RECTS(®ion); 30005b261ecSmrg 30105b261ecSmrg while (nbox--) 30205b261ecSmrg { 30305b261ecSmrg (*pExaScr->info->Solid) (pDstPix, 30405b261ecSmrg pbox->x1 + dst_off_x, pbox->y1 + dst_off_y, 30505b261ecSmrg pbox->x2 + dst_off_x, pbox->y2 + dst_off_y); 30605b261ecSmrg pbox++; 30705b261ecSmrg } 30805b261ecSmrg 30905b261ecSmrg (*pExaScr->info->DoneSolid) (pDstPix); 31005b261ecSmrg exaMarkSync(pDst->pDrawable->pScreen); 31105b261ecSmrg 31205b261ecSmrg REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); 31305b261ecSmrg return 1; 31405b261ecSmrg} 31505b261ecSmrg 31605b261ecSmrgstatic int 31705b261ecSmrgexaTryDriverComposite(CARD8 op, 31805b261ecSmrg PicturePtr pSrc, 31905b261ecSmrg PicturePtr pMask, 32005b261ecSmrg PicturePtr pDst, 32105b261ecSmrg INT16 xSrc, 32205b261ecSmrg INT16 ySrc, 32305b261ecSmrg INT16 xMask, 32405b261ecSmrg INT16 yMask, 32505b261ecSmrg INT16 xDst, 32605b261ecSmrg INT16 yDst, 32705b261ecSmrg CARD16 width, 32805b261ecSmrg CARD16 height) 32905b261ecSmrg{ 33005b261ecSmrg ExaScreenPriv (pDst->pDrawable->pScreen); 33105b261ecSmrg RegionRec region; 33205b261ecSmrg BoxPtr pbox; 33305b261ecSmrg int nbox; 33405b261ecSmrg int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y; 33505b261ecSmrg PixmapPtr pSrcPix, pMaskPix = NULL, pDstPix; 33605b261ecSmrg struct _Pixmap scratch; 33705b261ecSmrg ExaMigrationRec pixmaps[3]; 33805b261ecSmrg 33905b261ecSmrg pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable); 34005b261ecSmrg pDstPix = exaGetDrawablePixmap(pDst->pDrawable); 34105b261ecSmrg if (pMask) 34205b261ecSmrg pMaskPix = exaGetDrawablePixmap(pMask->pDrawable); 34305b261ecSmrg 34405b261ecSmrg /* Bail if we might exceed coord limits by rendering from/to these. We 34505b261ecSmrg * should really be making some scratch pixmaps with offsets and coords 34605b261ecSmrg * adjusted to deal with this, but it hasn't been done yet. 34705b261ecSmrg */ 34805b261ecSmrg if (pSrcPix->drawable.width > pExaScr->info->maxX || 34905b261ecSmrg pSrcPix->drawable.height > pExaScr->info->maxY || 35005b261ecSmrg pDstPix->drawable.width > pExaScr->info->maxX || 35105b261ecSmrg pDstPix->drawable.height > pExaScr->info->maxY || 35205b261ecSmrg (pMask && (pMaskPix->drawable.width > pExaScr->info->maxX || 35305b261ecSmrg pMaskPix->drawable.height > pExaScr->info->maxY))) 35405b261ecSmrg { 35505b261ecSmrg return -1; 35605b261ecSmrg } 35705b261ecSmrg 35805b261ecSmrg xDst += pDst->pDrawable->x; 35905b261ecSmrg yDst += pDst->pDrawable->y; 36005b261ecSmrg 36105b261ecSmrg if (pMask) { 36205b261ecSmrg xMask += pMask->pDrawable->x; 36305b261ecSmrg yMask += pMask->pDrawable->y; 36405b261ecSmrg } 36505b261ecSmrg 36605b261ecSmrg xSrc += pSrc->pDrawable->x; 36705b261ecSmrg ySrc += pSrc->pDrawable->y; 36805b261ecSmrg 36905b261ecSmrg if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, 37005b261ecSmrg xSrc, ySrc, xMask, yMask, xDst, yDst, 37105b261ecSmrg width, height)) 37205b261ecSmrg return 1; 37305b261ecSmrg 37405b261ecSmrg if (pExaScr->info->CheckComposite && 37505b261ecSmrg !(*pExaScr->info->CheckComposite) (op, pSrc, pMask, pDst)) 37605b261ecSmrg { 37705b261ecSmrg REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); 37805b261ecSmrg return -1; 37905b261ecSmrg } 38005b261ecSmrg 38105b261ecSmrg pixmaps[0].as_dst = TRUE; 38205b261ecSmrg pixmaps[0].as_src = exaOpReadsDestination(op); 38305b261ecSmrg pixmaps[0].pPix = exaGetDrawablePixmap (pDst->pDrawable); 38405b261ecSmrg pixmaps[1].as_dst = FALSE; 38505b261ecSmrg pixmaps[1].as_src = TRUE; 38605b261ecSmrg pixmaps[1].pPix = exaGetDrawablePixmap (pSrc->pDrawable); 38705b261ecSmrg if (pMask) { 38805b261ecSmrg pixmaps[2].as_dst = FALSE; 38905b261ecSmrg pixmaps[2].as_src = TRUE; 39005b261ecSmrg pixmaps[2].pPix = exaGetDrawablePixmap (pMask->pDrawable); 39105b261ecSmrg exaDoMigration(pixmaps, 3, TRUE); 39205b261ecSmrg } else { 39305b261ecSmrg exaDoMigration(pixmaps, 2, TRUE); 39405b261ecSmrg } 39505b261ecSmrg 39605b261ecSmrg pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y); 39705b261ecSmrg if (pMask) 39805b261ecSmrg pMaskPix = exaGetOffscreenPixmap (pMask->pDrawable, &mask_off_x, 39905b261ecSmrg &mask_off_y); 40005b261ecSmrg pDstPix = exaGetOffscreenPixmap (pDst->pDrawable, &dst_off_x, &dst_off_y); 40105b261ecSmrg 40205b261ecSmrg if (!pDstPix) { 40305b261ecSmrg REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); 40405b261ecSmrg return 0; 40505b261ecSmrg } 40605b261ecSmrg 40705b261ecSmrg if (!pSrcPix && (!pMask || pMaskPix) && pExaScr->info->UploadToScratch) { 40805b261ecSmrg pSrcPix = exaGetDrawablePixmap (pSrc->pDrawable); 40905b261ecSmrg if ((*pExaScr->info->UploadToScratch) (pSrcPix, &scratch)) 41005b261ecSmrg pSrcPix = &scratch; 41105b261ecSmrg } else if (pSrcPix && pMask && !pMaskPix && pExaScr->info->UploadToScratch) { 41205b261ecSmrg pMaskPix = exaGetDrawablePixmap (pMask->pDrawable); 41305b261ecSmrg if ((*pExaScr->info->UploadToScratch) (pMaskPix, &scratch)) 41405b261ecSmrg pMaskPix = &scratch; 41505b261ecSmrg } 41605b261ecSmrg 41705b261ecSmrg if (!pSrcPix || (pMask && !pMaskPix)) { 41805b261ecSmrg REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); 41905b261ecSmrg return 0; 42005b261ecSmrg } 42105b261ecSmrg 42205b261ecSmrg if (!(*pExaScr->info->PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix, 42305b261ecSmrg pMaskPix, pDstPix)) 42405b261ecSmrg { 42505b261ecSmrg REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); 42605b261ecSmrg return -1; 42705b261ecSmrg } 42805b261ecSmrg 42905b261ecSmrg nbox = REGION_NUM_RECTS(®ion); 43005b261ecSmrg pbox = REGION_RECTS(®ion); 43105b261ecSmrg 43205b261ecSmrg xMask -= xDst; 43305b261ecSmrg yMask -= yDst; 43405b261ecSmrg 43505b261ecSmrg xSrc -= xDst; 43605b261ecSmrg ySrc -= yDst; 43705b261ecSmrg 43805b261ecSmrg while (nbox--) 43905b261ecSmrg { 44005b261ecSmrg (*pExaScr->info->Composite) (pDstPix, 44105b261ecSmrg pbox->x1 + xSrc + src_off_x, 44205b261ecSmrg pbox->y1 + ySrc + src_off_y, 44305b261ecSmrg pbox->x1 + xMask + mask_off_x, 44405b261ecSmrg pbox->y1 + yMask + mask_off_y, 44505b261ecSmrg pbox->x1 + dst_off_x, 44605b261ecSmrg pbox->y1 + dst_off_y, 44705b261ecSmrg pbox->x2 - pbox->x1, 44805b261ecSmrg pbox->y2 - pbox->y1); 44905b261ecSmrg pbox++; 45005b261ecSmrg } 45105b261ecSmrg (*pExaScr->info->DoneComposite) (pDstPix); 45205b261ecSmrg exaMarkSync(pDst->pDrawable->pScreen); 45305b261ecSmrg 45405b261ecSmrg REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); 45505b261ecSmrg return 1; 45605b261ecSmrg} 45705b261ecSmrg 45805b261ecSmrg/** 45905b261ecSmrg * exaTryMagicTwoPassCompositeHelper implements PictOpOver using two passes of 46005b261ecSmrg * simpler operations PictOpOutReverse and PictOpAdd. Mainly used for component 46105b261ecSmrg * alpha and limited 1-tmu cards. 46205b261ecSmrg * 46305b261ecSmrg * From http://anholt.livejournal.com/32058.html: 46405b261ecSmrg * 46505b261ecSmrg * The trouble is that component-alpha rendering requires two different sources 46605b261ecSmrg * for blending: one for the source value to the blender, which is the 46705b261ecSmrg * per-channel multiplication of source and mask, and one for the source alpha 46805b261ecSmrg * for multiplying with the destination channels, which is the multiplication 46905b261ecSmrg * of the source channels by the mask alpha. So the equation for Over is: 47005b261ecSmrg * 47105b261ecSmrg * dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A 47205b261ecSmrg * dst.R = src.R * mask.R + (1 - (src.A * mask.R)) * dst.R 47305b261ecSmrg * dst.G = src.G * mask.G + (1 - (src.A * mask.G)) * dst.G 47405b261ecSmrg * dst.B = src.B * mask.B + (1 - (src.A * mask.B)) * dst.B 47505b261ecSmrg * 47605b261ecSmrg * But we can do some simpler operations, right? How about PictOpOutReverse, 47705b261ecSmrg * which has a source factor of 0 and dest factor of (1 - source alpha). We 47805b261ecSmrg * can get the source alpha value (srca.X = src.A * mask.X) out of the texture 47905b261ecSmrg * blenders pretty easily. So we can do a component-alpha OutReverse, which 48005b261ecSmrg * gets us: 48105b261ecSmrg * 48205b261ecSmrg * dst.A = 0 + (1 - (src.A * mask.A)) * dst.A 48305b261ecSmrg * dst.R = 0 + (1 - (src.A * mask.R)) * dst.R 48405b261ecSmrg * dst.G = 0 + (1 - (src.A * mask.G)) * dst.G 48505b261ecSmrg * dst.B = 0 + (1 - (src.A * mask.B)) * dst.B 48605b261ecSmrg * 48705b261ecSmrg * OK. And if an op doesn't use the source alpha value for the destination 48805b261ecSmrg * factor, then we can do the channel multiplication in the texture blenders 48905b261ecSmrg * to get the source value, and ignore the source alpha that we wouldn't use. 49005b261ecSmrg * We've supported this in the Radeon driver for a long time. An example would 49105b261ecSmrg * be PictOpAdd, which does: 49205b261ecSmrg * 49305b261ecSmrg * dst.A = src.A * mask.A + dst.A 49405b261ecSmrg * dst.R = src.R * mask.R + dst.R 49505b261ecSmrg * dst.G = src.G * mask.G + dst.G 49605b261ecSmrg * dst.B = src.B * mask.B + dst.B 49705b261ecSmrg * 49805b261ecSmrg * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right 49905b261ecSmrg * after it, we get: 50005b261ecSmrg * 50105b261ecSmrg * dst.A = src.A * mask.A + ((1 - (src.A * mask.A)) * dst.A) 50205b261ecSmrg * dst.R = src.R * mask.R + ((1 - (src.A * mask.R)) * dst.R) 50305b261ecSmrg * dst.G = src.G * mask.G + ((1 - (src.A * mask.G)) * dst.G) 50405b261ecSmrg * dst.B = src.B * mask.B + ((1 - (src.A * mask.B)) * dst.B) 50505b261ecSmrg */ 50605b261ecSmrg 50705b261ecSmrgstatic int 50805b261ecSmrgexaTryMagicTwoPassCompositeHelper(CARD8 op, 50905b261ecSmrg PicturePtr pSrc, 51005b261ecSmrg PicturePtr pMask, 51105b261ecSmrg PicturePtr pDst, 51205b261ecSmrg INT16 xSrc, 51305b261ecSmrg INT16 ySrc, 51405b261ecSmrg INT16 xMask, 51505b261ecSmrg INT16 yMask, 51605b261ecSmrg INT16 xDst, 51705b261ecSmrg INT16 yDst, 51805b261ecSmrg CARD16 width, 51905b261ecSmrg CARD16 height) 52005b261ecSmrg{ 52105b261ecSmrg ExaScreenPriv (pDst->pDrawable->pScreen); 52205b261ecSmrg DrawablePtr pDstDraw = pDst->pDrawable; 52305b261ecSmrg PixmapPtr pDstPixmap = exaGetDrawablePixmap(pDstDraw); 52405b261ecSmrg int xoff, yoff; 52505b261ecSmrg 52605b261ecSmrg assert(op == PictOpOver); 52705b261ecSmrg 52805b261ecSmrg if (pExaScr->info->CheckComposite && 52905b261ecSmrg (!(*pExaScr->info->CheckComposite)(PictOpOutReverse, pSrc, pMask, 53005b261ecSmrg pDst) || 53105b261ecSmrg !(*pExaScr->info->CheckComposite)(PictOpAdd, pSrc, pMask, pDst))) 53205b261ecSmrg { 53305b261ecSmrg return -1; 53405b261ecSmrg } 53505b261ecSmrg 53605b261ecSmrg /* Now, we think we should be able to accelerate this operation. First, 53705b261ecSmrg * composite the destination to be the destination times the source alpha 53805b261ecSmrg * factors. 53905b261ecSmrg */ 54005b261ecSmrg exaComposite(PictOpOutReverse, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, 54105b261ecSmrg xDst, yDst, width, height); 54205b261ecSmrg 54305b261ecSmrg exaGetDrawableDeltas(pDstDraw, pDstPixmap, &xoff, &yoff); 54405b261ecSmrg xoff += pDstDraw->x; 54505b261ecSmrg yoff += pDstDraw->y; 54605b261ecSmrg exaPixmapDirty(pDstPixmap, xDst + xoff, yDst + yoff, xDst + xoff + width, 54705b261ecSmrg yDst + yoff + height); 54805b261ecSmrg 54905b261ecSmrg /* Then, add in the source value times the destination alpha factors (1.0). 55005b261ecSmrg */ 55105b261ecSmrg exaComposite(PictOpAdd, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, 55205b261ecSmrg xDst, yDst, width, height); 55305b261ecSmrg 55405b261ecSmrg return 1; 55505b261ecSmrg} 55605b261ecSmrg 55705b261ecSmrgvoid 55805b261ecSmrgexaComposite(CARD8 op, 55905b261ecSmrg PicturePtr pSrc, 56005b261ecSmrg PicturePtr pMask, 56105b261ecSmrg PicturePtr pDst, 56205b261ecSmrg INT16 xSrc, 56305b261ecSmrg INT16 ySrc, 56405b261ecSmrg INT16 xMask, 56505b261ecSmrg INT16 yMask, 56605b261ecSmrg INT16 xDst, 56705b261ecSmrg INT16 yDst, 56805b261ecSmrg CARD16 width, 56905b261ecSmrg CARD16 height) 57005b261ecSmrg{ 57105b261ecSmrg ExaScreenPriv (pDst->pDrawable->pScreen); 57205b261ecSmrg int ret = -1; 57305b261ecSmrg Bool saveSrcRepeat = pSrc->repeat; 57405b261ecSmrg Bool saveMaskRepeat = pMask ? pMask->repeat : 0; 57505b261ecSmrg ExaMigrationRec pixmaps[3]; 57605b261ecSmrg int npixmaps = 1; 57705b261ecSmrg PixmapPtr pSrcPixmap = NULL; 57805b261ecSmrg 57905b261ecSmrg pixmaps[0].as_dst = TRUE; 58005b261ecSmrg pixmaps[0].as_src = exaOpReadsDestination(op); 58105b261ecSmrg pixmaps[0].pPix = exaGetDrawablePixmap (pDst->pDrawable); 58205b261ecSmrg 58305b261ecSmrg if (pSrc->pDrawable) { 58405b261ecSmrg pSrcPixmap = exaGetDrawablePixmap (pSrc->pDrawable); 58505b261ecSmrg pixmaps[npixmaps].as_dst = FALSE; 58605b261ecSmrg pixmaps[npixmaps].as_src = TRUE; 58705b261ecSmrg pixmaps[npixmaps].pPix = pSrcPixmap; 58805b261ecSmrg npixmaps++; 58905b261ecSmrg } 59005b261ecSmrg 59105b261ecSmrg if (pMask && pMask->pDrawable) { 59205b261ecSmrg pixmaps[npixmaps].as_dst = FALSE; 59305b261ecSmrg pixmaps[npixmaps].as_src = TRUE; 59405b261ecSmrg pixmaps[npixmaps].pPix = exaGetDrawablePixmap (pMask->pDrawable); 59505b261ecSmrg npixmaps++; 59605b261ecSmrg } 59705b261ecSmrg 59805b261ecSmrg /* We currently don't support acceleration of gradients, or other pictures 59905b261ecSmrg * with a NULL pDrawable. 60005b261ecSmrg */ 60105b261ecSmrg if (pExaScr->swappedOut || 60205b261ecSmrg pSrc->pDrawable == NULL || (pMask != NULL && pMask->pDrawable == NULL)) 60305b261ecSmrg { 60405b261ecSmrg goto fallback; 60505b261ecSmrg } 60605b261ecSmrg 60705b261ecSmrg /* Remove repeat in source if useless */ 60805b261ecSmrg if (pSrc->repeat && !pSrc->transform && xSrc >= 0 && 60905b261ecSmrg (xSrc + width) <= pSrc->pDrawable->width && ySrc >= 0 && 61005b261ecSmrg (ySrc + height) <= pSrc->pDrawable->height) 61105b261ecSmrg pSrc->repeat = 0; 61205b261ecSmrg 61305b261ecSmrg if (!pMask) 61405b261ecSmrg { 61505b261ecSmrg if ((op == PictOpSrc && 61605b261ecSmrg ((pSrc->format == pDst->format) || 61705b261ecSmrg (pSrc->format==PICT_a8r8g8b8 && pDst->format==PICT_x8r8g8b8) || 61805b261ecSmrg (pSrc->format==PICT_a8b8g8r8 && pDst->format==PICT_x8b8g8r8))) || 61905b261ecSmrg (op == PictOpOver && !pSrc->alphaMap && !pDst->alphaMap && 62005b261ecSmrg pSrc->format == pDst->format && 62105b261ecSmrg (pSrc->format==PICT_x8r8g8b8 || pSrc->format==PICT_x8b8g8r8))) 62205b261ecSmrg { 62305b261ecSmrg if (pSrc->pDrawable->width == 1 && 62405b261ecSmrg pSrc->pDrawable->height == 1 && 62505b261ecSmrg pSrc->repeat) 62605b261ecSmrg { 62705b261ecSmrg ret = exaTryDriverSolidFill(pSrc, pDst, xSrc, ySrc, xDst, yDst, 62805b261ecSmrg width, height); 62905b261ecSmrg if (ret == 1) 63005b261ecSmrg goto done; 63105b261ecSmrg } 63205b261ecSmrg else if (pSrcPixmap && !pSrc->repeat && !pSrc->transform) 63305b261ecSmrg { 63405b261ecSmrg RegionRec region; 63505b261ecSmrg 63605b261ecSmrg xDst += pDst->pDrawable->x; 63705b261ecSmrg yDst += pDst->pDrawable->y; 63805b261ecSmrg xSrc += pSrc->pDrawable->x; 63905b261ecSmrg ySrc += pSrc->pDrawable->y; 64005b261ecSmrg 64105b261ecSmrg if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, 64205b261ecSmrg xSrc, ySrc, xMask, yMask, xDst, 64305b261ecSmrg yDst, width, height)) 64405b261ecSmrg goto done; 64505b261ecSmrg 64605b261ecSmrg 64705b261ecSmrg exaCopyNtoN (pSrc->pDrawable, pDst->pDrawable, NULL, 64805b261ecSmrg REGION_RECTS(®ion), REGION_NUM_RECTS(®ion), 64905b261ecSmrg xSrc - xDst, ySrc - yDst, 65005b261ecSmrg FALSE, FALSE, 0, NULL); 65105b261ecSmrg REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); 65205b261ecSmrg goto done; 65305b261ecSmrg } 65405b261ecSmrg else if (pSrcPixmap && !pSrc->transform && 65505b261ecSmrg pSrc->repeatType == RepeatNormal) 65605b261ecSmrg { 65705b261ecSmrg RegionRec region; 65805b261ecSmrg DDXPointRec srcOrg; 65905b261ecSmrg 66005b261ecSmrg /* Let's see if the driver can do the repeat in one go */ 66105b261ecSmrg if (pExaScr->info->PrepareComposite && !pSrc->alphaMap && 66205b261ecSmrg !pDst->alphaMap) 66305b261ecSmrg { 66405b261ecSmrg ret = exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc, 66505b261ecSmrg ySrc, xMask, yMask, xDst, yDst, 66605b261ecSmrg width, height); 66705b261ecSmrg if (ret == 1) 66805b261ecSmrg goto done; 66905b261ecSmrg } 67005b261ecSmrg 67105b261ecSmrg /* Now see if we can use exaFillRegionTiled() */ 67205b261ecSmrg xDst += pDst->pDrawable->x; 67305b261ecSmrg yDst += pDst->pDrawable->y; 67405b261ecSmrg xSrc += pSrc->pDrawable->x; 67505b261ecSmrg ySrc += pSrc->pDrawable->y; 67605b261ecSmrg 67705b261ecSmrg if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, xSrc, 67805b261ecSmrg ySrc, xMask, yMask, xDst, yDst, 67905b261ecSmrg width, height)) 68005b261ecSmrg goto done; 68105b261ecSmrg 68205b261ecSmrg srcOrg.x = (xSrc - xDst) % pSrcPixmap->drawable.width; 68305b261ecSmrg srcOrg.y = (ySrc - yDst) % pSrcPixmap->drawable.height; 68405b261ecSmrg 68505b261ecSmrg ret = exaFillRegionTiled(pDst->pDrawable, ®ion, pSrcPixmap, 68605b261ecSmrg &srcOrg, FB_ALLONES, GXcopy); 68705b261ecSmrg 68805b261ecSmrg REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); 68905b261ecSmrg 69005b261ecSmrg if (ret) 69105b261ecSmrg goto done; 69205b261ecSmrg } 69305b261ecSmrg } 69405b261ecSmrg } 69505b261ecSmrg 69605b261ecSmrg /* Remove repeat in mask if useless */ 69705b261ecSmrg if (pMask && pMask->repeat && !pMask->transform && xMask >= 0 && 69805b261ecSmrg (xMask + width) <= pMask->pDrawable->width && yMask >= 0 && 69905b261ecSmrg (yMask + height) <= pMask->pDrawable->height) 70005b261ecSmrg pMask->repeat = 0; 70105b261ecSmrg 70205b261ecSmrg if (pExaScr->info->PrepareComposite && 70305b261ecSmrg (!pSrc->repeat || pSrc->repeatType == RepeatNormal) && 70405b261ecSmrg (!pMask || !pMask->repeat || pMask->repeatType == RepeatNormal) && 70505b261ecSmrg !pSrc->alphaMap && (!pMask || !pMask->alphaMap) && !pDst->alphaMap) 70605b261ecSmrg { 70705b261ecSmrg Bool isSrcSolid; 70805b261ecSmrg 70905b261ecSmrg ret = exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask, 71005b261ecSmrg yMask, xDst, yDst, width, height); 71105b261ecSmrg if (ret == 1) 71205b261ecSmrg goto done; 71305b261ecSmrg 71405b261ecSmrg /* For generic masks and solid src pictures, mach64 can do Over in two 71505b261ecSmrg * passes, similar to the component-alpha case. 71605b261ecSmrg */ 71705b261ecSmrg isSrcSolid = pSrc->pDrawable->width == 1 && 71805b261ecSmrg pSrc->pDrawable->height == 1 && 71905b261ecSmrg pSrc->repeat; 72005b261ecSmrg 72105b261ecSmrg /* If we couldn't do the Composite in a single pass, and it was a 72205b261ecSmrg * component-alpha Over, see if we can do it in two passes with 72305b261ecSmrg * an OutReverse and then an Add. 72405b261ecSmrg */ 72505b261ecSmrg if (ret == -1 && op == PictOpOver && pMask && 72605b261ecSmrg (pMask->componentAlpha || isSrcSolid)) { 72705b261ecSmrg ret = exaTryMagicTwoPassCompositeHelper(op, pSrc, pMask, pDst, 72805b261ecSmrg xSrc, ySrc, 72905b261ecSmrg xMask, yMask, xDst, yDst, 73005b261ecSmrg width, height); 73105b261ecSmrg if (ret == 1) 73205b261ecSmrg goto done; 73305b261ecSmrg } 73405b261ecSmrg } 73505b261ecSmrg 73605b261ecSmrgfallback: 73705b261ecSmrg#if DEBUG_TRACE_FALL 73805b261ecSmrg exaPrintCompositeFallback (op, pSrc, pMask, pDst); 73905b261ecSmrg#endif 74005b261ecSmrg 74105b261ecSmrg exaDoMigration(pixmaps, npixmaps, FALSE); 74205b261ecSmrg ExaCheckComposite (op, pSrc, pMask, pDst, xSrc, ySrc, 74305b261ecSmrg xMask, yMask, xDst, yDst, width, height); 74405b261ecSmrg 74505b261ecSmrgdone: 74605b261ecSmrg pSrc->repeat = saveSrcRepeat; 74705b261ecSmrg if (pMask) 74805b261ecSmrg pMask->repeat = saveMaskRepeat; 74905b261ecSmrg} 75005b261ecSmrg#endif 75105b261ecSmrg 75205b261ecSmrg/** 75305b261ecSmrg * Same as miCreateAlphaPicture, except it uses ExaCheckPolyFillRect instead 75405b261ecSmrg * of PolyFillRect to initialize the pixmap after creating it, to prevent 75505b261ecSmrg * the pixmap from being migrated. 75605b261ecSmrg * 75705b261ecSmrg * See the comments about exaTrapezoids. 75805b261ecSmrg */ 75905b261ecSmrgstatic PicturePtr 76005b261ecSmrgexaCreateAlphaPicture (ScreenPtr pScreen, 76105b261ecSmrg PicturePtr pDst, 76205b261ecSmrg PictFormatPtr pPictFormat, 76305b261ecSmrg CARD16 width, 76405b261ecSmrg CARD16 height) 76505b261ecSmrg{ 76605b261ecSmrg PixmapPtr pPixmap; 76705b261ecSmrg PicturePtr pPicture; 76805b261ecSmrg GCPtr pGC; 76905b261ecSmrg int error; 77005b261ecSmrg xRectangle rect; 77105b261ecSmrg 77205b261ecSmrg if (width > 32767 || height > 32767) 77305b261ecSmrg return 0; 77405b261ecSmrg 77505b261ecSmrg if (!pPictFormat) 77605b261ecSmrg { 77705b261ecSmrg if (pDst->polyEdge == PolyEdgeSharp) 77805b261ecSmrg pPictFormat = PictureMatchFormat (pScreen, 1, PICT_a1); 77905b261ecSmrg else 78005b261ecSmrg pPictFormat = PictureMatchFormat (pScreen, 8, PICT_a8); 78105b261ecSmrg if (!pPictFormat) 78205b261ecSmrg return 0; 78305b261ecSmrg } 78405b261ecSmrg 78505b261ecSmrg pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, 78605b261ecSmrg pPictFormat->depth); 78705b261ecSmrg if (!pPixmap) 78805b261ecSmrg return 0; 78905b261ecSmrg pGC = GetScratchGC (pPixmap->drawable.depth, pScreen); 79005b261ecSmrg if (!pGC) 79105b261ecSmrg { 79205b261ecSmrg (*pScreen->DestroyPixmap) (pPixmap); 79305b261ecSmrg return 0; 79405b261ecSmrg } 79505b261ecSmrg ValidateGC (&pPixmap->drawable, pGC); 79605b261ecSmrg rect.x = 0; 79705b261ecSmrg rect.y = 0; 79805b261ecSmrg rect.width = width; 79905b261ecSmrg rect.height = height; 80005b261ecSmrg ExaCheckPolyFillRect (&pPixmap->drawable, pGC, 1, &rect); 80105b261ecSmrg exaPixmapDirty (pPixmap, 0, 0, width, height); 80205b261ecSmrg FreeScratchGC (pGC); 80305b261ecSmrg pPicture = CreatePicture (0, &pPixmap->drawable, pPictFormat, 80405b261ecSmrg 0, 0, serverClient, &error); 80505b261ecSmrg (*pScreen->DestroyPixmap) (pPixmap); 80605b261ecSmrg return pPicture; 80705b261ecSmrg} 80805b261ecSmrg 80905b261ecSmrg/** 81005b261ecSmrg * exaTrapezoids is essentially a copy of miTrapezoids that uses 81105b261ecSmrg * exaCreateAlphaPicture instead of miCreateAlphaPicture. 81205b261ecSmrg * 81305b261ecSmrg * The problem with miCreateAlphaPicture is that it calls PolyFillRect 81405b261ecSmrg * to initialize the contents after creating the pixmap, which 81505b261ecSmrg * causes the pixmap to be moved in for acceleration. The subsequent 81605b261ecSmrg * call to RasterizeTrapezoid won't be accelerated however, which 81705b261ecSmrg * forces the pixmap to be moved out again. 81805b261ecSmrg * 81905b261ecSmrg * exaCreateAlphaPicture avoids this roundtrip by using ExaCheckPolyFillRect 82005b261ecSmrg * to initialize the contents. 82105b261ecSmrg */ 82205b261ecSmrgvoid 82305b261ecSmrgexaTrapezoids (CARD8 op, PicturePtr pSrc, PicturePtr pDst, 82405b261ecSmrg PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, 82505b261ecSmrg int ntrap, xTrapezoid *traps) 82605b261ecSmrg{ 82705b261ecSmrg ScreenPtr pScreen = pDst->pDrawable->pScreen; 82805b261ecSmrg PictureScreenPtr ps = GetPictureScreen(pScreen); 82905b261ecSmrg 83005b261ecSmrg /* 83105b261ecSmrg * Check for solid alpha add 83205b261ecSmrg */ 83305b261ecSmrg if (op == PictOpAdd && miIsSolidAlpha (pSrc)) 83405b261ecSmrg { 83505b261ecSmrg for (; ntrap; ntrap--, traps++) 83605b261ecSmrg (*ps->RasterizeTrapezoid) (pDst, traps, 0, 0); 83705b261ecSmrg } 83805b261ecSmrg else if (maskFormat) 83905b261ecSmrg { 84005b261ecSmrg PicturePtr pPicture; 84105b261ecSmrg BoxRec bounds; 84205b261ecSmrg INT16 xDst, yDst; 84305b261ecSmrg INT16 xRel, yRel; 84405b261ecSmrg 84505b261ecSmrg xDst = traps[0].left.p1.x >> 16; 84605b261ecSmrg yDst = traps[0].left.p1.y >> 16; 84705b261ecSmrg 84805b261ecSmrg miTrapezoidBounds (ntrap, traps, &bounds); 84905b261ecSmrg if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) 85005b261ecSmrg return; 85105b261ecSmrg pPicture = exaCreateAlphaPicture (pScreen, pDst, maskFormat, 85205b261ecSmrg bounds.x2 - bounds.x1, 85305b261ecSmrg bounds.y2 - bounds.y1); 85405b261ecSmrg if (!pPicture) 85505b261ecSmrg return; 85605b261ecSmrg for (; ntrap; ntrap--, traps++) 85705b261ecSmrg (*ps->RasterizeTrapezoid) (pPicture, traps, 85805b261ecSmrg -bounds.x1, -bounds.y1); 85905b261ecSmrg xRel = bounds.x1 + xSrc - xDst; 86005b261ecSmrg yRel = bounds.y1 + ySrc - yDst; 86105b261ecSmrg CompositePicture (op, pSrc, pPicture, pDst, 86205b261ecSmrg xRel, yRel, 0, 0, bounds.x1, bounds.y1, 86305b261ecSmrg bounds.x2 - bounds.x1, 86405b261ecSmrg bounds.y2 - bounds.y1); 86505b261ecSmrg FreePicture (pPicture, 0); 86605b261ecSmrg } 86705b261ecSmrg else 86805b261ecSmrg { 86905b261ecSmrg if (pDst->polyEdge == PolyEdgeSharp) 87005b261ecSmrg maskFormat = PictureMatchFormat (pScreen, 1, PICT_a1); 87105b261ecSmrg else 87205b261ecSmrg maskFormat = PictureMatchFormat (pScreen, 8, PICT_a8); 87305b261ecSmrg for (; ntrap; ntrap--, traps++) 87405b261ecSmrg exaTrapezoids (op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, traps); 87505b261ecSmrg } 87605b261ecSmrg} 87705b261ecSmrg 87805b261ecSmrg#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0) 87905b261ecSmrg 88005b261ecSmrg/** 88105b261ecSmrg * exaRasterizeTrapezoid is just a wrapper around the software implementation. 88205b261ecSmrg * 88305b261ecSmrg * The trapezoid specification is basically too hard to be done in hardware (at 88405b261ecSmrg * the very least, without programmability), so we just do the appropriate 88505b261ecSmrg * Prepare/FinishAccess for it before using fbtrap.c. 88605b261ecSmrg */ 88705b261ecSmrgvoid 88805b261ecSmrgexaRasterizeTrapezoid (PicturePtr pPicture, xTrapezoid *trap, 88905b261ecSmrg int x_off, int y_off) 89005b261ecSmrg{ 89105b261ecSmrg DrawablePtr pDraw = pPicture->pDrawable; 89205b261ecSmrg ExaMigrationRec pixmaps[1]; 89305b261ecSmrg int xoff, yoff; 89405b261ecSmrg 89505b261ecSmrg pixmaps[0].as_dst = TRUE; 89605b261ecSmrg pixmaps[0].as_src = TRUE; 89705b261ecSmrg pixmaps[0].pPix = exaGetDrawablePixmap (pDraw); 89805b261ecSmrg exaDoMigration(pixmaps, 1, FALSE); 89905b261ecSmrg 90005b261ecSmrg exaPrepareAccess(pDraw, EXA_PREPARE_DEST); 90105b261ecSmrg fbRasterizeTrapezoid(pPicture, trap, x_off, y_off); 90205b261ecSmrg exaGetDrawableDeltas(pDraw, pixmaps[0].pPix, &xoff, &yoff); 90305b261ecSmrg exaPixmapDirty(pixmaps[0].pPix, pDraw->x + xoff, pDraw->y + yoff, 90405b261ecSmrg pDraw->x + xoff + pDraw->width, 90505b261ecSmrg pDraw->y + yoff + pDraw->height); 90605b261ecSmrg exaFinishAccess(pDraw, EXA_PREPARE_DEST); 90705b261ecSmrg} 90805b261ecSmrg 90905b261ecSmrg/** 91005b261ecSmrg * exaAddTriangles does migration and syncing before dumping down to the 91105b261ecSmrg * software implementation. 91205b261ecSmrg */ 91305b261ecSmrgvoid 91405b261ecSmrgexaAddTriangles (PicturePtr pPicture, INT16 x_off, INT16 y_off, int ntri, 91505b261ecSmrg xTriangle *tris) 91605b261ecSmrg{ 91705b261ecSmrg DrawablePtr pDraw = pPicture->pDrawable; 91805b261ecSmrg ExaMigrationRec pixmaps[1]; 91905b261ecSmrg int xoff, yoff; 92005b261ecSmrg 92105b261ecSmrg pixmaps[0].as_dst = TRUE; 92205b261ecSmrg pixmaps[0].as_src = TRUE; 92305b261ecSmrg pixmaps[0].pPix = exaGetDrawablePixmap (pDraw); 92405b261ecSmrg exaDoMigration(pixmaps, 1, FALSE); 92505b261ecSmrg 92605b261ecSmrg exaPrepareAccess(pDraw, EXA_PREPARE_DEST); 92705b261ecSmrg fbAddTriangles(pPicture, x_off, y_off, ntri, tris); 92805b261ecSmrg exaGetDrawableDeltas(pDraw, pixmaps[0].pPix, &xoff, &yoff); 92905b261ecSmrg exaPixmapDirty(pixmaps[0].pPix, pDraw->x + xoff, pDraw->y + yoff, 93005b261ecSmrg pDraw->x + xoff + pDraw->width, 93105b261ecSmrg pDraw->y + yoff + pDraw->height); 93205b261ecSmrg exaFinishAccess(pDraw, EXA_PREPARE_DEST); 93305b261ecSmrg} 93405b261ecSmrg 93505b261ecSmrg/** 93605b261ecSmrg * Returns TRUE if the glyphs in the lists intersect. Only checks based on 93705b261ecSmrg * bounding box, which appears to be good enough to catch most cases at least. 93805b261ecSmrg */ 93905b261ecSmrgstatic Bool 94005b261ecSmrgexaGlyphsIntersect(int nlist, GlyphListPtr list, GlyphPtr *glyphs) 94105b261ecSmrg{ 94205b261ecSmrg int x1, x2, y1, y2; 94305b261ecSmrg int n; 94405b261ecSmrg GlyphPtr glyph; 94505b261ecSmrg int x, y; 94605b261ecSmrg BoxRec extents; 94705b261ecSmrg Bool first = TRUE; 94805b261ecSmrg 94905b261ecSmrg x = 0; 95005b261ecSmrg y = 0; 95105b261ecSmrg while (nlist--) { 95205b261ecSmrg x += list->xOff; 95305b261ecSmrg y += list->yOff; 95405b261ecSmrg n = list->len; 95505b261ecSmrg list++; 95605b261ecSmrg while (n--) { 95705b261ecSmrg glyph = *glyphs++; 95805b261ecSmrg 95905b261ecSmrg if (glyph->info.width == 0 || glyph->info.height == 0) { 96005b261ecSmrg x += glyph->info.xOff; 96105b261ecSmrg y += glyph->info.yOff; 96205b261ecSmrg continue; 96305b261ecSmrg } 96405b261ecSmrg 96505b261ecSmrg x1 = x - glyph->info.x; 96605b261ecSmrg if (x1 < MINSHORT) 96705b261ecSmrg x1 = MINSHORT; 96805b261ecSmrg y1 = y - glyph->info.y; 96905b261ecSmrg if (y1 < MINSHORT) 97005b261ecSmrg y1 = MINSHORT; 97105b261ecSmrg x2 = x1 + glyph->info.width; 97205b261ecSmrg if (x2 > MAXSHORT) 97305b261ecSmrg x2 = MAXSHORT; 97405b261ecSmrg y2 = y1 + glyph->info.height; 97505b261ecSmrg if (y2 > MAXSHORT) 97605b261ecSmrg y2 = MAXSHORT; 97705b261ecSmrg 97805b261ecSmrg if (first) { 97905b261ecSmrg extents.x1 = x1; 98005b261ecSmrg extents.y1 = y1; 98105b261ecSmrg extents.x2 = x2; 98205b261ecSmrg extents.y2 = y2; 98305b261ecSmrg first = FALSE; 98405b261ecSmrg } else { 98505b261ecSmrg if (x1 < extents.x2 && x2 > extents.x1 && 98605b261ecSmrg y1 < extents.y2 && y2 > extents.y1) 98705b261ecSmrg { 98805b261ecSmrg return TRUE; 98905b261ecSmrg } 99005b261ecSmrg 99105b261ecSmrg if (x1 < extents.x1) 99205b261ecSmrg extents.x1 = x1; 99305b261ecSmrg if (x2 > extents.x2) 99405b261ecSmrg extents.x2 = x2; 99505b261ecSmrg if (y1 < extents.y1) 99605b261ecSmrg extents.y1 = y1; 99705b261ecSmrg if (y2 > extents.y2) 99805b261ecSmrg extents.y2 = y2; 99905b261ecSmrg } 100005b261ecSmrg x += glyph->info.xOff; 100105b261ecSmrg y += glyph->info.yOff; 100205b261ecSmrg } 100305b261ecSmrg } 100405b261ecSmrg 100505b261ecSmrg return FALSE; 100605b261ecSmrg} 100705b261ecSmrg 100805b261ecSmrg/* exaGlyphs is a slight variation on miGlyphs, to support acceleration. The 100905b261ecSmrg * issue is that miGlyphs' use of ModifyPixmapHeader makes it impossible to 101005b261ecSmrg * migrate these pixmaps. So, instead we create a pixmap at the beginning of 101105b261ecSmrg * the loop and upload each glyph into the pixmap before compositing. 101205b261ecSmrg */ 101305b261ecSmrgvoid 101405b261ecSmrgexaGlyphs (CARD8 op, 101505b261ecSmrg PicturePtr pSrc, 101605b261ecSmrg PicturePtr pDst, 101705b261ecSmrg PictFormatPtr maskFormat, 101805b261ecSmrg INT16 xSrc, 101905b261ecSmrg INT16 ySrc, 102005b261ecSmrg int nlist, 102105b261ecSmrg GlyphListPtr list, 102205b261ecSmrg GlyphPtr *glyphs) 102305b261ecSmrg{ 102405b261ecSmrg ExaScreenPriv (pDst->pDrawable->pScreen); 102505b261ecSmrg PixmapPtr pPixmap = NULL; 102605b261ecSmrg PicturePtr pPicture; 102705b261ecSmrg PixmapPtr pMaskPixmap = NULL; 102805b261ecSmrg PixmapPtr pDstPixmap = exaGetDrawablePixmap(pDst->pDrawable); 102905b261ecSmrg PicturePtr pMask; 103005b261ecSmrg ScreenPtr pScreen = pDst->pDrawable->pScreen; 103105b261ecSmrg int width = 0, height = 0; 103205b261ecSmrg int x, y, x1, y1, xoff, yoff; 103305b261ecSmrg int xDst = list->xOff, yDst = list->yOff; 103405b261ecSmrg int n; 103505b261ecSmrg int error; 103605b261ecSmrg BoxRec extents; 103705b261ecSmrg CARD32 component_alpha; 103805b261ecSmrg 103905b261ecSmrg /* If we have a mask format but it's the same as all the glyphs and 104005b261ecSmrg * the glyphs don't intersect, we can avoid accumulating the glyphs in the 104105b261ecSmrg * temporary picture. 104205b261ecSmrg */ 104305b261ecSmrg if (maskFormat != NULL) { 104405b261ecSmrg Bool sameFormat = TRUE; 104505b261ecSmrg int i; 104605b261ecSmrg 104705b261ecSmrg for (i = 0; i < nlist; i++) { 104805b261ecSmrg if (maskFormat->format != list[i].format->format) { 104905b261ecSmrg sameFormat = FALSE; 105005b261ecSmrg break; 105105b261ecSmrg } 105205b261ecSmrg } 105305b261ecSmrg if (sameFormat) { 105405b261ecSmrg if (!exaGlyphsIntersect(nlist, list, glyphs)) { 105505b261ecSmrg maskFormat = NULL; 105605b261ecSmrg } 105705b261ecSmrg } 105805b261ecSmrg } 105905b261ecSmrg 106005b261ecSmrg /* If the driver doesn't support accelerated composite, there's no point in 106105b261ecSmrg * going to this extra work. Assume that any driver that supports Composite 106205b261ecSmrg * will be able to support component alpha using the two-pass helper. 106305b261ecSmrg */ 106405b261ecSmrg if (!pExaScr->info->PrepareComposite) 106505b261ecSmrg { 106605b261ecSmrg miGlyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs); 106705b261ecSmrg return; 106805b261ecSmrg } 106905b261ecSmrg 107005b261ecSmrg if (maskFormat) 107105b261ecSmrg { 107205b261ecSmrg GCPtr pGC; 107305b261ecSmrg xRectangle rect; 107405b261ecSmrg 107505b261ecSmrg miGlyphExtents (nlist, list, glyphs, &extents); 107605b261ecSmrg 107705b261ecSmrg extents.x1 = max(extents.x1, 0); 107805b261ecSmrg extents.y1 = max(extents.y1, 0); 107905b261ecSmrg extents.x2 = min(extents.x2, pDst->pDrawable->width); 108005b261ecSmrg extents.y2 = min(extents.y2, pDst->pDrawable->height); 108105b261ecSmrg 108205b261ecSmrg if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1) 108305b261ecSmrg return; 108405b261ecSmrg width = extents.x2 - extents.x1; 108505b261ecSmrg height = extents.y2 - extents.y1; 108605b261ecSmrg pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, 108705b261ecSmrg maskFormat->depth); 108805b261ecSmrg if (!pMaskPixmap) 108905b261ecSmrg return; 109005b261ecSmrg component_alpha = NeedsComponent(maskFormat->format); 109105b261ecSmrg pMask = CreatePicture (0, &pMaskPixmap->drawable, 109205b261ecSmrg maskFormat, CPComponentAlpha, &component_alpha, 109305b261ecSmrg serverClient, &error); 109405b261ecSmrg if (!pMask) 109505b261ecSmrg { 109605b261ecSmrg (*pScreen->DestroyPixmap) (pMaskPixmap); 109705b261ecSmrg return; 109805b261ecSmrg } 109905b261ecSmrg ValidatePicture(pMask); 110005b261ecSmrg pGC = GetScratchGC (pMaskPixmap->drawable.depth, pScreen); 110105b261ecSmrg ValidateGC (&pMaskPixmap->drawable, pGC); 110205b261ecSmrg rect.x = 0; 110305b261ecSmrg rect.y = 0; 110405b261ecSmrg rect.width = width; 110505b261ecSmrg rect.height = height; 110605b261ecSmrg (*pGC->ops->PolyFillRect) (&pMaskPixmap->drawable, pGC, 1, &rect); 110705b261ecSmrg exaPixmapDirty(pMaskPixmap, 0, 0, width, height); 110805b261ecSmrg FreeScratchGC (pGC); 110905b261ecSmrg x = -extents.x1; 111005b261ecSmrg y = -extents.y1; 111105b261ecSmrg } 111205b261ecSmrg else 111305b261ecSmrg { 111405b261ecSmrg pMask = pDst; 111505b261ecSmrg x = 0; 111605b261ecSmrg y = 0; 111705b261ecSmrg } 111805b261ecSmrg 111905b261ecSmrg exaGetDrawableDeltas(pDst->pDrawable, pDstPixmap, &xoff, &yoff); 112005b261ecSmrg 112105b261ecSmrg while (nlist--) 112205b261ecSmrg { 112305b261ecSmrg GCPtr pGC = NULL; 112405b261ecSmrg int maxwidth = 0, maxheight = 0, i; 112505b261ecSmrg ExaMigrationRec pixmaps[1]; 112605b261ecSmrg PixmapPtr pScratchPixmap = NULL; 112705b261ecSmrg 112805b261ecSmrg x += list->xOff; 112905b261ecSmrg y += list->yOff; 113005b261ecSmrg n = list->len; 113105b261ecSmrg for (i = 0; i < n; i++) { 113205b261ecSmrg if (glyphs[i]->info.width > maxwidth) 113305b261ecSmrg maxwidth = glyphs[i]->info.width; 113405b261ecSmrg if (glyphs[i]->info.height > maxheight) 113505b261ecSmrg maxheight = glyphs[i]->info.height; 113605b261ecSmrg } 113705b261ecSmrg if (maxwidth == 0 || maxheight == 0) { 113805b261ecSmrg while (n--) 113905b261ecSmrg { 114005b261ecSmrg GlyphPtr glyph; 114105b261ecSmrg 114205b261ecSmrg glyph = *glyphs++; 114305b261ecSmrg x += glyph->info.xOff; 114405b261ecSmrg y += glyph->info.yOff; 114505b261ecSmrg } 114605b261ecSmrg list++; 114705b261ecSmrg continue; 114805b261ecSmrg } 114905b261ecSmrg 115005b261ecSmrg /* Create the (real) temporary pixmap to store the current glyph in */ 115105b261ecSmrg pPixmap = (*pScreen->CreatePixmap) (pScreen, maxwidth, maxheight, 115205b261ecSmrg list->format->depth); 115305b261ecSmrg if (!pPixmap) 115405b261ecSmrg return; 115505b261ecSmrg 115605b261ecSmrg /* Create a temporary picture to wrap the temporary pixmap, so it can be 115705b261ecSmrg * used as a source for Composite. 115805b261ecSmrg */ 115905b261ecSmrg component_alpha = NeedsComponent(list->format->format); 116005b261ecSmrg pPicture = CreatePicture (0, &pPixmap->drawable, list->format, 116105b261ecSmrg CPComponentAlpha, &component_alpha, 116205b261ecSmrg serverClient, &error); 116305b261ecSmrg if (!pPicture) { 116405b261ecSmrg (*pScreen->DestroyPixmap) (pPixmap); 116505b261ecSmrg return; 116605b261ecSmrg } 116705b261ecSmrg ValidatePicture(pPicture); 116805b261ecSmrg 116905b261ecSmrg /* Give the temporary pixmap an initial kick towards the screen, so 117005b261ecSmrg * it'll stick there. 117105b261ecSmrg */ 117205b261ecSmrg pixmaps[0].as_dst = TRUE; 117305b261ecSmrg pixmaps[0].as_src = TRUE; 117405b261ecSmrg pixmaps[0].pPix = pPixmap; 117505b261ecSmrg exaDoMigration (pixmaps, 1, pExaScr->info->PrepareComposite != NULL); 117605b261ecSmrg 117705b261ecSmrg while (n--) 117805b261ecSmrg { 117905b261ecSmrg GlyphPtr glyph = *glyphs++; 118005b261ecSmrg pointer glyphdata = (pointer) (glyph + 1); 118105b261ecSmrg DrawablePtr pCmpDrw = (maskFormat ? pMask : pDst)->pDrawable; 118205b261ecSmrg 118305b261ecSmrg x1 = x - glyph->info.x; 118405b261ecSmrg y1 = y - glyph->info.y; 118505b261ecSmrg 118605b261ecSmrg if (x1 >= pCmpDrw->width || y1 >= pCmpDrw->height || 118705b261ecSmrg glyph->info.width == 0 || glyph->info.height == 0 || 118805b261ecSmrg (x1 + glyph->info.width) <= 0 || (y1 + glyph->info.height) <= 0) 118905b261ecSmrg goto nextglyph; 119005b261ecSmrg 119105b261ecSmrg (*pScreen->ModifyPixmapHeader) (pScratchPixmap, 119205b261ecSmrg glyph->info.width, 119305b261ecSmrg glyph->info.height, 119405b261ecSmrg 0, 0, -1, glyphdata); 119505b261ecSmrg 119605b261ecSmrg /* Copy the glyph data into the proper pixmap instead of a fake. 119705b261ecSmrg * First we try to use UploadToScreen, if we can, then we fall back 119805b261ecSmrg * to a plain exaCopyArea in case of failure. 119905b261ecSmrg */ 120005b261ecSmrg if (pExaScr->info->UploadToScreen && 120105b261ecSmrg exaPixmapIsOffscreen(pPixmap) && 120205b261ecSmrg (*pExaScr->info->UploadToScreen) (pPixmap, 0, 0, 120305b261ecSmrg glyph->info.width, 120405b261ecSmrg glyph->info.height, 120505b261ecSmrg glyphdata, 120605b261ecSmrg PixmapBytePad(glyph->info.width, 120705b261ecSmrg list->format->depth))) 120805b261ecSmrg { 120905b261ecSmrg exaMarkSync (pScreen); 121005b261ecSmrg } else { 121105b261ecSmrg /* Set up the scratch pixmap/GC for doing a CopyArea. */ 121205b261ecSmrg if (pScratchPixmap == NULL) { 121305b261ecSmrg /* Get a scratch pixmap to wrap the original glyph data */ 121405b261ecSmrg pScratchPixmap = GetScratchPixmapHeader (pScreen, 121505b261ecSmrg glyph->info.width, 121605b261ecSmrg glyph->info.height, 121705b261ecSmrg list->format->depth, 121805b261ecSmrg list->format->depth, 121905b261ecSmrg -1, glyphdata); 122005b261ecSmrg if (!pScratchPixmap) { 122105b261ecSmrg FreePicture(pPicture, 0); 122205b261ecSmrg (*pScreen->DestroyPixmap) (pPixmap); 122305b261ecSmrg return; 122405b261ecSmrg } 122505b261ecSmrg 122605b261ecSmrg /* Get a scratch GC with which to copy the glyph data from 122705b261ecSmrg * scratch to temporary 122805b261ecSmrg */ 122905b261ecSmrg pGC = GetScratchGC (list->format->depth, pScreen); 123005b261ecSmrg ValidateGC (&pPixmap->drawable, pGC); 123105b261ecSmrg } else { 123205b261ecSmrg (*pScreen->ModifyPixmapHeader) (pScratchPixmap, 123305b261ecSmrg glyph->info.width, 123405b261ecSmrg glyph->info.height, 123505b261ecSmrg 0, 0, -1, glyphdata); 123605b261ecSmrg pScratchPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; 123705b261ecSmrg } 123805b261ecSmrg 123905b261ecSmrg exaCopyArea (&pScratchPixmap->drawable, &pPixmap->drawable, pGC, 124005b261ecSmrg 0, 0, glyph->info.width, glyph->info.height, 0, 0); 124105b261ecSmrg } 124205b261ecSmrg 124305b261ecSmrg exaPixmapDirty (pPixmap, 0, 0, 124405b261ecSmrg glyph->info.width, glyph->info.height); 124505b261ecSmrg 124605b261ecSmrg if (maskFormat) 124705b261ecSmrg { 124805b261ecSmrg exaComposite (PictOpAdd, pPicture, NULL, pMask, 0, 0, 0, 0, 124905b261ecSmrg x1, y1, glyph->info.width, glyph->info.height); 125005b261ecSmrg exaPixmapDirty(pMaskPixmap, x1, y1, x1 + glyph->info.width, 125105b261ecSmrg y1 + glyph->info.height); 125205b261ecSmrg } 125305b261ecSmrg else 125405b261ecSmrg { 125505b261ecSmrg exaComposite (op, pSrc, pPicture, pDst, 125605b261ecSmrg xSrc + x1 - xDst, ySrc + y1 - yDst, 125705b261ecSmrg 0, 0, x1, y1, glyph->info.width, 125805b261ecSmrg glyph->info.height); 125905b261ecSmrg x1 += pDst->pDrawable->x + xoff; 126005b261ecSmrg y1 += pDst->pDrawable->y + yoff; 126105b261ecSmrg exaPixmapDirty(pDstPixmap, x1, y1, x1 + glyph->info.width, 126205b261ecSmrg y1 + glyph->info.height); 126305b261ecSmrg } 126405b261ecSmrgnextglyph: 126505b261ecSmrg x += glyph->info.xOff; 126605b261ecSmrg y += glyph->info.yOff; 126705b261ecSmrg } 126805b261ecSmrg list++; 126905b261ecSmrg if (pGC != NULL) 127005b261ecSmrg FreeScratchGC (pGC); 127105b261ecSmrg FreePicture ((pointer) pPicture, 0); 127205b261ecSmrg (*pScreen->DestroyPixmap) (pPixmap); 127305b261ecSmrg if (pScratchPixmap != NULL) 127405b261ecSmrg FreeScratchPixmapHeader (pScratchPixmap); 127505b261ecSmrg } 127605b261ecSmrg if (maskFormat) 127705b261ecSmrg { 127805b261ecSmrg x = extents.x1; 127905b261ecSmrg y = extents.y1; 128005b261ecSmrg exaComposite (op, pSrc, pMask, pDst, xSrc + x - xDst, ySrc + y - yDst, 128105b261ecSmrg 0, 0, x, y, width, height); 128205b261ecSmrg FreePicture ((pointer) pMask, (XID) 0); 128305b261ecSmrg (*pScreen->DestroyPixmap) (pMaskPixmap); 128405b261ecSmrg } 128505b261ecSmrg} 1286