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