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