1/*
2 * Copyright (c) 2007  David Turner
3 * Copyright (c) 2008  M Joonas Pihlaja
4 * Copyright (c) 2011 Intel Corporation
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
15 * Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 *
25 * Authors:
26 *    Chris Wilson <chris@chris-wilson.co.uk>
27 *
28 */
29
30#ifdef HAVE_CONFIG_H
31#include "config.h"
32#endif
33
34#include "sna.h"
35#include "sna_render.h"
36#include "sna_render_inline.h"
37#include "sna_trapezoids.h"
38#include "fb/fbpict.h"
39
40#include <mipict.h>
41
42/* TODO: Emit unantialiased and MSAA triangles. */
43
44#ifndef MAX
45#define MAX(x,y) ((x) >= (y) ? (x) : (y))
46#endif
47
48#ifndef MIN
49#define MIN(x,y) ((x) <= (y) ? (x) : (y))
50#endif
51
52#define region_count(r) ((r)->data ? (r)->data->numRects : 1)
53#define region_boxes(r) ((r)->data ? (BoxPtr)((r)->data + 1) : &(r)->extents)
54
55#if HAS_DEBUG_FULL
56static void _assert_pixmap_contains_box(PixmapPtr pixmap, BoxPtr box, const char *function)
57{
58	if (box->x1 < 0 || box->y1 < 0 ||
59	    box->x2 > pixmap->drawable.width ||
60	    box->y2 > pixmap->drawable.height)
61	{
62		FatalError("%s: damage box is beyond the pixmap: box=(%d, %d), (%d, %d), pixmap=(%d, %d)\n",
63			   function,
64			   box->x1, box->y1, box->x2, box->y2,
65			   pixmap->drawable.width,
66			   pixmap->drawable.height);
67	}
68}
69#define assert_pixmap_contains_box(p, b) _assert_pixmap_contains_box(p, b, __FUNCTION__)
70#else
71#define assert_pixmap_contains_box(p, b)
72#endif
73
74static void apply_damage(struct sna_composite_op *op, RegionPtr region)
75{
76	DBG(("%s: damage=%p, region=%dx[(%d, %d), (%d, %d)]\n",
77	     __FUNCTION__, op->damage,
78	     region_num_rects(region),
79	     region->extents.x1, region->extents.y1,
80	     region->extents.x2, region->extents.y2));
81
82	if (op->damage == NULL)
83		return;
84
85	RegionTranslate(region, op->dst.x, op->dst.y);
86
87	assert_pixmap_contains_box(op->dst.pixmap, RegionExtents(region));
88	if (sna_damage_add_to_pixmap(op->damage, region, op->dst.pixmap))
89		op->damage = NULL;
90}
91
92static void _apply_damage_box(struct sna_composite_op *op, const BoxRec *box)
93{
94	BoxRec r;
95
96	r.x1 = box->x1 + op->dst.x;
97	r.x2 = box->x2 + op->dst.x;
98	r.y1 = box->y1 + op->dst.y;
99	r.y2 = box->y2 + op->dst.y;
100
101	assert_pixmap_contains_box(op->dst.pixmap, &r);
102	sna_damage_add_box(op->damage, &r);
103}
104
105inline static void apply_damage_box(struct sna_composite_op *op, const BoxRec *box)
106{
107	if (op->damage)
108		_apply_damage_box(op, box);
109}
110
111bool
112composite_aligned_boxes(struct sna *sna,
113			CARD8 op,
114			PicturePtr src,
115			PicturePtr dst,
116			PictFormatPtr maskFormat,
117			INT16 src_x, INT16 src_y,
118			int ntrap, const xTrapezoid *traps,
119			bool force_fallback)
120{
121	BoxRec stack_boxes[64], *boxes;
122	pixman_region16_t region, clip;
123	struct sna_composite_op tmp;
124	int16_t dst_x, dst_y;
125	bool ret = true;
126	int dx, dy, n, num_boxes;
127
128	if (NO_ALIGNED_BOXES)
129		return false;
130
131	DBG(("%s: pixmap=%ld, nboxes=%d, dx=(%d, %d)\n", __FUNCTION__,
132	    get_drawable_pixmap(dst->pDrawable)->drawable.serialNumber,
133	    ntrap, dst->pDrawable->x, dst->pDrawable->y));
134
135	boxes = stack_boxes;
136	if (ntrap > (int)ARRAY_SIZE(stack_boxes)) {
137		boxes = malloc(sizeof(BoxRec)*ntrap);
138		if (boxes == NULL)
139			return false;
140	}
141
142	dx = dst->pDrawable->x;
143	dy = dst->pDrawable->y;
144
145	region.extents.x1 = region.extents.y1 = 32767;
146	region.extents.x2 = region.extents.y2 = -32767;
147	num_boxes = 0;
148	for (n = 0; n < ntrap; n++) {
149		boxes[num_boxes].x1 = dx + pixman_fixed_to_int(traps[n].left.p1.x + pixman_fixed_1_minus_e/2);
150		boxes[num_boxes].y1 = dy + pixman_fixed_to_int(traps[n].top + pixman_fixed_1_minus_e/2);
151		boxes[num_boxes].x2 = dx + pixman_fixed_to_int(traps[n].right.p2.x + pixman_fixed_1_minus_e/2);
152		boxes[num_boxes].y2 = dy + pixman_fixed_to_int(traps[n].bottom + pixman_fixed_1_minus_e/2);
153
154		if (boxes[num_boxes].x1 >= boxes[num_boxes].x2)
155			continue;
156		if (boxes[num_boxes].y1 >= boxes[num_boxes].y2)
157			continue;
158
159		if (boxes[num_boxes].x1 < region.extents.x1)
160			region.extents.x1 = boxes[num_boxes].x1;
161		if (boxes[num_boxes].x2 > region.extents.x2)
162			region.extents.x2 = boxes[num_boxes].x2;
163
164		if (boxes[num_boxes].y1 < region.extents.y1)
165			region.extents.y1 = boxes[num_boxes].y1;
166		if (boxes[num_boxes].y2 > region.extents.y2)
167			region.extents.y2 = boxes[num_boxes].y2;
168
169		num_boxes++;
170	}
171
172	if (num_boxes == 0)
173		goto free_boxes;
174
175	trapezoid_origin(&traps[0].left, &dst_x, &dst_y);
176
177	DBG(("%s: extents (%d, %d), (%d, %d) offset of (%d, %d), origin (%d, %d)\n",
178	     __FUNCTION__,
179	     region.extents.x1, region.extents.y1,
180	     region.extents.x2, region.extents.y2,
181	     region.extents.x1 - boxes[0].x1,
182	     region.extents.y1 - boxes[0].y1,
183	     dst_x, dst_y));
184
185	if (!sna_compute_composite_region(&clip,
186					  src, NULL, dst,
187					  src_x + region.extents.x1 - dst_x - dx,
188					  src_y + region.extents.y1 - dst_y - dy,
189					  0, 0,
190					  region.extents.x1 - dx, region.extents.y1 - dy,
191					  region.extents.x2 - region.extents.x1,
192					  region.extents.y2 - region.extents.y1)) {
193		DBG(("%s: trapezoids do not intersect drawable clips\n",
194		     __FUNCTION__)) ;
195		goto done;
196	}
197
198	if (op == PictOpClear && sna->clear)
199		src = sna->clear;
200
201	DBG(("%s: clipped extents (%d, %d), (%d, %d);  now offset by (%d, %d), origin (%d, %d)\n",
202	     __FUNCTION__,
203	     clip.extents.x1, clip.extents.y1,
204	     clip.extents.x2, clip.extents.y2,
205	     clip.extents.x1 - boxes[0].x1,
206	     clip.extents.y1 - boxes[0].y1,
207	     dst_x, dst_y));
208
209	if (force_fallback ||
210	    !sna->render.composite(sna, op, src, NULL, dst,
211				   src_x + clip.extents.x1 - dst_x,
212				   src_y + clip.extents.y1 - dst_y,
213				   0, 0,
214				   clip.extents.x1,  clip.extents.y1,
215				   clip.extents.x2 - clip.extents.x1,
216				   clip.extents.y2 - clip.extents.y1,
217				   (clip.data || num_boxes > 1) ?  COMPOSITE_PARTIAL : 0,
218				   memset(&tmp, 0, sizeof(tmp)))) {
219		unsigned int flags;
220		const pixman_box16_t *b;
221		int i, count;
222
223		DBG(("%s: composite render op not supported\n",
224		     __FUNCTION__));
225
226		flags = MOVE_READ | MOVE_WRITE;
227		if (op <= PictOpSrc) {
228			flags |= MOVE_INPLACE_HINT;
229			if (n == 1)
230				flags &= ~MOVE_READ;
231		}
232
233		if (!sna_drawable_move_region_to_cpu(dst->pDrawable, &clip, flags))
234			goto done;
235		if (dst->alphaMap  &&
236		    !sna_drawable_move_to_cpu(dst->alphaMap->pDrawable,
237					      MOVE_READ | MOVE_WRITE))
238			goto done;
239		if (src->pDrawable) {
240			if (!sna_drawable_move_to_cpu(src->pDrawable,
241						      MOVE_READ))
242				goto done;
243			if (src->alphaMap &&
244			    !sna_drawable_move_to_cpu(src->alphaMap->pDrawable,
245						      MOVE_READ))
246				goto done;
247		}
248
249		DBG(("%s: fbComposite()\n", __FUNCTION__));
250		src_x -= dst_x - dx;
251		src_y -= dst_y - dy;
252		if (maskFormat) {
253			pixman_region_init_rects(&region, boxes, num_boxes);
254			RegionIntersect(&region, &region, &clip);
255
256			if (sigtrap_get() == 0) {
257				b = region_rects(&region);
258				count = region_num_rects(&region);
259				for (i = 0; i < count; i++) {
260					fbComposite(op, src, NULL, dst,
261						    src_x + b[i].x1,
262						    src_y + b[i].y1,
263						    0, 0,
264						    b[i].x1, b[i].y1,
265						    b[i].x2 - b[i].x1, b[i].y2 - b[i].y1);
266				}
267				sigtrap_put();
268			}
269			pixman_region_fini(&region);
270		} else {
271			for (n = 0; n < num_boxes; n++) {
272				pixman_region_init_rects(&region, &boxes[n], 1);
273				RegionIntersect(&region, &region, &clip);
274				b = region_rects(&region);
275				count = region_num_rects(&region);
276				if (sigtrap_get() == 0) {
277					for (i = 0; i < count; i++) {
278						fbComposite(op, src, NULL, dst,
279							    src_x + b[i].x1,
280							    src_y + b[i].y1,
281							    0, 0,
282							    b[i].x1, b[i].y1,
283							    b[i].x2 - b[i].x1, b[i].y2 - b[i].y1);
284					}
285					sigtrap_put();
286				}
287				pixman_region_fini(&region);
288				pixman_region_fini(&region);
289			}
290		}
291		ret = true;
292		goto done;
293	}
294
295	if (maskFormat ||
296	    (op == PictOpSrc || op == PictOpClear) ||
297	    num_boxes == 1) {
298		pixman_region_init_rects(&region, boxes, num_boxes);
299		RegionIntersect(&region, &region, &clip);
300		if (region_num_rects(&region)) {
301			tmp.boxes(sna, &tmp,
302				  region_rects(&region),
303				  region_num_rects(&region));
304			apply_damage(&tmp, &region);
305		}
306		pixman_region_fini(&region);
307	} else {
308		for (n = 0; n < num_boxes; n++) {
309			pixman_region_init_rects(&region, &boxes[n], 1);
310			RegionIntersect(&region, &region, &clip);
311			if (region_num_rects(&region)) {
312				tmp.boxes(sna, &tmp,
313					  region_rects(&region),
314					  region_num_rects(&region));
315				apply_damage(&tmp, &region);
316			}
317			pixman_region_fini(&region);
318		}
319	}
320	tmp.done(sna, &tmp);
321
322done:
323	REGION_UNINIT(NULL, &clip);
324free_boxes:
325	if (boxes != stack_boxes)
326		free(boxes);
327
328	return ret;
329}
330
331static inline int grid_coverage(int samples, pixman_fixed_t f)
332{
333	return (samples * pixman_fixed_frac(f) + pixman_fixed_1/2) / pixman_fixed_1;
334}
335
336inline static void
337composite_unaligned_box(struct sna *sna,
338			struct sna_composite_spans_op *tmp,
339			const BoxRec *box,
340			float opacity,
341			pixman_region16_t *clip)
342{
343	assert(opacity != 0.);
344
345	if (clip) {
346		pixman_region16_t region;
347
348		pixman_region_init_rects(&region, box, 1);
349		RegionIntersect(&region, &region, clip);
350		if (region_num_rects(&region))
351			tmp->boxes(sna, tmp,
352				   region_rects(&region),
353				   region_num_rects(&region),
354				   opacity);
355		pixman_region_fini(&region);
356	} else
357		tmp->box(sna, tmp, box, opacity);
358}
359
360inline static void
361composite_unaligned_trap_row(struct sna *sna,
362			     struct sna_composite_spans_op *tmp,
363			     const xTrapezoid *trap, int dx,
364			     int y1, int y2, int covered,
365			     pixman_region16_t *clip)
366{
367	BoxRec box;
368	int opacity;
369	int x1, x2;
370#define u8_to_float(x) ((x) * (1.f/255))
371
372	if (covered == 0)
373		return;
374
375	x1 = dx + pixman_fixed_to_int(trap->left.p1.x);
376	x2 = dx + pixman_fixed_to_int(trap->right.p1.x);
377	if (clip) {
378		if (y2 > clip->extents.y2)
379			y2 = clip->extents.y2;
380		if (y1 < clip->extents.y1)
381			y1 = clip->extents.y1;
382		if (y1 >= y2)
383			return;
384
385		if (x2 < clip->extents.x1 || x1 > clip->extents.x2)
386			return;
387	}
388
389	box.y1 = y1;
390	box.y2 = y2;
391
392	if (x1 == x2) {
393		box.x1 = x1;
394		box.x2 = x2 + 1;
395
396		opacity = covered;
397		opacity *= grid_coverage(SAMPLES_X, trap->right.p1.x) - grid_coverage(SAMPLES_X, trap->left.p1.x);
398
399		if (opacity)
400			composite_unaligned_box(sna, tmp, &box,
401						u8_to_float(opacity), clip);
402	} else {
403		if (pixman_fixed_frac(trap->left.p1.x)) {
404			box.x1 = x1;
405			box.x2 = ++x1;
406
407			opacity = covered;
408			opacity *= SAMPLES_X - grid_coverage(SAMPLES_X, trap->left.p1.x);
409
410			if (opacity)
411				composite_unaligned_box(sna, tmp, &box,
412							u8_to_float(opacity), clip);
413		}
414
415		if (x2 > x1) {
416			box.x1 = x1;
417			box.x2 = x2;
418
419			composite_unaligned_box(sna, tmp, &box,
420						covered == SAMPLES_Y ? 1. : u8_to_float(covered*SAMPLES_X),
421						clip);
422		}
423
424		if (pixman_fixed_frac(trap->right.p1.x)) {
425			box.x1 = x2;
426			box.x2 = x2 + 1;
427
428			opacity = covered;
429			opacity *= grid_coverage(SAMPLES_X, trap->right.p1.x);
430
431			if (opacity)
432				composite_unaligned_box(sna, tmp, &box,
433							u8_to_float(opacity), clip);
434		}
435	}
436}
437
438flatten static void
439composite_unaligned_trap(struct sna *sna,
440			struct sna_composite_spans_op *tmp,
441			const xTrapezoid *trap,
442			int dx, int dy,
443			pixman_region16_t *clip)
444{
445	int y1, y2;
446
447	y1 = dy + pixman_fixed_to_int(trap->top);
448	y2 = dy + pixman_fixed_to_int(trap->bottom);
449
450	DBG(("%s: y1=%d, y2=%d\n", __FUNCTION__, y1, y2));
451
452	if (y1 == y2) {
453		composite_unaligned_trap_row(sna, tmp, trap, dx,
454					     y1, y1 + 1,
455					     grid_coverage(SAMPLES_Y, trap->bottom) - grid_coverage(SAMPLES_Y, trap->top),
456					     clip);
457	} else {
458		if (pixman_fixed_frac(trap->top)) {
459			composite_unaligned_trap_row(sna, tmp, trap, dx,
460						     y1, y1 + 1,
461						     SAMPLES_Y - grid_coverage(SAMPLES_Y, trap->top),
462						     clip);
463			y1++;
464		}
465
466		if (y2 > y1)
467			composite_unaligned_trap_row(sna, tmp, trap, dx,
468						     y1, y2,
469						     SAMPLES_Y,
470						     clip);
471
472		if (pixman_fixed_frac(trap->bottom))
473			composite_unaligned_trap_row(sna, tmp, trap, dx,
474						     y2, y2 + 1,
475						     grid_coverage(SAMPLES_Y, trap->bottom),
476						     clip);
477	}
478
479	if (tmp->base.damage) {
480		BoxRec box;
481
482		box.x1 = dx + pixman_fixed_to_int(trap->left.p1.x);
483		box.x2 = dx + pixman_fixed_to_int(trap->right.p1.x + pixman_fixed_1_minus_e);
484		box.y1 = dy + pixman_fixed_to_int(trap->top);
485		box.y2 = dy + pixman_fixed_to_int(trap->bottom + pixman_fixed_1_minus_e);
486
487		if (clip) {
488			pixman_region16_t region;
489
490			pixman_region_init_rects(&region, &box, 1);
491			RegionIntersect(&region, &region, clip);
492			if (region_num_rects(&region))
493				apply_damage(&tmp->base, &region);
494			RegionUninit(&region);
495		} else
496			apply_damage_box(&tmp->base, &box);
497	}
498}
499
500inline static void
501blt_opacity(PixmapPtr scratch,
502	    int x1, int x2,
503	    int y, int h,
504	    uint8_t opacity)
505{
506	uint8_t *ptr;
507
508	if (opacity == 0xff)
509		return;
510
511	if (x1 < 0)
512		x1 = 0;
513	if (x2 > scratch->drawable.width)
514		x2 = scratch->drawable.width;
515	if (x1 >= x2)
516		return;
517
518	x2 -= x1;
519
520	ptr = scratch->devPrivate.ptr;
521	ptr += scratch->devKind * y;
522	ptr += x1;
523	do {
524		if (x2 == 1)
525			*ptr = opacity;
526		else
527			memset(ptr, opacity, x2);
528		ptr += scratch->devKind;
529	} while (--h);
530}
531
532static void
533blt_unaligned_box_row(PixmapPtr scratch,
534		      BoxPtr extents,
535		      const xTrapezoid *trap,
536		      int y1, int y2,
537		      int covered)
538{
539	int x1, x2;
540
541	if (y2 > scratch->drawable.height)
542		y2 = scratch->drawable.height;
543	if (y1 < 0)
544		y1 = 0;
545	if (y1 >= y2)
546		return;
547
548	y2 -= y1;
549
550	x1 = pixman_fixed_to_int(trap->left.p1.x);
551	x2 = pixman_fixed_to_int(trap->right.p1.x);
552
553	x1 -= extents->x1;
554	x2 -= extents->x1;
555
556	if (x1 == x2) {
557		blt_opacity(scratch,
558			    x1, x1+1,
559			    y1, y2,
560			    covered * (grid_coverage(SAMPLES_X, trap->right.p1.x) - grid_coverage(SAMPLES_X, trap->left.p1.x)));
561	} else {
562		if (pixman_fixed_frac(trap->left.p1.x)) {
563			blt_opacity(scratch,
564				    x1, x1 + 1,
565				    y1, y2,
566				    covered * (SAMPLES_X - grid_coverage(SAMPLES_X, trap->left.p1.x)));
567			x1++;
568		}
569
570		if (x2 > x1) {
571			blt_opacity(scratch,
572				    x1, x2,
573				    y1, y2,
574				    covered*SAMPLES_X);
575		}
576
577		if (pixman_fixed_frac(trap->right.p1.x))
578			blt_opacity(scratch,
579				    x2, x2 + 1,
580				    y1, y2,
581				    covered * grid_coverage(SAMPLES_X, trap->right.p1.x));
582	}
583}
584
585inline static void
586lerp32_opacity(PixmapPtr scratch,
587	       uint32_t color,
588	       int16_t x, int16_t w,
589	       int16_t y, int16_t h,
590	       uint8_t opacity)
591{
592	uint32_t *ptr;
593	int stride, i;
594
595	sigtrap_assert_active();
596
597	ptr = (uint32_t*)((uint8_t *)scratch->devPrivate.ptr + scratch->devKind * y);
598	ptr += x;
599	stride = scratch->devKind / 4;
600
601	if (opacity == 0xff) {
602		if ((w | h) == 1) {
603			*ptr = color;
604		} else {
605			if (w < 16) {
606				do {
607					for (i = 0; i < w; i++)
608						ptr[i] = color;
609					ptr += stride;
610				} while (--h);
611			} else {
612				pixman_fill(ptr, stride, 32,
613					    0, 0, w, h, color);
614			}
615		}
616	} else {
617		if ((w | h) == 1) {
618			*ptr = lerp8x4(color, opacity, *ptr);
619		} else if (w == 1) {
620			do {
621				*ptr = lerp8x4(color, opacity, *ptr);
622				ptr += stride;
623			} while (--h);
624		} else{
625			do {
626				for (i = 0; i < w; i++)
627					ptr[i] = lerp8x4(color, opacity, ptr[i]);
628				ptr += stride;
629			} while (--h);
630		}
631	}
632}
633
634static void
635lerp32_unaligned_box_row(PixmapPtr scratch, uint32_t color,
636			 const BoxRec *extents,
637			 const xTrapezoid *trap, int16_t dx,
638			 int16_t y, int16_t h,
639			 uint8_t covered)
640{
641	int16_t x1 = pixman_fixed_to_int(trap->left.p1.x) + dx;
642	uint16_t fx1 = grid_coverage(SAMPLES_X, trap->left.p1.x);
643	int16_t x2 = pixman_fixed_to_int(trap->right.p2.x) + dx;
644	uint16_t fx2 = grid_coverage(SAMPLES_X, trap->right.p2.x);
645
646	if (x1 < extents->x1)
647		x1 = extents->x1, fx1 = 0;
648	if (x2 >= extents->x2)
649		x2 = extents->x2, fx2 = 0;
650
651	DBG(("%s: x=(%d.%d, %d.%d), y=%dx%d, covered=%d\n", __FUNCTION__,
652	     x1, fx1, x2, fx2, y, h, covered));
653
654	if (x1 < x2) {
655		if (fx1) {
656			lerp32_opacity(scratch, color,
657				       x1, 1,
658				       y, h,
659				       covered * (SAMPLES_X - fx1));
660			x1++;
661		}
662
663		if (x2 > x1) {
664			lerp32_opacity(scratch, color,
665				       x1, x2-x1,
666				       y, h,
667				       covered*SAMPLES_X);
668		}
669
670		if (fx2) {
671			lerp32_opacity(scratch, color,
672				       x2, 1,
673				       y, h,
674				       covered * fx2);
675		}
676	} else if (x1 == x2 && fx2 > fx1) {
677		lerp32_opacity(scratch, color,
678			       x1, 1,
679			       y, h,
680			       covered * (fx2 - fx1));
681	}
682}
683
684struct pixman_inplace {
685	pixman_image_t *image, *source, *mask;
686	uint32_t color;
687	uint32_t *bits;
688	int dx, dy;
689	int sx, sy;
690	uint8_t op;
691};
692
693inline static void
694pixsolid_opacity(struct pixman_inplace *pi,
695		 int16_t x, int16_t w,
696		 int16_t y, int16_t h,
697		 uint8_t opacity)
698{
699	if (opacity == 0xff)
700		*pi->bits = pi->color;
701	else
702		*pi->bits = mul_4x8_8(pi->color, opacity);
703	sna_image_composite(pi->op, pi->source, NULL, pi->image,
704			    0, 0, 0, 0, pi->dx + x, pi->dy + y, w, h);
705}
706
707static void
708pixsolid_unaligned_box_row(struct pixman_inplace *pi,
709			   const BoxRec *extents,
710			   const xTrapezoid *trap,
711			   int16_t y, int16_t h,
712			   uint8_t covered)
713{
714	int16_t x1 = pixman_fixed_to_int(trap->left.p1.x);
715	uint16_t fx1 = grid_coverage(SAMPLES_X, trap->left.p1.x);
716	int16_t x2 = pixman_fixed_to_int(trap->right.p1.x);
717	uint16_t fx2 = grid_coverage(SAMPLES_X, trap->right.p1.x);
718
719	if (x1 < extents->x1)
720		x1 = extents->x1, fx1 = 0;
721	if (x2 >= extents->x2)
722		x2 = extents->x2, fx2 = 0;
723
724	if (x1 < x2) {
725		if (fx1) {
726			pixsolid_opacity(pi, x1, 1, y, h,
727					 covered * (SAMPLES_X - fx1));
728			x1++;
729		}
730
731		if (x2 > x1)
732			pixsolid_opacity(pi, x1, x2-x1, y, h, covered*SAMPLES_X);
733
734		if (fx2)
735			pixsolid_opacity(pi, x2, 1, y, h, covered * fx2);
736	} else if (x1 == x2 && fx2 > fx1) {
737		pixsolid_opacity(pi, x1, 1, y, h, covered * (fx2 - fx1));
738	}
739}
740
741static bool
742composite_unaligned_boxes_inplace__solid(struct sna *sna,
743					 CARD8 op, uint32_t color,
744					 PicturePtr dst,
745					 int n, const xTrapezoid *t,
746					 bool force_fallback)
747{
748	PixmapPtr pixmap;
749	int16_t dx, dy;
750
751	DBG(("%s: force=%d, is_gpu=%d, op=%d, color=%x\n", __FUNCTION__,
752	     force_fallback, is_gpu(sna, dst->pDrawable, PREFER_GPU_SPANS), op, color));
753
754	if (!force_fallback && is_gpu(sna, dst->pDrawable, PREFER_GPU_SPANS)) {
755		DBG(("%s: fallback -- can not perform operation in place, destination busy\n",
756		     __FUNCTION__));
757
758		return false;
759	}
760
761	/* XXX a8 boxes */
762	if (!(dst->format == PICT_a8r8g8b8 || dst->format == PICT_x8r8g8b8)) {
763		DBG(("%s: fallback -- can not perform operation in place, unhanbled format %08lx\n",
764		     __FUNCTION__, (long)dst->format));
765
766		goto pixman;
767	}
768
769	pixmap = get_drawable_pixmap(dst->pDrawable);
770	get_drawable_deltas(dst->pDrawable, pixmap, &dx, &dy);
771
772	if (op == PictOpOver && (color >> 24) == 0xff)
773		op = PictOpSrc;
774	if (op == PictOpOver || op == PictOpAdd) {
775		struct sna_pixmap *priv = sna_pixmap(pixmap);
776		if (priv && priv->clear && priv->clear_color == 0)
777			op = PictOpSrc;
778	}
779
780	switch (op) {
781	case PictOpSrc:
782		break;
783	default:
784		DBG(("%s: fallback -- can not perform op [%d] in place\n",
785		     __FUNCTION__, op));
786		goto pixman;
787	}
788
789	DBG(("%s: inplace operation on argb32 destination x %d\n",
790	     __FUNCTION__, n));
791	do {
792		RegionRec clip;
793		const BoxRec *extents;
794		int count;
795
796		clip.extents.x1 = pixman_fixed_to_int(t->left.p1.x);
797		clip.extents.x2 = pixman_fixed_to_int(t->right.p1.x + pixman_fixed_1_minus_e);
798		clip.extents.y1 = pixman_fixed_to_int(t->top);
799		clip.extents.y2 = pixman_fixed_to_int(t->bottom + pixman_fixed_1_minus_e);
800		clip.data = NULL;
801
802		if (!sna_compute_composite_region(&clip,
803						   NULL, NULL, dst,
804						   0, 0,
805						   0, 0,
806						   clip.extents.x1, clip.extents.y1,
807						   clip.extents.x2 - clip.extents.x1,
808						   clip.extents.y2 - clip.extents.y1))
809			continue;
810
811		if (!sna_drawable_move_region_to_cpu(dst->pDrawable, &clip,
812						     MOVE_WRITE | MOVE_READ)) {
813			RegionUninit(&clip);
814			continue;
815		}
816
817		if (sigtrap_get() == 0) {
818			RegionTranslate(&clip, dx, dy);
819			count = region_num_rects(&clip);
820			extents = region_rects(&clip);
821			while (count--) {
822				int16_t y1 = dy + pixman_fixed_to_int(t->top);
823				uint16_t fy1 = pixman_fixed_frac(t->top);
824				int16_t y2 = dy + pixman_fixed_to_int(t->bottom);
825				uint16_t fy2 = pixman_fixed_frac(t->bottom);
826
827				DBG(("%s: t=(%d, %d), (%d, %d), extents (%d, %d), (%d, %d)\n",
828				     __FUNCTION__,
829				     pixman_fixed_to_int(t->left.p1.x),
830				     pixman_fixed_to_int(t->top),
831				     pixman_fixed_to_int(t->right.p2.x),
832				     pixman_fixed_to_int(t->bottom),
833				     extents->x1, extents->y1,
834				     extents->x2, extents->y2));
835
836				if (y1 < extents->y1)
837					y1 = extents->y1, fy1 = 0;
838				if (y2 >= extents->y2)
839					y2 = extents->y2, fy2 = 0;
840
841				if (y1 < y2) {
842					if (fy1) {
843						lerp32_unaligned_box_row(pixmap, color, extents,
844									 t, dx, y1, 1,
845									 SAMPLES_Y - grid_coverage(SAMPLES_Y, fy1));
846						y1++;
847					}
848
849					if (y2 > y1)
850						lerp32_unaligned_box_row(pixmap, color, extents,
851									 t, dx, y1, y2 - y1,
852									 SAMPLES_Y);
853
854					if (fy2)
855						lerp32_unaligned_box_row(pixmap, color,  extents,
856									 t, dx, y2, 1,
857									 grid_coverage(SAMPLES_Y, fy2));
858				} else if (y1 == y2 && fy2 > fy1) {
859					lerp32_unaligned_box_row(pixmap, color, extents,
860								 t, dx, y1, 1,
861								 grid_coverage(SAMPLES_Y, fy2) - grid_coverage(SAMPLES_Y, fy1));
862				}
863				extents++;
864			}
865			sigtrap_put();
866		}
867
868		RegionUninit(&clip);
869	} while (--n && t++);
870
871	return true;
872
873pixman:
874	do {
875		struct pixman_inplace pi;
876		RegionRec clip;
877		const BoxRec *extents;
878		int count;
879
880		clip.extents.x1 = pixman_fixed_to_int(t->left.p1.x);
881		clip.extents.x2 = pixman_fixed_to_int(t->right.p1.x + pixman_fixed_1_minus_e);
882		clip.extents.y1 = pixman_fixed_to_int(t->top);
883		clip.extents.y2 = pixman_fixed_to_int(t->bottom + pixman_fixed_1_minus_e);
884		clip.data = NULL;
885
886		if (!sna_compute_composite_region(&clip,
887						   NULL, NULL, dst,
888						   0, 0,
889						   0, 0,
890						   clip.extents.x1, clip.extents.y1,
891						   clip.extents.x2 - clip.extents.x1,
892						   clip.extents.y2 - clip.extents.y1))
893			continue;
894
895		if (!sna_drawable_move_region_to_cpu(dst->pDrawable, &clip,
896						     MOVE_WRITE | MOVE_READ)) {
897			RegionUninit(&clip);
898			continue;
899		}
900
901		pi.image = image_from_pict(dst, false, &pi.dx, &pi.dy);
902		pi.source = pixman_image_create_bits(PIXMAN_a8r8g8b8, 1, 1, NULL, 0);
903		pixman_image_set_repeat(pi.source, PIXMAN_REPEAT_NORMAL);
904		pi.bits = pixman_image_get_data(pi.source);
905		pi.color = color;
906		pi.op = op;
907
908		if (sigtrap_get() == 0) {
909			count = region_num_rects(&clip);
910			extents = region_rects(&clip);
911			while (count--) {
912				int16_t y1 = pixman_fixed_to_int(t->top);
913				uint16_t fy1 = pixman_fixed_frac(t->top);
914				int16_t y2 = pixman_fixed_to_int(t->bottom);
915				uint16_t fy2 = pixman_fixed_frac(t->bottom);
916
917				if (y1 < extents->y1)
918					y1 = extents->y1, fy1 = 0;
919				if (y2 >= extents->y2)
920					y2 = extents->y2, fy2 = 0;
921				if (y1 < y2) {
922					if (fy1) {
923						pixsolid_unaligned_box_row(&pi, extents, t, y1, 1,
924									   SAMPLES_Y - grid_coverage(SAMPLES_Y, fy1));
925						y1++;
926					}
927
928					if (y2 > y1)
929						pixsolid_unaligned_box_row(&pi, extents, t, y1, y2 - y1,
930									   SAMPLES_Y);
931
932					if (fy2)
933						pixsolid_unaligned_box_row(&pi, extents, t, y2, 1,
934									   grid_coverage(SAMPLES_Y, fy2));
935				} else if (y1 == y2 && fy2 > fy1) {
936					pixsolid_unaligned_box_row(&pi, extents, t, y1, 1,
937								   grid_coverage(SAMPLES_Y, fy2) - grid_coverage(SAMPLES_Y, fy1));
938				}
939				extents++;
940			}
941			sigtrap_put();
942		}
943
944		RegionUninit(&clip);
945		pixman_image_unref(pi.image);
946		pixman_image_unref(pi.source);
947	} while (--n && t++);
948	return true;
949}
950
951inline static void
952pixmask_opacity(struct pixman_inplace *pi,
953		int16_t x, int16_t w,
954		int16_t y, int16_t h,
955		uint8_t opacity)
956{
957	if (opacity == 0xff) {
958		pixman_image_composite(pi->op, pi->source, NULL, pi->image,
959				       pi->sx + x, pi->sy + y,
960				       0, 0,
961				       pi->dx + x, pi->dy + y,
962				       w, h);
963	} else {
964		*pi->bits = opacity;
965		pixman_image_composite(pi->op, pi->source, pi->mask, pi->image,
966				       pi->sx + x, pi->sy + y,
967				       0, 0,
968				       pi->dx + x, pi->dy + y,
969				       w, h);
970	}
971}
972
973static void
974pixmask_unaligned_box_row(struct pixman_inplace *pi,
975			  const BoxRec *extents,
976			  const xTrapezoid *trap,
977			  int16_t y, int16_t h,
978			  uint8_t covered)
979{
980	int16_t x1 = pixman_fixed_to_int(trap->left.p1.x);
981	uint16_t fx1 = grid_coverage(SAMPLES_X, trap->left.p1.x);
982	int16_t x2 = pixman_fixed_to_int(trap->right.p1.x);
983	uint16_t fx2 = grid_coverage(SAMPLES_X, trap->right.p1.x);
984
985	if (x1 < extents->x1)
986		x1 = extents->x1, fx1 = 0;
987	if (x2 >= extents->x2)
988		x2 = extents->x2, fx2 = 0;
989
990	if (x1 < x2) {
991		if (fx1) {
992			pixmask_opacity(pi, x1, 1, y, h,
993					 covered * (SAMPLES_X - fx1));
994			x1++;
995		}
996
997		if (x2 > x1)
998			pixmask_opacity(pi, x1, x2-x1, y, h, covered*SAMPLES_X);
999
1000		if (fx2)
1001			pixmask_opacity(pi, x2, 1, y, h, covered * fx2);
1002	} else if (x1 == x2 && fx2 > fx1) {
1003		pixmask_opacity(pi, x1, 1, y, h, covered * (fx2 - fx1));
1004	}
1005}
1006
1007struct rectilinear_inplace_thread {
1008	pixman_image_t *dst, *src;
1009	const RegionRec *clip;
1010	const xTrapezoid *trap;
1011	int dx, dy, sx, sy;
1012	int y1, y2;
1013	CARD8 op;
1014};
1015
1016static void rectilinear_inplace_thread(void *arg)
1017{
1018	struct rectilinear_inplace_thread *thread = arg;
1019	const xTrapezoid *t = thread->trap;
1020	struct pixman_inplace pi;
1021	const BoxRec *extents;
1022	int count;
1023
1024	pi.image = thread->dst;
1025	pi.dx = thread->dx;
1026	pi.dy = thread->dy;
1027
1028	pi.source = thread->src;
1029	pi.sx = thread->sx;
1030	pi.sy = thread->sy;
1031
1032	pi.mask = pixman_image_create_bits(PIXMAN_a8, 1, 1, &pi.color, 4);
1033	pixman_image_set_repeat(pi.mask, PIXMAN_REPEAT_NORMAL);
1034	pi.bits = pixman_image_get_data(pi.mask);
1035	pi.op = thread->op;
1036
1037	count = region_count(thread->clip);
1038	extents = region_boxes(thread->clip);
1039	while (count--) {
1040		int16_t y1 = pixman_fixed_to_int(t->top);
1041		uint16_t fy1 = pixman_fixed_frac(t->top);
1042		int16_t y2 = pixman_fixed_to_int(t->bottom);
1043		uint16_t fy2 = pixman_fixed_frac(t->bottom);
1044
1045		if (y1 < MAX(thread->y1, extents->y1))
1046			y1 = MAX(thread->y1, extents->y1), fy1 = 0;
1047		if (y2 > MIN(thread->y2, extents->y2))
1048			y2 = MIN(thread->y2, extents->y2), fy2 = 0;
1049		if (y1 < y2) {
1050			if (fy1) {
1051				pixmask_unaligned_box_row(&pi, extents, t, y1, 1,
1052							  SAMPLES_Y - grid_coverage(SAMPLES_Y, fy1));
1053				y1++;
1054			}
1055
1056			if (y2 > y1)
1057				pixmask_unaligned_box_row(&pi, extents, t, y1, y2 - y1,
1058							  SAMPLES_Y);
1059
1060			if (fy2)
1061				pixmask_unaligned_box_row(&pi, extents, t, y2, 1,
1062							  grid_coverage(SAMPLES_Y, fy2));
1063		} else if (y1 == y2 && fy2 > fy1) {
1064			pixmask_unaligned_box_row(&pi, extents, t, y1, 1,
1065						  grid_coverage(SAMPLES_Y, fy2) - grid_coverage(SAMPLES_Y, fy1));
1066		}
1067		extents++;
1068	}
1069
1070	pixman_image_unref(pi.mask);
1071}
1072
1073static bool
1074composite_unaligned_boxes_inplace(struct sna *sna,
1075				  CARD8 op,
1076				  PicturePtr src, int16_t src_x, int16_t src_y,
1077				  PicturePtr dst, int n, const xTrapezoid *t,
1078				  bool force_fallback)
1079{
1080	if (!force_fallback &&
1081	    (is_gpu(sna, dst->pDrawable, PREFER_GPU_SPANS) ||
1082	     picture_is_gpu(sna, src, PREFER_GPU_SPANS))) {
1083		DBG(("%s: fallback -- not forcing\n", __FUNCTION__));
1084		return false;
1085	}
1086
1087	DBG(("%s\n", __FUNCTION__));
1088
1089	src_x -= pixman_fixed_to_int(t[0].left.p1.x);
1090	src_y -= pixman_fixed_to_int(t[0].left.p1.y);
1091	do {
1092		RegionRec clip;
1093		const BoxRec *extents;
1094		int count;
1095		int num_threads;
1096
1097		clip.extents.x1 = pixman_fixed_to_int(t->left.p1.x);
1098		clip.extents.x2 = pixman_fixed_to_int(t->right.p1.x + pixman_fixed_1_minus_e);
1099		clip.extents.y1 = pixman_fixed_to_int(t->top);
1100		clip.extents.y2 = pixman_fixed_to_int(t->bottom + pixman_fixed_1_minus_e);
1101		clip.data = NULL;
1102
1103		if (!sna_compute_composite_region(&clip,
1104						   src, NULL, dst,
1105						   clip.extents.x1 + src_x,
1106						   clip.extents.y1 + src_y,
1107						   0, 0,
1108						   clip.extents.x1, clip.extents.y1,
1109						   clip.extents.x2 - clip.extents.x1,
1110						   clip.extents.y2 - clip.extents.y1))
1111			continue;
1112
1113		if (!sna_drawable_move_region_to_cpu(dst->pDrawable, &clip,
1114						     MOVE_WRITE | MOVE_READ)) {
1115			RegionUninit(&clip);
1116			continue;
1117		}
1118
1119		if (src->pDrawable) {
1120			if (!sna_drawable_move_to_cpu(src->pDrawable,
1121						      MOVE_READ)) {
1122				RegionUninit(&clip);
1123				continue;
1124			}
1125			if (src->alphaMap) {
1126				if (!sna_drawable_move_to_cpu(src->alphaMap->pDrawable,
1127							      MOVE_READ)) {
1128					RegionUninit(&clip);
1129					continue;
1130				}
1131			}
1132		}
1133
1134		num_threads = sna_use_threads(clip.extents.x2 - clip.extents.x1,
1135					      clip.extents.y2 - clip.extents.y1,
1136					      32);
1137		if (num_threads == 1) {
1138			struct pixman_inplace pi;
1139
1140			pi.image = image_from_pict(dst, false, &pi.dx, &pi.dy);
1141			pi.source = image_from_pict(src, false, &pi.sx, &pi.sy);
1142			pi.sx += src_x;
1143			pi.sy += src_y;
1144			pi.mask = pixman_image_create_bits(PIXMAN_a8, 1, 1, &pi.color, 4);
1145			pixman_image_set_repeat(pi.mask, PIXMAN_REPEAT_NORMAL);
1146			pi.bits = pixman_image_get_data(pi.mask);
1147			pi.op = op;
1148
1149			if (sigtrap_get() == 0) {
1150				count = region_num_rects(&clip);
1151				extents = region_rects(&clip);
1152				while (count--) {
1153					int16_t y1 = pixman_fixed_to_int(t->top);
1154					uint16_t fy1 = pixman_fixed_frac(t->top);
1155					int16_t y2 = pixman_fixed_to_int(t->bottom);
1156					uint16_t fy2 = pixman_fixed_frac(t->bottom);
1157
1158					if (y1 < extents->y1)
1159						y1 = extents->y1, fy1 = 0;
1160					if (y2 > extents->y2)
1161						y2 = extents->y2, fy2 = 0;
1162					if (y1 < y2) {
1163						if (fy1) {
1164							pixmask_unaligned_box_row(&pi, extents, t, y1, 1,
1165										  SAMPLES_Y - grid_coverage(SAMPLES_Y, fy1));
1166							y1++;
1167						}
1168
1169						if (y2 > y1)
1170							pixmask_unaligned_box_row(&pi, extents, t, y1, y2 - y1,
1171										  SAMPLES_Y);
1172
1173						if (fy2)
1174							pixmask_unaligned_box_row(&pi, extents, t, y2, 1,
1175										  grid_coverage(SAMPLES_Y, fy2));
1176					} else if (y1 == y2 && fy2 > fy1) {
1177						pixmask_unaligned_box_row(&pi, extents, t, y1, 1,
1178									  grid_coverage(SAMPLES_Y, fy2) - grid_coverage(SAMPLES_Y, fy1));
1179					}
1180					extents++;
1181				}
1182				sigtrap_put();
1183			}
1184
1185			pixman_image_unref(pi.image);
1186			pixman_image_unref(pi.source);
1187			pixman_image_unref(pi.mask);
1188		} else {
1189			struct rectilinear_inplace_thread thread[num_threads];
1190			int i, y, dy;
1191
1192
1193			thread[0].trap = t;
1194			thread[0].dst = image_from_pict(dst, false, &thread[0].dx, &thread[0].dy);
1195			thread[0].src = image_from_pict(src, false, &thread[0].sx, &thread[0].sy);
1196			thread[0].sx += src_x;
1197			thread[0].sy += src_y;
1198
1199			thread[0].clip = &clip;
1200			thread[0].op = op;
1201
1202			y = clip.extents.y1;
1203			dy = (clip.extents.y2 - clip.extents.y1 + num_threads - 1) / num_threads;
1204			num_threads = (clip.extents.y2 - clip.extents.y1 + dy - 1) / dy;
1205
1206			if (sigtrap_get() == 0) {
1207				for (i = 1; i < num_threads; i++) {
1208					thread[i] = thread[0];
1209					thread[i].y1 = y;
1210					thread[i].y2 = y += dy;
1211					sna_threads_run(i, rectilinear_inplace_thread, &thread[i]);
1212				}
1213
1214				assert(y < clip.extents.y2);
1215				thread[0].y1 = y;
1216				thread[0].y2 = clip.extents.y2;
1217				rectilinear_inplace_thread(&thread[0]);
1218
1219				sna_threads_wait();
1220				sigtrap_put();
1221			} else
1222				sna_threads_kill();
1223
1224			pixman_image_unref(thread[0].dst);
1225			pixman_image_unref(thread[0].src);
1226		}
1227
1228		RegionUninit(&clip);
1229	} while (--n && t++);
1230
1231	return true;
1232}
1233
1234static bool
1235composite_unaligned_boxes_fallback(struct sna *sna,
1236				   CARD8 op,
1237				   PicturePtr src,
1238				   PicturePtr dst,
1239				   INT16 src_x, INT16 src_y,
1240				   int ntrap, const xTrapezoid *traps,
1241				   bool force_fallback)
1242{
1243	ScreenPtr screen = dst->pDrawable->pScreen;
1244	uint32_t color;
1245	int16_t dst_x, dst_y;
1246	int16_t dx, dy;
1247	int n;
1248
1249	if (sna_picture_is_solid(src, &color) &&
1250	    composite_unaligned_boxes_inplace__solid(sna, op, color, dst,
1251						     ntrap, traps,
1252						     force_fallback))
1253		return true;
1254
1255	if (composite_unaligned_boxes_inplace(sna, op, src, src_x, src_y,
1256					      dst, ntrap, traps,
1257					      force_fallback))
1258		return true;
1259
1260	trapezoid_origin(&traps[0].left, &dst_x, &dst_y);
1261	dx = dst->pDrawable->x;
1262	dy = dst->pDrawable->y;
1263	for (n = 0; n < ntrap; n++) {
1264		const xTrapezoid *t = &traps[n];
1265		PixmapPtr scratch;
1266		PicturePtr mask;
1267		BoxRec extents;
1268		int error;
1269		int y1, y2;
1270
1271		extents.x1 = pixman_fixed_to_int(t->left.p1.x);
1272		extents.x2 = pixman_fixed_to_int(t->right.p1.x + pixman_fixed_1_minus_e);
1273		extents.y1 = pixman_fixed_to_int(t->top);
1274		extents.y2 = pixman_fixed_to_int(t->bottom + pixman_fixed_1_minus_e);
1275
1276		if (!sna_compute_composite_extents(&extents,
1277						   src, NULL, dst,
1278						   src_x, src_y,
1279						   0, 0,
1280						   extents.x1, extents.y1,
1281						   extents.x2 - extents.x1,
1282						   extents.y2 - extents.y1))
1283			continue;
1284
1285		if (force_fallback)
1286			scratch = sna_pixmap_create_unattached(screen,
1287							       extents.x2 - extents.x1,
1288							       extents.y2 - extents.y1,
1289							       8);
1290		else
1291			scratch = sna_pixmap_create_upload(screen,
1292							   extents.x2 - extents.x1,
1293							   extents.y2 - extents.y1,
1294							   8, KGEM_BUFFER_WRITE_INPLACE);
1295		if (!scratch)
1296			continue;
1297
1298		memset(scratch->devPrivate.ptr, 0xff,
1299		       scratch->devKind * (extents.y2 - extents.y1));
1300
1301		extents.x1 -= dx;
1302		extents.x2 -= dx;
1303		extents.y1 -= dy;
1304		extents.y2 -= dy;
1305
1306		y1 = pixman_fixed_to_int(t->top) - extents.y1;
1307		y2 = pixman_fixed_to_int(t->bottom) - extents.y1;
1308
1309		if (y1 == y2) {
1310			blt_unaligned_box_row(scratch, &extents, t, y1, y1 + 1,
1311					      grid_coverage(SAMPLES_Y, t->bottom) - grid_coverage(SAMPLES_Y, t->top));
1312		} else {
1313			if (pixman_fixed_frac(t->top)) {
1314				blt_unaligned_box_row(scratch, &extents, t, y1, y1 + 1,
1315						      SAMPLES_Y - grid_coverage(SAMPLES_Y, t->top));
1316				y1++;
1317			}
1318
1319			if (y2 > y1)
1320				blt_unaligned_box_row(scratch, &extents, t, y1, y2,
1321						      SAMPLES_Y);
1322
1323			if (pixman_fixed_frac(t->bottom))
1324				blt_unaligned_box_row(scratch, &extents, t, y2, y2+1,
1325						      grid_coverage(SAMPLES_Y, t->bottom));
1326		}
1327
1328		mask = CreatePicture(0, &scratch->drawable,
1329				     PictureMatchFormat(screen, 8, PICT_a8),
1330				     0, 0, serverClient, &error);
1331		if (mask) {
1332			CompositePicture(op, src, mask, dst,
1333					 src_x + extents.x1 - dst_x,
1334					 src_y + extents.y1 - dst_y,
1335					 0, 0,
1336					 extents.x1, extents.y1,
1337					 extents.x2 - extents.x1,
1338					 extents.y2 - extents.y1);
1339			FreePicture(mask, 0);
1340		}
1341		sna_pixmap_destroy(scratch);
1342	}
1343
1344	return true;
1345}
1346
1347bool
1348composite_unaligned_boxes(struct sna *sna,
1349			  CARD8 op,
1350			  PicturePtr src,
1351			  PicturePtr dst,
1352			  PictFormatPtr maskFormat,
1353			  INT16 src_x, INT16 src_y,
1354			  int ntrap, const xTrapezoid *traps,
1355			  bool force_fallback)
1356{
1357	BoxRec extents;
1358	struct sna_composite_spans_op tmp;
1359	struct sna_pixmap *priv;
1360	pixman_region16_t clip, *c;
1361	int16_t dst_x, dst_y;
1362	int dx, dy, n;
1363
1364	if (NO_UNALIGNED_BOXES)
1365		return false;
1366
1367	DBG(("%s: force_fallback=%d, mask=%x, n=%d, op=%d\n",
1368	     __FUNCTION__, force_fallback, maskFormat ? (int)maskFormat->format : 0, ntrap, op));
1369
1370	/* need a span converter to handle overlapping traps */
1371	if (ntrap > 1 && maskFormat)
1372		return false;
1373
1374	if (force_fallback ||
1375	    !sna->render.check_composite_spans(sna, op, src, dst, 0, 0,
1376					       COMPOSITE_SPANS_RECTILINEAR)) {
1377fallback:
1378		return composite_unaligned_boxes_fallback(sna, op, src, dst,
1379							  src_x, src_y,
1380							  ntrap, traps,
1381							  force_fallback);
1382	}
1383
1384	trapezoid_origin(&traps[0].left, &dst_x, &dst_y);
1385
1386	extents.x1 = pixman_fixed_to_int(traps[0].left.p1.x);
1387	extents.x2 = pixman_fixed_to_int(traps[0].right.p1.x + pixman_fixed_1_minus_e);
1388	extents.y1 = pixman_fixed_to_int(traps[0].top);
1389	extents.y2 = pixman_fixed_to_int(traps[0].bottom + pixman_fixed_1_minus_e);
1390
1391	DBG(("%s: src=(%d, %d), dst=(%d, %d)\n",
1392	     __FUNCTION__, src_x, src_y, dst_x, dst_y));
1393
1394	for (n = 1; n < ntrap; n++) {
1395		int x1 = pixman_fixed_to_int(traps[n].left.p1.x);
1396		int x2 = pixman_fixed_to_int(traps[n].right.p1.x + pixman_fixed_1_minus_e);
1397		int y1 = pixman_fixed_to_int(traps[n].top);
1398		int y2 = pixman_fixed_to_int(traps[n].bottom + pixman_fixed_1_minus_e);
1399
1400		if (x1 < extents.x1)
1401			extents.x1 = x1;
1402		if (x2 > extents.x2)
1403			extents.x2 = x2;
1404		if (y1 < extents.y1)
1405			extents.y1 = y1;
1406		if (y2 > extents.y2)
1407			extents.y2 = y2;
1408	}
1409
1410	DBG(("%s: extents (%d, %d), (%d, %d)\n", __FUNCTION__,
1411	     extents.x1, extents.y1, extents.x2, extents.y2));
1412
1413	if (!sna_compute_composite_region(&clip,
1414					  src, NULL, dst,
1415					  src_x + extents.x1 - dst_x,
1416					  src_y + extents.y1 - dst_y,
1417					  0, 0,
1418					  extents.x1, extents.y1,
1419					  extents.x2 - extents.x1,
1420					  extents.y2 - extents.y1)) {
1421		DBG(("%s: trapezoids do not intersect drawable clips\n",
1422		     __FUNCTION__)) ;
1423		return true;
1424	}
1425
1426	if (!sna->render.check_composite_spans(sna, op, src, dst,
1427					       clip.extents.x2 - clip.extents.x1,
1428					       clip.extents.y2 - clip.extents.y1,
1429					       COMPOSITE_SPANS_RECTILINEAR)) {
1430		DBG(("%s: fallback -- composite spans not supported\n",
1431		     __FUNCTION__));
1432		goto fallback;
1433	}
1434
1435	c = NULL;
1436	if (extents.x2 - extents.x1 > clip.extents.x2 - clip.extents.x1 ||
1437	    extents.y2 - extents.y1 > clip.extents.y2 - clip.extents.y1) {
1438		DBG(("%s: forcing clip\n", __FUNCTION__));
1439		c = &clip;
1440	}
1441
1442	extents = *RegionExtents(&clip);
1443	dx = dst->pDrawable->x;
1444	dy = dst->pDrawable->y;
1445
1446	DBG(("%s: after clip -- extents (%d, %d), (%d, %d), delta=(%d, %d) src -> (%d, %d)\n",
1447	     __FUNCTION__,
1448	     extents.x1, extents.y1,
1449	     extents.x2, extents.y2,
1450	     dx, dy,
1451	     src_x + extents.x1 - dst_x - dx,
1452	     src_y + extents.y1 - dst_y - dy));
1453
1454	switch (op) {
1455	case PictOpAdd:
1456	case PictOpOver:
1457		priv = sna_pixmap(get_drawable_pixmap(dst->pDrawable));
1458		assert(priv != NULL);
1459		if (priv->clear && priv->clear_color == 0) {
1460			DBG(("%s: converting %d to PictOpSrc\n",
1461			     __FUNCTION__, op));
1462			op = PictOpSrc;
1463		}
1464		break;
1465	case PictOpIn:
1466		priv = sna_pixmap(get_drawable_pixmap(dst->pDrawable));
1467		assert(priv != NULL);
1468		if (priv->clear && priv->clear_color == 0) {
1469			DBG(("%s: clear destination using In, skipping\n",
1470			     __FUNCTION__));
1471			return true;
1472		}
1473		break;
1474	}
1475
1476	if (!sna->render.composite_spans(sna, op, src, dst,
1477					 src_x + extents.x1 - dst_x - dx,
1478					 src_y + extents.y1 - dst_y - dy,
1479					 extents.x1,  extents.y1,
1480					 extents.x2 - extents.x1,
1481					 extents.y2 - extents.y1,
1482					 COMPOSITE_SPANS_RECTILINEAR,
1483					 memset(&tmp, 0, sizeof(tmp)))) {
1484		DBG(("%s: composite spans render op not supported\n",
1485		     __FUNCTION__));
1486		REGION_UNINIT(NULL, &clip);
1487		goto fallback;
1488	}
1489
1490	for (n = 0; n < ntrap; n++)
1491		composite_unaligned_trap(sna, &tmp, &traps[n], dx, dy, c);
1492	tmp.done(sna, &tmp);
1493	REGION_UNINIT(NULL, &clip);
1494	return true;
1495}
1496