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#include "mipict.h" 3405b261ecSmrg 3505b261ecSmrg#if DEBUG_TRACE_FALL 36f7df2e56Smrgstatic void 37f7df2e56SmrgexaCompositeFallbackPictDesc(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) { 45f7df2e56Smrg snprintf(string, n, "None"); 46f7df2e56Smrg return; 4705b261ecSmrg } 4805b261ecSmrg 49f7df2e56Smrg switch (pict->format) { 5005b261ecSmrg case PICT_a8r8g8b8: 51f7df2e56Smrg snprintf(format, 20, "ARGB8888"); 52f7df2e56Smrg break; 534642e01fSmrg case PICT_x8r8g8b8: 54f7df2e56Smrg snprintf(format, 20, "XRGB8888"); 55f7df2e56Smrg break; 566747b715Smrg case PICT_b8g8r8a8: 57f7df2e56Smrg snprintf(format, 20, "BGRA8888"); 58f7df2e56Smrg break; 596747b715Smrg case PICT_b8g8r8x8: 60f7df2e56Smrg snprintf(format, 20, "BGRX8888"); 61f7df2e56Smrg break; 6205b261ecSmrg case PICT_r5g6b5: 63f7df2e56Smrg snprintf(format, 20, "RGB565 "); 64f7df2e56Smrg break; 6505b261ecSmrg case PICT_x1r5g5b5: 66f7df2e56Smrg snprintf(format, 20, "RGB555 "); 67f7df2e56Smrg break; 6805b261ecSmrg case PICT_a8: 69f7df2e56Smrg snprintf(format, 20, "A8 "); 70f7df2e56Smrg break; 7105b261ecSmrg case PICT_a1: 72f7df2e56Smrg snprintf(format, 20, "A1 "); 73f7df2e56Smrg break; 7405b261ecSmrg default: 75f7df2e56Smrg snprintf(format, 20, "0x%x", (int) pict->format); 76f7df2e56Smrg break; 7705b261ecSmrg } 7805b261ecSmrg 796747b715Smrg if (pict->pDrawable) { 80f7df2e56Smrg loc = exaGetOffscreenPixmap(pict->pDrawable, &temp, &temp) ? 's' : 'm'; 8105b261ecSmrg 82f7df2e56Smrg snprintf(size, 20, "%dx%d%s", pict->pDrawable->width, 83f7df2e56Smrg pict->pDrawable->height, pict->repeat ? " R" : ""); 84f7df2e56Smrg } 85f7df2e56Smrg else { 86f7df2e56Smrg loc = '-'; 876747b715Smrg 88f7df2e56Smrg snprintf(size, 20, "%s", pict->repeat ? " R" : ""); 896747b715Smrg } 9005b261ecSmrg 91f7df2e56Smrg snprintf(string, n, "%p:%c fmt %s (%s)", pict->pDrawable, loc, format, 92f7df2e56Smrg size); 9305b261ecSmrg} 9405b261ecSmrg 9505b261ecSmrgstatic void 9605b261ecSmrgexaPrintCompositeFallback(CARD8 op, 97f7df2e56Smrg PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst) 9805b261ecSmrg{ 9905b261ecSmrg char sop[20]; 10005b261ecSmrg char srcdesc[40], maskdesc[40], dstdesc[40]; 10105b261ecSmrg 102f7df2e56Smrg switch (op) { 10305b261ecSmrg case PictOpSrc: 104f7df2e56Smrg snprintf(sop, sizeof(sop), "Src"); 105f7df2e56Smrg break; 10605b261ecSmrg case PictOpOver: 107f7df2e56Smrg snprintf(sop, sizeof(sop), "Over"); 108f7df2e56Smrg break; 10905b261ecSmrg default: 110f7df2e56Smrg snprintf(sop, sizeof(sop), "0x%x", (int) op); 111f7df2e56Smrg break; 11205b261ecSmrg } 11305b261ecSmrg 11405b261ecSmrg exaCompositeFallbackPictDesc(pSrc, srcdesc, 40); 11505b261ecSmrg exaCompositeFallbackPictDesc(pMask, maskdesc, 40); 11605b261ecSmrg exaCompositeFallbackPictDesc(pDst, dstdesc, 40); 11705b261ecSmrg 11805b261ecSmrg ErrorF("Composite fallback: op %s, \n" 119f7df2e56Smrg " src %s, \n" 120f7df2e56Smrg " mask %s, \n" 121f7df2e56Smrg " dst %s, \n", sop, srcdesc, maskdesc, dstdesc); 12205b261ecSmrg} 123f7df2e56Smrg#endif /* DEBUG_TRACE_FALL */ 12405b261ecSmrg 1254642e01fSmrgBool 126f7df2e56SmrgexaOpReadsDestination(CARD8 op) 12705b261ecSmrg{ 12805b261ecSmrg /* FALSE (does not read destination) is the list of ops in the protocol 12905b261ecSmrg * document with "0" in the "Fb" column and no "Ab" in the "Fa" column. 13005b261ecSmrg * That's just Clear and Src. ReduceCompositeOp() will already have 13105b261ecSmrg * converted con/disjoint clear/src to Clear or Src. 13205b261ecSmrg */ 13305b261ecSmrg switch (op) { 13405b261ecSmrg case PictOpClear: 13505b261ecSmrg case PictOpSrc: 136f7df2e56Smrg return FALSE; 13705b261ecSmrg default: 138f7df2e56Smrg return TRUE; 13905b261ecSmrg } 14005b261ecSmrg} 14105b261ecSmrg 14205b261ecSmrgstatic Bool 143f7df2e56SmrgexaGetPixelFromRGBA(CARD32 *pixel, 144f7df2e56Smrg CARD16 red, 145f7df2e56Smrg CARD16 green, 146f7df2e56Smrg CARD16 blue, CARD16 alpha, PictFormatPtr pFormat) 14705b261ecSmrg{ 14805b261ecSmrg int rbits, bbits, gbits, abits; 14905b261ecSmrg int rshift, bshift, gshift, ashift; 15005b261ecSmrg 15105b261ecSmrg *pixel = 0; 15205b261ecSmrg 1536747b715Smrg if (!PICT_FORMAT_COLOR(pFormat->format) && 154f7df2e56Smrg PICT_FORMAT_TYPE(pFormat->format) != PICT_TYPE_A) 155f7df2e56Smrg return FALSE; 15605b261ecSmrg 1576747b715Smrg rbits = PICT_FORMAT_R(pFormat->format); 1586747b715Smrg gbits = PICT_FORMAT_G(pFormat->format); 1596747b715Smrg bbits = PICT_FORMAT_B(pFormat->format); 1606747b715Smrg abits = PICT_FORMAT_A(pFormat->format); 16105b261ecSmrg 1626747b715Smrg rshift = pFormat->direct.red; 1636747b715Smrg gshift = pFormat->direct.green; 1646747b715Smrg bshift = pFormat->direct.blue; 1656747b715Smrg ashift = pFormat->direct.alpha; 16605b261ecSmrg 167f7df2e56Smrg *pixel |= (blue >> (16 - bbits)) << bshift; 168f7df2e56Smrg *pixel |= (red >> (16 - rbits)) << rshift; 169f7df2e56Smrg *pixel |= (green >> (16 - gbits)) << gshift; 170f7df2e56Smrg *pixel |= (alpha >> (16 - abits)) << ashift; 17105b261ecSmrg 17205b261ecSmrg return TRUE; 17305b261ecSmrg} 17405b261ecSmrg 17505b261ecSmrgstatic Bool 176f7df2e56SmrgexaGetRGBAFromPixel(CARD32 pixel, 177f7df2e56Smrg CARD16 *red, 178f7df2e56Smrg CARD16 *green, 179f7df2e56Smrg CARD16 *blue, 180f7df2e56Smrg CARD16 *alpha, 181f7df2e56Smrg PictFormatPtr pFormat, PictFormatShort format) 18205b261ecSmrg{ 18305b261ecSmrg int rbits, bbits, gbits, abits; 18405b261ecSmrg int rshift, bshift, gshift, ashift; 18505b261ecSmrg 1866747b715Smrg if (!PICT_FORMAT_COLOR(format) && PICT_FORMAT_TYPE(format) != PICT_TYPE_A) 187f7df2e56Smrg return FALSE; 18805b261ecSmrg 18905b261ecSmrg rbits = PICT_FORMAT_R(format); 19005b261ecSmrg gbits = PICT_FORMAT_G(format); 19105b261ecSmrg bbits = PICT_FORMAT_B(format); 19205b261ecSmrg abits = PICT_FORMAT_A(format); 19305b261ecSmrg 1946747b715Smrg if (pFormat) { 195f7df2e56Smrg rshift = pFormat->direct.red; 196f7df2e56Smrg gshift = pFormat->direct.green; 197f7df2e56Smrg bshift = pFormat->direct.blue; 198f7df2e56Smrg ashift = pFormat->direct.alpha; 199f7df2e56Smrg } 200f7df2e56Smrg else if (format == PICT_a8r8g8b8) { 201f7df2e56Smrg rshift = 16; 202f7df2e56Smrg gshift = 8; 203f7df2e56Smrg bshift = 0; 204f7df2e56Smrg ashift = 24; 205f7df2e56Smrg } 206f7df2e56Smrg else 207f7df2e56Smrg FatalError("EXA bug: exaGetRGBAFromPixel() doesn't match " 208f7df2e56Smrg "createSourcePicture()\n"); 2096747b715Smrg 2106747b715Smrg if (rbits) { 211f7df2e56Smrg *red = ((pixel >> rshift) & ((1 << rbits) - 1)) << (16 - rbits); 212f7df2e56Smrg while (rbits < 16) { 213f7df2e56Smrg *red |= *red >> rbits; 214f7df2e56Smrg rbits <<= 1; 215f7df2e56Smrg } 216f7df2e56Smrg 217f7df2e56Smrg *green = ((pixel >> gshift) & ((1 << gbits) - 1)) << (16 - gbits); 218f7df2e56Smrg while (gbits < 16) { 219f7df2e56Smrg *green |= *green >> gbits; 220f7df2e56Smrg gbits <<= 1; 221f7df2e56Smrg } 222f7df2e56Smrg 223f7df2e56Smrg *blue = ((pixel >> bshift) & ((1 << bbits) - 1)) << (16 - bbits); 224f7df2e56Smrg while (bbits < 16) { 225f7df2e56Smrg *blue |= *blue >> bbits; 226f7df2e56Smrg bbits <<= 1; 227f7df2e56Smrg } 228f7df2e56Smrg } 229f7df2e56Smrg else { 230f7df2e56Smrg *red = 0x0000; 231f7df2e56Smrg *green = 0x0000; 232f7df2e56Smrg *blue = 0x0000; 23305b261ecSmrg } 23405b261ecSmrg 23505b261ecSmrg if (abits) { 236f7df2e56Smrg *alpha = ((pixel >> ashift) & ((1 << abits) - 1)) << (16 - abits); 237f7df2e56Smrg while (abits < 16) { 238f7df2e56Smrg *alpha |= *alpha >> abits; 239f7df2e56Smrg abits <<= 1; 240f7df2e56Smrg } 241f7df2e56Smrg } 242f7df2e56Smrg else 243f7df2e56Smrg *alpha = 0xffff; 24405b261ecSmrg 24505b261ecSmrg return TRUE; 24605b261ecSmrg} 24705b261ecSmrg 24805b261ecSmrgstatic int 249f7df2e56SmrgexaTryDriverSolidFill(PicturePtr pSrc, 250f7df2e56Smrg PicturePtr pDst, 251f7df2e56Smrg INT16 xSrc, 252f7df2e56Smrg INT16 ySrc, 253f7df2e56Smrg INT16 xDst, INT16 yDst, CARD16 width, CARD16 height) 25405b261ecSmrg{ 255f7df2e56Smrg ExaScreenPriv(pDst->pDrawable->pScreen); 25605b261ecSmrg RegionRec region; 25705b261ecSmrg BoxPtr pbox; 25805b261ecSmrg int nbox; 25905b261ecSmrg int dst_off_x, dst_off_y; 26005b261ecSmrg PixmapPtr pSrcPix, pDstPix; 2616747b715Smrg ExaPixmapPrivPtr pDstExaPix; 26205b261ecSmrg CARD32 pixel; 26305b261ecSmrg CARD16 red, green, blue, alpha; 26405b261ecSmrg 265f7df2e56Smrg pDstPix = exaGetDrawablePixmap(pDst->pDrawable); 2664642e01fSmrg pDstExaPix = ExaGetPixmapPriv(pDstPix); 2674642e01fSmrg 2686747b715Smrg /* Check whether the accelerator can use the destination pixmap. 2694642e01fSmrg */ 270f7df2e56Smrg if (pDstExaPix->accel_blocked) { 271f7df2e56Smrg return -1; 2724642e01fSmrg } 2734642e01fSmrg 27405b261ecSmrg xDst += pDst->pDrawable->x; 27505b261ecSmrg yDst += pDst->pDrawable->y; 2766747b715Smrg if (pSrc->pDrawable) { 277f7df2e56Smrg xSrc += pSrc->pDrawable->x; 278f7df2e56Smrg ySrc += pSrc->pDrawable->y; 2796747b715Smrg } 28005b261ecSmrg 281f7df2e56Smrg if (!miComputeCompositeRegion(®ion, pSrc, NULL, pDst, 282f7df2e56Smrg xSrc, ySrc, 0, 0, xDst, yDst, width, height)) 283f7df2e56Smrg return 1; 28405b261ecSmrg 285f7df2e56Smrg exaGetDrawableDeltas(pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y); 2864642e01fSmrg 2876747b715Smrg RegionTranslate(®ion, dst_off_x, dst_off_y); 28805b261ecSmrg 2896747b715Smrg if (pSrc->pDrawable) { 290f7df2e56Smrg pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable); 291f7df2e56Smrg pixel = exaGetPixmapFirstPixel(pSrcPix); 292f7df2e56Smrg } 293f7df2e56Smrg else 2947e31ba66Smrg miRenderColorToPixel(PictureMatchFormat(pDst->pDrawable->pScreen, 32, 2957e31ba66Smrg pSrc->format), 2967e31ba66Smrg &pSrc->pSourcePict->solidFill.fullcolor, 2977e31ba66Smrg &pixel); 29805b261ecSmrg 29905b261ecSmrg if (!exaGetRGBAFromPixel(pixel, &red, &green, &blue, &alpha, 300f7df2e56Smrg pSrc->pFormat, pSrc->format) || 301f7df2e56Smrg !exaGetPixelFromRGBA(&pixel, red, green, blue, alpha, pDst->pFormat)) { 302f7df2e56Smrg RegionUninit(®ion); 303f7df2e56Smrg return -1; 30405b261ecSmrg } 30505b261ecSmrg 3066747b715Smrg if (pExaScr->do_migration) { 307f7df2e56Smrg ExaMigrationRec pixmaps[1]; 3086747b715Smrg 309f7df2e56Smrg pixmaps[0].as_dst = TRUE; 310f7df2e56Smrg pixmaps[0].as_src = FALSE; 311f7df2e56Smrg pixmaps[0].pPix = pDstPix; 312f7df2e56Smrg pixmaps[0].pReg = ®ion; 313f7df2e56Smrg exaDoMigration(pixmaps, 1, TRUE); 3146747b715Smrg } 3156747b715Smrg 3166747b715Smrg if (!exaPixmapHasGpuCopy(pDstPix)) { 317f7df2e56Smrg RegionUninit(®ion); 318f7df2e56Smrg return 0; 31905b261ecSmrg } 32005b261ecSmrg 321f7df2e56Smrg if (!(*pExaScr->info->PrepareSolid) (pDstPix, GXcopy, 0xffffffff, pixel)) { 322f7df2e56Smrg RegionUninit(®ion); 323f7df2e56Smrg return -1; 32405b261ecSmrg } 32505b261ecSmrg 3266747b715Smrg nbox = RegionNumRects(®ion); 3276747b715Smrg pbox = RegionRects(®ion); 32805b261ecSmrg 329f7df2e56Smrg while (nbox--) { 330f7df2e56Smrg (*pExaScr->info->Solid) (pDstPix, pbox->x1, pbox->y1, pbox->x2, 331f7df2e56Smrg pbox->y2); 332f7df2e56Smrg pbox++; 33305b261ecSmrg } 33405b261ecSmrg 33505b261ecSmrg (*pExaScr->info->DoneSolid) (pDstPix); 33605b261ecSmrg exaMarkSync(pDst->pDrawable->pScreen); 33705b261ecSmrg 3386747b715Smrg RegionUninit(®ion); 33905b261ecSmrg return 1; 34005b261ecSmrg} 34105b261ecSmrg 3424642e01fSmrgstatic int 343f7df2e56SmrgexaTryDriverCompositeRects(CARD8 op, 344f7df2e56Smrg PicturePtr pSrc, 345f7df2e56Smrg PicturePtr pMask, 346f7df2e56Smrg PicturePtr pDst, 347f7df2e56Smrg int nrect, ExaCompositeRectPtr rects) 3484642e01fSmrg{ 349f7df2e56Smrg ExaScreenPriv(pDst->pDrawable->pScreen); 3506747b715Smrg int src_off_x = 0, src_off_y = 0, mask_off_x = 0, mask_off_y = 0; 3516747b715Smrg int dst_off_x, dst_off_y; 3526747b715Smrg PixmapPtr pSrcPix = NULL, pMaskPix = NULL, pDstPix; 3536747b715Smrg ExaPixmapPrivPtr pSrcExaPix = NULL, pMaskExaPix = NULL, pDstExaPix; 3544642e01fSmrg 3554642e01fSmrg if (!pExaScr->info->PrepareComposite) 356f7df2e56Smrg return -1; 3574642e01fSmrg 3586747b715Smrg if (pSrc->pDrawable) { 359f7df2e56Smrg pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable); 360f7df2e56Smrg pSrcExaPix = ExaGetPixmapPriv(pSrcPix); 3616747b715Smrg } 3626747b715Smrg 3636747b715Smrg if (pMask && pMask->pDrawable) { 364f7df2e56Smrg pMaskPix = exaGetDrawablePixmap(pMask->pDrawable); 365f7df2e56Smrg pMaskExaPix = ExaGetPixmapPriv(pMaskPix); 3666747b715Smrg } 3674642e01fSmrg 3684642e01fSmrg pDstPix = exaGetDrawablePixmap(pDst->pDrawable); 3694642e01fSmrg pDstExaPix = ExaGetPixmapPriv(pDstPix); 3704642e01fSmrg 3714642e01fSmrg /* Check whether the accelerator can use these pixmaps. 3724642e01fSmrg * FIXME: If it cannot, use temporary pixmaps so that the drawing 3734642e01fSmrg * happens within limits. 3744642e01fSmrg */ 3756747b715Smrg if (pDstExaPix->accel_blocked || 376f7df2e56Smrg (pSrcExaPix && pSrcExaPix->accel_blocked) || 377f7df2e56Smrg (pMaskExaPix && pMaskExaPix->accel_blocked)) { 378f7df2e56Smrg return -1; 3794642e01fSmrg } 3804642e01fSmrg 3814642e01fSmrg if (pExaScr->info->CheckComposite && 382f7df2e56Smrg !(*pExaScr->info->CheckComposite) (op, pSrc, pMask, pDst)) { 383f7df2e56Smrg return -1; 3844642e01fSmrg } 3854642e01fSmrg 3866747b715Smrg if (pExaScr->do_migration) { 387f7df2e56Smrg ExaMigrationRec pixmaps[3]; 388f7df2e56Smrg int i = 0; 389f7df2e56Smrg 390f7df2e56Smrg pixmaps[i].as_dst = TRUE; 391f7df2e56Smrg pixmaps[i].as_src = exaOpReadsDestination(op); 392f7df2e56Smrg pixmaps[i].pPix = pDstPix; 393f7df2e56Smrg pixmaps[i].pReg = NULL; 394f7df2e56Smrg i++; 395f7df2e56Smrg 396f7df2e56Smrg if (pSrcPix) { 397f7df2e56Smrg pixmaps[i].as_dst = FALSE; 398f7df2e56Smrg pixmaps[i].as_src = TRUE; 399f7df2e56Smrg pixmaps[i].pPix = pSrcPix; 400f7df2e56Smrg pixmaps[i].pReg = NULL; 401f7df2e56Smrg i++; 402f7df2e56Smrg } 403f7df2e56Smrg 404f7df2e56Smrg if (pMaskPix) { 405f7df2e56Smrg pixmaps[i].as_dst = FALSE; 406f7df2e56Smrg pixmaps[i].as_src = TRUE; 407f7df2e56Smrg pixmaps[i].pPix = pMaskPix; 408f7df2e56Smrg pixmaps[i].pReg = NULL; 409f7df2e56Smrg i++; 410f7df2e56Smrg } 411f7df2e56Smrg 412f7df2e56Smrg exaDoMigration(pixmaps, i, TRUE); 4134642e01fSmrg } 4144642e01fSmrg 415f7df2e56Smrg pDstPix = exaGetOffscreenPixmap(pDst->pDrawable, &dst_off_x, &dst_off_y); 4166747b715Smrg if (!pDstPix) 417f7df2e56Smrg return 0; 4184642e01fSmrg 4196747b715Smrg if (pSrcPix) { 420f7df2e56Smrg pSrcPix = 421f7df2e56Smrg exaGetOffscreenPixmap(pSrc->pDrawable, &src_off_x, &src_off_y); 422f7df2e56Smrg if (!pSrcPix) 423f7df2e56Smrg return 0; 4246747b715Smrg } 4256747b715Smrg 4266747b715Smrg if (pMaskPix) { 427f7df2e56Smrg pMaskPix = 428f7df2e56Smrg exaGetOffscreenPixmap(pMask->pDrawable, &mask_off_x, &mask_off_y); 429f7df2e56Smrg if (!pMaskPix) 430f7df2e56Smrg return 0; 4316747b715Smrg } 4326747b715Smrg 4336747b715Smrg if (!(*pExaScr->info->PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix, 434f7df2e56Smrg pMaskPix, pDstPix)) 435f7df2e56Smrg return -1; 436f7df2e56Smrg 437f7df2e56Smrg while (nrect--) { 438f7df2e56Smrg INT16 xDst = rects->xDst + pDst->pDrawable->x; 439f7df2e56Smrg INT16 yDst = rects->yDst + pDst->pDrawable->y; 440f7df2e56Smrg INT16 xMask = rects->xMask; 441f7df2e56Smrg INT16 yMask = rects->yMask; 442f7df2e56Smrg INT16 xSrc = rects->xSrc; 443f7df2e56Smrg INT16 ySrc = rects->ySrc; 444f7df2e56Smrg RegionRec region; 445f7df2e56Smrg BoxPtr pbox; 446f7df2e56Smrg int nbox; 447f7df2e56Smrg 448f7df2e56Smrg if (pMaskPix) { 449f7df2e56Smrg xMask += pMask->pDrawable->x; 450f7df2e56Smrg yMask += pMask->pDrawable->y; 451f7df2e56Smrg } 452f7df2e56Smrg 453f7df2e56Smrg if (pSrcPix) { 454f7df2e56Smrg xSrc += pSrc->pDrawable->x; 455f7df2e56Smrg ySrc += pSrc->pDrawable->y; 456f7df2e56Smrg } 457f7df2e56Smrg 458f7df2e56Smrg if (!miComputeCompositeRegion(®ion, pSrc, pMask, pDst, 459f7df2e56Smrg xSrc, ySrc, xMask, yMask, xDst, yDst, 460f7df2e56Smrg rects->width, rects->height)) 461f7df2e56Smrg goto next_rect; 462f7df2e56Smrg 463f7df2e56Smrg RegionTranslate(®ion, dst_off_x, dst_off_y); 464f7df2e56Smrg 465f7df2e56Smrg nbox = RegionNumRects(®ion); 466f7df2e56Smrg pbox = RegionRects(®ion); 467f7df2e56Smrg 468f7df2e56Smrg xMask = xMask + mask_off_x - xDst - dst_off_x; 469f7df2e56Smrg yMask = yMask + mask_off_y - yDst - dst_off_y; 470f7df2e56Smrg xSrc = xSrc + src_off_x - xDst - dst_off_x; 471f7df2e56Smrg ySrc = ySrc + src_off_y - yDst - dst_off_y; 472f7df2e56Smrg 473f7df2e56Smrg while (nbox--) { 474f7df2e56Smrg (*pExaScr->info->Composite) (pDstPix, 475f7df2e56Smrg pbox->x1 + xSrc, 476f7df2e56Smrg pbox->y1 + ySrc, 477f7df2e56Smrg pbox->x1 + xMask, 478f7df2e56Smrg pbox->y1 + yMask, 479f7df2e56Smrg pbox->x1, 480f7df2e56Smrg pbox->y1, 481f7df2e56Smrg pbox->x2 - pbox->x1, 482f7df2e56Smrg pbox->y2 - pbox->y1); 483f7df2e56Smrg pbox++; 484f7df2e56Smrg } 485f7df2e56Smrg 486f7df2e56Smrg next_rect: 487f7df2e56Smrg RegionUninit(®ion); 488f7df2e56Smrg 489f7df2e56Smrg rects++; 4904642e01fSmrg } 4914642e01fSmrg 4924642e01fSmrg (*pExaScr->info->DoneComposite) (pDstPix); 4934642e01fSmrg exaMarkSync(pDst->pDrawable->pScreen); 4944642e01fSmrg 4954642e01fSmrg return 1; 4964642e01fSmrg} 4974642e01fSmrg 4984642e01fSmrg/** 4994642e01fSmrg * Copy a number of rectangles from source to destination in a single 5006747b715Smrg * operation. This is specialized for glyph rendering: we don't have the 5016747b715Smrg * special-case fallbacks found in exaComposite() - if the driver can support 5026747b715Smrg * it, we use the driver functionality, otherwise we fall back straight to 5036747b715Smrg * software. 5044642e01fSmrg */ 5054642e01fSmrgvoid 506f7df2e56SmrgexaCompositeRects(CARD8 op, 507f7df2e56Smrg PicturePtr pSrc, 508f7df2e56Smrg PicturePtr pMask, 509f7df2e56Smrg PicturePtr pDst, int nrect, ExaCompositeRectPtr rects) 5104642e01fSmrg{ 511f7df2e56Smrg ExaScreenPriv(pDst->pDrawable->pScreen); 5124642e01fSmrg int n; 5134642e01fSmrg ExaCompositeRectPtr r; 5146747b715Smrg int ret; 5156747b715Smrg 5166747b715Smrg /* If we get a mask, that means we're rendering to the exaGlyphs 5176747b715Smrg * destination directly, so the damage layer takes care of this. 5186747b715Smrg */ 5196747b715Smrg if (!pMask) { 520f7df2e56Smrg RegionRec region; 521f7df2e56Smrg int x1 = MAXSHORT; 522f7df2e56Smrg int y1 = MAXSHORT; 523f7df2e56Smrg int x2 = MINSHORT; 524f7df2e56Smrg int y2 = MINSHORT; 525f7df2e56Smrg BoxRec box; 526f7df2e56Smrg 527f7df2e56Smrg /* We have to manage the damage ourselves, since CompositeRects isn't 528f7df2e56Smrg * something in the screen that can be managed by the damage extension, 529f7df2e56Smrg * and EXA depends on damage to track what needs to be migrated between 530f7df2e56Smrg * the gpu and the cpu. 531f7df2e56Smrg */ 532f7df2e56Smrg 533f7df2e56Smrg /* Compute the overall extents of the composited region - we're making 534f7df2e56Smrg * the assumption here that we are compositing a bunch of glyphs that 535f7df2e56Smrg * cluster closely together and damaging each glyph individually would 536f7df2e56Smrg * be a loss compared to damaging the bounding box. 537f7df2e56Smrg */ 538f7df2e56Smrg n = nrect; 539f7df2e56Smrg r = rects; 540f7df2e56Smrg while (n--) { 541f7df2e56Smrg int rect_x2 = r->xDst + r->width; 542f7df2e56Smrg int rect_y2 = r->yDst + r->height; 543f7df2e56Smrg 544f7df2e56Smrg if (r->xDst < x1) 545f7df2e56Smrg x1 = r->xDst; 546f7df2e56Smrg if (r->yDst < y1) 547f7df2e56Smrg y1 = r->yDst; 548f7df2e56Smrg if (rect_x2 > x2) 549f7df2e56Smrg x2 = rect_x2; 550f7df2e56Smrg if (rect_y2 > y2) 551f7df2e56Smrg y2 = rect_y2; 552f7df2e56Smrg 553f7df2e56Smrg r++; 554f7df2e56Smrg } 555f7df2e56Smrg 556f7df2e56Smrg if (x2 <= x1 || y2 <= y1) 557f7df2e56Smrg return; 558f7df2e56Smrg 559f7df2e56Smrg box.x1 = x1; 560f7df2e56Smrg box.x2 = x2 < MAXSHORT ? x2 : MAXSHORT; 561f7df2e56Smrg box.y1 = y1; 562f7df2e56Smrg box.y2 = y2 < MAXSHORT ? y2 : MAXSHORT; 563f7df2e56Smrg 564f7df2e56Smrg /* The pixmap migration code relies on pendingDamage indicating 565f7df2e56Smrg * the bounds of the current rendering, so we need to force 566f7df2e56Smrg * the actual damage into that region before we do anything, and 567f7df2e56Smrg * (see use of DamagePendingRegion in exaCopyDirty) 568f7df2e56Smrg */ 569f7df2e56Smrg 570f7df2e56Smrg RegionInit(®ion, &box, 1); 571f7df2e56Smrg 572f7df2e56Smrg DamageRegionAppend(pDst->pDrawable, ®ion); 573f7df2e56Smrg 574f7df2e56Smrg RegionUninit(®ion); 5754642e01fSmrg } 576f7df2e56Smrg 5774642e01fSmrg /************************************************************/ 578f7df2e56Smrg 579f7df2e56Smrg ValidatePicture(pSrc); 5806747b715Smrg if (pMask) 581f7df2e56Smrg ValidatePicture(pMask); 582f7df2e56Smrg ValidatePicture(pDst); 5836747b715Smrg 5846747b715Smrg ret = exaTryDriverCompositeRects(op, pSrc, pMask, pDst, nrect, rects); 5856747b715Smrg 5866747b715Smrg if (ret != 1) { 587f7df2e56Smrg if (ret == -1 && op == PictOpOver && pMask && pMask->componentAlpha && 588f7df2e56Smrg (!pExaScr->info->CheckComposite || 589f7df2e56Smrg ((*pExaScr->info->CheckComposite) (PictOpOutReverse, pSrc, pMask, 590f7df2e56Smrg pDst) && 591f7df2e56Smrg (*pExaScr->info->CheckComposite) (PictOpAdd, pSrc, pMask, 592f7df2e56Smrg pDst)))) { 593f7df2e56Smrg ret = 594f7df2e56Smrg exaTryDriverCompositeRects(PictOpOutReverse, pSrc, pMask, pDst, 595f7df2e56Smrg nrect, rects); 596f7df2e56Smrg if (ret == 1) { 597f7df2e56Smrg op = PictOpAdd; 598f7df2e56Smrg ret = exaTryDriverCompositeRects(op, pSrc, pMask, pDst, nrect, 599f7df2e56Smrg rects); 600f7df2e56Smrg } 601f7df2e56Smrg } 602f7df2e56Smrg 603f7df2e56Smrg if (ret != 1) { 604f7df2e56Smrg n = nrect; 605f7df2e56Smrg r = rects; 606f7df2e56Smrg while (n--) { 607f7df2e56Smrg ExaCheckComposite(op, pSrc, pMask, pDst, 608f7df2e56Smrg r->xSrc, r->ySrc, 609f7df2e56Smrg r->xMask, r->yMask, 610f7df2e56Smrg r->xDst, r->yDst, r->width, r->height); 611f7df2e56Smrg r++; 612f7df2e56Smrg } 613f7df2e56Smrg } 6144642e01fSmrg } 615f7df2e56Smrg 6164642e01fSmrg /************************************************************/ 6174642e01fSmrg 6186747b715Smrg if (!pMask) { 619f7df2e56Smrg /* Now we have to flush the damage out from pendingDamage => damage 620f7df2e56Smrg * Calling DamageRegionProcessPending has that effect. 621f7df2e56Smrg */ 6224642e01fSmrg 623f7df2e56Smrg DamageRegionProcessPending(pDst->pDrawable); 6244642e01fSmrg } 6254642e01fSmrg} 6264642e01fSmrg 62705b261ecSmrgstatic int 628f7df2e56SmrgexaTryDriverComposite(CARD8 op, 629f7df2e56Smrg PicturePtr pSrc, 630f7df2e56Smrg PicturePtr pMask, 631f7df2e56Smrg PicturePtr pDst, 632f7df2e56Smrg INT16 xSrc, 633f7df2e56Smrg INT16 ySrc, 634f7df2e56Smrg INT16 xMask, 635f7df2e56Smrg INT16 yMask, 636f7df2e56Smrg INT16 xDst, INT16 yDst, CARD16 width, CARD16 height) 63705b261ecSmrg{ 638f7df2e56Smrg ExaScreenPriv(pDst->pDrawable->pScreen); 63905b261ecSmrg RegionRec region; 64005b261ecSmrg BoxPtr pbox; 64105b261ecSmrg int nbox; 642f7df2e56Smrg int src_off_x, src_off_y, mask_off_x = 0, mask_off_y = 0, dst_off_x, dst_off_y; 6436747b715Smrg PixmapPtr pSrcPix = NULL, pMaskPix = NULL, pDstPix; 6446747b715Smrg ExaPixmapPrivPtr pSrcExaPix = NULL, pMaskExaPix = NULL, pDstExaPix; 64505b261ecSmrg 6466747b715Smrg if (pSrc->pDrawable) { 647f7df2e56Smrg pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable); 648f7df2e56Smrg pSrcExaPix = ExaGetPixmapPriv(pSrcPix); 6496747b715Smrg } 6504642e01fSmrg 65105b261ecSmrg pDstPix = exaGetDrawablePixmap(pDst->pDrawable); 6524642e01fSmrg pDstExaPix = ExaGetPixmapPriv(pDstPix); 6534642e01fSmrg 6546747b715Smrg if (pMask && pMask->pDrawable) { 655f7df2e56Smrg pMaskPix = exaGetDrawablePixmap(pMask->pDrawable); 6564642e01fSmrg pMaskExaPix = ExaGetPixmapPriv(pMaskPix); 6574642e01fSmrg } 65805b261ecSmrg 6594642e01fSmrg /* Check whether the accelerator can use these pixmaps. 6604642e01fSmrg * FIXME: If it cannot, use temporary pixmaps so that the drawing 6614642e01fSmrg * happens within limits. 66205b261ecSmrg */ 6636747b715Smrg if (pDstExaPix->accel_blocked || 664f7df2e56Smrg (pSrcExaPix && pSrcExaPix->accel_blocked) || 665f7df2e56Smrg (pMaskExaPix && (pMaskExaPix->accel_blocked))) { 666f7df2e56Smrg return -1; 66705b261ecSmrg } 66805b261ecSmrg 66905b261ecSmrg xDst += pDst->pDrawable->x; 67005b261ecSmrg yDst += pDst->pDrawable->y; 67105b261ecSmrg 6726747b715Smrg if (pMaskPix) { 673f7df2e56Smrg xMask += pMask->pDrawable->x; 674f7df2e56Smrg yMask += pMask->pDrawable->y; 67505b261ecSmrg } 67605b261ecSmrg 6776747b715Smrg if (pSrcPix) { 678f7df2e56Smrg xSrc += pSrc->pDrawable->x; 679f7df2e56Smrg ySrc += pSrc->pDrawable->y; 6806747b715Smrg } 68105b261ecSmrg 68205b261ecSmrg if (pExaScr->info->CheckComposite && 683f7df2e56Smrg !(*pExaScr->info->CheckComposite) (op, pSrc, pMask, pDst)) { 684f7df2e56Smrg return -1; 68505b261ecSmrg } 68605b261ecSmrg 687f7df2e56Smrg if (!miComputeCompositeRegion(®ion, pSrc, pMask, pDst, 688f7df2e56Smrg xSrc, ySrc, xMask, yMask, xDst, yDst, 689f7df2e56Smrg width, height)) 690f7df2e56Smrg return 1; 6914642e01fSmrg 692f7df2e56Smrg exaGetDrawableDeltas(pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y); 6934642e01fSmrg 6946747b715Smrg RegionTranslate(®ion, dst_off_x, dst_off_y); 69505b261ecSmrg 6966747b715Smrg if (pExaScr->do_migration) { 697f7df2e56Smrg ExaMigrationRec pixmaps[3]; 698f7df2e56Smrg int i = 0; 699f7df2e56Smrg 700f7df2e56Smrg pixmaps[i].as_dst = TRUE; 701f7df2e56Smrg pixmaps[i].as_src = exaOpReadsDestination(op); 702f7df2e56Smrg pixmaps[i].pPix = pDstPix; 703f7df2e56Smrg pixmaps[i].pReg = pixmaps[0].as_src ? NULL : ®ion; 704f7df2e56Smrg i++; 705f7df2e56Smrg 706f7df2e56Smrg if (pSrcPix) { 707f7df2e56Smrg pixmaps[i].as_dst = FALSE; 708f7df2e56Smrg pixmaps[i].as_src = TRUE; 709f7df2e56Smrg pixmaps[i].pPix = pSrcPix; 710f7df2e56Smrg pixmaps[i].pReg = NULL; 711f7df2e56Smrg i++; 712f7df2e56Smrg } 713f7df2e56Smrg 714f7df2e56Smrg if (pMaskPix) { 715f7df2e56Smrg pixmaps[i].as_dst = FALSE; 716f7df2e56Smrg pixmaps[i].as_src = TRUE; 717f7df2e56Smrg pixmaps[i].pPix = pMaskPix; 718f7df2e56Smrg pixmaps[i].pReg = NULL; 719f7df2e56Smrg i++; 720f7df2e56Smrg } 721f7df2e56Smrg 722f7df2e56Smrg exaDoMigration(pixmaps, i, TRUE); 72305b261ecSmrg } 72405b261ecSmrg 7256747b715Smrg if (pSrcPix) { 726f7df2e56Smrg pSrcPix = 727f7df2e56Smrg exaGetOffscreenPixmap(pSrc->pDrawable, &src_off_x, &src_off_y); 728f7df2e56Smrg if (!pSrcPix) { 729f7df2e56Smrg RegionUninit(®ion); 730f7df2e56Smrg return 0; 731f7df2e56Smrg } 7326747b715Smrg } 7336747b715Smrg 7346747b715Smrg if (pMaskPix) { 735f7df2e56Smrg pMaskPix = exaGetOffscreenPixmap(pMask->pDrawable, &mask_off_x, 736f7df2e56Smrg &mask_off_y); 737f7df2e56Smrg if (!pMaskPix) { 738f7df2e56Smrg RegionUninit(®ion); 739f7df2e56Smrg return 0; 740f7df2e56Smrg } 74105b261ecSmrg } 74205b261ecSmrg 7436747b715Smrg if (!exaPixmapHasGpuCopy(pDstPix)) { 744f7df2e56Smrg RegionUninit(®ion); 745f7df2e56Smrg return 0; 74605b261ecSmrg } 74705b261ecSmrg 74805b261ecSmrg if (!(*pExaScr->info->PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix, 749f7df2e56Smrg pMaskPix, pDstPix)) { 750f7df2e56Smrg RegionUninit(®ion); 751f7df2e56Smrg return -1; 75205b261ecSmrg } 75305b261ecSmrg 7546747b715Smrg nbox = RegionNumRects(®ion); 7556747b715Smrg pbox = RegionRects(®ion); 75605b261ecSmrg 7574642e01fSmrg xMask = xMask + mask_off_x - xDst - dst_off_x; 7584642e01fSmrg yMask = yMask + mask_off_y - yDst - dst_off_y; 75905b261ecSmrg 7604642e01fSmrg xSrc = xSrc + src_off_x - xDst - dst_off_x; 7614642e01fSmrg ySrc = ySrc + src_off_y - yDst - dst_off_y; 76205b261ecSmrg 763f7df2e56Smrg while (nbox--) { 764f7df2e56Smrg (*pExaScr->info->Composite) (pDstPix, 765f7df2e56Smrg pbox->x1 + xSrc, 766f7df2e56Smrg pbox->y1 + ySrc, 767f7df2e56Smrg pbox->x1 + xMask, 768f7df2e56Smrg pbox->y1 + yMask, 769f7df2e56Smrg pbox->x1, 770f7df2e56Smrg pbox->y1, 771f7df2e56Smrg pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); 772f7df2e56Smrg pbox++; 77305b261ecSmrg } 77405b261ecSmrg (*pExaScr->info->DoneComposite) (pDstPix); 77505b261ecSmrg exaMarkSync(pDst->pDrawable->pScreen); 77605b261ecSmrg 7776747b715Smrg RegionUninit(®ion); 77805b261ecSmrg return 1; 77905b261ecSmrg} 78005b261ecSmrg 78105b261ecSmrg/** 78205b261ecSmrg * exaTryMagicTwoPassCompositeHelper implements PictOpOver using two passes of 78305b261ecSmrg * simpler operations PictOpOutReverse and PictOpAdd. Mainly used for component 78405b261ecSmrg * alpha and limited 1-tmu cards. 78505b261ecSmrg * 78605b261ecSmrg * From http://anholt.livejournal.com/32058.html: 78705b261ecSmrg * 78805b261ecSmrg * The trouble is that component-alpha rendering requires two different sources 78905b261ecSmrg * for blending: one for the source value to the blender, which is the 79005b261ecSmrg * per-channel multiplication of source and mask, and one for the source alpha 79105b261ecSmrg * for multiplying with the destination channels, which is the multiplication 79205b261ecSmrg * of the source channels by the mask alpha. So the equation for Over is: 79305b261ecSmrg * 79405b261ecSmrg * dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A 79505b261ecSmrg * dst.R = src.R * mask.R + (1 - (src.A * mask.R)) * dst.R 79605b261ecSmrg * dst.G = src.G * mask.G + (1 - (src.A * mask.G)) * dst.G 79705b261ecSmrg * dst.B = src.B * mask.B + (1 - (src.A * mask.B)) * dst.B 79805b261ecSmrg * 79905b261ecSmrg * But we can do some simpler operations, right? How about PictOpOutReverse, 80005b261ecSmrg * which has a source factor of 0 and dest factor of (1 - source alpha). We 80105b261ecSmrg * can get the source alpha value (srca.X = src.A * mask.X) out of the texture 80205b261ecSmrg * blenders pretty easily. So we can do a component-alpha OutReverse, which 80305b261ecSmrg * gets us: 80405b261ecSmrg * 80505b261ecSmrg * dst.A = 0 + (1 - (src.A * mask.A)) * dst.A 80605b261ecSmrg * dst.R = 0 + (1 - (src.A * mask.R)) * dst.R 80705b261ecSmrg * dst.G = 0 + (1 - (src.A * mask.G)) * dst.G 80805b261ecSmrg * dst.B = 0 + (1 - (src.A * mask.B)) * dst.B 80905b261ecSmrg * 81005b261ecSmrg * OK. And if an op doesn't use the source alpha value for the destination 81105b261ecSmrg * factor, then we can do the channel multiplication in the texture blenders 81205b261ecSmrg * to get the source value, and ignore the source alpha that we wouldn't use. 81305b261ecSmrg * We've supported this in the Radeon driver for a long time. An example would 81405b261ecSmrg * be PictOpAdd, which does: 81505b261ecSmrg * 81605b261ecSmrg * dst.A = src.A * mask.A + dst.A 81705b261ecSmrg * dst.R = src.R * mask.R + dst.R 81805b261ecSmrg * dst.G = src.G * mask.G + dst.G 81905b261ecSmrg * dst.B = src.B * mask.B + dst.B 82005b261ecSmrg * 82105b261ecSmrg * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right 82205b261ecSmrg * after it, we get: 82305b261ecSmrg * 82405b261ecSmrg * dst.A = src.A * mask.A + ((1 - (src.A * mask.A)) * dst.A) 82505b261ecSmrg * dst.R = src.R * mask.R + ((1 - (src.A * mask.R)) * dst.R) 82605b261ecSmrg * dst.G = src.G * mask.G + ((1 - (src.A * mask.G)) * dst.G) 82705b261ecSmrg * dst.B = src.B * mask.B + ((1 - (src.A * mask.B)) * dst.B) 82805b261ecSmrg */ 82905b261ecSmrg 83005b261ecSmrgstatic int 83105b261ecSmrgexaTryMagicTwoPassCompositeHelper(CARD8 op, 832f7df2e56Smrg PicturePtr pSrc, 833f7df2e56Smrg PicturePtr pMask, 834f7df2e56Smrg PicturePtr pDst, 835f7df2e56Smrg INT16 xSrc, 836f7df2e56Smrg INT16 ySrc, 837f7df2e56Smrg INT16 xMask, 838f7df2e56Smrg INT16 yMask, 839f7df2e56Smrg INT16 xDst, 840f7df2e56Smrg INT16 yDst, CARD16 width, CARD16 height) 84105b261ecSmrg{ 842f7df2e56Smrg ExaScreenPriv(pDst->pDrawable->pScreen); 84305b261ecSmrg 84405b261ecSmrg assert(op == PictOpOver); 84505b261ecSmrg 84605b261ecSmrg if (pExaScr->info->CheckComposite && 847f7df2e56Smrg (!(*pExaScr->info->CheckComposite) (PictOpOutReverse, pSrc, pMask, 848f7df2e56Smrg pDst) || 849f7df2e56Smrg !(*pExaScr->info->CheckComposite) (PictOpAdd, pSrc, pMask, pDst))) { 850f7df2e56Smrg return -1; 85105b261ecSmrg } 85205b261ecSmrg 85305b261ecSmrg /* Now, we think we should be able to accelerate this operation. First, 85405b261ecSmrg * composite the destination to be the destination times the source alpha 85505b261ecSmrg * factors. 85605b261ecSmrg */ 85705b261ecSmrg exaComposite(PictOpOutReverse, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, 858f7df2e56Smrg xDst, yDst, width, height); 85905b261ecSmrg 86005b261ecSmrg /* Then, add in the source value times the destination alpha factors (1.0). 86105b261ecSmrg */ 86205b261ecSmrg exaComposite(PictOpAdd, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, 863f7df2e56Smrg xDst, yDst, width, height); 86405b261ecSmrg 86505b261ecSmrg return 1; 86605b261ecSmrg} 86705b261ecSmrg 86805b261ecSmrgvoid 869f7df2e56SmrgexaComposite(CARD8 op, 870f7df2e56Smrg PicturePtr pSrc, 871f7df2e56Smrg PicturePtr pMask, 872f7df2e56Smrg PicturePtr pDst, 873f7df2e56Smrg INT16 xSrc, 874f7df2e56Smrg INT16 ySrc, 875f7df2e56Smrg INT16 xMask, 876f7df2e56Smrg INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height) 87705b261ecSmrg{ 878f7df2e56Smrg ExaScreenPriv(pDst->pDrawable->pScreen); 87905b261ecSmrg int ret = -1; 88005b261ecSmrg Bool saveSrcRepeat = pSrc->repeat; 88105b261ecSmrg Bool saveMaskRepeat = pMask ? pMask->repeat : 0; 8824642e01fSmrg RegionRec region; 88305b261ecSmrg 8846747b715Smrg if (pExaScr->swappedOut) 885f7df2e56Smrg goto fallback; 88605b261ecSmrg 88705b261ecSmrg /* Remove repeat in source if useless */ 8886747b715Smrg if (pSrc->pDrawable && pSrc->repeat && !pSrc->transform && xSrc >= 0 && 889f7df2e56Smrg (xSrc + width) <= pSrc->pDrawable->width && ySrc >= 0 && 890f7df2e56Smrg (ySrc + height) <= pSrc->pDrawable->height) 891f7df2e56Smrg pSrc->repeat = 0; 89205b261ecSmrg 8936747b715Smrg if (!pMask && !pSrc->alphaMap && !pDst->alphaMap && 894f7df2e56Smrg (op == PictOpSrc || (op == PictOpOver && !PICT_FORMAT_A(pSrc->format)))) 89505b261ecSmrg { 896f7df2e56Smrg if (pSrc->pDrawable ? 897f7df2e56Smrg (pSrc->pDrawable->width == 1 && pSrc->pDrawable->height == 1 && 898f7df2e56Smrg pSrc->repeat) : 899f7df2e56Smrg (pSrc->pSourcePict->type == SourcePictTypeSolidFill)) { 900f7df2e56Smrg ret = exaTryDriverSolidFill(pSrc, pDst, xSrc, ySrc, xDst, yDst, 901f7df2e56Smrg width, height); 902f7df2e56Smrg if (ret == 1) 903f7df2e56Smrg goto done; 904f7df2e56Smrg } 905f7df2e56Smrg else if (pSrc->pDrawable && !pSrc->transform && 906f7df2e56Smrg ((op == PictOpSrc && 907f7df2e56Smrg (pSrc->format == pDst->format || 908f7df2e56Smrg (PICT_FORMAT_COLOR(pDst->format) && 909f7df2e56Smrg PICT_FORMAT_COLOR(pSrc->format) && 910f7df2e56Smrg pDst->format == PICT_FORMAT(PICT_FORMAT_BPP(pSrc->format), 911f7df2e56Smrg PICT_FORMAT_TYPE(pSrc->format), 912f7df2e56Smrg 0, 913f7df2e56Smrg PICT_FORMAT_R(pSrc->format), 914f7df2e56Smrg PICT_FORMAT_G(pSrc->format), 915f7df2e56Smrg PICT_FORMAT_B(pSrc->format))))) 916f7df2e56Smrg || (op == PictOpOver && pSrc->format == pDst->format && 917f7df2e56Smrg !PICT_FORMAT_A(pSrc->format)))) { 918f7df2e56Smrg if (!pSrc->repeat && xSrc >= 0 && ySrc >= 0 && 919f7df2e56Smrg (xSrc + width <= pSrc->pDrawable->width) && 920f7df2e56Smrg (ySrc + height <= pSrc->pDrawable->height)) { 921f7df2e56Smrg Bool suc; 922f7df2e56Smrg 923f7df2e56Smrg xDst += pDst->pDrawable->x; 924f7df2e56Smrg yDst += pDst->pDrawable->y; 925f7df2e56Smrg xSrc += pSrc->pDrawable->x; 926f7df2e56Smrg ySrc += pSrc->pDrawable->y; 927f7df2e56Smrg 928f7df2e56Smrg if (!miComputeCompositeRegion(®ion, pSrc, pMask, pDst, 929f7df2e56Smrg xSrc, ySrc, xMask, yMask, xDst, 930f7df2e56Smrg yDst, width, height)) 931f7df2e56Smrg goto done; 932f7df2e56Smrg 933f7df2e56Smrg suc = exaHWCopyNtoN(pSrc->pDrawable, pDst->pDrawable, NULL, 934f7df2e56Smrg RegionRects(®ion), 935f7df2e56Smrg RegionNumRects(®ion), xSrc - xDst, 936f7df2e56Smrg ySrc - yDst, FALSE, FALSE); 937f7df2e56Smrg RegionUninit(®ion); 938f7df2e56Smrg 939f7df2e56Smrg /* Reset values to their original values. */ 940f7df2e56Smrg xDst -= pDst->pDrawable->x; 941f7df2e56Smrg yDst -= pDst->pDrawable->y; 942f7df2e56Smrg xSrc -= pSrc->pDrawable->x; 943f7df2e56Smrg ySrc -= pSrc->pDrawable->y; 944f7df2e56Smrg 945f7df2e56Smrg if (!suc) 946f7df2e56Smrg goto fallback; 947f7df2e56Smrg 948f7df2e56Smrg goto done; 949f7df2e56Smrg } 950f7df2e56Smrg 951f7df2e56Smrg if (pSrc->repeat && pSrc->repeatType == RepeatNormal && 952f7df2e56Smrg pSrc->pDrawable->type == DRAWABLE_PIXMAP) { 953f7df2e56Smrg DDXPointRec patOrg; 954f7df2e56Smrg 955f7df2e56Smrg /* Let's see if the driver can do the repeat in one go */ 956f7df2e56Smrg if (pExaScr->info->PrepareComposite && !pSrc->alphaMap && 957f7df2e56Smrg !pDst->alphaMap) { 958f7df2e56Smrg ret = exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc, 959f7df2e56Smrg ySrc, xMask, yMask, xDst, yDst, 960f7df2e56Smrg width, height); 961f7df2e56Smrg if (ret == 1) 962f7df2e56Smrg goto done; 963f7df2e56Smrg } 964f7df2e56Smrg 965f7df2e56Smrg /* Now see if we can use exaFillRegionTiled() */ 966f7df2e56Smrg xDst += pDst->pDrawable->x; 967f7df2e56Smrg yDst += pDst->pDrawable->y; 968f7df2e56Smrg xSrc += pSrc->pDrawable->x; 969f7df2e56Smrg ySrc += pSrc->pDrawable->y; 970f7df2e56Smrg 971f7df2e56Smrg if (!miComputeCompositeRegion(®ion, pSrc, pMask, pDst, xSrc, 972f7df2e56Smrg ySrc, xMask, yMask, xDst, yDst, 973f7df2e56Smrg width, height)) 974f7df2e56Smrg goto done; 975f7df2e56Smrg 976f7df2e56Smrg /* pattern origin is the point in the destination drawable 977f7df2e56Smrg * corresponding to (0,0) in the source */ 978f7df2e56Smrg patOrg.x = xDst - xSrc; 979f7df2e56Smrg patOrg.y = yDst - ySrc; 980f7df2e56Smrg 981f7df2e56Smrg ret = exaFillRegionTiled(pDst->pDrawable, ®ion, 982f7df2e56Smrg (PixmapPtr) pSrc->pDrawable, 983f7df2e56Smrg &patOrg, FB_ALLONES, GXcopy, CT_NONE); 984f7df2e56Smrg 985f7df2e56Smrg RegionUninit(®ion); 986f7df2e56Smrg 987f7df2e56Smrg if (ret) 988f7df2e56Smrg goto done; 989f7df2e56Smrg 990f7df2e56Smrg /* Let's be correct and restore the variables to their original state. */ 991f7df2e56Smrg xDst -= pDst->pDrawable->x; 992f7df2e56Smrg yDst -= pDst->pDrawable->y; 993f7df2e56Smrg xSrc -= pSrc->pDrawable->x; 994f7df2e56Smrg ySrc -= pSrc->pDrawable->y; 995f7df2e56Smrg } 996f7df2e56Smrg } 99705b261ecSmrg } 99805b261ecSmrg 99905b261ecSmrg /* Remove repeat in mask if useless */ 10006747b715Smrg if (pMask && pMask->pDrawable && pMask->repeat && !pMask->transform && 1001f7df2e56Smrg xMask >= 0 && (xMask + width) <= pMask->pDrawable->width && 1002f7df2e56Smrg yMask >= 0 && (yMask + height) <= pMask->pDrawable->height) 1003f7df2e56Smrg pMask->repeat = 0; 100405b261ecSmrg 100505b261ecSmrg if (pExaScr->info->PrepareComposite && 1006f7df2e56Smrg !pSrc->alphaMap && (!pMask || !pMask->alphaMap) && !pDst->alphaMap) { 1007f7df2e56Smrg Bool isSrcSolid; 1008f7df2e56Smrg 1009f7df2e56Smrg ret = exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask, 1010f7df2e56Smrg yMask, xDst, yDst, width, height); 1011f7df2e56Smrg if (ret == 1) 1012f7df2e56Smrg goto done; 1013f7df2e56Smrg 1014f7df2e56Smrg /* For generic masks and solid src pictures, mach64 can do Over in two 1015f7df2e56Smrg * passes, similar to the component-alpha case. 1016f7df2e56Smrg */ 1017f7df2e56Smrg isSrcSolid = pSrc->pDrawable ? 1018f7df2e56Smrg (pSrc->pDrawable->width == 1 && pSrc->pDrawable->height == 1 && 1019f7df2e56Smrg pSrc->repeat) : 1020f7df2e56Smrg (pSrc->pSourcePict->type == SourcePictTypeSolidFill); 1021f7df2e56Smrg 1022f7df2e56Smrg /* If we couldn't do the Composite in a single pass, and it was a 1023f7df2e56Smrg * component-alpha Over, see if we can do it in two passes with 1024f7df2e56Smrg * an OutReverse and then an Add. 1025f7df2e56Smrg */ 1026f7df2e56Smrg if (ret == -1 && op == PictOpOver && pMask && 1027f7df2e56Smrg (pMask->componentAlpha || isSrcSolid)) { 1028f7df2e56Smrg ret = exaTryMagicTwoPassCompositeHelper(op, pSrc, pMask, pDst, 1029f7df2e56Smrg xSrc, ySrc, 1030f7df2e56Smrg xMask, yMask, xDst, yDst, 1031f7df2e56Smrg width, height); 1032f7df2e56Smrg if (ret == 1) 1033f7df2e56Smrg goto done; 1034f7df2e56Smrg } 103505b261ecSmrg } 103605b261ecSmrg 1037f7df2e56Smrg fallback: 103805b261ecSmrg#if DEBUG_TRACE_FALL 1039f7df2e56Smrg exaPrintCompositeFallback(op, pSrc, pMask, pDst); 104005b261ecSmrg#endif 104105b261ecSmrg 1042f7df2e56Smrg ExaCheckComposite(op, pSrc, pMask, pDst, xSrc, ySrc, 1043f7df2e56Smrg xMask, yMask, xDst, yDst, width, height); 104405b261ecSmrg 1045f7df2e56Smrg done: 104605b261ecSmrg pSrc->repeat = saveSrcRepeat; 104705b261ecSmrg if (pMask) 1048f7df2e56Smrg pMask->repeat = saveMaskRepeat; 104905b261ecSmrg} 105005b261ecSmrg 105105b261ecSmrg/** 105205b261ecSmrg * Same as miCreateAlphaPicture, except it uses ExaCheckPolyFillRect instead 105305b261ecSmrg * of PolyFillRect to initialize the pixmap after creating it, to prevent 105405b261ecSmrg * the pixmap from being migrated. 105505b261ecSmrg * 10564642e01fSmrg * See the comments about exaTrapezoids and exaTriangles. 105705b261ecSmrg */ 105805b261ecSmrgstatic PicturePtr 1059f7df2e56SmrgexaCreateAlphaPicture(ScreenPtr pScreen, 1060f7df2e56Smrg PicturePtr pDst, 1061f7df2e56Smrg PictFormatPtr pPictFormat, CARD16 width, CARD16 height) 106205b261ecSmrg{ 1063f7df2e56Smrg PixmapPtr pPixmap; 1064f7df2e56Smrg PicturePtr pPicture; 1065f7df2e56Smrg GCPtr pGC; 1066f7df2e56Smrg int error; 1067f7df2e56Smrg xRectangle rect; 106805b261ecSmrg 106905b261ecSmrg if (width > 32767 || height > 32767) 1070f7df2e56Smrg return 0; 1071f7df2e56Smrg 1072f7df2e56Smrg if (!pPictFormat) { 1073f7df2e56Smrg if (pDst->polyEdge == PolyEdgeSharp) 1074f7df2e56Smrg pPictFormat = PictureMatchFormat(pScreen, 1, PICT_a1); 1075f7df2e56Smrg else 1076f7df2e56Smrg pPictFormat = PictureMatchFormat(pScreen, 8, PICT_a8); 1077f7df2e56Smrg if (!pPictFormat) 1078f7df2e56Smrg return 0; 107905b261ecSmrg } 108005b261ecSmrg 108105b261ecSmrg pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, 1082f7df2e56Smrg pPictFormat->depth, 0); 108305b261ecSmrg if (!pPixmap) 1084f7df2e56Smrg return 0; 1085f7df2e56Smrg pGC = GetScratchGC(pPixmap->drawable.depth, pScreen); 1086f7df2e56Smrg if (!pGC) { 1087f7df2e56Smrg (*pScreen->DestroyPixmap) (pPixmap); 1088f7df2e56Smrg return 0; 108905b261ecSmrg } 1090f7df2e56Smrg ValidateGC(&pPixmap->drawable, pGC); 109105b261ecSmrg rect.x = 0; 109205b261ecSmrg rect.y = 0; 109305b261ecSmrg rect.width = width; 109405b261ecSmrg rect.height = height; 1095f7df2e56Smrg ExaCheckPolyFillRect(&pPixmap->drawable, pGC, 1, &rect); 1096f7df2e56Smrg exaPixmapDirty(pPixmap, 0, 0, width, height); 1097f7df2e56Smrg FreeScratchGC(pGC); 1098f7df2e56Smrg pPicture = CreatePicture(0, &pPixmap->drawable, pPictFormat, 1099f7df2e56Smrg 0, 0, serverClient, &error); 110005b261ecSmrg (*pScreen->DestroyPixmap) (pPixmap); 110105b261ecSmrg return pPicture; 110205b261ecSmrg} 110305b261ecSmrg 110405b261ecSmrg/** 110505b261ecSmrg * exaTrapezoids is essentially a copy of miTrapezoids that uses 110605b261ecSmrg * exaCreateAlphaPicture instead of miCreateAlphaPicture. 110705b261ecSmrg * 110805b261ecSmrg * The problem with miCreateAlphaPicture is that it calls PolyFillRect 110905b261ecSmrg * to initialize the contents after creating the pixmap, which 111005b261ecSmrg * causes the pixmap to be moved in for acceleration. The subsequent 111105b261ecSmrg * call to RasterizeTrapezoid won't be accelerated however, which 111205b261ecSmrg * forces the pixmap to be moved out again. 111305b261ecSmrg * 111405b261ecSmrg * exaCreateAlphaPicture avoids this roundtrip by using ExaCheckPolyFillRect 111505b261ecSmrg * to initialize the contents. 111605b261ecSmrg */ 111705b261ecSmrgvoid 1118f7df2e56SmrgexaTrapezoids(CARD8 op, PicturePtr pSrc, PicturePtr pDst, 1119f7df2e56Smrg PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, 1120f7df2e56Smrg int ntrap, xTrapezoid * traps) 112105b261ecSmrg{ 1122f7df2e56Smrg ScreenPtr pScreen = pDst->pDrawable->pScreen; 1123f7df2e56Smrg PictureScreenPtr ps = GetPictureScreen(pScreen); 1124f7df2e56Smrg BoxRec bounds; 11254642e01fSmrg 11264642e01fSmrg if (maskFormat) { 1127f7df2e56Smrg PicturePtr pPicture; 1128f7df2e56Smrg INT16 xDst, yDst; 1129f7df2e56Smrg INT16 xRel, yRel; 1130f7df2e56Smrg 1131f7df2e56Smrg miTrapezoidBounds(ntrap, traps, &bounds); 1132f7df2e56Smrg 1133f7df2e56Smrg if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) 1134f7df2e56Smrg return; 1135f7df2e56Smrg 1136f7df2e56Smrg xDst = traps[0].left.p1.x >> 16; 1137f7df2e56Smrg yDst = traps[0].left.p1.y >> 16; 1138f7df2e56Smrg 1139f7df2e56Smrg pPicture = exaCreateAlphaPicture(pScreen, pDst, maskFormat, 1140f7df2e56Smrg bounds.x2 - bounds.x1, 1141f7df2e56Smrg bounds.y2 - bounds.y1); 1142f7df2e56Smrg if (!pPicture) 1143f7df2e56Smrg return; 1144f7df2e56Smrg 1145f7df2e56Smrg exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST); 1146f7df2e56Smrg for (; ntrap; ntrap--, traps++) 1147f7df2e56Smrg if (xTrapezoidValid(traps)) 1148f7df2e56Smrg (*ps->RasterizeTrapezoid) (pPicture, traps, -bounds.x1, -bounds.y1); 1149f7df2e56Smrg exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST); 1150f7df2e56Smrg 1151f7df2e56Smrg xRel = bounds.x1 + xSrc - xDst; 1152f7df2e56Smrg yRel = bounds.y1 + ySrc - yDst; 1153f7df2e56Smrg CompositePicture(op, pSrc, pPicture, pDst, 1154f7df2e56Smrg xRel, yRel, 0, 0, bounds.x1, bounds.y1, 1155f7df2e56Smrg bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); 1156f7df2e56Smrg FreePicture(pPicture, 0); 1157f7df2e56Smrg } 1158f7df2e56Smrg else { 1159f7df2e56Smrg if (pDst->polyEdge == PolyEdgeSharp) 1160f7df2e56Smrg maskFormat = PictureMatchFormat(pScreen, 1, PICT_a1); 1161f7df2e56Smrg else 1162f7df2e56Smrg maskFormat = PictureMatchFormat(pScreen, 8, PICT_a8); 1163f7df2e56Smrg for (; ntrap; ntrap--, traps++) 1164f7df2e56Smrg exaTrapezoids(op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, traps); 116505b261ecSmrg } 116605b261ecSmrg} 116705b261ecSmrg 116805b261ecSmrg/** 11694642e01fSmrg * exaTriangles is essentially a copy of miTriangles that uses 11704642e01fSmrg * exaCreateAlphaPicture instead of miCreateAlphaPicture. 117105b261ecSmrg * 11724642e01fSmrg * The problem with miCreateAlphaPicture is that it calls PolyFillRect 11734642e01fSmrg * to initialize the contents after creating the pixmap, which 11744642e01fSmrg * causes the pixmap to be moved in for acceleration. The subsequent 11754642e01fSmrg * call to AddTriangles won't be accelerated however, which forces the pixmap 11764642e01fSmrg * to be moved out again. 11774642e01fSmrg * 11784642e01fSmrg * exaCreateAlphaPicture avoids this roundtrip by using ExaCheckPolyFillRect 11794642e01fSmrg * to initialize the contents. 118005b261ecSmrg */ 118105b261ecSmrgvoid 1182f7df2e56SmrgexaTriangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst, 1183f7df2e56Smrg PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, 1184f7df2e56Smrg int ntri, xTriangle * tris) 118505b261ecSmrg{ 1186f7df2e56Smrg ScreenPtr pScreen = pDst->pDrawable->pScreen; 1187f7df2e56Smrg PictureScreenPtr ps = GetPictureScreen(pScreen); 1188f7df2e56Smrg BoxRec bounds; 118905b261ecSmrg 11904642e01fSmrg if (maskFormat) { 1191f7df2e56Smrg PicturePtr pPicture; 1192f7df2e56Smrg INT16 xDst, yDst; 1193f7df2e56Smrg INT16 xRel, yRel; 1194f7df2e56Smrg 1195f7df2e56Smrg miTriangleBounds(ntri, tris, &bounds); 1196f7df2e56Smrg 1197f7df2e56Smrg if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) 1198f7df2e56Smrg return; 1199f7df2e56Smrg 1200f7df2e56Smrg xDst = tris[0].p1.x >> 16; 1201f7df2e56Smrg yDst = tris[0].p1.y >> 16; 1202f7df2e56Smrg 1203f7df2e56Smrg pPicture = exaCreateAlphaPicture(pScreen, pDst, maskFormat, 1204f7df2e56Smrg bounds.x2 - bounds.x1, 1205f7df2e56Smrg bounds.y2 - bounds.y1); 1206f7df2e56Smrg if (!pPicture) 1207f7df2e56Smrg return; 1208f7df2e56Smrg 1209f7df2e56Smrg exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST); 1210f7df2e56Smrg (*ps->AddTriangles) (pPicture, -bounds.x1, -bounds.y1, ntri, tris); 1211f7df2e56Smrg exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST); 1212f7df2e56Smrg 1213f7df2e56Smrg xRel = bounds.x1 + xSrc - xDst; 1214f7df2e56Smrg yRel = bounds.y1 + ySrc - yDst; 1215f7df2e56Smrg CompositePicture(op, pSrc, pPicture, pDst, 1216f7df2e56Smrg xRel, yRel, 0, 0, bounds.x1, bounds.y1, 1217f7df2e56Smrg bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); 1218f7df2e56Smrg FreePicture(pPicture, 0); 1219f7df2e56Smrg } 1220f7df2e56Smrg else { 1221f7df2e56Smrg if (pDst->polyEdge == PolyEdgeSharp) 1222f7df2e56Smrg maskFormat = PictureMatchFormat(pScreen, 1, PICT_a1); 1223f7df2e56Smrg else 1224f7df2e56Smrg maskFormat = PictureMatchFormat(pScreen, 8, PICT_a8); 1225f7df2e56Smrg 1226f7df2e56Smrg for (; ntri; ntri--, tris++) 1227f7df2e56Smrg exaTriangles(op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, tris); 122805b261ecSmrg } 122905b261ecSmrg} 1230