uxa-render.c revision d514b0f3
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 "uxa-priv.h"
32#include <xorgVersion.h>
33
34#ifdef RENDER
35#include "mipict.h"
36
37static void uxa_composite_fallback_pict_desc(PicturePtr pict, char *string,
38					     int n)
39{
40	char format[20];
41	char size[20];
42	char loc;
43
44	if (!pict) {
45		snprintf(string, n, "None");
46		return;
47	}
48
49	if (pict->pDrawable == NULL) {
50		snprintf(string, n, "source-only");
51		return;
52	}
53
54	switch (pict->format) {
55	case PICT_a8r8g8b8:
56		snprintf(format, 20, "ARGB8888");
57		break;
58	case PICT_x8r8g8b8:
59		snprintf(format, 20, "XRGB8888");
60		break;
61	case PICT_r5g6b5:
62		snprintf(format, 20, "RGB565  ");
63		break;
64	case PICT_x1r5g5b5:
65		snprintf(format, 20, "RGB555  ");
66		break;
67	case PICT_a8:
68		snprintf(format, 20, "A8      ");
69		break;
70	case PICT_a1:
71		snprintf(format, 20, "A1      ");
72		break;
73	default:
74		snprintf(format, 20, "0x%x", (int)pict->format);
75		break;
76	}
77
78	loc = uxa_drawable_is_offscreen(pict->pDrawable) ? 's' : 'm';
79
80	snprintf(size, 20, "%dx%d%s", pict->pDrawable->width,
81		 pict->pDrawable->height, pict->repeat ? " R" : "");
82
83	snprintf(string, n, "%p:%c fmt %s (%s)%s",
84		 pict->pDrawable, loc, format, size,
85		 pict->alphaMap ? " with alpha map" :"");
86}
87
88static const char *
89op_to_string(CARD8 op)
90{
91    switch (op) {
92#define C(x) case PictOp##x: return #x
93	C(Clear);
94	C(Src);
95	C(Dst);
96	C(Over);
97	C(OverReverse);
98	C(In);
99	C(InReverse);
100	C(Out);
101	C(OutReverse);
102	C(Atop);
103	C(AtopReverse);
104	C(Xor);
105	C(Add);
106	C(Saturate);
107
108	/*
109	 * Operators only available in version 0.2
110	 */
111	C(DisjointClear);
112	C(DisjointSrc);
113	C(DisjointDst);
114	C(DisjointOver);
115	C(DisjointOverReverse);
116	C(DisjointIn);
117	C(DisjointInReverse);
118	C(DisjointOut);
119	C(DisjointOutReverse);
120	C(DisjointAtop);
121	C(DisjointAtopReverse);
122	C(DisjointXor);
123
124	C(ConjointClear);
125	C(ConjointSrc);
126	C(ConjointDst);
127	C(ConjointOver);
128	C(ConjointOverReverse);
129	C(ConjointIn);
130	C(ConjointInReverse);
131	C(ConjointOut);
132	C(ConjointOutReverse);
133	C(ConjointAtop);
134	C(ConjointAtopReverse);
135	C(ConjointXor);
136
137	/*
138	 * Operators only available in version 0.11
139	 */
140	C(Multiply);
141	C(Screen);
142	C(Overlay);
143	C(Darken);
144	C(Lighten);
145	C(ColorDodge);
146	C(ColorBurn);
147	C(HardLight);
148	C(SoftLight);
149	C(Difference);
150	C(Exclusion);
151	C(HSLHue);
152	C(HSLSaturation);
153	C(HSLColor);
154	C(HSLLuminosity);
155    default: return "garbage";
156#undef C
157    }
158}
159
160static void
161uxa_print_composite_fallback(const char *func, CARD8 op,
162			     PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst)
163{
164	uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen);
165	char srcdesc[40], maskdesc[40], dstdesc[40];
166
167	if (! uxa_screen->fallback_debug)
168		return;
169
170	/* Limit the noise if fallbacks are expected. */
171	if (uxa_screen->force_fallback)
172		return;
173
174	uxa_composite_fallback_pict_desc(pSrc, srcdesc, 40);
175	uxa_composite_fallback_pict_desc(pMask, maskdesc, 40);
176	uxa_composite_fallback_pict_desc(pDst, dstdesc, 40);
177
178	ErrorF("Composite fallback at %s:\n"
179	       "  op   %s, \n"
180	       "  src  %s, \n"
181	       "  mask %s, \n"
182	       "  dst  %s, \n"
183	       "  screen %s\n",
184	       func, op_to_string (op), srcdesc, maskdesc, dstdesc,
185	       uxa_screen->swappedOut ? "swapped out" : "normal");
186}
187
188Bool uxa_op_reads_destination(CARD8 op)
189{
190	/* FALSE (does not read destination) is the list of ops in the protocol
191	 * document with "0" in the "Fb" column and no "Ab" in the "Fa" column.
192	 * That's just Clear and Src.  ReduceCompositeOp() will already have
193	 * converted con/disjoint clear/src to Clear or Src.
194	 */
195	switch (op) {
196	case PictOpClear:
197	case PictOpSrc:
198		return FALSE;
199	default:
200		return TRUE;
201	}
202}
203
204static Bool
205uxa_get_pixel_from_rgba(CARD32 * pixel,
206			CARD16 red,
207			CARD16 green,
208			CARD16 blue,
209			CARD16 alpha,
210			CARD32 format)
211{
212	int rbits, bbits, gbits, abits;
213	int rshift, bshift, gshift, ashift;
214
215	rbits = PICT_FORMAT_R(format);
216	gbits = PICT_FORMAT_G(format);
217	bbits = PICT_FORMAT_B(format);
218	abits = PICT_FORMAT_A(format);
219	if (abits == 0)
220	    abits = PICT_FORMAT_BPP(format) - (rbits+gbits+bbits);
221
222	if (PICT_FORMAT_TYPE(format) == PICT_TYPE_A) {
223		*pixel = alpha >> (16 - abits);
224		return TRUE;
225	}
226
227	if (!PICT_FORMAT_COLOR(format))
228		return FALSE;
229
230	if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
231		bshift = 0;
232		gshift = bbits;
233		rshift = gshift + gbits;
234		ashift = rshift + rbits;
235	} else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ABGR) {
236		rshift = 0;
237		gshift = rbits;
238		bshift = gshift + gbits;
239		ashift = bshift + bbits;
240	} else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_BGRA) {
241		ashift = 0;
242		rshift = abits;
243		gshift = rshift + rbits;
244		bshift = gshift + gbits;
245	} else {
246		return FALSE;
247	}
248
249	*pixel = 0;
250	*pixel |= (blue  >> (16 - bbits)) << bshift;
251	*pixel |= (green >> (16 - gbits)) << gshift;
252	*pixel |= (red   >> (16 - rbits)) << rshift;
253	*pixel |= (alpha >> (16 - abits)) << ashift;
254
255	return TRUE;
256}
257
258Bool
259uxa_get_rgba_from_pixel(CARD32 pixel,
260			CARD16 * red,
261			CARD16 * green,
262			CARD16 * blue,
263			CARD16 * alpha,
264			CARD32 format)
265{
266	int rbits, bbits, gbits, abits;
267	int rshift, bshift, gshift, ashift;
268
269	rbits = PICT_FORMAT_R(format);
270	gbits = PICT_FORMAT_G(format);
271	bbits = PICT_FORMAT_B(format);
272	abits = PICT_FORMAT_A(format);
273
274	if (PICT_FORMAT_TYPE(format) == PICT_TYPE_A) {
275		rshift = gshift = bshift = ashift = 0;
276        } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
277		bshift = 0;
278		gshift = bbits;
279		rshift = gshift + gbits;
280		ashift = rshift + rbits;
281        } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ABGR) {
282		rshift = 0;
283		gshift = rbits;
284		bshift = gshift + gbits;
285		ashift = bshift + bbits;
286        } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_BGRA) {
287		ashift = 0;
288		rshift = abits;
289		if (abits == 0)
290			rshift = PICT_FORMAT_BPP(format) - (rbits+gbits+bbits);
291		gshift = rshift + rbits;
292		bshift = gshift + gbits;
293	} else {
294		return FALSE;
295	}
296
297	if (rbits) {
298		*red = ((pixel >> rshift) & ((1 << rbits) - 1)) << (16 - rbits);
299		while (rbits < 16) {
300			*red |= *red >> rbits;
301			rbits <<= 1;
302		}
303	} else
304		*red = 0;
305
306	if (gbits) {
307		*green = ((pixel >> gshift) & ((1 << gbits) - 1)) << (16 - gbits);
308		while (gbits < 16) {
309			*green |= *green >> gbits;
310			gbits <<= 1;
311		}
312	} else
313		*green = 0;
314
315	if (bbits) {
316		*blue = ((pixel >> bshift) & ((1 << bbits) - 1)) << (16 - bbits);
317		while (bbits < 16) {
318			*blue |= *blue >> bbits;
319			bbits <<= 1;
320		}
321	} else
322		*blue = 0;
323
324	if (abits) {
325		*alpha =
326		    ((pixel >> ashift) & ((1 << abits) - 1)) << (16 - abits);
327		while (abits < 16) {
328			*alpha |= *alpha >> abits;
329			abits <<= 1;
330		}
331	} else
332		*alpha = 0xffff;
333
334	return TRUE;
335}
336
337Bool
338uxa_get_color_for_pixmap (PixmapPtr	 pixmap,
339			  CARD32	 src_format,
340			  CARD32	 dst_format,
341			  CARD32	*pixel)
342{
343	CARD16 red, green, blue, alpha;
344
345	*pixel = uxa_get_pixmap_first_pixel(pixmap);
346
347	if (src_format != dst_format) {
348	    if (!uxa_get_rgba_from_pixel(*pixel,
349					 &red, &green, &blue, &alpha,
350					 src_format))
351		return FALSE;
352
353	    if (!uxa_get_pixel_from_rgba(pixel,
354					 red, green, blue, alpha,
355					 dst_format))
356		return FALSE;
357	}
358
359	return TRUE;
360}
361
362static int
363uxa_try_driver_solid_fill(PicturePtr pSrc,
364			  PicturePtr pDst,
365			  INT16 xSrc,
366			  INT16 ySrc,
367			  INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
368{
369	uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen);
370	RegionRec region;
371	BoxPtr pbox;
372	int nbox;
373	int dst_off_x, dst_off_y;
374	PixmapPtr pSrcPix = NULL, pDstPix;
375	CARD32 pixel;
376
377	if (uxa_screen->info->check_solid && !uxa_screen->info->check_solid(pDst->pDrawable, GXcopy, FB_ALLONES))
378		return -1;
379
380	pDstPix = uxa_get_offscreen_pixmap(pDst->pDrawable, &dst_off_x, &dst_off_y);
381	if (!pDstPix)
382		return -1;
383
384	xDst += pDst->pDrawable->x;
385	yDst += pDst->pDrawable->y;
386
387	if (pSrc->pDrawable) {
388		pSrcPix = uxa_get_drawable_pixmap(pSrc->pDrawable);
389		xSrc += pSrc->pDrawable->x;
390		ySrc += pSrc->pDrawable->y;
391	}
392
393	if (!miComputeCompositeRegion(&region, pSrc, NULL, pDst,
394				      xSrc, ySrc, 0, 0, xDst, yDst,
395				      width, height))
396		return 1;
397
398	if (pSrcPix) {
399		if (! uxa_get_color_for_pixmap (pSrcPix, pSrc->format, pDst->format, &pixel)) {
400			REGION_UNINIT(pDst->pDrawable->pScreen, &region);
401			return -1;
402		}
403	} else {
404		SourcePict *source = pSrc->pSourcePict;
405		PictSolidFill *solid = &source->solidFill;
406
407		if (source == NULL || source->type != SourcePictTypeSolidFill) {
408			REGION_UNINIT(pDst->pDrawable->pScreen, &region);
409			return -1;
410		}
411
412		if (pDst->format == PICT_a8r8g8b8) {
413			pixel = solid->color;
414		} else if (pDst->format == PICT_x8r8g8b8) {
415			pixel = solid->color | 0xff000000;
416		} else {
417			CARD16 red, green, blue, alpha;
418
419			if (!uxa_get_rgba_from_pixel(solid->color,
420						     &red, &green, &blue, &alpha,
421						     PIXMAN_a8r8g8b8) ||
422			    !uxa_get_pixel_from_rgba(&pixel,
423						     red, green, blue, alpha,
424						     pDst->format)) {
425				REGION_UNINIT(pDst->pDrawable->pScreen, &region);
426				return -1;
427			}
428		}
429	}
430
431	if (!(*uxa_screen->info->prepare_solid)
432	    (pDstPix, GXcopy, FB_ALLONES, pixel)) {
433		REGION_UNINIT(pDst->pDrawable->pScreen, &region);
434		return -1;
435	}
436
437	REGION_TRANSLATE(pScreen, &region, dst_off_x, dst_off_y);
438
439	nbox = REGION_NUM_RECTS(&region);
440	pbox = REGION_RECTS(&region);
441
442	while (nbox--) {
443		(*uxa_screen->info->solid) (pDstPix, pbox->x1, pbox->y1,
444					    pbox->x2, pbox->y2);
445		pbox++;
446	}
447
448	(*uxa_screen->info->done_solid) (pDstPix);
449
450	REGION_UNINIT(pDst->pDrawable->pScreen, &region);
451	return 1;
452}
453
454static PicturePtr
455uxa_picture_for_pixman_format(ScreenPtr pScreen,
456			      pixman_format_code_t format,
457			      int width, int height)
458{
459	PicturePtr pPicture;
460	PixmapPtr pPixmap;
461	int error;
462
463	if (format == PIXMAN_a1)
464		format = PIXMAN_a8;
465
466	/* fill alpha if unset */
467	if (PIXMAN_FORMAT_A(format) == 0)
468	    format = PIXMAN_a8r8g8b8;
469
470	pPixmap = (*pScreen->CreatePixmap)(pScreen, width, height,
471					   PIXMAN_FORMAT_DEPTH(format),
472					   UXA_CREATE_PIXMAP_FOR_MAP);
473	if (!pPixmap)
474		return 0;
475
476	pPicture = CreatePicture(0, &pPixmap->drawable,
477				 PictureMatchFormat(pScreen,
478						    PIXMAN_FORMAT_DEPTH(format),
479						    format),
480				 0, 0, serverClient, &error);
481	(*pScreen->DestroyPixmap) (pPixmap);
482	if (!pPicture)
483		return 0;
484
485	ValidatePicture(pPicture);
486
487	return pPicture;
488}
489
490static PicturePtr
491uxa_picture_from_pixman_image(ScreenPtr screen,
492			      pixman_image_t * image,
493			      pixman_format_code_t format)
494{
495	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
496	PicturePtr picture;
497	PixmapPtr pixmap;
498	int width, height;
499
500	width = pixman_image_get_width(image);
501	height = pixman_image_get_height(image);
502
503	picture = uxa_picture_for_pixman_format(screen, format,
504						width, height);
505	if (!picture)
506		return 0;
507
508	if (uxa_screen->info->put_image &&
509	    ((picture->pDrawable->depth << 24) | picture->format) == format &&
510	    uxa_screen->info->put_image((PixmapPtr)picture->pDrawable,
511					0, 0,
512					width, height,
513					(char *)pixman_image_get_data(image),
514					pixman_image_get_stride(image)))
515		return picture;
516
517	pixmap = GetScratchPixmapHeader(screen, width, height,
518					PIXMAN_FORMAT_DEPTH(format),
519					PIXMAN_FORMAT_BPP(format),
520					pixman_image_get_stride(image),
521					pixman_image_get_data(image));
522	if (!pixmap) {
523		FreePicture(picture, 0);
524		return 0;
525	}
526
527	if (((picture->pDrawable->depth << 24) | picture->format) == format) {
528		GCPtr gc;
529
530		gc = GetScratchGC(PIXMAN_FORMAT_DEPTH(format), screen);
531		if (!gc) {
532			FreeScratchPixmapHeader(pixmap);
533			FreePicture(picture, 0);
534			return 0;
535		}
536		ValidateGC(picture->pDrawable, gc);
537
538		(*gc->ops->CopyArea) (&pixmap->drawable, picture->pDrawable,
539				      gc, 0, 0, width, height, 0, 0);
540
541		FreeScratchGC(gc);
542	} else {
543		PicturePtr src;
544		int error;
545
546		src = CreatePicture(0, &pixmap->drawable,
547				    PictureMatchFormat(screen,
548						       PIXMAN_FORMAT_DEPTH(format),
549						       format),
550				    0, 0, serverClient, &error);
551		if (!src) {
552			FreeScratchPixmapHeader(pixmap);
553			FreePicture(picture, 0);
554			return 0;
555		}
556		ValidatePicture(src);
557
558		if (uxa_prepare_access(picture->pDrawable, NULL, UXA_ACCESS_RW)) {
559			fbComposite(PictOpSrc, src, NULL, picture,
560				    0, 0, 0, 0, 0, 0, width, height);
561			uxa_finish_access(picture->pDrawable);
562		}
563
564		FreePicture(src, 0);
565	}
566	FreeScratchPixmapHeader(pixmap);
567
568	return picture;
569}
570
571static PicturePtr
572uxa_create_solid(ScreenPtr screen, uint32_t color)
573{
574	PixmapPtr pixmap;
575	PicturePtr picture;
576	XID repeat = RepeatNormal;
577	int error = 0;
578
579	pixmap = (*screen->CreatePixmap)(screen, 1, 1, 32,
580					 UXA_CREATE_PIXMAP_FOR_MAP);
581	if (!pixmap)
582		return 0;
583
584	if (!uxa_prepare_access((DrawablePtr)pixmap, NULL, UXA_ACCESS_RW)) {
585		(*screen->DestroyPixmap)(pixmap);
586		return 0;
587	}
588	*((uint32_t *)pixmap->devPrivate.ptr) = color;
589	uxa_finish_access((DrawablePtr)pixmap);
590
591	picture = CreatePicture(0, &pixmap->drawable,
592				PictureMatchFormat(screen, 32, PICT_a8r8g8b8),
593				CPRepeat, &repeat, serverClient, &error);
594	(*screen->DestroyPixmap)(pixmap);
595
596	return picture;
597}
598
599static PicturePtr
600uxa_solid_clear(ScreenPtr screen)
601{
602	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
603	PicturePtr picture;
604
605	if (!uxa_screen->solid_clear) {
606		uxa_screen->solid_clear = uxa_create_solid(screen, 0);
607		if (!uxa_screen->solid_clear)
608			return 0;
609	}
610	picture = uxa_screen->solid_clear;
611	return picture;
612}
613
614PicturePtr
615uxa_acquire_solid(ScreenPtr screen, SourcePict *source)
616{
617	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
618	PictSolidFill *solid = &source->solidFill;
619	PicturePtr picture;
620	int i;
621
622	if ((solid->color >> 24) == 0) {
623		picture = uxa_solid_clear(screen);
624		if (!picture)
625		    return 0;
626
627		goto DONE;
628	} else if (solid->color == 0xff000000) {
629		if (!uxa_screen->solid_black) {
630			uxa_screen->solid_black = uxa_create_solid(screen, 0xff000000);
631			if (!uxa_screen->solid_black)
632				return 0;
633		}
634		picture = uxa_screen->solid_black;
635		goto DONE;
636	} else if (solid->color == 0xffffffff) {
637		if (!uxa_screen->solid_white) {
638			uxa_screen->solid_white = uxa_create_solid(screen, 0xffffffff);
639			if (!uxa_screen->solid_white)
640				return 0;
641		}
642		picture = uxa_screen->solid_white;
643		goto DONE;
644	}
645
646	for (i = 0; i < uxa_screen->solid_cache_size; i++) {
647		if (uxa_screen->solid_cache[i].color == solid->color) {
648			picture = uxa_screen->solid_cache[i].picture;
649			goto DONE;
650		}
651	}
652
653	picture = uxa_create_solid(screen, solid->color);
654	if (!picture)
655		return 0;
656
657	if (uxa_screen->solid_cache_size == UXA_NUM_SOLID_CACHE) {
658		i = rand() % UXA_NUM_SOLID_CACHE;
659		FreePicture(uxa_screen->solid_cache[i].picture, 0);
660	} else
661		uxa_screen->solid_cache_size++;
662
663	uxa_screen->solid_cache[i].picture = picture;
664	uxa_screen->solid_cache[i].color = solid->color;
665
666DONE:
667	picture->refcnt++;
668	return picture;
669}
670
671PicturePtr
672uxa_acquire_pattern(ScreenPtr pScreen,
673		    PicturePtr pSrc,
674		    pixman_format_code_t format,
675		    INT16 x, INT16 y, CARD16 width, CARD16 height)
676{
677	PicturePtr pDst;
678
679	if (pSrc->pSourcePict) {
680		SourcePict *source = pSrc->pSourcePict;
681		if (source->type == SourcePictTypeSolidFill)
682			return uxa_acquire_solid (pScreen, source);
683	}
684
685	pDst = uxa_picture_for_pixman_format(pScreen, format, width, height);
686	if (!pDst)
687		return 0;
688
689	if (uxa_prepare_access(pDst->pDrawable, NULL, UXA_ACCESS_RW)) {
690		fbComposite(PictOpSrc, pSrc, NULL, pDst,
691			    x, y, 0, 0, 0, 0, width, height);
692		uxa_finish_access(pDst->pDrawable);
693		return pDst;
694	} else {
695		FreePicture(pDst, 0);
696		return 0;
697	}
698}
699
700static Bool
701transform_is_integer_translation(PictTransformPtr t, int *tx, int *ty)
702{
703	if (t == NULL) {
704		*tx = *ty = 0;
705		return TRUE;
706	}
707
708	if (t->matrix[0][0] != IntToxFixed(1) ||
709	    t->matrix[0][1] != 0 ||
710	    t->matrix[1][0] != 0 ||
711	    t->matrix[1][1] != IntToxFixed(1) ||
712	    t->matrix[2][0] != 0 ||
713	    t->matrix[2][1] != 0 ||
714	    t->matrix[2][2] != IntToxFixed(1))
715		return FALSE;
716
717	if (xFixedFrac(t->matrix[0][2]) != 0 ||
718	    xFixedFrac(t->matrix[1][2]) != 0)
719		return FALSE;
720
721	*tx = xFixedToInt(t->matrix[0][2]);
722	*ty = xFixedToInt(t->matrix[1][2]);
723	return TRUE;
724}
725
726static PicturePtr
727uxa_render_picture(ScreenPtr screen,
728		   PicturePtr src,
729		   pixman_format_code_t format,
730		   INT16 x, INT16 y,
731		   CARD16 width, CARD16 height)
732{
733	PicturePtr picture;
734	int ret = 0;
735
736	/* XXX we need a mechanism for the card to choose the fallback format */
737
738	/* force alpha channel in case source does not entirely cover the extents */
739	if (PIXMAN_FORMAT_A(format) == 0)
740		format = PIXMAN_a8r8g8b8; /* available on all hardware */
741
742	picture = uxa_picture_for_pixman_format(screen, format, width, height);
743	if (!picture)
744		return 0;
745
746	if (uxa_prepare_access(picture->pDrawable, NULL, UXA_ACCESS_RW)) {
747	    if (uxa_prepare_access(src->pDrawable, NULL, UXA_ACCESS_RO)) {
748			ret = 1;
749			fbComposite(PictOpSrc, src, NULL, picture,
750				    x, y, 0, 0, 0, 0, width, height);
751			uxa_finish_access(src->pDrawable);
752		}
753		uxa_finish_access(picture->pDrawable);
754	}
755
756	if (!ret) {
757		FreePicture(picture, 0);
758		return 0;
759	}
760
761	return picture;
762}
763
764PicturePtr
765uxa_acquire_drawable(ScreenPtr pScreen,
766		     PicturePtr pSrc,
767		     INT16 x, INT16 y,
768		     CARD16 width, CARD16 height,
769		     INT16 * out_x, INT16 * out_y)
770{
771	PixmapPtr pPixmap;
772	PicturePtr pDst;
773	GCPtr pGC;
774	int depth, error;
775	int tx, ty;
776
777	depth = pSrc->pDrawable->depth;
778	if (depth == 1 ||
779	    pSrc->filter == PictFilterConvolution || /* XXX */
780	    !transform_is_integer_translation(pSrc->transform, &tx, &ty)) {
781		/* XXX extract the sample extents and do the transformation on the GPU */
782		pDst = uxa_render_picture(pScreen, pSrc,
783					  pSrc->format | (BitsPerPixel(pSrc->pDrawable->depth) << 24),
784					  x, y, width, height);
785
786		goto done;
787	} else {
788		if (width == pSrc->pDrawable->width && height == pSrc->pDrawable->depth) {
789			*out_x = x + pSrc->pDrawable->x;
790			*out_y = y + pSrc->pDrawable->y;
791			return pSrc;
792		}
793	}
794
795	pPixmap = pScreen->CreatePixmap(pScreen,
796					width, height, depth,
797					CREATE_PIXMAP_USAGE_SCRATCH);
798	if (!pPixmap)
799		return 0;
800
801	/* Skip the copy if the result remains in memory and not a bo */
802	if (!uxa_drawable_is_offscreen(&pPixmap->drawable)) {
803		pScreen->DestroyPixmap(pPixmap);
804		return 0;
805	}
806
807	pGC = GetScratchGC(depth, pScreen);
808	if (!pGC) {
809		pScreen->DestroyPixmap(pPixmap);
810		return 0;
811	}
812
813	ValidateGC(&pPixmap->drawable, pGC);
814	pGC->ops->CopyArea(pSrc->pDrawable, &pPixmap->drawable, pGC,
815			   x + tx, y + ty, width, height, 0, 0);
816	FreeScratchGC(pGC);
817
818	pDst = CreatePicture(0, &pPixmap->drawable,
819				 PictureMatchFormat(pScreen, depth, pSrc->format),
820				 0, 0, serverClient, &error);
821	pScreen->DestroyPixmap(pPixmap);
822	ValidatePicture(pDst);
823
824done:
825	pDst->componentAlpha = pSrc->componentAlpha;
826	*out_x = x;
827	*out_y = y;
828	return pDst;
829}
830
831static PicturePtr
832uxa_acquire_picture(ScreenPtr screen,
833		    PicturePtr src,
834		    pixman_format_code_t format,
835		    INT16 x, INT16 y,
836		    CARD16 width, CARD16 height,
837		    INT16 * out_x, INT16 * out_y)
838{
839	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
840
841	if (uxa_screen->info->check_composite_texture &&
842	    uxa_screen->info->check_composite_texture(screen, src)) {
843		if (src->pDrawable) {
844			*out_x = x + src->pDrawable->x;
845			*out_y = y + src->pDrawable->y;
846		} else {
847			*out_x = 0;
848			*out_y = 0;
849		}
850		return src;
851	}
852
853	if (src->pDrawable) {
854		PicturePtr dst;
855
856		dst = uxa_acquire_drawable(screen, src,
857					   x, y, width, height,
858					   out_x, out_y);
859		if (uxa_screen->info->check_composite_texture &&
860		    !uxa_screen->info->check_composite_texture(screen, dst)) {
861			if (dst != src)
862				FreePicture(dst, 0);
863			return 0;
864		}
865
866		return dst;
867	}
868
869	*out_x = 0;
870	*out_y = 0;
871	return uxa_acquire_pattern(screen, src,
872				   format, x, y, width, height);
873}
874
875static PicturePtr
876uxa_acquire_source(ScreenPtr screen,
877		   PicturePtr pict,
878		   INT16 x, INT16 y,
879		   CARD16 width, CARD16 height,
880		   INT16 * out_x, INT16 * out_y)
881{
882	return uxa_acquire_picture (screen, pict,
883				    PIXMAN_a8r8g8b8,
884				    x, y,
885				    width, height,
886				    out_x, out_y);
887}
888
889static PicturePtr
890uxa_acquire_mask(ScreenPtr screen,
891		 PicturePtr pict,
892		 INT16 x, INT16 y,
893		 INT16 width, INT16 height,
894		 INT16 * out_x, INT16 * out_y)
895{
896	return uxa_acquire_picture (screen, pict,
897				    PIXMAN_a8,
898				    x, y,
899				    width, height,
900				    out_x, out_y);
901}
902
903static Bool
904_pixman_region_init_rectangles(pixman_region16_t *region,
905			       int num_rects,
906			       xRectangle *rects,
907			       int tx, int ty)
908{
909	pixman_box16_t stack_boxes[64], *boxes = stack_boxes;
910	pixman_bool_t ret;
911	int i;
912
913	if (num_rects > sizeof(stack_boxes) / sizeof(stack_boxes[0])) {
914		boxes = malloc(sizeof(pixman_box16_t) * num_rects);
915		if (boxes == NULL)
916			return FALSE;
917	}
918
919	for (i = 0; i < num_rects; i++) {
920		boxes[i].x1 = rects[i].x + tx;
921		boxes[i].y1 = rects[i].y + ty;
922		boxes[i].x2 = rects[i].x + tx + rects[i].width;
923		boxes[i].y2 = rects[i].y + ty + rects[i].height;
924	}
925
926	ret = pixman_region_init_rects(region, boxes, num_rects);
927
928	if (boxes != stack_boxes)
929		free(boxes);
930
931	return ret;
932}
933
934void
935uxa_solid_rects (CARD8		op,
936		 PicturePtr	dst,
937		 xRenderColor  *color,
938		 int		num_rects,
939		 xRectangle    *rects)
940{
941	ScreenPtr screen = dst->pDrawable->pScreen;
942	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
943	PixmapPtr dst_pixmap, src_pixmap = NULL;
944	pixman_region16_t region;
945	pixman_box16_t *boxes, *extents;
946	PicturePtr src;
947	int dst_x, dst_y;
948	int num_boxes;
949
950	if (!pixman_region_not_empty(dst->pCompositeClip))
951		return;
952
953	if (dst->alphaMap)
954		goto fallback;
955
956	dst_pixmap = uxa_get_offscreen_pixmap(dst->pDrawable, &dst_x, &dst_y);
957	if (!dst_pixmap)
958		goto fallback;
959
960	if (!_pixman_region_init_rectangles(&region,
961					    num_rects, rects,
962					    dst->pDrawable->x, dst->pDrawable->y))
963		goto fallback;
964
965	if (!pixman_region_intersect(&region, &region, dst->pCompositeClip)) {
966		pixman_region_fini(&region);
967		return;
968	}
969
970	/* XXX xserver-1.8: CompositeRects is not tracked by Damage, so we must
971	 * manually append the damaged regions ourselves.
972	 */
973	DamageRegionAppend(dst->pDrawable, &region);
974
975	pixman_region_translate(&region, dst_x, dst_y);
976	boxes = pixman_region_rectangles(&region, &num_boxes);
977	extents = pixman_region_extents (&region);
978
979	if (op == PictOpClear)
980		color->red = color->green = color->blue = color->alpha = 0;
981	if (color->alpha >= 0xff00 && op == PictOpOver) {
982		color->alpha = 0xffff;
983		op = PictOpSrc;
984	}
985
986	/* Using GEM, the relocation costs outweigh the advantages of the blitter */
987	if (num_boxes == 1 && (op == PictOpSrc || op == PictOpClear)) {
988		CARD32 pixel;
989
990try_solid:
991		if (uxa_screen->info->check_solid &&
992		    !uxa_screen->info->check_solid(&dst_pixmap->drawable, GXcopy, FB_ALLONES))
993			goto err_region;
994
995		if (!uxa_get_pixel_from_rgba(&pixel,
996					     color->red,
997					     color->green,
998					     color->blue,
999					     color->alpha,
1000					     dst->format))
1001			goto err_region;
1002
1003		if (!uxa_screen->info->prepare_solid(dst_pixmap, GXcopy, FB_ALLONES, pixel))
1004			goto err_region;
1005
1006		while (num_boxes--) {
1007			uxa_screen->info->solid(dst_pixmap,
1008						boxes->x1, boxes->y1,
1009						boxes->x2, boxes->y2);
1010			boxes++;
1011		}
1012
1013		uxa_screen->info->done_solid(dst_pixmap);
1014	} else {
1015		int error;
1016
1017		src = CreateSolidPicture(0, color, &error);
1018		if (!src)
1019			goto err_region;
1020
1021		if (!uxa_screen->info->check_composite(op, src, NULL, dst,
1022						       extents->x2 - extents->x1,
1023						       extents->y2 - extents->y1)) {
1024			if (op == PictOpSrc || op == PictOpClear) {
1025				FreePicture(src, 0);
1026				goto try_solid;
1027			}
1028
1029			goto err_src;
1030		}
1031
1032		if (!uxa_screen->info->check_composite_texture ||
1033		    !uxa_screen->info->check_composite_texture(screen, src)) {
1034			PicturePtr solid;
1035			int src_off_x, src_off_y;
1036
1037			solid = uxa_acquire_solid(screen, src->pSourcePict);
1038			FreePicture(src, 0);
1039
1040			src = solid;
1041			src_pixmap = uxa_get_offscreen_pixmap(src->pDrawable,
1042							      &src_off_x, &src_off_y);
1043			if (!src_pixmap)
1044				goto err_src;
1045		}
1046
1047		if (!uxa_screen->info->prepare_composite(op, src, NULL, dst, src_pixmap, NULL, dst_pixmap))
1048			goto err_src;
1049
1050		while (num_boxes--) {
1051			uxa_screen->info->composite(dst_pixmap,
1052						    0, 0, 0, 0,
1053						    boxes->x1,
1054						    boxes->y1,
1055						    boxes->x2 - boxes->x1,
1056						    boxes->y2 - boxes->y1);
1057			boxes++;
1058		}
1059
1060		uxa_screen->info->done_composite(dst_pixmap);
1061		FreePicture(src, 0);
1062	}
1063
1064	pixman_region_fini(&region);
1065	return;
1066
1067err_src:
1068	FreePicture(src, 0);
1069err_region:
1070	pixman_region_fini(&region);
1071fallback:
1072	uxa_screen->SavedCompositeRects(op, dst, color, num_rects, rects);
1073}
1074
1075static int
1076uxa_try_driver_composite(CARD8 op,
1077			 PicturePtr pSrc,
1078			 PicturePtr pMask,
1079			 PicturePtr pDst,
1080			 INT16 xSrc, INT16 ySrc,
1081			 INT16 xMask, INT16 yMask,
1082			 INT16 xDst, INT16 yDst,
1083			 CARD16 width, CARD16 height)
1084{
1085	ScreenPtr screen = pDst->pDrawable->pScreen;
1086	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
1087	RegionRec region;
1088	BoxPtr pbox;
1089	int nbox;
1090	int xDst_copy = 0, yDst_copy = 0;
1091	int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y;
1092	PixmapPtr pSrcPix, pMaskPix = NULL, pDstPix;
1093	PicturePtr localSrc, localMask = NULL;
1094	PicturePtr localDst = pDst;
1095
1096	if (uxa_screen->info->check_composite &&
1097	    !(*uxa_screen->info->check_composite) (op, pSrc, pMask, pDst, width, height))
1098		return -1;
1099
1100	if (uxa_screen->info->check_composite_target &&
1101	    !uxa_screen->info->check_composite_target(uxa_get_drawable_pixmap(pDst->pDrawable))) {
1102		int depth = pDst->pDrawable->depth;
1103		PixmapPtr pixmap;
1104		int error;
1105		GCPtr gc;
1106
1107		pixmap = uxa_get_drawable_pixmap(pDst->pDrawable);
1108		if (uxa_screen->info->check_copy &&
1109		    !uxa_screen->info->check_copy(pixmap, pixmap, GXcopy, FB_ALLONES))
1110			return -1;
1111
1112		pixmap = screen->CreatePixmap(screen,
1113					      width, height, depth,
1114					      CREATE_PIXMAP_USAGE_SCRATCH);
1115		if (!pixmap)
1116			return 0;
1117
1118		gc = GetScratchGC(depth, screen);
1119		if (!gc) {
1120			screen->DestroyPixmap(pixmap);
1121			return 0;
1122		}
1123
1124		ValidateGC(&pixmap->drawable, gc);
1125		gc->ops->CopyArea(pDst->pDrawable, &pixmap->drawable, gc,
1126				  xDst, yDst, width, height, 0, 0);
1127		FreeScratchGC(gc);
1128
1129		xDst_copy = xDst; xDst = 0;
1130		yDst_copy = yDst; yDst = 0;
1131
1132		localDst = CreatePicture(0, &pixmap->drawable,
1133					 PictureMatchFormat(screen, depth, pDst->format),
1134					 0, 0, serverClient, &error);
1135		screen->DestroyPixmap(pixmap);
1136
1137		if (!localDst)
1138			return 0;
1139
1140		ValidatePicture(localDst);
1141	}
1142
1143	pDstPix =
1144	    uxa_get_offscreen_pixmap(localDst->pDrawable, &dst_off_x, &dst_off_y);
1145	if (!pDstPix) {
1146		if (localDst != pDst)
1147			FreePicture(localDst, 0);
1148		return -1;
1149	}
1150
1151	xDst += localDst->pDrawable->x;
1152	yDst += localDst->pDrawable->y;
1153
1154	localSrc = uxa_acquire_source(screen, pSrc,
1155				      xSrc, ySrc,
1156				      width, height,
1157				      &xSrc, &ySrc);
1158	if (!localSrc) {
1159		if (localDst != pDst)
1160			FreePicture(localDst, 0);
1161		return 0;
1162	}
1163
1164	if (pMask) {
1165		localMask = uxa_acquire_mask(screen, pMask,
1166					     xMask, yMask,
1167					     width, height,
1168					     &xMask, &yMask);
1169		if (!localMask) {
1170			if (localSrc != pSrc)
1171				FreePicture(localSrc, 0);
1172			if (localDst != pDst)
1173				FreePicture(localDst, 0);
1174
1175			return 0;
1176		}
1177	}
1178
1179	if (!miComputeCompositeRegion(&region, localSrc, localMask, localDst,
1180				      xSrc, ySrc, xMask, yMask, xDst, yDst,
1181				      width, height)) {
1182		if (localSrc != pSrc)
1183			FreePicture(localSrc, 0);
1184		if (localMask && localMask != pMask)
1185			FreePicture(localMask, 0);
1186		if (localDst != pDst)
1187			FreePicture(localDst, 0);
1188
1189		return 1;
1190	}
1191
1192	if (localSrc->pDrawable) {
1193		pSrcPix = uxa_get_offscreen_pixmap(localSrc->pDrawable,
1194						   &src_off_x, &src_off_y);
1195		if (!pSrcPix) {
1196			REGION_UNINIT(screen, &region);
1197
1198			if (localSrc != pSrc)
1199				FreePicture(localSrc, 0);
1200			if (localMask && localMask != pMask)
1201				FreePicture(localMask, 0);
1202			if (localDst != pDst)
1203				FreePicture(localDst, 0);
1204
1205			return 0;
1206		}
1207	} else {
1208		pSrcPix = NULL;
1209	}
1210
1211	if (localMask) {
1212		if (localMask->pDrawable) {
1213			pMaskPix = uxa_get_offscreen_pixmap(localMask->pDrawable,
1214							    &mask_off_x, &mask_off_y);
1215			if (!pMaskPix) {
1216				REGION_UNINIT(screen, &region);
1217
1218				if (localSrc != pSrc)
1219					FreePicture(localSrc, 0);
1220				if (localMask && localMask != pMask)
1221					FreePicture(localMask, 0);
1222				if (localDst != pDst)
1223					FreePicture(localDst, 0);
1224
1225				return 0;
1226			}
1227		} else {
1228			pMaskPix = NULL;
1229		}
1230	}
1231
1232	if (!(*uxa_screen->info->prepare_composite)
1233	    (op, localSrc, localMask, localDst, pSrcPix, pMaskPix, pDstPix)) {
1234		REGION_UNINIT(screen, &region);
1235
1236		if (localSrc != pSrc)
1237			FreePicture(localSrc, 0);
1238		if (localMask && localMask != pMask)
1239			FreePicture(localMask, 0);
1240		if (localDst != pDst)
1241			FreePicture(localDst, 0);
1242
1243		return -1;
1244	}
1245
1246	if (pMask) {
1247		xMask = xMask + mask_off_x - xDst;
1248		yMask = yMask + mask_off_y - yDst;
1249	}
1250
1251	xSrc = xSrc + src_off_x - xDst;
1252	ySrc = ySrc + src_off_y - yDst;
1253
1254	nbox = REGION_NUM_RECTS(&region);
1255	pbox = REGION_RECTS(&region);
1256	while (nbox--) {
1257		(*uxa_screen->info->composite) (pDstPix,
1258						pbox->x1 + xSrc,
1259						pbox->y1 + ySrc,
1260						pbox->x1 + xMask,
1261						pbox->y1 + yMask,
1262						pbox->x1 + dst_off_x,
1263						pbox->y1 + dst_off_y,
1264						pbox->x2 - pbox->x1,
1265						pbox->y2 - pbox->y1);
1266		pbox++;
1267	}
1268	(*uxa_screen->info->done_composite) (pDstPix);
1269
1270	REGION_UNINIT(screen, &region);
1271
1272	if (localSrc != pSrc)
1273		FreePicture(localSrc, 0);
1274	if (localMask && localMask != pMask)
1275		FreePicture(localMask, 0);
1276
1277	if (localDst != pDst) {
1278		GCPtr gc;
1279
1280		gc = GetScratchGC(pDst->pDrawable->depth, screen);
1281		if (gc) {
1282			ValidateGC(pDst->pDrawable, gc);
1283			gc->ops->CopyArea(localDst->pDrawable, pDst->pDrawable, gc,
1284					  0, 0, width, height, xDst_copy, yDst_copy);
1285			FreeScratchGC(gc);
1286		}
1287
1288		FreePicture(localDst, 0);
1289	}
1290
1291	return 1;
1292}
1293
1294/**
1295 * uxa_try_magic_two_pass_composite_helper implements PictOpOver using two passes of
1296 * simpler operations PictOpOutReverse and PictOpAdd. Mainly used for component
1297 * alpha and limited 1-tmu cards.
1298 *
1299 * From http://anholt.livejournal.com/32058.html:
1300 *
1301 * The trouble is that component-alpha rendering requires two different sources
1302 * for blending: one for the source value to the blender, which is the
1303 * per-channel multiplication of source and mask, and one for the source alpha
1304 * for multiplying with the destination channels, which is the multiplication
1305 * of the source channels by the mask alpha. So the equation for Over is:
1306 *
1307 * dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A
1308 * dst.R = src.R * mask.R + (1 - (src.A * mask.R)) * dst.R
1309 * dst.G = src.G * mask.G + (1 - (src.A * mask.G)) * dst.G
1310 * dst.B = src.B * mask.B + (1 - (src.A * mask.B)) * dst.B
1311 *
1312 * But we can do some simpler operations, right? How about PictOpOutReverse,
1313 * which has a source factor of 0 and dest factor of (1 - source alpha). We
1314 * can get the source alpha value (srca.X = src.A * mask.X) out of the texture
1315 * blenders pretty easily. So we can do a component-alpha OutReverse, which
1316 * gets us:
1317 *
1318 * dst.A = 0 + (1 - (src.A * mask.A)) * dst.A
1319 * dst.R = 0 + (1 - (src.A * mask.R)) * dst.R
1320 * dst.G = 0 + (1 - (src.A * mask.G)) * dst.G
1321 * dst.B = 0 + (1 - (src.A * mask.B)) * dst.B
1322 *
1323 * OK. And if an op doesn't use the source alpha value for the destination
1324 * factor, then we can do the channel multiplication in the texture blenders
1325 * to get the source value, and ignore the source alpha that we wouldn't use.
1326 * We've supported this in the Radeon driver for a long time. An example would
1327 * be PictOpAdd, which does:
1328 *
1329 * dst.A = src.A * mask.A + dst.A
1330 * dst.R = src.R * mask.R + dst.R
1331 * dst.G = src.G * mask.G + dst.G
1332 * dst.B = src.B * mask.B + dst.B
1333 *
1334 * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right
1335 * after it, we get:
1336 *
1337 * dst.A = src.A * mask.A + ((1 - (src.A * mask.A)) * dst.A)
1338 * dst.R = src.R * mask.R + ((1 - (src.A * mask.R)) * dst.R)
1339 * dst.G = src.G * mask.G + ((1 - (src.A * mask.G)) * dst.G)
1340 * dst.B = src.B * mask.B + ((1 - (src.A * mask.B)) * dst.B)
1341 */
1342
1343static int
1344uxa_try_magic_two_pass_composite_helper(CARD8 op,
1345					PicturePtr pSrc,
1346					PicturePtr pMask,
1347					PicturePtr pDst,
1348					INT16 xSrc, INT16 ySrc,
1349					INT16 xMask, INT16 yMask,
1350					INT16 xDst, INT16 yDst,
1351					CARD16 width, CARD16 height)
1352{
1353	ScreenPtr screen = pDst->pDrawable->pScreen;
1354	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
1355	PicturePtr localDst = pDst;
1356	int xDst_copy = 0, yDst_copy = 0;
1357
1358	assert(op == PictOpOver);
1359
1360	if (uxa_screen->info->check_composite &&
1361	    (!(*uxa_screen->info->check_composite) (PictOpOutReverse, pSrc,
1362						    pMask, pDst, width, height)
1363	     || !(*uxa_screen->info->check_composite) (PictOpAdd, pSrc, pMask,
1364						       pDst, width, height))) {
1365		return -1;
1366	}
1367
1368	if (uxa_screen->info->check_composite_target &&
1369	    !uxa_screen->info->check_composite_target(uxa_get_drawable_pixmap(pDst->pDrawable))) {
1370		int depth = pDst->pDrawable->depth;
1371		PixmapPtr pixmap;
1372		int error;
1373		GCPtr gc;
1374
1375		pixmap = uxa_get_drawable_pixmap(pDst->pDrawable);
1376		if (uxa_screen->info->check_copy &&
1377		    !uxa_screen->info->check_copy(pixmap, pixmap, GXcopy, FB_ALLONES))
1378			return -1;
1379
1380		pixmap = screen->CreatePixmap(screen,
1381					      width, height, depth,
1382					      CREATE_PIXMAP_USAGE_SCRATCH);
1383		if (!pixmap)
1384			return 0;
1385
1386		gc = GetScratchGC(depth, screen);
1387		if (!gc) {
1388			screen->DestroyPixmap(pixmap);
1389			return 0;
1390		}
1391
1392		ValidateGC(&pixmap->drawable, gc);
1393		gc->ops->CopyArea(pDst->pDrawable, &pixmap->drawable, gc,
1394				  xDst, yDst, width, height, 0, 0);
1395		FreeScratchGC(gc);
1396
1397		xDst_copy = xDst; xDst = 0;
1398		yDst_copy = yDst; yDst = 0;
1399
1400		localDst = CreatePicture(0, &pixmap->drawable,
1401					 PictureMatchFormat(screen, depth, pDst->format),
1402					 0, 0, serverClient, &error);
1403		screen->DestroyPixmap(pixmap);
1404
1405		if (!localDst)
1406			return 0;
1407
1408		ValidatePicture(localDst);
1409	}
1410
1411	/* Now, we think we should be able to accelerate this operation. First,
1412	 * composite the destination to be the destination times the source alpha
1413	 * factors.
1414	 */
1415	uxa_composite(PictOpOutReverse, pSrc, pMask, localDst,
1416		      xSrc, ySrc,
1417		      xMask, yMask,
1418		      xDst, yDst,
1419		      width, height);
1420
1421	/* Then, add in the source value times the destination alpha factors (1.0).
1422	 */
1423	uxa_composite(PictOpAdd, pSrc, pMask, localDst,
1424		      xSrc, ySrc,
1425		      xMask, yMask,
1426		      xDst, yDst,
1427		      width, height);
1428
1429	if (localDst != pDst) {
1430		GCPtr gc;
1431
1432		gc = GetScratchGC(pDst->pDrawable->depth, screen);
1433		if (gc) {
1434			ValidateGC(pDst->pDrawable, gc);
1435			gc->ops->CopyArea(localDst->pDrawable, pDst->pDrawable, gc,
1436					0, 0, width, height, xDst_copy, yDst_copy);
1437			FreeScratchGC(gc);
1438		}
1439
1440		FreePicture(localDst, 0);
1441	}
1442
1443	return 1;
1444}
1445
1446static int
1447compatible_formats (CARD8 op, PicturePtr dst, PicturePtr src)
1448{
1449	if (op == PictOpSrc) {
1450		if (src->format == dst->format)
1451			return 1;
1452
1453		/* Is the destination an alpha-less version of source? */
1454		if (dst->format == PICT_FORMAT(PICT_FORMAT_BPP(src->format),
1455					       PICT_FORMAT_TYPE(src->format),
1456					       0,
1457					       PICT_FORMAT_R(src->format),
1458					       PICT_FORMAT_G(src->format),
1459					       PICT_FORMAT_B(src->format)))
1460			return 1;
1461
1462		/* XXX xrgb is promoted to argb during image upload... */
1463#if 0
1464		if (dst->format == PICT_a8r8g8b8 && src->format == PICT_x8r8g8b8)
1465			return 1;
1466#endif
1467	} else if (op == PictOpOver) {
1468		if (PICT_FORMAT_A(src->format))
1469			return 0;
1470
1471		return src->format == dst->format;
1472	}
1473
1474	return 0;
1475}
1476
1477static int
1478drawable_contains (DrawablePtr drawable, int x, int y, int w, int h)
1479{
1480	if (x < 0 || y < 0)
1481		return FALSE;
1482
1483	if (x + w > drawable->width)
1484		return FALSE;
1485
1486	if (y + h > drawable->height)
1487		return FALSE;
1488
1489	return TRUE;
1490}
1491
1492void
1493uxa_composite(CARD8 op,
1494	      PicturePtr pSrc,
1495	      PicturePtr pMask,
1496	      PicturePtr pDst,
1497	      INT16 xSrc, INT16 ySrc,
1498	      INT16 xMask, INT16 yMask,
1499	      INT16 xDst, INT16 yDst,
1500	      CARD16 width, CARD16 height)
1501{
1502	uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen);
1503	int ret = -1;
1504	Bool saveSrcRepeat = pSrc->repeat;
1505	Bool saveMaskRepeat = pMask ? pMask->repeat : 0;
1506	RegionRec region;
1507	int tx, ty;
1508
1509	if (uxa_screen->swappedOut || uxa_screen->force_fallback)
1510		goto fallback;
1511
1512	if (!uxa_drawable_is_offscreen(pDst->pDrawable))
1513		goto fallback;
1514
1515	if (pDst->alphaMap || pSrc->alphaMap || (pMask && pMask->alphaMap))
1516		goto fallback;
1517
1518	/* Remove repeat in source if useless */
1519	if (pSrc->pDrawable && pSrc->repeat && pSrc->filter != PictFilterConvolution &&
1520	    transform_is_integer_translation(pSrc->transform, &tx, &ty) &&
1521	    (pSrc->pDrawable->width > 1 || pSrc->pDrawable->height > 1) &&
1522	    drawable_contains(pSrc->pDrawable, xSrc + tx, ySrc + ty, width, height))
1523		pSrc->repeat = 0;
1524
1525	if (!pMask) {
1526		if (op == PictOpClear) {
1527			PicturePtr clear = uxa_solid_clear(pDst->pDrawable->pScreen);
1528			if (clear &&
1529			    uxa_try_driver_solid_fill(clear, pDst,
1530						      xSrc, ySrc,
1531						      xDst, yDst,
1532						      width, height) == 1)
1533				goto done;
1534		}
1535
1536		if (pSrc->pDrawable == NULL) {
1537			if (pSrc->pSourcePict) {
1538				SourcePict *source = pSrc->pSourcePict;
1539				if (source->type == SourcePictTypeSolidFill) {
1540					if (op == PictOpSrc ||
1541					    (op == PictOpOver &&
1542					     (source->solidFill.color & 0xff000000) == 0xff000000)) {
1543						ret = uxa_try_driver_solid_fill(pSrc, pDst,
1544										xSrc, ySrc,
1545										xDst, yDst,
1546										width, height);
1547						if (ret == 1)
1548							goto done;
1549					}
1550				}
1551			}
1552		} else if (pSrc->pDrawable->width == 1 &&
1553			   pSrc->pDrawable->height == 1 &&
1554			   pSrc->repeat &&
1555			   (op == PictOpSrc || (op == PictOpOver && !PICT_FORMAT_A(pSrc->format)))) {
1556			ret = uxa_try_driver_solid_fill(pSrc, pDst,
1557							xSrc, ySrc,
1558							xDst, yDst,
1559							width, height);
1560			if (ret == 1)
1561				goto done;
1562		} else if (compatible_formats (op, pDst, pSrc) &&
1563			   pSrc->filter != PictFilterConvolution &&
1564			   transform_is_integer_translation(pSrc->transform, &tx, &ty)) {
1565			if (!pSrc->repeat &&
1566			    drawable_contains(pSrc->pDrawable,
1567					     xSrc + tx, ySrc + ty,
1568					     width, height)) {
1569				xDst += pDst->pDrawable->x;
1570				yDst += pDst->pDrawable->y;
1571				xSrc += pSrc->pDrawable->x + tx;
1572				ySrc += pSrc->pDrawable->y + ty;
1573
1574				if (!miComputeCompositeRegion
1575				    (&region, pSrc, pMask, pDst, xSrc, ySrc,
1576				     xMask, yMask, xDst, yDst, width, height))
1577					goto done;
1578
1579				uxa_copy_n_to_n(pSrc->pDrawable,
1580						pDst->pDrawable, NULL,
1581						REGION_RECTS(&region),
1582						REGION_NUM_RECTS(&region),
1583						xSrc - xDst, ySrc - yDst, FALSE,
1584						FALSE, 0, NULL);
1585				REGION_UNINIT(pDst->pDrawable->pScreen,
1586					      &region);
1587				goto done;
1588			} else if (pSrc->repeat && pSrc->repeatType == RepeatNormal &&
1589				   pSrc->pDrawable->type == DRAWABLE_PIXMAP) {
1590				DDXPointRec patOrg;
1591
1592				/* Let's see if the driver can do the repeat
1593				 * in one go
1594				 */
1595				if (uxa_screen->info->prepare_composite) {
1596					ret = uxa_try_driver_composite(op, pSrc,
1597								       pMask, pDst,
1598								       xSrc, ySrc,
1599								       xMask, yMask,
1600								       xDst, yDst,
1601								       width, height);
1602					if (ret == 1)
1603						goto done;
1604				}
1605
1606				/* Now see if we can use
1607				 * uxa_fill_region_tiled()
1608				 */
1609				xDst += pDst->pDrawable->x;
1610				yDst += pDst->pDrawable->y;
1611				xSrc += pSrc->pDrawable->x + tx;
1612				ySrc += pSrc->pDrawable->y + ty;
1613
1614				if (!miComputeCompositeRegion
1615				    (&region, pSrc, pMask, pDst, xSrc, ySrc,
1616				     xMask, yMask, xDst, yDst, width, height))
1617					goto done;
1618
1619				/* pattern origin is the point in the
1620				 * destination drawable
1621				 * corresponding to (0,0) in the source */
1622				patOrg.x = xDst - xSrc;
1623				patOrg.y = yDst - ySrc;
1624
1625				ret = uxa_fill_region_tiled(pDst->pDrawable,
1626							    &region,
1627							    (PixmapPtr) pSrc->
1628							    pDrawable, &patOrg,
1629							    FB_ALLONES, GXcopy);
1630
1631				REGION_UNINIT(pDst->pDrawable->pScreen,
1632					      &region);
1633
1634				if (ret)
1635					goto done;
1636			}
1637		}
1638	}
1639
1640	/* Remove repeat in mask if useless */
1641	if (pMask && pMask->pDrawable && pMask->repeat &&
1642	    pMask->filter != PictFilterConvolution &&
1643	    transform_is_integer_translation(pMask->transform, &tx, &ty) &&
1644	    (pMask->pDrawable->width > 1 || pMask->pDrawable->height > 1) &&
1645	    drawable_contains(pMask->pDrawable, xMask + tx, yMask + ty, width, height))
1646		pMask->repeat = 0;
1647
1648	if (uxa_screen->info->prepare_composite) {
1649		Bool isSrcSolid;
1650
1651		ret =
1652		    uxa_try_driver_composite(op, pSrc, pMask, pDst, xSrc, ySrc,
1653					     xMask, yMask, xDst, yDst, width,
1654					     height);
1655		if (ret == 1)
1656			goto done;
1657
1658		/* For generic masks and solid src pictures, mach64 can do
1659		 * Over in two passes, similar to the component-alpha case.
1660		 */
1661
1662		isSrcSolid =
1663			pSrc->pDrawable ?
1664				pSrc->pDrawable->width == 1 &&
1665				pSrc->pDrawable->height == 1 &&
1666				pSrc->repeat :
1667			pSrc->pSourcePict ?
1668				pSrc->pSourcePict->type == SourcePictTypeSolidFill :
1669			0;
1670
1671		/* If we couldn't do the Composite in a single pass, and it
1672		 * was a component-alpha Over, see if we can do it in two
1673		 * passes with an OutReverse and then an Add.
1674		 */
1675		if (ret == -1 && op == PictOpOver && pMask &&
1676		    (pMask->componentAlpha || isSrcSolid)) {
1677			ret =
1678			    uxa_try_magic_two_pass_composite_helper(op, pSrc,
1679								    pMask, pDst,
1680								    xSrc, ySrc,
1681								    xMask, yMask,
1682								    xDst, yDst,
1683								    width, height);
1684			if (ret == 1)
1685				goto done;
1686		}
1687
1688	}
1689
1690fallback:
1691	uxa_print_composite_fallback("uxa_composite",
1692				     op, pSrc, pMask, pDst);
1693
1694	uxa_check_composite(op, pSrc, pMask, pDst, xSrc, ySrc,
1695			    xMask, yMask, xDst, yDst, width, height);
1696
1697done:
1698	pSrc->repeat = saveSrcRepeat;
1699	if (pMask)
1700		pMask->repeat = saveMaskRepeat;
1701}
1702#endif
1703
1704/**
1705 * Same as miCreateAlphaPicture, except it uses uxa_check_poly_fill_rect instead
1706 * of PolyFillRect to initialize the pixmap after creating it, to prevent
1707 * the pixmap from being migrated.
1708 *
1709 * See the comments about uxa_trapezoids and uxa_triangles.
1710 */
1711static PicturePtr
1712uxa_create_alpha_picture(ScreenPtr pScreen,
1713			 PicturePtr pDst,
1714			 PictFormatPtr pPictFormat, CARD16 width, CARD16 height)
1715{
1716	PixmapPtr pPixmap;
1717	PicturePtr pPicture;
1718	int error;
1719
1720	if (width > 32767 || height > 32767)
1721		return 0;
1722
1723	if (!pPictFormat) {
1724		if (pDst->polyEdge == PolyEdgeSharp)
1725			pPictFormat = PictureMatchFormat(pScreen, 1, PICT_a1);
1726		else
1727			pPictFormat = PictureMatchFormat(pScreen, 8, PICT_a8);
1728		if (!pPictFormat)
1729			return 0;
1730	}
1731
1732	pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
1733					    pPictFormat->depth,
1734					    UXA_CREATE_PIXMAP_FOR_MAP);
1735	if (!pPixmap)
1736		return 0;
1737	pPicture = CreatePicture(0, &pPixmap->drawable, pPictFormat,
1738				 0, 0, serverClient, &error);
1739	(*pScreen->DestroyPixmap) (pPixmap);
1740	return pPicture;
1741}
1742
1743/**
1744 * uxa_trapezoids is essentially a copy of miTrapezoids that uses
1745 * uxa_create_alpha_picture instead of miCreateAlphaPicture.
1746 *
1747 * The problem with miCreateAlphaPicture is that it calls PolyFillRect
1748 * to initialize the contents after creating the pixmap, which
1749 * causes the pixmap to be moved in for acceleration. The subsequent
1750 * call to RasterizeTrapezoid won't be accelerated however, which
1751 * forces the pixmap to be moved out again.
1752 *
1753 * uxa_create_alpha_picture avoids this roundtrip by using
1754 * uxa_check_poly_fill_rect to initialize the contents.
1755 */
1756void
1757uxa_trapezoids(CARD8 op, PicturePtr src, PicturePtr dst,
1758	       PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
1759	       int ntrap, xTrapezoid * traps)
1760{
1761	ScreenPtr screen = dst->pDrawable->pScreen;
1762	BoxRec bounds;
1763	Bool direct;
1764
1765	direct = op == PictOpAdd && miIsSolidAlpha(src);
1766	if (maskFormat || direct) {
1767		miTrapezoidBounds(ntrap, traps, &bounds);
1768
1769		if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
1770			return;
1771	}
1772
1773	/*
1774	 * Check for solid alpha add
1775	 */
1776	if (direct) {
1777		DrawablePtr pDraw = dst->pDrawable;
1778		PixmapPtr pixmap = uxa_get_drawable_pixmap(pDraw);
1779		int xoff, yoff;
1780
1781		uxa_get_drawable_deltas(pDraw, pixmap, &xoff, &yoff);
1782
1783		xoff += pDraw->x;
1784		yoff += pDraw->y;
1785
1786		if (uxa_prepare_access(pDraw, NULL, UXA_ACCESS_RW)) {
1787			PictureScreenPtr ps = GetPictureScreen(screen);
1788
1789			for (; ntrap; ntrap--, traps++)
1790				(*ps->RasterizeTrapezoid) (dst, traps, 0, 0);
1791			uxa_finish_access(pDraw);
1792		}
1793	} else if (maskFormat) {
1794		PixmapPtr scratch = NULL;
1795		PicturePtr mask;
1796		INT16 xDst, yDst;
1797		INT16 xRel, yRel;
1798		int width, height;
1799		pixman_image_t *image;
1800		pixman_format_code_t format;
1801
1802		xDst = traps[0].left.p1.x >> 16;
1803		yDst = traps[0].left.p1.y >> 16;
1804
1805		width  = bounds.x2 - bounds.x1;
1806		height = bounds.y2 - bounds.y1;
1807
1808		format = maskFormat->format |
1809			(BitsPerPixel(maskFormat->depth) << 24);
1810		image =
1811		    pixman_image_create_bits(format, width, height, NULL, 0);
1812		if (!image)
1813			return;
1814
1815		for (; ntrap; ntrap--, traps++)
1816			pixman_rasterize_trapezoid(image,
1817						   (pixman_trapezoid_t *) traps,
1818						   -bounds.x1, -bounds.y1);
1819		if (uxa_drawable_is_offscreen(dst->pDrawable)) {
1820			mask = uxa_picture_from_pixman_image(screen, image, format);
1821		} else {
1822			int error;
1823
1824			scratch = GetScratchPixmapHeader(screen, width, height,
1825							PIXMAN_FORMAT_DEPTH(format),
1826							PIXMAN_FORMAT_BPP(format),
1827							pixman_image_get_stride(image),
1828							pixman_image_get_data(image));
1829			mask = CreatePicture(0, &scratch->drawable,
1830					     PictureMatchFormat(screen,
1831								PIXMAN_FORMAT_DEPTH(format),
1832								format),
1833					     0, 0, serverClient, &error);
1834		}
1835		if (!mask) {
1836			if (scratch)
1837				FreeScratchPixmapHeader(scratch);
1838			pixman_image_unref(image);
1839			return;
1840		}
1841
1842		xRel = bounds.x1 + xSrc - xDst;
1843		yRel = bounds.y1 + ySrc - yDst;
1844		CompositePicture(op, src, mask, dst,
1845				 xRel, yRel,
1846				 0, 0,
1847				 bounds.x1, bounds.y1,
1848				 width, height);
1849		FreePicture(mask, 0);
1850
1851		if (scratch)
1852			FreeScratchPixmapHeader(scratch);
1853		pixman_image_unref(image);
1854	} else {
1855		if (dst->polyEdge == PolyEdgeSharp)
1856			maskFormat = PictureMatchFormat(screen, 1, PICT_a1);
1857		else
1858			maskFormat = PictureMatchFormat(screen, 8, PICT_a8);
1859		for (; ntrap; ntrap--, traps++)
1860			uxa_trapezoids(op, src, dst, maskFormat, xSrc, ySrc,
1861				       1, traps);
1862	}
1863}
1864
1865/**
1866 * uxa_triangles is essentially a copy of miTriangles that uses
1867 * uxa_create_alpha_picture instead of miCreateAlphaPicture.
1868 *
1869 * The problem with miCreateAlphaPicture is that it calls PolyFillRect
1870 * to initialize the contents after creating the pixmap, which
1871 * causes the pixmap to be moved in for acceleration. The subsequent
1872 * call to AddTriangles won't be accelerated however, which forces the pixmap
1873 * to be moved out again.
1874 *
1875 * uxa_create_alpha_picture avoids this roundtrip by using
1876 * uxa_check_poly_fill_rect to initialize the contents.
1877 */
1878void
1879uxa_triangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
1880	      PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
1881	      int ntri, xTriangle * tris)
1882{
1883	ScreenPtr pScreen = pDst->pDrawable->pScreen;
1884	PictureScreenPtr ps = GetPictureScreen(pScreen);
1885	BoxRec bounds;
1886	Bool direct = op == PictOpAdd && miIsSolidAlpha(pSrc);
1887
1888	if (maskFormat || direct) {
1889		miTriangleBounds(ntri, tris, &bounds);
1890
1891		if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
1892			return;
1893	}
1894
1895	/*
1896	 * Check for solid alpha add
1897	 */
1898	if (direct) {
1899		DrawablePtr pDraw = pDst->pDrawable;
1900		if (uxa_prepare_access(pDraw, NULL, UXA_ACCESS_RW)) {
1901			(*ps->AddTriangles) (pDst, 0, 0, ntri, tris);
1902			uxa_finish_access(pDraw);
1903		}
1904	} else if (maskFormat) {
1905		PicturePtr pPicture;
1906		INT16 xDst, yDst;
1907		INT16 xRel, yRel;
1908		int width = bounds.x2 - bounds.x1;
1909		int height = bounds.y2 - bounds.y1;
1910		GCPtr pGC;
1911		xRectangle rect;
1912
1913		xDst = tris[0].p1.x >> 16;
1914		yDst = tris[0].p1.y >> 16;
1915
1916		pPicture = uxa_create_alpha_picture(pScreen, pDst, maskFormat,
1917						    width, height);
1918		if (!pPicture)
1919			return;
1920
1921		/* Clear the alpha picture to 0. */
1922		pGC = GetScratchGC(pPicture->pDrawable->depth, pScreen);
1923		if (!pGC) {
1924			FreePicture(pPicture, 0);
1925			return;
1926		}
1927		ValidateGC(pPicture->pDrawable, pGC);
1928		rect.x = 0;
1929		rect.y = 0;
1930		rect.width = width;
1931		rect.height = height;
1932		uxa_check_poly_fill_rect(pPicture->pDrawable, pGC, 1, &rect);
1933		FreeScratchGC(pGC);
1934
1935		if (uxa_prepare_access(pPicture->pDrawable, NULL, UXA_ACCESS_RW)) {
1936			(*ps->AddTriangles) (pPicture, -bounds.x1, -bounds.y1,
1937					     ntri, tris);
1938			uxa_finish_access(pPicture->pDrawable);
1939		}
1940
1941		xRel = bounds.x1 + xSrc - xDst;
1942		yRel = bounds.y1 + ySrc - yDst;
1943		CompositePicture(op, pSrc, pPicture, pDst,
1944				 xRel, yRel, 0, 0, bounds.x1, bounds.y1,
1945				 bounds.x2 - bounds.x1, bounds.y2 - bounds.y1);
1946		FreePicture(pPicture, 0);
1947	} else {
1948		if (pDst->polyEdge == PolyEdgeSharp)
1949			maskFormat = PictureMatchFormat(pScreen, 1, PICT_a1);
1950		else
1951			maskFormat = PictureMatchFormat(pScreen, 8, PICT_a8);
1952
1953		for (; ntri; ntri--, tris++)
1954			uxa_triangles(op, pSrc, pDst, maskFormat, xSrc, ySrc, 1,
1955				      tris);
1956	}
1957}
1958