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