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
36static void
37exaCompositeFallbackPictDesc(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
95static void
96exaPrintCompositeFallback(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
125Bool
126exaOpReadsDestination(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
142static Bool
143exaGetPixelFromRGBA(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
175static Bool
176exaGetRGBAFromPixel(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
248static int
249exaTryDriverSolidFill(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
342static int
343exaTryDriverCompositeRects(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 */
505void
506exaCompositeRects(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
627static int
628exaTryDriverComposite(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
830static int
831exaTryMagicTwoPassCompositeHelper(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
868void
869exaComposite(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 */
1058static PicturePtr
1059exaCreateAlphaPicture(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 */
1117void
1118exaTrapezoids(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 */
1181void
1182exaTriangles(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