142542f5fSchristos/*
242542f5fSchristos * Copyright (c) 2007  David Turner
342542f5fSchristos * Copyright (c) 2008  M Joonas Pihlaja
442542f5fSchristos * Copyright (c) 2011 Intel Corporation
542542f5fSchristos *
642542f5fSchristos * Permission is hereby granted, free of charge, to any person obtaining a
742542f5fSchristos * copy of this software and associated documentation files (the "Software"),
842542f5fSchristos * to deal in the Software without restriction, including without limitation
942542f5fSchristos * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1042542f5fSchristos * and/or sell copies of the Software, and to permit persons to whom the
1142542f5fSchristos * Software is furnished to do so, subject to the following conditions:
1242542f5fSchristos *
1342542f5fSchristos * The above copyright notice and this permission notice (including the next
1442542f5fSchristos * paragraph) shall be included in all copies or substantial portions of the
1542542f5fSchristos * Software.
1642542f5fSchristos *
1742542f5fSchristos * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1842542f5fSchristos * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1942542f5fSchristos * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
2042542f5fSchristos * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2142542f5fSchristos * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2242542f5fSchristos * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2342542f5fSchristos * SOFTWARE.
2442542f5fSchristos *
2542542f5fSchristos * Authors:
2642542f5fSchristos *    Chris Wilson <chris@chris-wilson.co.uk>
2742542f5fSchristos *
2842542f5fSchristos */
2942542f5fSchristos
3042542f5fSchristos#ifdef HAVE_CONFIG_H
3142542f5fSchristos#include "config.h"
3242542f5fSchristos#endif
3342542f5fSchristos
3442542f5fSchristos#include "sna.h"
3542542f5fSchristos#include "sna_render.h"
3642542f5fSchristos#include "sna_render_inline.h"
3742542f5fSchristos#include "sna_trapezoids.h"
3842542f5fSchristos#include "fb/fbpict.h"
3942542f5fSchristos
4042542f5fSchristos#include <mipict.h>
4142542f5fSchristos
4242542f5fSchristos#undef SAMPLES_X
4342542f5fSchristos#undef SAMPLES_Y
4442542f5fSchristos
4542542f5fSchristos/* TODO: Emit unantialiased and MSAA triangles. */
4642542f5fSchristos
4742542f5fSchristos#ifndef MAX
4842542f5fSchristos#define MAX(x,y) ((x) >= (y) ? (x) : (y))
4942542f5fSchristos#endif
5042542f5fSchristos
5142542f5fSchristos#ifndef MIN
5242542f5fSchristos#define MIN(x,y) ((x) <= (y) ? (x) : (y))
5342542f5fSchristos#endif
5442542f5fSchristos
5542542f5fSchristostypedef void (*span_func_t)(struct sna *sna,
5642542f5fSchristos			    struct sna_composite_spans_op *op,
5742542f5fSchristos			    pixman_region16_t *clip,
5842542f5fSchristos			    const BoxRec *box,
5942542f5fSchristos			    int coverage);
6042542f5fSchristos
6142542f5fSchristos#if HAS_DEBUG_FULL
6242542f5fSchristosstatic void _assert_pixmap_contains_box(PixmapPtr pixmap, BoxPtr box, const char *function)
6342542f5fSchristos{
6442542f5fSchristos	if (box->x1 < 0 || box->y1 < 0 ||
6542542f5fSchristos	    box->x2 > pixmap->drawable.width ||
6642542f5fSchristos	    box->y2 > pixmap->drawable.height)
6742542f5fSchristos	{
6842542f5fSchristos		FatalError("%s: damage box is beyond the pixmap: box=(%d, %d), (%d, %d), pixmap=(%d, %d)\n",
6942542f5fSchristos			   function,
7042542f5fSchristos			   box->x1, box->y1, box->x2, box->y2,
7142542f5fSchristos			   pixmap->drawable.width,
7242542f5fSchristos			   pixmap->drawable.height);
7342542f5fSchristos	}
7442542f5fSchristos}
7542542f5fSchristos#define assert_pixmap_contains_box(p, b) _assert_pixmap_contains_box(p, b, __FUNCTION__)
7642542f5fSchristos#else
7742542f5fSchristos#define assert_pixmap_contains_box(p, b)
7842542f5fSchristos#endif
7942542f5fSchristos
8042542f5fSchristosstatic void apply_damage(struct sna_composite_op *op, RegionPtr region)
8142542f5fSchristos{
8242542f5fSchristos	DBG(("%s: damage=%p, region=%dx[(%d, %d), (%d, %d)]\n",
8342542f5fSchristos	     __FUNCTION__, op->damage,
8442542f5fSchristos	     region_num_rects(region),
8542542f5fSchristos	     region->extents.x1, region->extents.y1,
8642542f5fSchristos	     region->extents.x2, region->extents.y2));
8742542f5fSchristos
8842542f5fSchristos	if (op->damage == NULL)
8942542f5fSchristos		return;
9042542f5fSchristos
9142542f5fSchristos	RegionTranslate(region, op->dst.x, op->dst.y);
9242542f5fSchristos
9342542f5fSchristos	assert_pixmap_contains_box(op->dst.pixmap, RegionExtents(region));
9442542f5fSchristos	sna_damage_add(op->damage, region);
9542542f5fSchristos}
9642542f5fSchristos
9742542f5fSchristosstatic void _apply_damage_box(struct sna_composite_op *op, const BoxRec *box)
9842542f5fSchristos{
9942542f5fSchristos	BoxRec r;
10042542f5fSchristos
10142542f5fSchristos	r.x1 = box->x1 + op->dst.x;
10242542f5fSchristos	r.x2 = box->x2 + op->dst.x;
10342542f5fSchristos	r.y1 = box->y1 + op->dst.y;
10442542f5fSchristos	r.y2 = box->y2 + op->dst.y;
10542542f5fSchristos
10642542f5fSchristos	assert_pixmap_contains_box(op->dst.pixmap, &r);
10742542f5fSchristos	sna_damage_add_box(op->damage, &r);
10842542f5fSchristos}
10942542f5fSchristos
11042542f5fSchristosinline static void apply_damage_box(struct sna_composite_op *op, const BoxRec *box)
11142542f5fSchristos{
11242542f5fSchristos	if (op->damage)
11342542f5fSchristos		_apply_damage_box(op, box);
11442542f5fSchristos}
11542542f5fSchristos
11642542f5fSchristos#define FAST_SAMPLES_X_TO_INT_FRAC(x, i, f) \
11742542f5fSchristos	_GRID_TO_INT_FRAC_shift(x, i, f, FAST_SAMPLES_shift)
11842542f5fSchristos
11942542f5fSchristos#define FAST_SAMPLES_INT(x) ((x) >> (FAST_SAMPLES_shift))
12042542f5fSchristos#define FAST_SAMPLES_FRAC(x) ((x) & (FAST_SAMPLES_mask))
12142542f5fSchristos
12242542f5fSchristos#define _GRID_TO_INT_FRAC_shift(t, i, f, b) do {	\
12342542f5fSchristos    (f) = FAST_SAMPLES_FRAC(t);				\
12442542f5fSchristos    (i) = FAST_SAMPLES_INT(t);				\
12542542f5fSchristos} while (0)
12642542f5fSchristos
12713496ba1Ssnj#define FAST_SAMPLES_XY (FAST_SAMPLES_X*FAST_SAMPLES_Y) /* Unit area on the grid. */
12842542f5fSchristos#define AREA_TO_ALPHA(c)  ((c) / (float)FAST_SAMPLES_XY)
12942542f5fSchristos
13042542f5fSchristosstruct quorem {
13142542f5fSchristos	int32_t quo;
13213496ba1Ssnj	int64_t rem;
13342542f5fSchristos};
13442542f5fSchristos
13542542f5fSchristosstruct edge {
13642542f5fSchristos	struct edge *next, *prev;
13742542f5fSchristos
13842542f5fSchristos	int dir;
13913496ba1Ssnj	int cell;
14042542f5fSchristos	int height_left;
14142542f5fSchristos
14242542f5fSchristos	struct quorem x;
14342542f5fSchristos
14442542f5fSchristos	/* Advance of the current x when moving down a subsample line. */
14542542f5fSchristos	struct quorem dxdy;
14613496ba1Ssnj	int64_t dy;
14742542f5fSchristos
14842542f5fSchristos	/* The clipped y of the top of the edge. */
14942542f5fSchristos	int ytop;
15042542f5fSchristos
15142542f5fSchristos	/* y2-y1 after orienting the edge downwards.  */
15242542f5fSchristos};
15342542f5fSchristos
15442542f5fSchristos/* Number of subsample rows per y-bucket. Must be SAMPLES_Y. */
15542542f5fSchristos#define EDGE_Y_BUCKET_HEIGHT FAST_SAMPLES_Y
15642542f5fSchristos#define EDGE_Y_BUCKET_INDEX(y, ymin) (((y) - (ymin))/EDGE_Y_BUCKET_HEIGHT)
15742542f5fSchristos
15842542f5fSchristos/* A collection of sorted and vertically clipped edges of the polygon.
15942542f5fSchristos * Edges are moved from the polygon to an active list while scan
16042542f5fSchristos * converting. */
16142542f5fSchristosstruct polygon {
16242542f5fSchristos	/* The vertical clip extents. */
16342542f5fSchristos	int ymin, ymax;
16442542f5fSchristos
16542542f5fSchristos	/* Array of edges all starting in the same bucket.	An edge is put
16642542f5fSchristos	 * into bucket EDGE_BUCKET_INDEX(edge->ytop, polygon->ymin) when
16742542f5fSchristos	 * it is added to the polygon. */
16842542f5fSchristos	struct edge **y_buckets;
16942542f5fSchristos	struct edge *y_buckets_embedded[64];
17042542f5fSchristos
17142542f5fSchristos	struct edge edges_embedded[32];
17242542f5fSchristos	struct edge *edges;
17342542f5fSchristos	int num_edges;
17442542f5fSchristos};
17542542f5fSchristos
17642542f5fSchristos/* A cell records the effect on pixel coverage of polygon edges
17742542f5fSchristos * passing through a pixel.  It contains two accumulators of pixel
17842542f5fSchristos * coverage.
17942542f5fSchristos *
18042542f5fSchristos * Consider the effects of a polygon edge on the coverage of a pixel
18142542f5fSchristos * it intersects and that of the following one.  The coverage of the
18242542f5fSchristos * following pixel is the height of the edge multiplied by the width
18342542f5fSchristos * of the pixel, and the coverage of the pixel itself is the area of
18442542f5fSchristos * the trapezoid formed by the edge and the right side of the pixel.
18542542f5fSchristos *
18642542f5fSchristos * +-----------------------+-----------------------+
18742542f5fSchristos * |                       |                       |
18842542f5fSchristos * |                       |                       |
18942542f5fSchristos * |_______________________|_______________________|
19042542f5fSchristos * |   \...................|.......................|\
19142542f5fSchristos * |    \..................|.......................| |
19242542f5fSchristos * |     \.................|.......................| |
19342542f5fSchristos * |      \....covered.....|.......................| |
19442542f5fSchristos * |       \....area.......|.......................| } covered height
19542542f5fSchristos * |        \..............|.......................| |
19642542f5fSchristos * |uncovered\.............|.......................| |
19742542f5fSchristos * |  area    \............|.......................| |
19842542f5fSchristos * |___________\...........|.......................|/
19942542f5fSchristos * |                       |                       |
20042542f5fSchristos * |                       |                       |
20142542f5fSchristos * |                       |                       |
20242542f5fSchristos * +-----------------------+-----------------------+
20342542f5fSchristos *
20442542f5fSchristos * Since the coverage of the following pixel will always be a multiple
20542542f5fSchristos * of the width of the pixel, we can store the height of the covered
20642542f5fSchristos * area instead.  The coverage of the pixel itself is the total
20742542f5fSchristos * coverage minus the area of the uncovered area to the left of the
20842542f5fSchristos * edge.  As it's faster to compute the uncovered area we only store
20942542f5fSchristos * that and subtract it from the total coverage later when forming
21042542f5fSchristos * spans to blit.
21142542f5fSchristos *
21242542f5fSchristos * The heights and areas are signed, with left edges of the polygon
21342542f5fSchristos * having positive sign and right edges having negative sign.  When
21442542f5fSchristos * two edges intersect they swap their left/rightness so their
21542542f5fSchristos * contribution above and below the intersection point must be
21642542f5fSchristos * computed separately. */
21742542f5fSchristosstruct cell {
21842542f5fSchristos	struct cell *next;
21942542f5fSchristos	int x;
22042542f5fSchristos	int16_t uncovered_area;
22142542f5fSchristos	int16_t covered_height;
22242542f5fSchristos};
22342542f5fSchristos
22442542f5fSchristos/* A cell list represents the scan line sparsely as cells ordered by
22542542f5fSchristos * ascending x.  It is geared towards scanning the cells in order
22642542f5fSchristos * using an internal cursor. */
22742542f5fSchristosstruct cell_list {
22842542f5fSchristos	struct cell *cursor;
22942542f5fSchristos
23042542f5fSchristos	/* Points to the left-most cell in the scan line. */
23142542f5fSchristos	struct cell head, tail;
23242542f5fSchristos
23342542f5fSchristos	int16_t x1, x2;
23442542f5fSchristos	int16_t count, size;
23542542f5fSchristos	struct cell *cells;
23642542f5fSchristos	struct cell embedded[256];
23742542f5fSchristos};
23842542f5fSchristos
23942542f5fSchristos/* The active list contains edges in the current scan line ordered by
24042542f5fSchristos * the x-coordinate of the intercept of the edge and the scan line. */
24142542f5fSchristosstruct active_list {
24242542f5fSchristos	/* Leftmost edge on the current scan line. */
24342542f5fSchristos	struct edge head, tail;
24442542f5fSchristos};
24542542f5fSchristos
24642542f5fSchristosstruct tor {
24742542f5fSchristos    struct polygon	polygon[1];
24842542f5fSchristos    struct active_list	active[1];
24942542f5fSchristos    struct cell_list	coverages[1];
25042542f5fSchristos
25142542f5fSchristos    BoxRec extents;
25242542f5fSchristos};
25342542f5fSchristos
25442542f5fSchristos/* Compute the floored division a/b. Assumes / and % perform symmetric
25542542f5fSchristos * division. */
25642542f5fSchristos/* Rewinds the cell list's cursor to the beginning.  After rewinding
25742542f5fSchristos * we're good to cell_list_find() the cell any x coordinate. */
25842542f5fSchristosinline static void
25942542f5fSchristoscell_list_rewind(struct cell_list *cells)
26042542f5fSchristos{
26142542f5fSchristos	cells->cursor = &cells->head;
26242542f5fSchristos}
26342542f5fSchristos
26442542f5fSchristosstatic bool
26542542f5fSchristoscell_list_init(struct cell_list *cells, int x1, int x2)
26642542f5fSchristos{
26742542f5fSchristos	cells->tail.next = NULL;
26842542f5fSchristos	cells->tail.x = INT_MAX;
26942542f5fSchristos	cells->head.x = INT_MIN;
27042542f5fSchristos	cells->head.next = &cells->tail;
27142542f5fSchristos	cells->head.covered_height = 0;
27242542f5fSchristos	cell_list_rewind(cells);
27342542f5fSchristos	cells->count = 0;
27442542f5fSchristos	cells->x1 = x1;
27542542f5fSchristos	cells->x2 = x2;
27642542f5fSchristos	cells->size = x2 - x1 + 1;
27742542f5fSchristos	cells->cells = cells->embedded;
27842542f5fSchristos	if (cells->size > ARRAY_SIZE(cells->embedded))
27942542f5fSchristos		cells->cells = malloc(cells->size * sizeof(struct cell));
28042542f5fSchristos	return cells->cells != NULL;
28142542f5fSchristos}
28242542f5fSchristos
28342542f5fSchristosstatic void
28442542f5fSchristoscell_list_fini(struct cell_list *cells)
28542542f5fSchristos{
28642542f5fSchristos	if (cells->cells != cells->embedded)
28742542f5fSchristos		free(cells->cells);
28842542f5fSchristos}
28942542f5fSchristos
29042542f5fSchristosinline static void
29142542f5fSchristoscell_list_reset(struct cell_list *cells)
29242542f5fSchristos{
29342542f5fSchristos	cell_list_rewind(cells);
29442542f5fSchristos	cells->head.next = &cells->tail;
29542542f5fSchristos	cells->head.covered_height = 0;
29642542f5fSchristos	cells->count = 0;
29742542f5fSchristos}
29842542f5fSchristos
29942542f5fSchristosinline static struct cell *
30042542f5fSchristoscell_list_alloc(struct cell_list *cells,
30142542f5fSchristos		struct cell *tail,
30242542f5fSchristos		int x)
30342542f5fSchristos{
30442542f5fSchristos	struct cell *cell;
30542542f5fSchristos
30642542f5fSchristos	assert(cells->count < cells->size);
30742542f5fSchristos	cell = cells->cells + cells->count++;
30842542f5fSchristos	cell->next = tail->next;
30942542f5fSchristos	tail->next = cell;
31042542f5fSchristos
31142542f5fSchristos	cell->x = x;
31242542f5fSchristos	cell->covered_height = 0;
31342542f5fSchristos	cell->uncovered_area = 0;
31442542f5fSchristos	return cell;
31542542f5fSchristos}
31642542f5fSchristos
31742542f5fSchristos/* Find a cell at the given x-coordinate.  Returns %NULL if a new cell
31842542f5fSchristos * needed to be allocated but couldn't be.  Cells must be found with
31942542f5fSchristos * non-decreasing x-coordinate until the cell list is rewound using
32042542f5fSchristos * cell_list_rewind(). Ownership of the returned cell is retained by
32142542f5fSchristos * the cell list. */
32242542f5fSchristosinline static struct cell *
32342542f5fSchristoscell_list_find(struct cell_list *cells, int x)
32442542f5fSchristos{
32542542f5fSchristos	struct cell *tail;
32642542f5fSchristos
32742542f5fSchristos	if (x >= cells->x2)
32842542f5fSchristos		return &cells->tail;
32942542f5fSchristos
33042542f5fSchristos	if (x < cells->x1)
33142542f5fSchristos		return &cells->head;
33242542f5fSchristos
33342542f5fSchristos	tail = cells->cursor;
33442542f5fSchristos	if (tail->x == x)
33542542f5fSchristos		return tail;
33642542f5fSchristos
33742542f5fSchristos	do {
33842542f5fSchristos		if (tail->next->x > x)
33942542f5fSchristos			break;
34042542f5fSchristos
34142542f5fSchristos		tail = tail->next;
34242542f5fSchristos		if (tail->next->x > x)
34342542f5fSchristos			break;
34442542f5fSchristos
34542542f5fSchristos		tail = tail->next;
34642542f5fSchristos		if (tail->next->x > x)
34742542f5fSchristos			break;
34842542f5fSchristos
34942542f5fSchristos		tail = tail->next;
35042542f5fSchristos	} while (1);
35142542f5fSchristos
35242542f5fSchristos	if (tail->x != x)
35342542f5fSchristos		tail = cell_list_alloc(cells, tail, x);
35442542f5fSchristos
35542542f5fSchristos	return cells->cursor = tail;
35642542f5fSchristos}
35742542f5fSchristos
35842542f5fSchristos/* Add a subpixel span covering [x1, x2) to the coverage cells. */
35942542f5fSchristosinline static void
36042542f5fSchristoscell_list_add_subspan(struct cell_list *cells, int x1, int x2)
36142542f5fSchristos{
36242542f5fSchristos	struct cell *cell;
36342542f5fSchristos	int ix1, fx1;
36442542f5fSchristos	int ix2, fx2;
36542542f5fSchristos
36642542f5fSchristos	if (x1 == x2)
36742542f5fSchristos		return;
36842542f5fSchristos
36942542f5fSchristos	FAST_SAMPLES_X_TO_INT_FRAC(x1, ix1, fx1);
37042542f5fSchristos	FAST_SAMPLES_X_TO_INT_FRAC(x2, ix2, fx2);
37142542f5fSchristos
37242542f5fSchristos	__DBG(("%s: x1=%d (%d+%d), x2=%d (%d+%d)\n", __FUNCTION__,
37342542f5fSchristos	       x1, ix1, fx1, x2, ix2, fx2));
37442542f5fSchristos
37542542f5fSchristos	cell = cell_list_find(cells, ix1);
37642542f5fSchristos	if (ix1 != ix2) {
37713496ba1Ssnj		cell->uncovered_area += fx1;
37842542f5fSchristos		++cell->covered_height;
37942542f5fSchristos
38042542f5fSchristos		cell = cell_list_find(cells, ix2);
38113496ba1Ssnj		cell->uncovered_area -= fx2;
38242542f5fSchristos		--cell->covered_height;
38342542f5fSchristos	} else
38413496ba1Ssnj		cell->uncovered_area += (fx1-fx2);
38542542f5fSchristos}
38642542f5fSchristos
38742542f5fSchristosinline static void
38842542f5fSchristoscell_list_add_span(struct cell_list *cells, int x1, int x2)
38942542f5fSchristos{
39042542f5fSchristos	struct cell *cell;
39142542f5fSchristos	int ix1, fx1;
39242542f5fSchristos	int ix2, fx2;
39342542f5fSchristos
39442542f5fSchristos	FAST_SAMPLES_X_TO_INT_FRAC(x1, ix1, fx1);
39542542f5fSchristos	FAST_SAMPLES_X_TO_INT_FRAC(x2, ix2, fx2);
39642542f5fSchristos
39742542f5fSchristos	__DBG(("%s: x1=%d (%d+%d), x2=%d (%d+%d)\n", __FUNCTION__,
39842542f5fSchristos	       x1, ix1, fx1, x2, ix2, fx2));
39942542f5fSchristos
40042542f5fSchristos	cell = cell_list_find(cells, ix1);
40142542f5fSchristos	if (ix1 != ix2) {
40213496ba1Ssnj		cell->uncovered_area += fx1*FAST_SAMPLES_Y;
40342542f5fSchristos		cell->covered_height += FAST_SAMPLES_Y;
40442542f5fSchristos
40542542f5fSchristos		cell = cell_list_find(cells, ix2);
40613496ba1Ssnj		cell->uncovered_area -= fx2*FAST_SAMPLES_Y;
40742542f5fSchristos		cell->covered_height -= FAST_SAMPLES_Y;
40842542f5fSchristos	} else
40913496ba1Ssnj		cell->uncovered_area += (fx1-fx2)*FAST_SAMPLES_Y;
41042542f5fSchristos}
41142542f5fSchristos
41242542f5fSchristosstatic void
41342542f5fSchristospolygon_fini(struct polygon *polygon)
41442542f5fSchristos{
41542542f5fSchristos	if (polygon->y_buckets != polygon->y_buckets_embedded)
41642542f5fSchristos		free(polygon->y_buckets);
41742542f5fSchristos
41842542f5fSchristos	if (polygon->edges != polygon->edges_embedded)
41942542f5fSchristos		free(polygon->edges);
42042542f5fSchristos}
42142542f5fSchristos
42242542f5fSchristosstatic bool
42342542f5fSchristospolygon_init(struct polygon *polygon, int num_edges, int ymin, int ymax)
42442542f5fSchristos{
42542542f5fSchristos	unsigned num_buckets = EDGE_Y_BUCKET_INDEX(ymax-1, ymin) + 1;
42642542f5fSchristos
42742542f5fSchristos	if (unlikely(ymax - ymin > 0x7FFFFFFFU - EDGE_Y_BUCKET_HEIGHT))
42842542f5fSchristos		return false;
42942542f5fSchristos
43042542f5fSchristos	polygon->edges = polygon->edges_embedded;
43142542f5fSchristos	polygon->y_buckets = polygon->y_buckets_embedded;
43242542f5fSchristos
43342542f5fSchristos	polygon->num_edges = 0;
43442542f5fSchristos	if (num_edges > (int)ARRAY_SIZE(polygon->edges_embedded)) {
43542542f5fSchristos		polygon->edges = malloc(sizeof(struct edge)*num_edges);
43642542f5fSchristos		if (unlikely(NULL == polygon->edges))
43742542f5fSchristos			goto bail_no_mem;
43842542f5fSchristos	}
43942542f5fSchristos
44042542f5fSchristos	if (num_buckets >= ARRAY_SIZE(polygon->y_buckets_embedded)) {
44142542f5fSchristos		polygon->y_buckets = malloc((1+num_buckets)*sizeof(struct edge *));
44242542f5fSchristos		if (unlikely(NULL == polygon->y_buckets))
44342542f5fSchristos			goto bail_no_mem;
44442542f5fSchristos	}
44542542f5fSchristos	memset(polygon->y_buckets, 0, num_buckets * sizeof(struct edge *));
44642542f5fSchristos	polygon->y_buckets[num_buckets] = (void *)-1;
44742542f5fSchristos
44842542f5fSchristos	polygon->ymin = ymin;
44942542f5fSchristos	polygon->ymax = ymax;
45042542f5fSchristos	return true;
45142542f5fSchristos
45242542f5fSchristosbail_no_mem:
45342542f5fSchristos	polygon_fini(polygon);
45442542f5fSchristos	return false;
45542542f5fSchristos}
45642542f5fSchristos
45742542f5fSchristosstatic void
45842542f5fSchristos_polygon_insert_edge_into_its_y_bucket(struct polygon *polygon, struct edge *e)
45942542f5fSchristos{
46042542f5fSchristos	unsigned ix = EDGE_Y_BUCKET_INDEX(e->ytop, polygon->ymin);
46142542f5fSchristos	struct edge **ptail = &polygon->y_buckets[ix];
46242542f5fSchristos	assert(e->ytop < polygon->ymax);
46342542f5fSchristos	e->next = *ptail;
46442542f5fSchristos	*ptail = e;
46542542f5fSchristos}
46642542f5fSchristos
46742542f5fSchristosinline static void
46842542f5fSchristospolygon_add_edge(struct polygon *polygon,
46913496ba1Ssnj		 const xTrapezoid *t,
47013496ba1Ssnj		 const xLineFixed *edge,
47113496ba1Ssnj		 int dir, int dx, int dy)
47242542f5fSchristos{
47342542f5fSchristos	struct edge *e = &polygon->edges[polygon->num_edges];
47442542f5fSchristos	int ytop, ybot;
47542542f5fSchristos
47613496ba1Ssnj	assert(t->bottom > t->top);
47713496ba1Ssnj	assert(edge->p2.y > edge->p1.y);
47813496ba1Ssnj
47942542f5fSchristos	e->dir = dir;
48042542f5fSchristos
48113496ba1Ssnj	ytop = pixman_fixed_to_fast(t->top) + dy;
48213496ba1Ssnj	if (ytop < polygon->ymin)
48313496ba1Ssnj		ytop = polygon->ymin;
48413496ba1Ssnj
48513496ba1Ssnj	ybot = pixman_fixed_to_fast(t->bottom) + dy;
48613496ba1Ssnj	if (ybot > polygon->ymax)
48713496ba1Ssnj		ybot = polygon->ymax;
48813496ba1Ssnj
48942542f5fSchristos	e->ytop = ytop;
49042542f5fSchristos	e->height_left = ybot - ytop;
49142542f5fSchristos	if (e->height_left <= 0)
49242542f5fSchristos		return;
49342542f5fSchristos
49413496ba1Ssnj	if (pixman_fixed_to_fast(edge->p1.x) == pixman_fixed_to_fast(edge->p2.x)) {
49513496ba1Ssnj		e->cell = e->x.quo = pixman_fixed_to_fast(edge->p1.x) + dx;
49642542f5fSchristos		e->x.rem = 0;
49742542f5fSchristos		e->dxdy.quo = 0;
49842542f5fSchristos		e->dxdy.rem = 0;
49913496ba1Ssnj		e->dy = 0;
50042542f5fSchristos	} else {
50113496ba1Ssnj		int64_t Ex, Ey, tmp;
50213496ba1Ssnj
50313496ba1Ssnj		Ex = ((int64_t)edge->p2.x - edge->p1.x) * FAST_SAMPLES_X;
50413496ba1Ssnj		Ey = ((int64_t)edge->p2.y - edge->p1.y) * FAST_SAMPLES_Y * (2 << 16);
50513496ba1Ssnj		assert(Ey > 0);
50613496ba1Ssnj
50713496ba1Ssnj		e->dxdy.quo = Ex * (2 << 16) / Ey;
50813496ba1Ssnj		e->dxdy.rem = Ex * (2 << 16) % Ey;
50913496ba1Ssnj
51013496ba1Ssnj		tmp = (int64_t)(2 * (ytop - dy) + 1) << 16;
51113496ba1Ssnj		tmp -= (int64_t)edge->p1.y * FAST_SAMPLES_Y * 2;
51213496ba1Ssnj		tmp *= Ex;
51313496ba1Ssnj		e->x.quo = tmp / Ey;
51413496ba1Ssnj		e->x.rem = tmp % Ey;
51513496ba1Ssnj
51613496ba1Ssnj		tmp = (int64_t)edge->p1.x * FAST_SAMPLES_X;
51713496ba1Ssnj		e->x.quo += tmp / (1 << 16) + dx;
51813496ba1Ssnj		tmp &= (1 << 16) - 1;
51913496ba1Ssnj		if (tmp) {
52013496ba1Ssnj			if (Ey < INT64_MAX >> 16)
52113496ba1Ssnj				tmp = (tmp * Ey) / (1 << 16);
52213496ba1Ssnj			else /* Handle overflow by losing precision */
52313496ba1Ssnj				tmp = tmp * (Ey / (1 << 16));
52413496ba1Ssnj			e->x.rem += tmp;
52542542f5fSchristos		}
52613496ba1Ssnj
52713496ba1Ssnj		if (e->x.rem < 0) {
52813496ba1Ssnj			--e->x.quo;
52913496ba1Ssnj			e->x.rem += Ey;
53013496ba1Ssnj		} else if (e->x.rem >= Ey) {
53113496ba1Ssnj			++e->x.quo;
53213496ba1Ssnj			e->x.rem -= Ey;
53313496ba1Ssnj		}
53413496ba1Ssnj		assert(e->x.rem >= 0 && e->x.rem < Ey);
53513496ba1Ssnj
53613496ba1Ssnj		e->cell = e->x.quo + (e->x.rem >= Ey/2);
53713496ba1Ssnj		e->dy = Ey;
53842542f5fSchristos	}
53942542f5fSchristos
54042542f5fSchristos	_polygon_insert_edge_into_its_y_bucket(polygon, e);
54142542f5fSchristos	polygon->num_edges++;
54242542f5fSchristos}
54342542f5fSchristos
54442542f5fSchristosinline static void
54542542f5fSchristospolygon_add_line(struct polygon *polygon,
54642542f5fSchristos		 const xPointFixed *p1,
54713496ba1Ssnj		 const xPointFixed *p2,
54813496ba1Ssnj		 int dx, int dy)
54942542f5fSchristos{
55042542f5fSchristos	struct edge *e = &polygon->edges[polygon->num_edges];
55142542f5fSchristos	int top, bot;
55242542f5fSchristos
55313496ba1Ssnj	if (p1->y == p2->y)
55442542f5fSchristos		return;
55542542f5fSchristos
55642542f5fSchristos	__DBG(("%s: line=(%d, %d), (%d, %d)\n",
55742542f5fSchristos	       __FUNCTION__, (int)p1->x, (int)p1->y, (int)p2->x, (int)p2->y));
55842542f5fSchristos
55942542f5fSchristos	e->dir = 1;
56013496ba1Ssnj	if (p2->y < p1->y) {
56142542f5fSchristos		const xPointFixed *t;
56242542f5fSchristos
56342542f5fSchristos		e->dir = -1;
56442542f5fSchristos
56542542f5fSchristos		t = p1;
56642542f5fSchristos		p1 = p2;
56742542f5fSchristos		p2 = t;
56842542f5fSchristos	}
56942542f5fSchristos
57013496ba1Ssnj	top = pixman_fixed_to_fast(p1->y) + dy;
57113496ba1Ssnj	if (top < polygon->ymin)
57213496ba1Ssnj		top = polygon->ymin;
57313496ba1Ssnj
57413496ba1Ssnj	bot = pixman_fixed_to_fast(p2->y) + dy;
57513496ba1Ssnj	if (bot > polygon->ymax)
57613496ba1Ssnj		bot = polygon->ymax;
57713496ba1Ssnj
57842542f5fSchristos	if (bot <= top)
57942542f5fSchristos		return;
58042542f5fSchristos
58142542f5fSchristos	e->ytop = top;
58242542f5fSchristos	e->height_left = bot - top;
58342542f5fSchristos	if (e->height_left <= 0)
58442542f5fSchristos		return;
58542542f5fSchristos
58613496ba1Ssnj	__DBG(("%s: edge height=%d\n", __FUNCTION__, e->dir * e->height_left));
58713496ba1Ssnj
58813496ba1Ssnj	if (pixman_fixed_to_fast(p1->x) == pixman_fixed_to_fast(p2->x)) {
58913496ba1Ssnj		e->cell = e->x.quo = pixman_fixed_to_fast(p1->x) + dx;
59013496ba1Ssnj		e->x.rem = 0;
59142542f5fSchristos		e->dxdy.quo = 0;
59242542f5fSchristos		e->dxdy.rem = 0;
59342542f5fSchristos		e->dy = 0;
59442542f5fSchristos	} else {
59513496ba1Ssnj		int64_t Ex, Ey, tmp;
59613496ba1Ssnj
59713496ba1Ssnj		Ex = ((int64_t)p2->x - p1->x) * FAST_SAMPLES_X;
59813496ba1Ssnj		Ey = ((int64_t)p2->y - p1->y) * FAST_SAMPLES_Y * (2 << 16);
59913496ba1Ssnj
60013496ba1Ssnj		e->dxdy.quo = Ex * (2 << 16) / Ey;
60113496ba1Ssnj		e->dxdy.rem = Ex * (2 << 16) % Ey;
60213496ba1Ssnj
60313496ba1Ssnj		tmp = (int64_t)(2 * (top - dy) + 1) << 16;
60413496ba1Ssnj		tmp -= (int64_t)p1->y * FAST_SAMPLES_Y * 2;
60513496ba1Ssnj		tmp *= Ex;
60613496ba1Ssnj		e->x.quo = tmp / Ey;
60713496ba1Ssnj		e->x.rem = tmp % Ey;
60813496ba1Ssnj
60913496ba1Ssnj		tmp = (int64_t)p1->x * FAST_SAMPLES_X;
61013496ba1Ssnj		e->x.quo += tmp / (1 << 16) + dx;
61113496ba1Ssnj		e->x.rem += ((tmp & ((1 << 16) - 1)) * Ey) / (1 << 16);
61213496ba1Ssnj
61313496ba1Ssnj		if (e->x.rem < 0) {
61413496ba1Ssnj			--e->x.quo;
61513496ba1Ssnj			e->x.rem += Ey;
61613496ba1Ssnj		} else if (e->x.rem >= Ey) {
61713496ba1Ssnj			++e->x.quo;
61813496ba1Ssnj			e->x.rem -= Ey;
61942542f5fSchristos		}
62013496ba1Ssnj
62113496ba1Ssnj		e->cell = e->x.quo + (e->x.rem >= Ey/2);
62213496ba1Ssnj		e->dy = Ey;
62342542f5fSchristos	}
62442542f5fSchristos
62542542f5fSchristos	if (polygon->num_edges > 0) {
62642542f5fSchristos		struct edge *prev = &polygon->edges[polygon->num_edges-1];
62742542f5fSchristos		/* detect degenerate triangles inserted into tristrips */
62842542f5fSchristos		if (e->dir == -prev->dir &&
62942542f5fSchristos		    e->ytop == prev->ytop &&
63042542f5fSchristos		    e->height_left == prev->height_left &&
63142542f5fSchristos		    e->x.quo == prev->x.quo &&
63242542f5fSchristos		    e->x.rem == prev->x.rem &&
63342542f5fSchristos		    e->dxdy.quo == prev->dxdy.quo &&
63442542f5fSchristos		    e->dxdy.rem == prev->dxdy.rem) {
63542542f5fSchristos			unsigned ix = EDGE_Y_BUCKET_INDEX(e->ytop,
63642542f5fSchristos							  polygon->ymin);
63742542f5fSchristos			polygon->y_buckets[ix] = prev->next;
63813496ba1Ssnj			polygon->num_edges--;
63942542f5fSchristos			return;
64042542f5fSchristos		}
64142542f5fSchristos	}
64242542f5fSchristos
64342542f5fSchristos	_polygon_insert_edge_into_its_y_bucket(polygon, e);
64442542f5fSchristos	polygon->num_edges++;
64542542f5fSchristos}
64642542f5fSchristos
64742542f5fSchristosstatic void
64842542f5fSchristosactive_list_reset(struct active_list *active)
64942542f5fSchristos{
65042542f5fSchristos	active->head.height_left = INT_MAX;
65113496ba1Ssnj	active->head.cell = INT_MIN;
65242542f5fSchristos	active->head.dy = 0;
65342542f5fSchristos	active->head.prev = NULL;
65442542f5fSchristos	active->head.next = &active->tail;
65542542f5fSchristos	active->tail.prev = &active->head;
65642542f5fSchristos	active->tail.next = NULL;
65713496ba1Ssnj	active->tail.cell = INT_MAX;
65842542f5fSchristos	active->tail.height_left = INT_MAX;
65942542f5fSchristos	active->tail.dy = 0;
66042542f5fSchristos}
66142542f5fSchristos
66242542f5fSchristosstatic struct edge *
66342542f5fSchristosmerge_sorted_edges(struct edge *head_a, struct edge *head_b)
66442542f5fSchristos{
66542542f5fSchristos	struct edge *head, **next, *prev;
66642542f5fSchristos	int32_t x;
66742542f5fSchristos
66842542f5fSchristos	if (head_b == NULL)
66942542f5fSchristos		return head_a;
67042542f5fSchristos
67142542f5fSchristos	prev = head_a->prev;
67242542f5fSchristos	next = &head;
67313496ba1Ssnj	if (head_a->cell <= head_b->cell) {
67442542f5fSchristos		head = head_a;
67542542f5fSchristos	} else {
67642542f5fSchristos		head = head_b;
67742542f5fSchristos		head_b->prev = prev;
67842542f5fSchristos		goto start_with_b;
67942542f5fSchristos	}
68042542f5fSchristos
68142542f5fSchristos	do {
68213496ba1Ssnj		x = head_b->cell;
68313496ba1Ssnj		while (head_a != NULL && head_a->cell <= x) {
68442542f5fSchristos			prev = head_a;
68542542f5fSchristos			next = &head_a->next;
68642542f5fSchristos			head_a = head_a->next;
68742542f5fSchristos		}
68842542f5fSchristos
68942542f5fSchristos		head_b->prev = prev;
69042542f5fSchristos		*next = head_b;
69142542f5fSchristos		if (head_a == NULL)
69242542f5fSchristos			return head;
69342542f5fSchristos
69442542f5fSchristosstart_with_b:
69513496ba1Ssnj		x = head_a->cell;
69613496ba1Ssnj		while (head_b != NULL && head_b->cell <= x) {
69742542f5fSchristos			prev = head_b;
69842542f5fSchristos			next = &head_b->next;
69942542f5fSchristos			head_b = head_b->next;
70042542f5fSchristos		}
70142542f5fSchristos
70242542f5fSchristos		head_a->prev = prev;
70342542f5fSchristos		*next = head_a;
70442542f5fSchristos		if (head_b == NULL)
70542542f5fSchristos			return head;
70642542f5fSchristos	} while (1);
70742542f5fSchristos}
70842542f5fSchristos
70942542f5fSchristosstatic struct edge *
71042542f5fSchristossort_edges(struct edge  *list,
71142542f5fSchristos	   unsigned int  level,
71242542f5fSchristos	   struct edge **head_out)
71342542f5fSchristos{
71442542f5fSchristos	struct edge *head_other, *remaining;
71542542f5fSchristos	unsigned int i;
71642542f5fSchristos
71742542f5fSchristos	head_other = list->next;
71842542f5fSchristos	if (head_other == NULL) {
71942542f5fSchristos		*head_out = list;
72042542f5fSchristos		return NULL;
72142542f5fSchristos	}
72242542f5fSchristos
72342542f5fSchristos	remaining = head_other->next;
72413496ba1Ssnj	if (list->cell <= head_other->cell) {
72542542f5fSchristos		*head_out = list;
72642542f5fSchristos		head_other->next = NULL;
72742542f5fSchristos	} else {
72842542f5fSchristos		*head_out = head_other;
72942542f5fSchristos		head_other->prev = list->prev;
73042542f5fSchristos		head_other->next = list;
73142542f5fSchristos		list->prev = head_other;
73242542f5fSchristos		list->next = NULL;
73342542f5fSchristos	}
73442542f5fSchristos
73542542f5fSchristos	for (i = 0; i < level && remaining; i++) {
73642542f5fSchristos		remaining = sort_edges(remaining, i, &head_other);
73742542f5fSchristos		*head_out = merge_sorted_edges(*head_out, head_other);
73842542f5fSchristos	}
73942542f5fSchristos
74042542f5fSchristos	return remaining;
74142542f5fSchristos}
74242542f5fSchristos
74342542f5fSchristosstatic struct edge *filter(struct edge *edges)
74442542f5fSchristos{
74542542f5fSchristos	struct edge *e;
74642542f5fSchristos
74742542f5fSchristos	e = edges;
74813496ba1Ssnj	while (e->next) {
74942542f5fSchristos		struct edge *n = e->next;
75042542f5fSchristos		if (e->dir == -n->dir &&
75142542f5fSchristos		    e->height_left == n->height_left &&
75213496ba1Ssnj		    &e->x.quo == &n->x.quo &&
75313496ba1Ssnj		    &e->x.rem == &n->x.rem &&
75413496ba1Ssnj		    &e->dxdy.quo == &n->dxdy.quo &&
75513496ba1Ssnj		    &e->dxdy.rem == &n->dxdy.rem) {
75642542f5fSchristos			if (e->prev)
75742542f5fSchristos				e->prev->next = n->next;
75842542f5fSchristos			else
75942542f5fSchristos				edges = n->next;
76042542f5fSchristos			if (n->next)
76142542f5fSchristos				n->next->prev = e->prev;
76242542f5fSchristos			else
76342542f5fSchristos				break;
76442542f5fSchristos			e = n->next;
76542542f5fSchristos		} else
76613496ba1Ssnj			e = n;
76713496ba1Ssnj	}
76842542f5fSchristos
76942542f5fSchristos	return edges;
77042542f5fSchristos}
77142542f5fSchristos
77242542f5fSchristosstatic struct edge *
77342542f5fSchristosmerge_unsorted_edges(struct edge *head, struct edge *unsorted)
77442542f5fSchristos{
77542542f5fSchristos	sort_edges(unsorted, UINT_MAX, &unsorted);
77642542f5fSchristos	return merge_sorted_edges(head, filter(unsorted));
77742542f5fSchristos}
77842542f5fSchristos
77942542f5fSchristos/* Test if the edges on the active list can be safely advanced by a
78042542f5fSchristos * full row without intersections or any edges ending. */
78142542f5fSchristosinline static int
78242542f5fSchristoscan_full_step(struct active_list *active)
78342542f5fSchristos{
78442542f5fSchristos	const struct edge *e;
78542542f5fSchristos	int min_height = INT_MAX;
78642542f5fSchristos
78742542f5fSchristos	assert(active->head.next != &active->tail);
78842542f5fSchristos	for (e = active->head.next; &active->tail != e; e = e->next) {
78942542f5fSchristos		assert(e->height_left > 0);
79042542f5fSchristos
79142542f5fSchristos		if (e->dy != 0)
79242542f5fSchristos			return 0;
79342542f5fSchristos
79442542f5fSchristos		if (e->height_left < min_height) {
79542542f5fSchristos			min_height = e->height_left;
79642542f5fSchristos			if (min_height < FAST_SAMPLES_Y)
79742542f5fSchristos				return 0;
79842542f5fSchristos		}
79942542f5fSchristos	}
80042542f5fSchristos
80142542f5fSchristos	return min_height;
80242542f5fSchristos}
80342542f5fSchristos
80442542f5fSchristosinline static void
80542542f5fSchristosmerge_edges(struct active_list *active, struct edge *edges)
80642542f5fSchristos{
80742542f5fSchristos	active->head.next = merge_unsorted_edges(active->head.next, edges);
80842542f5fSchristos}
80942542f5fSchristos
81013496ba1Ssnjinline static int
81142542f5fSchristosfill_buckets(struct active_list *active,
81242542f5fSchristos	     struct edge *edge,
81342542f5fSchristos	     struct edge **buckets)
81442542f5fSchristos{
81513496ba1Ssnj	int ymax = 0;
81613496ba1Ssnj
81742542f5fSchristos	while (edge) {
81813496ba1Ssnj		int y = edge->ytop & (FAST_SAMPLES_Y-1);
81942542f5fSchristos		struct edge *next = edge->next;
82013496ba1Ssnj		struct edge **b = &buckets[y];
82113496ba1Ssnj		__DBG(("%s: ytop %d -> bucket %d\n", __FUNCTION__,
82213496ba1Ssnj		       edge->ytop, y));
82342542f5fSchristos		if (*b)
82442542f5fSchristos			(*b)->prev = edge;
82542542f5fSchristos		edge->next = *b;
82642542f5fSchristos		edge->prev = NULL;
82742542f5fSchristos		*b = edge;
82842542f5fSchristos		edge = next;
82913496ba1Ssnj		if (y > ymax)
83013496ba1Ssnj			ymax = y;
83142542f5fSchristos	}
83213496ba1Ssnj
83313496ba1Ssnj	return ymax;
83442542f5fSchristos}
83542542f5fSchristos
83642542f5fSchristosinline static void
83742542f5fSchristosnonzero_subrow(struct active_list *active, struct cell_list *coverages)
83842542f5fSchristos{
83942542f5fSchristos	struct edge *edge = active->head.next;
84042542f5fSchristos	int prev_x = INT_MIN;
84113496ba1Ssnj	int winding = 0, xstart = edge->cell;
84242542f5fSchristos
84342542f5fSchristos	cell_list_rewind(coverages);
84442542f5fSchristos
84542542f5fSchristos	while (&active->tail != edge) {
84642542f5fSchristos		struct edge *next = edge->next;
84742542f5fSchristos
84842542f5fSchristos		winding += edge->dir;
84913496ba1Ssnj		if (0 == winding && edge->next->cell != edge->cell) {
85013496ba1Ssnj			cell_list_add_subspan(coverages, xstart, edge->cell);
85113496ba1Ssnj			xstart = edge->next->cell;
85242542f5fSchristos		}
85342542f5fSchristos
85442542f5fSchristos		assert(edge->height_left > 0);
85542542f5fSchristos		if (--edge->height_left) {
85642542f5fSchristos			if (edge->dy) {
85742542f5fSchristos				edge->x.quo += edge->dxdy.quo;
85842542f5fSchristos				edge->x.rem += edge->dxdy.rem;
85913496ba1Ssnj				if (edge->x.rem < 0) {
86013496ba1Ssnj					--edge->x.quo;
86113496ba1Ssnj					edge->x.rem += edge->dy;
86213496ba1Ssnj				} else if (edge->x.rem >= edge->dy) {
86342542f5fSchristos					++edge->x.quo;
86442542f5fSchristos					edge->x.rem -= edge->dy;
86542542f5fSchristos				}
86613496ba1Ssnj				edge->cell = edge->x.quo + (edge->x.rem >= edge->dy/2);
86742542f5fSchristos			}
86842542f5fSchristos
86913496ba1Ssnj			if (edge->cell < prev_x) {
87042542f5fSchristos				struct edge *pos = edge->prev;
87142542f5fSchristos				pos->next = next;
87242542f5fSchristos				next->prev = pos;
87313496ba1Ssnj				do
87442542f5fSchristos					pos = pos->prev;
87513496ba1Ssnj				while (edge->cell < pos->cell);
87642542f5fSchristos				pos->next->prev = edge;
87742542f5fSchristos				edge->next = pos->next;
87842542f5fSchristos				edge->prev = pos;
87942542f5fSchristos				pos->next = edge;
88042542f5fSchristos			} else
88113496ba1Ssnj				prev_x = edge->cell;
88242542f5fSchristos		} else {
88342542f5fSchristos			edge->prev->next = next;
88442542f5fSchristos			next->prev = edge->prev;
88542542f5fSchristos		}
88642542f5fSchristos
88742542f5fSchristos		edge = next;
88842542f5fSchristos	}
88942542f5fSchristos}
89042542f5fSchristos
89142542f5fSchristosstatic void
89242542f5fSchristosnonzero_row(struct active_list *active, struct cell_list *coverages)
89342542f5fSchristos{
89442542f5fSchristos	struct edge *left = active->head.next;
89542542f5fSchristos
89642542f5fSchristos	while (&active->tail != left) {
89742542f5fSchristos		struct edge *right;
89842542f5fSchristos		int winding = left->dir;
89942542f5fSchristos
90042542f5fSchristos		left->height_left -= FAST_SAMPLES_Y;
90142542f5fSchristos		assert(left->height_left >= 0);
90242542f5fSchristos		if (!left->height_left) {
90342542f5fSchristos			left->prev->next = left->next;
90442542f5fSchristos			left->next->prev = left->prev;
90542542f5fSchristos		}
90642542f5fSchristos
90742542f5fSchristos		right = left->next;
90842542f5fSchristos		do {
90942542f5fSchristos			right->height_left -= FAST_SAMPLES_Y;
91042542f5fSchristos			assert(right->height_left >= 0);
91142542f5fSchristos			if (!right->height_left) {
91242542f5fSchristos				right->prev->next = right->next;
91342542f5fSchristos				right->next->prev = right->prev;
91442542f5fSchristos			}
91542542f5fSchristos
91642542f5fSchristos			winding += right->dir;
91742542f5fSchristos			if (0 == winding)
91842542f5fSchristos				break;
91942542f5fSchristos
92042542f5fSchristos			right = right->next;
92142542f5fSchristos		} while (1);
92242542f5fSchristos
92313496ba1Ssnj		cell_list_add_span(coverages, left->cell, right->cell);
92442542f5fSchristos		left = right->next;
92542542f5fSchristos	}
92642542f5fSchristos}
92742542f5fSchristos
92842542f5fSchristosstatic void
92942542f5fSchristostor_fini(struct tor *converter)
93042542f5fSchristos{
93142542f5fSchristos	polygon_fini(converter->polygon);
93242542f5fSchristos	cell_list_fini(converter->coverages);
93342542f5fSchristos}
93442542f5fSchristos
93542542f5fSchristosstatic bool
93642542f5fSchristostor_init(struct tor *converter, const BoxRec *box, int num_edges)
93742542f5fSchristos{
93842542f5fSchristos	__DBG(("%s: (%d, %d),(%d, %d) x (%d, %d), num_edges=%d\n",
93942542f5fSchristos	       __FUNCTION__,
94042542f5fSchristos	       box->x1, box->y1, box->x2, box->y2,
94142542f5fSchristos	       FAST_SAMPLES_X, FAST_SAMPLES_Y,
94242542f5fSchristos	       num_edges));
94342542f5fSchristos
94442542f5fSchristos	converter->extents = *box;
94542542f5fSchristos
94642542f5fSchristos	if (!cell_list_init(converter->coverages, box->x1, box->x2))
94742542f5fSchristos		return false;
94842542f5fSchristos
94942542f5fSchristos	active_list_reset(converter->active);
95042542f5fSchristos	if (!polygon_init(converter->polygon, num_edges,
95142542f5fSchristos			  (int)box->y1 * FAST_SAMPLES_Y,
95242542f5fSchristos			  (int)box->y2 * FAST_SAMPLES_Y)) {
95342542f5fSchristos		cell_list_fini(converter->coverages);
95442542f5fSchristos		return false;
95542542f5fSchristos	}
95642542f5fSchristos
95742542f5fSchristos	return true;
95842542f5fSchristos}
95942542f5fSchristos
96042542f5fSchristosstatic void
96113496ba1Ssnjtor_add_trapezoid(struct tor *tor,
96213496ba1Ssnj		  const xTrapezoid *t,
96313496ba1Ssnj		  int dx, int dy)
96442542f5fSchristos{
965fe8aea9eSmrg	if (!xTrapezoidValid(t)) {
966fe8aea9eSmrg		__DBG(("%s: skipping invalid trapezoid: top=%d, bottom=%d, left=(%d, %d), (%d, %d), right=(%d, %d), (%d, %d)\n",
967fe8aea9eSmrg		       __FUNCTION__,
968fe8aea9eSmrg		       t->top, t->bottom,
969fe8aea9eSmrg		       t->left.p1.x, t->left.p1.y,
970fe8aea9eSmrg		       t->left.p2.x, t->left.p2.y,
971fe8aea9eSmrg		       t->right.p1.x, t->right.p1.y,
972fe8aea9eSmrg		       t->right.p2.x, t->right.p2.y));
973fe8aea9eSmrg		return;
974fe8aea9eSmrg	}
97513496ba1Ssnj	polygon_add_edge(tor->polygon, t, &t->left, 1, dx, dy);
97613496ba1Ssnj	polygon_add_edge(tor->polygon, t, &t->right, -1, dx, dy);
97742542f5fSchristos}
97842542f5fSchristos
97942542f5fSchristosstatic void
98042542f5fSchristosstep_edges(struct active_list *active, int count)
98142542f5fSchristos{
98242542f5fSchristos	struct edge *edge;
98342542f5fSchristos
98442542f5fSchristos	count *= FAST_SAMPLES_Y;
98542542f5fSchristos	for (edge = active->head.next; edge != &active->tail; edge = edge->next) {
98642542f5fSchristos		edge->height_left -= count;
98742542f5fSchristos		assert(edge->height_left >= 0);
98842542f5fSchristos		if (!edge->height_left) {
98942542f5fSchristos			edge->prev->next = edge->next;
99042542f5fSchristos			edge->next->prev = edge->prev;
99142542f5fSchristos		}
99242542f5fSchristos	}
99342542f5fSchristos}
99442542f5fSchristos
99542542f5fSchristosstatic void
99642542f5fSchristostor_blt_span(struct sna *sna,
99742542f5fSchristos	     struct sna_composite_spans_op *op,
99842542f5fSchristos	     pixman_region16_t *clip,
99942542f5fSchristos	     const BoxRec *box,
100042542f5fSchristos	     int coverage)
100142542f5fSchristos{
100242542f5fSchristos	__DBG(("%s: %d -> %d @ %d\n", __FUNCTION__, box->x1, box->x2, coverage));
100342542f5fSchristos
100442542f5fSchristos	op->box(sna, op, box, AREA_TO_ALPHA(coverage));
100542542f5fSchristos	apply_damage_box(&op->base, box);
100642542f5fSchristos}
100742542f5fSchristos
100842542f5fSchristosstatic void
100942542f5fSchristostor_blt_span__no_damage(struct sna *sna,
101042542f5fSchristos			struct sna_composite_spans_op *op,
101142542f5fSchristos			pixman_region16_t *clip,
101242542f5fSchristos			const BoxRec *box,
101342542f5fSchristos			int coverage)
101442542f5fSchristos{
101542542f5fSchristos	__DBG(("%s: %d -> %d @ %d\n", __FUNCTION__, box->x1, box->x2, coverage));
101642542f5fSchristos
101742542f5fSchristos	op->box(sna, op, box, AREA_TO_ALPHA(coverage));
101842542f5fSchristos}
101942542f5fSchristos
102042542f5fSchristosstatic void
102142542f5fSchristostor_blt_span_clipped(struct sna *sna,
102242542f5fSchristos		     struct sna_composite_spans_op *op,
102342542f5fSchristos		     pixman_region16_t *clip,
102442542f5fSchristos		     const BoxRec *box,
102542542f5fSchristos		     int coverage)
102642542f5fSchristos{
102742542f5fSchristos	pixman_region16_t region;
102842542f5fSchristos	float opacity;
102942542f5fSchristos
103042542f5fSchristos	opacity = AREA_TO_ALPHA(coverage);
103142542f5fSchristos	__DBG(("%s: %d -> %d @ %f\n", __FUNCTION__, box->x1, box->x2, opacity));
103242542f5fSchristos
103342542f5fSchristos	pixman_region_init_rects(&region, box, 1);
103442542f5fSchristos	RegionIntersect(&region, &region, clip);
103542542f5fSchristos	if (region_num_rects(&region)) {
103642542f5fSchristos		op->boxes(sna, op,
103742542f5fSchristos			  region_rects(&region),
103842542f5fSchristos			  region_num_rects(&region),
103942542f5fSchristos			  opacity);
104042542f5fSchristos		apply_damage(&op->base, &region);
104142542f5fSchristos	}
104242542f5fSchristos	pixman_region_fini(&region);
104342542f5fSchristos}
104442542f5fSchristos
104542542f5fSchristosstatic void
104642542f5fSchristostor_blt_span_mono(struct sna *sna,
104742542f5fSchristos		  struct sna_composite_spans_op *op,
104842542f5fSchristos		  pixman_region16_t *clip,
104942542f5fSchristos		  const BoxRec *box,
105042542f5fSchristos		  int coverage)
105142542f5fSchristos{
105242542f5fSchristos	if (coverage < FAST_SAMPLES_XY/2)
105342542f5fSchristos		return;
105442542f5fSchristos
105542542f5fSchristos	tor_blt_span(sna, op, clip, box, FAST_SAMPLES_XY);
105642542f5fSchristos}
105742542f5fSchristos
105842542f5fSchristosstatic void
105942542f5fSchristostor_blt_span_mono_clipped(struct sna *sna,
106042542f5fSchristos			  struct sna_composite_spans_op *op,
106142542f5fSchristos			  pixman_region16_t *clip,
106242542f5fSchristos			  const BoxRec *box,
106342542f5fSchristos			  int coverage)
106442542f5fSchristos{
106542542f5fSchristos	if (coverage < FAST_SAMPLES_XY/2)
106642542f5fSchristos		return;
106742542f5fSchristos
106842542f5fSchristos	tor_blt_span_clipped(sna, op, clip, box, FAST_SAMPLES_XY);
106942542f5fSchristos}
107042542f5fSchristos
107142542f5fSchristosstatic void
107242542f5fSchristostor_blt_span_mono_unbounded(struct sna *sna,
107342542f5fSchristos			    struct sna_composite_spans_op *op,
107442542f5fSchristos			    pixman_region16_t *clip,
107542542f5fSchristos			    const BoxRec *box,
107642542f5fSchristos			    int coverage)
107742542f5fSchristos{
107842542f5fSchristos	tor_blt_span(sna, op, clip, box,
107942542f5fSchristos		     coverage < FAST_SAMPLES_XY/2 ? 0 : FAST_SAMPLES_XY);
108042542f5fSchristos}
108142542f5fSchristos
108242542f5fSchristosstatic void
108342542f5fSchristostor_blt_span_mono_unbounded_clipped(struct sna *sna,
108442542f5fSchristos				    struct sna_composite_spans_op *op,
108542542f5fSchristos				    pixman_region16_t *clip,
108642542f5fSchristos				    const BoxRec *box,
108742542f5fSchristos				    int coverage)
108842542f5fSchristos{
108942542f5fSchristos	tor_blt_span_clipped(sna, op, clip, box,
109042542f5fSchristos			     coverage < FAST_SAMPLES_XY/2 ? 0 : FAST_SAMPLES_XY);
109142542f5fSchristos}
109242542f5fSchristos
109342542f5fSchristosstatic void
109442542f5fSchristostor_blt(struct sna *sna,
109542542f5fSchristos	struct tor *converter,
109642542f5fSchristos	struct sna_composite_spans_op *op,
109742542f5fSchristos	pixman_region16_t *clip,
109842542f5fSchristos	void (*span)(struct sna *sna,
109942542f5fSchristos		     struct sna_composite_spans_op *op,
110042542f5fSchristos		     pixman_region16_t *clip,
110142542f5fSchristos		     const BoxRec *box,
110242542f5fSchristos		     int coverage),
110342542f5fSchristos	int y, int height,
110442542f5fSchristos	int unbounded)
110542542f5fSchristos{
110642542f5fSchristos	struct cell_list *cells = converter->coverages;
110742542f5fSchristos	struct cell *cell;
110842542f5fSchristos	BoxRec box;
110942542f5fSchristos	int cover;
111042542f5fSchristos
111142542f5fSchristos	box.y1 = y + converter->extents.y1;
111242542f5fSchristos	box.y2 = box.y1 + height;
111342542f5fSchristos	assert(box.y2 <= converter->extents.y2);
111442542f5fSchristos	box.x1 = converter->extents.x1;
111542542f5fSchristos
111642542f5fSchristos	/* Form the spans from the coverages and areas. */
111713496ba1Ssnj	cover = cells->head.covered_height*FAST_SAMPLES_X;
111842542f5fSchristos	assert(cover >= 0);
111942542f5fSchristos	for (cell = cells->head.next; cell != &cells->tail; cell = cell->next) {
112042542f5fSchristos		int x = cell->x;
112142542f5fSchristos
112242542f5fSchristos		assert(x >= converter->extents.x1);
112342542f5fSchristos		assert(x < converter->extents.x2);
112413496ba1Ssnj		__DBG(("%s: cell=(%d, %d, %d), cover=%d\n", __FUNCTION__,
112542542f5fSchristos		       cell->x, cell->covered_height, cell->uncovered_area,
112613496ba1Ssnj		       cover));
112742542f5fSchristos
112842542f5fSchristos		if (cell->covered_height || cell->uncovered_area) {
112942542f5fSchristos			box.x2 = x;
113042542f5fSchristos			if (box.x2 > box.x1 && (unbounded || cover)) {
113142542f5fSchristos				__DBG(("%s: span (%d, %d)x(%d, %d) @ %d\n", __FUNCTION__,
113242542f5fSchristos				       box.x1, box.y1,
113342542f5fSchristos				       box.x2 - box.x1,
113442542f5fSchristos				       box.y2 - box.y1,
113542542f5fSchristos				       cover));
113642542f5fSchristos				span(sna, op, clip, &box, cover);
113742542f5fSchristos			}
113842542f5fSchristos			box.x1 = box.x2;
113913496ba1Ssnj			cover += cell->covered_height*FAST_SAMPLES_X;
114042542f5fSchristos		}
114142542f5fSchristos
114242542f5fSchristos		if (cell->uncovered_area) {
114342542f5fSchristos			int area = cover - cell->uncovered_area;
114442542f5fSchristos			box.x2 = x + 1;
114542542f5fSchristos			if (unbounded || area) {
114642542f5fSchristos				__DBG(("%s: span (%d, %d)x(%d, %d) @ %d\n", __FUNCTION__,
114742542f5fSchristos				       box.x1, box.y1,
114842542f5fSchristos				       box.x2 - box.x1,
114942542f5fSchristos				       box.y2 - box.y1,
115042542f5fSchristos				       area));
115142542f5fSchristos				span(sna, op, clip, &box, area);
115242542f5fSchristos			}
115342542f5fSchristos			box.x1 = box.x2;
115442542f5fSchristos		}
115542542f5fSchristos	}
115642542f5fSchristos
115742542f5fSchristos	box.x2 = converter->extents.x2;
115842542f5fSchristos	if (box.x2 > box.x1 && (unbounded || cover)) {
115942542f5fSchristos		__DBG(("%s: span (%d, %d)x(%d, %d) @ %d\n", __FUNCTION__,
116042542f5fSchristos		       box.x1, box.y1,
116142542f5fSchristos		       box.x2 - box.x1,
116242542f5fSchristos		       box.y2 - box.y1,
116342542f5fSchristos		       cover));
116442542f5fSchristos		span(sna, op, clip, &box, cover);
116542542f5fSchristos	}
116642542f5fSchristos}
116742542f5fSchristos
116842542f5fSchristosflatten static void
116942542f5fSchristostor_render(struct sna *sna,
117042542f5fSchristos	   struct tor *converter,
117142542f5fSchristos	   struct sna_composite_spans_op *op,
117242542f5fSchristos	   pixman_region16_t *clip,
117342542f5fSchristos	   void (*span)(struct sna *sna,
117442542f5fSchristos			struct sna_composite_spans_op *op,
117542542f5fSchristos			pixman_region16_t *clip,
117642542f5fSchristos			const BoxRec *box,
117742542f5fSchristos			int coverage),
117842542f5fSchristos	   int unbounded)
117942542f5fSchristos{
118042542f5fSchristos	struct polygon *polygon = converter->polygon;
118142542f5fSchristos	struct cell_list *coverages = converter->coverages;
118242542f5fSchristos	struct active_list *active = converter->active;
118342542f5fSchristos	struct edge *buckets[FAST_SAMPLES_Y] = { 0 };
118442542f5fSchristos	int16_t i, j, h = converter->extents.y2 - converter->extents.y1;
118542542f5fSchristos
118642542f5fSchristos	__DBG(("%s: unbounded=%d\n", __FUNCTION__, unbounded));
118742542f5fSchristos
118842542f5fSchristos	/* Render each pixel row. */
118942542f5fSchristos	for (i = 0; i < h; i = j) {
119042542f5fSchristos		int do_full_step = 0;
119142542f5fSchristos
119242542f5fSchristos		j = i + 1;
119342542f5fSchristos
119442542f5fSchristos		/* Determine if we can ignore this row or use the full pixel
119542542f5fSchristos		 * stepper. */
119613496ba1Ssnj		if (fill_buckets(active, polygon->y_buckets[i], buckets) == 0) {
119713496ba1Ssnj			if (buckets[0]) {
119813496ba1Ssnj				merge_edges(active, buckets[0]);
119913496ba1Ssnj				buckets[0] = NULL;
120013496ba1Ssnj			}
120142542f5fSchristos			if (active->head.next == &active->tail) {
120242542f5fSchristos				for (; polygon->y_buckets[j] == NULL; j++)
120342542f5fSchristos					;
120442542f5fSchristos				__DBG(("%s: no new edges and no exisiting edges, skipping, %d -> %d\n",
120542542f5fSchristos				       __FUNCTION__, i, j));
120642542f5fSchristos
120742542f5fSchristos				assert(j <= h);
120842542f5fSchristos				if (unbounded) {
120942542f5fSchristos					BoxRec box;
121042542f5fSchristos
121142542f5fSchristos					box = converter->extents;
121242542f5fSchristos					box.y1 += i;
121342542f5fSchristos					box.y2 = converter->extents.y1 + j;
121442542f5fSchristos
121542542f5fSchristos					span(sna, op, clip, &box, 0);
121642542f5fSchristos				}
121742542f5fSchristos				continue;
121842542f5fSchristos			}
121942542f5fSchristos
122042542f5fSchristos			do_full_step = can_full_step(active);
122142542f5fSchristos		}
122242542f5fSchristos
122313496ba1Ssnj		__DBG(("%s: y=%d-%d, do_full_step=%d, new edges=%d\n",
122442542f5fSchristos		       __FUNCTION__,
122513496ba1Ssnj		       i, j, do_full_step,
122642542f5fSchristos		       polygon->y_buckets[i] != NULL));
122742542f5fSchristos		if (do_full_step) {
122842542f5fSchristos			nonzero_row(active, coverages);
122942542f5fSchristos
123042542f5fSchristos			while (polygon->y_buckets[j] == NULL &&
123142542f5fSchristos			       do_full_step >= 2*FAST_SAMPLES_Y) {
123242542f5fSchristos				do_full_step -= FAST_SAMPLES_Y;
123342542f5fSchristos				j++;
123442542f5fSchristos			}
123542542f5fSchristos			assert(j >= i + 1 && j <= h);
123642542f5fSchristos			if (j != i + 1)
123742542f5fSchristos				step_edges(active, j - (i + 1));
123842542f5fSchristos
123942542f5fSchristos			__DBG(("%s: vertical edges, full step (%d, %d)\n",
124042542f5fSchristos			       __FUNCTION__,  i, j));
124142542f5fSchristos		} else {
124242542f5fSchristos			int suby;
124342542f5fSchristos
124442542f5fSchristos			/* Subsample this row. */
124542542f5fSchristos			for (suby = 0; suby < FAST_SAMPLES_Y; suby++) {
124642542f5fSchristos				if (buckets[suby]) {
124742542f5fSchristos					merge_edges(active, buckets[suby]);
124842542f5fSchristos					buckets[suby] = NULL;
124942542f5fSchristos				}
125042542f5fSchristos
125142542f5fSchristos				nonzero_subrow(active, coverages);
125242542f5fSchristos			}
125342542f5fSchristos		}
125442542f5fSchristos
125542542f5fSchristos		assert(j > i);
125642542f5fSchristos		tor_blt(sna, converter, op, clip, span, i, j-i, unbounded);
125742542f5fSchristos		cell_list_reset(coverages);
125842542f5fSchristos	}
125942542f5fSchristos}
126042542f5fSchristos
126142542f5fSchristosstatic void
126242542f5fSchristosinplace_row(struct active_list *active, uint8_t *row, int width)
126342542f5fSchristos{
126442542f5fSchristos	struct edge *left = active->head.next;
126542542f5fSchristos
126642542f5fSchristos	while (&active->tail != left) {
126742542f5fSchristos		struct edge *right;
126842542f5fSchristos		int winding = left->dir;
126942542f5fSchristos		int lfx, rfx;
127042542f5fSchristos		int lix, rix;
127142542f5fSchristos
127242542f5fSchristos		left->height_left -= FAST_SAMPLES_Y;
127342542f5fSchristos		assert(left->height_left >= 0);
127442542f5fSchristos		if (!left->height_left) {
127542542f5fSchristos			left->prev->next = left->next;
127642542f5fSchristos			left->next->prev = left->prev;
127742542f5fSchristos		}
127842542f5fSchristos
127942542f5fSchristos		right = left->next;
128042542f5fSchristos		do {
128142542f5fSchristos			right->height_left -= FAST_SAMPLES_Y;
128242542f5fSchristos			assert(right->height_left >= 0);
128342542f5fSchristos			if (!right->height_left) {
128442542f5fSchristos				right->prev->next = right->next;
128542542f5fSchristos				right->next->prev = right->prev;
128642542f5fSchristos			}
128742542f5fSchristos
128842542f5fSchristos			winding += right->dir;
128913496ba1Ssnj			if (0 == winding && right->cell != right->next->cell)
129042542f5fSchristos				break;
129142542f5fSchristos
129242542f5fSchristos			right = right->next;
129342542f5fSchristos		} while (1);
129442542f5fSchristos
129513496ba1Ssnj		if (left->cell < 0) {
129642542f5fSchristos			lix = lfx = 0;
129713496ba1Ssnj		} else if (left->cell >= width * FAST_SAMPLES_X) {
129842542f5fSchristos			lix = width;
129942542f5fSchristos			lfx = 0;
130042542f5fSchristos		} else
130113496ba1Ssnj			FAST_SAMPLES_X_TO_INT_FRAC(left->cell, lix, lfx);
130242542f5fSchristos
130313496ba1Ssnj		if (right->cell < 0) {
130442542f5fSchristos			rix = rfx = 0;
130513496ba1Ssnj		} else if (right->cell >= width * FAST_SAMPLES_X) {
130642542f5fSchristos			rix = width;
130742542f5fSchristos			rfx = 0;
130842542f5fSchristos		} else
130913496ba1Ssnj			FAST_SAMPLES_X_TO_INT_FRAC(right->cell, rix, rfx);
131042542f5fSchristos		if (lix == rix) {
131142542f5fSchristos			if (rfx != lfx) {
131242542f5fSchristos				assert(lix < width);
131342542f5fSchristos				row[lix] += (rfx-lfx) * 256 / FAST_SAMPLES_X;
131442542f5fSchristos			}
131542542f5fSchristos		} else {
131642542f5fSchristos			assert(lix < width);
131742542f5fSchristos			if (lfx == 0)
131842542f5fSchristos				row[lix] = 0xff;
131942542f5fSchristos			else
132042542f5fSchristos				row[lix] += 256 - lfx * 256 / FAST_SAMPLES_X;
132142542f5fSchristos
132242542f5fSchristos			assert(rix <= width);
132342542f5fSchristos			if (rfx) {
132442542f5fSchristos				assert(rix < width);
132542542f5fSchristos				row[rix] += rfx * 256 / FAST_SAMPLES_X;
132642542f5fSchristos			}
132742542f5fSchristos
132842542f5fSchristos			if (rix > ++lix) {
132942542f5fSchristos				uint8_t *r = row + lix;
133042542f5fSchristos				rix -= lix;
133142542f5fSchristos#if 0
133242542f5fSchristos				if (rix == 1)
133342542f5fSchristos					*row = 0xff;
133442542f5fSchristos				else
133542542f5fSchristos					memset(row, 0xff, rix);
133642542f5fSchristos#else
133742542f5fSchristos				if ((uintptr_t)r & 1 && rix) {
133842542f5fSchristos					*r++ = 0xff;
133942542f5fSchristos					rix--;
134042542f5fSchristos				}
134142542f5fSchristos				if ((uintptr_t)r & 2 && rix >= 2) {
134242542f5fSchristos					*(uint16_t *)r = 0xffff;
134342542f5fSchristos					r += 2;
134442542f5fSchristos					rix -= 2;
134542542f5fSchristos				}
134642542f5fSchristos				if ((uintptr_t)r & 4 && rix >= 4) {
134742542f5fSchristos					*(uint32_t *)r = 0xffffffff;
134842542f5fSchristos					r += 4;
134942542f5fSchristos					rix -= 4;
135042542f5fSchristos				}
135142542f5fSchristos				while (rix >= 8) {
135242542f5fSchristos					*(uint64_t *)r = 0xffffffffffffffff;
135342542f5fSchristos					r += 8;
135442542f5fSchristos					rix -= 8;
135542542f5fSchristos				}
135642542f5fSchristos				if (rix & 4) {
135742542f5fSchristos					*(uint32_t *)r = 0xffffffff;
135842542f5fSchristos					r += 4;
135942542f5fSchristos				}
136042542f5fSchristos				if (rix & 2) {
136142542f5fSchristos					*(uint16_t *)r = 0xffff;
136242542f5fSchristos					r += 2;
136342542f5fSchristos				}
136442542f5fSchristos				if (rix & 1)
136542542f5fSchristos					*r = 0xff;
136642542f5fSchristos#endif
136742542f5fSchristos			}
136842542f5fSchristos		}
136942542f5fSchristos
137042542f5fSchristos		left = right->next;
137142542f5fSchristos	}
137242542f5fSchristos}
137342542f5fSchristos
137442542f5fSchristosinline static void
137542542f5fSchristosinplace_subrow(struct active_list *active, int8_t *row,
137642542f5fSchristos	       int width, int *min, int *max)
137742542f5fSchristos{
137842542f5fSchristos	struct edge *edge = active->head.next;
137942542f5fSchristos	int prev_x = INT_MIN;
138042542f5fSchristos	int winding = 0, xstart = INT_MIN;
138142542f5fSchristos
138242542f5fSchristos	while (&active->tail != edge) {
138342542f5fSchristos		struct edge *next = edge->next;
138442542f5fSchristos
138542542f5fSchristos		winding += edge->dir;
138642542f5fSchristos		if (0 == winding) {
138713496ba1Ssnj			if (edge->next->cell != edge->cell) {
138813496ba1Ssnj				if (edge->cell <= xstart) {
138942542f5fSchristos					xstart = INT_MIN;
139042542f5fSchristos				} else  {
139142542f5fSchristos					int fx;
139242542f5fSchristos					int ix;
139342542f5fSchristos
139442542f5fSchristos					if (xstart < FAST_SAMPLES_X * width) {
139542542f5fSchristos						FAST_SAMPLES_X_TO_INT_FRAC(xstart, ix, fx);
139642542f5fSchristos						if (ix < *min)
139742542f5fSchristos							*min = ix;
139842542f5fSchristos
139942542f5fSchristos						row[ix++] += FAST_SAMPLES_X - fx;
140042542f5fSchristos						if (fx && ix < width)
140142542f5fSchristos							row[ix] += fx;
140242542f5fSchristos					}
140342542f5fSchristos
140413496ba1Ssnj					xstart = edge->cell;
140542542f5fSchristos					if (xstart < FAST_SAMPLES_X * width) {
140642542f5fSchristos						FAST_SAMPLES_X_TO_INT_FRAC(xstart, ix, fx);
140742542f5fSchristos						row[ix] -= FAST_SAMPLES_X - fx;
140842542f5fSchristos						if (fx && ix + 1 < width)
140942542f5fSchristos							row[++ix] -= fx;
141042542f5fSchristos
141142542f5fSchristos						if (ix >= *max)
141242542f5fSchristos							*max = ix + 1;
141342542f5fSchristos
141442542f5fSchristos						xstart = INT_MIN;
141542542f5fSchristos					} else
141642542f5fSchristos						*max = width;
141742542f5fSchristos				}
141842542f5fSchristos			}
141942542f5fSchristos		} else if (xstart < 0) {
142013496ba1Ssnj			xstart = MAX(edge->cell, 0);
142142542f5fSchristos		}
142242542f5fSchristos
142342542f5fSchristos		assert(edge->height_left > 0);
142442542f5fSchristos		if (--edge->height_left) {
142542542f5fSchristos			if (edge->dy) {
142642542f5fSchristos				edge->x.quo += edge->dxdy.quo;
142742542f5fSchristos				edge->x.rem += edge->dxdy.rem;
142813496ba1Ssnj				if (edge->x.rem < 0) {
142913496ba1Ssnj					--edge->x.quo;
143013496ba1Ssnj					edge->x.rem += edge->dy;
143113496ba1Ssnj				} else if (edge->x.rem >= 0) {
143242542f5fSchristos					++edge->x.quo;
143342542f5fSchristos					edge->x.rem -= edge->dy;
143442542f5fSchristos				}
143513496ba1Ssnj				edge->cell = edge->x.quo + (edge->x.rem >= edge->dy/2);
143642542f5fSchristos			}
143742542f5fSchristos
143813496ba1Ssnj			if (edge->cell < prev_x) {
143942542f5fSchristos				struct edge *pos = edge->prev;
144042542f5fSchristos				pos->next = next;
144142542f5fSchristos				next->prev = pos;
144213496ba1Ssnj				do
144342542f5fSchristos					pos = pos->prev;
144413496ba1Ssnj				while (edge->cell < pos->cell);
144542542f5fSchristos				pos->next->prev = edge;
144642542f5fSchristos				edge->next = pos->next;
144742542f5fSchristos				edge->prev = pos;
144842542f5fSchristos				pos->next = edge;
144942542f5fSchristos			} else
145013496ba1Ssnj				prev_x = edge->cell;
145142542f5fSchristos		} else {
145242542f5fSchristos			edge->prev->next = next;
145342542f5fSchristos			next->prev = edge->prev;
145442542f5fSchristos		}
145542542f5fSchristos
145642542f5fSchristos		edge = next;
145742542f5fSchristos	}
145842542f5fSchristos}
145942542f5fSchristos
146042542f5fSchristosinline static void
146142542f5fSchristosinplace_end_subrows(struct active_list *active, uint8_t *row,
146242542f5fSchristos		    int8_t *buf, int width)
146342542f5fSchristos{
146442542f5fSchristos	int cover = 0;
146542542f5fSchristos
146642542f5fSchristos	while (width >= 4) {
146742542f5fSchristos		uint32_t dw;
146842542f5fSchristos		int v;
146942542f5fSchristos
147042542f5fSchristos		dw = *(uint32_t *)buf;
147142542f5fSchristos		buf += 4;
147242542f5fSchristos
147342542f5fSchristos		if (dw == 0) {
147413496ba1Ssnj			v = cover * 256 / FAST_SAMPLES_XY;
147542542f5fSchristos			v -= v >> 8;
147642542f5fSchristos			v |= v << 8;
147742542f5fSchristos			dw = v | v << 16;
147842542f5fSchristos		} else {
147942542f5fSchristos			cover += (int8_t)(dw & 0xff);
148042542f5fSchristos			if (cover) {
148142542f5fSchristos				assert(cover > 0);
148213496ba1Ssnj				v = cover * 256 / FAST_SAMPLES_XY;
148342542f5fSchristos				v -= v >> 8;
148442542f5fSchristos				dw >>= 8;
148542542f5fSchristos				dw |= v << 24;
148642542f5fSchristos			} else
148742542f5fSchristos				dw >>= 8;
148842542f5fSchristos
148942542f5fSchristos			cover += (int8_t)(dw & 0xff);
149042542f5fSchristos			if (cover) {
149142542f5fSchristos				assert(cover > 0);
149213496ba1Ssnj				v = cover * 256 / FAST_SAMPLES_XY;
149342542f5fSchristos				v -= v >> 8;
149442542f5fSchristos				dw >>= 8;
149542542f5fSchristos				dw |= v << 24;
149642542f5fSchristos			} else
149742542f5fSchristos				dw >>= 8;
149842542f5fSchristos
149942542f5fSchristos			cover += (int8_t)(dw & 0xff);
150042542f5fSchristos			if (cover) {
150142542f5fSchristos				assert(cover > 0);
150213496ba1Ssnj				v = cover * 256 / FAST_SAMPLES_XY;
150342542f5fSchristos				v -= v >> 8;
150442542f5fSchristos				dw >>= 8;
150542542f5fSchristos				dw |= v << 24;
150642542f5fSchristos			} else
150742542f5fSchristos				dw >>= 8;
150842542f5fSchristos
150942542f5fSchristos			cover += (int8_t)(dw & 0xff);
151042542f5fSchristos			if (cover) {
151142542f5fSchristos				assert(cover > 0);
151213496ba1Ssnj				v = cover * 256 / FAST_SAMPLES_XY;
151342542f5fSchristos				v -= v >> 8;
151442542f5fSchristos				dw >>= 8;
151542542f5fSchristos				dw |= v << 24;
151642542f5fSchristos			} else
151742542f5fSchristos				dw >>= 8;
151842542f5fSchristos		}
151942542f5fSchristos
152042542f5fSchristos		*(uint32_t *)row = dw;
152142542f5fSchristos		row += 4;
152242542f5fSchristos		width -= 4;
152342542f5fSchristos	}
152442542f5fSchristos
152542542f5fSchristos	while (width--) {
152642542f5fSchristos		int v;
152742542f5fSchristos
152842542f5fSchristos		cover += *buf++;
152942542f5fSchristos		assert(cover >= 0);
153042542f5fSchristos
153113496ba1Ssnj		v = cover * 256 / FAST_SAMPLES_XY;
153242542f5fSchristos		v -= v >> 8;
153342542f5fSchristos		*row++ = v;
153442542f5fSchristos	}
153542542f5fSchristos}
153642542f5fSchristos
153742542f5fSchristosstatic void
153842542f5fSchristosconvert_mono(uint8_t *ptr, int w)
153942542f5fSchristos{
154042542f5fSchristos	while (w--) {
154142542f5fSchristos		*ptr = 0xff * (*ptr >= 0xf0);
154242542f5fSchristos		ptr++;
154342542f5fSchristos	}
154442542f5fSchristos}
154542542f5fSchristos
154642542f5fSchristosstatic void
154742542f5fSchristostor_inplace(struct tor *converter, PixmapPtr scratch, int mono, uint8_t *buf)
154842542f5fSchristos{
154942542f5fSchristos	int i, j, h = converter->extents.y2;
155042542f5fSchristos	struct polygon *polygon = converter->polygon;
155142542f5fSchristos	struct active_list *active = converter->active;
155242542f5fSchristos	struct edge *buckets[FAST_SAMPLES_Y] = { 0 };
155342542f5fSchristos	uint8_t *row = scratch->devPrivate.ptr;
155442542f5fSchristos	int stride = scratch->devKind;
155542542f5fSchristos	int width = scratch->drawable.width;
155642542f5fSchristos
155742542f5fSchristos	__DBG(("%s: mono=%d, buf?=%d\n", __FUNCTION__, mono, buf != NULL));
155842542f5fSchristos	assert(converter->extents.y1 == 0);
155942542f5fSchristos	assert(converter->extents.x1 == 0);
156042542f5fSchristos	assert(scratch->drawable.depth == 8);
156142542f5fSchristos
156242542f5fSchristos	/* Render each pixel row. */
156342542f5fSchristos	for (i = 0; i < h; i = j) {
156442542f5fSchristos		int do_full_step = 0;
156542542f5fSchristos		void *ptr = buf ?: row;
156642542f5fSchristos
156742542f5fSchristos		j = i + 1;
156842542f5fSchristos
156942542f5fSchristos		/* Determine if we can ignore this row or use the full pixel
157042542f5fSchristos		 * stepper. */
157113496ba1Ssnj		if (fill_buckets(active, polygon->y_buckets[i], buckets) == 0) {
157213496ba1Ssnj			if (buckets[0]) {
157313496ba1Ssnj				merge_edges(active, buckets[0]);
157413496ba1Ssnj				buckets[0] = NULL;
157513496ba1Ssnj			}
157642542f5fSchristos			if (active->head.next == &active->tail) {
157742542f5fSchristos				for (; !polygon->y_buckets[j]; j++)
157842542f5fSchristos					;
157942542f5fSchristos				__DBG(("%s: no new edges and no exisiting edges, skipping, %d -> %d\n",
158042542f5fSchristos				       __FUNCTION__, i, j));
158142542f5fSchristos
158242542f5fSchristos				memset(row, 0, stride*(j-i));
158342542f5fSchristos				row += stride*(j-i);
158442542f5fSchristos				continue;
158542542f5fSchristos			}
158642542f5fSchristos
158742542f5fSchristos			do_full_step = can_full_step(active);
158842542f5fSchristos		}
158942542f5fSchristos
159042542f5fSchristos		__DBG(("%s: y=%d, do_full_step=%d, new edges=%d, min_height=%d, vertical=%d\n",
159142542f5fSchristos		       __FUNCTION__,
159242542f5fSchristos		       i, do_full_step,
159342542f5fSchristos		       polygon->y_buckets[i] != NULL));
159442542f5fSchristos		if (do_full_step) {
159542542f5fSchristos			memset(ptr, 0, width);
159642542f5fSchristos			inplace_row(active, ptr, width);
159742542f5fSchristos			if (mono)
159842542f5fSchristos				convert_mono(ptr, width);
159942542f5fSchristos			if (row != ptr)
160042542f5fSchristos				memcpy(row, ptr, width);
160142542f5fSchristos
160242542f5fSchristos			while (polygon->y_buckets[j] == NULL &&
160342542f5fSchristos			       do_full_step >= 2*FAST_SAMPLES_Y) {
160442542f5fSchristos				do_full_step -= FAST_SAMPLES_Y;
160542542f5fSchristos				row += stride;
160642542f5fSchristos				memcpy(row, ptr, width);
160742542f5fSchristos				j++;
160842542f5fSchristos			}
160942542f5fSchristos			if (j != i + 1)
161042542f5fSchristos				step_edges(active, j - (i + 1));
161142542f5fSchristos
161242542f5fSchristos			__DBG(("%s: vertical edges, full step (%d, %d)\n",
161342542f5fSchristos			       __FUNCTION__,  i, j));
161442542f5fSchristos		} else {
161542542f5fSchristos			int min = width, max = 0, suby;
161642542f5fSchristos
161742542f5fSchristos			/* Subsample this row. */
161842542f5fSchristos			memset(ptr, 0, width);
161942542f5fSchristos			for (suby = 0; suby < FAST_SAMPLES_Y; suby++) {
162042542f5fSchristos				if (buckets[suby]) {
162142542f5fSchristos					merge_edges(active, buckets[suby]);
162242542f5fSchristos					buckets[suby] = NULL;
162342542f5fSchristos				}
162442542f5fSchristos
162542542f5fSchristos				inplace_subrow(active, ptr, width, &min, &max);
162642542f5fSchristos			}
162742542f5fSchristos			assert(min >= 0 && max <= width);
162842542f5fSchristos			memset(row, 0, min);
162942542f5fSchristos			if (max > min) {
163042542f5fSchristos				inplace_end_subrows(active, row+min, (int8_t*)ptr+min, max-min);
163142542f5fSchristos				if (mono)
163242542f5fSchristos					convert_mono(row+min, max-min);
163342542f5fSchristos			}
163442542f5fSchristos			if (max < width)
163542542f5fSchristos				memset(row+max, 0, width-max);
163642542f5fSchristos		}
163742542f5fSchristos
163842542f5fSchristos		row += stride;
163942542f5fSchristos	}
164042542f5fSchristos}
164142542f5fSchristos
164242542f5fSchristosstatic int operator_is_bounded(uint8_t op)
164342542f5fSchristos{
164442542f5fSchristos	switch (op) {
164542542f5fSchristos	case PictOpOver:
164642542f5fSchristos	case PictOpOutReverse:
164742542f5fSchristos	case PictOpAdd:
164842542f5fSchristos		return true;
164942542f5fSchristos	default:
165042542f5fSchristos		return false;
165142542f5fSchristos	}
165242542f5fSchristos}
165342542f5fSchristos
165442542f5fSchristosstatic span_func_t
165542542f5fSchristoschoose_span(struct sna_composite_spans_op *tmp,
165642542f5fSchristos	    PicturePtr dst,
165742542f5fSchristos	    PictFormatPtr maskFormat,
165842542f5fSchristos	    RegionPtr clip)
165942542f5fSchristos{
166042542f5fSchristos	span_func_t span;
166142542f5fSchristos
166242542f5fSchristos	if (is_mono(dst, maskFormat)) {
166342542f5fSchristos		/* XXX An imprecise approximation */
166442542f5fSchristos		if (maskFormat && !operator_is_bounded(tmp->base.op)) {
166542542f5fSchristos			span = tor_blt_span_mono_unbounded;
166642542f5fSchristos			if (clip->data)
166742542f5fSchristos				span = tor_blt_span_mono_unbounded_clipped;
166842542f5fSchristos		} else {
166942542f5fSchristos			span = tor_blt_span_mono;
167042542f5fSchristos			if (clip->data)
167142542f5fSchristos				span = tor_blt_span_mono_clipped;
167242542f5fSchristos		}
167342542f5fSchristos	} else {
167442542f5fSchristos		if (clip->data)
167542542f5fSchristos			span = tor_blt_span_clipped;
167642542f5fSchristos		else if (tmp->base.damage == NULL)
167742542f5fSchristos			span = tor_blt_span__no_damage;
167842542f5fSchristos		else
167942542f5fSchristos			span = tor_blt_span;
168042542f5fSchristos	}
168142542f5fSchristos
168242542f5fSchristos	return span;
168342542f5fSchristos}
168442542f5fSchristos
168542542f5fSchristosstruct span_thread {
168642542f5fSchristos	struct sna *sna;
168742542f5fSchristos	const struct sna_composite_spans_op *op;
168842542f5fSchristos	const xTrapezoid *traps;
168942542f5fSchristos	RegionPtr clip;
169042542f5fSchristos	span_func_t span;
169142542f5fSchristos	BoxRec extents;
169242542f5fSchristos	int dx, dy, draw_y;
169342542f5fSchristos	int ntrap;
169442542f5fSchristos	bool unbounded;
169542542f5fSchristos};
169642542f5fSchristos
169742542f5fSchristos#define SPAN_THREAD_MAX_BOXES (8192/sizeof(struct sna_opacity_box))
169842542f5fSchristosstruct span_thread_boxes {
169942542f5fSchristos	const struct sna_composite_spans_op *op;
1700fe8aea9eSmrg	const BoxRec *clip_start, *clip_end;
170142542f5fSchristos	int num_boxes;
170242542f5fSchristos	struct sna_opacity_box boxes[SPAN_THREAD_MAX_BOXES];
170342542f5fSchristos};
170442542f5fSchristos
1705fe8aea9eSmrgstatic void span_thread_add_box(struct sna *sna, void *data,
1706fe8aea9eSmrg				const BoxRec *box, float alpha)
170742542f5fSchristos{
170842542f5fSchristos	struct span_thread_boxes *b = data;
170942542f5fSchristos
1710fe8aea9eSmrg	__DBG(("%s: adding box with alpha=%f\n", __FUNCTION__, alpha));
171142542f5fSchristos
1712fe8aea9eSmrg	if (unlikely(b->num_boxes == SPAN_THREAD_MAX_BOXES)) {
1713fe8aea9eSmrg		DBG(("%s: flushing %d boxes\n", __FUNCTION__, b->num_boxes));
171442542f5fSchristos		b->op->thread_boxes(sna, b->op, b->boxes, b->num_boxes);
171542542f5fSchristos		b->num_boxes = 0;
171642542f5fSchristos	}
171742542f5fSchristos
1718fe8aea9eSmrg	b->boxes[b->num_boxes].box = *box++;
1719fe8aea9eSmrg	b->boxes[b->num_boxes].alpha = alpha;
1720fe8aea9eSmrg	b->num_boxes++;
172142542f5fSchristos	assert(b->num_boxes <= SPAN_THREAD_MAX_BOXES);
172242542f5fSchristos}
172342542f5fSchristos
172442542f5fSchristosstatic void
172542542f5fSchristosspan_thread_box(struct sna *sna,
172642542f5fSchristos		struct sna_composite_spans_op *op,
172742542f5fSchristos		pixman_region16_t *clip,
172842542f5fSchristos		const BoxRec *box,
172942542f5fSchristos		int coverage)
173042542f5fSchristos{
1731fe8aea9eSmrg	struct span_thread_boxes *b = (struct span_thread_boxes *)op;
1732fe8aea9eSmrg
173342542f5fSchristos	__DBG(("%s: %d -> %d @ %d\n", __FUNCTION__, box->x1, box->x2, coverage));
1734fe8aea9eSmrg	if (b->num_boxes) {
1735fe8aea9eSmrg		struct sna_opacity_box *bb = &b->boxes[b->num_boxes-1];
1736fe8aea9eSmrg		if (bb->box.x1 == box->x1 &&
1737fe8aea9eSmrg		    bb->box.x2 == box->x2 &&
1738fe8aea9eSmrg		    bb->box.y2 == box->y1 &&
1739fe8aea9eSmrg		    bb->alpha == AREA_TO_ALPHA(coverage)) {
1740fe8aea9eSmrg			bb->box.y2 = box->y2;
1741fe8aea9eSmrg			__DBG(("%s: contracted double row: %d -> %d\n", __func__, bb->box.y1, bb->box.y2));
1742fe8aea9eSmrg			return;
1743fe8aea9eSmrg		}
1744fe8aea9eSmrg	}
1745fe8aea9eSmrg
1746fe8aea9eSmrg	span_thread_add_box(sna, op, box, AREA_TO_ALPHA(coverage));
174742542f5fSchristos}
174842542f5fSchristos
174942542f5fSchristosstatic void
175042542f5fSchristosspan_thread_clipped_box(struct sna *sna,
175142542f5fSchristos			struct sna_composite_spans_op *op,
175242542f5fSchristos			pixman_region16_t *clip,
175342542f5fSchristos			const BoxRec *box,
175442542f5fSchristos			int coverage)
175542542f5fSchristos{
1756fe8aea9eSmrg	struct span_thread_boxes *b = (struct span_thread_boxes *)op;
1757fe8aea9eSmrg	const BoxRec *c;
175842542f5fSchristos
175942542f5fSchristos	__DBG(("%s: %d -> %d @ %f\n", __FUNCTION__, box->x1, box->x2,
176042542f5fSchristos	       AREA_TO_ALPHA(coverage)));
176142542f5fSchristos
1762fe8aea9eSmrg	b->clip_start =
1763fe8aea9eSmrg		find_clip_box_for_y(b->clip_start, b->clip_end, box->y1);
1764fe8aea9eSmrg
1765fe8aea9eSmrg	c = b->clip_start;
1766fe8aea9eSmrg	while (c != b->clip_end) {
1767fe8aea9eSmrg		BoxRec clipped;
1768fe8aea9eSmrg
1769fe8aea9eSmrg		if (box->y2 <= c->y1)
1770fe8aea9eSmrg			break;
1771fe8aea9eSmrg
1772fe8aea9eSmrg		clipped = *box;
1773fe8aea9eSmrg		if (!box_intersect(&clipped, c++))
1774fe8aea9eSmrg			continue;
1775fe8aea9eSmrg
1776fe8aea9eSmrg		span_thread_add_box(sna, op, &clipped, AREA_TO_ALPHA(coverage));
177742542f5fSchristos	}
177842542f5fSchristos}
177942542f5fSchristos
178042542f5fSchristosstatic span_func_t
178142542f5fSchristosthread_choose_span(struct sna_composite_spans_op *tmp,
178242542f5fSchristos		   PicturePtr dst,
178342542f5fSchristos		   PictFormatPtr maskFormat,
178442542f5fSchristos		   RegionPtr clip)
178542542f5fSchristos{
178642542f5fSchristos	span_func_t span;
178742542f5fSchristos
178842542f5fSchristos	if (tmp->base.damage) {
178942542f5fSchristos		DBG(("%s: damaged -> no thread support\n", __FUNCTION__));
179042542f5fSchristos		return NULL;
179142542f5fSchristos	}
179242542f5fSchristos
179342542f5fSchristos	if (is_mono(dst, maskFormat)) {
179442542f5fSchristos		DBG(("%s: mono rendering -> no thread support\n", __FUNCTION__));
179542542f5fSchristos		return NULL;
179642542f5fSchristos	} else {
179742542f5fSchristos		assert(tmp->thread_boxes);
179842542f5fSchristos		DBG(("%s: clipped? %d\n", __FUNCTION__, clip->data != NULL));
179942542f5fSchristos		if (clip->data)
180042542f5fSchristos			span = span_thread_clipped_box;
180142542f5fSchristos		else
180242542f5fSchristos			span = span_thread_box;
180342542f5fSchristos	}
180442542f5fSchristos
180542542f5fSchristos	return span;
180642542f5fSchristos}
180742542f5fSchristos
1808fe8aea9eSmrginline static void
1809fe8aea9eSmrgspan_thread_boxes_init(struct span_thread_boxes *boxes,
1810fe8aea9eSmrg		       const struct sna_composite_spans_op *op,
1811fe8aea9eSmrg		       const RegionRec *clip)
1812fe8aea9eSmrg{
1813fe8aea9eSmrg	boxes->op = op;
1814fe8aea9eSmrg	region_get_boxes(clip, &boxes->clip_start, &boxes->clip_end);
1815fe8aea9eSmrg	boxes->num_boxes = 0;
1816fe8aea9eSmrg}
1817fe8aea9eSmrg
181842542f5fSchristosstatic void
181942542f5fSchristosspan_thread(void *arg)
182042542f5fSchristos{
182142542f5fSchristos	struct span_thread *thread = arg;
182242542f5fSchristos	struct span_thread_boxes boxes;
182342542f5fSchristos	struct tor tor;
182442542f5fSchristos	const xTrapezoid *t;
182542542f5fSchristos	int n, y1, y2;
182642542f5fSchristos
182742542f5fSchristos	if (!tor_init(&tor, &thread->extents, 2*thread->ntrap))
182842542f5fSchristos		return;
182942542f5fSchristos
1830fe8aea9eSmrg	span_thread_boxes_init(&boxes, thread->op, thread->clip);
183142542f5fSchristos
183242542f5fSchristos	y1 = thread->extents.y1 - thread->draw_y;
183342542f5fSchristos	y2 = thread->extents.y2 - thread->draw_y;
183442542f5fSchristos	for (n = thread->ntrap, t = thread->traps; n--; t++) {
183542542f5fSchristos		if (pixman_fixed_integer_floor(t->top) >= y2 ||
183642542f5fSchristos		    pixman_fixed_integer_ceil(t->bottom) <= y1)
183742542f5fSchristos			continue;
183842542f5fSchristos
183913496ba1Ssnj		tor_add_trapezoid(&tor, t, thread->dx, thread->dy);
184042542f5fSchristos	}
184142542f5fSchristos
184242542f5fSchristos	tor_render(thread->sna, &tor,
184342542f5fSchristos		   (struct sna_composite_spans_op *)&boxes, thread->clip,
184442542f5fSchristos		   thread->span, thread->unbounded);
184542542f5fSchristos
184642542f5fSchristos	tor_fini(&tor);
184742542f5fSchristos
184842542f5fSchristos	if (boxes.num_boxes) {
184942542f5fSchristos		DBG(("%s: flushing %d boxes\n", __FUNCTION__, boxes.num_boxes));
185042542f5fSchristos		assert(boxes.num_boxes <= SPAN_THREAD_MAX_BOXES);
185142542f5fSchristos		thread->op->thread_boxes(thread->sna, thread->op,
185242542f5fSchristos					 boxes.boxes, boxes.num_boxes);
185342542f5fSchristos	}
185442542f5fSchristos}
185542542f5fSchristos
185642542f5fSchristosbool
185742542f5fSchristosimprecise_trapezoid_span_converter(struct sna *sna,
185842542f5fSchristos				   CARD8 op, PicturePtr src, PicturePtr dst,
185942542f5fSchristos				   PictFormatPtr maskFormat, unsigned int flags,
186042542f5fSchristos				   INT16 src_x, INT16 src_y,
186142542f5fSchristos				   int ntrap, xTrapezoid *traps)
186242542f5fSchristos{
186342542f5fSchristos	struct sna_composite_spans_op tmp;
186442542f5fSchristos	pixman_region16_t clip;
186542542f5fSchristos	int16_t dst_x, dst_y;
186642542f5fSchristos	bool was_clear;
186742542f5fSchristos	int dx, dy, n;
186842542f5fSchristos	int num_threads;
186942542f5fSchristos
187042542f5fSchristos	if (NO_IMPRECISE)
187142542f5fSchristos		return false;
187242542f5fSchristos
187342542f5fSchristos	if (!sna->render.check_composite_spans(sna, op, src, dst, 0, 0, flags)) {
187442542f5fSchristos		DBG(("%s: fallback -- composite spans not supported\n",
187542542f5fSchristos		     __FUNCTION__));
187642542f5fSchristos		return false;
187742542f5fSchristos	}
187842542f5fSchristos
187942542f5fSchristos	if (!trapezoids_bounds(ntrap, traps, &clip.extents))
188042542f5fSchristos		return true;
188142542f5fSchristos
188242542f5fSchristos#if 0
188342542f5fSchristos	if (clip.extents.y2 - clip.extents.y1 < 64 &&
188442542f5fSchristos	    clip.extents.x2 - clip.extents.x1 < 64) {
188542542f5fSchristos		DBG(("%s: fallback -- traps extents too small %dx%d\n",
188642542f5fSchristos		     __FUNCTION__, extents.y2 - extents.y1, extents.x2 - extents.x1));
188742542f5fSchristos		return false;
188842542f5fSchristos	}
188942542f5fSchristos#endif
189042542f5fSchristos
189142542f5fSchristos	DBG(("%s: extents (%d, %d), (%d, %d)\n",
189242542f5fSchristos	     __FUNCTION__,
189342542f5fSchristos	     clip.extents.x1, clip.extents.y1,
189442542f5fSchristos	     clip.extents.x2, clip.extents.y2));
189542542f5fSchristos
189642542f5fSchristos	trapezoid_origin(&traps[0].left, &dst_x, &dst_y);
189742542f5fSchristos
189842542f5fSchristos	if (!sna_compute_composite_region(&clip,
189942542f5fSchristos					  src, NULL, dst,
190042542f5fSchristos					  src_x + clip.extents.x1 - dst_x,
190142542f5fSchristos					  src_y + clip.extents.y1 - dst_y,
190242542f5fSchristos					  0, 0,
190342542f5fSchristos					  clip.extents.x1, clip.extents.y1,
190442542f5fSchristos					  clip.extents.x2 - clip.extents.x1,
190542542f5fSchristos					  clip.extents.y2 - clip.extents.y1)) {
190642542f5fSchristos		DBG(("%s: trapezoids do not intersect drawable clips\n",
190742542f5fSchristos		     __FUNCTION__)) ;
190842542f5fSchristos		return true;
190942542f5fSchristos	}
191042542f5fSchristos
191142542f5fSchristos	if (!sna->render.check_composite_spans(sna, op, src, dst,
191242542f5fSchristos					       clip.extents.x2 - clip.extents.x1,
191342542f5fSchristos					       clip.extents.y2 - clip.extents.y1,
191442542f5fSchristos					       flags)) {
191542542f5fSchristos		DBG(("%s: fallback -- composite spans not supported\n",
191642542f5fSchristos		     __FUNCTION__));
191742542f5fSchristos		return false;
191842542f5fSchristos	}
191942542f5fSchristos
192042542f5fSchristos	dx = dst->pDrawable->x;
192142542f5fSchristos	dy = dst->pDrawable->y;
192242542f5fSchristos
192342542f5fSchristos	DBG(("%s: after clip -- extents (%d, %d), (%d, %d), delta=(%d, %d) src -> (%d, %d)\n",
192442542f5fSchristos	     __FUNCTION__,
192542542f5fSchristos	     clip.extents.x1, clip.extents.y1,
192642542f5fSchristos	     clip.extents.x2, clip.extents.y2,
192742542f5fSchristos	     dx, dy,
192842542f5fSchristos	     src_x + clip.extents.x1 - dst_x - dx,
192942542f5fSchristos	     src_y + clip.extents.y1 - dst_y - dy));
193042542f5fSchristos
193142542f5fSchristos	was_clear = sna_drawable_is_clear(dst->pDrawable);
193242542f5fSchristos	switch (op) {
193342542f5fSchristos	case PictOpAdd:
193442542f5fSchristos	case PictOpOver:
193542542f5fSchristos		if (was_clear)
193642542f5fSchristos			op = PictOpSrc;
193742542f5fSchristos		break;
193842542f5fSchristos	case PictOpIn:
193942542f5fSchristos		if (was_clear)
194042542f5fSchristos			return true;
194142542f5fSchristos		break;
194242542f5fSchristos	}
194342542f5fSchristos
194442542f5fSchristos	if (!sna->render.composite_spans(sna, op, src, dst,
194542542f5fSchristos					 src_x + clip.extents.x1 - dst_x - dx,
194642542f5fSchristos					 src_y + clip.extents.y1 - dst_y - dy,
194742542f5fSchristos					 clip.extents.x1,  clip.extents.y1,
194842542f5fSchristos					 clip.extents.x2 - clip.extents.x1,
194942542f5fSchristos					 clip.extents.y2 - clip.extents.y1,
195042542f5fSchristos					 flags, memset(&tmp, 0, sizeof(tmp)))) {
195142542f5fSchristos		DBG(("%s: fallback -- composite spans render op not supported\n",
195242542f5fSchristos		     __FUNCTION__));
195342542f5fSchristos		return false;
195442542f5fSchristos	}
195542542f5fSchristos
195642542f5fSchristos	dx *= FAST_SAMPLES_X;
195742542f5fSchristos	dy *= FAST_SAMPLES_Y;
195842542f5fSchristos
195942542f5fSchristos	num_threads = 1;
196042542f5fSchristos	if (!NO_GPU_THREADS &&
196142542f5fSchristos	    (flags & COMPOSITE_SPANS_RECTILINEAR) == 0 &&
196242542f5fSchristos	    tmp.thread_boxes &&
196342542f5fSchristos	    thread_choose_span(&tmp, dst, maskFormat, &clip))
196442542f5fSchristos		num_threads = sna_use_threads(clip.extents.x2-clip.extents.x1,
196542542f5fSchristos					      clip.extents.y2-clip.extents.y1,
196642542f5fSchristos					      16);
196742542f5fSchristos	DBG(("%s: using %d threads\n", __FUNCTION__, num_threads));
196842542f5fSchristos	if (num_threads == 1) {
196942542f5fSchristos		struct tor tor;
197042542f5fSchristos
197142542f5fSchristos		if (!tor_init(&tor, &clip.extents, 2*ntrap))
197242542f5fSchristos			goto skip;
197342542f5fSchristos
197442542f5fSchristos		for (n = 0; n < ntrap; n++) {
197542542f5fSchristos			if (pixman_fixed_integer_floor(traps[n].top) + dst->pDrawable->y >= clip.extents.y2 ||
197642542f5fSchristos			    pixman_fixed_integer_ceil(traps[n].bottom) + dst->pDrawable->y <= clip.extents.y1)
197742542f5fSchristos				continue;
197842542f5fSchristos
197913496ba1Ssnj			tor_add_trapezoid(&tor, &traps[n], dx, dy);
198042542f5fSchristos		}
198142542f5fSchristos
198242542f5fSchristos		tor_render(sna, &tor, &tmp, &clip,
198342542f5fSchristos			   choose_span(&tmp, dst, maskFormat, &clip),
198442542f5fSchristos			   !was_clear && maskFormat && !operator_is_bounded(op));
198542542f5fSchristos
198642542f5fSchristos		tor_fini(&tor);
198742542f5fSchristos	} else {
198842542f5fSchristos		struct span_thread threads[num_threads];
198942542f5fSchristos		int y, h;
199042542f5fSchristos
199142542f5fSchristos		DBG(("%s: using %d threads for span compositing %dx%d\n",
199242542f5fSchristos		     __FUNCTION__, num_threads,
199342542f5fSchristos		     clip.extents.x2 - clip.extents.x1,
199442542f5fSchristos		     clip.extents.y2 - clip.extents.y1));
199542542f5fSchristos
199642542f5fSchristos		threads[0].sna = sna;
199742542f5fSchristos		threads[0].op = &tmp;
199842542f5fSchristos		threads[0].traps = traps;
199942542f5fSchristos		threads[0].ntrap = ntrap;
200042542f5fSchristos		threads[0].extents = clip.extents;
200142542f5fSchristos		threads[0].clip = &clip;
200242542f5fSchristos		threads[0].dx = dx;
200342542f5fSchristos		threads[0].dy = dy;
200442542f5fSchristos		threads[0].draw_y = dst->pDrawable->y;
200542542f5fSchristos		threads[0].unbounded = !was_clear && maskFormat && !operator_is_bounded(op);
200642542f5fSchristos		threads[0].span = thread_choose_span(&tmp, dst, maskFormat, &clip);
200742542f5fSchristos
200842542f5fSchristos		y = clip.extents.y1;
200942542f5fSchristos		h = clip.extents.y2 - clip.extents.y1;
201042542f5fSchristos		h = (h + num_threads - 1) / num_threads;
201142542f5fSchristos		num_threads -= (num_threads-1) * h >= clip.extents.y2 - clip.extents.y1;
201242542f5fSchristos
201342542f5fSchristos		for (n = 1; n < num_threads; n++) {
201442542f5fSchristos			threads[n] = threads[0];
201542542f5fSchristos			threads[n].extents.y1 = y;
201642542f5fSchristos			threads[n].extents.y2 = y += h;
201742542f5fSchristos
201842542f5fSchristos			sna_threads_run(n, span_thread, &threads[n]);
201942542f5fSchristos		}
202042542f5fSchristos
202142542f5fSchristos		assert(y < threads[0].extents.y2);
202242542f5fSchristos		threads[0].extents.y1 = y;
202342542f5fSchristos		span_thread(&threads[0]);
202442542f5fSchristos
202542542f5fSchristos		sna_threads_wait();
202642542f5fSchristos	}
202742542f5fSchristosskip:
202842542f5fSchristos	tmp.done(sna, &tmp);
202942542f5fSchristos
203042542f5fSchristos	REGION_UNINIT(NULL, &clip);
203142542f5fSchristos	return true;
203242542f5fSchristos}
203342542f5fSchristos
203442542f5fSchristosstatic void
203542542f5fSchristostor_blt_mask(struct sna *sna,
203642542f5fSchristos	     struct sna_composite_spans_op *op,
203742542f5fSchristos	     pixman_region16_t *clip,
203842542f5fSchristos	     const BoxRec *box,
203942542f5fSchristos	     int coverage)
204042542f5fSchristos{
204142542f5fSchristos	uint8_t *ptr = (uint8_t *)op;
204242542f5fSchristos	int stride = (intptr_t)clip;
204342542f5fSchristos	int h, w;
204442542f5fSchristos
204542542f5fSchristos	coverage = 256 * coverage / FAST_SAMPLES_XY;
204642542f5fSchristos	coverage -= coverage >> 8;
204742542f5fSchristos
204842542f5fSchristos	ptr += box->y1 * stride + box->x1;
204942542f5fSchristos
205042542f5fSchristos	h = box->y2 - box->y1;
205142542f5fSchristos	w = box->x2 - box->x1;
205242542f5fSchristos	if ((w | h) == 1) {
205342542f5fSchristos		*ptr = coverage;
205442542f5fSchristos	} else if (w == 1) {
205542542f5fSchristos		do {
205642542f5fSchristos			*ptr = coverage;
205742542f5fSchristos			ptr += stride;
205842542f5fSchristos		} while (--h);
205942542f5fSchristos	} else do {
206042542f5fSchristos		memset(ptr, coverage, w);
206142542f5fSchristos		ptr += stride;
206242542f5fSchristos	} while (--h);
206342542f5fSchristos}
206442542f5fSchristos
206542542f5fSchristosstatic void
206642542f5fSchristostor_blt_mask_mono(struct sna *sna,
206742542f5fSchristos		  struct sna_composite_spans_op *op,
206842542f5fSchristos		  pixman_region16_t *clip,
206942542f5fSchristos		  const BoxRec *box,
207042542f5fSchristos		  int coverage)
207142542f5fSchristos{
207242542f5fSchristos	tor_blt_mask(sna, op, clip, box,
207342542f5fSchristos		     coverage < FAST_SAMPLES_XY/2 ? 0 : FAST_SAMPLES_XY);
207442542f5fSchristos}
207542542f5fSchristos
207642542f5fSchristosbool
207742542f5fSchristosimprecise_trapezoid_mask_converter(CARD8 op, PicturePtr src, PicturePtr dst,
207842542f5fSchristos				   PictFormatPtr maskFormat, unsigned flags,
207942542f5fSchristos				   INT16 src_x, INT16 src_y,
208042542f5fSchristos				   int ntrap, xTrapezoid *traps)
208142542f5fSchristos{
208242542f5fSchristos	struct tor tor;
208342542f5fSchristos	ScreenPtr screen = dst->pDrawable->pScreen;
208442542f5fSchristos	PixmapPtr scratch;
208542542f5fSchristos	PicturePtr mask;
208642542f5fSchristos	BoxRec extents;
208742542f5fSchristos	int16_t dst_x, dst_y;
208842542f5fSchristos	int dx, dy;
208942542f5fSchristos	int error, n;
209042542f5fSchristos
209142542f5fSchristos	if (NO_IMPRECISE)
209242542f5fSchristos		return false;
209342542f5fSchristos
209442542f5fSchristos	if (maskFormat == NULL && ntrap > 1) {
209542542f5fSchristos		DBG(("%s: individual rasterisation requested\n",
209642542f5fSchristos		     __FUNCTION__));
209742542f5fSchristos		do {
209842542f5fSchristos			/* XXX unwind errors? */
209942542f5fSchristos			if (!imprecise_trapezoid_mask_converter(op, src, dst, NULL, flags,
210042542f5fSchristos								src_x, src_y, 1, traps++))
210142542f5fSchristos				return false;
210242542f5fSchristos		} while (--ntrap);
210342542f5fSchristos		return true;
210442542f5fSchristos	}
210542542f5fSchristos
210642542f5fSchristos	if (!trapezoids_bounds(ntrap, traps, &extents))
210742542f5fSchristos		return true;
210842542f5fSchristos
210942542f5fSchristos	DBG(("%s: ntraps=%d, extents (%d, %d), (%d, %d)\n",
211042542f5fSchristos	     __FUNCTION__, ntrap, extents.x1, extents.y1, extents.x2, extents.y2));
211142542f5fSchristos
211242542f5fSchristos	if (!sna_compute_composite_extents(&extents,
211342542f5fSchristos					   src, NULL, dst,
211442542f5fSchristos					   src_x, src_y,
211542542f5fSchristos					   0, 0,
211642542f5fSchristos					   extents.x1, extents.y1,
211742542f5fSchristos					   extents.x2 - extents.x1,
211842542f5fSchristos					   extents.y2 - extents.y1))
211942542f5fSchristos		return true;
212042542f5fSchristos
212142542f5fSchristos	DBG(("%s: extents (%d, %d), (%d, %d)\n",
212242542f5fSchristos	     __FUNCTION__, extents.x1, extents.y1, extents.x2, extents.y2));
212342542f5fSchristos
212442542f5fSchristos	extents.y2 -= extents.y1;
212542542f5fSchristos	extents.x2 -= extents.x1;
212642542f5fSchristos	extents.x1 -= dst->pDrawable->x;
212742542f5fSchristos	extents.y1 -= dst->pDrawable->y;
212842542f5fSchristos	dst_x = extents.x1;
212942542f5fSchristos	dst_y = extents.y1;
213042542f5fSchristos	dx = -extents.x1 * FAST_SAMPLES_X;
213142542f5fSchristos	dy = -extents.y1 * FAST_SAMPLES_Y;
213242542f5fSchristos	extents.x1 = extents.y1 = 0;
213342542f5fSchristos
213442542f5fSchristos	DBG(("%s: mask (%dx%d), dx=(%d, %d)\n",
213542542f5fSchristos	     __FUNCTION__, extents.x2, extents.y2, dx, dy));
213642542f5fSchristos	scratch = sna_pixmap_create_upload(screen,
213742542f5fSchristos					   extents.x2, extents.y2, 8,
213842542f5fSchristos					   KGEM_BUFFER_WRITE_INPLACE);
213942542f5fSchristos	if (!scratch)
214042542f5fSchristos		return true;
214142542f5fSchristos
214242542f5fSchristos	DBG(("%s: created buffer %p, stride %d\n",
214342542f5fSchristos	     __FUNCTION__, scratch->devPrivate.ptr, scratch->devKind));
214442542f5fSchristos
214542542f5fSchristos	if (!tor_init(&tor, &extents, 2*ntrap)) {
214642542f5fSchristos		sna_pixmap_destroy(scratch);
214742542f5fSchristos		return true;
214842542f5fSchristos	}
214942542f5fSchristos
215042542f5fSchristos	for (n = 0; n < ntrap; n++) {
215142542f5fSchristos		if (pixman_fixed_to_int(traps[n].top) - dst_y >= extents.y2 ||
215242542f5fSchristos		    pixman_fixed_to_int(traps[n].bottom) - dst_y < 0)
215342542f5fSchristos			continue;
215442542f5fSchristos
215513496ba1Ssnj		tor_add_trapezoid(&tor, &traps[n], dx, dy);
215642542f5fSchristos	}
215742542f5fSchristos
215842542f5fSchristos	if (extents.x2 <= TOR_INPLACE_SIZE) {
215942542f5fSchristos		uint8_t buf[TOR_INPLACE_SIZE];
216042542f5fSchristos		tor_inplace(&tor, scratch, is_mono(dst, maskFormat),
216142542f5fSchristos			    scratch->usage_hint ? NULL : buf);
216242542f5fSchristos	} else {
216342542f5fSchristos		tor_render(NULL, &tor,
216442542f5fSchristos			   scratch->devPrivate.ptr,
216542542f5fSchristos			   (void *)(intptr_t)scratch->devKind,
216642542f5fSchristos			   is_mono(dst, maskFormat) ? tor_blt_mask_mono : tor_blt_mask,
216742542f5fSchristos			   true);
216842542f5fSchristos	}
216942542f5fSchristos	tor_fini(&tor);
217042542f5fSchristos
217142542f5fSchristos	mask = CreatePicture(0, &scratch->drawable,
217242542f5fSchristos			     PictureMatchFormat(screen, 8, PICT_a8),
217342542f5fSchristos			     0, 0, serverClient, &error);
217442542f5fSchristos	if (mask) {
217542542f5fSchristos		int16_t x0, y0;
217642542f5fSchristos
217742542f5fSchristos		trapezoid_origin(&traps[0].left, &x0, &y0);
217842542f5fSchristos
217942542f5fSchristos		CompositePicture(op, src, mask, dst,
218042542f5fSchristos				 src_x + dst_x - x0,
218142542f5fSchristos				 src_y + dst_y - y0,
218242542f5fSchristos				 0, 0,
218342542f5fSchristos				 dst_x, dst_y,
218442542f5fSchristos				 extents.x2, extents.y2);
218542542f5fSchristos		FreePicture(mask, 0);
218642542f5fSchristos	}
218742542f5fSchristos	sna_pixmap_destroy(scratch);
218842542f5fSchristos
218942542f5fSchristos	return true;
219042542f5fSchristos}
219142542f5fSchristos
219242542f5fSchristosstruct inplace {
219342542f5fSchristos	uint8_t *ptr;
219442542f5fSchristos	uint32_t stride;
219542542f5fSchristos	union {
219642542f5fSchristos		uint8_t opacity;
219742542f5fSchristos		uint32_t color;
219842542f5fSchristos	};
219942542f5fSchristos};
220042542f5fSchristos
220142542f5fSchristosstatic force_inline uint8_t coverage_opacity(int coverage, uint8_t opacity)
220242542f5fSchristos{
220342542f5fSchristos	coverage = coverage * 256 / FAST_SAMPLES_XY;
220442542f5fSchristos	coverage -= coverage >> 8;
220542542f5fSchristos	return opacity == 255 ? coverage : mul_8_8(coverage, opacity);
220642542f5fSchristos}
220742542f5fSchristos
220842542f5fSchristosstatic void _tor_blt_src(struct inplace *in, const BoxRec *box, uint8_t v)
220942542f5fSchristos{
221042542f5fSchristos	uint8_t *ptr = in->ptr;
221142542f5fSchristos	int h, w;
221242542f5fSchristos
221342542f5fSchristos	ptr += box->y1 * in->stride + box->x1;
221442542f5fSchristos
221542542f5fSchristos	h = box->y2 - box->y1;
221642542f5fSchristos	w = box->x2 - box->x1;
221742542f5fSchristos	if ((w | h) == 1) {
221842542f5fSchristos		*ptr = v;
221942542f5fSchristos	} else if (w == 1) {
222042542f5fSchristos		do {
222142542f5fSchristos			*ptr = v;
222242542f5fSchristos			ptr += in->stride;
222342542f5fSchristos		} while (--h);
222442542f5fSchristos	} else do {
222542542f5fSchristos		memset(ptr, v, w);
222642542f5fSchristos		ptr += in->stride;
222742542f5fSchristos	} while (--h);
222842542f5fSchristos}
222942542f5fSchristos
2230fe8aea9eSmrgstruct clipped_span {
2231fe8aea9eSmrg	span_func_t span;
2232fe8aea9eSmrg	const BoxRec *clip_start, *clip_end;
2233fe8aea9eSmrg};
2234fe8aea9eSmrg
2235fe8aea9eSmrgstatic void
2236fe8aea9eSmrgtor_blt_clipped(struct sna *sna,
2237fe8aea9eSmrg		struct sna_composite_spans_op *op,
2238fe8aea9eSmrg		pixman_region16_t *clip,
2239fe8aea9eSmrg		const BoxRec *box,
2240fe8aea9eSmrg		int coverage)
2241fe8aea9eSmrg{
2242fe8aea9eSmrg	struct clipped_span *cs = (struct clipped_span *)clip;
2243fe8aea9eSmrg	const BoxRec *c;
2244fe8aea9eSmrg
2245fe8aea9eSmrg	cs->clip_start =
2246fe8aea9eSmrg		find_clip_box_for_y(cs->clip_start, cs->clip_end, box->y1);
2247fe8aea9eSmrg
2248fe8aea9eSmrg	c = cs->clip_start;
2249fe8aea9eSmrg	while (c != cs->clip_end) {
2250fe8aea9eSmrg		BoxRec clipped;
2251fe8aea9eSmrg
2252fe8aea9eSmrg		if (box->y2 <= c->y1)
2253fe8aea9eSmrg			break;
2254fe8aea9eSmrg
2255fe8aea9eSmrg		clipped = *box;
2256fe8aea9eSmrg		if (!box_intersect(&clipped, c++))
2257fe8aea9eSmrg			continue;
2258fe8aea9eSmrg
2259fe8aea9eSmrg		cs->span(sna, op, NULL, &clipped, coverage);
2260fe8aea9eSmrg	}
2261fe8aea9eSmrg}
2262fe8aea9eSmrg
2263fe8aea9eSmrginline static span_func_t
2264fe8aea9eSmrgclipped_span(struct clipped_span *cs,
2265fe8aea9eSmrg	     span_func_t span,
2266fe8aea9eSmrg	     const RegionRec *clip)
2267fe8aea9eSmrg{
2268fe8aea9eSmrg	if (clip->data) {
2269fe8aea9eSmrg		cs->span = span;
2270fe8aea9eSmrg		region_get_boxes(clip, &cs->clip_start, &cs->clip_end);
2271fe8aea9eSmrg		span = tor_blt_clipped;
2272fe8aea9eSmrg	}
2273fe8aea9eSmrg	return span;
2274fe8aea9eSmrg}
2275fe8aea9eSmrg
227642542f5fSchristosstatic void
227742542f5fSchristostor_blt_src(struct sna *sna,
227842542f5fSchristos	    struct sna_composite_spans_op *op,
227942542f5fSchristos	    pixman_region16_t *clip,
228042542f5fSchristos	    const BoxRec *box,
228142542f5fSchristos	    int coverage)
228242542f5fSchristos{
228342542f5fSchristos	struct inplace *in = (struct inplace *)op;
228442542f5fSchristos
228542542f5fSchristos	_tor_blt_src(in, box, coverage_opacity(coverage, in->opacity));
228642542f5fSchristos}
228742542f5fSchristos
228842542f5fSchristosstatic void
228942542f5fSchristostor_blt_in(struct sna *sna,
229042542f5fSchristos	   struct sna_composite_spans_op *op,
229142542f5fSchristos	   pixman_region16_t *clip,
229242542f5fSchristos	   const BoxRec *box,
229342542f5fSchristos	   int coverage)
229442542f5fSchristos{
229542542f5fSchristos	struct inplace *in = (struct inplace *)op;
229642542f5fSchristos	uint8_t *ptr = in->ptr;
229742542f5fSchristos	int h, w, i;
229842542f5fSchristos
229942542f5fSchristos	if (coverage == 0) {
230042542f5fSchristos		_tor_blt_src(in, box, 0);
230142542f5fSchristos		return;
230242542f5fSchristos	}
230342542f5fSchristos
230442542f5fSchristos	coverage = coverage_opacity(coverage, in->opacity);
230542542f5fSchristos	if (coverage == 0xff)
230642542f5fSchristos		return;
230742542f5fSchristos
230842542f5fSchristos	ptr += box->y1 * in->stride + box->x1;
230942542f5fSchristos
231042542f5fSchristos	h = box->y2 - box->y1;
231142542f5fSchristos	w = box->x2 - box->x1;
231242542f5fSchristos	do {
231342542f5fSchristos		for (i = 0; i < w; i++)
231442542f5fSchristos			ptr[i] = mul_8_8(ptr[i], coverage);
231542542f5fSchristos		ptr += in->stride;
231642542f5fSchristos	} while (--h);
231742542f5fSchristos}
231842542f5fSchristos
231942542f5fSchristosstatic void
232042542f5fSchristostor_blt_add(struct sna *sna,
232142542f5fSchristos	    struct sna_composite_spans_op *op,
232242542f5fSchristos	    pixman_region16_t *clip,
232342542f5fSchristos	    const BoxRec *box,
232442542f5fSchristos	    int coverage)
232542542f5fSchristos{
232642542f5fSchristos	struct inplace *in = (struct inplace *)op;
232742542f5fSchristos	uint8_t *ptr = in->ptr;
232842542f5fSchristos	int h, w, v, i;
232942542f5fSchristos
233042542f5fSchristos	if (coverage == 0)
233142542f5fSchristos		return;
233242542f5fSchristos
233342542f5fSchristos	coverage = coverage_opacity(coverage, in->opacity);
233442542f5fSchristos	if (coverage == 0xff) {
233542542f5fSchristos		_tor_blt_src(in, box, 0xff);
233642542f5fSchristos		return;
233742542f5fSchristos	}
233842542f5fSchristos
233942542f5fSchristos	ptr += box->y1 * in->stride + box->x1;
234042542f5fSchristos
234142542f5fSchristos	h = box->y2 - box->y1;
234242542f5fSchristos	w = box->x2 - box->x1;
234342542f5fSchristos	if ((w | h) == 1) {
234442542f5fSchristos		v = coverage + *ptr;
234542542f5fSchristos		*ptr = v >= 255 ? 255 : v;
234642542f5fSchristos	} else {
234742542f5fSchristos		do {
234842542f5fSchristos			for (i = 0; i < w; i++) {
234942542f5fSchristos				v = coverage + ptr[i];
235042542f5fSchristos				ptr[i] = v >= 255 ? 255 : v;
235142542f5fSchristos			}
235242542f5fSchristos			ptr += in->stride;
235342542f5fSchristos		} while (--h);
235442542f5fSchristos	}
235542542f5fSchristos}
235642542f5fSchristos
235742542f5fSchristosstatic void
235842542f5fSchristostor_blt_lerp32(struct sna *sna,
235942542f5fSchristos	       struct sna_composite_spans_op *op,
236042542f5fSchristos	       pixman_region16_t *clip,
236142542f5fSchristos	       const BoxRec *box,
236242542f5fSchristos	       int coverage)
236342542f5fSchristos{
236442542f5fSchristos	struct inplace *in = (struct inplace *)op;
236542542f5fSchristos	uint32_t *ptr = (uint32_t *)in->ptr;
236642542f5fSchristos	int stride = in->stride / sizeof(uint32_t);
236742542f5fSchristos	int h, w, i;
236842542f5fSchristos
236942542f5fSchristos	if (coverage == 0)
237042542f5fSchristos		return;
237142542f5fSchristos
2372fe8aea9eSmrg	sigtrap_assert_active();
237342542f5fSchristos	ptr += box->y1 * stride + box->x1;
237442542f5fSchristos
237542542f5fSchristos	h = box->y2 - box->y1;
237642542f5fSchristos	w = box->x2 - box->x1;
237742542f5fSchristos	if (coverage == FAST_SAMPLES_XY) {
237842542f5fSchristos		if ((w | h) == 1) {
237942542f5fSchristos			*ptr = in->color;
238042542f5fSchristos		} else {
238142542f5fSchristos			if (w < 16) {
238242542f5fSchristos				do {
238342542f5fSchristos					for (i = 0; i < w; i++)
238442542f5fSchristos						ptr[i] = in->color;
238542542f5fSchristos					ptr += stride;
238642542f5fSchristos				} while (--h);
238742542f5fSchristos			} else {
238842542f5fSchristos				pixman_fill(ptr, stride, 32,
238942542f5fSchristos					    0, 0, w, h, in->color);
239042542f5fSchristos			}
239142542f5fSchristos		}
239242542f5fSchristos	} else {
239342542f5fSchristos		coverage = coverage * 256 / FAST_SAMPLES_XY;
239442542f5fSchristos		coverage -= coverage >> 8;
239542542f5fSchristos
239642542f5fSchristos		if ((w | h) == 1) {
239742542f5fSchristos			*ptr = lerp8x4(in->color, coverage, *ptr);
239842542f5fSchristos		} else if (w == 1) {
239942542f5fSchristos			do {
240042542f5fSchristos				*ptr = lerp8x4(in->color, coverage, *ptr);
240142542f5fSchristos				ptr += stride;
240242542f5fSchristos			} while (--h);
240342542f5fSchristos		} else{
240442542f5fSchristos			do {
240542542f5fSchristos				for (i = 0; i < w; i++)
240642542f5fSchristos					ptr[i] = lerp8x4(in->color, coverage, ptr[i]);
240742542f5fSchristos				ptr += stride;
240842542f5fSchristos			} while (--h);
240942542f5fSchristos		}
241042542f5fSchristos	}
241142542f5fSchristos}
241242542f5fSchristos
241342542f5fSchristosstruct pixman_inplace {
241442542f5fSchristos	pixman_image_t *image, *source, *mask;
241542542f5fSchristos	uint32_t color;
241642542f5fSchristos	uint32_t *bits;
241742542f5fSchristos	int dx, dy;
241842542f5fSchristos	int sx, sy;
241942542f5fSchristos	uint8_t op;
242042542f5fSchristos};
242142542f5fSchristos
242242542f5fSchristosstatic void
242342542f5fSchristospixmask_span_solid(struct sna *sna,
242442542f5fSchristos		   struct sna_composite_spans_op *op,
242542542f5fSchristos		   pixman_region16_t *clip,
242642542f5fSchristos		   const BoxRec *box,
242742542f5fSchristos		   int coverage)
242842542f5fSchristos{
242942542f5fSchristos	struct pixman_inplace *pi = (struct pixman_inplace *)op;
243042542f5fSchristos	if (coverage != FAST_SAMPLES_XY) {
243142542f5fSchristos		coverage = coverage * 256 / FAST_SAMPLES_XY;
243242542f5fSchristos		coverage -= coverage >> 8;
243342542f5fSchristos		*pi->bits = mul_4x8_8(pi->color, coverage);
243442542f5fSchristos	} else
243542542f5fSchristos		*pi->bits = pi->color;
243642542f5fSchristos	pixman_image_composite(pi->op, pi->source, NULL, pi->image,
243742542f5fSchristos			       box->x1, box->y1,
243842542f5fSchristos			       0, 0,
243942542f5fSchristos			       pi->dx + box->x1, pi->dy + box->y1,
244042542f5fSchristos			       box->x2 - box->x1, box->y2 - box->y1);
244142542f5fSchristos}
244242542f5fSchristos
244342542f5fSchristosstatic void
244442542f5fSchristospixmask_span(struct sna *sna,
244542542f5fSchristos	     struct sna_composite_spans_op *op,
244642542f5fSchristos	     pixman_region16_t *clip,
244742542f5fSchristos	     const BoxRec *box,
244842542f5fSchristos	     int coverage)
244942542f5fSchristos{
245042542f5fSchristos	struct pixman_inplace *pi = (struct pixman_inplace *)op;
245142542f5fSchristos	pixman_image_t *mask = NULL;
245242542f5fSchristos	if (coverage != FAST_SAMPLES_XY) {
245342542f5fSchristos		coverage = coverage * 256 / FAST_SAMPLES_XY;
245442542f5fSchristos		coverage -= coverage >> 8;
245542542f5fSchristos		*pi->bits = coverage;
245642542f5fSchristos		mask = pi->mask;
245742542f5fSchristos	}
245842542f5fSchristos	pixman_image_composite(pi->op, pi->source, mask, pi->image,
245942542f5fSchristos			       pi->sx + box->x1, pi->sy + box->y1,
246042542f5fSchristos			       0, 0,
246142542f5fSchristos			       pi->dx + box->x1, pi->dy + box->y1,
246242542f5fSchristos			       box->x2 - box->x1, box->y2 - box->y1);
246342542f5fSchristos}
246442542f5fSchristos
246542542f5fSchristosstruct inplace_x8r8g8b8_thread {
246642542f5fSchristos	xTrapezoid *traps;
246742542f5fSchristos	PicturePtr dst, src;
246842542f5fSchristos	BoxRec extents;
246942542f5fSchristos	int dx, dy;
247042542f5fSchristos	int ntrap;
247142542f5fSchristos	bool lerp, is_solid;
247242542f5fSchristos	uint32_t color;
247342542f5fSchristos	int16_t src_x, src_y;
247442542f5fSchristos	uint8_t op;
247542542f5fSchristos};
247642542f5fSchristos
247742542f5fSchristosstatic void inplace_x8r8g8b8_thread(void *arg)
247842542f5fSchristos{
247942542f5fSchristos	struct inplace_x8r8g8b8_thread *thread = arg;
248042542f5fSchristos	struct tor tor;
248142542f5fSchristos	span_func_t span;
2482fe8aea9eSmrg	struct clipped_span clipped;
248342542f5fSchristos	RegionPtr clip;
248442542f5fSchristos	int y1, y2, n;
248542542f5fSchristos
248642542f5fSchristos	if (!tor_init(&tor, &thread->extents, 2*thread->ntrap))
248742542f5fSchristos		return;
248842542f5fSchristos
248942542f5fSchristos	y1 = thread->extents.y1 - thread->dst->pDrawable->y;
249042542f5fSchristos	y2 = thread->extents.y2 - thread->dst->pDrawable->y;
249142542f5fSchristos	for (n = 0; n < thread->ntrap; n++) {
249242542f5fSchristos		if (pixman_fixed_to_int(thread->traps[n].top) >= y2 ||
249342542f5fSchristos		    pixman_fixed_to_int(thread->traps[n].bottom) < y1)
249442542f5fSchristos			continue;
249542542f5fSchristos
249613496ba1Ssnj		tor_add_trapezoid(&tor, &thread->traps[n], thread->dx, thread->dy);
249742542f5fSchristos	}
249842542f5fSchristos
249942542f5fSchristos	clip = thread->dst->pCompositeClip;
250042542f5fSchristos	if (thread->lerp) {
250142542f5fSchristos		struct inplace inplace;
250242542f5fSchristos		int16_t dst_x, dst_y;
250342542f5fSchristos		PixmapPtr pixmap;
250442542f5fSchristos
250542542f5fSchristos		pixmap = get_drawable_pixmap(thread->dst->pDrawable);
250642542f5fSchristos
250742542f5fSchristos		inplace.ptr = pixmap->devPrivate.ptr;
250842542f5fSchristos		if (get_drawable_deltas(thread->dst->pDrawable, pixmap, &dst_x, &dst_y))
250942542f5fSchristos			inplace.ptr += dst_y * pixmap->devKind + dst_x * 4;
251042542f5fSchristos		inplace.stride = pixmap->devKind;
251142542f5fSchristos		inplace.color = thread->color;
251242542f5fSchristos
2513fe8aea9eSmrg		span = clipped_span(&clipped, tor_blt_lerp32, clip);
251442542f5fSchristos
2515fe8aea9eSmrg		tor_render(NULL, &tor,
2516fe8aea9eSmrg			   (void*)&inplace, (void*)&clipped,
2517fe8aea9eSmrg			   span, false);
251842542f5fSchristos	} else if (thread->is_solid) {
251942542f5fSchristos		struct pixman_inplace pi;
252042542f5fSchristos
252142542f5fSchristos		pi.image = image_from_pict(thread->dst, false, &pi.dx, &pi.dy);
252242542f5fSchristos		pi.op = thread->op;
252342542f5fSchristos		pi.color = thread->color;
252442542f5fSchristos
252542542f5fSchristos		pi.bits = (uint32_t *)&pi.sx;
252642542f5fSchristos		pi.source = pixman_image_create_bits(PIXMAN_a8r8g8b8,
252742542f5fSchristos						     1, 1, pi.bits, 0);
252842542f5fSchristos		pixman_image_set_repeat(pi.source, PIXMAN_REPEAT_NORMAL);
252942542f5fSchristos
2530fe8aea9eSmrg		span = clipped_span(&clipped, pixmask_span_solid, clip);
253142542f5fSchristos
2532fe8aea9eSmrg		tor_render(NULL, &tor,
2533fe8aea9eSmrg			   (void*)&pi, (void *)&clipped,
2534fe8aea9eSmrg			   span, false);
253542542f5fSchristos
253642542f5fSchristos		pixman_image_unref(pi.source);
253742542f5fSchristos		pixman_image_unref(pi.image);
253842542f5fSchristos	} else {
253942542f5fSchristos		struct pixman_inplace pi;
254042542f5fSchristos		int16_t x0, y0;
254142542f5fSchristos
254242542f5fSchristos		trapezoid_origin(&thread->traps[0].left, &x0, &y0);
254342542f5fSchristos
254442542f5fSchristos		pi.image = image_from_pict(thread->dst, false, &pi.dx, &pi.dy);
254542542f5fSchristos		pi.source = image_from_pict(thread->src, false, &pi.sx, &pi.sy);
254642542f5fSchristos		pi.sx += thread->src_x - x0;
254742542f5fSchristos		pi.sy += thread->src_y - y0;
254842542f5fSchristos		pi.mask = pixman_image_create_bits(PIXMAN_a8, 1, 1, NULL, 0);
254942542f5fSchristos		pixman_image_set_repeat(pi.mask, PIXMAN_REPEAT_NORMAL);
255042542f5fSchristos		pi.bits = pixman_image_get_data(pi.mask);
255142542f5fSchristos		pi.op = thread->op;
255242542f5fSchristos
2553fe8aea9eSmrg		span = clipped_span(&clipped, pixmask_span, clip);
255442542f5fSchristos
2555fe8aea9eSmrg		tor_render(NULL, &tor,
2556fe8aea9eSmrg			   (void*)&pi, (void *)&clipped,
2557fe8aea9eSmrg			   span, false);
255842542f5fSchristos
255942542f5fSchristos		pixman_image_unref(pi.mask);
256042542f5fSchristos		pixman_image_unref(pi.source);
256142542f5fSchristos		pixman_image_unref(pi.image);
256242542f5fSchristos	}
256342542f5fSchristos
256442542f5fSchristos	tor_fini(&tor);
256542542f5fSchristos}
256642542f5fSchristos
256742542f5fSchristosstatic bool
256842542f5fSchristostrapezoid_span_inplace__x8r8g8b8(CARD8 op,
256942542f5fSchristos				 PicturePtr dst,
257042542f5fSchristos				 PicturePtr src, int16_t src_x, int16_t src_y,
257142542f5fSchristos				 PictFormatPtr maskFormat,
257242542f5fSchristos				 int ntrap, xTrapezoid *traps)
257342542f5fSchristos{
257442542f5fSchristos	uint32_t color;
257542542f5fSchristos	bool lerp, is_solid;
257642542f5fSchristos	RegionRec region;
257742542f5fSchristos	int dx, dy;
257842542f5fSchristos	int num_threads, n;
257942542f5fSchristos
258042542f5fSchristos	lerp = false;
258142542f5fSchristos	is_solid = sna_picture_is_solid(src, &color);
258242542f5fSchristos	if (is_solid) {
258342542f5fSchristos		if (op == PictOpOver && (color >> 24) == 0xff)
258442542f5fSchristos			op = PictOpSrc;
258542542f5fSchristos		if (op == PictOpOver && sna_drawable_is_clear(dst->pDrawable))
258642542f5fSchristos			op = PictOpSrc;
258742542f5fSchristos		lerp = op == PictOpSrc;
258842542f5fSchristos	}
258942542f5fSchristos	if (!lerp) {
259042542f5fSchristos		switch (op) {
259142542f5fSchristos		case PictOpOver:
259242542f5fSchristos		case PictOpAdd:
259342542f5fSchristos		case PictOpOutReverse:
259442542f5fSchristos			break;
259542542f5fSchristos		case PictOpSrc:
259642542f5fSchristos			if (!sna_drawable_is_clear(dst->pDrawable))
259742542f5fSchristos				return false;
259842542f5fSchristos			break;
259942542f5fSchristos		default:
260042542f5fSchristos			return false;
260142542f5fSchristos		}
260242542f5fSchristos	}
260342542f5fSchristos
260442542f5fSchristos	if (maskFormat == NULL && ntrap > 1) {
260542542f5fSchristos		DBG(("%s: individual rasterisation requested\n",
260642542f5fSchristos		     __FUNCTION__));
260742542f5fSchristos		do {
260842542f5fSchristos			/* XXX unwind errors? */
260942542f5fSchristos			if (!trapezoid_span_inplace__x8r8g8b8(op, dst,
261042542f5fSchristos							      src, src_x, src_y,
261142542f5fSchristos							      NULL, 1, traps++))
261242542f5fSchristos				return false;
261342542f5fSchristos		} while (--ntrap);
261442542f5fSchristos		return true;
261542542f5fSchristos	}
261642542f5fSchristos
261742542f5fSchristos	if (!trapezoids_bounds(ntrap, traps, &region.extents))
261842542f5fSchristos		return true;
261942542f5fSchristos
262042542f5fSchristos	DBG(("%s: extents (%d, %d), (%d, %d)\n",
262142542f5fSchristos	     __FUNCTION__,
262242542f5fSchristos	     region.extents.x1, region.extents.y1,
262342542f5fSchristos	     region.extents.x2, region.extents.y2));
262442542f5fSchristos
262542542f5fSchristos	if (!sna_compute_composite_extents(&region.extents,
262642542f5fSchristos					   src, NULL, dst,
262742542f5fSchristos					   src_x, src_y,
262842542f5fSchristos					   0, 0,
262942542f5fSchristos					   region.extents.x1, region.extents.y1,
263042542f5fSchristos					   region.extents.x2 - region.extents.x1,
263142542f5fSchristos					   region.extents.y2 - region.extents.y1))
263242542f5fSchristos		return true;
263342542f5fSchristos
263442542f5fSchristos	DBG(("%s: clipped extents (%d, %d), (%d, %d)\n",
263542542f5fSchristos	     __FUNCTION__,
263642542f5fSchristos	     region.extents.x1, region.extents.y1,
263742542f5fSchristos	     region.extents.x2, region.extents.y2));
263842542f5fSchristos
263942542f5fSchristos	region.data = NULL;
264042542f5fSchristos	if (!sna_drawable_move_region_to_cpu(dst->pDrawable, &region,
264142542f5fSchristos					    MOVE_WRITE | MOVE_READ))
264242542f5fSchristos		return true;
264342542f5fSchristos
264442542f5fSchristos	if (!is_solid && src->pDrawable) {
264542542f5fSchristos		if (!sna_drawable_move_to_cpu(src->pDrawable,
264642542f5fSchristos					      MOVE_READ))
264742542f5fSchristos			return true;
264842542f5fSchristos
264942542f5fSchristos		if (src->alphaMap &&
265042542f5fSchristos		    !sna_drawable_move_to_cpu(src->alphaMap->pDrawable,
265142542f5fSchristos					      MOVE_READ))
265242542f5fSchristos			return true;
265342542f5fSchristos	}
265442542f5fSchristos
265542542f5fSchristos	dx = dst->pDrawable->x * FAST_SAMPLES_X;
265642542f5fSchristos	dy = dst->pDrawable->y * FAST_SAMPLES_Y;
265742542f5fSchristos
265842542f5fSchristos	num_threads = sna_use_threads(4*(region.extents.x2 - region.extents.x1),
265942542f5fSchristos				      region.extents.y2 - region.extents.y1,
266042542f5fSchristos				      16);
266142542f5fSchristos
266242542f5fSchristos	DBG(("%s: %dx%d, format=%x, op=%d, lerp?=%d, num_threads=%d\n",
266342542f5fSchristos	     __FUNCTION__,
266442542f5fSchristos	     region.extents.x2 - region.extents.x1,
266542542f5fSchristos	     region.extents.y2 - region.extents.y1,
266642542f5fSchristos	     dst->format, op, lerp, num_threads));
266742542f5fSchristos
266842542f5fSchristos	if (num_threads == 1) {
266942542f5fSchristos		struct tor tor;
267042542f5fSchristos		span_func_t span;
2671fe8aea9eSmrg		struct clipped_span clipped;
267242542f5fSchristos
267342542f5fSchristos		if (!tor_init(&tor, &region.extents, 2*ntrap))
267442542f5fSchristos			return true;
267542542f5fSchristos
267642542f5fSchristos		for (n = 0; n < ntrap; n++) {
267742542f5fSchristos			if (pixman_fixed_to_int(traps[n].top) >= region.extents.y2 - dst->pDrawable->y ||
267842542f5fSchristos			    pixman_fixed_to_int(traps[n].bottom) < region.extents.y1 - dst->pDrawable->y)
267942542f5fSchristos				continue;
268042542f5fSchristos
268113496ba1Ssnj			tor_add_trapezoid(&tor, &traps[n], dx, dy);
268242542f5fSchristos		}
268342542f5fSchristos
268442542f5fSchristos		if (lerp) {
268542542f5fSchristos			struct inplace inplace;
268642542f5fSchristos			PixmapPtr pixmap;
268742542f5fSchristos			int16_t dst_x, dst_y;
268842542f5fSchristos
268942542f5fSchristos			pixmap = get_drawable_pixmap(dst->pDrawable);
269042542f5fSchristos
269142542f5fSchristos			inplace.ptr = pixmap->devPrivate.ptr;
269242542f5fSchristos			if (get_drawable_deltas(dst->pDrawable, pixmap, &dst_x, &dst_y))
269342542f5fSchristos				inplace.ptr += dst_y * pixmap->devKind + dst_x * 4;
269442542f5fSchristos			inplace.stride = pixmap->devKind;
269542542f5fSchristos			inplace.color = color;
269642542f5fSchristos
2697fe8aea9eSmrg			span = clipped_span(&clipped, tor_blt_lerp32, dst->pCompositeClip);
269842542f5fSchristos
269942542f5fSchristos			DBG(("%s: render inplace op=%d, color=%08x\n",
270042542f5fSchristos			     __FUNCTION__, op, color));
270142542f5fSchristos
270242542f5fSchristos			if (sigtrap_get() == 0) {
2703fe8aea9eSmrg				tor_render(NULL, &tor,
2704fe8aea9eSmrg					   (void*)&inplace, (void*)&clipped,
2705fe8aea9eSmrg					   span, false);
270642542f5fSchristos				sigtrap_put();
270742542f5fSchristos			}
270842542f5fSchristos		} else if (is_solid) {
270942542f5fSchristos			struct pixman_inplace pi;
271042542f5fSchristos
271142542f5fSchristos			pi.image = image_from_pict(dst, false, &pi.dx, &pi.dy);
271242542f5fSchristos			pi.op = op;
271342542f5fSchristos			pi.color = color;
271442542f5fSchristos
271542542f5fSchristos			pi.bits = (uint32_t *)&pi.sx;
271642542f5fSchristos			pi.source = pixman_image_create_bits(PIXMAN_a8r8g8b8,
271742542f5fSchristos							     1, 1, pi.bits, 0);
271842542f5fSchristos			pixman_image_set_repeat(pi.source, PIXMAN_REPEAT_NORMAL);
271942542f5fSchristos
2720fe8aea9eSmrg			span = clipped_span(&clipped, pixmask_span_solid, dst->pCompositeClip);
272142542f5fSchristos
272242542f5fSchristos			if (sigtrap_get() == 0) {
2723fe8aea9eSmrg				tor_render(NULL, &tor,
2724fe8aea9eSmrg					   (void*)&pi, (void*)&clipped,
2725fe8aea9eSmrg					   span, false);
272642542f5fSchristos				sigtrap_put();
272742542f5fSchristos			}
272842542f5fSchristos
272942542f5fSchristos			pixman_image_unref(pi.source);
273042542f5fSchristos			pixman_image_unref(pi.image);
273142542f5fSchristos		} else {
273242542f5fSchristos			struct pixman_inplace pi;
273342542f5fSchristos			int16_t x0, y0;
273442542f5fSchristos
273542542f5fSchristos			trapezoid_origin(&traps[0].left, &x0, &y0);
273642542f5fSchristos
273742542f5fSchristos			pi.image = image_from_pict(dst, false, &pi.dx, &pi.dy);
273842542f5fSchristos			pi.source = image_from_pict(src, false, &pi.sx, &pi.sy);
273942542f5fSchristos			pi.sx += src_x - x0;
274042542f5fSchristos			pi.sy += src_y - y0;
274142542f5fSchristos			pi.mask = pixman_image_create_bits(PIXMAN_a8, 1, 1, NULL, 0);
274242542f5fSchristos			pixman_image_set_repeat(pi.mask, PIXMAN_REPEAT_NORMAL);
274342542f5fSchristos			pi.bits = pixman_image_get_data(pi.mask);
274442542f5fSchristos			pi.op = op;
274542542f5fSchristos
2746fe8aea9eSmrg			span = clipped_span(&clipped, pixmask_span, dst->pCompositeClip);
274742542f5fSchristos
274842542f5fSchristos			if (sigtrap_get() == 0) {
2749fe8aea9eSmrg				tor_render(NULL, &tor,
2750fe8aea9eSmrg					   (void*)&pi, (void*)&clipped,
2751fe8aea9eSmrg					   span, false);
275242542f5fSchristos				sigtrap_put();
275342542f5fSchristos			}
275442542f5fSchristos
275542542f5fSchristos			pixman_image_unref(pi.mask);
275642542f5fSchristos			pixman_image_unref(pi.source);
275742542f5fSchristos			pixman_image_unref(pi.image);
275842542f5fSchristos		}
275942542f5fSchristos
276042542f5fSchristos		tor_fini(&tor);
276142542f5fSchristos	} else {
276242542f5fSchristos		struct inplace_x8r8g8b8_thread threads[num_threads];
276342542f5fSchristos		int y, h;
276442542f5fSchristos
276542542f5fSchristos		DBG(("%s: using %d threads for inplace compositing %dx%d\n",
276642542f5fSchristos		     __FUNCTION__, num_threads,
276742542f5fSchristos		     region.extents.x2 - region.extents.x1,
276842542f5fSchristos		     region.extents.y2 - region.extents.y1));
276942542f5fSchristos
277042542f5fSchristos		threads[0].traps = traps;
277142542f5fSchristos		threads[0].ntrap = ntrap;
277242542f5fSchristos		threads[0].extents = region.extents;
277342542f5fSchristos		threads[0].lerp = lerp;
277442542f5fSchristos		threads[0].is_solid = is_solid;
277542542f5fSchristos		threads[0].color = color;
277642542f5fSchristos		threads[0].dx = dx;
277742542f5fSchristos		threads[0].dy = dy;
277842542f5fSchristos		threads[0].dst = dst;
277942542f5fSchristos		threads[0].src = src;
278042542f5fSchristos		threads[0].op = op;
278142542f5fSchristos		threads[0].src_x = src_x;
278242542f5fSchristos		threads[0].src_y = src_y;
278342542f5fSchristos
278442542f5fSchristos		y = region.extents.y1;
278542542f5fSchristos		h = region.extents.y2 - region.extents.y1;
278642542f5fSchristos		h = (h + num_threads - 1) / num_threads;
278742542f5fSchristos		num_threads -= (num_threads-1) * h >= region.extents.y2 - region.extents.y1;
278842542f5fSchristos
278942542f5fSchristos		if (sigtrap_get() == 0) {
279042542f5fSchristos			for (n = 1; n < num_threads; n++) {
279142542f5fSchristos				threads[n] = threads[0];
279242542f5fSchristos				threads[n].extents.y1 = y;
279342542f5fSchristos				threads[n].extents.y2 = y += h;
279442542f5fSchristos
279542542f5fSchristos				sna_threads_run(n, inplace_x8r8g8b8_thread, &threads[n]);
279642542f5fSchristos			}
279742542f5fSchristos
279842542f5fSchristos			assert(y < threads[0].extents.y2);
279942542f5fSchristos			threads[0].extents.y1 = y;
280042542f5fSchristos			inplace_x8r8g8b8_thread(&threads[0]);
280142542f5fSchristos
280242542f5fSchristos			sna_threads_wait();
280342542f5fSchristos			sigtrap_put();
280442542f5fSchristos		} else
280542542f5fSchristos			sna_threads_kill(); /* leaks thread allocations */
280642542f5fSchristos	}
280742542f5fSchristos
280842542f5fSchristos	return true;
280942542f5fSchristos}
281042542f5fSchristos
281142542f5fSchristosstruct inplace_thread {
281242542f5fSchristos	xTrapezoid *traps;
281342542f5fSchristos	span_func_t span;
281442542f5fSchristos	struct inplace inplace;
2815fe8aea9eSmrg	struct clipped_span clipped;
281642542f5fSchristos	BoxRec extents;
281742542f5fSchristos	int dx, dy;
281842542f5fSchristos	int draw_x, draw_y;
281942542f5fSchristos	bool unbounded;
282042542f5fSchristos	int ntrap;
282142542f5fSchristos};
282242542f5fSchristos
282342542f5fSchristosstatic void inplace_thread(void *arg)
282442542f5fSchristos{
282542542f5fSchristos	struct inplace_thread *thread = arg;
282642542f5fSchristos	struct tor tor;
282742542f5fSchristos	int n;
282842542f5fSchristos
282942542f5fSchristos	if (!tor_init(&tor, &thread->extents, 2*thread->ntrap))
283042542f5fSchristos		return;
283142542f5fSchristos
283242542f5fSchristos	for (n = 0; n < thread->ntrap; n++) {
283342542f5fSchristos		if (pixman_fixed_to_int(thread->traps[n].top) >= thread->extents.y2 - thread->draw_y ||
283442542f5fSchristos		    pixman_fixed_to_int(thread->traps[n].bottom) < thread->extents.y1 - thread->draw_y)
283542542f5fSchristos			continue;
283642542f5fSchristos
283713496ba1Ssnj		tor_add_trapezoid(&tor, &thread->traps[n], thread->dx, thread->dy);
283842542f5fSchristos	}
283942542f5fSchristos
2840fe8aea9eSmrg	tor_render(NULL, &tor,
2841fe8aea9eSmrg		   (void*)&thread->inplace, (void*)&thread->clipped,
2842fe8aea9eSmrg		   thread->span, thread->unbounded);
284342542f5fSchristos
284442542f5fSchristos	tor_fini(&tor);
284542542f5fSchristos}
284642542f5fSchristos
284742542f5fSchristosbool
284842542f5fSchristosimprecise_trapezoid_span_inplace(struct sna *sna,
284942542f5fSchristos				 CARD8 op, PicturePtr src, PicturePtr dst,
285042542f5fSchristos				 PictFormatPtr maskFormat, unsigned flags,
285142542f5fSchristos				 INT16 src_x, INT16 src_y,
285242542f5fSchristos				 int ntrap, xTrapezoid *traps,
285342542f5fSchristos				 bool fallback)
285442542f5fSchristos{
285542542f5fSchristos	struct inplace inplace;
2856fe8aea9eSmrg	struct clipped_span clipped;
285742542f5fSchristos	span_func_t span;
285842542f5fSchristos	PixmapPtr pixmap;
285942542f5fSchristos	struct sna_pixmap *priv;
286042542f5fSchristos	RegionRec region;
286142542f5fSchristos	uint32_t color;
286242542f5fSchristos	bool unbounded;
286342542f5fSchristos	int16_t dst_x, dst_y;
286442542f5fSchristos	int dx, dy;
286542542f5fSchristos	int num_threads, n;
286642542f5fSchristos
286742542f5fSchristos	if (NO_IMPRECISE)
286842542f5fSchristos		return false;
286942542f5fSchristos
287042542f5fSchristos	if (dst->format == PICT_a8r8g8b8 || dst->format == PICT_x8r8g8b8)
287142542f5fSchristos		return trapezoid_span_inplace__x8r8g8b8(op, dst,
287242542f5fSchristos							src, src_x, src_y,
287342542f5fSchristos							maskFormat,
287442542f5fSchristos							ntrap, traps);
287542542f5fSchristos
287642542f5fSchristos	if (!sna_picture_is_solid(src, &color)) {
287742542f5fSchristos		DBG(("%s: fallback -- can not perform operation in place, requires solid source\n",
287842542f5fSchristos		     __FUNCTION__));
287942542f5fSchristos		return false;
288042542f5fSchristos	}
288142542f5fSchristos
288242542f5fSchristos	if (dst->format != PICT_a8) {
288342542f5fSchristos		DBG(("%s: fallback -- can not perform operation in place, format=%x\n",
288442542f5fSchristos		     __FUNCTION__, dst->format));
288542542f5fSchristos		return false;
288642542f5fSchristos	}
288742542f5fSchristos
288842542f5fSchristos	pixmap = get_drawable_pixmap(dst->pDrawable);
288942542f5fSchristos
289042542f5fSchristos	unbounded = false;
289142542f5fSchristos	priv = sna_pixmap(pixmap);
289242542f5fSchristos	if (priv) {
289342542f5fSchristos		switch (op) {
289442542f5fSchristos		case PictOpAdd:
289542542f5fSchristos			if (priv->clear && priv->clear_color == 0) {
289642542f5fSchristos				unbounded = true;
289742542f5fSchristos				op = PictOpSrc;
289842542f5fSchristos			}
289942542f5fSchristos			if ((color >> 24) == 0)
290042542f5fSchristos				return true;
290142542f5fSchristos			break;
290242542f5fSchristos		case PictOpIn:
290342542f5fSchristos			if (priv->clear && priv->clear_color == 0)
290442542f5fSchristos				return true;
290542542f5fSchristos			if (priv->clear && priv->clear_color == 0xff)
290642542f5fSchristos				op = PictOpSrc;
290742542f5fSchristos			unbounded = true;
290842542f5fSchristos			break;
290942542f5fSchristos		case PictOpSrc:
291042542f5fSchristos			unbounded = true;
291142542f5fSchristos			break;
291242542f5fSchristos		default:
291342542f5fSchristos			DBG(("%s: fallback -- can not perform op [%d] in place\n",
291442542f5fSchristos			     __FUNCTION__, op));
291542542f5fSchristos			return false;
291642542f5fSchristos		}
291742542f5fSchristos	} else {
291842542f5fSchristos		switch (op) {
291942542f5fSchristos		case PictOpAdd:
292042542f5fSchristos			if ((color >> 24) == 0)
292142542f5fSchristos				return true;
292242542f5fSchristos			break;
292342542f5fSchristos		case PictOpIn:
292442542f5fSchristos		case PictOpSrc:
292542542f5fSchristos			unbounded = true;
292642542f5fSchristos			break;
292742542f5fSchristos		default:
292842542f5fSchristos			DBG(("%s: fallback -- can not perform op [%d] in place\n",
292942542f5fSchristos			     __FUNCTION__, op));
293042542f5fSchristos			return false;
293142542f5fSchristos		}
293242542f5fSchristos	}
293342542f5fSchristos
293442542f5fSchristos	DBG(("%s: format=%x, op=%d, color=%x\n",
293542542f5fSchristos	     __FUNCTION__, dst->format, op, color));
293642542f5fSchristos
293742542f5fSchristos	if (maskFormat == NULL && ntrap > 1) {
293842542f5fSchristos		DBG(("%s: individual rasterisation requested\n",
293942542f5fSchristos		     __FUNCTION__));
294042542f5fSchristos		do {
294142542f5fSchristos			/* XXX unwind errors? */
294242542f5fSchristos			if (!imprecise_trapezoid_span_inplace(sna, op, src, dst, NULL, flags,
294342542f5fSchristos							      src_x, src_y, 1, traps++,
294442542f5fSchristos							      fallback))
294542542f5fSchristos				return false;
294642542f5fSchristos		} while (--ntrap);
294742542f5fSchristos		return true;
294842542f5fSchristos	}
294942542f5fSchristos
295042542f5fSchristos	if (!trapezoids_bounds(ntrap, traps, &region.extents))
295142542f5fSchristos		return true;
295242542f5fSchristos
295342542f5fSchristos	DBG(("%s: extents (%d, %d), (%d, %d)\n",
295442542f5fSchristos	     __FUNCTION__,
295542542f5fSchristos	     region.extents.x1, region.extents.y1,
295642542f5fSchristos	     region.extents.x2, region.extents.y2));
295742542f5fSchristos
295842542f5fSchristos	if (!sna_compute_composite_extents(&region.extents,
295942542f5fSchristos					   NULL, NULL, dst,
296042542f5fSchristos					   0, 0,
296142542f5fSchristos					   0, 0,
296242542f5fSchristos					   region.extents.x1, region.extents.y1,
296342542f5fSchristos					   region.extents.x2 - region.extents.x1,
296442542f5fSchristos					   region.extents.y2 - region.extents.y1))
296542542f5fSchristos		return true;
296642542f5fSchristos
296742542f5fSchristos	DBG(("%s: clipped extents (%d, %d), (%d, %d)\n",
296842542f5fSchristos	     __FUNCTION__,
296942542f5fSchristos	     region.extents.x1, region.extents.y1,
297042542f5fSchristos	     region.extents.x2, region.extents.y2));
297142542f5fSchristos
297242542f5fSchristos	if (op == PictOpSrc) {
2973fe8aea9eSmrg		span = tor_blt_src;
297442542f5fSchristos	} else if (op == PictOpIn) {
2975fe8aea9eSmrg		span = tor_blt_in;
297642542f5fSchristos	} else {
297742542f5fSchristos		assert(op == PictOpAdd);
2978fe8aea9eSmrg		span = tor_blt_add;
297942542f5fSchristos	}
298042542f5fSchristos
298142542f5fSchristos	DBG(("%s: move-to-cpu\n", __FUNCTION__));
298242542f5fSchristos	region.data = NULL;
298342542f5fSchristos	if (!sna_drawable_move_region_to_cpu(dst->pDrawable, &region,
298442542f5fSchristos					     op == PictOpSrc ? MOVE_WRITE | MOVE_INPLACE_HINT : MOVE_WRITE | MOVE_READ))
298542542f5fSchristos		return true;
298642542f5fSchristos
298742542f5fSchristos	dx = dst->pDrawable->x * FAST_SAMPLES_X;
298842542f5fSchristos	dy = dst->pDrawable->y * FAST_SAMPLES_Y;
298942542f5fSchristos
299042542f5fSchristos	inplace.ptr = pixmap->devPrivate.ptr;
299142542f5fSchristos	if (get_drawable_deltas(dst->pDrawable, pixmap, &dst_x, &dst_y))
299242542f5fSchristos		inplace.ptr += dst_y * pixmap->devKind + dst_x;
299342542f5fSchristos	inplace.stride = pixmap->devKind;
299442542f5fSchristos	inplace.opacity = color >> 24;
299542542f5fSchristos
2996fe8aea9eSmrg	span = clipped_span(&clipped, span, dst->pCompositeClip);
2997fe8aea9eSmrg
299842542f5fSchristos	num_threads = 1;
299942542f5fSchristos	if ((flags & COMPOSITE_SPANS_RECTILINEAR) == 0)
300042542f5fSchristos		num_threads = sna_use_threads(region.extents.x2 - region.extents.x1,
300142542f5fSchristos					      region.extents.y2 - region.extents.y1,
300242542f5fSchristos					      16);
300342542f5fSchristos	if (num_threads == 1) {
300442542f5fSchristos		struct tor tor;
300542542f5fSchristos
300642542f5fSchristos		if (!tor_init(&tor, &region.extents, 2*ntrap))
300742542f5fSchristos			return true;
300842542f5fSchristos
300942542f5fSchristos		for (n = 0; n < ntrap; n++) {
301042542f5fSchristos			if (pixman_fixed_to_int(traps[n].top) >= region.extents.y2 - dst->pDrawable->y ||
301142542f5fSchristos			    pixman_fixed_to_int(traps[n].bottom) < region.extents.y1 - dst->pDrawable->y)
301242542f5fSchristos				continue;
301342542f5fSchristos
301413496ba1Ssnj			tor_add_trapezoid(&tor, &traps[n], dx, dy);
301542542f5fSchristos		}
301642542f5fSchristos
301742542f5fSchristos		if (sigtrap_get() == 0) {
3018fe8aea9eSmrg			tor_render(NULL, &tor,
3019fe8aea9eSmrg				   (void*)&inplace, (void *)&clipped,
3020fe8aea9eSmrg				   span, unbounded);
302142542f5fSchristos			sigtrap_put();
302242542f5fSchristos		}
302342542f5fSchristos
302442542f5fSchristos		tor_fini(&tor);
302542542f5fSchristos	} else {
302642542f5fSchristos		struct inplace_thread threads[num_threads];
302742542f5fSchristos		int y, h;
302842542f5fSchristos
302942542f5fSchristos		DBG(("%s: using %d threads for inplace compositing %dx%d\n",
303042542f5fSchristos		     __FUNCTION__, num_threads,
303142542f5fSchristos		     region.extents.x2 - region.extents.x1,
303242542f5fSchristos		     region.extents.y2 - region.extents.y1));
303342542f5fSchristos
303442542f5fSchristos		threads[0].traps = traps;
303542542f5fSchristos		threads[0].ntrap = ntrap;
303642542f5fSchristos		threads[0].inplace = inplace;
3037fe8aea9eSmrg		threads[0].clipped = clipped;
303842542f5fSchristos		threads[0].extents = region.extents;
303942542f5fSchristos		threads[0].span = span;
304042542f5fSchristos		threads[0].unbounded = unbounded;
304142542f5fSchristos		threads[0].dx = dx;
304242542f5fSchristos		threads[0].dy = dy;
304342542f5fSchristos		threads[0].draw_x = dst->pDrawable->x;
304442542f5fSchristos		threads[0].draw_y = dst->pDrawable->y;
304542542f5fSchristos
304642542f5fSchristos		y = region.extents.y1;
304742542f5fSchristos		h = region.extents.y2 - region.extents.y1;
304842542f5fSchristos		h = (h + num_threads - 1) / num_threads;
304942542f5fSchristos		num_threads -= (num_threads-1) * h >= region.extents.y2 - region.extents.y1;
305042542f5fSchristos
305142542f5fSchristos		if (sigtrap_get() == 0) {
305242542f5fSchristos			for (n = 1; n < num_threads; n++) {
305342542f5fSchristos				threads[n] = threads[0];
305442542f5fSchristos				threads[n].extents.y1 = y;
305542542f5fSchristos				threads[n].extents.y2 = y += h;
305642542f5fSchristos
305742542f5fSchristos				sna_threads_run(n, inplace_thread, &threads[n]);
305842542f5fSchristos			}
305942542f5fSchristos
306042542f5fSchristos			assert(y < threads[0].extents.y2);
306142542f5fSchristos			threads[0].extents.y1 = y;
306242542f5fSchristos			inplace_thread(&threads[0]);
306342542f5fSchristos
306442542f5fSchristos			sna_threads_wait();
306542542f5fSchristos			sigtrap_put();
306642542f5fSchristos		} else
306742542f5fSchristos			sna_threads_kill(); /* leaks thread allocations */
306842542f5fSchristos	}
306942542f5fSchristos
307042542f5fSchristos	return true;
307142542f5fSchristos}
307242542f5fSchristos
307342542f5fSchristosbool
307442542f5fSchristosimprecise_trapezoid_span_fallback(CARD8 op, PicturePtr src, PicturePtr dst,
307542542f5fSchristos				  PictFormatPtr maskFormat, unsigned flags,
307642542f5fSchristos				  INT16 src_x, INT16 src_y,
307742542f5fSchristos				  int ntrap, xTrapezoid *traps)
307842542f5fSchristos{
307942542f5fSchristos	struct tor tor;
308042542f5fSchristos	ScreenPtr screen = dst->pDrawable->pScreen;
308142542f5fSchristos	PixmapPtr scratch;
308242542f5fSchristos	PicturePtr mask;
308342542f5fSchristos	BoxRec extents;
308442542f5fSchristos	int16_t dst_x, dst_y;
308542542f5fSchristos	int dx, dy;
308642542f5fSchristos	int error, n;
308742542f5fSchristos
308842542f5fSchristos	if (NO_IMPRECISE)
308942542f5fSchristos		return false;
309042542f5fSchristos
309142542f5fSchristos	if (maskFormat == NULL && ntrap > 1) {
309242542f5fSchristos		DBG(("%s: individual rasterisation requested\n",
309342542f5fSchristos		     __FUNCTION__));
309442542f5fSchristos		do {
309542542f5fSchristos			/* XXX unwind errors? */
309642542f5fSchristos			if (!imprecise_trapezoid_span_fallback(op, src, dst, NULL, flags,
309742542f5fSchristos							       src_x, src_y, 1, traps++))
309842542f5fSchristos				return false;
309942542f5fSchristos		} while (--ntrap);
310042542f5fSchristos		return true;
310142542f5fSchristos	}
310242542f5fSchristos
310342542f5fSchristos	if (!trapezoids_bounds(ntrap, traps, &extents))
310442542f5fSchristos		return true;
310542542f5fSchristos
310642542f5fSchristos	DBG(("%s: ntraps=%d, extents (%d, %d), (%d, %d)\n",
310742542f5fSchristos	     __FUNCTION__, ntrap, extents.x1, extents.y1, extents.x2, extents.y2));
310842542f5fSchristos
310942542f5fSchristos	if (!sna_compute_composite_extents(&extents,
311042542f5fSchristos					   src, NULL, dst,
311142542f5fSchristos					   src_x, src_y,
311242542f5fSchristos					   0, 0,
311342542f5fSchristos					   extents.x1, extents.y1,
311442542f5fSchristos					   extents.x2 - extents.x1,
311542542f5fSchristos					   extents.y2 - extents.y1))
311642542f5fSchristos		return true;
311742542f5fSchristos
311842542f5fSchristos	DBG(("%s: extents (%d, %d), (%d, %d)\n",
311942542f5fSchristos	     __FUNCTION__, extents.x1, extents.y1, extents.x2, extents.y2));
312042542f5fSchristos
312142542f5fSchristos	extents.y2 -= extents.y1;
312242542f5fSchristos	extents.x2 -= extents.x1;
312342542f5fSchristos	extents.x1 -= dst->pDrawable->x;
312442542f5fSchristos	extents.y1 -= dst->pDrawable->y;
312542542f5fSchristos	dst_x = extents.x1;
312642542f5fSchristos	dst_y = extents.y1;
312742542f5fSchristos	dx = -extents.x1 * FAST_SAMPLES_X;
312842542f5fSchristos	dy = -extents.y1 * FAST_SAMPLES_Y;
312942542f5fSchristos	extents.x1 = extents.y1 = 0;
313042542f5fSchristos
313142542f5fSchristos	DBG(("%s: mask (%dx%d), dx=(%d, %d)\n",
313242542f5fSchristos	     __FUNCTION__, extents.x2, extents.y2, dx, dy));
313342542f5fSchristos	scratch = sna_pixmap_create_unattached(screen,
313442542f5fSchristos					       extents.x2, extents.y2, 8);
313542542f5fSchristos	if (!scratch)
313642542f5fSchristos		return true;
313742542f5fSchristos
313842542f5fSchristos	DBG(("%s: created buffer %p, stride %d\n",
313942542f5fSchristos	     __FUNCTION__, scratch->devPrivate.ptr, scratch->devKind));
314042542f5fSchristos
314142542f5fSchristos	if (!tor_init(&tor, &extents, 2*ntrap)) {
314242542f5fSchristos		sna_pixmap_destroy(scratch);
314342542f5fSchristos		return true;
314442542f5fSchristos	}
314542542f5fSchristos
314642542f5fSchristos	for (n = 0; n < ntrap; n++) {
314742542f5fSchristos		if (pixman_fixed_to_int(traps[n].top) - dst_y >= extents.y2 ||
314842542f5fSchristos		    pixman_fixed_to_int(traps[n].bottom) - dst_y < 0)
314942542f5fSchristos			continue;
315042542f5fSchristos
315113496ba1Ssnj		tor_add_trapezoid(&tor, &traps[n], dx, dy);
315242542f5fSchristos	}
315342542f5fSchristos
315442542f5fSchristos	if (extents.x2 <= TOR_INPLACE_SIZE) {
315542542f5fSchristos		tor_inplace(&tor, scratch, is_mono(dst, maskFormat), NULL);
315642542f5fSchristos	} else {
315742542f5fSchristos		tor_render(NULL, &tor,
315842542f5fSchristos			   scratch->devPrivate.ptr,
315942542f5fSchristos			   (void *)(intptr_t)scratch->devKind,
316042542f5fSchristos			   is_mono(dst, maskFormat) ? tor_blt_mask_mono : tor_blt_mask,
316142542f5fSchristos			   true);
316242542f5fSchristos	}
316342542f5fSchristos	tor_fini(&tor);
316442542f5fSchristos
316542542f5fSchristos	mask = CreatePicture(0, &scratch->drawable,
316642542f5fSchristos			     PictureMatchFormat(screen, 8, PICT_a8),
316742542f5fSchristos			     0, 0, serverClient, &error);
316842542f5fSchristos	if (mask) {
316942542f5fSchristos		RegionRec region;
317042542f5fSchristos		int16_t x0, y0;
317142542f5fSchristos
317242542f5fSchristos		region.extents.x1 = dst_x + dst->pDrawable->x;
317342542f5fSchristos		region.extents.y1 = dst_y + dst->pDrawable->y;
317442542f5fSchristos		region.extents.x2 = region.extents.x1 + extents.x2;
317542542f5fSchristos		region.extents.y2 = region.extents.y1 + extents.y2;
317642542f5fSchristos		region.data = NULL;
317742542f5fSchristos
317842542f5fSchristos		trapezoid_origin(&traps[0].left, &x0, &y0);
317942542f5fSchristos
318042542f5fSchristos		DBG(("%s: fbComposite()\n", __FUNCTION__));
318142542f5fSchristos		sna_composite_fb(op, src, mask, dst, &region,
318242542f5fSchristos				 src_x + dst_x - x0, src_y + dst_y - y0,
318342542f5fSchristos				 0, 0,
318442542f5fSchristos				 dst_x, dst_y,
318542542f5fSchristos				 extents.x2, extents.y2);
318642542f5fSchristos
318742542f5fSchristos		FreePicture(mask, 0);
318842542f5fSchristos	}
318942542f5fSchristos	sna_pixmap_destroy(scratch);
319042542f5fSchristos
319142542f5fSchristos	return true;
319242542f5fSchristos}
319342542f5fSchristos
319442542f5fSchristosbool
319513496ba1Ssnjimprecise_trap_span_converter(struct sna *sna,
319613496ba1Ssnj			      PicturePtr dst,
319713496ba1Ssnj			      INT16 src_x, INT16 src_y,
319813496ba1Ssnj			      int ntrap, xTrap *trap)
319942542f5fSchristos{
320042542f5fSchristos	struct sna_composite_spans_op tmp;
320142542f5fSchristos	struct tor tor;
320242542f5fSchristos	BoxRec extents;
320342542f5fSchristos	pixman_region16_t *clip;
320442542f5fSchristos	int dx, dy, n;
320542542f5fSchristos
320642542f5fSchristos	if (dst->pDrawable->depth < 8)
320742542f5fSchristos		return false;
320842542f5fSchristos
320942542f5fSchristos	if (!sna->render.check_composite_spans(sna, PictOpAdd, sna->render.white_picture, dst,
321042542f5fSchristos					       dst->pCompositeClip->extents.x2 - dst->pCompositeClip->extents.x1,
321142542f5fSchristos					       dst->pCompositeClip->extents.y2 - dst->pCompositeClip->extents.y1,
321242542f5fSchristos					       0)) {
321342542f5fSchristos		DBG(("%s: fallback -- composite spans not supported\n",
321442542f5fSchristos		     __FUNCTION__));
321542542f5fSchristos		return false;
321642542f5fSchristos	}
321742542f5fSchristos
321842542f5fSchristos	clip = dst->pCompositeClip;
321942542f5fSchristos	extents = *RegionExtents(clip);
322042542f5fSchristos	dx = dst->pDrawable->x;
322142542f5fSchristos	dy = dst->pDrawable->y;
322242542f5fSchristos
322342542f5fSchristos	DBG(("%s: after clip -- extents (%d, %d), (%d, %d), delta=(%d, %d)\n",
322442542f5fSchristos	     __FUNCTION__,
322542542f5fSchristos	     extents.x1, extents.y1,
322642542f5fSchristos	     extents.x2, extents.y2,
322742542f5fSchristos	     dx, dy));
322842542f5fSchristos
322942542f5fSchristos	memset(&tmp, 0, sizeof(tmp));
323042542f5fSchristos	if (!sna->render.composite_spans(sna, PictOpAdd, sna->render.white_picture, dst,
323142542f5fSchristos					 0, 0,
323242542f5fSchristos					 extents.x1,  extents.y1,
323342542f5fSchristos					 extents.x2 - extents.x1,
323442542f5fSchristos					 extents.y2 - extents.y1,
323542542f5fSchristos					 0,
323642542f5fSchristos					 &tmp)) {
323742542f5fSchristos		DBG(("%s: fallback -- composite spans render op not supported\n",
323842542f5fSchristos		     __FUNCTION__));
323942542f5fSchristos		return false;
324042542f5fSchristos	}
324142542f5fSchristos
324242542f5fSchristos	dx *= FAST_SAMPLES_X;
324342542f5fSchristos	dy *= FAST_SAMPLES_Y;
324442542f5fSchristos	if (!tor_init(&tor, &extents, 2*ntrap))
324542542f5fSchristos		goto skip;
324642542f5fSchristos
324742542f5fSchristos	for (n = 0; n < ntrap; n++) {
324842542f5fSchristos		xPointFixed p1, p2;
324942542f5fSchristos
325042542f5fSchristos		if (pixman_fixed_to_int(trap[n].top.y) + dst->pDrawable->y >= extents.y2 ||
325142542f5fSchristos		    pixman_fixed_to_int(trap[n].bot.y) + dst->pDrawable->y < extents.y1)
325242542f5fSchristos			continue;
325342542f5fSchristos
325413496ba1Ssnj		p1.y = trap[n].top.y;
325513496ba1Ssnj		p2.y = trap[n].bot.y;
325613496ba1Ssnj		p1.x = trap[n].top.l;
325713496ba1Ssnj		p2.x = trap[n].bot.l;
325813496ba1Ssnj		polygon_add_line(tor.polygon, &p1, &p2, dx, dy);
325942542f5fSchristos
326013496ba1Ssnj		p1.y = trap[n].bot.y;
326113496ba1Ssnj		p2.y = trap[n].top.y;
326213496ba1Ssnj		p1.x = trap[n].top.r;
326313496ba1Ssnj		p2.x = trap[n].bot.r;
326413496ba1Ssnj		polygon_add_line(tor.polygon, &p1, &p2, dx, dy);
326542542f5fSchristos	}
326642542f5fSchristos
326742542f5fSchristos	tor_render(sna, &tor, &tmp, clip,
326842542f5fSchristos		   choose_span(&tmp, dst, NULL, clip), false);
326942542f5fSchristos
327042542f5fSchristos	tor_fini(&tor);
327142542f5fSchristosskip:
327242542f5fSchristos	tmp.done(sna, &tmp);
327342542f5fSchristos	return true;
327442542f5fSchristos}
327542542f5fSchristos
327642542f5fSchristosstatic void mark_damaged(PixmapPtr pixmap, struct sna_pixmap *priv,
327742542f5fSchristos			 BoxPtr box, int16_t x, int16_t y)
327842542f5fSchristos{
327942542f5fSchristos	box->x1 += x; box->x2 += x;
328042542f5fSchristos	box->y1 += y; box->y2 += y;
328142542f5fSchristos	if (box->x1 <= 0 && box->y1 <= 0 &&
328242542f5fSchristos	    box->x2 >= pixmap->drawable.width &&
328342542f5fSchristos	    box->y2 >= pixmap->drawable.height) {
328442542f5fSchristos		sna_damage_destroy(&priv->cpu_damage);
328542542f5fSchristos		sna_damage_all(&priv->gpu_damage, pixmap);
328642542f5fSchristos		list_del(&priv->flush_list);
328742542f5fSchristos	} else {
328842542f5fSchristos		sna_damage_add_box(&priv->gpu_damage, box);
328942542f5fSchristos		sna_damage_subtract_box(&priv->cpu_damage, box);
329042542f5fSchristos	}
329142542f5fSchristos}
329242542f5fSchristos
329342542f5fSchristosbool
329442542f5fSchristostrap_mask_converter(struct sna *sna,
329542542f5fSchristos		    PicturePtr picture,
329642542f5fSchristos		    INT16 x, INT16 y,
329742542f5fSchristos		    int ntrap, xTrap *trap)
329842542f5fSchristos{
329942542f5fSchristos	struct tor tor;
330042542f5fSchristos	ScreenPtr screen = picture->pDrawable->pScreen;
330142542f5fSchristos	PixmapPtr scratch, pixmap;
330242542f5fSchristos	struct sna_pixmap *priv;
330342542f5fSchristos	BoxRec extents;
330442542f5fSchristos	span_func_t span;
330542542f5fSchristos	int dx, dy, n;
330642542f5fSchristos
330742542f5fSchristos	if (NO_SCAN_CONVERTER)
330842542f5fSchristos		return false;
330942542f5fSchristos
331042542f5fSchristos	pixmap = get_drawable_pixmap(picture->pDrawable);
331142542f5fSchristos	priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_WRITE);
331242542f5fSchristos	if (priv == NULL)
331342542f5fSchristos		return false;
331442542f5fSchristos
331542542f5fSchristos	/* XXX strict adherence to the Render specification */
331642542f5fSchristos	if (picture->polyMode == PolyModePrecise &&
331742542f5fSchristos	    picture->polyEdge != PolyEdgeSharp) {
331842542f5fSchristos		DBG(("%s: fallback -- precise rasterisation requested\n",
331942542f5fSchristos		     __FUNCTION__));
332042542f5fSchristos		return false;
332142542f5fSchristos	}
332242542f5fSchristos
332342542f5fSchristos	extents = *RegionExtents(picture->pCompositeClip);
332442542f5fSchristos	for (n = 0; n < ntrap; n++) {
332542542f5fSchristos		int v;
332642542f5fSchristos
332742542f5fSchristos		v = x + pixman_fixed_integer_floor (MIN(trap[n].top.l, trap[n].bot.l));
332842542f5fSchristos		if (v < extents.x1)
332942542f5fSchristos			extents.x1 = v;
333042542f5fSchristos
333142542f5fSchristos		v = x + pixman_fixed_integer_ceil (MAX(trap[n].top.r, trap[n].bot.r));
333242542f5fSchristos		if (v > extents.x2)
333342542f5fSchristos			extents.x2 = v;
333442542f5fSchristos
333542542f5fSchristos		v = y + pixman_fixed_integer_floor (trap[n].top.y);
333642542f5fSchristos		if (v < extents.y1)
333742542f5fSchristos			extents.y1 = v;
333842542f5fSchristos
333942542f5fSchristos		v = y + pixman_fixed_integer_ceil (trap[n].bot.y);
334042542f5fSchristos		if (v > extents.y2)
334142542f5fSchristos			extents.y2 = v;
334242542f5fSchristos	}
334342542f5fSchristos
334442542f5fSchristos	DBG(("%s: extents (%d, %d), (%d, %d)\n",
334542542f5fSchristos	     __FUNCTION__, extents.x1, extents.y1, extents.x2, extents.y2));
334642542f5fSchristos
334742542f5fSchristos	scratch = sna_pixmap_create_upload(screen,
334842542f5fSchristos					   extents.x2-extents.x1,
334942542f5fSchristos					   extents.y2-extents.y1,
335042542f5fSchristos					   8, KGEM_BUFFER_WRITE_INPLACE);
335142542f5fSchristos	if (!scratch)
335242542f5fSchristos		return true;
335342542f5fSchristos
335442542f5fSchristos	dx = picture->pDrawable->x;
335542542f5fSchristos	dy = picture->pDrawable->y;
335642542f5fSchristos	dx *= FAST_SAMPLES_X;
335742542f5fSchristos	dy *= FAST_SAMPLES_Y;
335842542f5fSchristos	if (!tor_init(&tor, &extents, 2*ntrap)) {
335942542f5fSchristos		sna_pixmap_destroy(scratch);
336042542f5fSchristos		return true;
336142542f5fSchristos	}
336242542f5fSchristos
336342542f5fSchristos	for (n = 0; n < ntrap; n++) {
336442542f5fSchristos		xPointFixed p1, p2;
336542542f5fSchristos
336642542f5fSchristos		if (pixman_fixed_to_int(trap[n].top.y) + picture->pDrawable->y >= extents.y2 ||
336742542f5fSchristos		    pixman_fixed_to_int(trap[n].bot.y) + picture->pDrawable->y < extents.y1)
336842542f5fSchristos			continue;
336942542f5fSchristos
337013496ba1Ssnj		p1.y = trap[n].top.y;
337113496ba1Ssnj		p2.y = trap[n].bot.y;
337213496ba1Ssnj		p1.x = trap[n].top.l;
337313496ba1Ssnj		p2.x = trap[n].bot.l;
337413496ba1Ssnj		polygon_add_line(tor.polygon, &p1, &p2, dx, dy);
337542542f5fSchristos
337613496ba1Ssnj		p1.y = trap[n].bot.y;
337713496ba1Ssnj		p2.y = trap[n].top.y;
337813496ba1Ssnj		p1.x = trap[n].top.r;
337913496ba1Ssnj		p2.x = trap[n].bot.r;
338013496ba1Ssnj		polygon_add_line(tor.polygon, &p1, &p2, dx, dy);
338142542f5fSchristos	}
338242542f5fSchristos
338342542f5fSchristos	if (picture->polyEdge == PolyEdgeSharp)
338442542f5fSchristos		span = tor_blt_mask_mono;
338542542f5fSchristos	else
338642542f5fSchristos		span = tor_blt_mask;
338742542f5fSchristos
338842542f5fSchristos	tor_render(NULL, &tor,
338942542f5fSchristos		   scratch->devPrivate.ptr,
339042542f5fSchristos		   (void *)(intptr_t)scratch->devKind,
339142542f5fSchristos		   span, true);
339242542f5fSchristos
339342542f5fSchristos	tor_fini(&tor);
339442542f5fSchristos
339542542f5fSchristos	/* XXX clip boxes */
339642542f5fSchristos	get_drawable_deltas(picture->pDrawable, pixmap, &x, &y);
339742542f5fSchristos	sna = to_sna_from_screen(screen);
339842542f5fSchristos	sna->render.copy_boxes(sna, GXcopy,
339942542f5fSchristos			       &scratch->drawable, __sna_pixmap_get_bo(scratch), -extents.x1, -extents.x1,
340042542f5fSchristos			       &pixmap->drawable, priv->gpu_bo, x, y,
340142542f5fSchristos			       &extents, 1, 0);
340242542f5fSchristos	mark_damaged(pixmap, priv, &extents ,x, y);
340342542f5fSchristos	sna_pixmap_destroy(scratch);
340442542f5fSchristos	return true;
340542542f5fSchristos}
340642542f5fSchristos
340742542f5fSchristosbool
340842542f5fSchristostriangles_span_converter(struct sna *sna,
340942542f5fSchristos			 CARD8 op, PicturePtr src, PicturePtr dst,
341042542f5fSchristos			 PictFormatPtr maskFormat, INT16 src_x, INT16 src_y,
341142542f5fSchristos			 int count, xTriangle *tri)
341242542f5fSchristos{
341342542f5fSchristos	struct sna_composite_spans_op tmp;
341442542f5fSchristos	struct tor tor;
341542542f5fSchristos	BoxRec extents;
341642542f5fSchristos	pixman_region16_t clip;
341742542f5fSchristos	int16_t dst_x, dst_y;
341842542f5fSchristos	int dx, dy, n;
341942542f5fSchristos	bool was_clear;
342042542f5fSchristos
342142542f5fSchristos	if (NO_SCAN_CONVERTER)
342242542f5fSchristos		return false;
342342542f5fSchristos
342442542f5fSchristos	if (is_mono(dst, maskFormat))
342542542f5fSchristos		return mono_triangles_span_converter(sna, op, src, dst,
342642542f5fSchristos						     src_x, src_y,
342742542f5fSchristos						     count, tri);
342842542f5fSchristos
342942542f5fSchristos	/* XXX strict adherence to the Render specification */
343042542f5fSchristos	if (dst->polyMode == PolyModePrecise) {
343142542f5fSchristos		DBG(("%s: fallback -- precise rasterisation requested\n",
343242542f5fSchristos		     __FUNCTION__));
343342542f5fSchristos		return false;
343442542f5fSchristos	}
343542542f5fSchristos
343642542f5fSchristos	if (!sna->render.check_composite_spans(sna, op, src, dst, 0, 0, 0)) {
343742542f5fSchristos		DBG(("%s: fallback -- composite spans not supported\n",
343842542f5fSchristos		     __FUNCTION__));
343942542f5fSchristos		return false;
344042542f5fSchristos	}
344142542f5fSchristos
344242542f5fSchristos	dst_x = pixman_fixed_to_int(tri[0].p1.x);
344342542f5fSchristos	dst_y = pixman_fixed_to_int(tri[0].p1.y);
344442542f5fSchristos
344542542f5fSchristos	miTriangleBounds(count, tri, &extents);
344642542f5fSchristos	DBG(("%s: extents (%d, %d), (%d, %d)\n",
344742542f5fSchristos	     __FUNCTION__, extents.x1, extents.y1, extents.x2, extents.y2));
344842542f5fSchristos
344942542f5fSchristos	if (extents.y1 >= extents.y2 || extents.x1 >= extents.x2)
345042542f5fSchristos		return true;
345142542f5fSchristos
345242542f5fSchristos#if 0
345342542f5fSchristos	if (extents.y2 - extents.y1 < 64 && extents.x2 - extents.x1 < 64) {
345442542f5fSchristos		DBG(("%s: fallback -- traps extents too small %dx%d\n",
345542542f5fSchristos		     __FUNCTION__, extents.y2 - extents.y1, extents.x2 - extents.x1));
345642542f5fSchristos		return false;
345742542f5fSchristos	}
345842542f5fSchristos#endif
345942542f5fSchristos
346042542f5fSchristos	if (!sna_compute_composite_region(&clip,
346142542f5fSchristos					  src, NULL, dst,
346242542f5fSchristos					  src_x + extents.x1 - dst_x,
346342542f5fSchristos					  src_y + extents.y1 - dst_y,
346442542f5fSchristos					  0, 0,
346542542f5fSchristos					  extents.x1, extents.y1,
346642542f5fSchristos					  extents.x2 - extents.x1,
346742542f5fSchristos					  extents.y2 - extents.y1)) {
346842542f5fSchristos		DBG(("%s: triangles do not intersect drawable clips\n",
346942542f5fSchristos		     __FUNCTION__)) ;
347042542f5fSchristos		return true;
347142542f5fSchristos	}
347242542f5fSchristos
347342542f5fSchristos	if (!sna->render.check_composite_spans(sna, op, src, dst,
347442542f5fSchristos					       clip.extents.x2 - clip.extents.x1,
347542542f5fSchristos					       clip.extents.y2 - clip.extents.y1,
347642542f5fSchristos					       0)) {
347742542f5fSchristos		DBG(("%s: fallback -- composite spans not supported\n",
347842542f5fSchristos		     __FUNCTION__));
347942542f5fSchristos		return false;
348042542f5fSchristos	}
348142542f5fSchristos
348242542f5fSchristos	extents = *RegionExtents(&clip);
348342542f5fSchristos	dx = dst->pDrawable->x;
348442542f5fSchristos	dy = dst->pDrawable->y;
348542542f5fSchristos
348642542f5fSchristos	DBG(("%s: after clip -- extents (%d, %d), (%d, %d), delta=(%d, %d) src -> (%d, %d)\n",
348742542f5fSchristos	     __FUNCTION__,
348842542f5fSchristos	     extents.x1, extents.y1,
348942542f5fSchristos	     extents.x2, extents.y2,
349042542f5fSchristos	     dx, dy,
349142542f5fSchristos	     src_x + extents.x1 - dst_x - dx,
349242542f5fSchristos	     src_y + extents.y1 - dst_y - dy));
349342542f5fSchristos
349442542f5fSchristos	was_clear = sna_drawable_is_clear(dst->pDrawable);
349542542f5fSchristos
349642542f5fSchristos	memset(&tmp, 0, sizeof(tmp));
349742542f5fSchristos	if (!sna->render.composite_spans(sna, op, src, dst,
349842542f5fSchristos					 src_x + extents.x1 - dst_x - dx,
349942542f5fSchristos					 src_y + extents.y1 - dst_y - dy,
350042542f5fSchristos					 extents.x1,  extents.y1,
350142542f5fSchristos					 extents.x2 - extents.x1,
350242542f5fSchristos					 extents.y2 - extents.y1,
350342542f5fSchristos					 0,
350442542f5fSchristos					 &tmp)) {
350542542f5fSchristos		DBG(("%s: fallback -- composite spans render op not supported\n",
350642542f5fSchristos		     __FUNCTION__));
350742542f5fSchristos		return false;
350842542f5fSchristos	}
350942542f5fSchristos
351042542f5fSchristos	dx *= FAST_SAMPLES_X;
351142542f5fSchristos	dy *= FAST_SAMPLES_Y;
351242542f5fSchristos	if (!tor_init(&tor, &extents, 3*count))
351342542f5fSchristos		goto skip;
351442542f5fSchristos
351542542f5fSchristos	for (n = 0; n < count; n++) {
351613496ba1Ssnj		polygon_add_line(tor.polygon, &tri[n].p1, &tri[n].p2, dx, dy);
351713496ba1Ssnj		polygon_add_line(tor.polygon, &tri[n].p2, &tri[n].p3, dx, dy);
351813496ba1Ssnj		polygon_add_line(tor.polygon, &tri[n].p3, &tri[n].p1, dx, dy);
351942542f5fSchristos	}
352042542f5fSchristos
352142542f5fSchristos	tor_render(sna, &tor, &tmp, &clip,
352242542f5fSchristos		   choose_span(&tmp, dst, maskFormat, &clip),
352342542f5fSchristos		   !was_clear && maskFormat && !operator_is_bounded(op));
352442542f5fSchristos
352542542f5fSchristos	tor_fini(&tor);
352642542f5fSchristosskip:
352742542f5fSchristos	tmp.done(sna, &tmp);
352842542f5fSchristos
352942542f5fSchristos	REGION_UNINIT(NULL, &clip);
353042542f5fSchristos	return true;
353142542f5fSchristos}
353242542f5fSchristos
353342542f5fSchristosbool
353442542f5fSchristostriangles_mask_converter(CARD8 op, PicturePtr src, PicturePtr dst,
353542542f5fSchristos			 PictFormatPtr maskFormat, INT16 src_x, INT16 src_y,
353642542f5fSchristos			 int count, xTriangle *tri)
353742542f5fSchristos{
353842542f5fSchristos	struct tor tor;
353942542f5fSchristos	void (*span)(struct sna *sna,
354042542f5fSchristos		     struct sna_composite_spans_op *op,
354142542f5fSchristos		     pixman_region16_t *clip,
354242542f5fSchristos		     const BoxRec *box,
354342542f5fSchristos		     int coverage);
354442542f5fSchristos	ScreenPtr screen = dst->pDrawable->pScreen;
354542542f5fSchristos	PixmapPtr scratch;
354642542f5fSchristos	PicturePtr mask;
354742542f5fSchristos	BoxRec extents;
354842542f5fSchristos	int16_t dst_x, dst_y;
354942542f5fSchristos	int dx, dy;
355042542f5fSchristos	int error, n;
355142542f5fSchristos
355242542f5fSchristos	if (NO_SCAN_CONVERTER)
355342542f5fSchristos		return false;
355442542f5fSchristos
355542542f5fSchristos	if (is_precise(dst, maskFormat)) {
355642542f5fSchristos		DBG(("%s: fallback -- precise rasterisation requested\n",
355742542f5fSchristos		     __FUNCTION__));
355842542f5fSchristos		return false;
355942542f5fSchristos	}
356042542f5fSchristos
356142542f5fSchristos	if (maskFormat == NULL && count > 1) {
356242542f5fSchristos		DBG(("%s: fallback -- individual rasterisation requested\n",
356342542f5fSchristos		     __FUNCTION__));
356442542f5fSchristos		return false;
356542542f5fSchristos	}
356642542f5fSchristos
356742542f5fSchristos	miTriangleBounds(count, tri, &extents);
356842542f5fSchristos	DBG(("%s: extents (%d, %d), (%d, %d)\n",
356942542f5fSchristos	     __FUNCTION__, extents.x1, extents.y1, extents.x2, extents.y2));
357042542f5fSchristos
357142542f5fSchristos	if (extents.y1 >= extents.y2 || extents.x1 >= extents.x2)
357242542f5fSchristos		return true;
357342542f5fSchristos
357442542f5fSchristos	if (!sna_compute_composite_extents(&extents,
357542542f5fSchristos					   src, NULL, dst,
357642542f5fSchristos					   src_x, src_y,
357742542f5fSchristos					   0, 0,
357842542f5fSchristos					   extents.x1, extents.y1,
357942542f5fSchristos					   extents.x2 - extents.x1,
358042542f5fSchristos					   extents.y2 - extents.y1))
358142542f5fSchristos		return true;
358242542f5fSchristos
358342542f5fSchristos	DBG(("%s: extents (%d, %d), (%d, %d)\n",
358442542f5fSchristos	     __FUNCTION__, extents.x1, extents.y1, extents.x2, extents.y2));
358542542f5fSchristos
358642542f5fSchristos	extents.y2 -= extents.y1;
358742542f5fSchristos	extents.x2 -= extents.x1;
358842542f5fSchristos	extents.x1 -= dst->pDrawable->x;
358942542f5fSchristos	extents.y1 -= dst->pDrawable->y;
359042542f5fSchristos	dst_x = extents.x1;
359142542f5fSchristos	dst_y = extents.y1;
359242542f5fSchristos	dx = -extents.x1 * FAST_SAMPLES_X;
359342542f5fSchristos	dy = -extents.y1 * FAST_SAMPLES_Y;
359442542f5fSchristos	extents.x1 = extents.y1 = 0;
359542542f5fSchristos
359642542f5fSchristos	DBG(("%s: mask (%dx%d)\n",
359742542f5fSchristos	     __FUNCTION__, extents.x2, extents.y2));
359842542f5fSchristos	scratch = sna_pixmap_create_upload(screen,
359942542f5fSchristos					   extents.x2, extents.y2, 8,
360042542f5fSchristos					   KGEM_BUFFER_WRITE_INPLACE);
360142542f5fSchristos	if (!scratch)
360242542f5fSchristos		return true;
360342542f5fSchristos
360442542f5fSchristos	DBG(("%s: created buffer %p, stride %d\n",
360542542f5fSchristos	     __FUNCTION__, scratch->devPrivate.ptr, scratch->devKind));
360642542f5fSchristos
360742542f5fSchristos	if (!tor_init(&tor, &extents, 3*count)) {
360842542f5fSchristos		sna_pixmap_destroy(scratch);
360942542f5fSchristos		return true;
361042542f5fSchristos	}
361142542f5fSchristos
361242542f5fSchristos	for (n = 0; n < count; n++) {
361313496ba1Ssnj		polygon_add_line(tor.polygon, &tri[n].p1, &tri[n].p2, dx, dy);
361413496ba1Ssnj		polygon_add_line(tor.polygon, &tri[n].p2, &tri[n].p3, dx, dy);
361513496ba1Ssnj		polygon_add_line(tor.polygon, &tri[n].p3, &tri[n].p1, dx, dy);
361642542f5fSchristos	}
361742542f5fSchristos
361842542f5fSchristos	if (maskFormat ? maskFormat->depth < 8 : dst->polyEdge == PolyEdgeSharp)
361942542f5fSchristos		span = tor_blt_mask_mono;
362042542f5fSchristos	else
362142542f5fSchristos		span = tor_blt_mask;
362242542f5fSchristos
362342542f5fSchristos	tor_render(NULL, &tor,
362442542f5fSchristos		   scratch->devPrivate.ptr,
362542542f5fSchristos		   (void *)(intptr_t)scratch->devKind,
362642542f5fSchristos		   span, true);
362742542f5fSchristos
362842542f5fSchristos	mask = CreatePicture(0, &scratch->drawable,
362942542f5fSchristos			     PictureMatchFormat(screen, 8, PICT_a8),
363042542f5fSchristos			     0, 0, serverClient, &error);
363142542f5fSchristos	if (mask) {
363242542f5fSchristos		CompositePicture(op, src, mask, dst,
363342542f5fSchristos				 src_x + dst_x - pixman_fixed_to_int(tri[0].p1.x),
363442542f5fSchristos				 src_y + dst_y - pixman_fixed_to_int(tri[0].p1.y),
363542542f5fSchristos				 0, 0,
363642542f5fSchristos				 dst_x, dst_y,
363742542f5fSchristos				 extents.x2, extents.y2);
363842542f5fSchristos		FreePicture(mask, 0);
363942542f5fSchristos	}
364042542f5fSchristos	tor_fini(&tor);
364142542f5fSchristos	sna_pixmap_destroy(scratch);
364242542f5fSchristos
364342542f5fSchristos	return true;
364442542f5fSchristos}
364542542f5fSchristos
364613496ba1Ssnjstruct tristrip_thread {
364713496ba1Ssnj	struct sna *sna;
364813496ba1Ssnj	const struct sna_composite_spans_op *op;
364913496ba1Ssnj	const xPointFixed *points;
365013496ba1Ssnj	RegionPtr clip;
365113496ba1Ssnj	span_func_t span;
365213496ba1Ssnj	BoxRec extents;
365313496ba1Ssnj	int dx, dy, draw_y;
365413496ba1Ssnj	int count;
365513496ba1Ssnj	bool unbounded;
365613496ba1Ssnj};
365713496ba1Ssnj
365813496ba1Ssnjstatic void
365913496ba1Ssnjtristrip_thread(void *arg)
366013496ba1Ssnj{
366113496ba1Ssnj	struct tristrip_thread *thread = arg;
366213496ba1Ssnj	struct span_thread_boxes boxes;
366313496ba1Ssnj	struct tor tor;
366413496ba1Ssnj	int n, cw, ccw;
366513496ba1Ssnj
366613496ba1Ssnj	if (!tor_init(&tor, &thread->extents, 2*thread->count))
366713496ba1Ssnj		return;
366813496ba1Ssnj
3669fe8aea9eSmrg	span_thread_boxes_init(&boxes, thread->op, thread->clip);
367013496ba1Ssnj
367113496ba1Ssnj	cw = 0; ccw = 1;
367213496ba1Ssnj	polygon_add_line(tor.polygon,
367313496ba1Ssnj			 &thread->points[ccw], &thread->points[cw],
367413496ba1Ssnj			 thread->dx, thread->dy);
367513496ba1Ssnj	n = 2;
367613496ba1Ssnj	do {
367713496ba1Ssnj		polygon_add_line(tor.polygon,
367813496ba1Ssnj				 &thread->points[cw], &thread->points[n],
367913496ba1Ssnj				 thread->dx, thread->dy);
368013496ba1Ssnj		cw = n;
368113496ba1Ssnj		if (++n == thread->count)
368213496ba1Ssnj			break;
368313496ba1Ssnj
368413496ba1Ssnj		polygon_add_line(tor.polygon,
368513496ba1Ssnj				 &thread->points[n], &thread->points[ccw],
368613496ba1Ssnj				 thread->dx, thread->dy);
368713496ba1Ssnj		ccw = n;
368813496ba1Ssnj		if (++n == thread->count)
368913496ba1Ssnj			break;
369013496ba1Ssnj	} while (1);
369113496ba1Ssnj	polygon_add_line(tor.polygon,
369213496ba1Ssnj			 &thread->points[cw], &thread->points[ccw],
369313496ba1Ssnj			 thread->dx, thread->dy);
369413496ba1Ssnj	assert(tor.polygon->num_edges <= 2*thread->count);
369513496ba1Ssnj
369613496ba1Ssnj	tor_render(thread->sna, &tor,
369713496ba1Ssnj		   (struct sna_composite_spans_op *)&boxes, thread->clip,
369813496ba1Ssnj		   thread->span, thread->unbounded);
369913496ba1Ssnj
370013496ba1Ssnj	tor_fini(&tor);
370113496ba1Ssnj
370213496ba1Ssnj	if (boxes.num_boxes) {
370313496ba1Ssnj		DBG(("%s: flushing %d boxes\n", __FUNCTION__, boxes.num_boxes));
370413496ba1Ssnj		assert(boxes.num_boxes <= SPAN_THREAD_MAX_BOXES);
370513496ba1Ssnj		thread->op->thread_boxes(thread->sna, thread->op,
370613496ba1Ssnj					 boxes.boxes, boxes.num_boxes);
370713496ba1Ssnj	}
370813496ba1Ssnj}
370913496ba1Ssnj
371042542f5fSchristosbool
371113496ba1Ssnjimprecise_tristrip_span_converter(struct sna *sna,
371213496ba1Ssnj				  CARD8 op, PicturePtr src, PicturePtr dst,
371313496ba1Ssnj				  PictFormatPtr maskFormat, INT16 src_x, INT16 src_y,
371413496ba1Ssnj				  int count, xPointFixed *points)
371542542f5fSchristos{
371642542f5fSchristos	struct sna_composite_spans_op tmp;
371742542f5fSchristos	BoxRec extents;
371842542f5fSchristos	pixman_region16_t clip;
371942542f5fSchristos	int16_t dst_x, dst_y;
372013496ba1Ssnj	int dx, dy, num_threads;
372142542f5fSchristos	bool was_clear;
372242542f5fSchristos
372342542f5fSchristos	if (!sna->render.check_composite_spans(sna, op, src, dst, 0, 0, 0)) {
372442542f5fSchristos		DBG(("%s: fallback -- composite spans not supported\n",
372542542f5fSchristos		     __FUNCTION__));
372642542f5fSchristos		return false;
372742542f5fSchristos	}
372842542f5fSchristos
372942542f5fSchristos	dst_x = pixman_fixed_to_int(points[0].x);
373042542f5fSchristos	dst_y = pixman_fixed_to_int(points[0].y);
373142542f5fSchristos
373242542f5fSchristos	miPointFixedBounds(count, points, &extents);
373342542f5fSchristos	DBG(("%s: extents (%d, %d), (%d, %d)\n",
373442542f5fSchristos	     __FUNCTION__, extents.x1, extents.y1, extents.x2, extents.y2));
373542542f5fSchristos
373642542f5fSchristos	if (extents.y1 >= extents.y2 || extents.x1 >= extents.x2)
373742542f5fSchristos		return true;
373842542f5fSchristos
373942542f5fSchristos#if 0
374042542f5fSchristos	if (extents.y2 - extents.y1 < 64 && extents.x2 - extents.x1 < 64) {
374142542f5fSchristos		DBG(("%s: fallback -- traps extents too small %dx%d\n",
374242542f5fSchristos		     __FUNCTION__, extents.y2 - extents.y1, extents.x2 - extents.x1));
374342542f5fSchristos		return false;
374442542f5fSchristos	}
374542542f5fSchristos#endif
374642542f5fSchristos
374742542f5fSchristos	if (!sna_compute_composite_region(&clip,
374842542f5fSchristos					  src, NULL, dst,
374942542f5fSchristos					  src_x + extents.x1 - dst_x,
375042542f5fSchristos					  src_y + extents.y1 - dst_y,
375142542f5fSchristos					  0, 0,
375242542f5fSchristos					  extents.x1, extents.y1,
375342542f5fSchristos					  extents.x2 - extents.x1,
375442542f5fSchristos					  extents.y2 - extents.y1)) {
375542542f5fSchristos		DBG(("%s: triangles do not intersect drawable clips\n",
375642542f5fSchristos		     __FUNCTION__)) ;
375742542f5fSchristos		return true;
375842542f5fSchristos	}
375942542f5fSchristos
376042542f5fSchristos	if (!sna->render.check_composite_spans(sna, op, src, dst,
376142542f5fSchristos					       clip.extents.x2 - clip.extents.x1,
376242542f5fSchristos					       clip.extents.y2 - clip.extents.y1,
376342542f5fSchristos					       0)) {
376442542f5fSchristos		DBG(("%s: fallback -- composite spans not supported\n",
376542542f5fSchristos		     __FUNCTION__));
376642542f5fSchristos		return false;
376742542f5fSchristos	}
376842542f5fSchristos
376942542f5fSchristos	extents = *RegionExtents(&clip);
377042542f5fSchristos	dx = dst->pDrawable->x;
377142542f5fSchristos	dy = dst->pDrawable->y;
377242542f5fSchristos
377342542f5fSchristos	DBG(("%s: after clip -- extents (%d, %d), (%d, %d), delta=(%d, %d) src -> (%d, %d)\n",
377442542f5fSchristos	     __FUNCTION__,
377542542f5fSchristos	     extents.x1, extents.y1,
377642542f5fSchristos	     extents.x2, extents.y2,
377742542f5fSchristos	     dx, dy,
377842542f5fSchristos	     src_x + extents.x1 - dst_x - dx,
377942542f5fSchristos	     src_y + extents.y1 - dst_y - dy));
378042542f5fSchristos
378142542f5fSchristos	was_clear = sna_drawable_is_clear(dst->pDrawable);
378242542f5fSchristos
378342542f5fSchristos	memset(&tmp, 0, sizeof(tmp));
378442542f5fSchristos	if (!sna->render.composite_spans(sna, op, src, dst,
378542542f5fSchristos					 src_x + extents.x1 - dst_x - dx,
378642542f5fSchristos					 src_y + extents.y1 - dst_y - dy,
378742542f5fSchristos					 extents.x1,  extents.y1,
378842542f5fSchristos					 extents.x2 - extents.x1,
378942542f5fSchristos					 extents.y2 - extents.y1,
379042542f5fSchristos					 0,
379142542f5fSchristos					 &tmp)) {
379242542f5fSchristos		DBG(("%s: fallback -- composite spans render op not supported\n",
379342542f5fSchristos		     __FUNCTION__));
379442542f5fSchristos		return false;
379542542f5fSchristos	}
379642542f5fSchristos
379742542f5fSchristos	dx *= FAST_SAMPLES_X;
379842542f5fSchristos	dy *= FAST_SAMPLES_Y;
379942542f5fSchristos
380013496ba1Ssnj	num_threads = 1;
380113496ba1Ssnj	if (!NO_GPU_THREADS &&
380213496ba1Ssnj	    tmp.thread_boxes &&
380313496ba1Ssnj	    thread_choose_span(&tmp, dst, maskFormat, &clip))
380413496ba1Ssnj		num_threads = sna_use_threads(extents.x2 - extents.x1,
380513496ba1Ssnj					      extents.y2 - extents.y1,
380613496ba1Ssnj					      16);
380713496ba1Ssnj	if (num_threads == 1) {
380813496ba1Ssnj		struct tor tor;
380913496ba1Ssnj		int cw, ccw, n;
381042542f5fSchristos
381113496ba1Ssnj		if (!tor_init(&tor, &extents, 2*count))
381213496ba1Ssnj			goto skip;
381342542f5fSchristos
381413496ba1Ssnj		cw = 0; ccw = 1;
381513496ba1Ssnj		polygon_add_line(tor.polygon,
381613496ba1Ssnj				 &points[ccw], &points[cw],
381713496ba1Ssnj				 dx, dy);
381813496ba1Ssnj		n = 2;
381913496ba1Ssnj		do {
382013496ba1Ssnj			polygon_add_line(tor.polygon,
382113496ba1Ssnj					 &points[cw], &points[n],
382213496ba1Ssnj					 dx, dy);
382313496ba1Ssnj			cw = n;
382413496ba1Ssnj			if (++n == count)
382513496ba1Ssnj				break;
382642542f5fSchristos
382713496ba1Ssnj			polygon_add_line(tor.polygon,
382813496ba1Ssnj					 &points[n], &points[ccw],
382913496ba1Ssnj					 dx, dy);
383013496ba1Ssnj			ccw = n;
383113496ba1Ssnj			if (++n == count)
383213496ba1Ssnj				break;
383313496ba1Ssnj		} while (1);
383413496ba1Ssnj		polygon_add_line(tor.polygon,
3835fe8aea9eSmrg				 &points[cw], &points[ccw],
383613496ba1Ssnj				 dx, dy);
383713496ba1Ssnj		assert(tor.polygon->num_edges <= 2*count);
383813496ba1Ssnj
383913496ba1Ssnj		tor_render(sna, &tor, &tmp, &clip,
384013496ba1Ssnj			   choose_span(&tmp, dst, maskFormat, &clip),
384113496ba1Ssnj			   !was_clear && maskFormat && !operator_is_bounded(op));
384213496ba1Ssnj
384313496ba1Ssnj		tor_fini(&tor);
384413496ba1Ssnj	} else {
384513496ba1Ssnj		struct tristrip_thread threads[num_threads];
384613496ba1Ssnj		int y, h, n;
384713496ba1Ssnj
384813496ba1Ssnj		DBG(("%s: using %d threads for tristrip compositing %dx%d\n",
384913496ba1Ssnj		     __FUNCTION__, num_threads,
385013496ba1Ssnj		     clip.extents.x2 - clip.extents.x1,
385113496ba1Ssnj		     clip.extents.y2 - clip.extents.y1));
385213496ba1Ssnj
385313496ba1Ssnj		threads[0].sna = sna;
385413496ba1Ssnj		threads[0].op = &tmp;
385513496ba1Ssnj		threads[0].points = points;
385613496ba1Ssnj		threads[0].count = count;
385713496ba1Ssnj		threads[0].extents = clip.extents;
385813496ba1Ssnj		threads[0].clip = &clip;
385913496ba1Ssnj		threads[0].dx = dx;
386013496ba1Ssnj		threads[0].dy = dy;
386113496ba1Ssnj		threads[0].draw_y = dst->pDrawable->y;
386213496ba1Ssnj		threads[0].unbounded = !was_clear && maskFormat && !operator_is_bounded(op);
386313496ba1Ssnj		threads[0].span = thread_choose_span(&tmp, dst, maskFormat, &clip);
386413496ba1Ssnj
386513496ba1Ssnj		y = clip.extents.y1;
386613496ba1Ssnj		h = clip.extents.y2 - clip.extents.y1;
386713496ba1Ssnj		h = (h + num_threads - 1) / num_threads;
386813496ba1Ssnj		num_threads -= (num_threads-1) * h >= clip.extents.y2 - clip.extents.y1;
386913496ba1Ssnj
387013496ba1Ssnj		for (n = 1; n < num_threads; n++) {
387113496ba1Ssnj			threads[n] = threads[0];
387213496ba1Ssnj			threads[n].extents.y1 = y;
387313496ba1Ssnj			threads[n].extents.y2 = y += h;
387413496ba1Ssnj
387513496ba1Ssnj			sna_threads_run(n, tristrip_thread, &threads[n]);
387613496ba1Ssnj		}
387713496ba1Ssnj
387813496ba1Ssnj		assert(y < threads[0].extents.y2);
387913496ba1Ssnj		threads[0].extents.y1 = y;
388013496ba1Ssnj		tristrip_thread(&threads[0]);
388113496ba1Ssnj
388213496ba1Ssnj		sna_threads_wait();
388313496ba1Ssnj	}
388442542f5fSchristosskip:
388542542f5fSchristos	tmp.done(sna, &tmp);
388642542f5fSchristos
388742542f5fSchristos	REGION_UNINIT(NULL, &clip);
388842542f5fSchristos	return true;
388942542f5fSchristos}
3890