103b705cfSriastradh/*
203b705cfSriastradh * Copyright (c) 2007  David Turner
303b705cfSriastradh * Copyright (c) 2008  M Joonas Pihlaja
403b705cfSriastradh * Copyright (c) 2011 Intel Corporation
503b705cfSriastradh *
603b705cfSriastradh * Permission is hereby granted, free of charge, to any person obtaining a
703b705cfSriastradh * copy of this software and associated documentation files (the "Software"),
803b705cfSriastradh * to deal in the Software without restriction, including without limitation
903b705cfSriastradh * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1003b705cfSriastradh * and/or sell copies of the Software, and to permit persons to whom the
1103b705cfSriastradh * Software is furnished to do so, subject to the following conditions:
1203b705cfSriastradh *
1303b705cfSriastradh * The above copyright notice and this permission notice (including the next
1403b705cfSriastradh * paragraph) shall be included in all copies or substantial portions of the
1503b705cfSriastradh * Software.
1603b705cfSriastradh *
1703b705cfSriastradh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1803b705cfSriastradh * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1903b705cfSriastradh * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
2003b705cfSriastradh * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2103b705cfSriastradh * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2203b705cfSriastradh * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2303b705cfSriastradh * SOFTWARE.
2403b705cfSriastradh *
2503b705cfSriastradh * Authors:
2603b705cfSriastradh *    Chris Wilson <chris@chris-wilson.co.uk>
2703b705cfSriastradh *
2803b705cfSriastradh */
2903b705cfSriastradh
3003b705cfSriastradh#ifdef HAVE_CONFIG_H
3103b705cfSriastradh#include "config.h"
3203b705cfSriastradh#endif
3303b705cfSriastradh
3403b705cfSriastradh#include "sna.h"
3503b705cfSriastradh#include "sna_render.h"
3603b705cfSriastradh#include "sna_render_inline.h"
3742542f5fSchristos#include "sna_trapezoids.h"
3803b705cfSriastradh#include "fb/fbpict.h"
3903b705cfSriastradh
4003b705cfSriastradh#include <mipict.h>
4103b705cfSriastradh
4203b705cfSriastradh/* TODO: Emit unantialiased and MSAA triangles. */
4303b705cfSriastradh
4403b705cfSriastradh#ifndef MAX
4503b705cfSriastradh#define MAX(x,y) ((x) >= (y) ? (x) : (y))
4603b705cfSriastradh#endif
4703b705cfSriastradh
4803b705cfSriastradh#ifndef MIN
4903b705cfSriastradh#define MIN(x,y) ((x) <= (y) ? (x) : (y))
5003b705cfSriastradh#endif
5103b705cfSriastradh
5203b705cfSriastradh#define region_count(r) ((r)->data ? (r)->data->numRects : 1)
5303b705cfSriastradh#define region_boxes(r) ((r)->data ? (BoxPtr)((r)->data + 1) : &(r)->extents)
5403b705cfSriastradh
5542542f5fSchristosinline static xFixed
5642542f5fSchristosline_x_for_y(const xLineFixed *l, xFixed y, bool ceil)
5703b705cfSriastradh{
5842542f5fSchristos	xFixed_32_32 ex = (xFixed_32_32)(y - l->p1.y) * (l->p2.x - l->p1.x);
5942542f5fSchristos	xFixed d = l->p2.y - l->p1.y;
6003b705cfSriastradh
6142542f5fSchristos	if (ceil)
6242542f5fSchristos		ex += (d - 1);
6303b705cfSriastradh
6442542f5fSchristos	return l->p1.x + (xFixed) (ex / d);
6503b705cfSriastradh}
6603b705cfSriastradh
6742542f5fSchristosbool trapezoids_bounds(int n, const xTrapezoid *t, BoxPtr box)
6803b705cfSriastradh{
6942542f5fSchristos	xFixed x1, y1, x2, y2;
7003b705cfSriastradh
7142542f5fSchristos	/* XXX need 33 bits... */
7242542f5fSchristos	x1 = y1 = INT_MAX / 2;
7342542f5fSchristos	x2 = y2 = INT_MIN / 2;
7403b705cfSriastradh
7542542f5fSchristos	do {
7642542f5fSchristos		xFixed fx1, fx2, v;
7703b705cfSriastradh
7813496ba1Ssnj		if (!xTrapezoidValid(t)) {
7913496ba1Ssnj			__DBG(("%s: skipping invalid trapezoid: top=%d, bottom=%d, left=(%d, %d), (%d, %d), right=(%d, %d), (%d, %d)\n",
8013496ba1Ssnj			       __FUNCTION__,
8113496ba1Ssnj			       t->top, t->bottom,
8213496ba1Ssnj			       t->left.p1.x, t->left.p1.y,
8313496ba1Ssnj			       t->left.p2.x, t->left.p2.y,
8413496ba1Ssnj			       t->right.p1.x, t->right.p1.y,
8513496ba1Ssnj			       t->right.p2.x, t->right.p2.y));
8642542f5fSchristos			continue;
8713496ba1Ssnj		}
8803b705cfSriastradh
8942542f5fSchristos		if (t->top < y1)
9042542f5fSchristos			y1 = t->top;
9142542f5fSchristos		if (t->bottom > y2)
9242542f5fSchristos			y2 = t->bottom;
9303b705cfSriastradh
9442542f5fSchristos		if (((t->left.p1.x - x1) | (t->left.p2.x - x1)) < 0) {
9542542f5fSchristos			if (pixman_fixed_floor(t->left.p1.x) == pixman_fixed_floor(t->left.p2.x)) {
9642542f5fSchristos				x1 = pixman_fixed_floor(t->left.p1.x);
9742542f5fSchristos			} else {
9842542f5fSchristos				if (t->left.p1.y == t->top)
9942542f5fSchristos					fx1 = t->left.p1.x;
10042542f5fSchristos				else
10142542f5fSchristos					fx1 = line_x_for_y(&t->left, t->top, false);
10203b705cfSriastradh
10342542f5fSchristos				if (t->left.p2.y == t->bottom)
10442542f5fSchristos					fx2 = t->left.p2.x;
10542542f5fSchristos				else
10642542f5fSchristos					fx2 = line_x_for_y(&t->left, t->bottom, false);
10703b705cfSriastradh
10842542f5fSchristos				v = min(fx1, fx2);
10942542f5fSchristos				if (v < x1)
11042542f5fSchristos					x1 = pixman_fixed_floor(v);
11142542f5fSchristos			}
11242542f5fSchristos		}
11303b705cfSriastradh
11442542f5fSchristos		if (((x2 - t->right.p1.x) | (x2 - t->right.p2.x)) < 0) {
11513496ba1Ssnj			if (pixman_fixed_ceil(t->right.p1.x) == pixman_fixed_ceil(t->right.p2.x)) {
11642542f5fSchristos				x2 = pixman_fixed_ceil(t->right.p1.x);
11742542f5fSchristos			} else {
11842542f5fSchristos				if (t->right.p1.y == t->top)
11942542f5fSchristos					fx1 = t->right.p1.x;
12042542f5fSchristos				else
12142542f5fSchristos					fx1 = line_x_for_y(&t->right, t->top, true);
12203b705cfSriastradh
12342542f5fSchristos				if (t->right.p2.y == t->bottom)
12442542f5fSchristos					fx2 = t->right.p2.x;
12542542f5fSchristos				else
12642542f5fSchristos					fx2 = line_x_for_y(&t->right, t->bottom, true);
12703b705cfSriastradh
12842542f5fSchristos				v = max(fx1, fx2);
12942542f5fSchristos				if (v > x2)
13042542f5fSchristos					x2 = pixman_fixed_ceil(v);
13142542f5fSchristos			}
13242542f5fSchristos		}
13342542f5fSchristos	} while (t++, --n);
13403b705cfSriastradh
13542542f5fSchristos	box->x1 = pixman_fixed_to_int(x1);
13642542f5fSchristos	box->x2 = pixman_fixed_to_int(x2);
13742542f5fSchristos	box->y1 = pixman_fixed_integer_floor(y1);
13842542f5fSchristos	box->y2 = pixman_fixed_integer_ceil(y2);
13903b705cfSriastradh
14042542f5fSchristos	return box->x2 > box->x1 && box->y2 > box->y1;
14142542f5fSchristos}
14203b705cfSriastradh
14342542f5fSchristosstatic bool
14442542f5fSchristostrapezoids_inplace_fallback(struct sna *sna,
14542542f5fSchristos			    CARD8 op,
14642542f5fSchristos			    PicturePtr src, PicturePtr dst, PictFormatPtr mask,
14742542f5fSchristos			    int ntrap, xTrapezoid *traps)
14842542f5fSchristos{
14942542f5fSchristos	pixman_image_t *image;
15042542f5fSchristos	BoxRec box;
15142542f5fSchristos	uint32_t color;
15242542f5fSchristos	int dx, dy;
15303b705cfSriastradh
15442542f5fSchristos	if (op != PictOpAdd)
15542542f5fSchristos		return false;
15603b705cfSriastradh
15742542f5fSchristos	if (is_mono(dst, mask)) {
15842542f5fSchristos		if (dst->format != PICT_a1)
15942542f5fSchristos			return false;
16042542f5fSchristos	} else {
16142542f5fSchristos		if (dst->format != PICT_a8)
16242542f5fSchristos			return false;
16342542f5fSchristos	}
16403b705cfSriastradh
16542542f5fSchristos	if (!sna_picture_is_solid(src, &color) || (color >> 24) != 0xff) {
16642542f5fSchristos		DBG(("%s: not an opaque solid source\n", __FUNCTION__));
16742542f5fSchristos		return false;
16842542f5fSchristos	}
16903b705cfSriastradh
17042542f5fSchristos	box.x1 = dst->pDrawable->x;
17142542f5fSchristos	box.y1 = dst->pDrawable->y;
17242542f5fSchristos	box.x2 = dst->pDrawable->width;
17342542f5fSchristos	box.y2 = dst->pDrawable->height;
17442542f5fSchristos	if (pixman_region_contains_rectangle(dst->pCompositeClip,
17542542f5fSchristos					     &box) != PIXMAN_REGION_IN) {
17642542f5fSchristos		DBG(("%s: requires clipping, drawable (%d,%d), (%d, %d), clip (%d, %d), (%d, %d)\n", __FUNCTION__,
17742542f5fSchristos		     box.x1, box.y1, box.x2, box.y2,
17842542f5fSchristos		     dst->pCompositeClip->extents.x1,
17942542f5fSchristos		     dst->pCompositeClip->extents.y1,
18042542f5fSchristos		     dst->pCompositeClip->extents.x2,
18142542f5fSchristos		     dst->pCompositeClip->extents.y2));
18242542f5fSchristos		return false;
18342542f5fSchristos	}
18403b705cfSriastradh
18542542f5fSchristos	if (is_gpu(sna, dst->pDrawable, PREFER_GPU_SPANS)) {
18642542f5fSchristos		DBG(("%s: not performing inplace as dst is already on the GPU\n",
18742542f5fSchristos		     __FUNCTION__));
18842542f5fSchristos		return false;
18942542f5fSchristos	}
19003b705cfSriastradh
19142542f5fSchristos	DBG(("%s\n", __FUNCTION__));
19203b705cfSriastradh
19342542f5fSchristos	image = NULL;
19442542f5fSchristos	if (sna_drawable_move_to_cpu(dst->pDrawable, MOVE_READ | MOVE_WRITE))
19542542f5fSchristos		image = image_from_pict(dst, false, &dx, &dy);
19642542f5fSchristos	if (image) {
19742542f5fSchristos		dx += dst->pDrawable->x;
19842542f5fSchristos		dy += dst->pDrawable->y;
19903b705cfSriastradh
20042542f5fSchristos		if (sigtrap_get() == 0) {
20142542f5fSchristos			for (; ntrap; ntrap--, traps++)
20242542f5fSchristos				if (xTrapezoidValid(traps))
20342542f5fSchristos					pixman_rasterize_trapezoid(image,
20442542f5fSchristos								   (pixman_trapezoid_t *)traps,
20542542f5fSchristos								   dx, dy);
20642542f5fSchristos			sigtrap_put();
20742542f5fSchristos		}
20803b705cfSriastradh
20942542f5fSchristos		pixman_image_unref(image);
21003b705cfSriastradh	}
21103b705cfSriastradh
21242542f5fSchristos	return true;
21303b705cfSriastradh}
21403b705cfSriastradh
21542542f5fSchristosstruct rasterize_traps_thread {
21642542f5fSchristos	xTrapezoid *traps;
21742542f5fSchristos	char *ptr;
21842542f5fSchristos	int stride;
21942542f5fSchristos	BoxRec bounds;
22042542f5fSchristos	pixman_format_code_t format;
22142542f5fSchristos	int ntrap;
22242542f5fSchristos};
22303b705cfSriastradh
22442542f5fSchristosstatic void rasterize_traps_thread(void *arg)
22503b705cfSriastradh{
22642542f5fSchristos	struct rasterize_traps_thread *thread = arg;
22742542f5fSchristos	pixman_image_t *image;
22842542f5fSchristos	int width, height, n;
22903b705cfSriastradh
23042542f5fSchristos	width = thread->bounds.x2 - thread->bounds.x1;
23142542f5fSchristos	height = thread->bounds.y2 - thread->bounds.y1;
23203b705cfSriastradh
23342542f5fSchristos	memset(thread->ptr, 0, thread->stride*height);
23442542f5fSchristos	if (PIXMAN_FORMAT_DEPTH(thread->format) < 8)
23542542f5fSchristos		image = pixman_image_create_bits(thread->format,
23642542f5fSchristos						 width, height,
23742542f5fSchristos						 NULL, 0);
23842542f5fSchristos	else
23942542f5fSchristos		image = pixman_image_create_bits(thread->format,
24042542f5fSchristos						 width, height,
24142542f5fSchristos						 (uint32_t *)thread->ptr,
24242542f5fSchristos						 thread->stride);
24342542f5fSchristos	if (image == NULL)
24442542f5fSchristos		return;
24503b705cfSriastradh
24642542f5fSchristos	for (n = 0; n < thread->ntrap; n++)
24742542f5fSchristos		if (xTrapezoidValid(&thread->traps[n]))
24842542f5fSchristos			pixman_rasterize_trapezoid(image,
24942542f5fSchristos						   (pixman_trapezoid_t *)&thread->traps[n],
25042542f5fSchristos						   -thread->bounds.x1, -thread->bounds.y1);
25142542f5fSchristos
25242542f5fSchristos	if (PIXMAN_FORMAT_DEPTH(thread->format) < 8) {
25342542f5fSchristos		pixman_image_t *a8;
25403b705cfSriastradh
25542542f5fSchristos		a8 = pixman_image_create_bits(PIXMAN_a8,
25642542f5fSchristos					      width, height,
25742542f5fSchristos					      (uint32_t *)thread->ptr,
25842542f5fSchristos					      thread->stride);
25942542f5fSchristos		if (a8) {
26042542f5fSchristos			pixman_image_composite(PIXMAN_OP_SRC,
26142542f5fSchristos					       image, NULL, a8,
26242542f5fSchristos					       0, 0,
26342542f5fSchristos					       0, 0,
26442542f5fSchristos					       0, 0,
26542542f5fSchristos					       width, height);
26642542f5fSchristos			pixman_image_unref(a8);
26742542f5fSchristos		}
26842542f5fSchristos	}
26903b705cfSriastradh
27042542f5fSchristos	pixman_image_unref(image);
27103b705cfSriastradh}
27203b705cfSriastradh
27342542f5fSchristosstatic void
27442542f5fSchristostrapezoids_fallback(struct sna *sna,
27542542f5fSchristos		    CARD8 op, PicturePtr src, PicturePtr dst,
27642542f5fSchristos		    PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
27742542f5fSchristos		    int ntrap, xTrapezoid * traps)
27803b705cfSriastradh{
27942542f5fSchristos	ScreenPtr screen = dst->pDrawable->pScreen;
28003b705cfSriastradh
28142542f5fSchristos	if (maskFormat) {
28242542f5fSchristos		PixmapPtr scratch;
28342542f5fSchristos		PicturePtr mask;
28442542f5fSchristos		INT16 dst_x, dst_y;
28542542f5fSchristos		BoxRec bounds;
28642542f5fSchristos		int width, height, depth;
28742542f5fSchristos		pixman_image_t *image;
28842542f5fSchristos		pixman_format_code_t format;
28942542f5fSchristos		int error;
29003b705cfSriastradh
29142542f5fSchristos		trapezoid_origin(&traps[0].left, &dst_x, &dst_y);
29203b705cfSriastradh
29342542f5fSchristos		if (!trapezoids_bounds(ntrap, traps, &bounds))
29442542f5fSchristos			return;
29503b705cfSriastradh
29642542f5fSchristos		DBG(("%s: bounds (%d, %d), (%d, %d)\n", __FUNCTION__,
29742542f5fSchristos		     bounds.x1, bounds.y1, bounds.x2, bounds.y2));
29803b705cfSriastradh
29942542f5fSchristos		if (!sna_compute_composite_extents(&bounds,
30042542f5fSchristos						   src, NULL, dst,
30142542f5fSchristos						   xSrc, ySrc,
30242542f5fSchristos						   0, 0,
30342542f5fSchristos						   bounds.x1, bounds.y1,
30442542f5fSchristos						   bounds.x2 - bounds.x1,
30542542f5fSchristos						   bounds.y2 - bounds.y1))
30642542f5fSchristos			return;
30703b705cfSriastradh
30842542f5fSchristos		DBG(("%s: extents (%d, %d), (%d, %d)\n", __FUNCTION__,
30942542f5fSchristos		     bounds.x1, bounds.y1, bounds.x2, bounds.y2));
31003b705cfSriastradh
31142542f5fSchristos		width  = bounds.x2 - bounds.x1;
31242542f5fSchristos		height = bounds.y2 - bounds.y1;
31342542f5fSchristos		bounds.x1 -= dst->pDrawable->x;
31442542f5fSchristos		bounds.y1 -= dst->pDrawable->y;
31542542f5fSchristos		bounds.x2 -= dst->pDrawable->x;
31642542f5fSchristos		bounds.y2 -= dst->pDrawable->y;
31742542f5fSchristos		depth = maskFormat->depth;
31842542f5fSchristos		if (depth == 1) {
31942542f5fSchristos			format = PIXMAN_a1;
32042542f5fSchristos		} else if (depth <= 4) {
32142542f5fSchristos			format = PIXMAN_a4;
32242542f5fSchristos			depth = 4;
32342542f5fSchristos		} else
32442542f5fSchristos			format = PIXMAN_a8;
32503b705cfSriastradh
32642542f5fSchristos		DBG(("%s: mask (%dx%d) depth=%d, format=%08x\n",
32742542f5fSchristos		     __FUNCTION__, width, height, depth, format));
32842542f5fSchristos		if (is_gpu(sna, dst->pDrawable, PREFER_GPU_RENDER) ||
32942542f5fSchristos		    picture_is_gpu(sna, src, PREFER_GPU_RENDER)) {
33042542f5fSchristos			int num_threads;
33103b705cfSriastradh
33242542f5fSchristos			scratch = sna_pixmap_create_upload(screen,
33342542f5fSchristos							   width, height, 8,
33442542f5fSchristos							   KGEM_BUFFER_WRITE);
33542542f5fSchristos			if (!scratch)
33642542f5fSchristos				return;
33703b705cfSriastradh
33842542f5fSchristos			num_threads = sna_use_threads(width, height, 8);
33942542f5fSchristos			if (num_threads == 1) {
34042542f5fSchristos				if (depth < 8) {
34142542f5fSchristos					image = pixman_image_create_bits(format, width, height,
34242542f5fSchristos									 NULL, 0);
34342542f5fSchristos				} else {
34442542f5fSchristos					memset(scratch->devPrivate.ptr, 0, scratch->devKind*height);
34503b705cfSriastradh
34642542f5fSchristos					image = pixman_image_create_bits(format, width, height,
34742542f5fSchristos									 scratch->devPrivate.ptr,
34842542f5fSchristos									 scratch->devKind);
34942542f5fSchristos				}
35042542f5fSchristos				if (image) {
35142542f5fSchristos					for (; ntrap; ntrap--, traps++)
35242542f5fSchristos						if (xTrapezoidValid(traps))
35342542f5fSchristos							pixman_rasterize_trapezoid(image,
35442542f5fSchristos										   (pixman_trapezoid_t *)traps,
35542542f5fSchristos										   -bounds.x1, -bounds.y1);
35642542f5fSchristos					if (depth < 8) {
35742542f5fSchristos						pixman_image_t *a8;
35803b705cfSriastradh
35942542f5fSchristos						a8 = pixman_image_create_bits(PIXMAN_a8, width, height,
36042542f5fSchristos									      scratch->devPrivate.ptr,
36142542f5fSchristos									      scratch->devKind);
36242542f5fSchristos						if (a8) {
36342542f5fSchristos							pixman_image_composite(PIXMAN_OP_SRC,
36442542f5fSchristos									       image, NULL, a8,
36542542f5fSchristos									       0, 0,
36642542f5fSchristos									       0, 0,
36742542f5fSchristos									       0, 0,
36842542f5fSchristos									       width, height);
36942542f5fSchristos							format = PIXMAN_a8;
37042542f5fSchristos							depth = 8;
37142542f5fSchristos							pixman_image_unref(a8);
37242542f5fSchristos						}
37342542f5fSchristos					}
37403b705cfSriastradh
37542542f5fSchristos					pixman_image_unref(image);
37642542f5fSchristos				}
37742542f5fSchristos				if (format != PIXMAN_a8) {
37842542f5fSchristos					sna_pixmap_destroy(scratch);
37942542f5fSchristos					return;
38042542f5fSchristos				}
38142542f5fSchristos			} else {
38242542f5fSchristos				struct rasterize_traps_thread threads[num_threads];
38342542f5fSchristos				int y, dy, n;
38403b705cfSriastradh
38542542f5fSchristos				threads[0].ptr = scratch->devPrivate.ptr;
38642542f5fSchristos				threads[0].stride = scratch->devKind;
38742542f5fSchristos				threads[0].traps = traps;
38842542f5fSchristos				threads[0].ntrap = ntrap;
38942542f5fSchristos				threads[0].bounds = bounds;
39042542f5fSchristos				threads[0].format = format;
39103b705cfSriastradh
39242542f5fSchristos				y = bounds.y1;
39342542f5fSchristos				dy = (height + num_threads - 1) / num_threads;
39442542f5fSchristos				num_threads -= (num_threads-1) * dy >= bounds.y2 - bounds.y1;
39503b705cfSriastradh
39642542f5fSchristos				if (sigtrap_get() == 0) {
39742542f5fSchristos					for (n = 1; n < num_threads; n++) {
39842542f5fSchristos						threads[n] = threads[0];
39942542f5fSchristos						threads[n].ptr += (y - bounds.y1) * threads[n].stride;
40042542f5fSchristos						threads[n].bounds.y1 = y;
40142542f5fSchristos						threads[n].bounds.y2 = y += dy;
40203b705cfSriastradh
40342542f5fSchristos						sna_threads_run(n, rasterize_traps_thread, &threads[n]);
40442542f5fSchristos					}
40503b705cfSriastradh
40642542f5fSchristos					assert(y < threads[0].bounds.y2);
40742542f5fSchristos					threads[0].ptr += (y - bounds.y1) * threads[0].stride;
40842542f5fSchristos					threads[0].bounds.y1 = y;
40942542f5fSchristos					rasterize_traps_thread(&threads[0]);
41003b705cfSriastradh
41142542f5fSchristos					sna_threads_wait();
41242542f5fSchristos					sigtrap_put();
41342542f5fSchristos				} else
41442542f5fSchristos					sna_threads_kill();
41503b705cfSriastradh
41642542f5fSchristos				format = PIXMAN_a8;
41742542f5fSchristos				depth = 8;
41842542f5fSchristos			}
41903b705cfSriastradh		} else {
42042542f5fSchristos			scratch = sna_pixmap_create_unattached(screen,
42142542f5fSchristos							       width, height,
42242542f5fSchristos							       depth);
42342542f5fSchristos			if (!scratch)
42442542f5fSchristos				return;
42503b705cfSriastradh
42642542f5fSchristos			memset(scratch->devPrivate.ptr, 0, scratch->devKind*height);
42742542f5fSchristos			image = pixman_image_create_bits(format, width, height,
42842542f5fSchristos							 scratch->devPrivate.ptr,
42942542f5fSchristos							 scratch->devKind);
43042542f5fSchristos			if (image) {
43142542f5fSchristos				for (; ntrap; ntrap--, traps++)
43242542f5fSchristos					if (xTrapezoidValid(traps))
43342542f5fSchristos						pixman_rasterize_trapezoid(image,
43442542f5fSchristos									   (pixman_trapezoid_t *)traps,
43542542f5fSchristos									   -bounds.x1, -bounds.y1);
43642542f5fSchristos				pixman_image_unref(image);
43703b705cfSriastradh			}
43803b705cfSriastradh		}
43903b705cfSriastradh
44042542f5fSchristos		mask = CreatePicture(0, &scratch->drawable,
44142542f5fSchristos				     PictureMatchFormat(screen, depth, format),
44242542f5fSchristos				     0, 0, serverClient, &error);
44342542f5fSchristos		if (mask) {
44442542f5fSchristos			CompositePicture(op, src, mask, dst,
44542542f5fSchristos					 xSrc + bounds.x1 - dst_x,
44642542f5fSchristos					 ySrc + bounds.y1 - dst_y,
44742542f5fSchristos					 0, 0,
44842542f5fSchristos					 bounds.x1, bounds.y1,
44942542f5fSchristos					 width, height);
45042542f5fSchristos			FreePicture(mask, 0);
45103b705cfSriastradh		}
45242542f5fSchristos		sna_pixmap_destroy(scratch);
45303b705cfSriastradh	} else {
45442542f5fSchristos		if (dst->polyEdge == PolyEdgeSharp)
45542542f5fSchristos			maskFormat = PictureMatchFormat(screen, 1, PICT_a1);
45642542f5fSchristos		else
45742542f5fSchristos			maskFormat = PictureMatchFormat(screen, 8, PICT_a8);
45803b705cfSriastradh
45942542f5fSchristos		for (; ntrap; ntrap--, traps++)
46042542f5fSchristos			trapezoids_fallback(sna, op,
46142542f5fSchristos					    src, dst, maskFormat,
46242542f5fSchristos					    xSrc, ySrc, 1, traps);
46303b705cfSriastradh	}
46403b705cfSriastradh}
46503b705cfSriastradh
46603b705cfSriastradhstatic bool
46742542f5fSchristostrapezoid_spans_maybe_inplace(struct sna *sna,
46842542f5fSchristos			      CARD8 op, PicturePtr src, PicturePtr dst,
46942542f5fSchristos			      PictFormatPtr maskFormat)
47003b705cfSriastradh{
47142542f5fSchristos	struct sna_pixmap *priv;
47203b705cfSriastradh
47303b705cfSriastradh	if (NO_SCAN_CONVERTER)
47403b705cfSriastradh		return false;
47503b705cfSriastradh
47642542f5fSchristos	if (dst->alphaMap)
47703b705cfSriastradh		return false;
47842542f5fSchristos	if (is_mono(dst, maskFormat))
47942542f5fSchristos		goto out;
48003b705cfSriastradh
48142542f5fSchristos	switch ((int)dst->format) {
48242542f5fSchristos	case PICT_a8:
48342542f5fSchristos		if (!sna_picture_is_solid(src, NULL))
48442542f5fSchristos			return false;
48503b705cfSriastradh
48642542f5fSchristos		switch (op) {
48742542f5fSchristos		case PictOpIn:
48842542f5fSchristos		case PictOpAdd:
48942542f5fSchristos		case PictOpSrc:
49042542f5fSchristos			break;
49142542f5fSchristos		default:
49242542f5fSchristos			return false;
49342542f5fSchristos		}
49442542f5fSchristos		break;
49503b705cfSriastradh
49642542f5fSchristos	case PICT_x8r8g8b8:
49742542f5fSchristos	case PICT_a8r8g8b8:
49842542f5fSchristos		if (picture_is_gpu(sna, src, 0))
49942542f5fSchristos			return false;
50003b705cfSriastradh
50142542f5fSchristos		switch (op) {
50242542f5fSchristos		case PictOpOver:
50342542f5fSchristos		case PictOpAdd:
50442542f5fSchristos		case PictOpOutReverse:
50542542f5fSchristos			break;
50642542f5fSchristos		case PictOpSrc:
50742542f5fSchristos			if (sna_picture_is_solid(src, NULL))
50842542f5fSchristos				break;
50903b705cfSriastradh
51042542f5fSchristos			if (!sna_drawable_is_clear(dst->pDrawable))
51142542f5fSchristos				return false;
51242542f5fSchristos			break;
51342542f5fSchristos		default:
51442542f5fSchristos			return false;
51542542f5fSchristos		}
51642542f5fSchristos		break;
51742542f5fSchristos	default:
51842542f5fSchristos		return false;
51942542f5fSchristos	}
52003b705cfSriastradh
52142542f5fSchristosout:
52242542f5fSchristos	priv = sna_pixmap_from_drawable(dst->pDrawable);
52342542f5fSchristos	if (priv == NULL) {
52442542f5fSchristos		DBG(("%s? yes -- unattached\n", __FUNCTION__));
52503b705cfSriastradh		return true;
52642542f5fSchristos	}
52703b705cfSriastradh
52842542f5fSchristos	if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo)) {
52942542f5fSchristos		DBG(("%s? no -- CPU bo is busy\n", __FUNCTION__));
53042542f5fSchristos		return false;
53142542f5fSchristos	}
53203b705cfSriastradh
53342542f5fSchristos	if (DAMAGE_IS_ALL(priv->cpu_damage) || priv->gpu_damage == NULL) {
53442542f5fSchristos		DBG(("%s? yes -- damaged on CPU only (all? %d)\n", __FUNCTION__, DAMAGE_IS_ALL(priv->cpu_damage)));
53503b705cfSriastradh		return true;
53603b705cfSriastradh	}
53703b705cfSriastradh
53842542f5fSchristos	if (priv->clear) {
53942542f5fSchristos		DBG(("%s? clear, %s\n", __FUNCTION__,
54042542f5fSchristos		     dst->pDrawable->width <= TOR_INPLACE_SIZE ? "yes" : "no"));
54142542f5fSchristos		return dst->pDrawable->width <= TOR_INPLACE_SIZE;
54203b705cfSriastradh	}
54303b705cfSriastradh
54442542f5fSchristos	if (kgem_bo_is_busy(priv->gpu_bo)) {
54542542f5fSchristos		DBG(("%s? no, GPU bo is busy\n", __FUNCTION__));
54642542f5fSchristos		return false;
54703b705cfSriastradh	}
54842542f5fSchristos
54942542f5fSchristos	if (priv->cpu_damage) {
55042542f5fSchristos		DBG(("%s? yes, idle GPU bo and damage on idle CPU\n", __FUNCTION__));
55142542f5fSchristos		return true;
55203b705cfSriastradh	}
55303b705cfSriastradh
55442542f5fSchristos	DBG(("%s? small enough? %s\n", __FUNCTION__,
55542542f5fSchristos	     dst->pDrawable->width <= TOR_INPLACE_SIZE ? "yes" : "no"));
55642542f5fSchristos	return dst->pDrawable->width <= TOR_INPLACE_SIZE;
55703b705cfSriastradh}
55803b705cfSriastradh
55903b705cfSriastradhvoid
56003b705cfSriastradhsna_composite_trapezoids(CARD8 op,
56103b705cfSriastradh			 PicturePtr src,
56203b705cfSriastradh			 PicturePtr dst,
56303b705cfSriastradh			 PictFormatPtr maskFormat,
56403b705cfSriastradh			 INT16 xSrc, INT16 ySrc,
56503b705cfSriastradh			 int ntrap, xTrapezoid *traps)
56603b705cfSriastradh{
56703b705cfSriastradh	PixmapPtr pixmap = get_drawable_pixmap(dst->pDrawable);
56803b705cfSriastradh	struct sna *sna = to_sna_from_pixmap(pixmap);
56903b705cfSriastradh	struct sna_pixmap *priv;
57042542f5fSchristos	bool force_fallback = false;
57142542f5fSchristos	bool rectilinear, pixel_aligned;
57203b705cfSriastradh	unsigned flags;
57303b705cfSriastradh	int n;
57403b705cfSriastradh
57503b705cfSriastradh	DBG(("%s(op=%d, src=(%d, %d), mask=%08x, ntrap=%d)\n", __FUNCTION__,
57603b705cfSriastradh	     op, xSrc, ySrc,
57703b705cfSriastradh	     maskFormat ? (int)maskFormat->format : 0,
57803b705cfSriastradh	     ntrap));
57903b705cfSriastradh
58003b705cfSriastradh	if (ntrap == 0)
58103b705cfSriastradh		return;
58203b705cfSriastradh
58303b705cfSriastradh	if (NO_ACCEL)
58442542f5fSchristos		goto force_fallback;
58542542f5fSchristos
58642542f5fSchristos	if (FORCE_FALLBACK > 0)
58742542f5fSchristos		goto force_fallback;
58803b705cfSriastradh
58903b705cfSriastradh	if (wedged(sna)) {
59003b705cfSriastradh		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
59142542f5fSchristos		goto force_fallback;
59203b705cfSriastradh	}
59303b705cfSriastradh
59403b705cfSriastradh	if (dst->alphaMap) {
59503b705cfSriastradh		DBG(("%s: fallback -- dst alpha map\n", __FUNCTION__));
59642542f5fSchristos		goto force_fallback;
59703b705cfSriastradh	}
59803b705cfSriastradh
59903b705cfSriastradh	priv = sna_pixmap(pixmap);
60003b705cfSriastradh	if (priv == NULL) {
60103b705cfSriastradh		DBG(("%s: fallback -- dst is unattached\n", __FUNCTION__));
60242542f5fSchristos		goto force_fallback;
60303b705cfSriastradh	}
60403b705cfSriastradh
60542542f5fSchristos	if (FORCE_FALLBACK == 0 &&
60642542f5fSchristos	    !is_gpu_dst(priv) && !picture_is_gpu(sna, src, 0) && untransformed(src)) {
60742542f5fSchristos		DBG(("%s: force fallbacks -- (!gpu dst, %dx%d? %d) && (src-is-cpu? %d && untransformed? %d)\n",
60842542f5fSchristos		     __FUNCTION__, dst->pDrawable->width, dst->pDrawable->height,
60942542f5fSchristos		     !is_gpu_dst(priv), !picture_is_gpu(sna, src, 0), untransformed(src)));
61042542f5fSchristos
61142542f5fSchristosforce_fallback:
61203b705cfSriastradh		force_fallback = true;
61303b705cfSriastradh	}
61403b705cfSriastradh
61503b705cfSriastradh	/* scan through for fast rectangles */
61603b705cfSriastradh	rectilinear = pixel_aligned = true;
61703b705cfSriastradh	if (is_mono(dst, maskFormat)) {
61803b705cfSriastradh		for (n = 0; n < ntrap && rectilinear; n++) {
61903b705cfSriastradh			int lx1 = pixman_fixed_to_int(traps[n].left.p1.x + pixman_fixed_1_minus_e/2);
62003b705cfSriastradh			int lx2 = pixman_fixed_to_int(traps[n].left.p2.x + pixman_fixed_1_minus_e/2);
62103b705cfSriastradh			int rx1 = pixman_fixed_to_int(traps[n].right.p1.x + pixman_fixed_1_minus_e/2);
62203b705cfSriastradh			int rx2 = pixman_fixed_to_int(traps[n].right.p2.x + pixman_fixed_1_minus_e/2);
62303b705cfSriastradh			rectilinear &= lx1 == lx2 && rx1 == rx2;
62403b705cfSriastradh		}
62503b705cfSriastradh	} else if (dst->polyMode != PolyModePrecise) {
62603b705cfSriastradh		for (n = 0; n < ntrap && rectilinear; n++) {
62742542f5fSchristos			int lx1 = pixman_fixed_to_fast(traps[n].left.p1.x);
62842542f5fSchristos			int lx2 = pixman_fixed_to_fast(traps[n].left.p2.x);
62942542f5fSchristos			int rx1 = pixman_fixed_to_fast(traps[n].right.p1.x);
63042542f5fSchristos			int rx2 = pixman_fixed_to_fast(traps[n].right.p2.x);
63142542f5fSchristos			int top = pixman_fixed_to_fast(traps[n].top);
63242542f5fSchristos			int bot = pixman_fixed_to_fast(traps[n].bottom);
63303b705cfSriastradh
63403b705cfSriastradh			rectilinear &= lx1 == lx2 && rx1 == rx2;
63503b705cfSriastradh			pixel_aligned &= ((top | bot | lx1 | lx2 | rx1 | rx2) & FAST_SAMPLES_mask) == 0;
63603b705cfSriastradh		}
63703b705cfSriastradh	} else {
63803b705cfSriastradh		for (n = 0; n < ntrap && rectilinear; n++) {
63903b705cfSriastradh			rectilinear &=
64003b705cfSriastradh				traps[n].left.p1.x == traps[n].left.p2.x &&
64103b705cfSriastradh				traps[n].right.p1.x == traps[n].right.p2.x;
64203b705cfSriastradh			pixel_aligned &=
64303b705cfSriastradh				((traps[n].top | traps[n].bottom |
64403b705cfSriastradh				  traps[n].left.p1.x | traps[n].left.p2.x |
64503b705cfSriastradh				  traps[n].right.p1.x | traps[n].right.p2.x)
64603b705cfSriastradh				 & pixman_fixed_1_minus_e) == 0;
64703b705cfSriastradh		}
64803b705cfSriastradh	}
64903b705cfSriastradh
65042542f5fSchristos	DBG(("%s: rectilinear? %d, pixel-aligned? %d, mono? %d precise? %d\n",
65142542f5fSchristos	     __FUNCTION__, rectilinear, pixel_aligned,
65242542f5fSchristos	     is_mono(dst, maskFormat), is_precise(dst, maskFormat)));
65342542f5fSchristos
65403b705cfSriastradh	flags = 0;
65503b705cfSriastradh	if (rectilinear) {
65603b705cfSriastradh		if (pixel_aligned) {
65703b705cfSriastradh			if (composite_aligned_boxes(sna, op, src, dst,
65803b705cfSriastradh						    maskFormat,
65903b705cfSriastradh						    xSrc, ySrc,
66003b705cfSriastradh						    ntrap, traps,
66103b705cfSriastradh						    force_fallback))
66203b705cfSriastradh			    return;
66303b705cfSriastradh		} else {
66403b705cfSriastradh			if (composite_unaligned_boxes(sna, op, src, dst,
66503b705cfSriastradh						      maskFormat,
66603b705cfSriastradh						      xSrc, ySrc,
66703b705cfSriastradh						      ntrap, traps,
66803b705cfSriastradh						      force_fallback))
66903b705cfSriastradh				return;
67003b705cfSriastradh		}
67103b705cfSriastradh		flags |= COMPOSITE_SPANS_RECTILINEAR;
67203b705cfSriastradh	}
67303b705cfSriastradh
67403b705cfSriastradh	if (force_fallback)
67503b705cfSriastradh		goto fallback;
67603b705cfSriastradh
67703b705cfSriastradh	if (is_mono(dst, maskFormat) &&
67803b705cfSriastradh	    mono_trapezoids_span_converter(sna, op, src, dst,
67903b705cfSriastradh					   xSrc, ySrc,
68003b705cfSriastradh					   ntrap, traps))
68103b705cfSriastradh		return;
68242542f5fSchristos
68342542f5fSchristos	if (trapezoid_spans_maybe_inplace(sna, op, src, dst, maskFormat)) {
68442542f5fSchristos		flags |= COMPOSITE_SPANS_INPLACE_HINT;
68542542f5fSchristos		if (trapezoid_span_inplace(sna, op, src, dst, maskFormat, flags,
68642542f5fSchristos					   xSrc, ySrc, ntrap, traps,
68742542f5fSchristos					   false))
68842542f5fSchristos			return;
68903b705cfSriastradh	}
69003b705cfSriastradh
69142542f5fSchristos	if (trapezoid_span_converter(sna, op, src, dst, maskFormat, flags,
69242542f5fSchristos				     xSrc, ySrc, ntrap, traps))
69342542f5fSchristos		return;
69403b705cfSriastradh
69542542f5fSchristos	if (trapezoid_span_inplace(sna, op, src, dst, maskFormat, flags,
69642542f5fSchristos				   xSrc, ySrc, ntrap, traps,
69742542f5fSchristos				   false))
69842542f5fSchristos		return;
69903b705cfSriastradh
70042542f5fSchristos	if (trapezoid_mask_converter(op, src, dst, maskFormat, flags,
70142542f5fSchristos				     xSrc, ySrc, ntrap, traps))
70242542f5fSchristos		return;
70303b705cfSriastradh
70442542f5fSchristosfallback:
70542542f5fSchristos	if (trapezoid_span_inplace(sna, op, src, dst, maskFormat, flags,
70642542f5fSchristos				   xSrc, ySrc, ntrap, traps,
70742542f5fSchristos				   true))
70842542f5fSchristos		return;
70903b705cfSriastradh
71042542f5fSchristos	if (trapezoid_span_fallback(op, src, dst, maskFormat, flags,
71142542f5fSchristos				    xSrc, ySrc, ntrap, traps))
71242542f5fSchristos		return;
71303b705cfSriastradh
71442542f5fSchristos	if (trapezoids_inplace_fallback(sna, op, src, dst, maskFormat,
71542542f5fSchristos					ntrap, traps))
71642542f5fSchristos		return;
71703b705cfSriastradh
71842542f5fSchristos	DBG(("%s: fallback mask=%08x, ntrap=%d\n", __FUNCTION__,
71942542f5fSchristos	     maskFormat ? (unsigned)maskFormat->format : 0, ntrap));
72042542f5fSchristos	trapezoids_fallback(sna, op, src, dst, maskFormat,
72142542f5fSchristos			    xSrc, ySrc,
72242542f5fSchristos			    ntrap, traps);
72342542f5fSchristos}
72403b705cfSriastradh
72542542f5fSchristosstatic void mark_damaged(PixmapPtr pixmap, struct sna_pixmap *priv,
72642542f5fSchristos			 BoxPtr box, int16_t x, int16_t y)
72742542f5fSchristos{
72842542f5fSchristos	box->x1 += x; box->x2 += x;
72942542f5fSchristos	box->y1 += y; box->y2 += y;
73042542f5fSchristos	if (box->x1 <= 0 && box->y1 <= 0 &&
73142542f5fSchristos	    box->x2 >= pixmap->drawable.width &&
73242542f5fSchristos	    box->y2 >= pixmap->drawable.height) {
73342542f5fSchristos		sna_damage_destroy(&priv->cpu_damage);
73442542f5fSchristos		sna_damage_all(&priv->gpu_damage, pixmap);
73542542f5fSchristos		list_del(&priv->flush_list);
73642542f5fSchristos	} else {
73742542f5fSchristos		sna_damage_add_box(&priv->gpu_damage, box);
73842542f5fSchristos		sna_damage_subtract_box(&priv->cpu_damage, box);
73942542f5fSchristos	}
74003b705cfSriastradh}
74103b705cfSriastradh
74203b705cfSriastradhstatic bool
74303b705cfSriastradhtrap_upload(PicturePtr picture,
74403b705cfSriastradh	    INT16 x, INT16 y,
74503b705cfSriastradh	    int ntrap, xTrap *trap)
74603b705cfSriastradh{
74703b705cfSriastradh	ScreenPtr screen = picture->pDrawable->pScreen;
74803b705cfSriastradh	struct sna *sna = to_sna_from_screen(screen);
74903b705cfSriastradh	PixmapPtr pixmap = get_drawable_pixmap(picture->pDrawable);
75003b705cfSriastradh	PixmapPtr scratch;
75103b705cfSriastradh	struct sna_pixmap *priv;
75203b705cfSriastradh	BoxRec extents;
75303b705cfSriastradh	pixman_image_t *image;
75403b705cfSriastradh	int width, height, depth;
75503b705cfSriastradh	int n;
75603b705cfSriastradh
75703b705cfSriastradh	priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_WRITE);
75803b705cfSriastradh	if (priv == NULL)
75903b705cfSriastradh		return false;
76003b705cfSriastradh
76103b705cfSriastradh	extents = *RegionExtents(picture->pCompositeClip);
76203b705cfSriastradh	for (n = 0; n < ntrap; n++) {
76303b705cfSriastradh		int v;
76403b705cfSriastradh
76503b705cfSriastradh		v = x + pixman_fixed_integer_floor (MIN(trap[n].top.l, trap[n].bot.l));
76603b705cfSriastradh		if (v < extents.x1)
76703b705cfSriastradh			extents.x1 = v;
76803b705cfSriastradh
76903b705cfSriastradh		v = x + pixman_fixed_integer_ceil (MAX(trap[n].top.r, trap[n].bot.r));
77003b705cfSriastradh		if (v > extents.x2)
77103b705cfSriastradh			extents.x2 = v;
77203b705cfSriastradh
77303b705cfSriastradh		v = y + pixman_fixed_integer_floor (trap[n].top.y);
77403b705cfSriastradh		if (v < extents.y1)
77503b705cfSriastradh			extents.y1 = v;
77603b705cfSriastradh
77703b705cfSriastradh		v = y + pixman_fixed_integer_ceil (trap[n].bot.y);
77803b705cfSriastradh		if (v > extents.y2)
77903b705cfSriastradh			extents.y2 = v;
78003b705cfSriastradh	}
78103b705cfSriastradh
78203b705cfSriastradh	DBG(("%s: extents (%d, %d), (%d, %d)\n",
78303b705cfSriastradh	     __FUNCTION__, extents.x1, extents.y1, extents.x2, extents.y2));
78403b705cfSriastradh
78503b705cfSriastradh	width  = extents.x2 - extents.x1;
78603b705cfSriastradh	height = extents.y2 - extents.y1;
78703b705cfSriastradh	depth = picture->pDrawable->depth;
78803b705cfSriastradh
78903b705cfSriastradh	DBG(("%s: tmp (%dx%d) depth=%d\n",
79003b705cfSriastradh	     __FUNCTION__, width, height, depth));
79103b705cfSriastradh	scratch = sna_pixmap_create_upload(screen,
79203b705cfSriastradh					   width, height, depth,
79303b705cfSriastradh					   KGEM_BUFFER_WRITE);
79403b705cfSriastradh	if (!scratch)
79503b705cfSriastradh		return true;
79603b705cfSriastradh
79703b705cfSriastradh	memset(scratch->devPrivate.ptr, 0, scratch->devKind*height);
79842542f5fSchristos	image = pixman_image_create_bits((pixman_format_code_t)picture->format,
79942542f5fSchristos					 width, height,
80003b705cfSriastradh					 scratch->devPrivate.ptr,
80103b705cfSriastradh					 scratch->devKind);
80203b705cfSriastradh	if (image) {
80303b705cfSriastradh		pixman_add_traps (image, -extents.x1, -extents.y1,
80403b705cfSriastradh				  ntrap, (pixman_trap_t *)trap);
80503b705cfSriastradh
80603b705cfSriastradh		pixman_image_unref(image);
80703b705cfSriastradh	}
80803b705cfSriastradh
80903b705cfSriastradh	/* XXX clip boxes */
81003b705cfSriastradh	get_drawable_deltas(picture->pDrawable, pixmap, &x, &y);
81103b705cfSriastradh	sna->render.copy_boxes(sna, GXcopy,
81242542f5fSchristos			       &scratch->drawable, __sna_pixmap_get_bo(scratch), -extents.x1, -extents.x1,
81342542f5fSchristos			       &pixmap->drawable, priv->gpu_bo, x, y,
81403b705cfSriastradh			       &extents, 1, 0);
81503b705cfSriastradh	mark_damaged(pixmap, priv, &extents, x, y);
81603b705cfSriastradh
81703b705cfSriastradh	sna_pixmap_destroy(scratch);
81803b705cfSriastradh	return true;
81903b705cfSriastradh}
82003b705cfSriastradh
82103b705cfSriastradhvoid
82203b705cfSriastradhsna_add_traps(PicturePtr picture, INT16 x, INT16 y, int n, xTrap *t)
82303b705cfSriastradh{
82413496ba1Ssnj	PixmapPtr pixmap = get_drawable_pixmap(picture->pDrawable);
82513496ba1Ssnj	struct sna *sna = to_sna_from_pixmap(pixmap);
82613496ba1Ssnj	struct sna_pixmap *priv = sna_pixmap(pixmap);
82703b705cfSriastradh
82803b705cfSriastradh	DBG(("%s (%d, %d) x %d\n", __FUNCTION__, x, y, n));
82903b705cfSriastradh
83013496ba1Ssnj	if (priv && is_gpu_dst(priv)) {
83103b705cfSriastradh		if (trap_span_converter(sna, picture, x, y, n, t))
83203b705cfSriastradh			return;
83303b705cfSriastradh	}
83403b705cfSriastradh
83503b705cfSriastradh	if (is_gpu(sna, picture->pDrawable, PREFER_GPU_RENDER)) {
83603b705cfSriastradh		if (trap_mask_converter(sna, picture, x, y, n, t))
83703b705cfSriastradh			return;
83803b705cfSriastradh
83903b705cfSriastradh		if (trap_upload(picture, x, y, n, t))
84003b705cfSriastradh			return;
84103b705cfSriastradh	}
84203b705cfSriastradh
84303b705cfSriastradh	DBG(("%s -- fallback\n", __FUNCTION__));
84413496ba1Ssnj	if (sna_pixmap_move_to_cpu(pixmap, MOVE_READ | MOVE_WRITE)) {
84503b705cfSriastradh		pixman_image_t *image;
84603b705cfSriastradh		int dx, dy;
84703b705cfSriastradh
84803b705cfSriastradh		if (!(image = image_from_pict(picture, false, &dx, &dy)))
84903b705cfSriastradh			return;
85003b705cfSriastradh
85142542f5fSchristos		if (sigtrap_get() == 0) {
85242542f5fSchristos			pixman_add_traps(image, x + dx, y + dy, n, (pixman_trap_t *)t);
85342542f5fSchristos			sigtrap_put();
85442542f5fSchristos		}
85503b705cfSriastradh
85603b705cfSriastradh		free_pixman_pict(picture, image);
85703b705cfSriastradh	}
85803b705cfSriastradh}
85903b705cfSriastradh
86003b705cfSriastradh#if HAS_PIXMAN_TRIANGLES
86103b705cfSriastradhstatic void
86203b705cfSriastradhtriangles_fallback(CARD8 op,
86303b705cfSriastradh		   PicturePtr src,
86403b705cfSriastradh		   PicturePtr dst,
86503b705cfSriastradh		   PictFormatPtr maskFormat,
86603b705cfSriastradh		   INT16 xSrc, INT16 ySrc,
86703b705cfSriastradh		   int n, xTriangle *tri)
86803b705cfSriastradh{
86903b705cfSriastradh	ScreenPtr screen = dst->pDrawable->pScreen;
87003b705cfSriastradh
87103b705cfSriastradh	DBG(("%s op=%d, count=%d\n", __FUNCTION__, op, n));
87203b705cfSriastradh
87303b705cfSriastradh	if (maskFormat) {
87403b705cfSriastradh		PixmapPtr scratch;
87503b705cfSriastradh		PicturePtr mask;
87603b705cfSriastradh		INT16 dst_x, dst_y;
87703b705cfSriastradh		BoxRec bounds;
87803b705cfSriastradh		int width, height, depth;
87903b705cfSriastradh		pixman_image_t *image;
88003b705cfSriastradh		pixman_format_code_t format;
88103b705cfSriastradh		int error;
88203b705cfSriastradh
88303b705cfSriastradh		dst_x = pixman_fixed_to_int(tri[0].p1.x);
88403b705cfSriastradh		dst_y = pixman_fixed_to_int(tri[0].p1.y);
88503b705cfSriastradh
88603b705cfSriastradh		miTriangleBounds(n, tri, &bounds);
88703b705cfSriastradh		DBG(("%s: bounds (%d, %d), (%d, %d)\n",
88803b705cfSriastradh		     __FUNCTION__, bounds.x1, bounds.y1, bounds.x2, bounds.y2));
88903b705cfSriastradh
89003b705cfSriastradh		if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
89103b705cfSriastradh			return;
89203b705cfSriastradh
89303b705cfSriastradh		if (!sna_compute_composite_extents(&bounds,
89403b705cfSriastradh						   src, NULL, dst,
89503b705cfSriastradh						   xSrc, ySrc,
89603b705cfSriastradh						   0, 0,
89703b705cfSriastradh						   bounds.x1, bounds.y1,
89803b705cfSriastradh						   bounds.x2 - bounds.x1,
89903b705cfSriastradh						   bounds.y2 - bounds.y1))
90003b705cfSriastradh			return;
90103b705cfSriastradh
90203b705cfSriastradh		DBG(("%s: extents (%d, %d), (%d, %d)\n",
90303b705cfSriastradh		     __FUNCTION__, bounds.x1, bounds.y1, bounds.x2, bounds.y2));
90403b705cfSriastradh
90503b705cfSriastradh		width  = bounds.x2 - bounds.x1;
90603b705cfSriastradh		height = bounds.y2 - bounds.y1;
90703b705cfSriastradh		bounds.x1 -= dst->pDrawable->x;
90803b705cfSriastradh		bounds.y1 -= dst->pDrawable->y;
90903b705cfSriastradh		depth = maskFormat->depth;
91003b705cfSriastradh		format = maskFormat->format | (BitsPerPixel(depth) << 24);
91103b705cfSriastradh
91203b705cfSriastradh		DBG(("%s: mask (%dx%d) depth=%d, format=%08x\n",
91303b705cfSriastradh		     __FUNCTION__, width, height, depth, format));
91403b705cfSriastradh		scratch = sna_pixmap_create_upload(screen,
91503b705cfSriastradh						   width, height, depth,
91603b705cfSriastradh						   KGEM_BUFFER_WRITE);
91703b705cfSriastradh		if (!scratch)
91803b705cfSriastradh			return;
91903b705cfSriastradh
92042542f5fSchristos		memset(scratch->devPrivate.ptr, 0, (size_t)scratch->devKind*height);
92103b705cfSriastradh		image = pixman_image_create_bits(format, width, height,
92203b705cfSriastradh						 scratch->devPrivate.ptr,
92303b705cfSriastradh						 scratch->devKind);
92403b705cfSriastradh		if (image) {
92503b705cfSriastradh			pixman_add_triangles(image,
92603b705cfSriastradh					     -bounds.x1, -bounds.y1,
92703b705cfSriastradh					     n, (pixman_triangle_t *)tri);
92803b705cfSriastradh			pixman_image_unref(image);
92903b705cfSriastradh		}
93003b705cfSriastradh
93103b705cfSriastradh		mask = CreatePicture(0, &scratch->drawable,
93203b705cfSriastradh				     PictureMatchFormat(screen, depth, format),
93303b705cfSriastradh				     0, 0, serverClient, &error);
93403b705cfSriastradh		if (mask) {
93503b705cfSriastradh			CompositePicture(op, src, mask, dst,
93603b705cfSriastradh					 xSrc + bounds.x1 - dst_x,
93703b705cfSriastradh					 ySrc + bounds.y1 - dst_y,
93803b705cfSriastradh					 0, 0,
93903b705cfSriastradh					 bounds.x1, bounds.y1,
94003b705cfSriastradh					 width, height);
94103b705cfSriastradh			FreePicture(mask, 0);
94203b705cfSriastradh		}
94303b705cfSriastradh		sna_pixmap_destroy(scratch);
94403b705cfSriastradh	} else {
94503b705cfSriastradh		if (dst->polyEdge == PolyEdgeSharp)
94603b705cfSriastradh			maskFormat = PictureMatchFormat(screen, 1, PICT_a1);
94703b705cfSriastradh		else
94803b705cfSriastradh			maskFormat = PictureMatchFormat(screen, 8, PICT_a8);
94903b705cfSriastradh
95003b705cfSriastradh		for (; n--; tri++)
95103b705cfSriastradh			triangles_fallback(op,
95203b705cfSriastradh					   src, dst, maskFormat,
95303b705cfSriastradh					   xSrc, ySrc, 1, tri);
95403b705cfSriastradh	}
95503b705cfSriastradh}
95603b705cfSriastradh
95703b705cfSriastradhvoid
95803b705cfSriastradhsna_composite_triangles(CARD8 op,
95903b705cfSriastradh			 PicturePtr src,
96003b705cfSriastradh			 PicturePtr dst,
96103b705cfSriastradh			 PictFormatPtr maskFormat,
96203b705cfSriastradh			 INT16 xSrc, INT16 ySrc,
96303b705cfSriastradh			 int n, xTriangle *tri)
96403b705cfSriastradh{
96503b705cfSriastradh	struct sna *sna = to_sna_from_drawable(dst->pDrawable);
96603b705cfSriastradh
96703b705cfSriastradh	if (triangles_span_converter(sna, op, src, dst, maskFormat,
96803b705cfSriastradh				     xSrc, ySrc,
96903b705cfSriastradh				     n, tri))
97003b705cfSriastradh		return;
97103b705cfSriastradh
97203b705cfSriastradh	if (triangles_mask_converter(op, src, dst, maskFormat,
97303b705cfSriastradh				     xSrc, ySrc,
97403b705cfSriastradh				     n, tri))
97503b705cfSriastradh		return;
97603b705cfSriastradh
97703b705cfSriastradh	triangles_fallback(op, src, dst, maskFormat, xSrc, ySrc, n, tri);
97803b705cfSriastradh}
97903b705cfSriastradh
98003b705cfSriastradhstatic void
98103b705cfSriastradhtristrip_fallback(CARD8 op,
98203b705cfSriastradh		  PicturePtr src,
98303b705cfSriastradh		  PicturePtr dst,
98403b705cfSriastradh		  PictFormatPtr maskFormat,
98503b705cfSriastradh		  INT16 xSrc, INT16 ySrc,
98603b705cfSriastradh		  int n, xPointFixed *points)
98703b705cfSriastradh{
98803b705cfSriastradh	ScreenPtr screen = dst->pDrawable->pScreen;
98903b705cfSriastradh
99003b705cfSriastradh	if (maskFormat) {
99103b705cfSriastradh		PixmapPtr scratch;
99203b705cfSriastradh		PicturePtr mask;
99303b705cfSriastradh		INT16 dst_x, dst_y;
99403b705cfSriastradh		BoxRec bounds;
99503b705cfSriastradh		int width, height, depth;
99603b705cfSriastradh		pixman_image_t *image;
99703b705cfSriastradh		pixman_format_code_t format;
99803b705cfSriastradh		int error;
99903b705cfSriastradh
100003b705cfSriastradh		dst_x = pixman_fixed_to_int(points->x);
100103b705cfSriastradh		dst_y = pixman_fixed_to_int(points->y);
100203b705cfSriastradh
100303b705cfSriastradh		miPointFixedBounds(n, points, &bounds);
100403b705cfSriastradh		DBG(("%s: bounds (%d, %d), (%d, %d)\n",
100503b705cfSriastradh		     __FUNCTION__, bounds.x1, bounds.y1, bounds.x2, bounds.y2));
100603b705cfSriastradh
100703b705cfSriastradh		if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
100803b705cfSriastradh			return;
100903b705cfSriastradh
101003b705cfSriastradh		if (!sna_compute_composite_extents(&bounds,
101103b705cfSriastradh						   src, NULL, dst,
101203b705cfSriastradh						   xSrc, ySrc,
101303b705cfSriastradh						   0, 0,
101403b705cfSriastradh						   bounds.x1, bounds.y1,
101503b705cfSriastradh						   bounds.x2 - bounds.x1,
101603b705cfSriastradh						   bounds.y2 - bounds.y1))
101703b705cfSriastradh			return;
101803b705cfSriastradh
101903b705cfSriastradh		DBG(("%s: extents (%d, %d), (%d, %d)\n",
102003b705cfSriastradh		     __FUNCTION__, bounds.x1, bounds.y1, bounds.x2, bounds.y2));
102103b705cfSriastradh
102203b705cfSriastradh		width  = bounds.x2 - bounds.x1;
102303b705cfSriastradh		height = bounds.y2 - bounds.y1;
102403b705cfSriastradh		bounds.x1 -= dst->pDrawable->x;
102503b705cfSriastradh		bounds.y1 -= dst->pDrawable->y;
102603b705cfSriastradh		depth = maskFormat->depth;
102703b705cfSriastradh		format = maskFormat->format | (BitsPerPixel(depth) << 24);
102803b705cfSriastradh
102903b705cfSriastradh		DBG(("%s: mask (%dx%d) depth=%d, format=%08x\n",
103003b705cfSriastradh		     __FUNCTION__, width, height, depth, format));
103103b705cfSriastradh		scratch = sna_pixmap_create_upload(screen,
103203b705cfSriastradh						   width, height, depth,
103303b705cfSriastradh						   KGEM_BUFFER_WRITE);
103403b705cfSriastradh		if (!scratch)
103503b705cfSriastradh			return;
103603b705cfSriastradh
103703b705cfSriastradh		memset(scratch->devPrivate.ptr, 0, scratch->devKind*height);
103803b705cfSriastradh		image = pixman_image_create_bits(format, width, height,
103903b705cfSriastradh						 scratch->devPrivate.ptr,
104003b705cfSriastradh						 scratch->devKind);
104103b705cfSriastradh		if (image) {
104203b705cfSriastradh			xTriangle tri;
104303b705cfSriastradh			xPointFixed *p[3] = { &tri.p1, &tri.p2, &tri.p3 };
104403b705cfSriastradh			int i;
104503b705cfSriastradh
104603b705cfSriastradh			*p[0] = points[0];
104703b705cfSriastradh			*p[1] = points[1];
104803b705cfSriastradh			*p[2] = points[2];
104903b705cfSriastradh			pixman_add_triangles(image,
105003b705cfSriastradh					     -bounds.x1, -bounds.y1,
105103b705cfSriastradh					     1, (pixman_triangle_t *)&tri);
105203b705cfSriastradh			for (i = 3; i < n; i++) {
105303b705cfSriastradh				*p[i%3] = points[i];
105403b705cfSriastradh				pixman_add_triangles(image,
105503b705cfSriastradh						     -bounds.x1, -bounds.y1,
105603b705cfSriastradh						     1, (pixman_triangle_t *)&tri);
105703b705cfSriastradh			}
105803b705cfSriastradh			pixman_image_unref(image);
105903b705cfSriastradh		}
106003b705cfSriastradh
106103b705cfSriastradh		mask = CreatePicture(0, &scratch->drawable,
106203b705cfSriastradh				     PictureMatchFormat(screen, depth, format),
106303b705cfSriastradh				     0, 0, serverClient, &error);
106403b705cfSriastradh		if (mask) {
106503b705cfSriastradh			CompositePicture(op, src, mask, dst,
106603b705cfSriastradh					 xSrc + bounds.x1 - dst_x,
106703b705cfSriastradh					 ySrc + bounds.y1 - dst_y,
106803b705cfSriastradh					 0, 0,
106903b705cfSriastradh					 bounds.x1, bounds.y1,
107003b705cfSriastradh					 width, height);
107103b705cfSriastradh			FreePicture(mask, 0);
107203b705cfSriastradh		}
107303b705cfSriastradh		sna_pixmap_destroy(scratch);
107403b705cfSriastradh	} else {
107503b705cfSriastradh		xTriangle tri;
107603b705cfSriastradh		xPointFixed *p[3] = { &tri.p1, &tri.p2, &tri.p3 };
107703b705cfSriastradh		int i;
107803b705cfSriastradh
107903b705cfSriastradh		if (dst->polyEdge == PolyEdgeSharp)
108003b705cfSriastradh			maskFormat = PictureMatchFormat(screen, 1, PICT_a1);
108103b705cfSriastradh		else
108203b705cfSriastradh			maskFormat = PictureMatchFormat(screen, 8, PICT_a8);
108303b705cfSriastradh
108403b705cfSriastradh		*p[0] = points[0];
108503b705cfSriastradh		*p[1] = points[1];
108603b705cfSriastradh		*p[2] = points[2];
108703b705cfSriastradh		triangles_fallback(op,
108803b705cfSriastradh				   src, dst, maskFormat,
108903b705cfSriastradh				   xSrc, ySrc, 1, &tri);
109003b705cfSriastradh		for (i = 3; i < n; i++) {
109103b705cfSriastradh			*p[i%3] = points[i];
109203b705cfSriastradh			/* Should xSrc,ySrc be updated? */
109303b705cfSriastradh			triangles_fallback(op,
109403b705cfSriastradh					   src, dst, maskFormat,
109503b705cfSriastradh					   xSrc, ySrc, 1, &tri);
109603b705cfSriastradh		}
109703b705cfSriastradh	}
109803b705cfSriastradh}
109903b705cfSriastradh
110003b705cfSriastradhvoid
110103b705cfSriastradhsna_composite_tristrip(CARD8 op,
110203b705cfSriastradh		       PicturePtr src,
110303b705cfSriastradh		       PicturePtr dst,
110403b705cfSriastradh		       PictFormatPtr maskFormat,
110503b705cfSriastradh		       INT16 xSrc, INT16 ySrc,
110603b705cfSriastradh		       int n, xPointFixed *points)
110703b705cfSriastradh{
110803b705cfSriastradh	struct sna *sna = to_sna_from_drawable(dst->pDrawable);
110903b705cfSriastradh
111003b705cfSriastradh	if (tristrip_span_converter(sna, op, src, dst, maskFormat, xSrc, ySrc, n, points))
111103b705cfSriastradh		return;
111203b705cfSriastradh
111303b705cfSriastradh	tristrip_fallback(op, src, dst, maskFormat, xSrc, ySrc, n, points);
111403b705cfSriastradh}
111503b705cfSriastradh
111603b705cfSriastradhstatic void
111703b705cfSriastradhtrifan_fallback(CARD8 op,
111803b705cfSriastradh		PicturePtr src,
111903b705cfSriastradh		PicturePtr dst,
112003b705cfSriastradh		PictFormatPtr maskFormat,
112103b705cfSriastradh		INT16 xSrc, INT16 ySrc,
112203b705cfSriastradh		int n, xPointFixed *points)
112303b705cfSriastradh{
112403b705cfSriastradh	ScreenPtr screen = dst->pDrawable->pScreen;
112503b705cfSriastradh
112603b705cfSriastradh	if (maskFormat) {
112703b705cfSriastradh		PixmapPtr scratch;
112803b705cfSriastradh		PicturePtr mask;
112903b705cfSriastradh		INT16 dst_x, dst_y;
113003b705cfSriastradh		BoxRec bounds;
113103b705cfSriastradh		int width, height, depth;
113203b705cfSriastradh		pixman_image_t *image;
113303b705cfSriastradh		pixman_format_code_t format;
113403b705cfSriastradh		int error;
113503b705cfSriastradh
113603b705cfSriastradh		dst_x = pixman_fixed_to_int(points->x);
113703b705cfSriastradh		dst_y = pixman_fixed_to_int(points->y);
113803b705cfSriastradh
113903b705cfSriastradh		miPointFixedBounds(n, points, &bounds);
114003b705cfSriastradh		DBG(("%s: bounds (%d, %d), (%d, %d)\n",
114103b705cfSriastradh		     __FUNCTION__, bounds.x1, bounds.y1, bounds.x2, bounds.y2));
114203b705cfSriastradh
114303b705cfSriastradh		if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
114403b705cfSriastradh			return;
114503b705cfSriastradh
114603b705cfSriastradh		if (!sna_compute_composite_extents(&bounds,
114703b705cfSriastradh						   src, NULL, dst,
114803b705cfSriastradh						   xSrc, ySrc,
114903b705cfSriastradh						   0, 0,
115003b705cfSriastradh						   bounds.x1, bounds.y1,
115103b705cfSriastradh						   bounds.x2 - bounds.x1,
115203b705cfSriastradh						   bounds.y2 - bounds.y1))
115303b705cfSriastradh			return;
115403b705cfSriastradh
115503b705cfSriastradh		DBG(("%s: extents (%d, %d), (%d, %d)\n",
115603b705cfSriastradh		     __FUNCTION__, bounds.x1, bounds.y1, bounds.x2, bounds.y2));
115703b705cfSriastradh
115803b705cfSriastradh		width  = bounds.x2 - bounds.x1;
115903b705cfSriastradh		height = bounds.y2 - bounds.y1;
116003b705cfSriastradh		bounds.x1 -= dst->pDrawable->x;
116103b705cfSriastradh		bounds.y1 -= dst->pDrawable->y;
116203b705cfSriastradh		depth = maskFormat->depth;
116303b705cfSriastradh		format = maskFormat->format | (BitsPerPixel(depth) << 24);
116403b705cfSriastradh
116503b705cfSriastradh		DBG(("%s: mask (%dx%d) depth=%d, format=%08x\n",
116603b705cfSriastradh		     __FUNCTION__, width, height, depth, format));
116703b705cfSriastradh		scratch = sna_pixmap_create_upload(screen,
116803b705cfSriastradh						   width, height, depth,
116903b705cfSriastradh						   KGEM_BUFFER_WRITE);
117003b705cfSriastradh		if (!scratch)
117103b705cfSriastradh			return;
117203b705cfSriastradh
117303b705cfSriastradh		memset(scratch->devPrivate.ptr, 0, scratch->devKind*height);
117403b705cfSriastradh		image = pixman_image_create_bits(format, width, height,
117503b705cfSriastradh						 scratch->devPrivate.ptr,
117603b705cfSriastradh						 scratch->devKind);
117703b705cfSriastradh		if (image) {
117803b705cfSriastradh			xTriangle tri;
117903b705cfSriastradh			xPointFixed *p[3] = { &tri.p1, &tri.p2, &tri.p3 };
118003b705cfSriastradh			int i;
118103b705cfSriastradh
118203b705cfSriastradh			*p[0] = points[0];
118303b705cfSriastradh			*p[1] = points[1];
118403b705cfSriastradh			*p[2] = points[2];
118503b705cfSriastradh			pixman_add_triangles(image,
118603b705cfSriastradh					     -bounds.x1, -bounds.y1,
118703b705cfSriastradh					     1, (pixman_triangle_t *)&tri);
118803b705cfSriastradh			for (i = 3; i < n; i++) {
118903b705cfSriastradh				*p[2 - (i&1)] = points[i];
119003b705cfSriastradh				pixman_add_triangles(image,
119103b705cfSriastradh						     -bounds.x1, -bounds.y1,
119203b705cfSriastradh						     1, (pixman_triangle_t *)&tri);
119303b705cfSriastradh			}
119403b705cfSriastradh			pixman_image_unref(image);
119503b705cfSriastradh		}
119603b705cfSriastradh
119703b705cfSriastradh		mask = CreatePicture(0, &scratch->drawable,
119803b705cfSriastradh				     PictureMatchFormat(screen, depth, format),
119903b705cfSriastradh				     0, 0, serverClient, &error);
120003b705cfSriastradh		if (mask) {
120103b705cfSriastradh			CompositePicture(op, src, mask, dst,
120203b705cfSriastradh					 xSrc + bounds.x1 - dst_x,
120303b705cfSriastradh					 ySrc + bounds.y1 - dst_y,
120403b705cfSriastradh					 0, 0,
120503b705cfSriastradh					 bounds.x1, bounds.y1,
120603b705cfSriastradh					 width, height);
120703b705cfSriastradh			FreePicture(mask, 0);
120803b705cfSriastradh		}
120903b705cfSriastradh		sna_pixmap_destroy(scratch);
121003b705cfSriastradh	} else {
121103b705cfSriastradh		xTriangle tri;
121203b705cfSriastradh		xPointFixed *p[3] = { &tri.p1, &tri.p2, &tri.p3 };
121303b705cfSriastradh		int i;
121403b705cfSriastradh
121503b705cfSriastradh		if (dst->polyEdge == PolyEdgeSharp)
121603b705cfSriastradh			maskFormat = PictureMatchFormat(screen, 1, PICT_a1);
121703b705cfSriastradh		else
121803b705cfSriastradh			maskFormat = PictureMatchFormat(screen, 8, PICT_a8);
121903b705cfSriastradh
122003b705cfSriastradh		*p[0] = points[0];
122103b705cfSriastradh		*p[1] = points[1];
122203b705cfSriastradh		*p[2] = points[2];
122303b705cfSriastradh		triangles_fallback(op,
122403b705cfSriastradh				   src, dst, maskFormat,
122503b705cfSriastradh				   xSrc, ySrc, 1, &tri);
122603b705cfSriastradh		for (i = 3; i < n; i++) {
122703b705cfSriastradh			*p[2 - (i&1)] = points[i];
122803b705cfSriastradh			/* Should xSrc,ySrc be updated? */
122903b705cfSriastradh			triangles_fallback(op,
123003b705cfSriastradh					   src, dst, maskFormat,
123103b705cfSriastradh					   xSrc, ySrc, 1, &tri);
123203b705cfSriastradh		}
123303b705cfSriastradh	}
123403b705cfSriastradh}
123503b705cfSriastradh
123603b705cfSriastradhvoid
123703b705cfSriastradhsna_composite_trifan(CARD8 op,
123803b705cfSriastradh		     PicturePtr src,
123903b705cfSriastradh		     PicturePtr dst,
124003b705cfSriastradh		     PictFormatPtr maskFormat,
124103b705cfSriastradh		     INT16 xSrc, INT16 ySrc,
124203b705cfSriastradh		     int n, xPointFixed *points)
124303b705cfSriastradh{
124403b705cfSriastradh	trifan_fallback(op, src, dst, maskFormat, xSrc, ySrc, n, points);
124503b705cfSriastradh}
124603b705cfSriastradh#endif
1247