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), orgin (%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	ptr = (uint32_t*)((uint8_t *)scratch->devPrivate.ptr + scratch->devKind * y);
596	ptr += x;
597	stride = scratch->devKind / 4;
598
599	if (opacity == 0xff) {
600		if ((w | h) == 1) {
601			*ptr = color;
602		} else {
603			if (w < 16) {
604				do {
605					for (i = 0; i < w; i++)
606						ptr[i] = color;
607					ptr += stride;
608				} while (--h);
609			} else {
610				pixman_fill(ptr, stride, 32,
611					    0, 0, w, h, color);
612			}
613		}
614	} else {
615		if ((w | h) == 1) {
616			*ptr = lerp8x4(color, opacity, *ptr);
617		} else if (w == 1) {
618			do {
619				*ptr = lerp8x4(color, opacity, *ptr);
620				ptr += stride;
621			} while (--h);
622		} else{
623			do {
624				for (i = 0; i < w; i++)
625					ptr[i] = lerp8x4(color, opacity, ptr[i]);
626				ptr += stride;
627			} while (--h);
628		}
629	}
630}
631
632static void
633lerp32_unaligned_box_row(PixmapPtr scratch, uint32_t color,
634			 const BoxRec *extents,
635			 const xTrapezoid *trap, int16_t dx,
636			 int16_t y, int16_t h,
637			 uint8_t covered)
638{
639	int16_t x1 = pixman_fixed_to_int(trap->left.p1.x) + dx;
640	uint16_t fx1 = grid_coverage(SAMPLES_X, trap->left.p1.x);
641	int16_t x2 = pixman_fixed_to_int(trap->right.p2.x) + dx;
642	uint16_t fx2 = grid_coverage(SAMPLES_X, trap->right.p2.x);
643
644	if (x1 < extents->x1)
645		x1 = extents->x1, fx1 = 0;
646	if (x2 >= extents->x2)
647		x2 = extents->x2, fx2 = 0;
648
649	DBG(("%s: x=(%d.%d, %d.%d), y=%dx%d, covered=%d\n", __FUNCTION__,
650	     x1, fx1, x2, fx2, y, h, covered));
651
652	if (x1 < x2) {
653		if (fx1) {
654			lerp32_opacity(scratch, color,
655				       x1, 1,
656				       y, h,
657				       covered * (SAMPLES_X - fx1));
658			x1++;
659		}
660
661		if (x2 > x1) {
662			lerp32_opacity(scratch, color,
663				       x1, x2-x1,
664				       y, h,
665				       covered*SAMPLES_X);
666		}
667
668		if (fx2) {
669			lerp32_opacity(scratch, color,
670				       x2, 1,
671				       y, h,
672				       covered * fx2);
673		}
674	} else if (x1 == x2 && fx2 > fx1) {
675		lerp32_opacity(scratch, color,
676			       x1, 1,
677			       y, h,
678			       covered * (fx2 - fx1));
679	}
680}
681
682struct pixman_inplace {
683	pixman_image_t *image, *source, *mask;
684	uint32_t color;
685	uint32_t *bits;
686	int dx, dy;
687	int sx, sy;
688	uint8_t op;
689};
690
691inline static void
692pixsolid_opacity(struct pixman_inplace *pi,
693		 int16_t x, int16_t w,
694		 int16_t y, int16_t h,
695		 uint8_t opacity)
696{
697	if (opacity == 0xff)
698		*pi->bits = pi->color;
699	else
700		*pi->bits = mul_4x8_8(pi->color, opacity);
701	sna_image_composite(pi->op, pi->source, NULL, pi->image,
702			    0, 0, 0, 0, pi->dx + x, pi->dy + y, w, h);
703}
704
705static void
706pixsolid_unaligned_box_row(struct pixman_inplace *pi,
707			   const BoxRec *extents,
708			   const xTrapezoid *trap,
709			   int16_t y, int16_t h,
710			   uint8_t covered)
711{
712	int16_t x1 = pixman_fixed_to_int(trap->left.p1.x);
713	uint16_t fx1 = grid_coverage(SAMPLES_X, trap->left.p1.x);
714	int16_t x2 = pixman_fixed_to_int(trap->right.p1.x);
715	uint16_t fx2 = grid_coverage(SAMPLES_X, trap->right.p1.x);
716
717	if (x1 < extents->x1)
718		x1 = extents->x1, fx1 = 0;
719	if (x2 >= extents->x2)
720		x2 = extents->x2, fx2 = 0;
721
722	if (x1 < x2) {
723		if (fx1) {
724			pixsolid_opacity(pi, x1, 1, y, h,
725					 covered * (SAMPLES_X - fx1));
726			x1++;
727		}
728
729		if (x2 > x1)
730			pixsolid_opacity(pi, x1, x2-x1, y, h, covered*SAMPLES_X);
731
732		if (fx2)
733			pixsolid_opacity(pi, x2, 1, y, h, covered * fx2);
734	} else if (x1 == x2 && fx2 > fx1) {
735		pixsolid_opacity(pi, x1, 1, y, h, covered * (fx2 - fx1));
736	}
737}
738
739static bool
740composite_unaligned_boxes_inplace__solid(struct sna *sna,
741					 CARD8 op, uint32_t color,
742					 PicturePtr dst,
743					 int n, const xTrapezoid *t,
744					 bool force_fallback)
745{
746	PixmapPtr pixmap;
747	int16_t dx, dy;
748
749	DBG(("%s: force=%d, is_gpu=%d, op=%d, color=%x\n", __FUNCTION__,
750	     force_fallback, is_gpu(sna, dst->pDrawable, PREFER_GPU_SPANS), op, color));
751
752	if (!force_fallback && is_gpu(sna, dst->pDrawable, PREFER_GPU_SPANS)) {
753		DBG(("%s: fallback -- can not perform operation in place, destination busy\n",
754		     __FUNCTION__));
755
756		return false;
757	}
758
759	/* XXX a8 boxes */
760	if (!(dst->format == PICT_a8r8g8b8 || dst->format == PICT_x8r8g8b8)) {
761		DBG(("%s: fallback -- can not perform operation in place, unhanbled format %08lx\n",
762		     __FUNCTION__, (long)dst->format));
763
764		goto pixman;
765	}
766
767	pixmap = get_drawable_pixmap(dst->pDrawable);
768	get_drawable_deltas(dst->pDrawable, pixmap, &dx, &dy);
769
770	if (op == PictOpOver && (color >> 24) == 0xff)
771		op = PictOpSrc;
772	if (op == PictOpOver || op == PictOpAdd) {
773		struct sna_pixmap *priv = sna_pixmap(pixmap);
774		if (priv && priv->clear && priv->clear_color == 0)
775			op = PictOpSrc;
776	}
777
778	switch (op) {
779	case PictOpSrc:
780		break;
781	default:
782		DBG(("%s: fallback -- can not perform op [%d] in place\n",
783		     __FUNCTION__, op));
784		goto pixman;
785	}
786
787	DBG(("%s: inplace operation on argb32 destination x %d\n",
788	     __FUNCTION__, n));
789	do {
790		RegionRec clip;
791		const BoxRec *extents;
792		int count;
793
794		clip.extents.x1 = pixman_fixed_to_int(t->left.p1.x);
795		clip.extents.x2 = pixman_fixed_to_int(t->right.p1.x + pixman_fixed_1_minus_e);
796		clip.extents.y1 = pixman_fixed_to_int(t->top);
797		clip.extents.y2 = pixman_fixed_to_int(t->bottom + pixman_fixed_1_minus_e);
798		clip.data = NULL;
799
800		if (!sna_compute_composite_region(&clip,
801						   NULL, NULL, dst,
802						   0, 0,
803						   0, 0,
804						   clip.extents.x1, clip.extents.y1,
805						   clip.extents.x2 - clip.extents.x1,
806						   clip.extents.y2 - clip.extents.y1))
807			continue;
808
809		if (!sna_drawable_move_region_to_cpu(dst->pDrawable, &clip,
810						     MOVE_WRITE | MOVE_READ)) {
811			RegionUninit(&clip);
812			continue;
813		}
814
815		if (sigtrap_get() == 0) {
816			RegionTranslate(&clip, dx, dy);
817			count = region_num_rects(&clip);
818			extents = region_rects(&clip);
819			while (count--) {
820				int16_t y1 = dy + pixman_fixed_to_int(t->top);
821				uint16_t fy1 = pixman_fixed_frac(t->top);
822				int16_t y2 = dy + pixman_fixed_to_int(t->bottom);
823				uint16_t fy2 = pixman_fixed_frac(t->bottom);
824
825				DBG(("%s: t=(%d, %d), (%d, %d), extents (%d, %d), (%d, %d)\n",
826				     __FUNCTION__,
827				     pixman_fixed_to_int(t->left.p1.x),
828				     pixman_fixed_to_int(t->top),
829				     pixman_fixed_to_int(t->right.p2.x),
830				     pixman_fixed_to_int(t->bottom),
831				     extents->x1, extents->y1,
832				     extents->x2, extents->y2));
833
834				if (y1 < extents->y1)
835					y1 = extents->y1, fy1 = 0;
836				if (y2 >= extents->y2)
837					y2 = extents->y2, fy2 = 0;
838
839				if (y1 < y2) {
840					if (fy1) {
841						lerp32_unaligned_box_row(pixmap, color, extents,
842									 t, dx, y1, 1,
843									 SAMPLES_Y - grid_coverage(SAMPLES_Y, fy1));
844						y1++;
845					}
846
847					if (y2 > y1)
848						lerp32_unaligned_box_row(pixmap, color, extents,
849									 t, dx, y1, y2 - y1,
850									 SAMPLES_Y);
851
852					if (fy2)
853						lerp32_unaligned_box_row(pixmap, color,  extents,
854									 t, dx, y2, 1,
855									 grid_coverage(SAMPLES_Y, fy2));
856				} else if (y1 == y2 && fy2 > fy1) {
857					lerp32_unaligned_box_row(pixmap, color, extents,
858								 t, dx, y1, 1,
859								 grid_coverage(SAMPLES_Y, fy2) - grid_coverage(SAMPLES_Y, fy1));
860				}
861				extents++;
862			}
863			sigtrap_put();
864		}
865
866		RegionUninit(&clip);
867	} while (--n && t++);
868
869	return true;
870
871pixman:
872	do {
873		struct pixman_inplace pi;
874		RegionRec clip;
875		const BoxRec *extents;
876		int count;
877
878		clip.extents.x1 = pixman_fixed_to_int(t->left.p1.x);
879		clip.extents.x2 = pixman_fixed_to_int(t->right.p1.x + pixman_fixed_1_minus_e);
880		clip.extents.y1 = pixman_fixed_to_int(t->top);
881		clip.extents.y2 = pixman_fixed_to_int(t->bottom + pixman_fixed_1_minus_e);
882		clip.data = NULL;
883
884		if (!sna_compute_composite_region(&clip,
885						   NULL, NULL, dst,
886						   0, 0,
887						   0, 0,
888						   clip.extents.x1, clip.extents.y1,
889						   clip.extents.x2 - clip.extents.x1,
890						   clip.extents.y2 - clip.extents.y1))
891			continue;
892
893		if (!sna_drawable_move_region_to_cpu(dst->pDrawable, &clip,
894						     MOVE_WRITE | MOVE_READ)) {
895			RegionUninit(&clip);
896			continue;
897		}
898
899		pi.image = image_from_pict(dst, false, &pi.dx, &pi.dy);
900		pi.source = pixman_image_create_bits(PIXMAN_a8r8g8b8, 1, 1, NULL, 0);
901		pixman_image_set_repeat(pi.source, PIXMAN_REPEAT_NORMAL);
902		pi.bits = pixman_image_get_data(pi.source);
903		pi.color = color;
904		pi.op = op;
905
906		if (sigtrap_get() == 0) {
907			count = region_num_rects(&clip);
908			extents = region_rects(&clip);
909			while (count--) {
910				int16_t y1 = pixman_fixed_to_int(t->top);
911				uint16_t fy1 = pixman_fixed_frac(t->top);
912				int16_t y2 = pixman_fixed_to_int(t->bottom);
913				uint16_t fy2 = pixman_fixed_frac(t->bottom);
914
915				if (y1 < extents->y1)
916					y1 = extents->y1, fy1 = 0;
917				if (y2 >= extents->y2)
918					y2 = extents->y2, fy2 = 0;
919				if (y1 < y2) {
920					if (fy1) {
921						pixsolid_unaligned_box_row(&pi, extents, t, y1, 1,
922									   SAMPLES_Y - grid_coverage(SAMPLES_Y, fy1));
923						y1++;
924					}
925
926					if (y2 > y1)
927						pixsolid_unaligned_box_row(&pi, extents, t, y1, y2 - y1,
928									   SAMPLES_Y);
929
930					if (fy2)
931						pixsolid_unaligned_box_row(&pi, extents, t, y2, 1,
932									   grid_coverage(SAMPLES_Y, fy2));
933				} else if (y1 == y2 && fy2 > fy1) {
934					pixsolid_unaligned_box_row(&pi, extents, t, y1, 1,
935								   grid_coverage(SAMPLES_Y, fy2) - grid_coverage(SAMPLES_Y, fy1));
936				}
937				extents++;
938			}
939			sigtrap_put();
940		}
941
942		RegionUninit(&clip);
943		pixman_image_unref(pi.image);
944		pixman_image_unref(pi.source);
945	} while (--n && t++);
946	return true;
947}
948
949inline static void
950pixmask_opacity(struct pixman_inplace *pi,
951		int16_t x, int16_t w,
952		int16_t y, int16_t h,
953		uint8_t opacity)
954{
955	if (opacity == 0xff) {
956		pixman_image_composite(pi->op, pi->source, NULL, pi->image,
957				       pi->sx + x, pi->sy + y,
958				       0, 0,
959				       pi->dx + x, pi->dy + y,
960				       w, h);
961	} else {
962		*pi->bits = opacity;
963		pixman_image_composite(pi->op, pi->source, pi->mask, pi->image,
964				       pi->sx + x, pi->sy + y,
965				       0, 0,
966				       pi->dx + x, pi->dy + y,
967				       w, h);
968	}
969}
970
971static void
972pixmask_unaligned_box_row(struct pixman_inplace *pi,
973			  const BoxRec *extents,
974			  const xTrapezoid *trap,
975			  int16_t y, int16_t h,
976			  uint8_t covered)
977{
978	int16_t x1 = pixman_fixed_to_int(trap->left.p1.x);
979	uint16_t fx1 = grid_coverage(SAMPLES_X, trap->left.p1.x);
980	int16_t x2 = pixman_fixed_to_int(trap->right.p1.x);
981	uint16_t fx2 = grid_coverage(SAMPLES_X, trap->right.p1.x);
982
983	if (x1 < extents->x1)
984		x1 = extents->x1, fx1 = 0;
985	if (x2 >= extents->x2)
986		x2 = extents->x2, fx2 = 0;
987
988	if (x1 < x2) {
989		if (fx1) {
990			pixmask_opacity(pi, x1, 1, y, h,
991					 covered * (SAMPLES_X - fx1));
992			x1++;
993		}
994
995		if (x2 > x1)
996			pixmask_opacity(pi, x1, x2-x1, y, h, covered*SAMPLES_X);
997
998		if (fx2)
999			pixmask_opacity(pi, x2, 1, y, h, covered * fx2);
1000	} else if (x1 == x2 && fx2 > fx1) {
1001		pixmask_opacity(pi, x1, 1, y, h, covered * (fx2 - fx1));
1002	}
1003}
1004
1005struct rectilinear_inplace_thread {
1006	pixman_image_t *dst, *src;
1007	const RegionRec *clip;
1008	const xTrapezoid *trap;
1009	int dx, dy, sx, sy;
1010	int y1, y2;
1011	CARD8 op;
1012};
1013
1014static void rectilinear_inplace_thread(void *arg)
1015{
1016	struct rectilinear_inplace_thread *thread = arg;
1017	const xTrapezoid *t = thread->trap;
1018	struct pixman_inplace pi;
1019	const BoxRec *extents;
1020	int count;
1021
1022	pi.image = thread->dst;
1023	pi.dx = thread->dx;
1024	pi.dy = thread->dy;
1025
1026	pi.source = thread->src;
1027	pi.sx = thread->sx;
1028	pi.sy = thread->sy;
1029
1030	pi.mask = pixman_image_create_bits(PIXMAN_a8, 1, 1, &pi.color, 4);
1031	pixman_image_set_repeat(pi.mask, PIXMAN_REPEAT_NORMAL);
1032	pi.bits = pixman_image_get_data(pi.mask);
1033	pi.op = thread->op;
1034
1035	count = region_count(thread->clip);
1036	extents = region_boxes(thread->clip);
1037	while (count--) {
1038		int16_t y1 = pixman_fixed_to_int(t->top);
1039		uint16_t fy1 = pixman_fixed_frac(t->top);
1040		int16_t y2 = pixman_fixed_to_int(t->bottom);
1041		uint16_t fy2 = pixman_fixed_frac(t->bottom);
1042
1043		if (y1 < MAX(thread->y1, extents->y1))
1044			y1 = MAX(thread->y1, extents->y1), fy1 = 0;
1045		if (y2 > MIN(thread->y2, extents->y2))
1046			y2 = MIN(thread->y2, extents->y2), fy2 = 0;
1047		if (y1 < y2) {
1048			if (fy1) {
1049				pixmask_unaligned_box_row(&pi, extents, t, y1, 1,
1050							  SAMPLES_Y - grid_coverage(SAMPLES_Y, fy1));
1051				y1++;
1052			}
1053
1054			if (y2 > y1)
1055				pixmask_unaligned_box_row(&pi, extents, t, y1, y2 - y1,
1056							  SAMPLES_Y);
1057
1058			if (fy2)
1059				pixmask_unaligned_box_row(&pi, extents, t, y2, 1,
1060							  grid_coverage(SAMPLES_Y, fy2));
1061		} else if (y1 == y2 && fy2 > fy1) {
1062			pixmask_unaligned_box_row(&pi, extents, t, y1, 1,
1063						  grid_coverage(SAMPLES_Y, fy2) - grid_coverage(SAMPLES_Y, fy1));
1064		}
1065		extents++;
1066	}
1067
1068	pixman_image_unref(pi.mask);
1069}
1070
1071static bool
1072composite_unaligned_boxes_inplace(struct sna *sna,
1073				  CARD8 op,
1074				  PicturePtr src, int16_t src_x, int16_t src_y,
1075				  PicturePtr dst, int n, const xTrapezoid *t,
1076				  bool force_fallback)
1077{
1078	if (!force_fallback &&
1079	    (is_gpu(sna, dst->pDrawable, PREFER_GPU_SPANS) ||
1080	     picture_is_gpu(sna, src, PREFER_GPU_SPANS))) {
1081		DBG(("%s: fallback -- not forcing\n", __FUNCTION__));
1082		return false;
1083	}
1084
1085	DBG(("%s\n", __FUNCTION__));
1086
1087	src_x -= pixman_fixed_to_int(t[0].left.p1.x);
1088	src_y -= pixman_fixed_to_int(t[0].left.p1.y);
1089	do {
1090		RegionRec clip;
1091		const BoxRec *extents;
1092		int count;
1093		int num_threads;
1094
1095		clip.extents.x1 = pixman_fixed_to_int(t->left.p1.x);
1096		clip.extents.x2 = pixman_fixed_to_int(t->right.p1.x + pixman_fixed_1_minus_e);
1097		clip.extents.y1 = pixman_fixed_to_int(t->top);
1098		clip.extents.y2 = pixman_fixed_to_int(t->bottom + pixman_fixed_1_minus_e);
1099		clip.data = NULL;
1100
1101		if (!sna_compute_composite_region(&clip,
1102						   src, NULL, dst,
1103						   clip.extents.x1 + src_x,
1104						   clip.extents.y1 + src_y,
1105						   0, 0,
1106						   clip.extents.x1, clip.extents.y1,
1107						   clip.extents.x2 - clip.extents.x1,
1108						   clip.extents.y2 - clip.extents.y1))
1109			continue;
1110
1111		if (!sna_drawable_move_region_to_cpu(dst->pDrawable, &clip,
1112						     MOVE_WRITE | MOVE_READ)) {
1113			RegionUninit(&clip);
1114			continue;
1115		}
1116
1117		if (src->pDrawable) {
1118			if (!sna_drawable_move_to_cpu(src->pDrawable,
1119						      MOVE_READ)) {
1120				RegionUninit(&clip);
1121				continue;
1122			}
1123			if (src->alphaMap) {
1124				if (!sna_drawable_move_to_cpu(src->alphaMap->pDrawable,
1125							      MOVE_READ)) {
1126					RegionUninit(&clip);
1127					continue;
1128				}
1129			}
1130		}
1131
1132		num_threads = sna_use_threads(clip.extents.x2 - clip.extents.x1,
1133					      clip.extents.y2 - clip.extents.y1,
1134					      32);
1135		if (num_threads == 1) {
1136			struct pixman_inplace pi;
1137
1138			pi.image = image_from_pict(dst, false, &pi.dx, &pi.dy);
1139			pi.source = image_from_pict(src, false, &pi.sx, &pi.sy);
1140			pi.sx += src_x;
1141			pi.sy += src_y;
1142			pi.mask = pixman_image_create_bits(PIXMAN_a8, 1, 1, &pi.color, 4);
1143			pixman_image_set_repeat(pi.mask, PIXMAN_REPEAT_NORMAL);
1144			pi.bits = pixman_image_get_data(pi.mask);
1145			pi.op = op;
1146
1147			if (sigtrap_get() == 0) {
1148				count = region_num_rects(&clip);
1149				extents = region_rects(&clip);
1150				while (count--) {
1151					int16_t y1 = pixman_fixed_to_int(t->top);
1152					uint16_t fy1 = pixman_fixed_frac(t->top);
1153					int16_t y2 = pixman_fixed_to_int(t->bottom);
1154					uint16_t fy2 = pixman_fixed_frac(t->bottom);
1155
1156					if (y1 < extents->y1)
1157						y1 = extents->y1, fy1 = 0;
1158					if (y2 > extents->y2)
1159						y2 = extents->y2, fy2 = 0;
1160					if (y1 < y2) {
1161						if (fy1) {
1162							pixmask_unaligned_box_row(&pi, extents, t, y1, 1,
1163										  SAMPLES_Y - grid_coverage(SAMPLES_Y, fy1));
1164							y1++;
1165						}
1166
1167						if (y2 > y1)
1168							pixmask_unaligned_box_row(&pi, extents, t, y1, y2 - y1,
1169										  SAMPLES_Y);
1170
1171						if (fy2)
1172							pixmask_unaligned_box_row(&pi, extents, t, y2, 1,
1173										  grid_coverage(SAMPLES_Y, fy2));
1174					} else if (y1 == y2 && fy2 > fy1) {
1175						pixmask_unaligned_box_row(&pi, extents, t, y1, 1,
1176									  grid_coverage(SAMPLES_Y, fy2) - grid_coverage(SAMPLES_Y, fy1));
1177					}
1178					extents++;
1179				}
1180				sigtrap_put();
1181			}
1182
1183			pixman_image_unref(pi.image);
1184			pixman_image_unref(pi.source);
1185			pixman_image_unref(pi.mask);
1186		} else {
1187			struct rectilinear_inplace_thread thread[num_threads];
1188			int i, y, dy;
1189
1190
1191			thread[0].trap = t;
1192			thread[0].dst = image_from_pict(dst, false, &thread[0].dx, &thread[0].dy);
1193			thread[0].src = image_from_pict(src, false, &thread[0].sx, &thread[0].sy);
1194			thread[0].sx += src_x;
1195			thread[0].sy += src_y;
1196
1197			thread[0].clip = &clip;
1198			thread[0].op = op;
1199
1200			y = clip.extents.y1;
1201			dy = (clip.extents.y2 - clip.extents.y1 + num_threads - 1) / num_threads;
1202			num_threads = (clip.extents.y2 - clip.extents.y1 + dy - 1) / dy;
1203
1204			if (sigtrap_get() == 0) {
1205				for (i = 1; i < num_threads; i++) {
1206					thread[i] = thread[0];
1207					thread[i].y1 = y;
1208					thread[i].y2 = y += dy;
1209					sna_threads_run(i, rectilinear_inplace_thread, &thread[i]);
1210				}
1211
1212				assert(y < clip.extents.y2);
1213				thread[0].y1 = y;
1214				thread[0].y2 = clip.extents.y2;
1215				rectilinear_inplace_thread(&thread[0]);
1216
1217				sna_threads_wait();
1218				sigtrap_put();
1219			} else
1220				sna_threads_kill();
1221
1222			pixman_image_unref(thread[0].dst);
1223			pixman_image_unref(thread[0].src);
1224		}
1225
1226		RegionUninit(&clip);
1227	} while (--n && t++);
1228
1229	return true;
1230}
1231
1232static bool
1233composite_unaligned_boxes_fallback(struct sna *sna,
1234				   CARD8 op,
1235				   PicturePtr src,
1236				   PicturePtr dst,
1237				   INT16 src_x, INT16 src_y,
1238				   int ntrap, const xTrapezoid *traps,
1239				   bool force_fallback)
1240{
1241	ScreenPtr screen = dst->pDrawable->pScreen;
1242	uint32_t color;
1243	int16_t dst_x, dst_y;
1244	int16_t dx, dy;
1245	int n;
1246
1247	if (sna_picture_is_solid(src, &color) &&
1248	    composite_unaligned_boxes_inplace__solid(sna, op, color, dst,
1249						     ntrap, traps,
1250						     force_fallback))
1251		return true;
1252
1253	if (composite_unaligned_boxes_inplace(sna, op, src, src_x, src_y,
1254					      dst, ntrap, traps,
1255					      force_fallback))
1256		return true;
1257
1258	trapezoid_origin(&traps[0].left, &dst_x, &dst_y);
1259	dx = dst->pDrawable->x;
1260	dy = dst->pDrawable->y;
1261	for (n = 0; n < ntrap; n++) {
1262		const xTrapezoid *t = &traps[n];
1263		PixmapPtr scratch;
1264		PicturePtr mask;
1265		BoxRec extents;
1266		int error;
1267		int y1, y2;
1268
1269		extents.x1 = pixman_fixed_to_int(t->left.p1.x);
1270		extents.x2 = pixman_fixed_to_int(t->right.p1.x + pixman_fixed_1_minus_e);
1271		extents.y1 = pixman_fixed_to_int(t->top);
1272		extents.y2 = pixman_fixed_to_int(t->bottom + pixman_fixed_1_minus_e);
1273
1274		if (!sna_compute_composite_extents(&extents,
1275						   src, NULL, dst,
1276						   src_x, src_y,
1277						   0, 0,
1278						   extents.x1, extents.y1,
1279						   extents.x2 - extents.x1,
1280						   extents.y2 - extents.y1))
1281			continue;
1282
1283		if (force_fallback)
1284			scratch = sna_pixmap_create_unattached(screen,
1285							       extents.x2 - extents.x1,
1286							       extents.y2 - extents.y1,
1287							       8);
1288		else
1289			scratch = sna_pixmap_create_upload(screen,
1290							   extents.x2 - extents.x1,
1291							   extents.y2 - extents.y1,
1292							   8, KGEM_BUFFER_WRITE_INPLACE);
1293		if (!scratch)
1294			continue;
1295
1296		memset(scratch->devPrivate.ptr, 0xff,
1297		       scratch->devKind * (extents.y2 - extents.y1));
1298
1299		extents.x1 -= dx;
1300		extents.x2 -= dx;
1301		extents.y1 -= dy;
1302		extents.y2 -= dy;
1303
1304		y1 = pixman_fixed_to_int(t->top) - extents.y1;
1305		y2 = pixman_fixed_to_int(t->bottom) - extents.y1;
1306
1307		if (y1 == y2) {
1308			blt_unaligned_box_row(scratch, &extents, t, y1, y1 + 1,
1309					      grid_coverage(SAMPLES_Y, t->bottom) - grid_coverage(SAMPLES_Y, t->top));
1310		} else {
1311			if (pixman_fixed_frac(t->top)) {
1312				blt_unaligned_box_row(scratch, &extents, t, y1, y1 + 1,
1313						      SAMPLES_Y - grid_coverage(SAMPLES_Y, t->top));
1314				y1++;
1315			}
1316
1317			if (y2 > y1)
1318				blt_unaligned_box_row(scratch, &extents, t, y1, y2,
1319						      SAMPLES_Y);
1320
1321			if (pixman_fixed_frac(t->bottom))
1322				blt_unaligned_box_row(scratch, &extents, t, y2, y2+1,
1323						      grid_coverage(SAMPLES_Y, t->bottom));
1324		}
1325
1326		mask = CreatePicture(0, &scratch->drawable,
1327				     PictureMatchFormat(screen, 8, PICT_a8),
1328				     0, 0, serverClient, &error);
1329		if (mask) {
1330			CompositePicture(op, src, mask, dst,
1331					 src_x + extents.x1 - dst_x,
1332					 src_y + extents.y1 - dst_y,
1333					 0, 0,
1334					 extents.x1, extents.y1,
1335					 extents.x2 - extents.x1,
1336					 extents.y2 - extents.y1);
1337			FreePicture(mask, 0);
1338		}
1339		sna_pixmap_destroy(scratch);
1340	}
1341
1342	return true;
1343}
1344
1345bool
1346composite_unaligned_boxes(struct sna *sna,
1347			  CARD8 op,
1348			  PicturePtr src,
1349			  PicturePtr dst,
1350			  PictFormatPtr maskFormat,
1351			  INT16 src_x, INT16 src_y,
1352			  int ntrap, const xTrapezoid *traps,
1353			  bool force_fallback)
1354{
1355	BoxRec extents;
1356	struct sna_composite_spans_op tmp;
1357	struct sna_pixmap *priv;
1358	pixman_region16_t clip, *c;
1359	int16_t dst_x, dst_y;
1360	int dx, dy, n;
1361
1362	if (NO_UNALIGNED_BOXES)
1363		return false;
1364
1365	DBG(("%s: force_fallback=%d, mask=%x, n=%d, op=%d\n",
1366	     __FUNCTION__, force_fallback, maskFormat ? (int)maskFormat->format : 0, ntrap, op));
1367
1368	/* need a span converter to handle overlapping traps */
1369	if (ntrap > 1 && maskFormat)
1370		return false;
1371
1372	if (force_fallback ||
1373	    !sna->render.check_composite_spans(sna, op, src, dst, 0, 0,
1374					       COMPOSITE_SPANS_RECTILINEAR)) {
1375fallback:
1376		return composite_unaligned_boxes_fallback(sna, op, src, dst,
1377							  src_x, src_y,
1378							  ntrap, traps,
1379							  force_fallback);
1380	}
1381
1382	trapezoid_origin(&traps[0].left, &dst_x, &dst_y);
1383
1384	extents.x1 = pixman_fixed_to_int(traps[0].left.p1.x);
1385	extents.x2 = pixman_fixed_to_int(traps[0].right.p1.x + pixman_fixed_1_minus_e);
1386	extents.y1 = pixman_fixed_to_int(traps[0].top);
1387	extents.y2 = pixman_fixed_to_int(traps[0].bottom + pixman_fixed_1_minus_e);
1388
1389	DBG(("%s: src=(%d, %d), dst=(%d, %d)\n",
1390	     __FUNCTION__, src_x, src_y, dst_x, dst_y));
1391
1392	for (n = 1; n < ntrap; n++) {
1393		int x1 = pixman_fixed_to_int(traps[n].left.p1.x);
1394		int x2 = pixman_fixed_to_int(traps[n].right.p1.x + pixman_fixed_1_minus_e);
1395		int y1 = pixman_fixed_to_int(traps[n].top);
1396		int y2 = pixman_fixed_to_int(traps[n].bottom + pixman_fixed_1_minus_e);
1397
1398		if (x1 < extents.x1)
1399			extents.x1 = x1;
1400		if (x2 > extents.x2)
1401			extents.x2 = x2;
1402		if (y1 < extents.y1)
1403			extents.y1 = y1;
1404		if (y2 > extents.y2)
1405			extents.y2 = y2;
1406	}
1407
1408	DBG(("%s: extents (%d, %d), (%d, %d)\n", __FUNCTION__,
1409	     extents.x1, extents.y1, extents.x2, extents.y2));
1410
1411	if (!sna_compute_composite_region(&clip,
1412					  src, NULL, dst,
1413					  src_x + extents.x1 - dst_x,
1414					  src_y + extents.y1 - dst_y,
1415					  0, 0,
1416					  extents.x1, extents.y1,
1417					  extents.x2 - extents.x1,
1418					  extents.y2 - extents.y1)) {
1419		DBG(("%s: trapezoids do not intersect drawable clips\n",
1420		     __FUNCTION__)) ;
1421		return true;
1422	}
1423
1424	if (!sna->render.check_composite_spans(sna, op, src, dst,
1425					       clip.extents.x2 - clip.extents.x1,
1426					       clip.extents.y2 - clip.extents.y1,
1427					       COMPOSITE_SPANS_RECTILINEAR)) {
1428		DBG(("%s: fallback -- composite spans not supported\n",
1429		     __FUNCTION__));
1430		goto fallback;
1431	}
1432
1433	c = NULL;
1434	if (extents.x2 - extents.x1 > clip.extents.x2 - clip.extents.x1 ||
1435	    extents.y2 - extents.y1 > clip.extents.y2 - clip.extents.y1) {
1436		DBG(("%s: forcing clip\n", __FUNCTION__));
1437		c = &clip;
1438	}
1439
1440	extents = *RegionExtents(&clip);
1441	dx = dst->pDrawable->x;
1442	dy = dst->pDrawable->y;
1443
1444	DBG(("%s: after clip -- extents (%d, %d), (%d, %d), delta=(%d, %d) src -> (%d, %d)\n",
1445	     __FUNCTION__,
1446	     extents.x1, extents.y1,
1447	     extents.x2, extents.y2,
1448	     dx, dy,
1449	     src_x + extents.x1 - dst_x - dx,
1450	     src_y + extents.y1 - dst_y - dy));
1451
1452	switch (op) {
1453	case PictOpAdd:
1454	case PictOpOver:
1455		priv = sna_pixmap(get_drawable_pixmap(dst->pDrawable));
1456		assert(priv != NULL);
1457		if (priv->clear && priv->clear_color == 0) {
1458			DBG(("%s: converting %d to PictOpSrc\n",
1459			     __FUNCTION__, op));
1460			op = PictOpSrc;
1461		}
1462		break;
1463	case PictOpIn:
1464		priv = sna_pixmap(get_drawable_pixmap(dst->pDrawable));
1465		assert(priv != NULL);
1466		if (priv->clear && priv->clear_color == 0) {
1467			DBG(("%s: clear destination using In, skipping\n",
1468			     __FUNCTION__));
1469			return true;
1470		}
1471		break;
1472	}
1473
1474	if (!sna->render.composite_spans(sna, op, src, dst,
1475					 src_x + extents.x1 - dst_x - dx,
1476					 src_y + extents.y1 - dst_y - dy,
1477					 extents.x1,  extents.y1,
1478					 extents.x2 - extents.x1,
1479					 extents.y2 - extents.y1,
1480					 COMPOSITE_SPANS_RECTILINEAR,
1481					 memset(&tmp, 0, sizeof(tmp)))) {
1482		DBG(("%s: composite spans render op not supported\n",
1483		     __FUNCTION__));
1484		REGION_UNINIT(NULL, &clip);
1485		goto fallback;
1486	}
1487
1488	for (n = 0; n < ntrap; n++)
1489		composite_unaligned_trap(sna, &tmp, &traps[n], dx, dy, c);
1490	tmp.done(sna, &tmp);
1491	REGION_UNINIT(NULL, &clip);
1492	return true;
1493}
1494