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
55inline static xFixed
56line_x_for_y(const xLineFixed *l, xFixed y, bool ceil)
57{
58	xFixed_32_32 ex = (xFixed_32_32)(y - l->p1.y) * (l->p2.x - l->p1.x);
59	xFixed d = l->p2.y - l->p1.y;
60
61	if (ceil)
62		ex += (d - 1);
63
64	return l->p1.x + (xFixed) (ex / d);
65}
66
67bool trapezoids_bounds(int n, const xTrapezoid *t, BoxPtr box)
68{
69	xFixed x1, y1, x2, y2;
70
71	/* XXX need 33 bits... */
72	x1 = y1 = INT_MAX / 2;
73	x2 = y2 = INT_MIN / 2;
74
75	do {
76		xFixed fx1, fx2, v;
77
78		if (!xTrapezoidValid(t)) {
79			__DBG(("%s: skipping invalid trapezoid: top=%d, bottom=%d, left=(%d, %d), (%d, %d), right=(%d, %d), (%d, %d)\n",
80			       __FUNCTION__,
81			       t->top, t->bottom,
82			       t->left.p1.x, t->left.p1.y,
83			       t->left.p2.x, t->left.p2.y,
84			       t->right.p1.x, t->right.p1.y,
85			       t->right.p2.x, t->right.p2.y));
86			continue;
87		}
88
89		if (t->top < y1)
90			y1 = t->top;
91		if (t->bottom > y2)
92			y2 = t->bottom;
93
94		if (((t->left.p1.x - x1) | (t->left.p2.x - x1)) < 0) {
95			if (pixman_fixed_floor(t->left.p1.x) == pixman_fixed_floor(t->left.p2.x)) {
96				x1 = pixman_fixed_floor(t->left.p1.x);
97			} else {
98				if (t->left.p1.y == t->top)
99					fx1 = t->left.p1.x;
100				else
101					fx1 = line_x_for_y(&t->left, t->top, false);
102
103				if (t->left.p2.y == t->bottom)
104					fx2 = t->left.p2.x;
105				else
106					fx2 = line_x_for_y(&t->left, t->bottom, false);
107
108				v = min(fx1, fx2);
109				if (v < x1)
110					x1 = pixman_fixed_floor(v);
111			}
112		}
113
114		if (((x2 - t->right.p1.x) | (x2 - t->right.p2.x)) < 0) {
115			if (pixman_fixed_ceil(t->right.p1.x) == pixman_fixed_ceil(t->right.p2.x)) {
116				x2 = pixman_fixed_ceil(t->right.p1.x);
117			} else {
118				if (t->right.p1.y == t->top)
119					fx1 = t->right.p1.x;
120				else
121					fx1 = line_x_for_y(&t->right, t->top, true);
122
123				if (t->right.p2.y == t->bottom)
124					fx2 = t->right.p2.x;
125				else
126					fx2 = line_x_for_y(&t->right, t->bottom, true);
127
128				v = max(fx1, fx2);
129				if (v > x2)
130					x2 = pixman_fixed_ceil(v);
131			}
132		}
133	} while (t++, --n);
134
135	box->x1 = pixman_fixed_to_int(x1);
136	box->x2 = pixman_fixed_to_int(x2);
137	box->y1 = pixman_fixed_integer_floor(y1);
138	box->y2 = pixman_fixed_integer_ceil(y2);
139
140	return box->x2 > box->x1 && box->y2 > box->y1;
141}
142
143static bool
144trapezoids_inplace_fallback(struct sna *sna,
145			    CARD8 op,
146			    PicturePtr src, PicturePtr dst, PictFormatPtr mask,
147			    int ntrap, xTrapezoid *traps)
148{
149	pixman_image_t *image;
150	BoxRec box;
151	uint32_t color;
152	int dx, dy;
153
154	if (op != PictOpAdd)
155		return false;
156
157	if (is_mono(dst, mask)) {
158		if (dst->format != PICT_a1)
159			return false;
160	} else {
161		if (dst->format != PICT_a8)
162			return false;
163	}
164
165	if (!sna_picture_is_solid(src, &color) || (color >> 24) != 0xff) {
166		DBG(("%s: not an opaque solid source\n", __FUNCTION__));
167		return false;
168	}
169
170	box.x1 = dst->pDrawable->x;
171	box.y1 = dst->pDrawable->y;
172	box.x2 = dst->pDrawable->width;
173	box.y2 = dst->pDrawable->height;
174	if (pixman_region_contains_rectangle(dst->pCompositeClip,
175					     &box) != PIXMAN_REGION_IN) {
176		DBG(("%s: requires clipping, drawable (%d,%d), (%d, %d), clip (%d, %d), (%d, %d)\n", __FUNCTION__,
177		     box.x1, box.y1, box.x2, box.y2,
178		     dst->pCompositeClip->extents.x1,
179		     dst->pCompositeClip->extents.y1,
180		     dst->pCompositeClip->extents.x2,
181		     dst->pCompositeClip->extents.y2));
182		return false;
183	}
184
185	if (is_gpu(sna, dst->pDrawable, PREFER_GPU_SPANS)) {
186		DBG(("%s: not performing inplace as dst is already on the GPU\n",
187		     __FUNCTION__));
188		return false;
189	}
190
191	DBG(("%s\n", __FUNCTION__));
192
193	image = NULL;
194	if (sna_drawable_move_to_cpu(dst->pDrawable, MOVE_READ | MOVE_WRITE))
195		image = image_from_pict(dst, false, &dx, &dy);
196	if (image) {
197		dx += dst->pDrawable->x;
198		dy += dst->pDrawable->y;
199
200		if (sigtrap_get() == 0) {
201			for (; ntrap; ntrap--, traps++)
202				if (xTrapezoidValid(traps))
203					pixman_rasterize_trapezoid(image,
204								   (pixman_trapezoid_t *)traps,
205								   dx, dy);
206			sigtrap_put();
207		}
208
209		pixman_image_unref(image);
210	}
211
212	return true;
213}
214
215struct rasterize_traps_thread {
216	xTrapezoid *traps;
217	char *ptr;
218	int stride;
219	BoxRec bounds;
220	pixman_format_code_t format;
221	int ntrap;
222};
223
224static void rasterize_traps_thread(void *arg)
225{
226	struct rasterize_traps_thread *thread = arg;
227	pixman_image_t *image;
228	int width, height, n;
229
230	width = thread->bounds.x2 - thread->bounds.x1;
231	height = thread->bounds.y2 - thread->bounds.y1;
232
233	memset(thread->ptr, 0, thread->stride*height);
234	if (PIXMAN_FORMAT_DEPTH(thread->format) < 8)
235		image = pixman_image_create_bits(thread->format,
236						 width, height,
237						 NULL, 0);
238	else
239		image = pixman_image_create_bits(thread->format,
240						 width, height,
241						 (uint32_t *)thread->ptr,
242						 thread->stride);
243	if (image == NULL)
244		return;
245
246	for (n = 0; n < thread->ntrap; n++)
247		if (xTrapezoidValid(&thread->traps[n]))
248			pixman_rasterize_trapezoid(image,
249						   (pixman_trapezoid_t *)&thread->traps[n],
250						   -thread->bounds.x1, -thread->bounds.y1);
251
252	if (PIXMAN_FORMAT_DEPTH(thread->format) < 8) {
253		pixman_image_t *a8;
254
255		a8 = pixman_image_create_bits(PIXMAN_a8,
256					      width, height,
257					      (uint32_t *)thread->ptr,
258					      thread->stride);
259		if (a8) {
260			pixman_image_composite(PIXMAN_OP_SRC,
261					       image, NULL, a8,
262					       0, 0,
263					       0, 0,
264					       0, 0,
265					       width, height);
266			pixman_image_unref(a8);
267		}
268	}
269
270	pixman_image_unref(image);
271}
272
273static void
274trapezoids_fallback(struct sna *sna,
275		    CARD8 op, PicturePtr src, PicturePtr dst,
276		    PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
277		    int ntrap, xTrapezoid * traps)
278{
279	ScreenPtr screen = dst->pDrawable->pScreen;
280
281	if (maskFormat) {
282		PixmapPtr scratch;
283		PicturePtr mask;
284		INT16 dst_x, dst_y;
285		BoxRec bounds;
286		int width, height, depth;
287		pixman_image_t *image;
288		pixman_format_code_t format;
289		int error;
290
291		trapezoid_origin(&traps[0].left, &dst_x, &dst_y);
292
293		if (!trapezoids_bounds(ntrap, traps, &bounds))
294			return;
295
296		DBG(("%s: bounds (%d, %d), (%d, %d)\n", __FUNCTION__,
297		     bounds.x1, bounds.y1, bounds.x2, bounds.y2));
298
299		if (!sna_compute_composite_extents(&bounds,
300						   src, NULL, dst,
301						   xSrc, ySrc,
302						   0, 0,
303						   bounds.x1, bounds.y1,
304						   bounds.x2 - bounds.x1,
305						   bounds.y2 - bounds.y1))
306			return;
307
308		DBG(("%s: extents (%d, %d), (%d, %d)\n", __FUNCTION__,
309		     bounds.x1, bounds.y1, bounds.x2, bounds.y2));
310
311		width  = bounds.x2 - bounds.x1;
312		height = bounds.y2 - bounds.y1;
313		bounds.x1 -= dst->pDrawable->x;
314		bounds.y1 -= dst->pDrawable->y;
315		bounds.x2 -= dst->pDrawable->x;
316		bounds.y2 -= dst->pDrawable->y;
317		depth = maskFormat->depth;
318		if (depth == 1) {
319			format = PIXMAN_a1;
320		} else if (depth <= 4) {
321			format = PIXMAN_a4;
322			depth = 4;
323		} else
324			format = PIXMAN_a8;
325
326		DBG(("%s: mask (%dx%d) depth=%d, format=%08x\n",
327		     __FUNCTION__, width, height, depth, format));
328		if (is_gpu(sna, dst->pDrawable, PREFER_GPU_RENDER) ||
329		    picture_is_gpu(sna, src, PREFER_GPU_RENDER)) {
330			int num_threads;
331
332			scratch = sna_pixmap_create_upload(screen,
333							   width, height, 8,
334							   KGEM_BUFFER_WRITE);
335			if (!scratch)
336				return;
337
338			num_threads = sna_use_threads(width, height, 8);
339			if (num_threads == 1) {
340				if (depth < 8) {
341					image = pixman_image_create_bits(format, width, height,
342									 NULL, 0);
343				} else {
344					memset(scratch->devPrivate.ptr, 0, scratch->devKind*height);
345
346					image = pixman_image_create_bits(format, width, height,
347									 scratch->devPrivate.ptr,
348									 scratch->devKind);
349				}
350				if (image) {
351					for (; ntrap; ntrap--, traps++)
352						if (xTrapezoidValid(traps))
353							pixman_rasterize_trapezoid(image,
354										   (pixman_trapezoid_t *)traps,
355										   -bounds.x1, -bounds.y1);
356					if (depth < 8) {
357						pixman_image_t *a8;
358
359						a8 = pixman_image_create_bits(PIXMAN_a8, width, height,
360									      scratch->devPrivate.ptr,
361									      scratch->devKind);
362						if (a8) {
363							pixman_image_composite(PIXMAN_OP_SRC,
364									       image, NULL, a8,
365									       0, 0,
366									       0, 0,
367									       0, 0,
368									       width, height);
369							format = PIXMAN_a8;
370							depth = 8;
371							pixman_image_unref(a8);
372						}
373					}
374
375					pixman_image_unref(image);
376				}
377				if (format != PIXMAN_a8) {
378					sna_pixmap_destroy(scratch);
379					return;
380				}
381			} else {
382				struct rasterize_traps_thread threads[num_threads];
383				int y, dy, n;
384
385				threads[0].ptr = scratch->devPrivate.ptr;
386				threads[0].stride = scratch->devKind;
387				threads[0].traps = traps;
388				threads[0].ntrap = ntrap;
389				threads[0].bounds = bounds;
390				threads[0].format = format;
391
392				y = bounds.y1;
393				dy = (height + num_threads - 1) / num_threads;
394				num_threads -= (num_threads-1) * dy >= bounds.y2 - bounds.y1;
395
396				if (sigtrap_get() == 0) {
397					for (n = 1; n < num_threads; n++) {
398						threads[n] = threads[0];
399						threads[n].ptr += (y - bounds.y1) * threads[n].stride;
400						threads[n].bounds.y1 = y;
401						threads[n].bounds.y2 = y += dy;
402
403						sna_threads_run(n, rasterize_traps_thread, &threads[n]);
404					}
405
406					assert(y < threads[0].bounds.y2);
407					threads[0].ptr += (y - bounds.y1) * threads[0].stride;
408					threads[0].bounds.y1 = y;
409					rasterize_traps_thread(&threads[0]);
410
411					sna_threads_wait();
412					sigtrap_put();
413				} else
414					sna_threads_kill();
415
416				format = PIXMAN_a8;
417				depth = 8;
418			}
419		} else {
420			scratch = sna_pixmap_create_unattached(screen,
421							       width, height,
422							       depth);
423			if (!scratch)
424				return;
425
426			memset(scratch->devPrivate.ptr, 0, scratch->devKind*height);
427			image = pixman_image_create_bits(format, width, height,
428							 scratch->devPrivate.ptr,
429							 scratch->devKind);
430			if (image) {
431				for (; ntrap; ntrap--, traps++)
432					if (xTrapezoidValid(traps))
433						pixman_rasterize_trapezoid(image,
434									   (pixman_trapezoid_t *)traps,
435									   -bounds.x1, -bounds.y1);
436				pixman_image_unref(image);
437			}
438		}
439
440		mask = CreatePicture(0, &scratch->drawable,
441				     PictureMatchFormat(screen, depth, format),
442				     0, 0, serverClient, &error);
443		if (mask) {
444			CompositePicture(op, src, mask, dst,
445					 xSrc + bounds.x1 - dst_x,
446					 ySrc + bounds.y1 - dst_y,
447					 0, 0,
448					 bounds.x1, bounds.y1,
449					 width, height);
450			FreePicture(mask, 0);
451		}
452		sna_pixmap_destroy(scratch);
453	} else {
454		if (dst->polyEdge == PolyEdgeSharp)
455			maskFormat = PictureMatchFormat(screen, 1, PICT_a1);
456		else
457			maskFormat = PictureMatchFormat(screen, 8, PICT_a8);
458
459		for (; ntrap; ntrap--, traps++)
460			trapezoids_fallback(sna, op,
461					    src, dst, maskFormat,
462					    xSrc, ySrc, 1, traps);
463	}
464}
465
466static bool
467trapezoid_spans_maybe_inplace(struct sna *sna,
468			      CARD8 op, PicturePtr src, PicturePtr dst,
469			      PictFormatPtr maskFormat)
470{
471	struct sna_pixmap *priv;
472
473	if (NO_SCAN_CONVERTER)
474		return false;
475
476	if (dst->alphaMap)
477		return false;
478	if (is_mono(dst, maskFormat))
479		goto out;
480
481	switch ((int)dst->format) {
482	case PICT_a8:
483		if (!sna_picture_is_solid(src, NULL))
484			return false;
485
486		switch (op) {
487		case PictOpIn:
488		case PictOpAdd:
489		case PictOpSrc:
490			break;
491		default:
492			return false;
493		}
494		break;
495
496	case PICT_x8r8g8b8:
497	case PICT_a8r8g8b8:
498		if (picture_is_gpu(sna, src, 0))
499			return false;
500
501		switch (op) {
502		case PictOpOver:
503		case PictOpAdd:
504		case PictOpOutReverse:
505			break;
506		case PictOpSrc:
507			if (sna_picture_is_solid(src, NULL))
508				break;
509
510			if (!sna_drawable_is_clear(dst->pDrawable))
511				return false;
512			break;
513		default:
514			return false;
515		}
516		break;
517	default:
518		return false;
519	}
520
521out:
522	priv = sna_pixmap_from_drawable(dst->pDrawable);
523	if (priv == NULL) {
524		DBG(("%s? yes -- unattached\n", __FUNCTION__));
525		return true;
526	}
527
528	if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo)) {
529		DBG(("%s? no -- CPU bo is busy\n", __FUNCTION__));
530		return false;
531	}
532
533	if (DAMAGE_IS_ALL(priv->cpu_damage) || priv->gpu_damage == NULL) {
534		DBG(("%s? yes -- damaged on CPU only (all? %d)\n", __FUNCTION__, DAMAGE_IS_ALL(priv->cpu_damage)));
535		return true;
536	}
537
538	if (priv->clear) {
539		DBG(("%s? clear, %s\n", __FUNCTION__,
540		     dst->pDrawable->width <= TOR_INPLACE_SIZE ? "yes" : "no"));
541		return dst->pDrawable->width <= TOR_INPLACE_SIZE;
542	}
543
544	if (kgem_bo_is_busy(priv->gpu_bo)) {
545		DBG(("%s? no, GPU bo is busy\n", __FUNCTION__));
546		return false;
547	}
548
549	if (priv->cpu_damage) {
550		DBG(("%s? yes, idle GPU bo and damage on idle CPU\n", __FUNCTION__));
551		return true;
552	}
553
554	DBG(("%s? small enough? %s\n", __FUNCTION__,
555	     dst->pDrawable->width <= TOR_INPLACE_SIZE ? "yes" : "no"));
556	return dst->pDrawable->width <= TOR_INPLACE_SIZE;
557}
558
559void
560sna_composite_trapezoids(CARD8 op,
561			 PicturePtr src,
562			 PicturePtr dst,
563			 PictFormatPtr maskFormat,
564			 INT16 xSrc, INT16 ySrc,
565			 int ntrap, xTrapezoid *traps)
566{
567	PixmapPtr pixmap = get_drawable_pixmap(dst->pDrawable);
568	struct sna *sna = to_sna_from_pixmap(pixmap);
569	struct sna_pixmap *priv;
570	bool force_fallback = false;
571	bool rectilinear, pixel_aligned;
572	unsigned flags;
573	int n;
574
575	DBG(("%s(op=%d, src=(%d, %d), mask=%08x, ntrap=%d)\n", __FUNCTION__,
576	     op, xSrc, ySrc,
577	     maskFormat ? (int)maskFormat->format : 0,
578	     ntrap));
579
580	if (ntrap == 0)
581		return;
582
583	if (NO_ACCEL)
584		goto force_fallback;
585
586	if (FORCE_FALLBACK > 0)
587		goto force_fallback;
588
589	if (wedged(sna)) {
590		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
591		goto force_fallback;
592	}
593
594	if (dst->alphaMap) {
595		DBG(("%s: fallback -- dst alpha map\n", __FUNCTION__));
596		goto force_fallback;
597	}
598
599	priv = sna_pixmap(pixmap);
600	if (priv == NULL) {
601		DBG(("%s: fallback -- dst is unattached\n", __FUNCTION__));
602		goto force_fallback;
603	}
604
605	if (FORCE_FALLBACK == 0 &&
606	    !is_gpu_dst(priv) && !picture_is_gpu(sna, src, 0) && untransformed(src)) {
607		DBG(("%s: force fallbacks -- (!gpu dst, %dx%d? %d) && (src-is-cpu? %d && untransformed? %d)\n",
608		     __FUNCTION__, dst->pDrawable->width, dst->pDrawable->height,
609		     !is_gpu_dst(priv), !picture_is_gpu(sna, src, 0), untransformed(src)));
610
611force_fallback:
612		force_fallback = true;
613	}
614
615	/* scan through for fast rectangles */
616	rectilinear = pixel_aligned = true;
617	if (is_mono(dst, maskFormat)) {
618		for (n = 0; n < ntrap && rectilinear; n++) {
619			int lx1 = pixman_fixed_to_int(traps[n].left.p1.x + pixman_fixed_1_minus_e/2);
620			int lx2 = pixman_fixed_to_int(traps[n].left.p2.x + pixman_fixed_1_minus_e/2);
621			int rx1 = pixman_fixed_to_int(traps[n].right.p1.x + pixman_fixed_1_minus_e/2);
622			int rx2 = pixman_fixed_to_int(traps[n].right.p2.x + pixman_fixed_1_minus_e/2);
623			rectilinear &= lx1 == lx2 && rx1 == rx2;
624		}
625	} else if (dst->polyMode != PolyModePrecise) {
626		for (n = 0; n < ntrap && rectilinear; n++) {
627			int lx1 = pixman_fixed_to_fast(traps[n].left.p1.x);
628			int lx2 = pixman_fixed_to_fast(traps[n].left.p2.x);
629			int rx1 = pixman_fixed_to_fast(traps[n].right.p1.x);
630			int rx2 = pixman_fixed_to_fast(traps[n].right.p2.x);
631			int top = pixman_fixed_to_fast(traps[n].top);
632			int bot = pixman_fixed_to_fast(traps[n].bottom);
633
634			rectilinear &= lx1 == lx2 && rx1 == rx2;
635			pixel_aligned &= ((top | bot | lx1 | lx2 | rx1 | rx2) & FAST_SAMPLES_mask) == 0;
636		}
637	} else {
638		for (n = 0; n < ntrap && rectilinear; n++) {
639			rectilinear &=
640				traps[n].left.p1.x == traps[n].left.p2.x &&
641				traps[n].right.p1.x == traps[n].right.p2.x;
642			pixel_aligned &=
643				((traps[n].top | traps[n].bottom |
644				  traps[n].left.p1.x | traps[n].left.p2.x |
645				  traps[n].right.p1.x | traps[n].right.p2.x)
646				 & pixman_fixed_1_minus_e) == 0;
647		}
648	}
649
650	DBG(("%s: rectilinear? %d, pixel-aligned? %d, mono? %d precise? %d\n",
651	     __FUNCTION__, rectilinear, pixel_aligned,
652	     is_mono(dst, maskFormat), is_precise(dst, maskFormat)));
653
654	flags = 0;
655	if (rectilinear) {
656		if (pixel_aligned) {
657			if (composite_aligned_boxes(sna, op, src, dst,
658						    maskFormat,
659						    xSrc, ySrc,
660						    ntrap, traps,
661						    force_fallback))
662			    return;
663		} else {
664			if (composite_unaligned_boxes(sna, op, src, dst,
665						      maskFormat,
666						      xSrc, ySrc,
667						      ntrap, traps,
668						      force_fallback))
669				return;
670		}
671		flags |= COMPOSITE_SPANS_RECTILINEAR;
672	}
673
674	if (force_fallback)
675		goto fallback;
676
677	if (is_mono(dst, maskFormat) &&
678	    mono_trapezoids_span_converter(sna, op, src, dst,
679					   xSrc, ySrc,
680					   ntrap, traps))
681		return;
682
683	if (trapezoid_spans_maybe_inplace(sna, op, src, dst, maskFormat)) {
684		flags |= COMPOSITE_SPANS_INPLACE_HINT;
685		if (trapezoid_span_inplace(sna, op, src, dst, maskFormat, flags,
686					   xSrc, ySrc, ntrap, traps,
687					   false))
688			return;
689	}
690
691	if (trapezoid_span_converter(sna, op, src, dst, maskFormat, flags,
692				     xSrc, ySrc, ntrap, traps))
693		return;
694
695	if (trapezoid_span_inplace(sna, op, src, dst, maskFormat, flags,
696				   xSrc, ySrc, ntrap, traps,
697				   false))
698		return;
699
700	if (trapezoid_mask_converter(op, src, dst, maskFormat, flags,
701				     xSrc, ySrc, ntrap, traps))
702		return;
703
704fallback:
705	if (trapezoid_span_inplace(sna, op, src, dst, maskFormat, flags,
706				   xSrc, ySrc, ntrap, traps,
707				   true))
708		return;
709
710	if (trapezoid_span_fallback(op, src, dst, maskFormat, flags,
711				    xSrc, ySrc, ntrap, traps))
712		return;
713
714	if (trapezoids_inplace_fallback(sna, op, src, dst, maskFormat,
715					ntrap, traps))
716		return;
717
718	DBG(("%s: fallback mask=%08x, ntrap=%d\n", __FUNCTION__,
719	     maskFormat ? (unsigned)maskFormat->format : 0, ntrap));
720	trapezoids_fallback(sna, op, src, dst, maskFormat,
721			    xSrc, ySrc,
722			    ntrap, traps);
723}
724
725static void mark_damaged(PixmapPtr pixmap, struct sna_pixmap *priv,
726			 BoxPtr box, int16_t x, int16_t y)
727{
728	box->x1 += x; box->x2 += x;
729	box->y1 += y; box->y2 += y;
730	if (box->x1 <= 0 && box->y1 <= 0 &&
731	    box->x2 >= pixmap->drawable.width &&
732	    box->y2 >= pixmap->drawable.height) {
733		sna_damage_destroy(&priv->cpu_damage);
734		sna_damage_all(&priv->gpu_damage, pixmap);
735		list_del(&priv->flush_list);
736	} else {
737		sna_damage_add_box(&priv->gpu_damage, box);
738		sna_damage_subtract_box(&priv->cpu_damage, box);
739	}
740}
741
742static bool
743trap_upload(PicturePtr picture,
744	    INT16 x, INT16 y,
745	    int ntrap, xTrap *trap)
746{
747	ScreenPtr screen = picture->pDrawable->pScreen;
748	struct sna *sna = to_sna_from_screen(screen);
749	PixmapPtr pixmap = get_drawable_pixmap(picture->pDrawable);
750	PixmapPtr scratch;
751	struct sna_pixmap *priv;
752	BoxRec extents;
753	pixman_image_t *image;
754	int width, height, depth;
755	int n;
756
757	priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_WRITE);
758	if (priv == NULL)
759		return false;
760
761	extents = *RegionExtents(picture->pCompositeClip);
762	for (n = 0; n < ntrap; n++) {
763		int v;
764
765		v = x + pixman_fixed_integer_floor (MIN(trap[n].top.l, trap[n].bot.l));
766		if (v < extents.x1)
767			extents.x1 = v;
768
769		v = x + pixman_fixed_integer_ceil (MAX(trap[n].top.r, trap[n].bot.r));
770		if (v > extents.x2)
771			extents.x2 = v;
772
773		v = y + pixman_fixed_integer_floor (trap[n].top.y);
774		if (v < extents.y1)
775			extents.y1 = v;
776
777		v = y + pixman_fixed_integer_ceil (trap[n].bot.y);
778		if (v > extents.y2)
779			extents.y2 = v;
780	}
781
782	DBG(("%s: extents (%d, %d), (%d, %d)\n",
783	     __FUNCTION__, extents.x1, extents.y1, extents.x2, extents.y2));
784
785	width  = extents.x2 - extents.x1;
786	height = extents.y2 - extents.y1;
787	depth = picture->pDrawable->depth;
788
789	DBG(("%s: tmp (%dx%d) depth=%d\n",
790	     __FUNCTION__, width, height, depth));
791	scratch = sna_pixmap_create_upload(screen,
792					   width, height, depth,
793					   KGEM_BUFFER_WRITE);
794	if (!scratch)
795		return true;
796
797	memset(scratch->devPrivate.ptr, 0, scratch->devKind*height);
798	image = pixman_image_create_bits((pixman_format_code_t)picture->format,
799					 width, height,
800					 scratch->devPrivate.ptr,
801					 scratch->devKind);
802	if (image) {
803		pixman_add_traps (image, -extents.x1, -extents.y1,
804				  ntrap, (pixman_trap_t *)trap);
805
806		pixman_image_unref(image);
807	}
808
809	/* XXX clip boxes */
810	get_drawable_deltas(picture->pDrawable, pixmap, &x, &y);
811	sna->render.copy_boxes(sna, GXcopy,
812			       &scratch->drawable, __sna_pixmap_get_bo(scratch), -extents.x1, -extents.x1,
813			       &pixmap->drawable, priv->gpu_bo, x, y,
814			       &extents, 1, 0);
815	mark_damaged(pixmap, priv, &extents, x, y);
816
817	sna_pixmap_destroy(scratch);
818	return true;
819}
820
821void
822sna_add_traps(PicturePtr picture, INT16 x, INT16 y, int n, xTrap *t)
823{
824	PixmapPtr pixmap = get_drawable_pixmap(picture->pDrawable);
825	struct sna *sna = to_sna_from_pixmap(pixmap);
826	struct sna_pixmap *priv = sna_pixmap(pixmap);
827
828	DBG(("%s (%d, %d) x %d\n", __FUNCTION__, x, y, n));
829
830	if (priv && is_gpu_dst(priv)) {
831		if (trap_span_converter(sna, picture, x, y, n, t))
832			return;
833	}
834
835	if (is_gpu(sna, picture->pDrawable, PREFER_GPU_RENDER)) {
836		if (trap_mask_converter(sna, picture, x, y, n, t))
837			return;
838
839		if (trap_upload(picture, x, y, n, t))
840			return;
841	}
842
843	DBG(("%s -- fallback\n", __FUNCTION__));
844	if (sna_pixmap_move_to_cpu(pixmap, MOVE_READ | MOVE_WRITE)) {
845		pixman_image_t *image;
846		int dx, dy;
847
848		if (!(image = image_from_pict(picture, false, &dx, &dy)))
849			return;
850
851		if (sigtrap_get() == 0) {
852			pixman_add_traps(image, x + dx, y + dy, n, (pixman_trap_t *)t);
853			sigtrap_put();
854		}
855
856		free_pixman_pict(picture, image);
857	}
858}
859
860#if HAS_PIXMAN_TRIANGLES
861static void
862triangles_fallback(CARD8 op,
863		   PicturePtr src,
864		   PicturePtr dst,
865		   PictFormatPtr maskFormat,
866		   INT16 xSrc, INT16 ySrc,
867		   int n, xTriangle *tri)
868{
869	ScreenPtr screen = dst->pDrawable->pScreen;
870
871	DBG(("%s op=%d, count=%d\n", __FUNCTION__, op, n));
872
873	if (maskFormat) {
874		PixmapPtr scratch;
875		PicturePtr mask;
876		INT16 dst_x, dst_y;
877		BoxRec bounds;
878		int width, height, depth;
879		pixman_image_t *image;
880		pixman_format_code_t format;
881		int error;
882
883		dst_x = pixman_fixed_to_int(tri[0].p1.x);
884		dst_y = pixman_fixed_to_int(tri[0].p1.y);
885
886		miTriangleBounds(n, tri, &bounds);
887		DBG(("%s: bounds (%d, %d), (%d, %d)\n",
888		     __FUNCTION__, bounds.x1, bounds.y1, bounds.x2, bounds.y2));
889
890		if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
891			return;
892
893		if (!sna_compute_composite_extents(&bounds,
894						   src, NULL, dst,
895						   xSrc, ySrc,
896						   0, 0,
897						   bounds.x1, bounds.y1,
898						   bounds.x2 - bounds.x1,
899						   bounds.y2 - bounds.y1))
900			return;
901
902		DBG(("%s: extents (%d, %d), (%d, %d)\n",
903		     __FUNCTION__, bounds.x1, bounds.y1, bounds.x2, bounds.y2));
904
905		width  = bounds.x2 - bounds.x1;
906		height = bounds.y2 - bounds.y1;
907		bounds.x1 -= dst->pDrawable->x;
908		bounds.y1 -= dst->pDrawable->y;
909		depth = maskFormat->depth;
910		format = maskFormat->format | (BitsPerPixel(depth) << 24);
911
912		DBG(("%s: mask (%dx%d) depth=%d, format=%08x\n",
913		     __FUNCTION__, width, height, depth, format));
914		scratch = sna_pixmap_create_upload(screen,
915						   width, height, depth,
916						   KGEM_BUFFER_WRITE);
917		if (!scratch)
918			return;
919
920		memset(scratch->devPrivate.ptr, 0, (size_t)scratch->devKind*height);
921		image = pixman_image_create_bits(format, width, height,
922						 scratch->devPrivate.ptr,
923						 scratch->devKind);
924		if (image) {
925			pixman_add_triangles(image,
926					     -bounds.x1, -bounds.y1,
927					     n, (pixman_triangle_t *)tri);
928			pixman_image_unref(image);
929		}
930
931		mask = CreatePicture(0, &scratch->drawable,
932				     PictureMatchFormat(screen, depth, format),
933				     0, 0, serverClient, &error);
934		if (mask) {
935			CompositePicture(op, src, mask, dst,
936					 xSrc + bounds.x1 - dst_x,
937					 ySrc + bounds.y1 - dst_y,
938					 0, 0,
939					 bounds.x1, bounds.y1,
940					 width, height);
941			FreePicture(mask, 0);
942		}
943		sna_pixmap_destroy(scratch);
944	} else {
945		if (dst->polyEdge == PolyEdgeSharp)
946			maskFormat = PictureMatchFormat(screen, 1, PICT_a1);
947		else
948			maskFormat = PictureMatchFormat(screen, 8, PICT_a8);
949
950		for (; n--; tri++)
951			triangles_fallback(op,
952					   src, dst, maskFormat,
953					   xSrc, ySrc, 1, tri);
954	}
955}
956
957void
958sna_composite_triangles(CARD8 op,
959			 PicturePtr src,
960			 PicturePtr dst,
961			 PictFormatPtr maskFormat,
962			 INT16 xSrc, INT16 ySrc,
963			 int n, xTriangle *tri)
964{
965	struct sna *sna = to_sna_from_drawable(dst->pDrawable);
966
967	if (triangles_span_converter(sna, op, src, dst, maskFormat,
968				     xSrc, ySrc,
969				     n, tri))
970		return;
971
972	if (triangles_mask_converter(op, src, dst, maskFormat,
973				     xSrc, ySrc,
974				     n, tri))
975		return;
976
977	triangles_fallback(op, src, dst, maskFormat, xSrc, ySrc, n, tri);
978}
979
980static void
981tristrip_fallback(CARD8 op,
982		  PicturePtr src,
983		  PicturePtr dst,
984		  PictFormatPtr maskFormat,
985		  INT16 xSrc, INT16 ySrc,
986		  int n, xPointFixed *points)
987{
988	ScreenPtr screen = dst->pDrawable->pScreen;
989
990	if (maskFormat) {
991		PixmapPtr scratch;
992		PicturePtr mask;
993		INT16 dst_x, dst_y;
994		BoxRec bounds;
995		int width, height, depth;
996		pixman_image_t *image;
997		pixman_format_code_t format;
998		int error;
999
1000		dst_x = pixman_fixed_to_int(points->x);
1001		dst_y = pixman_fixed_to_int(points->y);
1002
1003		miPointFixedBounds(n, points, &bounds);
1004		DBG(("%s: bounds (%d, %d), (%d, %d)\n",
1005		     __FUNCTION__, bounds.x1, bounds.y1, bounds.x2, bounds.y2));
1006
1007		if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
1008			return;
1009
1010		if (!sna_compute_composite_extents(&bounds,
1011						   src, NULL, dst,
1012						   xSrc, ySrc,
1013						   0, 0,
1014						   bounds.x1, bounds.y1,
1015						   bounds.x2 - bounds.x1,
1016						   bounds.y2 - bounds.y1))
1017			return;
1018
1019		DBG(("%s: extents (%d, %d), (%d, %d)\n",
1020		     __FUNCTION__, bounds.x1, bounds.y1, bounds.x2, bounds.y2));
1021
1022		width  = bounds.x2 - bounds.x1;
1023		height = bounds.y2 - bounds.y1;
1024		bounds.x1 -= dst->pDrawable->x;
1025		bounds.y1 -= dst->pDrawable->y;
1026		depth = maskFormat->depth;
1027		format = maskFormat->format | (BitsPerPixel(depth) << 24);
1028
1029		DBG(("%s: mask (%dx%d) depth=%d, format=%08x\n",
1030		     __FUNCTION__, width, height, depth, format));
1031		scratch = sna_pixmap_create_upload(screen,
1032						   width, height, depth,
1033						   KGEM_BUFFER_WRITE);
1034		if (!scratch)
1035			return;
1036
1037		memset(scratch->devPrivate.ptr, 0, scratch->devKind*height);
1038		image = pixman_image_create_bits(format, width, height,
1039						 scratch->devPrivate.ptr,
1040						 scratch->devKind);
1041		if (image) {
1042			xTriangle tri;
1043			xPointFixed *p[3] = { &tri.p1, &tri.p2, &tri.p3 };
1044			int i;
1045
1046			*p[0] = points[0];
1047			*p[1] = points[1];
1048			*p[2] = points[2];
1049			pixman_add_triangles(image,
1050					     -bounds.x1, -bounds.y1,
1051					     1, (pixman_triangle_t *)&tri);
1052			for (i = 3; i < n; i++) {
1053				*p[i%3] = points[i];
1054				pixman_add_triangles(image,
1055						     -bounds.x1, -bounds.y1,
1056						     1, (pixman_triangle_t *)&tri);
1057			}
1058			pixman_image_unref(image);
1059		}
1060
1061		mask = CreatePicture(0, &scratch->drawable,
1062				     PictureMatchFormat(screen, depth, format),
1063				     0, 0, serverClient, &error);
1064		if (mask) {
1065			CompositePicture(op, src, mask, dst,
1066					 xSrc + bounds.x1 - dst_x,
1067					 ySrc + bounds.y1 - dst_y,
1068					 0, 0,
1069					 bounds.x1, bounds.y1,
1070					 width, height);
1071			FreePicture(mask, 0);
1072		}
1073		sna_pixmap_destroy(scratch);
1074	} else {
1075		xTriangle tri;
1076		xPointFixed *p[3] = { &tri.p1, &tri.p2, &tri.p3 };
1077		int i;
1078
1079		if (dst->polyEdge == PolyEdgeSharp)
1080			maskFormat = PictureMatchFormat(screen, 1, PICT_a1);
1081		else
1082			maskFormat = PictureMatchFormat(screen, 8, PICT_a8);
1083
1084		*p[0] = points[0];
1085		*p[1] = points[1];
1086		*p[2] = points[2];
1087		triangles_fallback(op,
1088				   src, dst, maskFormat,
1089				   xSrc, ySrc, 1, &tri);
1090		for (i = 3; i < n; i++) {
1091			*p[i%3] = points[i];
1092			/* Should xSrc,ySrc be updated? */
1093			triangles_fallback(op,
1094					   src, dst, maskFormat,
1095					   xSrc, ySrc, 1, &tri);
1096		}
1097	}
1098}
1099
1100void
1101sna_composite_tristrip(CARD8 op,
1102		       PicturePtr src,
1103		       PicturePtr dst,
1104		       PictFormatPtr maskFormat,
1105		       INT16 xSrc, INT16 ySrc,
1106		       int n, xPointFixed *points)
1107{
1108	struct sna *sna = to_sna_from_drawable(dst->pDrawable);
1109
1110	if (tristrip_span_converter(sna, op, src, dst, maskFormat, xSrc, ySrc, n, points))
1111		return;
1112
1113	tristrip_fallback(op, src, dst, maskFormat, xSrc, ySrc, n, points);
1114}
1115
1116static void
1117trifan_fallback(CARD8 op,
1118		PicturePtr src,
1119		PicturePtr dst,
1120		PictFormatPtr maskFormat,
1121		INT16 xSrc, INT16 ySrc,
1122		int n, xPointFixed *points)
1123{
1124	ScreenPtr screen = dst->pDrawable->pScreen;
1125
1126	if (maskFormat) {
1127		PixmapPtr scratch;
1128		PicturePtr mask;
1129		INT16 dst_x, dst_y;
1130		BoxRec bounds;
1131		int width, height, depth;
1132		pixman_image_t *image;
1133		pixman_format_code_t format;
1134		int error;
1135
1136		dst_x = pixman_fixed_to_int(points->x);
1137		dst_y = pixman_fixed_to_int(points->y);
1138
1139		miPointFixedBounds(n, points, &bounds);
1140		DBG(("%s: bounds (%d, %d), (%d, %d)\n",
1141		     __FUNCTION__, bounds.x1, bounds.y1, bounds.x2, bounds.y2));
1142
1143		if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
1144			return;
1145
1146		if (!sna_compute_composite_extents(&bounds,
1147						   src, NULL, dst,
1148						   xSrc, ySrc,
1149						   0, 0,
1150						   bounds.x1, bounds.y1,
1151						   bounds.x2 - bounds.x1,
1152						   bounds.y2 - bounds.y1))
1153			return;
1154
1155		DBG(("%s: extents (%d, %d), (%d, %d)\n",
1156		     __FUNCTION__, bounds.x1, bounds.y1, bounds.x2, bounds.y2));
1157
1158		width  = bounds.x2 - bounds.x1;
1159		height = bounds.y2 - bounds.y1;
1160		bounds.x1 -= dst->pDrawable->x;
1161		bounds.y1 -= dst->pDrawable->y;
1162		depth = maskFormat->depth;
1163		format = maskFormat->format | (BitsPerPixel(depth) << 24);
1164
1165		DBG(("%s: mask (%dx%d) depth=%d, format=%08x\n",
1166		     __FUNCTION__, width, height, depth, format));
1167		scratch = sna_pixmap_create_upload(screen,
1168						   width, height, depth,
1169						   KGEM_BUFFER_WRITE);
1170		if (!scratch)
1171			return;
1172
1173		memset(scratch->devPrivate.ptr, 0, scratch->devKind*height);
1174		image = pixman_image_create_bits(format, width, height,
1175						 scratch->devPrivate.ptr,
1176						 scratch->devKind);
1177		if (image) {
1178			xTriangle tri;
1179			xPointFixed *p[3] = { &tri.p1, &tri.p2, &tri.p3 };
1180			int i;
1181
1182			*p[0] = points[0];
1183			*p[1] = points[1];
1184			*p[2] = points[2];
1185			pixman_add_triangles(image,
1186					     -bounds.x1, -bounds.y1,
1187					     1, (pixman_triangle_t *)&tri);
1188			for (i = 3; i < n; i++) {
1189				*p[2 - (i&1)] = points[i];
1190				pixman_add_triangles(image,
1191						     -bounds.x1, -bounds.y1,
1192						     1, (pixman_triangle_t *)&tri);
1193			}
1194			pixman_image_unref(image);
1195		}
1196
1197		mask = CreatePicture(0, &scratch->drawable,
1198				     PictureMatchFormat(screen, depth, format),
1199				     0, 0, serverClient, &error);
1200		if (mask) {
1201			CompositePicture(op, src, mask, dst,
1202					 xSrc + bounds.x1 - dst_x,
1203					 ySrc + bounds.y1 - dst_y,
1204					 0, 0,
1205					 bounds.x1, bounds.y1,
1206					 width, height);
1207			FreePicture(mask, 0);
1208		}
1209		sna_pixmap_destroy(scratch);
1210	} else {
1211		xTriangle tri;
1212		xPointFixed *p[3] = { &tri.p1, &tri.p2, &tri.p3 };
1213		int i;
1214
1215		if (dst->polyEdge == PolyEdgeSharp)
1216			maskFormat = PictureMatchFormat(screen, 1, PICT_a1);
1217		else
1218			maskFormat = PictureMatchFormat(screen, 8, PICT_a8);
1219
1220		*p[0] = points[0];
1221		*p[1] = points[1];
1222		*p[2] = points[2];
1223		triangles_fallback(op,
1224				   src, dst, maskFormat,
1225				   xSrc, ySrc, 1, &tri);
1226		for (i = 3; i < n; i++) {
1227			*p[2 - (i&1)] = points[i];
1228			/* Should xSrc,ySrc be updated? */
1229			triangles_fallback(op,
1230					   src, dst, maskFormat,
1231					   xSrc, ySrc, 1, &tri);
1232		}
1233	}
1234}
1235
1236void
1237sna_composite_trifan(CARD8 op,
1238		     PicturePtr src,
1239		     PicturePtr dst,
1240		     PictFormatPtr maskFormat,
1241		     INT16 xSrc, INT16 ySrc,
1242		     int n, xPointFixed *points)
1243{
1244	trifan_fallback(op, src, dst, maskFormat, xSrc, ySrc, n, points);
1245}
1246#endif
1247