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(®ion, 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(®ion, 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(®ion);
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 = ®ion;
313*4882a593Smuzhiyun exaDoMigration(pixmaps, 1, TRUE);
314*4882a593Smuzhiyun }
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun if (!exaPixmapHasGpuCopy(pDstPix)) {
317*4882a593Smuzhiyun RegionUninit(®ion);
318*4882a593Smuzhiyun return 0;
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun if (!(*pExaScr->info->PrepareSolid) (pDstPix, GXcopy, 0xffffffff, pixel)) {
322*4882a593Smuzhiyun RegionUninit(®ion);
323*4882a593Smuzhiyun return -1;
324*4882a593Smuzhiyun }
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun nbox = RegionNumRects(®ion);
327*4882a593Smuzhiyun pbox = RegionRects(®ion);
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(®ion);
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(®ion, 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(®ion, dst_off_x, dst_off_y);
464*4882a593Smuzhiyun
465*4882a593Smuzhiyun nbox = RegionNumRects(®ion);
466*4882a593Smuzhiyun pbox = RegionRects(®ion);
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(®ion);
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(®ion, &box, 1);
571*4882a593Smuzhiyun
572*4882a593Smuzhiyun DamageRegionAppend(pDst->pDrawable, ®ion);
573*4882a593Smuzhiyun
574*4882a593Smuzhiyun RegionUninit(®ion);
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(®ion, 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(®ion, 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 : ®ion;
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(®ion);
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(®ion);
739*4882a593Smuzhiyun return 0;
740*4882a593Smuzhiyun }
741*4882a593Smuzhiyun }
742*4882a593Smuzhiyun
743*4882a593Smuzhiyun if (!exaPixmapHasGpuCopy(pDstPix)) {
744*4882a593Smuzhiyun RegionUninit(®ion);
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(®ion);
751*4882a593Smuzhiyun return -1;
752*4882a593Smuzhiyun }
753*4882a593Smuzhiyun
754*4882a593Smuzhiyun nbox = RegionNumRects(®ion);
755*4882a593Smuzhiyun pbox = RegionRects(®ion);
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(®ion);
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(®ion, 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(®ion),
935*4882a593Smuzhiyun RegionNumRects(®ion), xSrc - xDst,
936*4882a593Smuzhiyun ySrc - yDst, FALSE, FALSE);
937*4882a593Smuzhiyun RegionUninit(®ion);
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(®ion, 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, ®ion,
982*4882a593Smuzhiyun (PixmapPtr) pSrc->pDrawable,
983*4882a593Smuzhiyun &patOrg, FB_ALLONES, GXcopy, CT_NONE);
984*4882a593Smuzhiyun
985*4882a593Smuzhiyun RegionUninit(®ion);
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