1 /*
2  * Copyright © 2001 Keith Packard
3  *
4  * Partly based on code that is Copyright © The XFree86 Project Inc.
5  *
6  * Permission to use, copy, modify, distribute, and sell this software and its
7  * documentation for any purpose is hereby granted without fee, provided that
8  * the above copyright notice appear in all copies and that both that
9  * copyright notice and this permission notice appear in supporting
10  * documentation, and that the name of Keith Packard not be used in
11  * advertising or publicity pertaining to distribution of the software without
12  * specific, written prior permission.  Keith Packard makes no
13  * representations about the suitability of this software for any purpose.  It
14  * is provided "as is" without express or implied warranty.
15  *
16  * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18  * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22  * PERFORMANCE OF THIS SOFTWARE.
23  */
24 
25 #ifdef HAVE_DIX_CONFIG_H
26 #include <dix-config.h>
27 #endif
28 
29 #include <stdlib.h>
30 
31 #include "exa_priv.h"
32 
33 #include "mipict.h"
34 
35 #if DEBUG_TRACE_FALL
36 static void
exaCompositeFallbackPictDesc(PicturePtr pict,char * string,int n)37 exaCompositeFallbackPictDesc(PicturePtr pict, char *string, int n)
38 {
39     char format[20];
40     char size[20];
41     char loc;
42     int temp;
43 
44     if (!pict) {
45         snprintf(string, n, "None");
46         return;
47     }
48 
49     switch (pict->format) {
50     case PICT_a8r8g8b8:
51         snprintf(format, 20, "ARGB8888");
52         break;
53     case PICT_x8r8g8b8:
54         snprintf(format, 20, "XRGB8888");
55         break;
56     case PICT_b8g8r8a8:
57         snprintf(format, 20, "BGRA8888");
58         break;
59     case PICT_b8g8r8x8:
60         snprintf(format, 20, "BGRX8888");
61         break;
62     case PICT_r5g6b5:
63         snprintf(format, 20, "RGB565  ");
64         break;
65     case PICT_x1r5g5b5:
66         snprintf(format, 20, "RGB555  ");
67         break;
68     case PICT_a8:
69         snprintf(format, 20, "A8      ");
70         break;
71     case PICT_a1:
72         snprintf(format, 20, "A1      ");
73         break;
74     default:
75         snprintf(format, 20, "0x%x", (int) pict->format);
76         break;
77     }
78 
79     if (pict->pDrawable) {
80         loc = exaGetOffscreenPixmap(pict->pDrawable, &temp, &temp) ? 's' : 'm';
81 
82         snprintf(size, 20, "%dx%d%s", pict->pDrawable->width,
83                  pict->pDrawable->height, pict->repeat ? " R" : "");
84     }
85     else {
86         loc = '-';
87 
88         snprintf(size, 20, "%s", pict->repeat ? " R" : "");
89     }
90 
91     snprintf(string, n, "%p:%c fmt %s (%s)", pict->pDrawable, loc, format,
92              size);
93 }
94 
95 static void
exaPrintCompositeFallback(CARD8 op,PicturePtr pSrc,PicturePtr pMask,PicturePtr pDst)96 exaPrintCompositeFallback(CARD8 op,
97                           PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst)
98 {
99     char sop[20];
100     char srcdesc[40], maskdesc[40], dstdesc[40];
101 
102     switch (op) {
103     case PictOpSrc:
104         snprintf(sop, sizeof(sop), "Src");
105         break;
106     case PictOpOver:
107         snprintf(sop, sizeof(sop), "Over");
108         break;
109     default:
110         snprintf(sop, sizeof(sop), "0x%x", (int) op);
111         break;
112     }
113 
114     exaCompositeFallbackPictDesc(pSrc, srcdesc, 40);
115     exaCompositeFallbackPictDesc(pMask, maskdesc, 40);
116     exaCompositeFallbackPictDesc(pDst, dstdesc, 40);
117 
118     ErrorF("Composite fallback: op %s, \n"
119            "                    src  %s, \n"
120            "                    mask %s, \n"
121            "                    dst  %s, \n", sop, srcdesc, maskdesc, dstdesc);
122 }
123 #endif                          /* DEBUG_TRACE_FALL */
124 
125 Bool
exaOpReadsDestination(CARD8 op)126 exaOpReadsDestination(CARD8 op)
127 {
128     /* FALSE (does not read destination) is the list of ops in the protocol
129      * document with "0" in the "Fb" column and no "Ab" in the "Fa" column.
130      * That's just Clear and Src.  ReduceCompositeOp() will already have
131      * converted con/disjoint clear/src to Clear or Src.
132      */
133     switch (op) {
134     case PictOpClear:
135     case PictOpSrc:
136         return FALSE;
137     default:
138         return TRUE;
139     }
140 }
141 
142 static Bool
exaGetPixelFromRGBA(CARD32 * pixel,CARD16 red,CARD16 green,CARD16 blue,CARD16 alpha,PictFormatPtr pFormat)143 exaGetPixelFromRGBA(CARD32 *pixel,
144                     CARD16 red,
145                     CARD16 green,
146                     CARD16 blue, CARD16 alpha, PictFormatPtr pFormat)
147 {
148     int rbits, bbits, gbits, abits;
149     int rshift, bshift, gshift, ashift;
150 
151     *pixel = 0;
152 
153     if (!PICT_FORMAT_COLOR(pFormat->format) &&
154         PICT_FORMAT_TYPE(pFormat->format) != PICT_TYPE_A)
155         return FALSE;
156 
157     rbits = PICT_FORMAT_R(pFormat->format);
158     gbits = PICT_FORMAT_G(pFormat->format);
159     bbits = PICT_FORMAT_B(pFormat->format);
160     abits = PICT_FORMAT_A(pFormat->format);
161 
162     rshift = pFormat->direct.red;
163     gshift = pFormat->direct.green;
164     bshift = pFormat->direct.blue;
165     ashift = pFormat->direct.alpha;
166 
167     *pixel |= (blue >> (16 - bbits)) << bshift;
168     *pixel |= (red >> (16 - rbits)) << rshift;
169     *pixel |= (green >> (16 - gbits)) << gshift;
170     *pixel |= (alpha >> (16 - abits)) << ashift;
171 
172     return TRUE;
173 }
174 
175 static Bool
exaGetRGBAFromPixel(CARD32 pixel,CARD16 * red,CARD16 * green,CARD16 * blue,CARD16 * alpha,PictFormatPtr pFormat,PictFormatShort format)176 exaGetRGBAFromPixel(CARD32 pixel,
177                     CARD16 *red,
178                     CARD16 *green,
179                     CARD16 *blue,
180                     CARD16 *alpha,
181                     PictFormatPtr pFormat, PictFormatShort format)
182 {
183     int rbits, bbits, gbits, abits;
184     int rshift, bshift, gshift, ashift;
185 
186     if (!PICT_FORMAT_COLOR(format) && PICT_FORMAT_TYPE(format) != PICT_TYPE_A)
187         return FALSE;
188 
189     rbits = PICT_FORMAT_R(format);
190     gbits = PICT_FORMAT_G(format);
191     bbits = PICT_FORMAT_B(format);
192     abits = PICT_FORMAT_A(format);
193 
194     if (pFormat) {
195         rshift = pFormat->direct.red;
196         gshift = pFormat->direct.green;
197         bshift = pFormat->direct.blue;
198         ashift = pFormat->direct.alpha;
199     }
200     else if (format == PICT_a8r8g8b8) {
201         rshift = 16;
202         gshift = 8;
203         bshift = 0;
204         ashift = 24;
205     }
206     else
207         FatalError("EXA bug: exaGetRGBAFromPixel() doesn't match "
208                    "createSourcePicture()\n");
209 
210     if (rbits) {
211         *red = ((pixel >> rshift) & ((1 << rbits) - 1)) << (16 - rbits);
212         while (rbits < 16) {
213             *red |= *red >> rbits;
214             rbits <<= 1;
215         }
216 
217         *green = ((pixel >> gshift) & ((1 << gbits) - 1)) << (16 - gbits);
218         while (gbits < 16) {
219             *green |= *green >> gbits;
220             gbits <<= 1;
221         }
222 
223         *blue = ((pixel >> bshift) & ((1 << bbits) - 1)) << (16 - bbits);
224         while (bbits < 16) {
225             *blue |= *blue >> bbits;
226             bbits <<= 1;
227         }
228     }
229     else {
230         *red = 0x0000;
231         *green = 0x0000;
232         *blue = 0x0000;
233     }
234 
235     if (abits) {
236         *alpha = ((pixel >> ashift) & ((1 << abits) - 1)) << (16 - abits);
237         while (abits < 16) {
238             *alpha |= *alpha >> abits;
239             abits <<= 1;
240         }
241     }
242     else
243         *alpha = 0xffff;
244 
245     return TRUE;
246 }
247 
248 static int
exaTryDriverSolidFill(PicturePtr pSrc,PicturePtr pDst,INT16 xSrc,INT16 ySrc,INT16 xDst,INT16 yDst,CARD16 width,CARD16 height)249 exaTryDriverSolidFill(PicturePtr pSrc,
250                       PicturePtr pDst,
251                       INT16 xSrc,
252                       INT16 ySrc,
253                       INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
254 {
255     ExaScreenPriv(pDst->pDrawable->pScreen);
256     RegionRec region;
257     BoxPtr pbox;
258     int nbox;
259     int dst_off_x, dst_off_y;
260     PixmapPtr pSrcPix, pDstPix;
261     ExaPixmapPrivPtr pDstExaPix;
262     CARD32 pixel;
263     CARD16 red, green, blue, alpha;
264 
265     pDstPix = exaGetDrawablePixmap(pDst->pDrawable);
266     pDstExaPix = ExaGetPixmapPriv(pDstPix);
267 
268     /* Check whether the accelerator can use the destination pixmap.
269      */
270     if (pDstExaPix->accel_blocked) {
271         return -1;
272     }
273 
274     xDst += pDst->pDrawable->x;
275     yDst += pDst->pDrawable->y;
276     if (pSrc->pDrawable) {
277         xSrc += pSrc->pDrawable->x;
278         ySrc += pSrc->pDrawable->y;
279     }
280 
281     if (!miComputeCompositeRegion(&region, pSrc, NULL, pDst,
282                                   xSrc, ySrc, 0, 0, xDst, yDst, width, height))
283         return 1;
284 
285     exaGetDrawableDeltas(pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y);
286 
287     RegionTranslate(&region, dst_off_x, dst_off_y);
288 
289     if (pSrc->pDrawable) {
290         pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable);
291         pixel = exaGetPixmapFirstPixel(pSrcPix);
292     }
293     else
294         miRenderColorToPixel(PictureMatchFormat(pDst->pDrawable->pScreen, 32,
295                                                 pSrc->format),
296                              &pSrc->pSourcePict->solidFill.fullcolor,
297                              &pixel);
298 
299     if (!exaGetRGBAFromPixel(pixel, &red, &green, &blue, &alpha,
300                              pSrc->pFormat, pSrc->format) ||
301         !exaGetPixelFromRGBA(&pixel, red, green, blue, alpha, pDst->pFormat)) {
302         RegionUninit(&region);
303         return -1;
304     }
305 
306     if (pExaScr->do_migration) {
307         ExaMigrationRec pixmaps[1];
308 
309         pixmaps[0].as_dst = TRUE;
310         pixmaps[0].as_src = FALSE;
311         pixmaps[0].pPix = pDstPix;
312         pixmaps[0].pReg = &region;
313         exaDoMigration(pixmaps, 1, TRUE);
314     }
315 
316     if (!exaPixmapHasGpuCopy(pDstPix)) {
317         RegionUninit(&region);
318         return 0;
319     }
320 
321     if (!(*pExaScr->info->PrepareSolid) (pDstPix, GXcopy, 0xffffffff, pixel)) {
322         RegionUninit(&region);
323         return -1;
324     }
325 
326     nbox = RegionNumRects(&region);
327     pbox = RegionRects(&region);
328 
329     while (nbox--) {
330         (*pExaScr->info->Solid) (pDstPix, pbox->x1, pbox->y1, pbox->x2,
331                                  pbox->y2);
332         pbox++;
333     }
334 
335     (*pExaScr->info->DoneSolid) (pDstPix);
336     exaMarkSync(pDst->pDrawable->pScreen);
337 
338     RegionUninit(&region);
339     return 1;
340 }
341 
342 static int
exaTryDriverCompositeRects(CARD8 op,PicturePtr pSrc,PicturePtr pMask,PicturePtr pDst,int nrect,ExaCompositeRectPtr rects)343 exaTryDriverCompositeRects(CARD8 op,
344                            PicturePtr pSrc,
345                            PicturePtr pMask,
346                            PicturePtr pDst,
347                            int nrect, ExaCompositeRectPtr rects)
348 {
349     ExaScreenPriv(pDst->pDrawable->pScreen);
350     int src_off_x = 0, src_off_y = 0, mask_off_x = 0, mask_off_y = 0;
351     int dst_off_x, dst_off_y;
352     PixmapPtr pSrcPix = NULL, pMaskPix = NULL, pDstPix;
353     ExaPixmapPrivPtr pSrcExaPix = NULL, pMaskExaPix = NULL, pDstExaPix;
354 
355     if (!pExaScr->info->PrepareComposite)
356         return -1;
357 
358     if (pSrc->pDrawable) {
359         pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable);
360         pSrcExaPix = ExaGetPixmapPriv(pSrcPix);
361     }
362 
363     if (pMask && pMask->pDrawable) {
364         pMaskPix = exaGetDrawablePixmap(pMask->pDrawable);
365         pMaskExaPix = ExaGetPixmapPriv(pMaskPix);
366     }
367 
368     pDstPix = exaGetDrawablePixmap(pDst->pDrawable);
369     pDstExaPix = ExaGetPixmapPriv(pDstPix);
370 
371     /* Check whether the accelerator can use these pixmaps.
372      * FIXME: If it cannot, use temporary pixmaps so that the drawing
373      * happens within limits.
374      */
375     if (pDstExaPix->accel_blocked ||
376         (pSrcExaPix && pSrcExaPix->accel_blocked) ||
377         (pMaskExaPix && pMaskExaPix->accel_blocked)) {
378         return -1;
379     }
380 
381     if (pExaScr->info->CheckComposite &&
382         !(*pExaScr->info->CheckComposite) (op, pSrc, pMask, pDst)) {
383         return -1;
384     }
385 
386     if (pExaScr->do_migration) {
387         ExaMigrationRec pixmaps[3];
388         int i = 0;
389 
390         pixmaps[i].as_dst = TRUE;
391         pixmaps[i].as_src = exaOpReadsDestination(op);
392         pixmaps[i].pPix = pDstPix;
393         pixmaps[i].pReg = NULL;
394         i++;
395 
396         if (pSrcPix) {
397             pixmaps[i].as_dst = FALSE;
398             pixmaps[i].as_src = TRUE;
399             pixmaps[i].pPix = pSrcPix;
400             pixmaps[i].pReg = NULL;
401             i++;
402         }
403 
404         if (pMaskPix) {
405             pixmaps[i].as_dst = FALSE;
406             pixmaps[i].as_src = TRUE;
407             pixmaps[i].pPix = pMaskPix;
408             pixmaps[i].pReg = NULL;
409             i++;
410         }
411 
412         exaDoMigration(pixmaps, i, TRUE);
413     }
414 
415     pDstPix = exaGetOffscreenPixmap(pDst->pDrawable, &dst_off_x, &dst_off_y);
416     if (!pDstPix)
417         return 0;
418 
419     if (pSrcPix) {
420         pSrcPix =
421             exaGetOffscreenPixmap(pSrc->pDrawable, &src_off_x, &src_off_y);
422         if (!pSrcPix)
423             return 0;
424     }
425 
426     if (pMaskPix) {
427         pMaskPix =
428             exaGetOffscreenPixmap(pMask->pDrawable, &mask_off_x, &mask_off_y);
429         if (!pMaskPix)
430             return 0;
431     }
432 
433     if (!(*pExaScr->info->PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix,
434                                              pMaskPix, pDstPix))
435         return -1;
436 
437     while (nrect--) {
438         INT16 xDst = rects->xDst + pDst->pDrawable->x;
439         INT16 yDst = rects->yDst + pDst->pDrawable->y;
440         INT16 xMask = rects->xMask;
441         INT16 yMask = rects->yMask;
442         INT16 xSrc = rects->xSrc;
443         INT16 ySrc = rects->ySrc;
444         RegionRec region;
445         BoxPtr pbox;
446         int nbox;
447 
448         if (pMaskPix) {
449             xMask += pMask->pDrawable->x;
450             yMask += pMask->pDrawable->y;
451         }
452 
453         if (pSrcPix) {
454             xSrc += pSrc->pDrawable->x;
455             ySrc += pSrc->pDrawable->y;
456         }
457 
458         if (!miComputeCompositeRegion(&region, pSrc, pMask, pDst,
459                                       xSrc, ySrc, xMask, yMask, xDst, yDst,
460                                       rects->width, rects->height))
461             goto next_rect;
462 
463         RegionTranslate(&region, dst_off_x, dst_off_y);
464 
465         nbox = RegionNumRects(&region);
466         pbox = RegionRects(&region);
467 
468         xMask = xMask + mask_off_x - xDst - dst_off_x;
469         yMask = yMask + mask_off_y - yDst - dst_off_y;
470         xSrc = xSrc + src_off_x - xDst - dst_off_x;
471         ySrc = ySrc + src_off_y - yDst - dst_off_y;
472 
473         while (nbox--) {
474             (*pExaScr->info->Composite) (pDstPix,
475                                          pbox->x1 + xSrc,
476                                          pbox->y1 + ySrc,
477                                          pbox->x1 + xMask,
478                                          pbox->y1 + yMask,
479                                          pbox->x1,
480                                          pbox->y1,
481                                          pbox->x2 - pbox->x1,
482                                          pbox->y2 - pbox->y1);
483             pbox++;
484         }
485 
486  next_rect:
487         RegionUninit(&region);
488 
489         rects++;
490     }
491 
492     (*pExaScr->info->DoneComposite) (pDstPix);
493     exaMarkSync(pDst->pDrawable->pScreen);
494 
495     return 1;
496 }
497 
498 /**
499  * Copy a number of rectangles from source to destination in a single
500  * operation. This is specialized for glyph rendering: we don't have the
501  * special-case fallbacks found in exaComposite() - if the driver can support
502  * it, we use the driver functionality, otherwise we fall back straight to
503  * software.
504  */
505 void
exaCompositeRects(CARD8 op,PicturePtr pSrc,PicturePtr pMask,PicturePtr pDst,int nrect,ExaCompositeRectPtr rects)506 exaCompositeRects(CARD8 op,
507                   PicturePtr pSrc,
508                   PicturePtr pMask,
509                   PicturePtr pDst, int nrect, ExaCompositeRectPtr rects)
510 {
511     ExaScreenPriv(pDst->pDrawable->pScreen);
512     int n;
513     ExaCompositeRectPtr r;
514     int ret;
515 
516     /* If we get a mask, that means we're rendering to the exaGlyphs
517      * destination directly, so the damage layer takes care of this.
518      */
519     if (!pMask) {
520         RegionRec region;
521         int x1 = MAXSHORT;
522         int y1 = MAXSHORT;
523         int x2 = MINSHORT;
524         int y2 = MINSHORT;
525         BoxRec box;
526 
527         /* We have to manage the damage ourselves, since CompositeRects isn't
528          * something in the screen that can be managed by the damage extension,
529          * and EXA depends on damage to track what needs to be migrated between
530          * the gpu and the cpu.
531          */
532 
533         /* Compute the overall extents of the composited region - we're making
534          * the assumption here that we are compositing a bunch of glyphs that
535          * cluster closely together and damaging each glyph individually would
536          * be a loss compared to damaging the bounding box.
537          */
538         n = nrect;
539         r = rects;
540         while (n--) {
541             int rect_x2 = r->xDst + r->width;
542             int rect_y2 = r->yDst + r->height;
543 
544             if (r->xDst < x1)
545                 x1 = r->xDst;
546             if (r->yDst < y1)
547                 y1 = r->yDst;
548             if (rect_x2 > x2)
549                 x2 = rect_x2;
550             if (rect_y2 > y2)
551                 y2 = rect_y2;
552 
553             r++;
554         }
555 
556         if (x2 <= x1 || y2 <= y1)
557             return;
558 
559         box.x1 = x1;
560         box.x2 = x2 < MAXSHORT ? x2 : MAXSHORT;
561         box.y1 = y1;
562         box.y2 = y2 < MAXSHORT ? y2 : MAXSHORT;
563 
564         /* The pixmap migration code relies on pendingDamage indicating
565          * the bounds of the current rendering, so we need to force
566          * the actual damage into that region before we do anything, and
567          * (see use of DamagePendingRegion in exaCopyDirty)
568          */
569 
570         RegionInit(&region, &box, 1);
571 
572         DamageRegionAppend(pDst->pDrawable, &region);
573 
574         RegionUninit(&region);
575     }
576 
577     /************************************************************/
578 
579     ValidatePicture(pSrc);
580     if (pMask)
581         ValidatePicture(pMask);
582     ValidatePicture(pDst);
583 
584     ret = exaTryDriverCompositeRects(op, pSrc, pMask, pDst, nrect, rects);
585 
586     if (ret != 1) {
587         if (ret == -1 && op == PictOpOver && pMask && pMask->componentAlpha &&
588             (!pExaScr->info->CheckComposite ||
589              ((*pExaScr->info->CheckComposite) (PictOpOutReverse, pSrc, pMask,
590                                                 pDst) &&
591               (*pExaScr->info->CheckComposite) (PictOpAdd, pSrc, pMask,
592                                                 pDst)))) {
593             ret =
594                 exaTryDriverCompositeRects(PictOpOutReverse, pSrc, pMask, pDst,
595                                            nrect, rects);
596             if (ret == 1) {
597                 op = PictOpAdd;
598                 ret = exaTryDriverCompositeRects(op, pSrc, pMask, pDst, nrect,
599                                                  rects);
600             }
601         }
602 
603         if (ret != 1) {
604             n = nrect;
605             r = rects;
606             while (n--) {
607                 ExaCheckComposite(op, pSrc, pMask, pDst,
608                                   r->xSrc, r->ySrc,
609                                   r->xMask, r->yMask,
610                                   r->xDst, r->yDst, r->width, r->height);
611                 r++;
612             }
613         }
614     }
615 
616     /************************************************************/
617 
618     if (!pMask) {
619         /* Now we have to flush the damage out from pendingDamage => damage
620          * Calling DamageRegionProcessPending has that effect.
621          */
622 
623         DamageRegionProcessPending(pDst->pDrawable);
624     }
625 }
626 
627 static int
exaTryDriverComposite(CARD8 op,PicturePtr pSrc,PicturePtr pMask,PicturePtr pDst,INT16 xSrc,INT16 ySrc,INT16 xMask,INT16 yMask,INT16 xDst,INT16 yDst,CARD16 width,CARD16 height)628 exaTryDriverComposite(CARD8 op,
629                       PicturePtr pSrc,
630                       PicturePtr pMask,
631                       PicturePtr pDst,
632                       INT16 xSrc,
633                       INT16 ySrc,
634                       INT16 xMask,
635                       INT16 yMask,
636                       INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
637 {
638     ExaScreenPriv(pDst->pDrawable->pScreen);
639     RegionRec region;
640     BoxPtr pbox;
641     int nbox;
642     int src_off_x, src_off_y, mask_off_x = 0, mask_off_y = 0, dst_off_x, dst_off_y;
643     PixmapPtr pSrcPix = NULL, pMaskPix = NULL, pDstPix;
644     ExaPixmapPrivPtr pSrcExaPix = NULL, pMaskExaPix = NULL, pDstExaPix;
645 
646     if (pSrc->pDrawable) {
647         pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable);
648         pSrcExaPix = ExaGetPixmapPriv(pSrcPix);
649     }
650 
651     pDstPix = exaGetDrawablePixmap(pDst->pDrawable);
652     pDstExaPix = ExaGetPixmapPriv(pDstPix);
653 
654     if (pMask && pMask->pDrawable) {
655         pMaskPix = exaGetDrawablePixmap(pMask->pDrawable);
656         pMaskExaPix = ExaGetPixmapPriv(pMaskPix);
657     }
658 
659     /* Check whether the accelerator can use these pixmaps.
660      * FIXME: If it cannot, use temporary pixmaps so that the drawing
661      * happens within limits.
662      */
663     if (pDstExaPix->accel_blocked ||
664         (pSrcExaPix && pSrcExaPix->accel_blocked) ||
665         (pMaskExaPix && (pMaskExaPix->accel_blocked))) {
666         return -1;
667     }
668 
669     xDst += pDst->pDrawable->x;
670     yDst += pDst->pDrawable->y;
671 
672     if (pMaskPix) {
673         xMask += pMask->pDrawable->x;
674         yMask += pMask->pDrawable->y;
675     }
676 
677     if (pSrcPix) {
678         xSrc += pSrc->pDrawable->x;
679         ySrc += pSrc->pDrawable->y;
680     }
681 
682     if (pExaScr->info->CheckComposite &&
683         !(*pExaScr->info->CheckComposite) (op, pSrc, pMask, pDst)) {
684         return -1;
685     }
686 
687     if (!miComputeCompositeRegion(&region, pSrc, pMask, pDst,
688                                   xSrc, ySrc, xMask, yMask, xDst, yDst,
689                                   width, height))
690         return 1;
691 
692     exaGetDrawableDeltas(pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y);
693 
694     RegionTranslate(&region, dst_off_x, dst_off_y);
695 
696     if (pExaScr->do_migration) {
697         ExaMigrationRec pixmaps[3];
698         int i = 0;
699 
700         pixmaps[i].as_dst = TRUE;
701         pixmaps[i].as_src = exaOpReadsDestination(op);
702         pixmaps[i].pPix = pDstPix;
703         pixmaps[i].pReg = pixmaps[0].as_src ? NULL : &region;
704         i++;
705 
706         if (pSrcPix) {
707             pixmaps[i].as_dst = FALSE;
708             pixmaps[i].as_src = TRUE;
709             pixmaps[i].pPix = pSrcPix;
710             pixmaps[i].pReg = NULL;
711             i++;
712         }
713 
714         if (pMaskPix) {
715             pixmaps[i].as_dst = FALSE;
716             pixmaps[i].as_src = TRUE;
717             pixmaps[i].pPix = pMaskPix;
718             pixmaps[i].pReg = NULL;
719             i++;
720         }
721 
722         exaDoMigration(pixmaps, i, TRUE);
723     }
724 
725     if (pSrcPix) {
726         pSrcPix =
727             exaGetOffscreenPixmap(pSrc->pDrawable, &src_off_x, &src_off_y);
728         if (!pSrcPix) {
729             RegionUninit(&region);
730             return 0;
731         }
732     }
733 
734     if (pMaskPix) {
735         pMaskPix = exaGetOffscreenPixmap(pMask->pDrawable, &mask_off_x,
736                                          &mask_off_y);
737         if (!pMaskPix) {
738             RegionUninit(&region);
739             return 0;
740         }
741     }
742 
743     if (!exaPixmapHasGpuCopy(pDstPix)) {
744         RegionUninit(&region);
745         return 0;
746     }
747 
748     if (!(*pExaScr->info->PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix,
749                                              pMaskPix, pDstPix)) {
750         RegionUninit(&region);
751         return -1;
752     }
753 
754     nbox = RegionNumRects(&region);
755     pbox = RegionRects(&region);
756 
757     xMask = xMask + mask_off_x - xDst - dst_off_x;
758     yMask = yMask + mask_off_y - yDst - dst_off_y;
759 
760     xSrc = xSrc + src_off_x - xDst - dst_off_x;
761     ySrc = ySrc + src_off_y - yDst - dst_off_y;
762 
763     while (nbox--) {
764         (*pExaScr->info->Composite) (pDstPix,
765                                      pbox->x1 + xSrc,
766                                      pbox->y1 + ySrc,
767                                      pbox->x1 + xMask,
768                                      pbox->y1 + yMask,
769                                      pbox->x1,
770                                      pbox->y1,
771                                      pbox->x2 - pbox->x1, pbox->y2 - pbox->y1);
772         pbox++;
773     }
774     (*pExaScr->info->DoneComposite) (pDstPix);
775     exaMarkSync(pDst->pDrawable->pScreen);
776 
777     RegionUninit(&region);
778     return 1;
779 }
780 
781 /**
782  * exaTryMagicTwoPassCompositeHelper implements PictOpOver using two passes of
783  * simpler operations PictOpOutReverse and PictOpAdd. Mainly used for component
784  * alpha and limited 1-tmu cards.
785  *
786  * From http://anholt.livejournal.com/32058.html:
787  *
788  * The trouble is that component-alpha rendering requires two different sources
789  * for blending: one for the source value to the blender, which is the
790  * per-channel multiplication of source and mask, and one for the source alpha
791  * for multiplying with the destination channels, which is the multiplication
792  * of the source channels by the mask alpha. So the equation for Over is:
793  *
794  * dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A
795  * dst.R = src.R * mask.R + (1 - (src.A * mask.R)) * dst.R
796  * dst.G = src.G * mask.G + (1 - (src.A * mask.G)) * dst.G
797  * dst.B = src.B * mask.B + (1 - (src.A * mask.B)) * dst.B
798  *
799  * But we can do some simpler operations, right? How about PictOpOutReverse,
800  * which has a source factor of 0 and dest factor of (1 - source alpha). We
801  * can get the source alpha value (srca.X = src.A * mask.X) out of the texture
802  * blenders pretty easily. So we can do a component-alpha OutReverse, which
803  * gets us:
804  *
805  * dst.A = 0 + (1 - (src.A * mask.A)) * dst.A
806  * dst.R = 0 + (1 - (src.A * mask.R)) * dst.R
807  * dst.G = 0 + (1 - (src.A * mask.G)) * dst.G
808  * dst.B = 0 + (1 - (src.A * mask.B)) * dst.B
809  *
810  * OK. And if an op doesn't use the source alpha value for the destination
811  * factor, then we can do the channel multiplication in the texture blenders
812  * to get the source value, and ignore the source alpha that we wouldn't use.
813  * We've supported this in the Radeon driver for a long time. An example would
814  * be PictOpAdd, which does:
815  *
816  * dst.A = src.A * mask.A + dst.A
817  * dst.R = src.R * mask.R + dst.R
818  * dst.G = src.G * mask.G + dst.G
819  * dst.B = src.B * mask.B + dst.B
820  *
821  * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right
822  * after it, we get:
823  *
824  * dst.A = src.A * mask.A + ((1 - (src.A * mask.A)) * dst.A)
825  * dst.R = src.R * mask.R + ((1 - (src.A * mask.R)) * dst.R)
826  * dst.G = src.G * mask.G + ((1 - (src.A * mask.G)) * dst.G)
827  * dst.B = src.B * mask.B + ((1 - (src.A * mask.B)) * dst.B)
828  */
829 
830 static int
exaTryMagicTwoPassCompositeHelper(CARD8 op,PicturePtr pSrc,PicturePtr pMask,PicturePtr pDst,INT16 xSrc,INT16 ySrc,INT16 xMask,INT16 yMask,INT16 xDst,INT16 yDst,CARD16 width,CARD16 height)831 exaTryMagicTwoPassCompositeHelper(CARD8 op,
832                                   PicturePtr pSrc,
833                                   PicturePtr pMask,
834                                   PicturePtr pDst,
835                                   INT16 xSrc,
836                                   INT16 ySrc,
837                                   INT16 xMask,
838                                   INT16 yMask,
839                                   INT16 xDst,
840                                   INT16 yDst, CARD16 width, CARD16 height)
841 {
842     ExaScreenPriv(pDst->pDrawable->pScreen);
843 
844     assert(op == PictOpOver);
845 
846     if (pExaScr->info->CheckComposite &&
847         (!(*pExaScr->info->CheckComposite) (PictOpOutReverse, pSrc, pMask,
848                                             pDst) ||
849          !(*pExaScr->info->CheckComposite) (PictOpAdd, pSrc, pMask, pDst))) {
850         return -1;
851     }
852 
853     /* Now, we think we should be able to accelerate this operation. First,
854      * composite the destination to be the destination times the source alpha
855      * factors.
856      */
857     exaComposite(PictOpOutReverse, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask,
858                  xDst, yDst, width, height);
859 
860     /* Then, add in the source value times the destination alpha factors (1.0).
861      */
862     exaComposite(PictOpAdd, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask,
863                  xDst, yDst, width, height);
864 
865     return 1;
866 }
867 
868 void
exaComposite(CARD8 op,PicturePtr pSrc,PicturePtr pMask,PicturePtr pDst,INT16 xSrc,INT16 ySrc,INT16 xMask,INT16 yMask,INT16 xDst,INT16 yDst,CARD16 width,CARD16 height)869 exaComposite(CARD8 op,
870              PicturePtr pSrc,
871              PicturePtr pMask,
872              PicturePtr pDst,
873              INT16 xSrc,
874              INT16 ySrc,
875              INT16 xMask,
876              INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
877 {
878     ExaScreenPriv(pDst->pDrawable->pScreen);
879     int ret = -1;
880     Bool saveSrcRepeat = pSrc->repeat;
881     Bool saveMaskRepeat = pMask ? pMask->repeat : 0;
882     RegionRec region;
883 
884     if (pExaScr->swappedOut)
885         goto fallback;
886 
887     /* Remove repeat in source if useless */
888     if (pSrc->pDrawable && pSrc->repeat && !pSrc->transform && xSrc >= 0 &&
889         (xSrc + width) <= pSrc->pDrawable->width && ySrc >= 0 &&
890         (ySrc + height) <= pSrc->pDrawable->height)
891         pSrc->repeat = 0;
892 
893     if (!pMask && !pSrc->alphaMap && !pDst->alphaMap &&
894         (op == PictOpSrc || (op == PictOpOver && !PICT_FORMAT_A(pSrc->format))))
895     {
896         if (pSrc->pDrawable ?
897             (pSrc->pDrawable->width == 1 && pSrc->pDrawable->height == 1 &&
898              pSrc->repeat) :
899             (pSrc->pSourcePict->type == SourcePictTypeSolidFill)) {
900             ret = exaTryDriverSolidFill(pSrc, pDst, xSrc, ySrc, xDst, yDst,
901                                         width, height);
902             if (ret == 1)
903                 goto done;
904         }
905         else if (pSrc->pDrawable && !pSrc->transform &&
906                  ((op == PictOpSrc &&
907                    (pSrc->format == pDst->format ||
908                     (PICT_FORMAT_COLOR(pDst->format) &&
909                      PICT_FORMAT_COLOR(pSrc->format) &&
910                      pDst->format == PICT_FORMAT(PICT_FORMAT_BPP(pSrc->format),
911                                                  PICT_FORMAT_TYPE(pSrc->format),
912                                                  0,
913                                                  PICT_FORMAT_R(pSrc->format),
914                                                  PICT_FORMAT_G(pSrc->format),
915                                                  PICT_FORMAT_B(pSrc->format)))))
916                   || (op == PictOpOver && pSrc->format == pDst->format &&
917                       !PICT_FORMAT_A(pSrc->format)))) {
918             if (!pSrc->repeat && xSrc >= 0 && ySrc >= 0 &&
919                 (xSrc + width <= pSrc->pDrawable->width) &&
920                 (ySrc + height <= pSrc->pDrawable->height)) {
921                 Bool suc;
922 
923                 xDst += pDst->pDrawable->x;
924                 yDst += pDst->pDrawable->y;
925                 xSrc += pSrc->pDrawable->x;
926                 ySrc += pSrc->pDrawable->y;
927 
928                 if (!miComputeCompositeRegion(&region, pSrc, pMask, pDst,
929                                               xSrc, ySrc, xMask, yMask, xDst,
930                                               yDst, width, height))
931                     goto done;
932 
933                 suc = exaHWCopyNtoN(pSrc->pDrawable, pDst->pDrawable, NULL,
934                                     RegionRects(&region),
935                                     RegionNumRects(&region), xSrc - xDst,
936                                     ySrc - yDst, FALSE, FALSE);
937                 RegionUninit(&region);
938 
939                 /* Reset values to their original values. */
940                 xDst -= pDst->pDrawable->x;
941                 yDst -= pDst->pDrawable->y;
942                 xSrc -= pSrc->pDrawable->x;
943                 ySrc -= pSrc->pDrawable->y;
944 
945                 if (!suc)
946                     goto fallback;
947 
948                 goto done;
949             }
950 
951             if (pSrc->repeat && pSrc->repeatType == RepeatNormal &&
952                 pSrc->pDrawable->type == DRAWABLE_PIXMAP) {
953                 DDXPointRec patOrg;
954 
955                 /* Let's see if the driver can do the repeat in one go */
956                 if (pExaScr->info->PrepareComposite && !pSrc->alphaMap &&
957                     !pDst->alphaMap) {
958                     ret = exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc,
959                                                 ySrc, xMask, yMask, xDst, yDst,
960                                                 width, height);
961                     if (ret == 1)
962                         goto done;
963                 }
964 
965                 /* Now see if we can use exaFillRegionTiled() */
966                 xDst += pDst->pDrawable->x;
967                 yDst += pDst->pDrawable->y;
968                 xSrc += pSrc->pDrawable->x;
969                 ySrc += pSrc->pDrawable->y;
970 
971                 if (!miComputeCompositeRegion(&region, pSrc, pMask, pDst, xSrc,
972                                               ySrc, xMask, yMask, xDst, yDst,
973                                               width, height))
974                     goto done;
975 
976                 /* pattern origin is the point in the destination drawable
977                  * corresponding to (0,0) in the source */
978                 patOrg.x = xDst - xSrc;
979                 patOrg.y = yDst - ySrc;
980 
981                 ret = exaFillRegionTiled(pDst->pDrawable, &region,
982                                          (PixmapPtr) pSrc->pDrawable,
983                                          &patOrg, FB_ALLONES, GXcopy, CT_NONE);
984 
985                 RegionUninit(&region);
986 
987                 if (ret)
988                     goto done;
989 
990                 /* Let's be correct and restore the variables to their original state. */
991                 xDst -= pDst->pDrawable->x;
992                 yDst -= pDst->pDrawable->y;
993                 xSrc -= pSrc->pDrawable->x;
994                 ySrc -= pSrc->pDrawable->y;
995             }
996         }
997     }
998 
999     /* Remove repeat in mask if useless */
1000     if (pMask && pMask->pDrawable && pMask->repeat && !pMask->transform &&
1001         xMask >= 0 && (xMask + width) <= pMask->pDrawable->width &&
1002         yMask >= 0 && (yMask + height) <= pMask->pDrawable->height)
1003         pMask->repeat = 0;
1004 
1005     if (pExaScr->info->PrepareComposite &&
1006         !pSrc->alphaMap && (!pMask || !pMask->alphaMap) && !pDst->alphaMap) {
1007         Bool isSrcSolid;
1008 
1009         ret = exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask,
1010                                     yMask, xDst, yDst, width, height);
1011         if (ret == 1)
1012             goto done;
1013 
1014         /* For generic masks and solid src pictures, mach64 can do Over in two
1015          * passes, similar to the component-alpha case.
1016          */
1017         isSrcSolid = pSrc->pDrawable ?
1018             (pSrc->pDrawable->width == 1 && pSrc->pDrawable->height == 1 &&
1019              pSrc->repeat) :
1020             (pSrc->pSourcePict->type == SourcePictTypeSolidFill);
1021 
1022         /* If we couldn't do the Composite in a single pass, and it was a
1023          * component-alpha Over, see if we can do it in two passes with
1024          * an OutReverse and then an Add.
1025          */
1026         if (ret == -1 && op == PictOpOver && pMask &&
1027             (pMask->componentAlpha || isSrcSolid)) {
1028             ret = exaTryMagicTwoPassCompositeHelper(op, pSrc, pMask, pDst,
1029                                                     xSrc, ySrc,
1030                                                     xMask, yMask, xDst, yDst,
1031                                                     width, height);
1032             if (ret == 1)
1033                 goto done;
1034         }
1035     }
1036 
1037  fallback:
1038 #if DEBUG_TRACE_FALL
1039     exaPrintCompositeFallback(op, pSrc, pMask, pDst);
1040 #endif
1041 
1042     ExaCheckComposite(op, pSrc, pMask, pDst, xSrc, ySrc,
1043                       xMask, yMask, xDst, yDst, width, height);
1044 
1045  done:
1046     pSrc->repeat = saveSrcRepeat;
1047     if (pMask)
1048         pMask->repeat = saveMaskRepeat;
1049 }
1050 
1051 /**
1052  * Same as miCreateAlphaPicture, except it uses ExaCheckPolyFillRect instead
1053  * of PolyFillRect to initialize the pixmap after creating it, to prevent
1054  * the pixmap from being migrated.
1055  *
1056  * See the comments about exaTrapezoids and exaTriangles.
1057  */
1058 static PicturePtr
exaCreateAlphaPicture(ScreenPtr pScreen,PicturePtr pDst,PictFormatPtr pPictFormat,CARD16 width,CARD16 height)1059 exaCreateAlphaPicture(ScreenPtr pScreen,
1060                       PicturePtr pDst,
1061                       PictFormatPtr pPictFormat, CARD16 width, CARD16 height)
1062 {
1063     PixmapPtr pPixmap;
1064     PicturePtr pPicture;
1065     GCPtr pGC;
1066     int error;
1067     xRectangle rect;
1068 
1069     if (width > 32767 || height > 32767)
1070         return 0;
1071 
1072     if (!pPictFormat) {
1073         if (pDst->polyEdge == PolyEdgeSharp)
1074             pPictFormat = PictureMatchFormat(pScreen, 1, PICT_a1);
1075         else
1076             pPictFormat = PictureMatchFormat(pScreen, 8, PICT_a8);
1077         if (!pPictFormat)
1078             return 0;
1079     }
1080 
1081     pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
1082                                         pPictFormat->depth, 0);
1083     if (!pPixmap)
1084         return 0;
1085     pGC = GetScratchGC(pPixmap->drawable.depth, pScreen);
1086     if (!pGC) {
1087         (*pScreen->DestroyPixmap) (pPixmap);
1088         return 0;
1089     }
1090     ValidateGC(&pPixmap->drawable, pGC);
1091     rect.x = 0;
1092     rect.y = 0;
1093     rect.width = width;
1094     rect.height = height;
1095     ExaCheckPolyFillRect(&pPixmap->drawable, pGC, 1, &rect);
1096     exaPixmapDirty(pPixmap, 0, 0, width, height);
1097     FreeScratchGC(pGC);
1098     pPicture = CreatePicture(0, &pPixmap->drawable, pPictFormat,
1099                              0, 0, serverClient, &error);
1100     (*pScreen->DestroyPixmap) (pPixmap);
1101     return pPicture;
1102 }
1103 
1104 /**
1105  * exaTrapezoids is essentially a copy of miTrapezoids that uses
1106  * exaCreateAlphaPicture instead of miCreateAlphaPicture.
1107  *
1108  * The problem with miCreateAlphaPicture is that it calls PolyFillRect
1109  * to initialize the contents after creating the pixmap, which
1110  * causes the pixmap to be moved in for acceleration. The subsequent
1111  * call to RasterizeTrapezoid won't be accelerated however, which
1112  * forces the pixmap to be moved out again.
1113  *
1114  * exaCreateAlphaPicture avoids this roundtrip by using ExaCheckPolyFillRect
1115  * to initialize the contents.
1116  */
1117 void
exaTrapezoids(CARD8 op,PicturePtr pSrc,PicturePtr pDst,PictFormatPtr maskFormat,INT16 xSrc,INT16 ySrc,int ntrap,xTrapezoid * traps)1118 exaTrapezoids(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
1119               PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
1120               int ntrap, xTrapezoid * traps)
1121 {
1122     ScreenPtr pScreen = pDst->pDrawable->pScreen;
1123     PictureScreenPtr ps = GetPictureScreen(pScreen);
1124     BoxRec bounds;
1125 
1126     if (maskFormat) {
1127         PicturePtr pPicture;
1128         INT16 xDst, yDst;
1129         INT16 xRel, yRel;
1130 
1131         miTrapezoidBounds(ntrap, traps, &bounds);
1132 
1133         if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
1134             return;
1135 
1136         xDst = traps[0].left.p1.x >> 16;
1137         yDst = traps[0].left.p1.y >> 16;
1138 
1139         pPicture = exaCreateAlphaPicture(pScreen, pDst, maskFormat,
1140                                          bounds.x2 - bounds.x1,
1141                                          bounds.y2 - bounds.y1);
1142         if (!pPicture)
1143             return;
1144 
1145         exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
1146         for (; ntrap; ntrap--, traps++)
1147             if (xTrapezoidValid(traps))
1148                 (*ps->RasterizeTrapezoid) (pPicture, traps, -bounds.x1, -bounds.y1);
1149         exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
1150 
1151         xRel = bounds.x1 + xSrc - xDst;
1152         yRel = bounds.y1 + ySrc - yDst;
1153         CompositePicture(op, pSrc, pPicture, pDst,
1154                          xRel, yRel, 0, 0, bounds.x1, bounds.y1,
1155                          bounds.x2 - bounds.x1, bounds.y2 - bounds.y1);
1156         FreePicture(pPicture, 0);
1157     }
1158     else {
1159         if (pDst->polyEdge == PolyEdgeSharp)
1160             maskFormat = PictureMatchFormat(pScreen, 1, PICT_a1);
1161         else
1162             maskFormat = PictureMatchFormat(pScreen, 8, PICT_a8);
1163         for (; ntrap; ntrap--, traps++)
1164             exaTrapezoids(op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, traps);
1165     }
1166 }
1167 
1168 /**
1169  * exaTriangles is essentially a copy of miTriangles that uses
1170  * exaCreateAlphaPicture instead of miCreateAlphaPicture.
1171  *
1172  * The problem with miCreateAlphaPicture is that it calls PolyFillRect
1173  * to initialize the contents after creating the pixmap, which
1174  * causes the pixmap to be moved in for acceleration. The subsequent
1175  * call to AddTriangles won't be accelerated however, which forces the pixmap
1176  * to be moved out again.
1177  *
1178  * exaCreateAlphaPicture avoids this roundtrip by using ExaCheckPolyFillRect
1179  * to initialize the contents.
1180  */
1181 void
exaTriangles(CARD8 op,PicturePtr pSrc,PicturePtr pDst,PictFormatPtr maskFormat,INT16 xSrc,INT16 ySrc,int ntri,xTriangle * tris)1182 exaTriangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
1183              PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
1184              int ntri, xTriangle * tris)
1185 {
1186     ScreenPtr pScreen = pDst->pDrawable->pScreen;
1187     PictureScreenPtr ps = GetPictureScreen(pScreen);
1188     BoxRec bounds;
1189 
1190     if (maskFormat) {
1191         PicturePtr pPicture;
1192         INT16 xDst, yDst;
1193         INT16 xRel, yRel;
1194 
1195         miTriangleBounds(ntri, tris, &bounds);
1196 
1197         if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
1198             return;
1199 
1200         xDst = tris[0].p1.x >> 16;
1201         yDst = tris[0].p1.y >> 16;
1202 
1203         pPicture = exaCreateAlphaPicture(pScreen, pDst, maskFormat,
1204                                          bounds.x2 - bounds.x1,
1205                                          bounds.y2 - bounds.y1);
1206         if (!pPicture)
1207             return;
1208 
1209         exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
1210         (*ps->AddTriangles) (pPicture, -bounds.x1, -bounds.y1, ntri, tris);
1211         exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
1212 
1213         xRel = bounds.x1 + xSrc - xDst;
1214         yRel = bounds.y1 + ySrc - yDst;
1215         CompositePicture(op, pSrc, pPicture, pDst,
1216                          xRel, yRel, 0, 0, bounds.x1, bounds.y1,
1217                          bounds.x2 - bounds.x1, bounds.y2 - bounds.y1);
1218         FreePicture(pPicture, 0);
1219     }
1220     else {
1221         if (pDst->polyEdge == PolyEdgeSharp)
1222             maskFormat = PictureMatchFormat(pScreen, 1, PICT_a1);
1223         else
1224             maskFormat = PictureMatchFormat(pScreen, 8, PICT_a8);
1225 
1226         for (; ntri; ntri--, tris++)
1227             exaTriangles(op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, tris);
1228     }
1229 }
1230