1706f2543Smrg/* 2706f2543Smrg * Copyright © 2001 Keith Packard 3706f2543Smrg * 4706f2543Smrg * Partly based on code that is Copyright © The XFree86 Project Inc. 5706f2543Smrg * 6706f2543Smrg * Permission to use, copy, modify, distribute, and sell this software and its 7706f2543Smrg * documentation for any purpose is hereby granted without fee, provided that 8706f2543Smrg * the above copyright notice appear in all copies and that both that 9706f2543Smrg * copyright notice and this permission notice appear in supporting 10706f2543Smrg * documentation, and that the name of Keith Packard not be used in 11706f2543Smrg * advertising or publicity pertaining to distribution of the software without 12706f2543Smrg * specific, written prior permission. Keith Packard makes no 13706f2543Smrg * representations about the suitability of this software for any purpose. It 14706f2543Smrg * is provided "as is" without express or implied warranty. 15706f2543Smrg * 16706f2543Smrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 17706f2543Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 18706f2543Smrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 19706f2543Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 20706f2543Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 21706f2543Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 22706f2543Smrg * PERFORMANCE OF THIS SOFTWARE. 23706f2543Smrg */ 24706f2543Smrg 25706f2543Smrg#ifdef HAVE_DIX_CONFIG_H 26706f2543Smrg#include <dix-config.h> 27706f2543Smrg#endif 28706f2543Smrg 29706f2543Smrg#include <stdlib.h> 30706f2543Smrg 31706f2543Smrg#include "exa_priv.h" 32706f2543Smrg 33706f2543Smrg#include "mipict.h" 34706f2543Smrg 35706f2543Smrg#if DEBUG_TRACE_FALL 36706f2543Smrgstatic void exaCompositeFallbackPictDesc(PicturePtr pict, char *string, int n) 37706f2543Smrg{ 38706f2543Smrg char format[20]; 39706f2543Smrg char size[20]; 40706f2543Smrg char loc; 41706f2543Smrg int temp; 42706f2543Smrg 43706f2543Smrg if (!pict) { 44706f2543Smrg snprintf(string, n, "None"); 45706f2543Smrg return; 46706f2543Smrg } 47706f2543Smrg 48706f2543Smrg switch (pict->format) 49706f2543Smrg { 50706f2543Smrg case PICT_a8r8g8b8: 51706f2543Smrg snprintf(format, 20, "ARGB8888"); 52706f2543Smrg break; 53706f2543Smrg case PICT_x8r8g8b8: 54706f2543Smrg snprintf(format, 20, "XRGB8888"); 55706f2543Smrg break; 56706f2543Smrg case PICT_b8g8r8a8: 57706f2543Smrg snprintf(format, 20, "BGRA8888"); 58706f2543Smrg break; 59706f2543Smrg case PICT_b8g8r8x8: 60706f2543Smrg snprintf(format, 20, "BGRX8888"); 61706f2543Smrg break; 62706f2543Smrg case PICT_r5g6b5: 63706f2543Smrg snprintf(format, 20, "RGB565 "); 64706f2543Smrg break; 65706f2543Smrg case PICT_x1r5g5b5: 66706f2543Smrg snprintf(format, 20, "RGB555 "); 67706f2543Smrg break; 68706f2543Smrg case PICT_a8: 69706f2543Smrg snprintf(format, 20, "A8 "); 70706f2543Smrg break; 71706f2543Smrg case PICT_a1: 72706f2543Smrg snprintf(format, 20, "A1 "); 73706f2543Smrg break; 74706f2543Smrg default: 75706f2543Smrg snprintf(format, 20, "0x%x", (int)pict->format); 76706f2543Smrg break; 77706f2543Smrg } 78706f2543Smrg 79706f2543Smrg if (pict->pDrawable) { 80706f2543Smrg loc = exaGetOffscreenPixmap(pict->pDrawable, &temp, &temp) ? 's' : 'm'; 81706f2543Smrg 82706f2543Smrg snprintf(size, 20, "%dx%d%s", pict->pDrawable->width, 83706f2543Smrg pict->pDrawable->height, pict->repeat ? 84706f2543Smrg " R" : ""); 85706f2543Smrg } else { 86706f2543Smrg loc = '-'; 87706f2543Smrg 88706f2543Smrg snprintf(size, 20, "%s", pict->repeat ? " R" : ""); 89706f2543Smrg } 90706f2543Smrg 91706f2543Smrg snprintf(string, n, "%p:%c fmt %s (%s)", pict->pDrawable, loc, format, size); 92706f2543Smrg} 93706f2543Smrg 94706f2543Smrgstatic void 95706f2543SmrgexaPrintCompositeFallback(CARD8 op, 96706f2543Smrg PicturePtr pSrc, 97706f2543Smrg PicturePtr pMask, 98706f2543Smrg PicturePtr pDst) 99706f2543Smrg{ 100706f2543Smrg char sop[20]; 101706f2543Smrg char srcdesc[40], maskdesc[40], dstdesc[40]; 102706f2543Smrg 103706f2543Smrg switch(op) 104706f2543Smrg { 105706f2543Smrg case PictOpSrc: 106706f2543Smrg sprintf(sop, "Src"); 107706f2543Smrg break; 108706f2543Smrg case PictOpOver: 109706f2543Smrg sprintf(sop, "Over"); 110706f2543Smrg break; 111706f2543Smrg default: 112706f2543Smrg sprintf(sop, "0x%x", (int)op); 113706f2543Smrg break; 114706f2543Smrg } 115706f2543Smrg 116706f2543Smrg exaCompositeFallbackPictDesc(pSrc, srcdesc, 40); 117706f2543Smrg exaCompositeFallbackPictDesc(pMask, maskdesc, 40); 118706f2543Smrg exaCompositeFallbackPictDesc(pDst, dstdesc, 40); 119706f2543Smrg 120706f2543Smrg ErrorF("Composite fallback: op %s, \n" 121706f2543Smrg " src %s, \n" 122706f2543Smrg " mask %s, \n" 123706f2543Smrg " dst %s, \n", 124706f2543Smrg sop, srcdesc, maskdesc, dstdesc); 125706f2543Smrg} 126706f2543Smrg#endif /* DEBUG_TRACE_FALL */ 127706f2543Smrg 128706f2543SmrgBool 129706f2543SmrgexaOpReadsDestination (CARD8 op) 130706f2543Smrg{ 131706f2543Smrg /* FALSE (does not read destination) is the list of ops in the protocol 132706f2543Smrg * document with "0" in the "Fb" column and no "Ab" in the "Fa" column. 133706f2543Smrg * That's just Clear and Src. ReduceCompositeOp() will already have 134706f2543Smrg * converted con/disjoint clear/src to Clear or Src. 135706f2543Smrg */ 136706f2543Smrg switch (op) { 137706f2543Smrg case PictOpClear: 138706f2543Smrg case PictOpSrc: 139706f2543Smrg return FALSE; 140706f2543Smrg default: 141706f2543Smrg return TRUE; 142706f2543Smrg } 143706f2543Smrg} 144706f2543Smrg 145706f2543Smrg 146706f2543Smrgstatic Bool 147706f2543SmrgexaGetPixelFromRGBA(CARD32 *pixel, 148706f2543Smrg CARD16 red, 149706f2543Smrg CARD16 green, 150706f2543Smrg CARD16 blue, 151706f2543Smrg CARD16 alpha, 152706f2543Smrg PictFormatPtr pFormat) 153706f2543Smrg{ 154706f2543Smrg int rbits, bbits, gbits, abits; 155706f2543Smrg int rshift, bshift, gshift, ashift; 156706f2543Smrg 157706f2543Smrg *pixel = 0; 158706f2543Smrg 159706f2543Smrg if (!PICT_FORMAT_COLOR(pFormat->format) && 160706f2543Smrg PICT_FORMAT_TYPE(pFormat->format) != PICT_TYPE_A) 161706f2543Smrg return FALSE; 162706f2543Smrg 163706f2543Smrg rbits = PICT_FORMAT_R(pFormat->format); 164706f2543Smrg gbits = PICT_FORMAT_G(pFormat->format); 165706f2543Smrg bbits = PICT_FORMAT_B(pFormat->format); 166706f2543Smrg abits = PICT_FORMAT_A(pFormat->format); 167706f2543Smrg 168706f2543Smrg rshift = pFormat->direct.red; 169706f2543Smrg gshift = pFormat->direct.green; 170706f2543Smrg bshift = pFormat->direct.blue; 171706f2543Smrg ashift = pFormat->direct.alpha; 172706f2543Smrg 173706f2543Smrg *pixel |= ( blue >> (16 - bbits)) << bshift; 174706f2543Smrg *pixel |= ( red >> (16 - rbits)) << rshift; 175706f2543Smrg *pixel |= (green >> (16 - gbits)) << gshift; 176706f2543Smrg *pixel |= (alpha >> (16 - abits)) << ashift; 177706f2543Smrg 178706f2543Smrg return TRUE; 179706f2543Smrg} 180706f2543Smrg 181706f2543Smrgstatic Bool 182706f2543SmrgexaGetRGBAFromPixel(CARD32 pixel, 183706f2543Smrg CARD16 *red, 184706f2543Smrg CARD16 *green, 185706f2543Smrg CARD16 *blue, 186706f2543Smrg CARD16 *alpha, 187706f2543Smrg PictFormatPtr pFormat, 188706f2543Smrg PictFormatShort format) 189706f2543Smrg{ 190706f2543Smrg int rbits, bbits, gbits, abits; 191706f2543Smrg int rshift, bshift, gshift, ashift; 192706f2543Smrg 193706f2543Smrg if (!PICT_FORMAT_COLOR(format) && PICT_FORMAT_TYPE(format) != PICT_TYPE_A) 194706f2543Smrg return FALSE; 195706f2543Smrg 196706f2543Smrg rbits = PICT_FORMAT_R(format); 197706f2543Smrg gbits = PICT_FORMAT_G(format); 198706f2543Smrg bbits = PICT_FORMAT_B(format); 199706f2543Smrg abits = PICT_FORMAT_A(format); 200706f2543Smrg 201706f2543Smrg if (pFormat) { 202706f2543Smrg rshift = pFormat->direct.red; 203706f2543Smrg gshift = pFormat->direct.green; 204706f2543Smrg bshift = pFormat->direct.blue; 205706f2543Smrg ashift = pFormat->direct.alpha; 206706f2543Smrg } else if (format == PICT_a8r8g8b8) { 207706f2543Smrg rshift = 16; 208706f2543Smrg gshift = 8; 209706f2543Smrg bshift = 0; 210706f2543Smrg ashift = 24; 211706f2543Smrg } else 212706f2543Smrg FatalError("EXA bug: exaGetRGBAFromPixel() doesn't match " 213706f2543Smrg "createSourcePicture()\n"); 214706f2543Smrg 215706f2543Smrg if (rbits) { 216706f2543Smrg *red = ((pixel >> rshift ) & ((1 << rbits) - 1)) << (16 - rbits); 217706f2543Smrg while (rbits < 16) { 218706f2543Smrg *red |= *red >> rbits; 219706f2543Smrg rbits <<= 1; 220706f2543Smrg } 221706f2543Smrg 222706f2543Smrg *green = ((pixel >> gshift ) & ((1 << gbits) - 1)) << (16 - gbits); 223706f2543Smrg while (gbits < 16) { 224706f2543Smrg *green |= *green >> gbits; 225706f2543Smrg gbits <<= 1; 226706f2543Smrg } 227706f2543Smrg 228706f2543Smrg *blue = ((pixel >> bshift ) & ((1 << bbits) - 1)) << (16 - bbits); 229706f2543Smrg while (bbits < 16) { 230706f2543Smrg *blue |= *blue >> bbits; 231706f2543Smrg bbits <<= 1; 232706f2543Smrg } 233706f2543Smrg } else { 234706f2543Smrg *red = 0x0000; 235706f2543Smrg *green = 0x0000; 236706f2543Smrg *blue = 0x0000; 237706f2543Smrg } 238706f2543Smrg 239706f2543Smrg if (abits) { 240706f2543Smrg *alpha = ((pixel >> ashift ) & ((1 << abits) - 1)) << (16 - abits); 241706f2543Smrg while (abits < 16) { 242706f2543Smrg *alpha |= *alpha >> abits; 243706f2543Smrg abits <<= 1; 244706f2543Smrg } 245706f2543Smrg } else 246706f2543Smrg *alpha = 0xffff; 247706f2543Smrg 248706f2543Smrg return TRUE; 249706f2543Smrg} 250706f2543Smrg 251706f2543Smrgstatic int 252706f2543SmrgexaTryDriverSolidFill(PicturePtr pSrc, 253706f2543Smrg PicturePtr pDst, 254706f2543Smrg INT16 xSrc, 255706f2543Smrg INT16 ySrc, 256706f2543Smrg INT16 xDst, 257706f2543Smrg INT16 yDst, 258706f2543Smrg CARD16 width, 259706f2543Smrg CARD16 height) 260706f2543Smrg{ 261706f2543Smrg ExaScreenPriv (pDst->pDrawable->pScreen); 262706f2543Smrg RegionRec region; 263706f2543Smrg BoxPtr pbox; 264706f2543Smrg int nbox; 265706f2543Smrg int dst_off_x, dst_off_y; 266706f2543Smrg PixmapPtr pSrcPix, pDstPix; 267706f2543Smrg ExaPixmapPrivPtr pDstExaPix; 268706f2543Smrg CARD32 pixel; 269706f2543Smrg CARD16 red, green, blue, alpha; 270706f2543Smrg 271706f2543Smrg pDstPix = exaGetDrawablePixmap (pDst->pDrawable); 272706f2543Smrg pDstExaPix = ExaGetPixmapPriv(pDstPix); 273706f2543Smrg 274706f2543Smrg /* Check whether the accelerator can use the destination pixmap. 275706f2543Smrg */ 276706f2543Smrg if (pDstExaPix->accel_blocked) 277706f2543Smrg { 278706f2543Smrg return -1; 279706f2543Smrg } 280706f2543Smrg 281706f2543Smrg xDst += pDst->pDrawable->x; 282706f2543Smrg yDst += pDst->pDrawable->y; 283706f2543Smrg if (pSrc->pDrawable) { 284706f2543Smrg xSrc += pSrc->pDrawable->x; 285706f2543Smrg ySrc += pSrc->pDrawable->y; 286706f2543Smrg } 287706f2543Smrg 288706f2543Smrg if (!miComputeCompositeRegion (®ion, pSrc, NULL, pDst, 289706f2543Smrg xSrc, ySrc, 0, 0, xDst, yDst, 290706f2543Smrg width, height)) 291706f2543Smrg return 1; 292706f2543Smrg 293706f2543Smrg exaGetDrawableDeltas (pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y); 294706f2543Smrg 295706f2543Smrg RegionTranslate(®ion, dst_off_x, dst_off_y); 296706f2543Smrg 297706f2543Smrg if (pSrc->pDrawable) { 298706f2543Smrg pSrcPix = exaGetDrawablePixmap (pSrc->pDrawable); 299706f2543Smrg pixel = exaGetPixmapFirstPixel (pSrcPix); 300706f2543Smrg } else 301706f2543Smrg pixel = pSrc->pSourcePict->solidFill.color; 302706f2543Smrg 303706f2543Smrg if (!exaGetRGBAFromPixel(pixel, &red, &green, &blue, &alpha, 304706f2543Smrg pSrc->pFormat, pSrc->format) || 305706f2543Smrg !exaGetPixelFromRGBA(&pixel, red, green, blue, alpha, 306706f2543Smrg pDst->pFormat)) 307706f2543Smrg { 308706f2543Smrg RegionUninit(®ion); 309706f2543Smrg return -1; 310706f2543Smrg } 311706f2543Smrg 312706f2543Smrg if (pExaScr->do_migration) { 313706f2543Smrg ExaMigrationRec pixmaps[1]; 314706f2543Smrg 315706f2543Smrg pixmaps[0].as_dst = TRUE; 316706f2543Smrg pixmaps[0].as_src = FALSE; 317706f2543Smrg pixmaps[0].pPix = pDstPix; 318706f2543Smrg pixmaps[0].pReg = ®ion; 319706f2543Smrg exaDoMigration(pixmaps, 1, TRUE); 320706f2543Smrg } 321706f2543Smrg 322706f2543Smrg if (!exaPixmapHasGpuCopy(pDstPix)) { 323706f2543Smrg RegionUninit(®ion); 324706f2543Smrg return 0; 325706f2543Smrg } 326706f2543Smrg 327706f2543Smrg if (!(*pExaScr->info->PrepareSolid) (pDstPix, GXcopy, 0xffffffff, pixel)) 328706f2543Smrg { 329706f2543Smrg RegionUninit(®ion); 330706f2543Smrg return -1; 331706f2543Smrg } 332706f2543Smrg 333706f2543Smrg nbox = RegionNumRects(®ion); 334706f2543Smrg pbox = RegionRects(®ion); 335706f2543Smrg 336706f2543Smrg while (nbox--) 337706f2543Smrg { 338706f2543Smrg (*pExaScr->info->Solid) (pDstPix, pbox->x1, pbox->y1, pbox->x2, pbox->y2); 339706f2543Smrg pbox++; 340706f2543Smrg } 341706f2543Smrg 342706f2543Smrg (*pExaScr->info->DoneSolid) (pDstPix); 343706f2543Smrg exaMarkSync(pDst->pDrawable->pScreen); 344706f2543Smrg 345706f2543Smrg RegionUninit(®ion); 346706f2543Smrg return 1; 347706f2543Smrg} 348706f2543Smrg 349706f2543Smrgstatic int 350706f2543SmrgexaTryDriverCompositeRects(CARD8 op, 351706f2543Smrg PicturePtr pSrc, 352706f2543Smrg PicturePtr pMask, 353706f2543Smrg PicturePtr pDst, 354706f2543Smrg int nrect, 355706f2543Smrg ExaCompositeRectPtr rects) 356706f2543Smrg{ 357706f2543Smrg ExaScreenPriv (pDst->pDrawable->pScreen); 358706f2543Smrg int src_off_x = 0, src_off_y = 0, mask_off_x = 0, mask_off_y = 0; 359706f2543Smrg int dst_off_x, dst_off_y; 360706f2543Smrg PixmapPtr pSrcPix = NULL, pMaskPix = NULL, pDstPix; 361706f2543Smrg ExaPixmapPrivPtr pSrcExaPix = NULL, pMaskExaPix = NULL, pDstExaPix; 362706f2543Smrg 363706f2543Smrg if (!pExaScr->info->PrepareComposite) 364706f2543Smrg return -1; 365706f2543Smrg 366706f2543Smrg if (pSrc->pDrawable) { 367706f2543Smrg pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable); 368706f2543Smrg pSrcExaPix = ExaGetPixmapPriv(pSrcPix); 369706f2543Smrg } 370706f2543Smrg 371706f2543Smrg if (pMask && pMask->pDrawable) { 372706f2543Smrg pMaskPix = exaGetDrawablePixmap(pMask->pDrawable); 373706f2543Smrg pMaskExaPix = ExaGetPixmapPriv(pMaskPix); 374706f2543Smrg } 375706f2543Smrg 376706f2543Smrg pDstPix = exaGetDrawablePixmap(pDst->pDrawable); 377706f2543Smrg pDstExaPix = ExaGetPixmapPriv(pDstPix); 378706f2543Smrg 379706f2543Smrg /* Check whether the accelerator can use these pixmaps. 380706f2543Smrg * FIXME: If it cannot, use temporary pixmaps so that the drawing 381706f2543Smrg * happens within limits. 382706f2543Smrg */ 383706f2543Smrg if (pDstExaPix->accel_blocked || 384706f2543Smrg (pSrcExaPix && pSrcExaPix->accel_blocked) || 385706f2543Smrg (pMaskExaPix && pMaskExaPix->accel_blocked)) 386706f2543Smrg { 387706f2543Smrg return -1; 388706f2543Smrg } 389706f2543Smrg 390706f2543Smrg if (pExaScr->info->CheckComposite && 391706f2543Smrg !(*pExaScr->info->CheckComposite) (op, pSrc, pMask, pDst)) 392706f2543Smrg { 393706f2543Smrg return -1; 394706f2543Smrg } 395706f2543Smrg 396706f2543Smrg if (pExaScr->do_migration) { 397706f2543Smrg ExaMigrationRec pixmaps[3]; 398706f2543Smrg int i = 0; 399706f2543Smrg 400706f2543Smrg pixmaps[i].as_dst = TRUE; 401706f2543Smrg pixmaps[i].as_src = exaOpReadsDestination(op); 402706f2543Smrg pixmaps[i].pPix = pDstPix; 403706f2543Smrg pixmaps[i].pReg = NULL; 404706f2543Smrg i++; 405706f2543Smrg 406706f2543Smrg if (pSrcPix) { 407706f2543Smrg pixmaps[i].as_dst = FALSE; 408706f2543Smrg pixmaps[i].as_src = TRUE; 409706f2543Smrg pixmaps[i].pPix = pSrcPix; 410706f2543Smrg pixmaps[i].pReg = NULL; 411706f2543Smrg i++; 412706f2543Smrg } 413706f2543Smrg 414706f2543Smrg if (pMaskPix) { 415706f2543Smrg pixmaps[i].as_dst = FALSE; 416706f2543Smrg pixmaps[i].as_src = TRUE; 417706f2543Smrg pixmaps[i].pPix = pMaskPix; 418706f2543Smrg pixmaps[i].pReg = NULL; 419706f2543Smrg i++; 420706f2543Smrg } 421706f2543Smrg 422706f2543Smrg exaDoMigration(pixmaps, i, TRUE); 423706f2543Smrg } 424706f2543Smrg 425706f2543Smrg pDstPix = exaGetOffscreenPixmap (pDst->pDrawable, &dst_off_x, &dst_off_y); 426706f2543Smrg if (!pDstPix) 427706f2543Smrg return 0; 428706f2543Smrg 429706f2543Smrg if (pSrcPix) { 430706f2543Smrg pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y); 431706f2543Smrg if (!pSrcPix) 432706f2543Smrg return 0; 433706f2543Smrg } 434706f2543Smrg 435706f2543Smrg if (pMaskPix) { 436706f2543Smrg pMaskPix = exaGetOffscreenPixmap (pMask->pDrawable, &mask_off_x, &mask_off_y); 437706f2543Smrg if (!pMaskPix) 438706f2543Smrg return 0; 439706f2543Smrg } 440706f2543Smrg 441706f2543Smrg if (!(*pExaScr->info->PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix, 442706f2543Smrg pMaskPix, pDstPix)) 443706f2543Smrg return -1; 444706f2543Smrg 445706f2543Smrg while (nrect--) 446706f2543Smrg { 447706f2543Smrg INT16 xDst = rects->xDst + pDst->pDrawable->x; 448706f2543Smrg INT16 yDst = rects->yDst + pDst->pDrawable->y; 449706f2543Smrg INT16 xMask = rects->xMask; 450706f2543Smrg INT16 yMask = rects->yMask; 451706f2543Smrg INT16 xSrc = rects->xSrc; 452706f2543Smrg INT16 ySrc = rects->ySrc; 453706f2543Smrg RegionRec region; 454706f2543Smrg BoxPtr pbox; 455706f2543Smrg int nbox; 456706f2543Smrg 457706f2543Smrg if (pMaskPix) { 458706f2543Smrg xMask += pMask->pDrawable->x; 459706f2543Smrg yMask += pMask->pDrawable->y; 460706f2543Smrg } 461706f2543Smrg 462706f2543Smrg if (pSrcPix) { 463706f2543Smrg xSrc += pSrc->pDrawable->x; 464706f2543Smrg ySrc += pSrc->pDrawable->y; 465706f2543Smrg } 466706f2543Smrg 467706f2543Smrg if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, 468706f2543Smrg xSrc, ySrc, xMask, yMask, xDst, yDst, 469706f2543Smrg rects->width, rects->height)) 470706f2543Smrg goto next_rect; 471706f2543Smrg 472706f2543Smrg RegionTranslate(®ion, dst_off_x, dst_off_y); 473706f2543Smrg 474706f2543Smrg nbox = RegionNumRects(®ion); 475706f2543Smrg pbox = RegionRects(®ion); 476706f2543Smrg 477706f2543Smrg xMask = xMask + mask_off_x - xDst - dst_off_x; 478706f2543Smrg yMask = yMask + mask_off_y - yDst - dst_off_y; 479706f2543Smrg xSrc = xSrc + src_off_x - xDst - dst_off_x; 480706f2543Smrg ySrc = ySrc + src_off_y - yDst - dst_off_y; 481706f2543Smrg 482706f2543Smrg while (nbox--) 483706f2543Smrg { 484706f2543Smrg (*pExaScr->info->Composite) (pDstPix, 485706f2543Smrg pbox->x1 + xSrc, 486706f2543Smrg pbox->y1 + ySrc, 487706f2543Smrg pbox->x1 + xMask, 488706f2543Smrg pbox->y1 + yMask, 489706f2543Smrg pbox->x1, 490706f2543Smrg pbox->y1, 491706f2543Smrg pbox->x2 - pbox->x1, 492706f2543Smrg pbox->y2 - pbox->y1); 493706f2543Smrg pbox++; 494706f2543Smrg } 495706f2543Smrg 496706f2543Smrg next_rect: 497706f2543Smrg RegionUninit(®ion); 498706f2543Smrg 499706f2543Smrg rects++; 500706f2543Smrg } 501706f2543Smrg 502706f2543Smrg (*pExaScr->info->DoneComposite) (pDstPix); 503706f2543Smrg exaMarkSync(pDst->pDrawable->pScreen); 504706f2543Smrg 505706f2543Smrg return 1; 506706f2543Smrg} 507706f2543Smrg 508706f2543Smrg/** 509706f2543Smrg * Copy a number of rectangles from source to destination in a single 510706f2543Smrg * operation. This is specialized for glyph rendering: we don't have the 511706f2543Smrg * special-case fallbacks found in exaComposite() - if the driver can support 512706f2543Smrg * it, we use the driver functionality, otherwise we fall back straight to 513706f2543Smrg * software. 514706f2543Smrg */ 515706f2543Smrgvoid 516706f2543SmrgexaCompositeRects(CARD8 op, 517706f2543Smrg PicturePtr pSrc, 518706f2543Smrg PicturePtr pMask, 519706f2543Smrg PicturePtr pDst, 520706f2543Smrg int nrect, 521706f2543Smrg ExaCompositeRectPtr rects) 522706f2543Smrg{ 523706f2543Smrg ExaScreenPriv (pDst->pDrawable->pScreen); 524706f2543Smrg int n; 525706f2543Smrg ExaCompositeRectPtr r; 526706f2543Smrg int ret; 527706f2543Smrg 528706f2543Smrg /* If we get a mask, that means we're rendering to the exaGlyphs 529706f2543Smrg * destination directly, so the damage layer takes care of this. 530706f2543Smrg */ 531706f2543Smrg if (!pMask) { 532706f2543Smrg RegionRec region; 533706f2543Smrg int x1 = MAXSHORT; 534706f2543Smrg int y1 = MAXSHORT; 535706f2543Smrg int x2 = MINSHORT; 536706f2543Smrg int y2 = MINSHORT; 537706f2543Smrg BoxRec box; 538706f2543Smrg 539706f2543Smrg /* We have to manage the damage ourselves, since CompositeRects isn't 540706f2543Smrg * something in the screen that can be managed by the damage extension, 541706f2543Smrg * and EXA depends on damage to track what needs to be migrated between 542706f2543Smrg * the gpu and the cpu. 543706f2543Smrg */ 544706f2543Smrg 545706f2543Smrg /* Compute the overall extents of the composited region - we're making 546706f2543Smrg * the assumption here that we are compositing a bunch of glyphs that 547706f2543Smrg * cluster closely together and damaging each glyph individually would 548706f2543Smrg * be a loss compared to damaging the bounding box. 549706f2543Smrg */ 550706f2543Smrg n = nrect; 551706f2543Smrg r = rects; 552706f2543Smrg while (n--) { 553706f2543Smrg int rect_x2 = r->xDst + r->width; 554706f2543Smrg int rect_y2 = r->yDst + r->height; 555706f2543Smrg 556706f2543Smrg if (r->xDst < x1) x1 = r->xDst; 557706f2543Smrg if (r->yDst < y1) y1 = r->yDst; 558706f2543Smrg if (rect_x2 > x2) x2 = rect_x2; 559706f2543Smrg if (rect_y2 > y2) y2 = rect_y2; 560706f2543Smrg 561706f2543Smrg r++; 562706f2543Smrg } 563706f2543Smrg 564706f2543Smrg if (x2 <= x1 || y2 <= y1) 565706f2543Smrg return; 566706f2543Smrg 567706f2543Smrg box.x1 = x1; 568706f2543Smrg box.x2 = x2 < MAXSHORT ? x2 : MAXSHORT; 569706f2543Smrg box.y1 = y1; 570706f2543Smrg box.y2 = y2 < MAXSHORT ? y2 : MAXSHORT; 571706f2543Smrg 572706f2543Smrg /* The pixmap migration code relies on pendingDamage indicating 573706f2543Smrg * the bounds of the current rendering, so we need to force 574706f2543Smrg * the actual damage into that region before we do anything, and 575706f2543Smrg * (see use of DamagePendingRegion in exaCopyDirty) 576706f2543Smrg */ 577706f2543Smrg 578706f2543Smrg RegionInit(®ion, &box, 1); 579706f2543Smrg 580706f2543Smrg DamageRegionAppend(pDst->pDrawable, ®ion); 581706f2543Smrg 582706f2543Smrg RegionUninit(®ion); 583706f2543Smrg } 584706f2543Smrg 585706f2543Smrg /************************************************************/ 586706f2543Smrg 587706f2543Smrg ValidatePicture (pSrc); 588706f2543Smrg if (pMask) 589706f2543Smrg ValidatePicture (pMask); 590706f2543Smrg ValidatePicture (pDst); 591706f2543Smrg 592706f2543Smrg ret = exaTryDriverCompositeRects(op, pSrc, pMask, pDst, nrect, rects); 593706f2543Smrg 594706f2543Smrg if (ret != 1) { 595706f2543Smrg if (ret == -1 && op == PictOpOver && pMask && pMask->componentAlpha && 596706f2543Smrg (!pExaScr->info->CheckComposite || 597706f2543Smrg ((*pExaScr->info->CheckComposite)(PictOpOutReverse, pSrc, pMask, 598706f2543Smrg pDst) && 599706f2543Smrg (*pExaScr->info->CheckComposite)(PictOpAdd, pSrc, pMask, pDst)))) { 600706f2543Smrg ret = exaTryDriverCompositeRects(PictOpOutReverse, pSrc, pMask, 601706f2543Smrg pDst, nrect, rects); 602706f2543Smrg if (ret == 1) { 603706f2543Smrg op = PictOpAdd; 604706f2543Smrg ret = exaTryDriverCompositeRects(op, pSrc, pMask, pDst, nrect, 605706f2543Smrg rects); 606706f2543Smrg } 607706f2543Smrg } 608706f2543Smrg 609706f2543Smrg if (ret != 1) { 610706f2543Smrg n = nrect; 611706f2543Smrg r = rects; 612706f2543Smrg while (n--) { 613706f2543Smrg ExaCheckComposite (op, pSrc, pMask, pDst, 614706f2543Smrg r->xSrc, r->ySrc, 615706f2543Smrg r->xMask, r->yMask, 616706f2543Smrg r->xDst, r->yDst, 617706f2543Smrg r->width, r->height); 618706f2543Smrg r++; 619706f2543Smrg } 620706f2543Smrg } 621706f2543Smrg } 622706f2543Smrg 623706f2543Smrg /************************************************************/ 624706f2543Smrg 625706f2543Smrg if (!pMask) { 626706f2543Smrg /* Now we have to flush the damage out from pendingDamage => damage 627706f2543Smrg * Calling DamageRegionProcessPending has that effect. 628706f2543Smrg */ 629706f2543Smrg 630706f2543Smrg DamageRegionProcessPending(pDst->pDrawable); 631706f2543Smrg } 632706f2543Smrg} 633706f2543Smrg 634706f2543Smrgstatic int 635706f2543SmrgexaTryDriverComposite(CARD8 op, 636706f2543Smrg PicturePtr pSrc, 637706f2543Smrg PicturePtr pMask, 638706f2543Smrg PicturePtr pDst, 639706f2543Smrg INT16 xSrc, 640706f2543Smrg INT16 ySrc, 641706f2543Smrg INT16 xMask, 642706f2543Smrg INT16 yMask, 643706f2543Smrg INT16 xDst, 644706f2543Smrg INT16 yDst, 645706f2543Smrg CARD16 width, 646706f2543Smrg CARD16 height) 647706f2543Smrg{ 648706f2543Smrg ExaScreenPriv (pDst->pDrawable->pScreen); 649706f2543Smrg RegionRec region; 650706f2543Smrg BoxPtr pbox; 651706f2543Smrg int nbox; 652706f2543Smrg int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y; 653706f2543Smrg PixmapPtr pSrcPix = NULL, pMaskPix = NULL, pDstPix; 654706f2543Smrg ExaPixmapPrivPtr pSrcExaPix = NULL, pMaskExaPix = NULL, pDstExaPix; 655706f2543Smrg 656706f2543Smrg if (pSrc->pDrawable) { 657706f2543Smrg pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable); 658706f2543Smrg pSrcExaPix = ExaGetPixmapPriv(pSrcPix); 659706f2543Smrg } 660706f2543Smrg 661706f2543Smrg pDstPix = exaGetDrawablePixmap(pDst->pDrawable); 662706f2543Smrg pDstExaPix = ExaGetPixmapPriv(pDstPix); 663706f2543Smrg 664706f2543Smrg if (pMask && pMask->pDrawable) { 665706f2543Smrg pMaskPix = exaGetDrawablePixmap(pMask->pDrawable); 666706f2543Smrg pMaskExaPix = ExaGetPixmapPriv(pMaskPix); 667706f2543Smrg } 668706f2543Smrg 669706f2543Smrg /* Check whether the accelerator can use these pixmaps. 670706f2543Smrg * FIXME: If it cannot, use temporary pixmaps so that the drawing 671706f2543Smrg * happens within limits. 672706f2543Smrg */ 673706f2543Smrg if (pDstExaPix->accel_blocked || 674706f2543Smrg (pSrcExaPix && pSrcExaPix->accel_blocked) || 675706f2543Smrg (pMaskExaPix && (pMaskExaPix->accel_blocked))) 676706f2543Smrg { 677706f2543Smrg return -1; 678706f2543Smrg } 679706f2543Smrg 680706f2543Smrg xDst += pDst->pDrawable->x; 681706f2543Smrg yDst += pDst->pDrawable->y; 682706f2543Smrg 683706f2543Smrg if (pMaskPix) { 684706f2543Smrg xMask += pMask->pDrawable->x; 685706f2543Smrg yMask += pMask->pDrawable->y; 686706f2543Smrg } 687706f2543Smrg 688706f2543Smrg if (pSrcPix) { 689706f2543Smrg xSrc += pSrc->pDrawable->x; 690706f2543Smrg ySrc += pSrc->pDrawable->y; 691706f2543Smrg } 692706f2543Smrg 693706f2543Smrg if (pExaScr->info->CheckComposite && 694706f2543Smrg !(*pExaScr->info->CheckComposite) (op, pSrc, pMask, pDst)) 695706f2543Smrg { 696706f2543Smrg return -1; 697706f2543Smrg } 698706f2543Smrg 699706f2543Smrg if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, 700706f2543Smrg xSrc, ySrc, xMask, yMask, xDst, yDst, 701706f2543Smrg width, height)) 702706f2543Smrg return 1; 703706f2543Smrg 704706f2543Smrg exaGetDrawableDeltas (pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y); 705706f2543Smrg 706706f2543Smrg RegionTranslate(®ion, dst_off_x, dst_off_y); 707706f2543Smrg 708706f2543Smrg if (pExaScr->do_migration) { 709706f2543Smrg ExaMigrationRec pixmaps[3]; 710706f2543Smrg int i = 0; 711706f2543Smrg 712706f2543Smrg pixmaps[i].as_dst = TRUE; 713706f2543Smrg pixmaps[i].as_src = exaOpReadsDestination(op); 714706f2543Smrg pixmaps[i].pPix = pDstPix; 715706f2543Smrg pixmaps[i].pReg = pixmaps[0].as_src ? NULL : ®ion; 716706f2543Smrg i++; 717706f2543Smrg 718706f2543Smrg if (pSrcPix) { 719706f2543Smrg pixmaps[i].as_dst = FALSE; 720706f2543Smrg pixmaps[i].as_src = TRUE; 721706f2543Smrg pixmaps[i].pPix = pSrcPix; 722706f2543Smrg pixmaps[i].pReg = NULL; 723706f2543Smrg i++; 724706f2543Smrg } 725706f2543Smrg 726706f2543Smrg if (pMaskPix) { 727706f2543Smrg pixmaps[i].as_dst = FALSE; 728706f2543Smrg pixmaps[i].as_src = TRUE; 729706f2543Smrg pixmaps[i].pPix = pMaskPix; 730706f2543Smrg pixmaps[i].pReg = NULL; 731706f2543Smrg i++; 732706f2543Smrg } 733706f2543Smrg 734706f2543Smrg exaDoMigration(pixmaps, i, TRUE); 735706f2543Smrg } 736706f2543Smrg 737706f2543Smrg if (pSrcPix) { 738706f2543Smrg pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y); 739706f2543Smrg if (!pSrcPix) { 740706f2543Smrg RegionUninit(®ion); 741706f2543Smrg return 0; 742706f2543Smrg } 743706f2543Smrg } 744706f2543Smrg 745706f2543Smrg if (pMaskPix) { 746706f2543Smrg pMaskPix = exaGetOffscreenPixmap (pMask->pDrawable, &mask_off_x, 747706f2543Smrg &mask_off_y); 748706f2543Smrg if (!pMaskPix) { 749706f2543Smrg RegionUninit(®ion); 750706f2543Smrg return 0; 751706f2543Smrg } 752706f2543Smrg } 753706f2543Smrg 754706f2543Smrg if (!exaPixmapHasGpuCopy(pDstPix)) { 755706f2543Smrg RegionUninit(®ion); 756706f2543Smrg return 0; 757706f2543Smrg } 758706f2543Smrg 759706f2543Smrg if (!(*pExaScr->info->PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix, 760706f2543Smrg pMaskPix, pDstPix)) 761706f2543Smrg { 762706f2543Smrg RegionUninit(®ion); 763706f2543Smrg return -1; 764706f2543Smrg } 765706f2543Smrg 766706f2543Smrg nbox = RegionNumRects(®ion); 767706f2543Smrg pbox = RegionRects(®ion); 768706f2543Smrg 769706f2543Smrg xMask = xMask + mask_off_x - xDst - dst_off_x; 770706f2543Smrg yMask = yMask + mask_off_y - yDst - dst_off_y; 771706f2543Smrg 772706f2543Smrg xSrc = xSrc + src_off_x - xDst - dst_off_x; 773706f2543Smrg ySrc = ySrc + src_off_y - yDst - dst_off_y; 774706f2543Smrg 775706f2543Smrg while (nbox--) 776706f2543Smrg { 777706f2543Smrg (*pExaScr->info->Composite) (pDstPix, 778706f2543Smrg pbox->x1 + xSrc, 779706f2543Smrg pbox->y1 + ySrc, 780706f2543Smrg pbox->x1 + xMask, 781706f2543Smrg pbox->y1 + yMask, 782706f2543Smrg pbox->x1, 783706f2543Smrg pbox->y1, 784706f2543Smrg pbox->x2 - pbox->x1, 785706f2543Smrg pbox->y2 - pbox->y1); 786706f2543Smrg pbox++; 787706f2543Smrg } 788706f2543Smrg (*pExaScr->info->DoneComposite) (pDstPix); 789706f2543Smrg exaMarkSync(pDst->pDrawable->pScreen); 790706f2543Smrg 791706f2543Smrg RegionUninit(®ion); 792706f2543Smrg return 1; 793706f2543Smrg} 794706f2543Smrg 795706f2543Smrg/** 796706f2543Smrg * exaTryMagicTwoPassCompositeHelper implements PictOpOver using two passes of 797706f2543Smrg * simpler operations PictOpOutReverse and PictOpAdd. Mainly used for component 798706f2543Smrg * alpha and limited 1-tmu cards. 799706f2543Smrg * 800706f2543Smrg * From http://anholt.livejournal.com/32058.html: 801706f2543Smrg * 802706f2543Smrg * The trouble is that component-alpha rendering requires two different sources 803706f2543Smrg * for blending: one for the source value to the blender, which is the 804706f2543Smrg * per-channel multiplication of source and mask, and one for the source alpha 805706f2543Smrg * for multiplying with the destination channels, which is the multiplication 806706f2543Smrg * of the source channels by the mask alpha. So the equation for Over is: 807706f2543Smrg * 808706f2543Smrg * dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A 809706f2543Smrg * dst.R = src.R * mask.R + (1 - (src.A * mask.R)) * dst.R 810706f2543Smrg * dst.G = src.G * mask.G + (1 - (src.A * mask.G)) * dst.G 811706f2543Smrg * dst.B = src.B * mask.B + (1 - (src.A * mask.B)) * dst.B 812706f2543Smrg * 813706f2543Smrg * But we can do some simpler operations, right? How about PictOpOutReverse, 814706f2543Smrg * which has a source factor of 0 and dest factor of (1 - source alpha). We 815706f2543Smrg * can get the source alpha value (srca.X = src.A * mask.X) out of the texture 816706f2543Smrg * blenders pretty easily. So we can do a component-alpha OutReverse, which 817706f2543Smrg * gets us: 818706f2543Smrg * 819706f2543Smrg * dst.A = 0 + (1 - (src.A * mask.A)) * dst.A 820706f2543Smrg * dst.R = 0 + (1 - (src.A * mask.R)) * dst.R 821706f2543Smrg * dst.G = 0 + (1 - (src.A * mask.G)) * dst.G 822706f2543Smrg * dst.B = 0 + (1 - (src.A * mask.B)) * dst.B 823706f2543Smrg * 824706f2543Smrg * OK. And if an op doesn't use the source alpha value for the destination 825706f2543Smrg * factor, then we can do the channel multiplication in the texture blenders 826706f2543Smrg * to get the source value, and ignore the source alpha that we wouldn't use. 827706f2543Smrg * We've supported this in the Radeon driver for a long time. An example would 828706f2543Smrg * be PictOpAdd, which does: 829706f2543Smrg * 830706f2543Smrg * dst.A = src.A * mask.A + dst.A 831706f2543Smrg * dst.R = src.R * mask.R + dst.R 832706f2543Smrg * dst.G = src.G * mask.G + dst.G 833706f2543Smrg * dst.B = src.B * mask.B + dst.B 834706f2543Smrg * 835706f2543Smrg * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right 836706f2543Smrg * after it, we get: 837706f2543Smrg * 838706f2543Smrg * dst.A = src.A * mask.A + ((1 - (src.A * mask.A)) * dst.A) 839706f2543Smrg * dst.R = src.R * mask.R + ((1 - (src.A * mask.R)) * dst.R) 840706f2543Smrg * dst.G = src.G * mask.G + ((1 - (src.A * mask.G)) * dst.G) 841706f2543Smrg * dst.B = src.B * mask.B + ((1 - (src.A * mask.B)) * dst.B) 842706f2543Smrg */ 843706f2543Smrg 844706f2543Smrgstatic int 845706f2543SmrgexaTryMagicTwoPassCompositeHelper(CARD8 op, 846706f2543Smrg PicturePtr pSrc, 847706f2543Smrg PicturePtr pMask, 848706f2543Smrg PicturePtr pDst, 849706f2543Smrg INT16 xSrc, 850706f2543Smrg INT16 ySrc, 851706f2543Smrg INT16 xMask, 852706f2543Smrg INT16 yMask, 853706f2543Smrg INT16 xDst, 854706f2543Smrg INT16 yDst, 855706f2543Smrg CARD16 width, 856706f2543Smrg CARD16 height) 857706f2543Smrg{ 858706f2543Smrg ExaScreenPriv (pDst->pDrawable->pScreen); 859706f2543Smrg 860706f2543Smrg assert(op == PictOpOver); 861706f2543Smrg 862706f2543Smrg if (pExaScr->info->CheckComposite && 863706f2543Smrg (!(*pExaScr->info->CheckComposite)(PictOpOutReverse, pSrc, pMask, 864706f2543Smrg pDst) || 865706f2543Smrg !(*pExaScr->info->CheckComposite)(PictOpAdd, pSrc, pMask, pDst))) 866706f2543Smrg { 867706f2543Smrg return -1; 868706f2543Smrg } 869706f2543Smrg 870706f2543Smrg /* Now, we think we should be able to accelerate this operation. First, 871706f2543Smrg * composite the destination to be the destination times the source alpha 872706f2543Smrg * factors. 873706f2543Smrg */ 874706f2543Smrg exaComposite(PictOpOutReverse, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, 875706f2543Smrg xDst, yDst, width, height); 876706f2543Smrg 877706f2543Smrg /* Then, add in the source value times the destination alpha factors (1.0). 878706f2543Smrg */ 879706f2543Smrg exaComposite(PictOpAdd, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, 880706f2543Smrg xDst, yDst, width, height); 881706f2543Smrg 882706f2543Smrg return 1; 883706f2543Smrg} 884706f2543Smrg 885706f2543Smrgvoid 886706f2543SmrgexaComposite(CARD8 op, 887706f2543Smrg PicturePtr pSrc, 888706f2543Smrg PicturePtr pMask, 889706f2543Smrg PicturePtr pDst, 890706f2543Smrg INT16 xSrc, 891706f2543Smrg INT16 ySrc, 892706f2543Smrg INT16 xMask, 893706f2543Smrg INT16 yMask, 894706f2543Smrg INT16 xDst, 895706f2543Smrg INT16 yDst, 896706f2543Smrg CARD16 width, 897706f2543Smrg CARD16 height) 898706f2543Smrg{ 899706f2543Smrg ExaScreenPriv (pDst->pDrawable->pScreen); 900706f2543Smrg int ret = -1; 901706f2543Smrg Bool saveSrcRepeat = pSrc->repeat; 902706f2543Smrg Bool saveMaskRepeat = pMask ? pMask->repeat : 0; 903706f2543Smrg RegionRec region; 904706f2543Smrg 905706f2543Smrg if (pExaScr->swappedOut) 906706f2543Smrg goto fallback; 907706f2543Smrg 908706f2543Smrg /* Remove repeat in source if useless */ 909706f2543Smrg if (pSrc->pDrawable && pSrc->repeat && !pSrc->transform && xSrc >= 0 && 910706f2543Smrg (xSrc + width) <= pSrc->pDrawable->width && ySrc >= 0 && 911706f2543Smrg (ySrc + height) <= pSrc->pDrawable->height) 912706f2543Smrg pSrc->repeat = 0; 913706f2543Smrg 914706f2543Smrg if (!pMask && !pSrc->alphaMap && !pDst->alphaMap && 915706f2543Smrg (op == PictOpSrc || (op == PictOpOver && !PICT_FORMAT_A(pSrc->format)))) 916706f2543Smrg { 917706f2543Smrg if (pSrc->pDrawable ? 918706f2543Smrg (pSrc->pDrawable->width == 1 && pSrc->pDrawable->height == 1 && 919706f2543Smrg pSrc->repeat) : 920706f2543Smrg (pSrc->pSourcePict->type == SourcePictTypeSolidFill)) 921706f2543Smrg { 922706f2543Smrg ret = exaTryDriverSolidFill(pSrc, pDst, xSrc, ySrc, xDst, yDst, 923706f2543Smrg width, height); 924706f2543Smrg if (ret == 1) 925706f2543Smrg goto done; 926706f2543Smrg } else if (pSrc->pDrawable && !pSrc->transform && 927706f2543Smrg ((op == PictOpSrc && 928706f2543Smrg (pSrc->format == pDst->format || 929706f2543Smrg (PICT_FORMAT_COLOR(pDst->format) && 930706f2543Smrg PICT_FORMAT_COLOR(pSrc->format) && 931706f2543Smrg pDst->format == PICT_FORMAT(PICT_FORMAT_BPP(pSrc->format), 932706f2543Smrg PICT_FORMAT_TYPE(pSrc->format), 933706f2543Smrg 0, 934706f2543Smrg PICT_FORMAT_R(pSrc->format), 935706f2543Smrg PICT_FORMAT_G(pSrc->format), 936706f2543Smrg PICT_FORMAT_B(pSrc->format))))) || 937706f2543Smrg (op == PictOpOver && pSrc->format == pDst->format && 938706f2543Smrg !PICT_FORMAT_A(pSrc->format)))) 939706f2543Smrg { 940706f2543Smrg if (!pSrc->repeat && xSrc >= 0 && ySrc >= 0 && 941706f2543Smrg (xSrc + width <= pSrc->pDrawable->width) && 942706f2543Smrg (ySrc + height <= pSrc->pDrawable->height)) 943706f2543Smrg { 944706f2543Smrg Bool ret; 945706f2543Smrg xDst += pDst->pDrawable->x; 946706f2543Smrg yDst += pDst->pDrawable->y; 947706f2543Smrg xSrc += pSrc->pDrawable->x; 948706f2543Smrg ySrc += pSrc->pDrawable->y; 949706f2543Smrg 950706f2543Smrg if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, 951706f2543Smrg xSrc, ySrc, xMask, yMask, xDst, 952706f2543Smrg yDst, width, height)) 953706f2543Smrg goto done; 954706f2543Smrg 955706f2543Smrg ret = exaHWCopyNtoN(pSrc->pDrawable, pDst->pDrawable, NULL, 956706f2543Smrg RegionRects(®ion), RegionNumRects(®ion), 957706f2543Smrg xSrc - xDst, ySrc - yDst, FALSE, FALSE); 958706f2543Smrg RegionUninit(®ion); 959706f2543Smrg 960706f2543Smrg /* Reset values to their original values. */ 961706f2543Smrg xDst -= pDst->pDrawable->x; 962706f2543Smrg yDst -= pDst->pDrawable->y; 963706f2543Smrg xSrc -= pSrc->pDrawable->x; 964706f2543Smrg ySrc -= pSrc->pDrawable->y; 965706f2543Smrg 966706f2543Smrg if (!ret) 967706f2543Smrg goto fallback; 968706f2543Smrg 969706f2543Smrg goto done; 970706f2543Smrg } 971706f2543Smrg 972706f2543Smrg if (pSrc->repeat && pSrc->repeatType == RepeatNormal && 973706f2543Smrg pSrc->pDrawable->type == DRAWABLE_PIXMAP) 974706f2543Smrg { 975706f2543Smrg DDXPointRec patOrg; 976706f2543Smrg 977706f2543Smrg /* Let's see if the driver can do the repeat in one go */ 978706f2543Smrg if (pExaScr->info->PrepareComposite && !pSrc->alphaMap && 979706f2543Smrg !pDst->alphaMap) 980706f2543Smrg { 981706f2543Smrg ret = exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc, 982706f2543Smrg ySrc, xMask, yMask, xDst, yDst, 983706f2543Smrg width, height); 984706f2543Smrg if (ret == 1) 985706f2543Smrg goto done; 986706f2543Smrg } 987706f2543Smrg 988706f2543Smrg /* Now see if we can use exaFillRegionTiled() */ 989706f2543Smrg xDst += pDst->pDrawable->x; 990706f2543Smrg yDst += pDst->pDrawable->y; 991706f2543Smrg xSrc += pSrc->pDrawable->x; 992706f2543Smrg ySrc += pSrc->pDrawable->y; 993706f2543Smrg 994706f2543Smrg if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, xSrc, 995706f2543Smrg ySrc, xMask, yMask, xDst, yDst, 996706f2543Smrg width, height)) 997706f2543Smrg goto done; 998706f2543Smrg 999706f2543Smrg /* pattern origin is the point in the destination drawable 1000706f2543Smrg * corresponding to (0,0) in the source */ 1001706f2543Smrg patOrg.x = xDst - xSrc; 1002706f2543Smrg patOrg.y = yDst - ySrc; 1003706f2543Smrg 1004706f2543Smrg ret = exaFillRegionTiled(pDst->pDrawable, ®ion, 1005706f2543Smrg (PixmapPtr)pSrc->pDrawable, 1006706f2543Smrg &patOrg, FB_ALLONES, GXcopy, CT_NONE); 1007706f2543Smrg 1008706f2543Smrg RegionUninit(®ion); 1009706f2543Smrg 1010706f2543Smrg if (ret) 1011706f2543Smrg goto done; 1012706f2543Smrg 1013706f2543Smrg /* Let's be correct and restore the variables to their original state. */ 1014706f2543Smrg xDst -= pDst->pDrawable->x; 1015706f2543Smrg yDst -= pDst->pDrawable->y; 1016706f2543Smrg xSrc -= pSrc->pDrawable->x; 1017706f2543Smrg ySrc -= pSrc->pDrawable->y; 1018706f2543Smrg } 1019706f2543Smrg } 1020706f2543Smrg } 1021706f2543Smrg 1022706f2543Smrg /* Remove repeat in mask if useless */ 1023706f2543Smrg if (pMask && pMask->pDrawable && pMask->repeat && !pMask->transform && 1024706f2543Smrg xMask >= 0 && (xMask + width) <= pMask->pDrawable->width && 1025706f2543Smrg yMask >= 0 && (yMask + height) <= pMask->pDrawable->height) 1026706f2543Smrg pMask->repeat = 0; 1027706f2543Smrg 1028706f2543Smrg if (pExaScr->info->PrepareComposite && 1029706f2543Smrg !pSrc->alphaMap && (!pMask || !pMask->alphaMap) && !pDst->alphaMap) 1030706f2543Smrg { 1031706f2543Smrg Bool isSrcSolid; 1032706f2543Smrg 1033706f2543Smrg ret = exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask, 1034706f2543Smrg yMask, xDst, yDst, width, height); 1035706f2543Smrg if (ret == 1) 1036706f2543Smrg goto done; 1037706f2543Smrg 1038706f2543Smrg /* For generic masks and solid src pictures, mach64 can do Over in two 1039706f2543Smrg * passes, similar to the component-alpha case. 1040706f2543Smrg */ 1041706f2543Smrg isSrcSolid = pSrc->pDrawable ? 1042706f2543Smrg (pSrc->pDrawable->width == 1 && pSrc->pDrawable->height == 1 && 1043706f2543Smrg pSrc->repeat) : 1044706f2543Smrg (pSrc->pSourcePict->type == SourcePictTypeSolidFill); 1045706f2543Smrg 1046706f2543Smrg /* If we couldn't do the Composite in a single pass, and it was a 1047706f2543Smrg * component-alpha Over, see if we can do it in two passes with 1048706f2543Smrg * an OutReverse and then an Add. 1049706f2543Smrg */ 1050706f2543Smrg if (ret == -1 && op == PictOpOver && pMask && 1051706f2543Smrg (pMask->componentAlpha || isSrcSolid)) { 1052706f2543Smrg ret = exaTryMagicTwoPassCompositeHelper(op, pSrc, pMask, pDst, 1053706f2543Smrg xSrc, ySrc, 1054706f2543Smrg xMask, yMask, xDst, yDst, 1055706f2543Smrg width, height); 1056706f2543Smrg if (ret == 1) 1057706f2543Smrg goto done; 1058706f2543Smrg } 1059706f2543Smrg } 1060706f2543Smrg 1061706f2543Smrgfallback: 1062706f2543Smrg#if DEBUG_TRACE_FALL 1063706f2543Smrg exaPrintCompositeFallback (op, pSrc, pMask, pDst); 1064706f2543Smrg#endif 1065706f2543Smrg 1066706f2543Smrg ExaCheckComposite (op, pSrc, pMask, pDst, xSrc, ySrc, 1067706f2543Smrg xMask, yMask, xDst, yDst, width, height); 1068706f2543Smrg 1069706f2543Smrgdone: 1070706f2543Smrg pSrc->repeat = saveSrcRepeat; 1071706f2543Smrg if (pMask) 1072706f2543Smrg pMask->repeat = saveMaskRepeat; 1073706f2543Smrg} 1074706f2543Smrg 1075706f2543Smrg/** 1076706f2543Smrg * Same as miCreateAlphaPicture, except it uses ExaCheckPolyFillRect instead 1077706f2543Smrg * of PolyFillRect to initialize the pixmap after creating it, to prevent 1078706f2543Smrg * the pixmap from being migrated. 1079706f2543Smrg * 1080706f2543Smrg * See the comments about exaTrapezoids and exaTriangles. 1081706f2543Smrg */ 1082706f2543Smrgstatic PicturePtr 1083706f2543SmrgexaCreateAlphaPicture (ScreenPtr pScreen, 1084706f2543Smrg PicturePtr pDst, 1085706f2543Smrg PictFormatPtr pPictFormat, 1086706f2543Smrg CARD16 width, 1087706f2543Smrg CARD16 height) 1088706f2543Smrg{ 1089706f2543Smrg PixmapPtr pPixmap; 1090706f2543Smrg PicturePtr pPicture; 1091706f2543Smrg GCPtr pGC; 1092706f2543Smrg int error; 1093706f2543Smrg xRectangle rect; 1094706f2543Smrg 1095706f2543Smrg if (width > 32767 || height > 32767) 1096706f2543Smrg return 0; 1097706f2543Smrg 1098706f2543Smrg if (!pPictFormat) 1099706f2543Smrg { 1100706f2543Smrg if (pDst->polyEdge == PolyEdgeSharp) 1101706f2543Smrg pPictFormat = PictureMatchFormat (pScreen, 1, PICT_a1); 1102706f2543Smrg else 1103706f2543Smrg pPictFormat = PictureMatchFormat (pScreen, 8, PICT_a8); 1104706f2543Smrg if (!pPictFormat) 1105706f2543Smrg return 0; 1106706f2543Smrg } 1107706f2543Smrg 1108706f2543Smrg pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, 1109706f2543Smrg pPictFormat->depth, 0); 1110706f2543Smrg if (!pPixmap) 1111706f2543Smrg return 0; 1112706f2543Smrg pGC = GetScratchGC (pPixmap->drawable.depth, pScreen); 1113706f2543Smrg if (!pGC) 1114706f2543Smrg { 1115706f2543Smrg (*pScreen->DestroyPixmap) (pPixmap); 1116706f2543Smrg return 0; 1117706f2543Smrg } 1118706f2543Smrg ValidateGC (&pPixmap->drawable, pGC); 1119706f2543Smrg rect.x = 0; 1120706f2543Smrg rect.y = 0; 1121706f2543Smrg rect.width = width; 1122706f2543Smrg rect.height = height; 1123706f2543Smrg ExaCheckPolyFillRect (&pPixmap->drawable, pGC, 1, &rect); 1124706f2543Smrg exaPixmapDirty (pPixmap, 0, 0, width, height); 1125706f2543Smrg FreeScratchGC (pGC); 1126706f2543Smrg pPicture = CreatePicture (0, &pPixmap->drawable, pPictFormat, 1127706f2543Smrg 0, 0, serverClient, &error); 1128706f2543Smrg (*pScreen->DestroyPixmap) (pPixmap); 1129706f2543Smrg return pPicture; 1130706f2543Smrg} 1131706f2543Smrg 1132706f2543Smrg/** 1133706f2543Smrg * exaTrapezoids is essentially a copy of miTrapezoids that uses 1134706f2543Smrg * exaCreateAlphaPicture instead of miCreateAlphaPicture. 1135706f2543Smrg * 1136706f2543Smrg * The problem with miCreateAlphaPicture is that it calls PolyFillRect 1137706f2543Smrg * to initialize the contents after creating the pixmap, which 1138706f2543Smrg * causes the pixmap to be moved in for acceleration. The subsequent 1139706f2543Smrg * call to RasterizeTrapezoid won't be accelerated however, which 1140706f2543Smrg * forces the pixmap to be moved out again. 1141706f2543Smrg * 1142706f2543Smrg * exaCreateAlphaPicture avoids this roundtrip by using ExaCheckPolyFillRect 1143706f2543Smrg * to initialize the contents. 1144706f2543Smrg */ 1145706f2543Smrgvoid 1146706f2543SmrgexaTrapezoids (CARD8 op, PicturePtr pSrc, PicturePtr pDst, 1147706f2543Smrg PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, 1148706f2543Smrg int ntrap, xTrapezoid *traps) 1149706f2543Smrg{ 1150706f2543Smrg ScreenPtr pScreen = pDst->pDrawable->pScreen; 1151706f2543Smrg PictureScreenPtr ps = GetPictureScreen(pScreen); 1152706f2543Smrg BoxRec bounds; 1153706f2543Smrg 1154706f2543Smrg if (maskFormat) { 1155706f2543Smrg PicturePtr pPicture; 1156706f2543Smrg INT16 xDst, yDst; 1157706f2543Smrg INT16 xRel, yRel; 1158706f2543Smrg 1159706f2543Smrg miTrapezoidBounds (ntrap, traps, &bounds); 1160706f2543Smrg 1161706f2543Smrg if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) 1162706f2543Smrg return; 1163706f2543Smrg 1164706f2543Smrg xDst = traps[0].left.p1.x >> 16; 1165706f2543Smrg yDst = traps[0].left.p1.y >> 16; 1166706f2543Smrg 1167706f2543Smrg pPicture = exaCreateAlphaPicture (pScreen, pDst, maskFormat, 1168706f2543Smrg bounds.x2 - bounds.x1, 1169706f2543Smrg bounds.y2 - bounds.y1); 1170706f2543Smrg if (!pPicture) 1171706f2543Smrg return; 1172706f2543Smrg 1173706f2543Smrg exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST); 1174706f2543Smrg for (; ntrap; ntrap--, traps++) 1175706f2543Smrg if (xTrapezoidValid(traps)) 1176706f2543Smrg (*ps->RasterizeTrapezoid) (pPicture, traps, 1177706f2543Smrg -bounds.x1, -bounds.y1); 1178706f2543Smrg exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST); 1179706f2543Smrg 1180706f2543Smrg xRel = bounds.x1 + xSrc - xDst; 1181706f2543Smrg yRel = bounds.y1 + ySrc - yDst; 1182706f2543Smrg CompositePicture (op, pSrc, pPicture, pDst, 1183706f2543Smrg xRel, yRel, 0, 0, bounds.x1, bounds.y1, 1184706f2543Smrg bounds.x2 - bounds.x1, 1185706f2543Smrg bounds.y2 - bounds.y1); 1186706f2543Smrg FreePicture (pPicture, 0); 1187706f2543Smrg } else { 1188706f2543Smrg if (pDst->polyEdge == PolyEdgeSharp) 1189706f2543Smrg maskFormat = PictureMatchFormat (pScreen, 1, PICT_a1); 1190706f2543Smrg else 1191706f2543Smrg maskFormat = PictureMatchFormat (pScreen, 8, PICT_a8); 1192706f2543Smrg for (; ntrap; ntrap--, traps++) 1193706f2543Smrg exaTrapezoids (op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, traps); 1194706f2543Smrg } 1195706f2543Smrg} 1196706f2543Smrg 1197706f2543Smrg/** 1198706f2543Smrg * exaTriangles is essentially a copy of miTriangles that uses 1199706f2543Smrg * exaCreateAlphaPicture instead of miCreateAlphaPicture. 1200706f2543Smrg * 1201706f2543Smrg * The problem with miCreateAlphaPicture is that it calls PolyFillRect 1202706f2543Smrg * to initialize the contents after creating the pixmap, which 1203706f2543Smrg * causes the pixmap to be moved in for acceleration. The subsequent 1204706f2543Smrg * call to AddTriangles won't be accelerated however, which forces the pixmap 1205706f2543Smrg * to be moved out again. 1206706f2543Smrg * 1207706f2543Smrg * exaCreateAlphaPicture avoids this roundtrip by using ExaCheckPolyFillRect 1208706f2543Smrg * to initialize the contents. 1209706f2543Smrg */ 1210706f2543Smrgvoid 1211706f2543SmrgexaTriangles (CARD8 op, PicturePtr pSrc, PicturePtr pDst, 1212706f2543Smrg PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, 1213706f2543Smrg int ntri, xTriangle *tris) 1214706f2543Smrg{ 1215706f2543Smrg ScreenPtr pScreen = pDst->pDrawable->pScreen; 1216706f2543Smrg PictureScreenPtr ps = GetPictureScreen(pScreen); 1217706f2543Smrg BoxRec bounds; 1218706f2543Smrg 1219706f2543Smrg if (maskFormat) { 1220706f2543Smrg PicturePtr pPicture; 1221706f2543Smrg INT16 xDst, yDst; 1222706f2543Smrg INT16 xRel, yRel; 1223706f2543Smrg 1224706f2543Smrg miTriangleBounds (ntri, tris, &bounds); 1225706f2543Smrg 1226706f2543Smrg if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) 1227706f2543Smrg return; 1228706f2543Smrg 1229706f2543Smrg xDst = tris[0].p1.x >> 16; 1230706f2543Smrg yDst = tris[0].p1.y >> 16; 1231706f2543Smrg 1232706f2543Smrg pPicture = exaCreateAlphaPicture (pScreen, pDst, maskFormat, 1233706f2543Smrg bounds.x2 - bounds.x1, 1234706f2543Smrg bounds.y2 - bounds.y1); 1235706f2543Smrg if (!pPicture) 1236706f2543Smrg return; 1237706f2543Smrg 1238706f2543Smrg exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST); 1239706f2543Smrg (*ps->AddTriangles) (pPicture, -bounds.x1, -bounds.y1, ntri, tris); 1240706f2543Smrg exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST); 1241706f2543Smrg 1242706f2543Smrg xRel = bounds.x1 + xSrc - xDst; 1243706f2543Smrg yRel = bounds.y1 + ySrc - yDst; 1244706f2543Smrg CompositePicture (op, pSrc, pPicture, pDst, 1245706f2543Smrg xRel, yRel, 0, 0, bounds.x1, bounds.y1, 1246706f2543Smrg bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); 1247706f2543Smrg FreePicture (pPicture, 0); 1248706f2543Smrg } else { 1249706f2543Smrg if (pDst->polyEdge == PolyEdgeSharp) 1250706f2543Smrg maskFormat = PictureMatchFormat (pScreen, 1, PICT_a1); 1251706f2543Smrg else 1252706f2543Smrg maskFormat = PictureMatchFormat (pScreen, 8, PICT_a8); 1253706f2543Smrg 1254706f2543Smrg for (; ntri; ntri--, tris++) 1255706f2543Smrg exaTriangles (op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, tris); 1256706f2543Smrg } 1257706f2543Smrg} 1258