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