1706f2543Smrg/*
2706f2543Smrg * Copyright © 2001 Keith Packard
3706f2543Smrg *
4706f2543Smrg * Partly based on code that is Copyright © The XFree86 Project Inc.
5706f2543Smrg *
6706f2543Smrg * Permission to use, copy, modify, distribute, and sell this software and its
7706f2543Smrg * documentation for any purpose is hereby granted without fee, provided that
8706f2543Smrg * the above copyright notice appear in all copies and that both that
9706f2543Smrg * copyright notice and this permission notice appear in supporting
10706f2543Smrg * documentation, and that the name of Keith Packard not be used in
11706f2543Smrg * advertising or publicity pertaining to distribution of the software without
12706f2543Smrg * specific, written prior permission.  Keith Packard makes no
13706f2543Smrg * representations about the suitability of this software for any purpose.  It
14706f2543Smrg * is provided "as is" without express or implied warranty.
15706f2543Smrg *
16706f2543Smrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17706f2543Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18706f2543Smrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19706f2543Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20706f2543Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21706f2543Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22706f2543Smrg * PERFORMANCE OF THIS SOFTWARE.
23706f2543Smrg */
24706f2543Smrg
25706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
26706f2543Smrg#include <dix-config.h>
27706f2543Smrg#endif
28706f2543Smrg
29706f2543Smrg#include <stdlib.h>
30706f2543Smrg
31706f2543Smrg#include "exa_priv.h"
32706f2543Smrg
33706f2543Smrg#include "mipict.h"
34706f2543Smrg
35706f2543Smrg#if DEBUG_TRACE_FALL
36706f2543Smrgstatic void exaCompositeFallbackPictDesc(PicturePtr pict, char *string, int n)
37706f2543Smrg{
38706f2543Smrg    char format[20];
39706f2543Smrg    char size[20];
40706f2543Smrg    char loc;
41706f2543Smrg    int temp;
42706f2543Smrg
43706f2543Smrg    if (!pict) {
44706f2543Smrg	snprintf(string, n, "None");
45706f2543Smrg	return;
46706f2543Smrg    }
47706f2543Smrg
48706f2543Smrg    switch (pict->format)
49706f2543Smrg    {
50706f2543Smrg    case PICT_a8r8g8b8:
51706f2543Smrg	snprintf(format, 20, "ARGB8888");
52706f2543Smrg	break;
53706f2543Smrg    case PICT_x8r8g8b8:
54706f2543Smrg	snprintf(format, 20, "XRGB8888");
55706f2543Smrg	break;
56706f2543Smrg    case PICT_b8g8r8a8:
57706f2543Smrg	snprintf(format, 20, "BGRA8888");
58706f2543Smrg	break;
59706f2543Smrg    case PICT_b8g8r8x8:
60706f2543Smrg	snprintf(format, 20, "BGRX8888");
61706f2543Smrg	break;
62706f2543Smrg    case PICT_r5g6b5:
63706f2543Smrg	snprintf(format, 20, "RGB565  ");
64706f2543Smrg	break;
65706f2543Smrg    case PICT_x1r5g5b5:
66706f2543Smrg	snprintf(format, 20, "RGB555  ");
67706f2543Smrg	break;
68706f2543Smrg    case PICT_a8:
69706f2543Smrg	snprintf(format, 20, "A8      ");
70706f2543Smrg	break;
71706f2543Smrg    case PICT_a1:
72706f2543Smrg	snprintf(format, 20, "A1      ");
73706f2543Smrg	break;
74706f2543Smrg    default:
75706f2543Smrg	snprintf(format, 20, "0x%x", (int)pict->format);
76706f2543Smrg	break;
77706f2543Smrg    }
78706f2543Smrg
79706f2543Smrg    if (pict->pDrawable) {
80706f2543Smrg	loc = exaGetOffscreenPixmap(pict->pDrawable, &temp, &temp) ? 's' : 'm';
81706f2543Smrg
82706f2543Smrg	snprintf(size, 20, "%dx%d%s", pict->pDrawable->width,
83706f2543Smrg		 pict->pDrawable->height, pict->repeat ?
84706f2543Smrg		 " R" : "");
85706f2543Smrg    } else {
86706f2543Smrg	loc = '-';
87706f2543Smrg
88706f2543Smrg	snprintf(size, 20, "%s", pict->repeat ? " R" : "");
89706f2543Smrg    }
90706f2543Smrg
91706f2543Smrg    snprintf(string, n, "%p:%c fmt %s (%s)", pict->pDrawable, loc, format, size);
92706f2543Smrg}
93706f2543Smrg
94706f2543Smrgstatic void
95706f2543SmrgexaPrintCompositeFallback(CARD8 op,
96706f2543Smrg			  PicturePtr pSrc,
97706f2543Smrg			  PicturePtr pMask,
98706f2543Smrg			  PicturePtr pDst)
99706f2543Smrg{
100706f2543Smrg    char sop[20];
101706f2543Smrg    char srcdesc[40], maskdesc[40], dstdesc[40];
102706f2543Smrg
103706f2543Smrg    switch(op)
104706f2543Smrg    {
105706f2543Smrg    case PictOpSrc:
106706f2543Smrg	sprintf(sop, "Src");
107706f2543Smrg	break;
108706f2543Smrg    case PictOpOver:
109706f2543Smrg	sprintf(sop, "Over");
110706f2543Smrg	break;
111706f2543Smrg    default:
112706f2543Smrg	sprintf(sop, "0x%x", (int)op);
113706f2543Smrg	break;
114706f2543Smrg    }
115706f2543Smrg
116706f2543Smrg    exaCompositeFallbackPictDesc(pSrc, srcdesc, 40);
117706f2543Smrg    exaCompositeFallbackPictDesc(pMask, maskdesc, 40);
118706f2543Smrg    exaCompositeFallbackPictDesc(pDst, dstdesc, 40);
119706f2543Smrg
120706f2543Smrg    ErrorF("Composite fallback: op %s, \n"
121706f2543Smrg	   "                    src  %s, \n"
122706f2543Smrg	   "                    mask %s, \n"
123706f2543Smrg	   "                    dst  %s, \n",
124706f2543Smrg	   sop, srcdesc, maskdesc, dstdesc);
125706f2543Smrg}
126706f2543Smrg#endif /* DEBUG_TRACE_FALL */
127706f2543Smrg
128706f2543SmrgBool
129706f2543SmrgexaOpReadsDestination (CARD8 op)
130706f2543Smrg{
131706f2543Smrg    /* FALSE (does not read destination) is the list of ops in the protocol
132706f2543Smrg     * document with "0" in the "Fb" column and no "Ab" in the "Fa" column.
133706f2543Smrg     * That's just Clear and Src.  ReduceCompositeOp() will already have
134706f2543Smrg     * converted con/disjoint clear/src to Clear or Src.
135706f2543Smrg     */
136706f2543Smrg    switch (op) {
137706f2543Smrg    case PictOpClear:
138706f2543Smrg    case PictOpSrc:
139706f2543Smrg	return FALSE;
140706f2543Smrg    default:
141706f2543Smrg	return TRUE;
142706f2543Smrg    }
143706f2543Smrg}
144706f2543Smrg
145706f2543Smrg
146706f2543Smrgstatic Bool
147706f2543SmrgexaGetPixelFromRGBA(CARD32	*pixel,
148706f2543Smrg		    CARD16	red,
149706f2543Smrg		    CARD16	green,
150706f2543Smrg		    CARD16	blue,
151706f2543Smrg		    CARD16	alpha,
152706f2543Smrg		    PictFormatPtr pFormat)
153706f2543Smrg{
154706f2543Smrg    int rbits, bbits, gbits, abits;
155706f2543Smrg    int rshift, bshift, gshift, ashift;
156706f2543Smrg
157706f2543Smrg    *pixel = 0;
158706f2543Smrg
159706f2543Smrg    if (!PICT_FORMAT_COLOR(pFormat->format) &&
160706f2543Smrg	PICT_FORMAT_TYPE(pFormat->format) != PICT_TYPE_A)
161706f2543Smrg	return FALSE;
162706f2543Smrg
163706f2543Smrg    rbits = PICT_FORMAT_R(pFormat->format);
164706f2543Smrg    gbits = PICT_FORMAT_G(pFormat->format);
165706f2543Smrg    bbits = PICT_FORMAT_B(pFormat->format);
166706f2543Smrg    abits = PICT_FORMAT_A(pFormat->format);
167706f2543Smrg
168706f2543Smrg    rshift = pFormat->direct.red;
169706f2543Smrg    gshift = pFormat->direct.green;
170706f2543Smrg    bshift = pFormat->direct.blue;
171706f2543Smrg    ashift = pFormat->direct.alpha;
172706f2543Smrg
173706f2543Smrg    *pixel |=  ( blue >> (16 - bbits)) << bshift;
174706f2543Smrg    *pixel |=  (  red >> (16 - rbits)) << rshift;
175706f2543Smrg    *pixel |=  (green >> (16 - gbits)) << gshift;
176706f2543Smrg    *pixel |=  (alpha >> (16 - abits)) << ashift;
177706f2543Smrg
178706f2543Smrg    return TRUE;
179706f2543Smrg}
180706f2543Smrg
181706f2543Smrgstatic Bool
182706f2543SmrgexaGetRGBAFromPixel(CARD32	pixel,
183706f2543Smrg		    CARD16	*red,
184706f2543Smrg		    CARD16	*green,
185706f2543Smrg		    CARD16	*blue,
186706f2543Smrg		    CARD16	*alpha,
187706f2543Smrg		    PictFormatPtr pFormat,
188706f2543Smrg		    PictFormatShort format)
189706f2543Smrg{
190706f2543Smrg    int rbits, bbits, gbits, abits;
191706f2543Smrg    int rshift, bshift, gshift, ashift;
192706f2543Smrg
193706f2543Smrg    if (!PICT_FORMAT_COLOR(format) && PICT_FORMAT_TYPE(format) != PICT_TYPE_A)
194706f2543Smrg	return FALSE;
195706f2543Smrg
196706f2543Smrg    rbits = PICT_FORMAT_R(format);
197706f2543Smrg    gbits = PICT_FORMAT_G(format);
198706f2543Smrg    bbits = PICT_FORMAT_B(format);
199706f2543Smrg    abits = PICT_FORMAT_A(format);
200706f2543Smrg
201706f2543Smrg    if (pFormat) {
202706f2543Smrg	rshift = pFormat->direct.red;
203706f2543Smrg	gshift = pFormat->direct.green;
204706f2543Smrg	bshift = pFormat->direct.blue;
205706f2543Smrg	ashift = pFormat->direct.alpha;
206706f2543Smrg    } else if (format == PICT_a8r8g8b8) {
207706f2543Smrg	rshift = 16;
208706f2543Smrg	gshift = 8;
209706f2543Smrg	bshift = 0;
210706f2543Smrg	ashift = 24;
211706f2543Smrg    } else
212706f2543Smrg	FatalError("EXA bug: exaGetRGBAFromPixel() doesn't match "
213706f2543Smrg		   "createSourcePicture()\n");
214706f2543Smrg
215706f2543Smrg    if (rbits) {
216706f2543Smrg	*red = ((pixel >> rshift ) & ((1 << rbits) - 1)) << (16 - rbits);
217706f2543Smrg	while (rbits < 16) {
218706f2543Smrg	    *red |= *red >> rbits;
219706f2543Smrg	    rbits <<= 1;
220706f2543Smrg	}
221706f2543Smrg
222706f2543Smrg	*green = ((pixel >> gshift ) & ((1 << gbits) - 1)) << (16 - gbits);
223706f2543Smrg	while (gbits < 16) {
224706f2543Smrg	    *green |= *green >> gbits;
225706f2543Smrg	    gbits <<= 1;
226706f2543Smrg	}
227706f2543Smrg
228706f2543Smrg	*blue = ((pixel >> bshift ) & ((1 << bbits) - 1)) << (16 - bbits);
229706f2543Smrg	while (bbits < 16) {
230706f2543Smrg	    *blue |= *blue >> bbits;
231706f2543Smrg	    bbits <<= 1;
232706f2543Smrg	}
233706f2543Smrg    } else {
234706f2543Smrg	*red = 0x0000;
235706f2543Smrg	*green = 0x0000;
236706f2543Smrg	*blue = 0x0000;
237706f2543Smrg    }
238706f2543Smrg
239706f2543Smrg    if (abits) {
240706f2543Smrg	*alpha = ((pixel >> ashift ) & ((1 << abits) - 1)) << (16 - abits);
241706f2543Smrg	while (abits < 16) {
242706f2543Smrg	    *alpha |= *alpha >> abits;
243706f2543Smrg	    abits <<= 1;
244706f2543Smrg	}
245706f2543Smrg    } else
246706f2543Smrg	*alpha = 0xffff;
247706f2543Smrg
248706f2543Smrg    return TRUE;
249706f2543Smrg}
250706f2543Smrg
251706f2543Smrgstatic int
252706f2543SmrgexaTryDriverSolidFill(PicturePtr	pSrc,
253706f2543Smrg		      PicturePtr	pDst,
254706f2543Smrg		      INT16		xSrc,
255706f2543Smrg		      INT16		ySrc,
256706f2543Smrg		      INT16		xDst,
257706f2543Smrg		      INT16		yDst,
258706f2543Smrg		      CARD16		width,
259706f2543Smrg		      CARD16		height)
260706f2543Smrg{
261706f2543Smrg    ExaScreenPriv (pDst->pDrawable->pScreen);
262706f2543Smrg    RegionRec region;
263706f2543Smrg    BoxPtr pbox;
264706f2543Smrg    int nbox;
265706f2543Smrg    int dst_off_x, dst_off_y;
266706f2543Smrg    PixmapPtr pSrcPix, pDstPix;
267706f2543Smrg    ExaPixmapPrivPtr pDstExaPix;
268706f2543Smrg    CARD32 pixel;
269706f2543Smrg    CARD16 red, green, blue, alpha;
270706f2543Smrg
271706f2543Smrg    pDstPix = exaGetDrawablePixmap (pDst->pDrawable);
272706f2543Smrg    pDstExaPix = ExaGetPixmapPriv(pDstPix);
273706f2543Smrg
274706f2543Smrg    /* Check whether the accelerator can use the destination pixmap.
275706f2543Smrg     */
276706f2543Smrg    if (pDstExaPix->accel_blocked)
277706f2543Smrg    {
278706f2543Smrg	return -1;
279706f2543Smrg    }
280706f2543Smrg
281706f2543Smrg    xDst += pDst->pDrawable->x;
282706f2543Smrg    yDst += pDst->pDrawable->y;
283706f2543Smrg    if (pSrc->pDrawable) {
284706f2543Smrg	xSrc += pSrc->pDrawable->x;
285706f2543Smrg	ySrc += pSrc->pDrawable->y;
286706f2543Smrg    }
287706f2543Smrg
288706f2543Smrg    if (!miComputeCompositeRegion (&region, pSrc, NULL, pDst,
289706f2543Smrg				   xSrc, ySrc, 0, 0, xDst, yDst,
290706f2543Smrg				   width, height))
291706f2543Smrg	return 1;
292706f2543Smrg
293706f2543Smrg    exaGetDrawableDeltas (pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y);
294706f2543Smrg
295706f2543Smrg    RegionTranslate(&region, dst_off_x, dst_off_y);
296706f2543Smrg
297706f2543Smrg    if (pSrc->pDrawable) {
298706f2543Smrg	pSrcPix = exaGetDrawablePixmap (pSrc->pDrawable);
299706f2543Smrg	pixel = exaGetPixmapFirstPixel (pSrcPix);
300706f2543Smrg    } else
301706f2543Smrg	pixel = pSrc->pSourcePict->solidFill.color;
302706f2543Smrg
303706f2543Smrg    if (!exaGetRGBAFromPixel(pixel, &red, &green, &blue, &alpha,
304706f2543Smrg			     pSrc->pFormat, pSrc->format) ||
305706f2543Smrg	!exaGetPixelFromRGBA(&pixel, red, green, blue, alpha,
306706f2543Smrg			     pDst->pFormat))
307706f2543Smrg    {
308706f2543Smrg	RegionUninit(&region);
309706f2543Smrg	return -1;
310706f2543Smrg    }
311706f2543Smrg
312706f2543Smrg    if (pExaScr->do_migration) {
313706f2543Smrg	ExaMigrationRec pixmaps[1];
314706f2543Smrg
315706f2543Smrg	pixmaps[0].as_dst = TRUE;
316706f2543Smrg	pixmaps[0].as_src = FALSE;
317706f2543Smrg	pixmaps[0].pPix = pDstPix;
318706f2543Smrg	pixmaps[0].pReg = &region;
319706f2543Smrg	exaDoMigration(pixmaps, 1, TRUE);
320706f2543Smrg    }
321706f2543Smrg
322706f2543Smrg    if (!exaPixmapHasGpuCopy(pDstPix)) {
323706f2543Smrg	RegionUninit(&region);
324706f2543Smrg	return 0;
325706f2543Smrg    }
326706f2543Smrg
327706f2543Smrg    if (!(*pExaScr->info->PrepareSolid) (pDstPix, GXcopy, 0xffffffff, pixel))
328706f2543Smrg    {
329706f2543Smrg	RegionUninit(&region);
330706f2543Smrg	return -1;
331706f2543Smrg    }
332706f2543Smrg
333706f2543Smrg    nbox = RegionNumRects(&region);
334706f2543Smrg    pbox = RegionRects(&region);
335706f2543Smrg
336706f2543Smrg    while (nbox--)
337706f2543Smrg    {
338706f2543Smrg	(*pExaScr->info->Solid) (pDstPix, pbox->x1, pbox->y1, pbox->x2, pbox->y2);
339706f2543Smrg	pbox++;
340706f2543Smrg    }
341706f2543Smrg
342706f2543Smrg    (*pExaScr->info->DoneSolid) (pDstPix);
343706f2543Smrg    exaMarkSync(pDst->pDrawable->pScreen);
344706f2543Smrg
345706f2543Smrg    RegionUninit(&region);
346706f2543Smrg    return 1;
347706f2543Smrg}
348706f2543Smrg
349706f2543Smrgstatic int
350706f2543SmrgexaTryDriverCompositeRects(CARD8	       op,
351706f2543Smrg			   PicturePtr	       pSrc,
352706f2543Smrg			   PicturePtr	       pMask,
353706f2543Smrg			   PicturePtr	       pDst,
354706f2543Smrg			   int                 nrect,
355706f2543Smrg			   ExaCompositeRectPtr rects)
356706f2543Smrg{
357706f2543Smrg    ExaScreenPriv (pDst->pDrawable->pScreen);
358706f2543Smrg    int src_off_x = 0, src_off_y = 0, mask_off_x = 0, mask_off_y = 0;
359706f2543Smrg    int dst_off_x, dst_off_y;
360706f2543Smrg    PixmapPtr pSrcPix = NULL, pMaskPix = NULL, pDstPix;
361706f2543Smrg    ExaPixmapPrivPtr pSrcExaPix = NULL, pMaskExaPix = NULL, pDstExaPix;
362706f2543Smrg
363706f2543Smrg    if (!pExaScr->info->PrepareComposite)
364706f2543Smrg	return -1;
365706f2543Smrg
366706f2543Smrg    if (pSrc->pDrawable) {
367706f2543Smrg	pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable);
368706f2543Smrg	pSrcExaPix = ExaGetPixmapPriv(pSrcPix);
369706f2543Smrg    }
370706f2543Smrg
371706f2543Smrg    if (pMask && pMask->pDrawable) {
372706f2543Smrg	pMaskPix = exaGetDrawablePixmap(pMask->pDrawable);
373706f2543Smrg	pMaskExaPix = ExaGetPixmapPriv(pMaskPix);
374706f2543Smrg    }
375706f2543Smrg
376706f2543Smrg    pDstPix = exaGetDrawablePixmap(pDst->pDrawable);
377706f2543Smrg    pDstExaPix = ExaGetPixmapPriv(pDstPix);
378706f2543Smrg
379706f2543Smrg    /* Check whether the accelerator can use these pixmaps.
380706f2543Smrg     * FIXME: If it cannot, use temporary pixmaps so that the drawing
381706f2543Smrg     * happens within limits.
382706f2543Smrg     */
383706f2543Smrg    if (pDstExaPix->accel_blocked ||
384706f2543Smrg	(pSrcExaPix && pSrcExaPix->accel_blocked) ||
385706f2543Smrg	(pMaskExaPix && pMaskExaPix->accel_blocked))
386706f2543Smrg    {
387706f2543Smrg	return -1;
388706f2543Smrg    }
389706f2543Smrg
390706f2543Smrg    if (pExaScr->info->CheckComposite &&
391706f2543Smrg	!(*pExaScr->info->CheckComposite) (op, pSrc, pMask, pDst))
392706f2543Smrg    {
393706f2543Smrg	return -1;
394706f2543Smrg    }
395706f2543Smrg
396706f2543Smrg    if (pExaScr->do_migration) {
397706f2543Smrg	ExaMigrationRec pixmaps[3];
398706f2543Smrg	int i = 0;
399706f2543Smrg
400706f2543Smrg	pixmaps[i].as_dst = TRUE;
401706f2543Smrg	pixmaps[i].as_src = exaOpReadsDestination(op);
402706f2543Smrg	pixmaps[i].pPix = pDstPix;
403706f2543Smrg	pixmaps[i].pReg = NULL;
404706f2543Smrg	i++;
405706f2543Smrg
406706f2543Smrg	if (pSrcPix) {
407706f2543Smrg	    pixmaps[i].as_dst = FALSE;
408706f2543Smrg	    pixmaps[i].as_src = TRUE;
409706f2543Smrg	    pixmaps[i].pPix = pSrcPix;
410706f2543Smrg	    pixmaps[i].pReg = NULL;
411706f2543Smrg	    i++;
412706f2543Smrg	}
413706f2543Smrg
414706f2543Smrg	if (pMaskPix) {
415706f2543Smrg	    pixmaps[i].as_dst = FALSE;
416706f2543Smrg	    pixmaps[i].as_src = TRUE;
417706f2543Smrg	    pixmaps[i].pPix = pMaskPix;
418706f2543Smrg	    pixmaps[i].pReg = NULL;
419706f2543Smrg	    i++;
420706f2543Smrg	}
421706f2543Smrg
422706f2543Smrg	exaDoMigration(pixmaps, i, TRUE);
423706f2543Smrg    }
424706f2543Smrg
425706f2543Smrg    pDstPix = exaGetOffscreenPixmap (pDst->pDrawable, &dst_off_x, &dst_off_y);
426706f2543Smrg    if (!pDstPix)
427706f2543Smrg	return 0;
428706f2543Smrg
429706f2543Smrg    if (pSrcPix) {
430706f2543Smrg	pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y);
431706f2543Smrg	if (!pSrcPix)
432706f2543Smrg	    return 0;
433706f2543Smrg    }
434706f2543Smrg
435706f2543Smrg    if (pMaskPix) {
436706f2543Smrg	pMaskPix = exaGetOffscreenPixmap (pMask->pDrawable, &mask_off_x, &mask_off_y);
437706f2543Smrg	if (!pMaskPix)
438706f2543Smrg	    return 0;
439706f2543Smrg    }
440706f2543Smrg
441706f2543Smrg    if (!(*pExaScr->info->PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix,
442706f2543Smrg					     pMaskPix, pDstPix))
443706f2543Smrg	return -1;
444706f2543Smrg
445706f2543Smrg    while (nrect--)
446706f2543Smrg    {
447706f2543Smrg	INT16 xDst = rects->xDst + pDst->pDrawable->x;
448706f2543Smrg	INT16 yDst = rects->yDst + pDst->pDrawable->y;
449706f2543Smrg	INT16 xMask = rects->xMask;
450706f2543Smrg	INT16 yMask = rects->yMask;
451706f2543Smrg	INT16 xSrc = rects->xSrc;
452706f2543Smrg	INT16 ySrc = rects->ySrc;
453706f2543Smrg	RegionRec region;
454706f2543Smrg	BoxPtr pbox;
455706f2543Smrg	int nbox;
456706f2543Smrg
457706f2543Smrg	if (pMaskPix) {
458706f2543Smrg	    xMask += pMask->pDrawable->x;
459706f2543Smrg	    yMask += pMask->pDrawable->y;
460706f2543Smrg	}
461706f2543Smrg
462706f2543Smrg	if (pSrcPix) {
463706f2543Smrg	    xSrc += pSrc->pDrawable->x;
464706f2543Smrg	    ySrc += pSrc->pDrawable->y;
465706f2543Smrg	}
466706f2543Smrg
467706f2543Smrg	if (!miComputeCompositeRegion (&region, pSrc, pMask, pDst,
468706f2543Smrg				       xSrc, ySrc, xMask, yMask, xDst, yDst,
469706f2543Smrg				       rects->width, rects->height))
470706f2543Smrg	    goto next_rect;
471706f2543Smrg
472706f2543Smrg	RegionTranslate(&region, dst_off_x, dst_off_y);
473706f2543Smrg
474706f2543Smrg	nbox = RegionNumRects(&region);
475706f2543Smrg	pbox = RegionRects(&region);
476706f2543Smrg
477706f2543Smrg	xMask = xMask + mask_off_x - xDst - dst_off_x;
478706f2543Smrg	yMask = yMask + mask_off_y - yDst - dst_off_y;
479706f2543Smrg	xSrc = xSrc + src_off_x - xDst - dst_off_x;
480706f2543Smrg	ySrc = ySrc + src_off_y - yDst - dst_off_y;
481706f2543Smrg
482706f2543Smrg	while (nbox--)
483706f2543Smrg	{
484706f2543Smrg	    (*pExaScr->info->Composite) (pDstPix,
485706f2543Smrg					 pbox->x1 + xSrc,
486706f2543Smrg					 pbox->y1 + ySrc,
487706f2543Smrg					 pbox->x1 + xMask,
488706f2543Smrg					 pbox->y1 + yMask,
489706f2543Smrg					 pbox->x1,
490706f2543Smrg					 pbox->y1,
491706f2543Smrg					 pbox->x2 - pbox->x1,
492706f2543Smrg					 pbox->y2 - pbox->y1);
493706f2543Smrg	    pbox++;
494706f2543Smrg	}
495706f2543Smrg
496706f2543Smrg    next_rect:
497706f2543Smrg	RegionUninit(&region);
498706f2543Smrg
499706f2543Smrg	rects++;
500706f2543Smrg    }
501706f2543Smrg
502706f2543Smrg    (*pExaScr->info->DoneComposite) (pDstPix);
503706f2543Smrg    exaMarkSync(pDst->pDrawable->pScreen);
504706f2543Smrg
505706f2543Smrg    return 1;
506706f2543Smrg}
507706f2543Smrg
508706f2543Smrg/**
509706f2543Smrg * Copy a number of rectangles from source to destination in a single
510706f2543Smrg * operation. This is specialized for glyph rendering: we don't have the
511706f2543Smrg * special-case fallbacks found in exaComposite() - if the driver can support
512706f2543Smrg * it, we use the driver functionality, otherwise we fall back straight to
513706f2543Smrg * software.
514706f2543Smrg */
515706f2543Smrgvoid
516706f2543SmrgexaCompositeRects(CARD8	              op,
517706f2543Smrg		  PicturePtr	      pSrc,
518706f2543Smrg		  PicturePtr	      pMask,
519706f2543Smrg		  PicturePtr	      pDst,
520706f2543Smrg		  int                 nrect,
521706f2543Smrg		  ExaCompositeRectPtr rects)
522706f2543Smrg{
523706f2543Smrg    ExaScreenPriv (pDst->pDrawable->pScreen);
524706f2543Smrg    int n;
525706f2543Smrg    ExaCompositeRectPtr r;
526706f2543Smrg    int ret;
527706f2543Smrg
528706f2543Smrg    /* If we get a mask, that means we're rendering to the exaGlyphs
529706f2543Smrg     * destination directly, so the damage layer takes care of this.
530706f2543Smrg     */
531706f2543Smrg    if (!pMask) {
532706f2543Smrg	RegionRec region;
533706f2543Smrg	int x1 = MAXSHORT;
534706f2543Smrg	int y1 = MAXSHORT;
535706f2543Smrg	int x2 = MINSHORT;
536706f2543Smrg	int y2 = MINSHORT;
537706f2543Smrg	BoxRec box;
538706f2543Smrg
539706f2543Smrg	/* We have to manage the damage ourselves, since CompositeRects isn't
540706f2543Smrg	 * something in the screen that can be managed by the damage extension,
541706f2543Smrg	 * and EXA depends on damage to track what needs to be migrated between
542706f2543Smrg	 * the gpu and the cpu.
543706f2543Smrg	 */
544706f2543Smrg
545706f2543Smrg	/* Compute the overall extents of the composited region - we're making
546706f2543Smrg	 * the assumption here that we are compositing a bunch of glyphs that
547706f2543Smrg	 * cluster closely together and damaging each glyph individually would
548706f2543Smrg	 * be a loss compared to damaging the bounding box.
549706f2543Smrg	 */
550706f2543Smrg	n = nrect;
551706f2543Smrg	r = rects;
552706f2543Smrg	while (n--) {
553706f2543Smrg	    int rect_x2 = r->xDst + r->width;
554706f2543Smrg	    int rect_y2 = r->yDst + r->height;
555706f2543Smrg
556706f2543Smrg	    if (r->xDst < x1) x1 = r->xDst;
557706f2543Smrg	    if (r->yDst < y1) y1 = r->yDst;
558706f2543Smrg	    if (rect_x2 > x2) x2 = rect_x2;
559706f2543Smrg	    if (rect_y2 > y2) y2 = rect_y2;
560706f2543Smrg
561706f2543Smrg	    r++;
562706f2543Smrg	}
563706f2543Smrg
564706f2543Smrg	if (x2 <= x1 || y2 <= y1)
565706f2543Smrg	    return;
566706f2543Smrg
567706f2543Smrg	box.x1 = x1;
568706f2543Smrg	box.x2 = x2 < MAXSHORT ? x2 : MAXSHORT;
569706f2543Smrg	box.y1 = y1;
570706f2543Smrg	box.y2 = y2 < MAXSHORT ? y2 : MAXSHORT;
571706f2543Smrg
572706f2543Smrg 	/* The pixmap migration code relies on pendingDamage indicating
573706f2543Smrg	 * the bounds of the current rendering, so we need to force
574706f2543Smrg	 * the actual damage into that region before we do anything, and
575706f2543Smrg	 * (see use of DamagePendingRegion in exaCopyDirty)
576706f2543Smrg	 */
577706f2543Smrg
578706f2543Smrg	RegionInit(&region, &box, 1);
579706f2543Smrg
580706f2543Smrg	DamageRegionAppend(pDst->pDrawable, &region);
581706f2543Smrg
582706f2543Smrg	RegionUninit(&region);
583706f2543Smrg    }
584706f2543Smrg
585706f2543Smrg    /************************************************************/
586706f2543Smrg
587706f2543Smrg    ValidatePicture (pSrc);
588706f2543Smrg    if (pMask)
589706f2543Smrg	ValidatePicture (pMask);
590706f2543Smrg    ValidatePicture (pDst);
591706f2543Smrg
592706f2543Smrg    ret = exaTryDriverCompositeRects(op, pSrc, pMask, pDst, nrect, rects);
593706f2543Smrg
594706f2543Smrg    if (ret != 1) {
595706f2543Smrg	if (ret == -1 && op == PictOpOver && pMask && pMask->componentAlpha &&
596706f2543Smrg	    (!pExaScr->info->CheckComposite ||
597706f2543Smrg	     ((*pExaScr->info->CheckComposite)(PictOpOutReverse, pSrc, pMask,
598706f2543Smrg					       pDst) &&
599706f2543Smrg	      (*pExaScr->info->CheckComposite)(PictOpAdd, pSrc, pMask, pDst)))) {
600706f2543Smrg	    ret = exaTryDriverCompositeRects(PictOpOutReverse, pSrc, pMask,
601706f2543Smrg					     pDst, nrect, rects);
602706f2543Smrg	    if (ret == 1) {
603706f2543Smrg		op = PictOpAdd;
604706f2543Smrg		ret = exaTryDriverCompositeRects(op, pSrc, pMask, pDst, nrect,
605706f2543Smrg						 rects);
606706f2543Smrg	    }
607706f2543Smrg	}
608706f2543Smrg
609706f2543Smrg	if (ret != 1) {
610706f2543Smrg	    n = nrect;
611706f2543Smrg	    r = rects;
612706f2543Smrg	    while (n--) {
613706f2543Smrg		ExaCheckComposite (op, pSrc, pMask, pDst,
614706f2543Smrg				   r->xSrc, r->ySrc,
615706f2543Smrg				   r->xMask, r->yMask,
616706f2543Smrg				   r->xDst, r->yDst,
617706f2543Smrg				   r->width, r->height);
618706f2543Smrg		r++;
619706f2543Smrg	    }
620706f2543Smrg	}
621706f2543Smrg    }
622706f2543Smrg
623706f2543Smrg    /************************************************************/
624706f2543Smrg
625706f2543Smrg    if (!pMask) {
626706f2543Smrg	/* Now we have to flush the damage out from pendingDamage => damage
627706f2543Smrg	 * Calling DamageRegionProcessPending has that effect.
628706f2543Smrg	 */
629706f2543Smrg
630706f2543Smrg	DamageRegionProcessPending(pDst->pDrawable);
631706f2543Smrg    }
632706f2543Smrg}
633706f2543Smrg
634706f2543Smrgstatic int
635706f2543SmrgexaTryDriverComposite(CARD8		op,
636706f2543Smrg		      PicturePtr	pSrc,
637706f2543Smrg		      PicturePtr	pMask,
638706f2543Smrg		      PicturePtr	pDst,
639706f2543Smrg		      INT16		xSrc,
640706f2543Smrg		      INT16		ySrc,
641706f2543Smrg		      INT16		xMask,
642706f2543Smrg		      INT16		yMask,
643706f2543Smrg		      INT16		xDst,
644706f2543Smrg		      INT16		yDst,
645706f2543Smrg		      CARD16		width,
646706f2543Smrg		      CARD16		height)
647706f2543Smrg{
648706f2543Smrg    ExaScreenPriv (pDst->pDrawable->pScreen);
649706f2543Smrg    RegionRec region;
650706f2543Smrg    BoxPtr pbox;
651706f2543Smrg    int nbox;
652706f2543Smrg    int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y;
653706f2543Smrg    PixmapPtr pSrcPix = NULL, pMaskPix = NULL, pDstPix;
654706f2543Smrg    ExaPixmapPrivPtr pSrcExaPix = NULL, pMaskExaPix = NULL, pDstExaPix;
655706f2543Smrg
656706f2543Smrg    if (pSrc->pDrawable) {
657706f2543Smrg	pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable);
658706f2543Smrg	pSrcExaPix = ExaGetPixmapPriv(pSrcPix);
659706f2543Smrg    }
660706f2543Smrg
661706f2543Smrg    pDstPix = exaGetDrawablePixmap(pDst->pDrawable);
662706f2543Smrg    pDstExaPix = ExaGetPixmapPriv(pDstPix);
663706f2543Smrg
664706f2543Smrg    if (pMask && pMask->pDrawable) {
665706f2543Smrg	pMaskPix = exaGetDrawablePixmap(pMask->pDrawable);
666706f2543Smrg        pMaskExaPix = ExaGetPixmapPriv(pMaskPix);
667706f2543Smrg    }
668706f2543Smrg
669706f2543Smrg    /* Check whether the accelerator can use these pixmaps.
670706f2543Smrg     * FIXME: If it cannot, use temporary pixmaps so that the drawing
671706f2543Smrg     * happens within limits.
672706f2543Smrg     */
673706f2543Smrg    if (pDstExaPix->accel_blocked ||
674706f2543Smrg	(pSrcExaPix && pSrcExaPix->accel_blocked) ||
675706f2543Smrg	(pMaskExaPix && (pMaskExaPix->accel_blocked)))
676706f2543Smrg    {
677706f2543Smrg	return -1;
678706f2543Smrg    }
679706f2543Smrg
680706f2543Smrg    xDst += pDst->pDrawable->x;
681706f2543Smrg    yDst += pDst->pDrawable->y;
682706f2543Smrg
683706f2543Smrg    if (pMaskPix) {
684706f2543Smrg	xMask += pMask->pDrawable->x;
685706f2543Smrg	yMask += pMask->pDrawable->y;
686706f2543Smrg    }
687706f2543Smrg
688706f2543Smrg    if (pSrcPix) {
689706f2543Smrg	xSrc += pSrc->pDrawable->x;
690706f2543Smrg	ySrc += pSrc->pDrawable->y;
691706f2543Smrg    }
692706f2543Smrg
693706f2543Smrg    if (pExaScr->info->CheckComposite &&
694706f2543Smrg	!(*pExaScr->info->CheckComposite) (op, pSrc, pMask, pDst))
695706f2543Smrg    {
696706f2543Smrg	return -1;
697706f2543Smrg    }
698706f2543Smrg
699706f2543Smrg    if (!miComputeCompositeRegion (&region, pSrc, pMask, pDst,
700706f2543Smrg				   xSrc, ySrc, xMask, yMask, xDst, yDst,
701706f2543Smrg				   width, height))
702706f2543Smrg	return 1;
703706f2543Smrg
704706f2543Smrg    exaGetDrawableDeltas (pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y);
705706f2543Smrg
706706f2543Smrg    RegionTranslate(&region, dst_off_x, dst_off_y);
707706f2543Smrg
708706f2543Smrg    if (pExaScr->do_migration) {
709706f2543Smrg	ExaMigrationRec pixmaps[3];
710706f2543Smrg	int i = 0;
711706f2543Smrg
712706f2543Smrg	pixmaps[i].as_dst = TRUE;
713706f2543Smrg	pixmaps[i].as_src = exaOpReadsDestination(op);
714706f2543Smrg	pixmaps[i].pPix = pDstPix;
715706f2543Smrg	pixmaps[i].pReg = pixmaps[0].as_src ? NULL : &region;
716706f2543Smrg	i++;
717706f2543Smrg
718706f2543Smrg	if (pSrcPix) {
719706f2543Smrg	    pixmaps[i].as_dst = FALSE;
720706f2543Smrg	    pixmaps[i].as_src = TRUE;
721706f2543Smrg	    pixmaps[i].pPix = pSrcPix;
722706f2543Smrg	    pixmaps[i].pReg = NULL;
723706f2543Smrg	    i++;
724706f2543Smrg	}
725706f2543Smrg
726706f2543Smrg	if (pMaskPix) {
727706f2543Smrg	    pixmaps[i].as_dst = FALSE;
728706f2543Smrg	    pixmaps[i].as_src = TRUE;
729706f2543Smrg	    pixmaps[i].pPix = pMaskPix;
730706f2543Smrg	    pixmaps[i].pReg = NULL;
731706f2543Smrg	    i++;
732706f2543Smrg	}
733706f2543Smrg
734706f2543Smrg	exaDoMigration(pixmaps, i, TRUE);
735706f2543Smrg    }
736706f2543Smrg
737706f2543Smrg    if (pSrcPix) {
738706f2543Smrg	pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y);
739706f2543Smrg	if (!pSrcPix) {
740706f2543Smrg	    RegionUninit(&region);
741706f2543Smrg	    return 0;
742706f2543Smrg	}
743706f2543Smrg    }
744706f2543Smrg
745706f2543Smrg    if (pMaskPix) {
746706f2543Smrg	pMaskPix = exaGetOffscreenPixmap (pMask->pDrawable, &mask_off_x,
747706f2543Smrg					  &mask_off_y);
748706f2543Smrg	if (!pMaskPix) {
749706f2543Smrg	    RegionUninit(&region);
750706f2543Smrg	    return 0;
751706f2543Smrg	}
752706f2543Smrg    }
753706f2543Smrg
754706f2543Smrg    if (!exaPixmapHasGpuCopy(pDstPix)) {
755706f2543Smrg	RegionUninit(&region);
756706f2543Smrg	return 0;
757706f2543Smrg    }
758706f2543Smrg
759706f2543Smrg    if (!(*pExaScr->info->PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix,
760706f2543Smrg					     pMaskPix, pDstPix))
761706f2543Smrg    {
762706f2543Smrg	RegionUninit(&region);
763706f2543Smrg	return -1;
764706f2543Smrg    }
765706f2543Smrg
766706f2543Smrg    nbox = RegionNumRects(&region);
767706f2543Smrg    pbox = RegionRects(&region);
768706f2543Smrg
769706f2543Smrg    xMask = xMask + mask_off_x - xDst - dst_off_x;
770706f2543Smrg    yMask = yMask + mask_off_y - yDst - dst_off_y;
771706f2543Smrg
772706f2543Smrg    xSrc = xSrc + src_off_x - xDst - dst_off_x;
773706f2543Smrg    ySrc = ySrc + src_off_y - yDst - dst_off_y;
774706f2543Smrg
775706f2543Smrg    while (nbox--)
776706f2543Smrg    {
777706f2543Smrg	(*pExaScr->info->Composite) (pDstPix,
778706f2543Smrg				     pbox->x1 + xSrc,
779706f2543Smrg				     pbox->y1 + ySrc,
780706f2543Smrg				     pbox->x1 + xMask,
781706f2543Smrg				     pbox->y1 + yMask,
782706f2543Smrg				     pbox->x1,
783706f2543Smrg				     pbox->y1,
784706f2543Smrg				     pbox->x2 - pbox->x1,
785706f2543Smrg				     pbox->y2 - pbox->y1);
786706f2543Smrg	pbox++;
787706f2543Smrg    }
788706f2543Smrg    (*pExaScr->info->DoneComposite) (pDstPix);
789706f2543Smrg    exaMarkSync(pDst->pDrawable->pScreen);
790706f2543Smrg
791706f2543Smrg    RegionUninit(&region);
792706f2543Smrg    return 1;
793706f2543Smrg}
794706f2543Smrg
795706f2543Smrg/**
796706f2543Smrg * exaTryMagicTwoPassCompositeHelper implements PictOpOver using two passes of
797706f2543Smrg * simpler operations PictOpOutReverse and PictOpAdd. Mainly used for component
798706f2543Smrg * alpha and limited 1-tmu cards.
799706f2543Smrg *
800706f2543Smrg * From http://anholt.livejournal.com/32058.html:
801706f2543Smrg *
802706f2543Smrg * The trouble is that component-alpha rendering requires two different sources
803706f2543Smrg * for blending: one for the source value to the blender, which is the
804706f2543Smrg * per-channel multiplication of source and mask, and one for the source alpha
805706f2543Smrg * for multiplying with the destination channels, which is the multiplication
806706f2543Smrg * of the source channels by the mask alpha. So the equation for Over is:
807706f2543Smrg *
808706f2543Smrg * dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A
809706f2543Smrg * dst.R = src.R * mask.R + (1 - (src.A * mask.R)) * dst.R
810706f2543Smrg * dst.G = src.G * mask.G + (1 - (src.A * mask.G)) * dst.G
811706f2543Smrg * dst.B = src.B * mask.B + (1 - (src.A * mask.B)) * dst.B
812706f2543Smrg *
813706f2543Smrg * But we can do some simpler operations, right? How about PictOpOutReverse,
814706f2543Smrg * which has a source factor of 0 and dest factor of (1 - source alpha). We
815706f2543Smrg * can get the source alpha value (srca.X = src.A * mask.X) out of the texture
816706f2543Smrg * blenders pretty easily. So we can do a component-alpha OutReverse, which
817706f2543Smrg * gets us:
818706f2543Smrg *
819706f2543Smrg * dst.A = 0 + (1 - (src.A * mask.A)) * dst.A
820706f2543Smrg * dst.R = 0 + (1 - (src.A * mask.R)) * dst.R
821706f2543Smrg * dst.G = 0 + (1 - (src.A * mask.G)) * dst.G
822706f2543Smrg * dst.B = 0 + (1 - (src.A * mask.B)) * dst.B
823706f2543Smrg *
824706f2543Smrg * OK. And if an op doesn't use the source alpha value for the destination
825706f2543Smrg * factor, then we can do the channel multiplication in the texture blenders
826706f2543Smrg * to get the source value, and ignore the source alpha that we wouldn't use.
827706f2543Smrg * We've supported this in the Radeon driver for a long time. An example would
828706f2543Smrg * be PictOpAdd, which does:
829706f2543Smrg *
830706f2543Smrg * dst.A = src.A * mask.A + dst.A
831706f2543Smrg * dst.R = src.R * mask.R + dst.R
832706f2543Smrg * dst.G = src.G * mask.G + dst.G
833706f2543Smrg * dst.B = src.B * mask.B + dst.B
834706f2543Smrg *
835706f2543Smrg * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right
836706f2543Smrg * after it, we get:
837706f2543Smrg *
838706f2543Smrg * dst.A = src.A * mask.A + ((1 - (src.A * mask.A)) * dst.A)
839706f2543Smrg * dst.R = src.R * mask.R + ((1 - (src.A * mask.R)) * dst.R)
840706f2543Smrg * dst.G = src.G * mask.G + ((1 - (src.A * mask.G)) * dst.G)
841706f2543Smrg * dst.B = src.B * mask.B + ((1 - (src.A * mask.B)) * dst.B)
842706f2543Smrg */
843706f2543Smrg
844706f2543Smrgstatic int
845706f2543SmrgexaTryMagicTwoPassCompositeHelper(CARD8 op,
846706f2543Smrg				  PicturePtr pSrc,
847706f2543Smrg				  PicturePtr pMask,
848706f2543Smrg				  PicturePtr pDst,
849706f2543Smrg				  INT16 xSrc,
850706f2543Smrg				  INT16 ySrc,
851706f2543Smrg				  INT16 xMask,
852706f2543Smrg				  INT16 yMask,
853706f2543Smrg				  INT16 xDst,
854706f2543Smrg				  INT16 yDst,
855706f2543Smrg				  CARD16 width,
856706f2543Smrg				  CARD16 height)
857706f2543Smrg{
858706f2543Smrg    ExaScreenPriv (pDst->pDrawable->pScreen);
859706f2543Smrg
860706f2543Smrg    assert(op == PictOpOver);
861706f2543Smrg
862706f2543Smrg    if (pExaScr->info->CheckComposite &&
863706f2543Smrg	(!(*pExaScr->info->CheckComposite)(PictOpOutReverse, pSrc, pMask,
864706f2543Smrg					   pDst) ||
865706f2543Smrg	 !(*pExaScr->info->CheckComposite)(PictOpAdd, pSrc, pMask, pDst)))
866706f2543Smrg    {
867706f2543Smrg	return -1;
868706f2543Smrg    }
869706f2543Smrg
870706f2543Smrg    /* Now, we think we should be able to accelerate this operation. First,
871706f2543Smrg     * composite the destination to be the destination times the source alpha
872706f2543Smrg     * factors.
873706f2543Smrg     */
874706f2543Smrg    exaComposite(PictOpOutReverse, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask,
875706f2543Smrg		 xDst, yDst, width, height);
876706f2543Smrg
877706f2543Smrg    /* Then, add in the source value times the destination alpha factors (1.0).
878706f2543Smrg     */
879706f2543Smrg    exaComposite(PictOpAdd, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask,
880706f2543Smrg		 xDst, yDst, width, height);
881706f2543Smrg
882706f2543Smrg    return 1;
883706f2543Smrg}
884706f2543Smrg
885706f2543Smrgvoid
886706f2543SmrgexaComposite(CARD8	op,
887706f2543Smrg	     PicturePtr pSrc,
888706f2543Smrg	     PicturePtr pMask,
889706f2543Smrg	     PicturePtr pDst,
890706f2543Smrg	     INT16	xSrc,
891706f2543Smrg	     INT16	ySrc,
892706f2543Smrg	     INT16	xMask,
893706f2543Smrg	     INT16	yMask,
894706f2543Smrg	     INT16	xDst,
895706f2543Smrg	     INT16	yDst,
896706f2543Smrg	     CARD16	width,
897706f2543Smrg	     CARD16	height)
898706f2543Smrg{
899706f2543Smrg    ExaScreenPriv (pDst->pDrawable->pScreen);
900706f2543Smrg    int ret = -1;
901706f2543Smrg    Bool saveSrcRepeat = pSrc->repeat;
902706f2543Smrg    Bool saveMaskRepeat = pMask ? pMask->repeat : 0;
903706f2543Smrg    RegionRec region;
904706f2543Smrg
905706f2543Smrg    if (pExaScr->swappedOut)
906706f2543Smrg	goto fallback;
907706f2543Smrg
908706f2543Smrg    /* Remove repeat in source if useless */
909706f2543Smrg    if (pSrc->pDrawable && pSrc->repeat && !pSrc->transform && xSrc >= 0 &&
910706f2543Smrg	(xSrc + width) <= pSrc->pDrawable->width && ySrc >= 0 &&
911706f2543Smrg	(ySrc + height) <= pSrc->pDrawable->height)
912706f2543Smrg	    pSrc->repeat = 0;
913706f2543Smrg
914706f2543Smrg    if (!pMask && !pSrc->alphaMap && !pDst->alphaMap &&
915706f2543Smrg	(op == PictOpSrc || (op == PictOpOver && !PICT_FORMAT_A(pSrc->format))))
916706f2543Smrg    {
917706f2543Smrg	if (pSrc->pDrawable ?
918706f2543Smrg	    (pSrc->pDrawable->width == 1 && pSrc->pDrawable->height == 1 &&
919706f2543Smrg	     pSrc->repeat) :
920706f2543Smrg	    (pSrc->pSourcePict->type == SourcePictTypeSolidFill))
921706f2543Smrg	{
922706f2543Smrg	    ret = exaTryDriverSolidFill(pSrc, pDst, xSrc, ySrc, xDst, yDst,
923706f2543Smrg					width, height);
924706f2543Smrg	    if (ret == 1)
925706f2543Smrg		goto done;
926706f2543Smrg	} else if (pSrc->pDrawable && !pSrc->transform &&
927706f2543Smrg	    ((op == PictOpSrc &&
928706f2543Smrg	      (pSrc->format == pDst->format ||
929706f2543Smrg	       (PICT_FORMAT_COLOR(pDst->format) &&
930706f2543Smrg		PICT_FORMAT_COLOR(pSrc->format) &&
931706f2543Smrg		pDst->format == PICT_FORMAT(PICT_FORMAT_BPP(pSrc->format),
932706f2543Smrg					    PICT_FORMAT_TYPE(pSrc->format),
933706f2543Smrg					    0,
934706f2543Smrg					    PICT_FORMAT_R(pSrc->format),
935706f2543Smrg					    PICT_FORMAT_G(pSrc->format),
936706f2543Smrg					    PICT_FORMAT_B(pSrc->format))))) ||
937706f2543Smrg	     (op == PictOpOver && pSrc->format == pDst->format &&
938706f2543Smrg	      !PICT_FORMAT_A(pSrc->format))))
939706f2543Smrg	{
940706f2543Smrg	    if (!pSrc->repeat && xSrc >= 0 && ySrc >= 0 &&
941706f2543Smrg		(xSrc + width <= pSrc->pDrawable->width) &&
942706f2543Smrg		(ySrc + height <= pSrc->pDrawable->height))
943706f2543Smrg	    {
944706f2543Smrg		Bool ret;
945706f2543Smrg		xDst += pDst->pDrawable->x;
946706f2543Smrg		yDst += pDst->pDrawable->y;
947706f2543Smrg		xSrc += pSrc->pDrawable->x;
948706f2543Smrg		ySrc += pSrc->pDrawable->y;
949706f2543Smrg
950706f2543Smrg		if (!miComputeCompositeRegion (&region, pSrc, pMask, pDst,
951706f2543Smrg					       xSrc, ySrc, xMask, yMask, xDst,
952706f2543Smrg					       yDst, width, height))
953706f2543Smrg		    goto done;
954706f2543Smrg
955706f2543Smrg		ret = exaHWCopyNtoN(pSrc->pDrawable, pDst->pDrawable, NULL,
956706f2543Smrg			     RegionRects(&region), RegionNumRects(&region),
957706f2543Smrg			     xSrc - xDst, ySrc - yDst, FALSE, FALSE);
958706f2543Smrg		RegionUninit(&region);
959706f2543Smrg
960706f2543Smrg		/* Reset values to their original values. */
961706f2543Smrg		xDst -= pDst->pDrawable->x;
962706f2543Smrg		yDst -= pDst->pDrawable->y;
963706f2543Smrg		xSrc -= pSrc->pDrawable->x;
964706f2543Smrg		ySrc -= pSrc->pDrawable->y;
965706f2543Smrg
966706f2543Smrg		if (!ret)
967706f2543Smrg		    goto fallback;
968706f2543Smrg
969706f2543Smrg		goto done;
970706f2543Smrg	    }
971706f2543Smrg
972706f2543Smrg	    if (pSrc->repeat && pSrc->repeatType == RepeatNormal &&
973706f2543Smrg		pSrc->pDrawable->type == DRAWABLE_PIXMAP)
974706f2543Smrg	    {
975706f2543Smrg		DDXPointRec patOrg;
976706f2543Smrg
977706f2543Smrg		/* Let's see if the driver can do the repeat in one go */
978706f2543Smrg		if (pExaScr->info->PrepareComposite && !pSrc->alphaMap &&
979706f2543Smrg		    !pDst->alphaMap)
980706f2543Smrg		{
981706f2543Smrg		    ret = exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc,
982706f2543Smrg						ySrc, xMask, yMask, xDst, yDst,
983706f2543Smrg						width, height);
984706f2543Smrg		    if (ret == 1)
985706f2543Smrg			goto done;
986706f2543Smrg		}
987706f2543Smrg
988706f2543Smrg		/* Now see if we can use exaFillRegionTiled() */
989706f2543Smrg		xDst += pDst->pDrawable->x;
990706f2543Smrg		yDst += pDst->pDrawable->y;
991706f2543Smrg		xSrc += pSrc->pDrawable->x;
992706f2543Smrg		ySrc += pSrc->pDrawable->y;
993706f2543Smrg
994706f2543Smrg		if (!miComputeCompositeRegion (&region, pSrc, pMask, pDst, xSrc,
995706f2543Smrg					       ySrc, xMask, yMask, xDst, yDst,
996706f2543Smrg					       width, height))
997706f2543Smrg		    goto done;
998706f2543Smrg
999706f2543Smrg		/* pattern origin is the point in the destination drawable
1000706f2543Smrg		 * corresponding to (0,0) in the source */
1001706f2543Smrg		patOrg.x = xDst - xSrc;
1002706f2543Smrg		patOrg.y = yDst - ySrc;
1003706f2543Smrg
1004706f2543Smrg		ret = exaFillRegionTiled(pDst->pDrawable, &region,
1005706f2543Smrg					 (PixmapPtr)pSrc->pDrawable,
1006706f2543Smrg					 &patOrg, FB_ALLONES, GXcopy, CT_NONE);
1007706f2543Smrg
1008706f2543Smrg		RegionUninit(&region);
1009706f2543Smrg
1010706f2543Smrg		if (ret)
1011706f2543Smrg		    goto done;
1012706f2543Smrg
1013706f2543Smrg		/* Let's be correct and restore the variables to their original state. */
1014706f2543Smrg		xDst -= pDst->pDrawable->x;
1015706f2543Smrg		yDst -= pDst->pDrawable->y;
1016706f2543Smrg		xSrc -= pSrc->pDrawable->x;
1017706f2543Smrg		ySrc -= pSrc->pDrawable->y;
1018706f2543Smrg	    }
1019706f2543Smrg	}
1020706f2543Smrg    }
1021706f2543Smrg
1022706f2543Smrg    /* Remove repeat in mask if useless */
1023706f2543Smrg    if (pMask && pMask->pDrawable && pMask->repeat && !pMask->transform &&
1024706f2543Smrg	xMask >= 0 && (xMask + width) <= pMask->pDrawable->width &&
1025706f2543Smrg	yMask >= 0 && (yMask + height) <= pMask->pDrawable->height)
1026706f2543Smrg	    pMask->repeat = 0;
1027706f2543Smrg
1028706f2543Smrg    if (pExaScr->info->PrepareComposite &&
1029706f2543Smrg	!pSrc->alphaMap && (!pMask || !pMask->alphaMap) && !pDst->alphaMap)
1030706f2543Smrg    {
1031706f2543Smrg	Bool isSrcSolid;
1032706f2543Smrg
1033706f2543Smrg	ret = exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask,
1034706f2543Smrg				    yMask, xDst, yDst, width, height);
1035706f2543Smrg	if (ret == 1)
1036706f2543Smrg	    goto done;
1037706f2543Smrg
1038706f2543Smrg	/* For generic masks and solid src pictures, mach64 can do Over in two
1039706f2543Smrg	 * passes, similar to the component-alpha case.
1040706f2543Smrg	 */
1041706f2543Smrg	isSrcSolid = pSrc->pDrawable ?
1042706f2543Smrg	    (pSrc->pDrawable->width == 1 && pSrc->pDrawable->height == 1 &&
1043706f2543Smrg	     pSrc->repeat) :
1044706f2543Smrg	    (pSrc->pSourcePict->type == SourcePictTypeSolidFill);
1045706f2543Smrg
1046706f2543Smrg	/* If we couldn't do the Composite in a single pass, and it was a
1047706f2543Smrg	 * component-alpha Over, see if we can do it in two passes with
1048706f2543Smrg	 * an OutReverse and then an Add.
1049706f2543Smrg	 */
1050706f2543Smrg	if (ret == -1 && op == PictOpOver && pMask &&
1051706f2543Smrg	    (pMask->componentAlpha || isSrcSolid)) {
1052706f2543Smrg	    ret = exaTryMagicTwoPassCompositeHelper(op, pSrc, pMask, pDst,
1053706f2543Smrg						    xSrc, ySrc,
1054706f2543Smrg						    xMask, yMask, xDst, yDst,
1055706f2543Smrg						    width, height);
1056706f2543Smrg	    if (ret == 1)
1057706f2543Smrg		goto done;
1058706f2543Smrg	}
1059706f2543Smrg    }
1060706f2543Smrg
1061706f2543Smrgfallback:
1062706f2543Smrg#if DEBUG_TRACE_FALL
1063706f2543Smrg    exaPrintCompositeFallback (op, pSrc, pMask, pDst);
1064706f2543Smrg#endif
1065706f2543Smrg
1066706f2543Smrg    ExaCheckComposite (op, pSrc, pMask, pDst, xSrc, ySrc,
1067706f2543Smrg		      xMask, yMask, xDst, yDst, width, height);
1068706f2543Smrg
1069706f2543Smrgdone:
1070706f2543Smrg    pSrc->repeat = saveSrcRepeat;
1071706f2543Smrg    if (pMask)
1072706f2543Smrg	pMask->repeat = saveMaskRepeat;
1073706f2543Smrg}
1074706f2543Smrg
1075706f2543Smrg/**
1076706f2543Smrg * Same as miCreateAlphaPicture, except it uses ExaCheckPolyFillRect instead
1077706f2543Smrg * of PolyFillRect to initialize the pixmap after creating it, to prevent
1078706f2543Smrg * the pixmap from being migrated.
1079706f2543Smrg *
1080706f2543Smrg * See the comments about exaTrapezoids and exaTriangles.
1081706f2543Smrg */
1082706f2543Smrgstatic PicturePtr
1083706f2543SmrgexaCreateAlphaPicture (ScreenPtr     pScreen,
1084706f2543Smrg                       PicturePtr    pDst,
1085706f2543Smrg                       PictFormatPtr pPictFormat,
1086706f2543Smrg                       CARD16        width,
1087706f2543Smrg                       CARD16        height)
1088706f2543Smrg{
1089706f2543Smrg    PixmapPtr	    pPixmap;
1090706f2543Smrg    PicturePtr	    pPicture;
1091706f2543Smrg    GCPtr	    pGC;
1092706f2543Smrg    int		    error;
1093706f2543Smrg    xRectangle	    rect;
1094706f2543Smrg
1095706f2543Smrg    if (width > 32767 || height > 32767)
1096706f2543Smrg	return 0;
1097706f2543Smrg
1098706f2543Smrg    if (!pPictFormat)
1099706f2543Smrg    {
1100706f2543Smrg	if (pDst->polyEdge == PolyEdgeSharp)
1101706f2543Smrg	    pPictFormat = PictureMatchFormat (pScreen, 1, PICT_a1);
1102706f2543Smrg	else
1103706f2543Smrg	    pPictFormat = PictureMatchFormat (pScreen, 8, PICT_a8);
1104706f2543Smrg	if (!pPictFormat)
1105706f2543Smrg	    return 0;
1106706f2543Smrg    }
1107706f2543Smrg
1108706f2543Smrg    pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
1109706f2543Smrg					pPictFormat->depth, 0);
1110706f2543Smrg    if (!pPixmap)
1111706f2543Smrg	return 0;
1112706f2543Smrg    pGC = GetScratchGC (pPixmap->drawable.depth, pScreen);
1113706f2543Smrg    if (!pGC)
1114706f2543Smrg    {
1115706f2543Smrg	(*pScreen->DestroyPixmap) (pPixmap);
1116706f2543Smrg	return 0;
1117706f2543Smrg    }
1118706f2543Smrg    ValidateGC (&pPixmap->drawable, pGC);
1119706f2543Smrg    rect.x = 0;
1120706f2543Smrg    rect.y = 0;
1121706f2543Smrg    rect.width = width;
1122706f2543Smrg    rect.height = height;
1123706f2543Smrg    ExaCheckPolyFillRect (&pPixmap->drawable, pGC, 1, &rect);
1124706f2543Smrg    exaPixmapDirty (pPixmap, 0, 0, width, height);
1125706f2543Smrg    FreeScratchGC (pGC);
1126706f2543Smrg    pPicture = CreatePicture (0, &pPixmap->drawable, pPictFormat,
1127706f2543Smrg			      0, 0, serverClient, &error);
1128706f2543Smrg    (*pScreen->DestroyPixmap) (pPixmap);
1129706f2543Smrg    return pPicture;
1130706f2543Smrg}
1131706f2543Smrg
1132706f2543Smrg/**
1133706f2543Smrg * exaTrapezoids is essentially a copy of miTrapezoids that uses
1134706f2543Smrg * exaCreateAlphaPicture instead of miCreateAlphaPicture.
1135706f2543Smrg *
1136706f2543Smrg * The problem with miCreateAlphaPicture is that it calls PolyFillRect
1137706f2543Smrg * to initialize the contents after creating the pixmap, which
1138706f2543Smrg * causes the pixmap to be moved in for acceleration. The subsequent
1139706f2543Smrg * call to RasterizeTrapezoid won't be accelerated however, which
1140706f2543Smrg * forces the pixmap to be moved out again.
1141706f2543Smrg *
1142706f2543Smrg * exaCreateAlphaPicture avoids this roundtrip by using ExaCheckPolyFillRect
1143706f2543Smrg * to initialize the contents.
1144706f2543Smrg */
1145706f2543Smrgvoid
1146706f2543SmrgexaTrapezoids (CARD8 op, PicturePtr pSrc, PicturePtr pDst,
1147706f2543Smrg               PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
1148706f2543Smrg               int ntrap, xTrapezoid *traps)
1149706f2543Smrg{
1150706f2543Smrg    ScreenPtr		pScreen = pDst->pDrawable->pScreen;
1151706f2543Smrg    PictureScreenPtr    ps = GetPictureScreen(pScreen);
1152706f2543Smrg    BoxRec		bounds;
1153706f2543Smrg
1154706f2543Smrg    if (maskFormat) {
1155706f2543Smrg	PicturePtr	pPicture;
1156706f2543Smrg	INT16		xDst, yDst;
1157706f2543Smrg	INT16		xRel, yRel;
1158706f2543Smrg
1159706f2543Smrg	miTrapezoidBounds (ntrap, traps, &bounds);
1160706f2543Smrg
1161706f2543Smrg	if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
1162706f2543Smrg	    return;
1163706f2543Smrg
1164706f2543Smrg	xDst = traps[0].left.p1.x >> 16;
1165706f2543Smrg	yDst = traps[0].left.p1.y >> 16;
1166706f2543Smrg
1167706f2543Smrg	pPicture = exaCreateAlphaPicture (pScreen, pDst, maskFormat,
1168706f2543Smrg	                                  bounds.x2 - bounds.x1,
1169706f2543Smrg	                                  bounds.y2 - bounds.y1);
1170706f2543Smrg	if (!pPicture)
1171706f2543Smrg	    return;
1172706f2543Smrg
1173706f2543Smrg	exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
1174706f2543Smrg	for (; ntrap; ntrap--, traps++)
1175706f2543Smrg          if (xTrapezoidValid(traps))
1176706f2543Smrg	    (*ps->RasterizeTrapezoid) (pPicture, traps,
1177706f2543Smrg				       -bounds.x1, -bounds.y1);
1178706f2543Smrg	exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
1179706f2543Smrg
1180706f2543Smrg	xRel = bounds.x1 + xSrc - xDst;
1181706f2543Smrg	yRel = bounds.y1 + ySrc - yDst;
1182706f2543Smrg	CompositePicture (op, pSrc, pPicture, pDst,
1183706f2543Smrg			  xRel, yRel, 0, 0, bounds.x1, bounds.y1,
1184706f2543Smrg			  bounds.x2 - bounds.x1,
1185706f2543Smrg			  bounds.y2 - bounds.y1);
1186706f2543Smrg	FreePicture (pPicture, 0);
1187706f2543Smrg    } else {
1188706f2543Smrg	if (pDst->polyEdge == PolyEdgeSharp)
1189706f2543Smrg	    maskFormat = PictureMatchFormat (pScreen, 1, PICT_a1);
1190706f2543Smrg	else
1191706f2543Smrg	    maskFormat = PictureMatchFormat (pScreen, 8, PICT_a8);
1192706f2543Smrg	for (; ntrap; ntrap--, traps++)
1193706f2543Smrg	    exaTrapezoids (op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, traps);
1194706f2543Smrg    }
1195706f2543Smrg}
1196706f2543Smrg
1197706f2543Smrg/**
1198706f2543Smrg * exaTriangles is essentially a copy of miTriangles that uses
1199706f2543Smrg * exaCreateAlphaPicture instead of miCreateAlphaPicture.
1200706f2543Smrg *
1201706f2543Smrg * The problem with miCreateAlphaPicture is that it calls PolyFillRect
1202706f2543Smrg * to initialize the contents after creating the pixmap, which
1203706f2543Smrg * causes the pixmap to be moved in for acceleration. The subsequent
1204706f2543Smrg * call to AddTriangles won't be accelerated however, which forces the pixmap
1205706f2543Smrg * to be moved out again.
1206706f2543Smrg *
1207706f2543Smrg * exaCreateAlphaPicture avoids this roundtrip by using ExaCheckPolyFillRect
1208706f2543Smrg * to initialize the contents.
1209706f2543Smrg */
1210706f2543Smrgvoid
1211706f2543SmrgexaTriangles (CARD8 op, PicturePtr pSrc, PicturePtr pDst,
1212706f2543Smrg	      PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
1213706f2543Smrg	      int ntri, xTriangle *tris)
1214706f2543Smrg{
1215706f2543Smrg    ScreenPtr		pScreen = pDst->pDrawable->pScreen;
1216706f2543Smrg    PictureScreenPtr    ps = GetPictureScreen(pScreen);
1217706f2543Smrg    BoxRec		bounds;
1218706f2543Smrg
1219706f2543Smrg    if (maskFormat) {
1220706f2543Smrg	PicturePtr	pPicture;
1221706f2543Smrg	INT16		xDst, yDst;
1222706f2543Smrg	INT16		xRel, yRel;
1223706f2543Smrg
1224706f2543Smrg	miTriangleBounds (ntri, tris, &bounds);
1225706f2543Smrg
1226706f2543Smrg	if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
1227706f2543Smrg	    return;
1228706f2543Smrg
1229706f2543Smrg	xDst = tris[0].p1.x >> 16;
1230706f2543Smrg	yDst = tris[0].p1.y >> 16;
1231706f2543Smrg
1232706f2543Smrg	pPicture = exaCreateAlphaPicture (pScreen, pDst, maskFormat,
1233706f2543Smrg					  bounds.x2 - bounds.x1,
1234706f2543Smrg					  bounds.y2 - bounds.y1);
1235706f2543Smrg	if (!pPicture)
1236706f2543Smrg	    return;
1237706f2543Smrg
1238706f2543Smrg	exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
1239706f2543Smrg	(*ps->AddTriangles) (pPicture, -bounds.x1, -bounds.y1, ntri, tris);
1240706f2543Smrg	exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
1241706f2543Smrg
1242706f2543Smrg	xRel = bounds.x1 + xSrc - xDst;
1243706f2543Smrg	yRel = bounds.y1 + ySrc - yDst;
1244706f2543Smrg	CompositePicture (op, pSrc, pPicture, pDst,
1245706f2543Smrg			  xRel, yRel, 0, 0, bounds.x1, bounds.y1,
1246706f2543Smrg			  bounds.x2 - bounds.x1, bounds.y2 - bounds.y1);
1247706f2543Smrg	FreePicture (pPicture, 0);
1248706f2543Smrg    } else {
1249706f2543Smrg	if (pDst->polyEdge == PolyEdgeSharp)
1250706f2543Smrg	    maskFormat = PictureMatchFormat (pScreen, 1, PICT_a1);
1251706f2543Smrg	else
1252706f2543Smrg	    maskFormat = PictureMatchFormat (pScreen, 8, PICT_a8);
1253706f2543Smrg
1254706f2543Smrg	for (; ntri; ntri--, tris++)
1255706f2543Smrg	    exaTriangles (op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, tris);
1256706f2543Smrg    }
1257706f2543Smrg}
1258