sna_trapezoids.c revision 03b705cf
103b705cfSriastradh/* 203b705cfSriastradh * Copyright (c) 2007 David Turner 303b705cfSriastradh * Copyright (c) 2008 M Joonas Pihlaja 403b705cfSriastradh * Copyright (c) 2011 Intel Corporation 503b705cfSriastradh * 603b705cfSriastradh * Permission is hereby granted, free of charge, to any person obtaining a 703b705cfSriastradh * copy of this software and associated documentation files (the "Software"), 803b705cfSriastradh * to deal in the Software without restriction, including without limitation 903b705cfSriastradh * the rights to use, copy, modify, merge, publish, distribute, sublicense, 1003b705cfSriastradh * and/or sell copies of the Software, and to permit persons to whom the 1103b705cfSriastradh * Software is furnished to do so, subject to the following conditions: 1203b705cfSriastradh * 1303b705cfSriastradh * The above copyright notice and this permission notice (including the next 1403b705cfSriastradh * paragraph) shall be included in all copies or substantial portions of the 1503b705cfSriastradh * Software. 1603b705cfSriastradh * 1703b705cfSriastradh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1803b705cfSriastradh * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1903b705cfSriastradh * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 2003b705cfSriastradh * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2103b705cfSriastradh * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2203b705cfSriastradh * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 2303b705cfSriastradh * SOFTWARE. 2403b705cfSriastradh * 2503b705cfSriastradh * Authors: 2603b705cfSriastradh * Chris Wilson <chris@chris-wilson.co.uk> 2703b705cfSriastradh * 2803b705cfSriastradh */ 2903b705cfSriastradh 3003b705cfSriastradh#ifdef HAVE_CONFIG_H 3103b705cfSriastradh#include "config.h" 3203b705cfSriastradh#endif 3303b705cfSriastradh 3403b705cfSriastradh#include "sna.h" 3503b705cfSriastradh#include "sna_render.h" 3603b705cfSriastradh#include "sna_render_inline.h" 3703b705cfSriastradh#include "fb/fbpict.h" 3803b705cfSriastradh 3903b705cfSriastradh#include <mipict.h> 4003b705cfSriastradh 4103b705cfSriastradh#if 0 4203b705cfSriastradh#define __DBG(x) ErrorF x 4303b705cfSriastradh#else 4403b705cfSriastradh#define __DBG(x) 4503b705cfSriastradh#endif 4603b705cfSriastradh 4703b705cfSriastradh#define NO_ACCEL 0 4803b705cfSriastradh#define FORCE_FALLBACK 0 4903b705cfSriastradh#define NO_ALIGNED_BOXES 0 5003b705cfSriastradh#define NO_UNALIGNED_BOXES 0 5103b705cfSriastradh#define NO_SCAN_CONVERTER 0 5203b705cfSriastradh#define NO_GPU_THREADS 0 5303b705cfSriastradh 5403b705cfSriastradh/* TODO: Emit unantialiased and MSAA triangles. */ 5503b705cfSriastradh 5603b705cfSriastradh#ifndef MAX 5703b705cfSriastradh#define MAX(x,y) ((x) >= (y) ? (x) : (y)) 5803b705cfSriastradh#endif 5903b705cfSriastradh 6003b705cfSriastradh#ifndef MIN 6103b705cfSriastradh#define MIN(x,y) ((x) <= (y) ? (x) : (y)) 6203b705cfSriastradh#endif 6303b705cfSriastradh 6403b705cfSriastradh#define SAMPLES_X 17 6503b705cfSriastradh#define SAMPLES_Y 15 6603b705cfSriastradh 6703b705cfSriastradh#define FAST_SAMPLES_shift 2 6803b705cfSriastradh#define FAST_SAMPLES_X (1<<FAST_SAMPLES_shift) 6903b705cfSriastradh#define FAST_SAMPLES_Y (1<<FAST_SAMPLES_shift) 7003b705cfSriastradh#define FAST_SAMPLES_mask ((1<<FAST_SAMPLES_shift)-1) 7103b705cfSriastradh 7203b705cfSriastradh#define region_count(r) ((r)->data ? (r)->data->numRects : 1) 7303b705cfSriastradh#define region_boxes(r) ((r)->data ? (BoxPtr)((r)->data + 1) : &(r)->extents) 7403b705cfSriastradh 7503b705cfSriastradhtypedef void (*span_func_t)(struct sna *sna, 7603b705cfSriastradh struct sna_composite_spans_op *op, 7703b705cfSriastradh pixman_region16_t *clip, 7803b705cfSriastradh const BoxRec *box, 7903b705cfSriastradh int coverage); 8003b705cfSriastradh 8103b705cfSriastradh#if HAS_DEBUG_FULL 8203b705cfSriastradhstatic void _assert_pixmap_contains_box(PixmapPtr pixmap, BoxPtr box, const char *function) 8303b705cfSriastradh{ 8403b705cfSriastradh if (box->x1 < 0 || box->y1 < 0 || 8503b705cfSriastradh box->x2 > pixmap->drawable.width || 8603b705cfSriastradh box->y2 > pixmap->drawable.height) 8703b705cfSriastradh { 8803b705cfSriastradh ErrorF("%s: damage box is beyond the pixmap: box=(%d, %d), (%d, %d), pixmap=(%d, %d)\n", 8903b705cfSriastradh __FUNCTION__, 9003b705cfSriastradh box->x1, box->y1, box->x2, box->y2, 9103b705cfSriastradh pixmap->drawable.width, 9203b705cfSriastradh pixmap->drawable.height); 9303b705cfSriastradh assert(0); 9403b705cfSriastradh } 9503b705cfSriastradh} 9603b705cfSriastradh#define assert_pixmap_contains_box(p, b) _assert_pixmap_contains_box(p, b, __FUNCTION__) 9703b705cfSriastradh#else 9803b705cfSriastradh#define assert_pixmap_contains_box(p, b) 9903b705cfSriastradh#endif 10003b705cfSriastradh 10103b705cfSriastradhstatic void apply_damage(struct sna_composite_op *op, RegionPtr region) 10203b705cfSriastradh{ 10303b705cfSriastradh DBG(("%s: damage=%p, region=%ldx[(%d, %d), (%d, %d)]\n", 10403b705cfSriastradh __FUNCTION__, op->damage, 10503b705cfSriastradh (long)REGION_NUM_RECTS(region), 10603b705cfSriastradh region->extents.x1, region->extents.y1, 10703b705cfSriastradh region->extents.x2, region->extents.y2)); 10803b705cfSriastradh 10903b705cfSriastradh if (op->damage == NULL) 11003b705cfSriastradh return; 11103b705cfSriastradh 11203b705cfSriastradh RegionTranslate(region, op->dst.x, op->dst.y); 11303b705cfSriastradh 11403b705cfSriastradh assert_pixmap_contains_box(op->dst.pixmap, RegionExtents(region)); 11503b705cfSriastradh sna_damage_add(op->damage, region); 11603b705cfSriastradh} 11703b705cfSriastradh 11803b705cfSriastradhstatic void _apply_damage_box(struct sna_composite_op *op, const BoxRec *box) 11903b705cfSriastradh{ 12003b705cfSriastradh BoxRec r; 12103b705cfSriastradh 12203b705cfSriastradh r.x1 = box->x1 + op->dst.x; 12303b705cfSriastradh r.x2 = box->x2 + op->dst.x; 12403b705cfSriastradh r.y1 = box->y1 + op->dst.y; 12503b705cfSriastradh r.y2 = box->y2 + op->dst.y; 12603b705cfSriastradh 12703b705cfSriastradh assert_pixmap_contains_box(op->dst.pixmap, &r); 12803b705cfSriastradh sna_damage_add_box(op->damage, &r); 12903b705cfSriastradh} 13003b705cfSriastradh 13103b705cfSriastradhinline static void apply_damage_box(struct sna_composite_op *op, const BoxRec *box) 13203b705cfSriastradh{ 13303b705cfSriastradh if (op->damage) 13403b705cfSriastradh _apply_damage_box(op, box); 13503b705cfSriastradh} 13603b705cfSriastradh 13703b705cfSriastradhtypedef int grid_scaled_x_t; 13803b705cfSriastradhtypedef int grid_scaled_y_t; 13903b705cfSriastradh 14003b705cfSriastradh#define FAST_SAMPLES_X_TO_INT_FRAC(x, i, f) \ 14103b705cfSriastradh _GRID_TO_INT_FRAC_shift(x, i, f, FAST_SAMPLES_shift) 14203b705cfSriastradh 14303b705cfSriastradh#define FAST_SAMPLES_INT(x) ((x) >> (FAST_SAMPLES_shift)) 14403b705cfSriastradh#define FAST_SAMPLES_FRAC(x) ((x) & (FAST_SAMPLES_mask)) 14503b705cfSriastradh 14603b705cfSriastradh#define _GRID_TO_INT_FRAC_shift(t, i, f, b) do { \ 14703b705cfSriastradh (f) = FAST_SAMPLES_FRAC(t); \ 14803b705cfSriastradh (i) = FAST_SAMPLES_INT(t); \ 14903b705cfSriastradh} while (0) 15003b705cfSriastradh 15103b705cfSriastradh/* A grid area is a real in [0,1] scaled by 2*SAMPLES_X*SAMPLES_Y. We want 15203b705cfSriastradh * to be able to represent exactly areas of subpixel trapezoids whose 15303b705cfSriastradh * vertices are given in grid scaled coordinates. The scale factor 15403b705cfSriastradh * comes from needing to accurately represent the area 0.5*dx*dy of a 15503b705cfSriastradh * triangle with base dx and height dy in grid scaled numbers. */ 15603b705cfSriastradhtypedef int grid_area_t; 15703b705cfSriastradh#define FAST_SAMPLES_XY (2*FAST_SAMPLES_X*FAST_SAMPLES_Y) /* Unit area on the grid. */ 15803b705cfSriastradh 15903b705cfSriastradh#define AREA_TO_ALPHA(c) ((c) / (float)FAST_SAMPLES_XY) 16003b705cfSriastradh 16103b705cfSriastradhstruct quorem { 16203b705cfSriastradh int32_t quo; 16303b705cfSriastradh int32_t rem; 16403b705cfSriastradh}; 16503b705cfSriastradh 16603b705cfSriastradhstruct edge { 16703b705cfSriastradh struct edge *next, *prev; 16803b705cfSriastradh 16903b705cfSriastradh int dir; 17003b705cfSriastradh 17103b705cfSriastradh grid_scaled_y_t height_left; 17203b705cfSriastradh 17303b705cfSriastradh /* Current x coordinate while the edge is on the active 17403b705cfSriastradh * list. Initialised to the x coordinate of the top of the 17503b705cfSriastradh * edge. The quotient is in grid_scaled_x_t units and the 17603b705cfSriastradh * remainder is mod dy in grid_scaled_y_t units.*/ 17703b705cfSriastradh struct quorem x; 17803b705cfSriastradh 17903b705cfSriastradh /* Advance of the current x when moving down a subsample line. */ 18003b705cfSriastradh struct quorem dxdy; 18103b705cfSriastradh grid_scaled_y_t dy; 18203b705cfSriastradh 18303b705cfSriastradh /* The clipped y of the top of the edge. */ 18403b705cfSriastradh grid_scaled_y_t ytop; 18503b705cfSriastradh 18603b705cfSriastradh /* y2-y1 after orienting the edge downwards. */ 18703b705cfSriastradh}; 18803b705cfSriastradh 18903b705cfSriastradh/* Number of subsample rows per y-bucket. Must be SAMPLES_Y. */ 19003b705cfSriastradh#define EDGE_Y_BUCKET_HEIGHT FAST_SAMPLES_Y 19103b705cfSriastradh#define EDGE_Y_BUCKET_INDEX(y, ymin) (((y) - (ymin))/EDGE_Y_BUCKET_HEIGHT) 19203b705cfSriastradh 19303b705cfSriastradh/* A collection of sorted and vertically clipped edges of the polygon. 19403b705cfSriastradh * Edges are moved from the polygon to an active list while scan 19503b705cfSriastradh * converting. */ 19603b705cfSriastradhstruct polygon { 19703b705cfSriastradh /* The vertical clip extents. */ 19803b705cfSriastradh grid_scaled_y_t ymin, ymax; 19903b705cfSriastradh 20003b705cfSriastradh /* Array of edges all starting in the same bucket. An edge is put 20103b705cfSriastradh * into bucket EDGE_BUCKET_INDEX(edge->ytop, polygon->ymin) when 20203b705cfSriastradh * it is added to the polygon. */ 20303b705cfSriastradh struct edge **y_buckets; 20403b705cfSriastradh struct edge *y_buckets_embedded[64]; 20503b705cfSriastradh 20603b705cfSriastradh struct edge edges_embedded[32]; 20703b705cfSriastradh struct edge *edges; 20803b705cfSriastradh int num_edges; 20903b705cfSriastradh}; 21003b705cfSriastradh 21103b705cfSriastradh/* A cell records the effect on pixel coverage of polygon edges 21203b705cfSriastradh * passing through a pixel. It contains two accumulators of pixel 21303b705cfSriastradh * coverage. 21403b705cfSriastradh * 21503b705cfSriastradh * Consider the effects of a polygon edge on the coverage of a pixel 21603b705cfSriastradh * it intersects and that of the following one. The coverage of the 21703b705cfSriastradh * following pixel is the height of the edge multiplied by the width 21803b705cfSriastradh * of the pixel, and the coverage of the pixel itself is the area of 21903b705cfSriastradh * the trapezoid formed by the edge and the right side of the pixel. 22003b705cfSriastradh * 22103b705cfSriastradh * +-----------------------+-----------------------+ 22203b705cfSriastradh * | | | 22303b705cfSriastradh * | | | 22403b705cfSriastradh * |_______________________|_______________________| 22503b705cfSriastradh * | \...................|.......................|\ 22603b705cfSriastradh * | \..................|.......................| | 22703b705cfSriastradh * | \.................|.......................| | 22803b705cfSriastradh * | \....covered.....|.......................| | 22903b705cfSriastradh * | \....area.......|.......................| } covered height 23003b705cfSriastradh * | \..............|.......................| | 23103b705cfSriastradh * |uncovered\.............|.......................| | 23203b705cfSriastradh * | area \............|.......................| | 23303b705cfSriastradh * |___________\...........|.......................|/ 23403b705cfSriastradh * | | | 23503b705cfSriastradh * | | | 23603b705cfSriastradh * | | | 23703b705cfSriastradh * +-----------------------+-----------------------+ 23803b705cfSriastradh * 23903b705cfSriastradh * Since the coverage of the following pixel will always be a multiple 24003b705cfSriastradh * of the width of the pixel, we can store the height of the covered 24103b705cfSriastradh * area instead. The coverage of the pixel itself is the total 24203b705cfSriastradh * coverage minus the area of the uncovered area to the left of the 24303b705cfSriastradh * edge. As it's faster to compute the uncovered area we only store 24403b705cfSriastradh * that and subtract it from the total coverage later when forming 24503b705cfSriastradh * spans to blit. 24603b705cfSriastradh * 24703b705cfSriastradh * The heights and areas are signed, with left edges of the polygon 24803b705cfSriastradh * having positive sign and right edges having negative sign. When 24903b705cfSriastradh * two edges intersect they swap their left/rightness so their 25003b705cfSriastradh * contribution above and below the intersection point must be 25103b705cfSriastradh * computed separately. */ 25203b705cfSriastradhstruct cell { 25303b705cfSriastradh struct cell *next; 25403b705cfSriastradh int x; 25503b705cfSriastradh grid_area_t uncovered_area; 25603b705cfSriastradh grid_scaled_y_t covered_height; 25703b705cfSriastradh}; 25803b705cfSriastradh 25903b705cfSriastradh/* A cell list represents the scan line sparsely as cells ordered by 26003b705cfSriastradh * ascending x. It is geared towards scanning the cells in order 26103b705cfSriastradh * using an internal cursor. */ 26203b705cfSriastradhstruct cell_list { 26303b705cfSriastradh struct cell *cursor; 26403b705cfSriastradh 26503b705cfSriastradh /* Points to the left-most cell in the scan line. */ 26603b705cfSriastradh struct cell head, tail; 26703b705cfSriastradh 26803b705cfSriastradh int16_t x1, x2; 26903b705cfSriastradh int16_t count, size; 27003b705cfSriastradh struct cell *cells; 27103b705cfSriastradh struct cell embedded[256]; 27203b705cfSriastradh}; 27303b705cfSriastradh 27403b705cfSriastradh/* The active list contains edges in the current scan line ordered by 27503b705cfSriastradh * the x-coordinate of the intercept of the edge and the scan line. */ 27603b705cfSriastradhstruct active_list { 27703b705cfSriastradh /* Leftmost edge on the current scan line. */ 27803b705cfSriastradh struct edge head, tail; 27903b705cfSriastradh 28003b705cfSriastradh /* A lower bound on the height of the active edges is used to 28103b705cfSriastradh * estimate how soon some active edge ends. We can't advance the 28203b705cfSriastradh * scan conversion by a full pixel row if an edge ends somewhere 28303b705cfSriastradh * within it. */ 28403b705cfSriastradh grid_scaled_y_t min_height; 28503b705cfSriastradh int is_vertical; 28603b705cfSriastradh}; 28703b705cfSriastradh 28803b705cfSriastradhstruct tor { 28903b705cfSriastradh struct polygon polygon[1]; 29003b705cfSriastradh struct active_list active[1]; 29103b705cfSriastradh struct cell_list coverages[1]; 29203b705cfSriastradh 29303b705cfSriastradh /* Clip box. */ 29403b705cfSriastradh grid_scaled_x_t xmin, xmax; 29503b705cfSriastradh grid_scaled_y_t ymin, ymax; 29603b705cfSriastradh}; 29703b705cfSriastradh 29803b705cfSriastradh/* Compute the floored division a/b. Assumes / and % perform symmetric 29903b705cfSriastradh * division. */ 30003b705cfSriastradhinline static struct quorem 30103b705cfSriastradhfloored_divrem(int a, int b) 30203b705cfSriastradh{ 30303b705cfSriastradh struct quorem qr; 30403b705cfSriastradh qr.quo = a/b; 30503b705cfSriastradh qr.rem = a%b; 30603b705cfSriastradh if (qr.rem && (a^b)<0) { 30703b705cfSriastradh qr.quo -= 1; 30803b705cfSriastradh qr.rem += b; 30903b705cfSriastradh } 31003b705cfSriastradh return qr; 31103b705cfSriastradh} 31203b705cfSriastradh 31303b705cfSriastradh/* Compute the floored division (x*a)/b. Assumes / and % perform symmetric 31403b705cfSriastradh * division. */ 31503b705cfSriastradhstatic struct quorem 31603b705cfSriastradhfloored_muldivrem(int32_t x, int32_t a, int32_t b) 31703b705cfSriastradh{ 31803b705cfSriastradh struct quorem qr; 31903b705cfSriastradh int64_t xa = (int64_t)x*a; 32003b705cfSriastradh qr.quo = xa/b; 32103b705cfSriastradh qr.rem = xa%b; 32203b705cfSriastradh if (qr.rem && (xa>=0) != (b>=0)) { 32303b705cfSriastradh qr.quo -= 1; 32403b705cfSriastradh qr.rem += b; 32503b705cfSriastradh } 32603b705cfSriastradh return qr; 32703b705cfSriastradh} 32803b705cfSriastradh 32903b705cfSriastradh/* Rewinds the cell list's cursor to the beginning. After rewinding 33003b705cfSriastradh * we're good to cell_list_find() the cell any x coordinate. */ 33103b705cfSriastradhinline static void 33203b705cfSriastradhcell_list_rewind(struct cell_list *cells) 33303b705cfSriastradh{ 33403b705cfSriastradh cells->cursor = &cells->head; 33503b705cfSriastradh} 33603b705cfSriastradh 33703b705cfSriastradhstatic bool 33803b705cfSriastradhcell_list_init(struct cell_list *cells, int x1, int x2) 33903b705cfSriastradh{ 34003b705cfSriastradh cells->tail.next = NULL; 34103b705cfSriastradh cells->tail.x = INT_MAX; 34203b705cfSriastradh cells->head.x = INT_MIN; 34303b705cfSriastradh cells->head.next = &cells->tail; 34403b705cfSriastradh cell_list_rewind(cells); 34503b705cfSriastradh cells->count = 0; 34603b705cfSriastradh cells->x1 = x1; 34703b705cfSriastradh cells->x2 = x2; 34803b705cfSriastradh cells->size = x2 - x1 + 1; 34903b705cfSriastradh cells->cells = cells->embedded; 35003b705cfSriastradh if (cells->size > ARRAY_SIZE(cells->embedded)) 35103b705cfSriastradh cells->cells = malloc(cells->size * sizeof(struct cell)); 35203b705cfSriastradh return cells->cells != NULL; 35303b705cfSriastradh} 35403b705cfSriastradh 35503b705cfSriastradhstatic void 35603b705cfSriastradhcell_list_fini(struct cell_list *cells) 35703b705cfSriastradh{ 35803b705cfSriastradh if (cells->cells != cells->embedded) 35903b705cfSriastradh free(cells->cells); 36003b705cfSriastradh} 36103b705cfSriastradh 36203b705cfSriastradhinline static void 36303b705cfSriastradhcell_list_reset(struct cell_list *cells) 36403b705cfSriastradh{ 36503b705cfSriastradh cell_list_rewind(cells); 36603b705cfSriastradh cells->head.next = &cells->tail; 36703b705cfSriastradh cells->count = 0; 36803b705cfSriastradh} 36903b705cfSriastradh 37003b705cfSriastradhinline static struct cell * 37103b705cfSriastradhcell_list_alloc(struct cell_list *cells, 37203b705cfSriastradh struct cell *tail, 37303b705cfSriastradh int x) 37403b705cfSriastradh{ 37503b705cfSriastradh struct cell *cell; 37603b705cfSriastradh 37703b705cfSriastradh assert(cells->count < cells->size); 37803b705cfSriastradh cell = cells->cells + cells->count++; 37903b705cfSriastradh cell->next = tail->next; 38003b705cfSriastradh tail->next = cell; 38103b705cfSriastradh 38203b705cfSriastradh cell->x = x; 38303b705cfSriastradh cell->uncovered_area = 0; 38403b705cfSriastradh cell->covered_height = 0; 38503b705cfSriastradh return cell; 38603b705cfSriastradh} 38703b705cfSriastradh 38803b705cfSriastradh/* Find a cell at the given x-coordinate. Returns %NULL if a new cell 38903b705cfSriastradh * needed to be allocated but couldn't be. Cells must be found with 39003b705cfSriastradh * non-decreasing x-coordinate until the cell list is rewound using 39103b705cfSriastradh * cell_list_rewind(). Ownership of the returned cell is retained by 39203b705cfSriastradh * the cell list. */ 39303b705cfSriastradhinline static struct cell * 39403b705cfSriastradhcell_list_find(struct cell_list *cells, int x) 39503b705cfSriastradh{ 39603b705cfSriastradh struct cell *tail = cells->cursor; 39703b705cfSriastradh 39803b705cfSriastradh if (tail->x == x) 39903b705cfSriastradh return tail; 40003b705cfSriastradh 40103b705cfSriastradh if (x >= cells->x2) 40203b705cfSriastradh return &cells->tail; 40303b705cfSriastradh 40403b705cfSriastradh if (x < cells->x1) 40503b705cfSriastradh x = cells->x1; 40603b705cfSriastradh 40703b705cfSriastradh if (tail->x == x) 40803b705cfSriastradh return tail; 40903b705cfSriastradh 41003b705cfSriastradh do { 41103b705cfSriastradh if (tail->next->x > x) 41203b705cfSriastradh break; 41303b705cfSriastradh 41403b705cfSriastradh tail = tail->next; 41503b705cfSriastradh if (tail->next->x > x) 41603b705cfSriastradh break; 41703b705cfSriastradh 41803b705cfSriastradh tail = tail->next; 41903b705cfSriastradh if (tail->next->x > x) 42003b705cfSriastradh break; 42103b705cfSriastradh 42203b705cfSriastradh tail = tail->next; 42303b705cfSriastradh } while (1); 42403b705cfSriastradh 42503b705cfSriastradh if (tail->x != x) 42603b705cfSriastradh tail = cell_list_alloc (cells, tail, x); 42703b705cfSriastradh 42803b705cfSriastradh return cells->cursor = tail; 42903b705cfSriastradh} 43003b705cfSriastradh 43103b705cfSriastradh/* Add a subpixel span covering [x1, x2) to the coverage cells. */ 43203b705cfSriastradhinline static void 43303b705cfSriastradhcell_list_add_subspan(struct cell_list *cells, 43403b705cfSriastradh grid_scaled_x_t x1, 43503b705cfSriastradh grid_scaled_x_t x2) 43603b705cfSriastradh{ 43703b705cfSriastradh struct cell *cell; 43803b705cfSriastradh int ix1, fx1; 43903b705cfSriastradh int ix2, fx2; 44003b705cfSriastradh 44103b705cfSriastradh if (x1 == x2) 44203b705cfSriastradh return; 44303b705cfSriastradh 44403b705cfSriastradh FAST_SAMPLES_X_TO_INT_FRAC(x1, ix1, fx1); 44503b705cfSriastradh FAST_SAMPLES_X_TO_INT_FRAC(x2, ix2, fx2); 44603b705cfSriastradh 44703b705cfSriastradh __DBG(("%s: x1=%d (%d+%d), x2=%d (%d+%d)\n", __FUNCTION__, 44803b705cfSriastradh x1, ix1, fx1, x2, ix2, fx2)); 44903b705cfSriastradh 45003b705cfSriastradh cell = cell_list_find(cells, ix1); 45103b705cfSriastradh if (ix1 != ix2) { 45203b705cfSriastradh cell->uncovered_area += 2*fx1; 45303b705cfSriastradh ++cell->covered_height; 45403b705cfSriastradh 45503b705cfSriastradh cell = cell_list_find(cells, ix2); 45603b705cfSriastradh cell->uncovered_area -= 2*fx2; 45703b705cfSriastradh --cell->covered_height; 45803b705cfSriastradh } else 45903b705cfSriastradh cell->uncovered_area += 2*(fx1-fx2); 46003b705cfSriastradh} 46103b705cfSriastradh 46203b705cfSriastradhinline static void 46303b705cfSriastradhcell_list_add_span(struct cell_list *cells, 46403b705cfSriastradh grid_scaled_x_t x1, 46503b705cfSriastradh grid_scaled_x_t x2) 46603b705cfSriastradh{ 46703b705cfSriastradh struct cell *cell; 46803b705cfSriastradh int ix1, fx1; 46903b705cfSriastradh int ix2, fx2; 47003b705cfSriastradh 47103b705cfSriastradh FAST_SAMPLES_X_TO_INT_FRAC(x1, ix1, fx1); 47203b705cfSriastradh FAST_SAMPLES_X_TO_INT_FRAC(x2, ix2, fx2); 47303b705cfSriastradh 47403b705cfSriastradh __DBG(("%s: x1=%d (%d+%d), x2=%d (%d+%d)\n", __FUNCTION__, 47503b705cfSriastradh x1, ix1, fx1, x2, ix2, fx2)); 47603b705cfSriastradh 47703b705cfSriastradh cell = cell_list_find(cells, ix1); 47803b705cfSriastradh if (ix1 != ix2) { 47903b705cfSriastradh cell->uncovered_area += 2*fx1*FAST_SAMPLES_Y; 48003b705cfSriastradh cell->covered_height += FAST_SAMPLES_Y; 48103b705cfSriastradh 48203b705cfSriastradh cell = cell_list_find(cells, ix2); 48303b705cfSriastradh cell->uncovered_area -= 2*fx2*FAST_SAMPLES_Y; 48403b705cfSriastradh cell->covered_height -= FAST_SAMPLES_Y; 48503b705cfSriastradh } else 48603b705cfSriastradh cell->uncovered_area += 2*(fx1-fx2)*FAST_SAMPLES_Y; 48703b705cfSriastradh} 48803b705cfSriastradh 48903b705cfSriastradhstatic void 49003b705cfSriastradhpolygon_fini(struct polygon *polygon) 49103b705cfSriastradh{ 49203b705cfSriastradh if (polygon->y_buckets != polygon->y_buckets_embedded) 49303b705cfSriastradh free(polygon->y_buckets); 49403b705cfSriastradh 49503b705cfSriastradh if (polygon->edges != polygon->edges_embedded) 49603b705cfSriastradh free(polygon->edges); 49703b705cfSriastradh} 49803b705cfSriastradh 49903b705cfSriastradhstatic bool 50003b705cfSriastradhpolygon_init(struct polygon *polygon, 50103b705cfSriastradh int num_edges, 50203b705cfSriastradh grid_scaled_y_t ymin, 50303b705cfSriastradh grid_scaled_y_t ymax) 50403b705cfSriastradh{ 50503b705cfSriastradh unsigned h = ymax - ymin; 50603b705cfSriastradh unsigned num_buckets = 50703b705cfSriastradh EDGE_Y_BUCKET_INDEX(ymax+EDGE_Y_BUCKET_HEIGHT-1, ymin); 50803b705cfSriastradh 50903b705cfSriastradh if (unlikely(h > 0x7FFFFFFFU - EDGE_Y_BUCKET_HEIGHT)) 51003b705cfSriastradh goto bail_no_mem; /* even if you could, you wouldn't want to. */ 51103b705cfSriastradh 51203b705cfSriastradh polygon->edges = polygon->edges_embedded; 51303b705cfSriastradh polygon->y_buckets = polygon->y_buckets_embedded; 51403b705cfSriastradh 51503b705cfSriastradh polygon->num_edges = 0; 51603b705cfSriastradh if (num_edges > (int)ARRAY_SIZE(polygon->edges_embedded)) { 51703b705cfSriastradh polygon->edges = malloc(sizeof(struct edge)*num_edges); 51803b705cfSriastradh if (unlikely(NULL == polygon->edges)) 51903b705cfSriastradh goto bail_no_mem; 52003b705cfSriastradh } 52103b705cfSriastradh 52203b705cfSriastradh if (num_buckets >= ARRAY_SIZE(polygon->y_buckets_embedded)) { 52303b705cfSriastradh polygon->y_buckets = malloc((1+num_buckets)*sizeof(struct edge *)); 52403b705cfSriastradh if (unlikely(NULL == polygon->y_buckets)) 52503b705cfSriastradh goto bail_no_mem; 52603b705cfSriastradh } 52703b705cfSriastradh memset(polygon->y_buckets, 0, num_buckets * sizeof(struct edge *)); 52803b705cfSriastradh polygon->y_buckets[num_buckets] = (void *)-1; 52903b705cfSriastradh 53003b705cfSriastradh polygon->ymin = ymin; 53103b705cfSriastradh polygon->ymax = ymax; 53203b705cfSriastradh return true; 53303b705cfSriastradh 53403b705cfSriastradhbail_no_mem: 53503b705cfSriastradh polygon_fini(polygon); 53603b705cfSriastradh return false; 53703b705cfSriastradh} 53803b705cfSriastradh 53903b705cfSriastradhstatic void 54003b705cfSriastradh_polygon_insert_edge_into_its_y_bucket(struct polygon *polygon, struct edge *e) 54103b705cfSriastradh{ 54203b705cfSriastradh unsigned ix = EDGE_Y_BUCKET_INDEX(e->ytop, polygon->ymin); 54303b705cfSriastradh struct edge **ptail = &polygon->y_buckets[ix]; 54403b705cfSriastradh e->next = *ptail; 54503b705cfSriastradh *ptail = e; 54603b705cfSriastradh} 54703b705cfSriastradh 54803b705cfSriastradhinline static void 54903b705cfSriastradhpolygon_add_edge(struct polygon *polygon, 55003b705cfSriastradh grid_scaled_x_t x1, 55103b705cfSriastradh grid_scaled_x_t x2, 55203b705cfSriastradh grid_scaled_y_t y1, 55303b705cfSriastradh grid_scaled_y_t y2, 55403b705cfSriastradh grid_scaled_y_t top, 55503b705cfSriastradh grid_scaled_y_t bottom, 55603b705cfSriastradh int dir) 55703b705cfSriastradh{ 55803b705cfSriastradh struct edge *e = &polygon->edges[polygon->num_edges++]; 55903b705cfSriastradh grid_scaled_x_t dx = x2 - x1; 56003b705cfSriastradh grid_scaled_y_t dy = y2 - y1; 56103b705cfSriastradh grid_scaled_y_t ytop, ybot; 56203b705cfSriastradh grid_scaled_y_t ymin = polygon->ymin; 56303b705cfSriastradh grid_scaled_y_t ymax = polygon->ymax; 56403b705cfSriastradh 56503b705cfSriastradh __DBG(("%s: edge=(%d [%d.%d], %d [%d.%d]), (%d [%d.%d], %d [%d.%d]), top=%d [%d.%d], bottom=%d [%d.%d], dir=%d\n", 56603b705cfSriastradh __FUNCTION__, 56703b705cfSriastradh x1, FAST_SAMPLES_INT(x1), FAST_SAMPLES_FRAC(x1), 56803b705cfSriastradh y1, FAST_SAMPLES_INT(y1), FAST_SAMPLES_FRAC(y1), 56903b705cfSriastradh x2, FAST_SAMPLES_INT(x2), FAST_SAMPLES_FRAC(x2), 57003b705cfSriastradh y2, FAST_SAMPLES_INT(y2), FAST_SAMPLES_FRAC(y2), 57103b705cfSriastradh top, FAST_SAMPLES_INT(top), FAST_SAMPLES_FRAC(top), 57203b705cfSriastradh bottom, FAST_SAMPLES_INT(bottom), FAST_SAMPLES_FRAC(bottom), 57303b705cfSriastradh dir)); 57403b705cfSriastradh assert (dy > 0); 57503b705cfSriastradh 57603b705cfSriastradh e->dy = dy; 57703b705cfSriastradh e->dir = dir; 57803b705cfSriastradh 57903b705cfSriastradh ytop = top >= ymin ? top : ymin; 58003b705cfSriastradh ybot = bottom <= ymax ? bottom : ymax; 58103b705cfSriastradh e->ytop = ytop; 58203b705cfSriastradh e->height_left = ybot - ytop; 58303b705cfSriastradh if (e->height_left <= 0) 58403b705cfSriastradh return; 58503b705cfSriastradh 58603b705cfSriastradh if (dx == 0) { 58703b705cfSriastradh e->x.quo = x1; 58803b705cfSriastradh e->x.rem = 0; 58903b705cfSriastradh e->dy = 0; 59003b705cfSriastradh e->dxdy.quo = 0; 59103b705cfSriastradh e->dxdy.rem = 0; 59203b705cfSriastradh } else { 59303b705cfSriastradh e->dxdy = floored_divrem(dx, dy); 59403b705cfSriastradh if (ytop == y1) { 59503b705cfSriastradh e->x.quo = x1; 59603b705cfSriastradh e->x.rem = 0; 59703b705cfSriastradh } else { 59803b705cfSriastradh e->x = floored_muldivrem(ytop - y1, dx, dy); 59903b705cfSriastradh e->x.quo += x1; 60003b705cfSriastradh } 60103b705cfSriastradh } 60203b705cfSriastradh 60303b705cfSriastradh _polygon_insert_edge_into_its_y_bucket(polygon, e); 60403b705cfSriastradh 60503b705cfSriastradh e->x.rem -= dy; /* Bias the remainder for faster edge advancement. */ 60603b705cfSriastradh} 60703b705cfSriastradh 60803b705cfSriastradhinline static void 60903b705cfSriastradhpolygon_add_line(struct polygon *polygon, 61003b705cfSriastradh const xPointFixed *p1, 61103b705cfSriastradh const xPointFixed *p2) 61203b705cfSriastradh{ 61303b705cfSriastradh struct edge *e = &polygon->edges[polygon->num_edges]; 61403b705cfSriastradh grid_scaled_x_t dx = p2->x - p1->x; 61503b705cfSriastradh grid_scaled_y_t dy = p2->y - p1->y; 61603b705cfSriastradh grid_scaled_y_t top, bot; 61703b705cfSriastradh 61803b705cfSriastradh if (dy == 0) 61903b705cfSriastradh return; 62003b705cfSriastradh 62103b705cfSriastradh __DBG(("%s: line=(%d, %d), (%d, %d)\n", 62203b705cfSriastradh __FUNCTION__, (int)p1->x, (int)p1->y, (int)p2->x, (int)p2->y)); 62303b705cfSriastradh 62403b705cfSriastradh e->dir = 1; 62503b705cfSriastradh if (dy < 0) { 62603b705cfSriastradh const xPointFixed *t; 62703b705cfSriastradh 62803b705cfSriastradh dx = -dx; 62903b705cfSriastradh dy = -dy; 63003b705cfSriastradh 63103b705cfSriastradh e->dir = -1; 63203b705cfSriastradh 63303b705cfSriastradh t = p1; 63403b705cfSriastradh p1 = p2; 63503b705cfSriastradh p2 = t; 63603b705cfSriastradh } 63703b705cfSriastradh assert (dy > 0); 63803b705cfSriastradh e->dy = dy; 63903b705cfSriastradh 64003b705cfSriastradh top = MAX(p1->y, polygon->ymin); 64103b705cfSriastradh bot = MIN(p2->y, polygon->ymax); 64203b705cfSriastradh if (bot <= top) 64303b705cfSriastradh return; 64403b705cfSriastradh 64503b705cfSriastradh e->ytop = top; 64603b705cfSriastradh e->height_left = bot - top; 64703b705cfSriastradh if (e->height_left <= 0) 64803b705cfSriastradh return; 64903b705cfSriastradh 65003b705cfSriastradh if (dx == 0) { 65103b705cfSriastradh e->x.quo = p1->x; 65203b705cfSriastradh e->x.rem = -dy; 65303b705cfSriastradh e->dxdy.quo = 0; 65403b705cfSriastradh e->dxdy.rem = 0; 65503b705cfSriastradh e->dy = 0; 65603b705cfSriastradh } else { 65703b705cfSriastradh e->dxdy = floored_divrem(dx, dy); 65803b705cfSriastradh if (top == p1->y) { 65903b705cfSriastradh e->x.quo = p1->x; 66003b705cfSriastradh e->x.rem = -dy; 66103b705cfSriastradh } else { 66203b705cfSriastradh e->x = floored_muldivrem(top - p1->y, dx, dy); 66303b705cfSriastradh e->x.quo += p1->x; 66403b705cfSriastradh e->x.rem -= dy; 66503b705cfSriastradh } 66603b705cfSriastradh } 66703b705cfSriastradh 66803b705cfSriastradh if (polygon->num_edges > 0) { 66903b705cfSriastradh struct edge *prev = &polygon->edges[polygon->num_edges-1]; 67003b705cfSriastradh /* detect degenerate triangles inserted into tristrips */ 67103b705cfSriastradh if (e->dir == -prev->dir && 67203b705cfSriastradh e->ytop == prev->ytop && 67303b705cfSriastradh e->height_left == prev->height_left && 67403b705cfSriastradh e->x.quo == prev->x.quo && 67503b705cfSriastradh e->x.rem == prev->x.rem && 67603b705cfSriastradh e->dxdy.quo == prev->dxdy.quo && 67703b705cfSriastradh e->dxdy.rem == prev->dxdy.rem) { 67803b705cfSriastradh unsigned ix = EDGE_Y_BUCKET_INDEX(e->ytop, 67903b705cfSriastradh polygon->ymin); 68003b705cfSriastradh polygon->y_buckets[ix] = prev->next; 68103b705cfSriastradh polygon->num_edges--; 68203b705cfSriastradh return; 68303b705cfSriastradh } 68403b705cfSriastradh } 68503b705cfSriastradh 68603b705cfSriastradh _polygon_insert_edge_into_its_y_bucket(polygon, e); 68703b705cfSriastradh polygon->num_edges++; 68803b705cfSriastradh} 68903b705cfSriastradh 69003b705cfSriastradhstatic void 69103b705cfSriastradhactive_list_reset(struct active_list *active) 69203b705cfSriastradh{ 69303b705cfSriastradh active->head.height_left = INT_MAX; 69403b705cfSriastradh active->head.x.quo = INT_MIN; 69503b705cfSriastradh active->head.dy = 0; 69603b705cfSriastradh active->head.prev = NULL; 69703b705cfSriastradh active->head.next = &active->tail; 69803b705cfSriastradh active->tail.prev = &active->head; 69903b705cfSriastradh active->tail.next = NULL; 70003b705cfSriastradh active->tail.x.quo = INT_MAX; 70103b705cfSriastradh active->tail.height_left = INT_MAX; 70203b705cfSriastradh active->tail.dy = 0; 70303b705cfSriastradh active->min_height = INT_MAX; 70403b705cfSriastradh active->is_vertical = 1; 70503b705cfSriastradh} 70603b705cfSriastradh 70703b705cfSriastradhstatic struct edge * 70803b705cfSriastradhmerge_sorted_edges(struct edge *head_a, struct edge *head_b) 70903b705cfSriastradh{ 71003b705cfSriastradh struct edge *head, **next, *prev; 71103b705cfSriastradh int32_t x; 71203b705cfSriastradh 71303b705cfSriastradh if (head_b == NULL) 71403b705cfSriastradh return head_a; 71503b705cfSriastradh 71603b705cfSriastradh prev = head_a->prev; 71703b705cfSriastradh next = &head; 71803b705cfSriastradh if (head_a->x.quo <= head_b->x.quo) { 71903b705cfSriastradh head = head_a; 72003b705cfSriastradh } else { 72103b705cfSriastradh head = head_b; 72203b705cfSriastradh head_b->prev = prev; 72303b705cfSriastradh goto start_with_b; 72403b705cfSriastradh } 72503b705cfSriastradh 72603b705cfSriastradh do { 72703b705cfSriastradh x = head_b->x.quo; 72803b705cfSriastradh while (head_a != NULL && head_a->x.quo <= x) { 72903b705cfSriastradh prev = head_a; 73003b705cfSriastradh next = &head_a->next; 73103b705cfSriastradh head_a = head_a->next; 73203b705cfSriastradh } 73303b705cfSriastradh 73403b705cfSriastradh head_b->prev = prev; 73503b705cfSriastradh *next = head_b; 73603b705cfSriastradh if (head_a == NULL) 73703b705cfSriastradh return head; 73803b705cfSriastradh 73903b705cfSriastradhstart_with_b: 74003b705cfSriastradh x = head_a->x.quo; 74103b705cfSriastradh while (head_b != NULL && head_b->x.quo <= x) { 74203b705cfSriastradh prev = head_b; 74303b705cfSriastradh next = &head_b->next; 74403b705cfSriastradh head_b = head_b->next; 74503b705cfSriastradh } 74603b705cfSriastradh 74703b705cfSriastradh head_a->prev = prev; 74803b705cfSriastradh *next = head_a; 74903b705cfSriastradh if (head_b == NULL) 75003b705cfSriastradh return head; 75103b705cfSriastradh } while (1); 75203b705cfSriastradh} 75303b705cfSriastradh 75403b705cfSriastradhstatic struct edge * 75503b705cfSriastradhsort_edges(struct edge *list, 75603b705cfSriastradh unsigned int level, 75703b705cfSriastradh struct edge **head_out) 75803b705cfSriastradh{ 75903b705cfSriastradh struct edge *head_other, *remaining; 76003b705cfSriastradh unsigned int i; 76103b705cfSriastradh 76203b705cfSriastradh head_other = list->next; 76303b705cfSriastradh if (head_other == NULL) { 76403b705cfSriastradh *head_out = list; 76503b705cfSriastradh return NULL; 76603b705cfSriastradh } 76703b705cfSriastradh 76803b705cfSriastradh remaining = head_other->next; 76903b705cfSriastradh if (list->x.quo <= head_other->x.quo) { 77003b705cfSriastradh *head_out = list; 77103b705cfSriastradh head_other->next = NULL; 77203b705cfSriastradh } else { 77303b705cfSriastradh *head_out = head_other; 77403b705cfSriastradh head_other->prev = list->prev; 77503b705cfSriastradh head_other->next = list; 77603b705cfSriastradh list->prev = head_other; 77703b705cfSriastradh list->next = NULL; 77803b705cfSriastradh } 77903b705cfSriastradh 78003b705cfSriastradh for (i = 0; i < level && remaining; i++) { 78103b705cfSriastradh remaining = sort_edges(remaining, i, &head_other); 78203b705cfSriastradh *head_out = merge_sorted_edges(*head_out, head_other); 78303b705cfSriastradh } 78403b705cfSriastradh 78503b705cfSriastradh return remaining; 78603b705cfSriastradh} 78703b705cfSriastradh 78803b705cfSriastradhstatic struct edge *filter(struct edge *edges) 78903b705cfSriastradh{ 79003b705cfSriastradh struct edge *e; 79103b705cfSriastradh 79203b705cfSriastradh e = edges; 79303b705cfSriastradh do { 79403b705cfSriastradh struct edge *n = e->next; 79503b705cfSriastradh if (e->dir == -n->dir && 79603b705cfSriastradh e->height_left == n->height_left && 79703b705cfSriastradh *(uint64_t *)&e->x == *(uint64_t *)&n->x && 79803b705cfSriastradh *(uint64_t *)&e->dxdy == *(uint64_t *)&n->dxdy) { 79903b705cfSriastradh if (e->prev) 80003b705cfSriastradh e->prev->next = n->next; 80103b705cfSriastradh else 80203b705cfSriastradh edges = n->next; 80303b705cfSriastradh if (n->next) 80403b705cfSriastradh n->next->prev = e->prev; 80503b705cfSriastradh else 80603b705cfSriastradh break; 80703b705cfSriastradh 80803b705cfSriastradh e = n->next; 80903b705cfSriastradh } else 81003b705cfSriastradh e = e->next; 81103b705cfSriastradh } while (e->next); 81203b705cfSriastradh 81303b705cfSriastradh return edges; 81403b705cfSriastradh} 81503b705cfSriastradh 81603b705cfSriastradhstatic struct edge * 81703b705cfSriastradhmerge_unsorted_edges (struct edge *head, struct edge *unsorted) 81803b705cfSriastradh{ 81903b705cfSriastradh sort_edges (unsorted, UINT_MAX, &unsorted); 82003b705cfSriastradh return merge_sorted_edges (head, filter(unsorted)); 82103b705cfSriastradh} 82203b705cfSriastradh 82303b705cfSriastradh/* Test if the edges on the active list can be safely advanced by a 82403b705cfSriastradh * full row without intersections or any edges ending. */ 82503b705cfSriastradhinline static bool 82603b705cfSriastradhcan_full_step(struct active_list *active) 82703b705cfSriastradh{ 82803b705cfSriastradh /* Recomputes the minimum height of all edges on the active 82903b705cfSriastradh * list if we have been dropping edges. */ 83003b705cfSriastradh if (active->min_height <= 0) { 83103b705cfSriastradh const struct edge *e; 83203b705cfSriastradh int min_height = INT_MAX; 83303b705cfSriastradh int is_vertical = 1; 83403b705cfSriastradh 83503b705cfSriastradh for (e = active->head.next; &active->tail != e; e = e->next) { 83603b705cfSriastradh if (e->height_left < min_height) 83703b705cfSriastradh min_height = e->height_left; 83803b705cfSriastradh if (is_vertical) 83903b705cfSriastradh is_vertical = e->dy == 0; 84003b705cfSriastradh } 84103b705cfSriastradh 84203b705cfSriastradh active->is_vertical = is_vertical; 84303b705cfSriastradh active->min_height = min_height; 84403b705cfSriastradh } 84503b705cfSriastradh 84603b705cfSriastradh if (active->min_height < FAST_SAMPLES_Y) 84703b705cfSriastradh return false; 84803b705cfSriastradh 84903b705cfSriastradh return active->is_vertical; 85003b705cfSriastradh} 85103b705cfSriastradh 85203b705cfSriastradhinline static void 85303b705cfSriastradhmerge_edges(struct active_list *active, struct edge *edges) 85403b705cfSriastradh{ 85503b705cfSriastradh active->head.next = merge_unsorted_edges (active->head.next, edges); 85603b705cfSriastradh} 85703b705cfSriastradh 85803b705cfSriastradhinline static void 85903b705cfSriastradhfill_buckets(struct active_list *active, 86003b705cfSriastradh struct edge *edge, 86103b705cfSriastradh struct edge **buckets) 86203b705cfSriastradh{ 86303b705cfSriastradh int min_height = active->min_height; 86403b705cfSriastradh int is_vertical = active->is_vertical; 86503b705cfSriastradh 86603b705cfSriastradh while (edge) { 86703b705cfSriastradh struct edge *next = edge->next; 86803b705cfSriastradh struct edge **b = &buckets[edge->ytop & (FAST_SAMPLES_Y-1)]; 86903b705cfSriastradh if (*b) 87003b705cfSriastradh (*b)->prev = edge; 87103b705cfSriastradh edge->next = *b; 87203b705cfSriastradh edge->prev = NULL; 87303b705cfSriastradh *b = edge; 87403b705cfSriastradh if (edge->height_left < min_height) 87503b705cfSriastradh min_height = edge->height_left; 87603b705cfSriastradh if (is_vertical) 87703b705cfSriastradh is_vertical = edge->dy == 0; 87803b705cfSriastradh edge = next; 87903b705cfSriastradh } 88003b705cfSriastradh 88103b705cfSriastradh active->is_vertical = is_vertical; 88203b705cfSriastradh active->min_height = min_height; 88303b705cfSriastradh} 88403b705cfSriastradh 88503b705cfSriastradhinline static void 88603b705cfSriastradhnonzero_subrow(struct active_list *active, struct cell_list *coverages) 88703b705cfSriastradh{ 88803b705cfSriastradh struct edge *edge = active->head.next; 88903b705cfSriastradh grid_scaled_x_t prev_x = INT_MIN; 89003b705cfSriastradh int winding = 0, xstart = INT_MIN; 89103b705cfSriastradh 89203b705cfSriastradh cell_list_rewind (coverages); 89303b705cfSriastradh 89403b705cfSriastradh while (&active->tail != edge) { 89503b705cfSriastradh struct edge *next = edge->next; 89603b705cfSriastradh 89703b705cfSriastradh winding += edge->dir; 89803b705cfSriastradh if (0 == winding) { 89903b705cfSriastradh if (edge->next->x.quo != edge->x.quo) { 90003b705cfSriastradh cell_list_add_subspan(coverages, 90103b705cfSriastradh xstart, edge->x.quo); 90203b705cfSriastradh xstart = INT_MIN; 90303b705cfSriastradh } 90403b705cfSriastradh } else if (xstart < 0) 90503b705cfSriastradh xstart = edge->x.quo; 90603b705cfSriastradh 90703b705cfSriastradh if (--edge->height_left) { 90803b705cfSriastradh if (edge->dy) { 90903b705cfSriastradh edge->x.quo += edge->dxdy.quo; 91003b705cfSriastradh edge->x.rem += edge->dxdy.rem; 91103b705cfSriastradh if (edge->x.rem >= 0) { 91203b705cfSriastradh ++edge->x.quo; 91303b705cfSriastradh edge->x.rem -= edge->dy; 91403b705cfSriastradh } 91503b705cfSriastradh } 91603b705cfSriastradh 91703b705cfSriastradh if (edge->x.quo < prev_x) { 91803b705cfSriastradh struct edge *pos = edge->prev; 91903b705cfSriastradh pos->next = next; 92003b705cfSriastradh next->prev = pos; 92103b705cfSriastradh do { 92203b705cfSriastradh pos = pos->prev; 92303b705cfSriastradh } while (edge->x.quo < pos->x.quo); 92403b705cfSriastradh pos->next->prev = edge; 92503b705cfSriastradh edge->next = pos->next; 92603b705cfSriastradh edge->prev = pos; 92703b705cfSriastradh pos->next = edge; 92803b705cfSriastradh } else 92903b705cfSriastradh prev_x = edge->x.quo; 93003b705cfSriastradh } else { 93103b705cfSriastradh edge->prev->next = next; 93203b705cfSriastradh next->prev = edge->prev; 93303b705cfSriastradh active->min_height = -1; 93403b705cfSriastradh } 93503b705cfSriastradh 93603b705cfSriastradh edge = next; 93703b705cfSriastradh } 93803b705cfSriastradh} 93903b705cfSriastradh 94003b705cfSriastradhstatic void 94103b705cfSriastradhnonzero_row(struct active_list *active, struct cell_list *coverages) 94203b705cfSriastradh{ 94303b705cfSriastradh struct edge *left = active->head.next; 94403b705cfSriastradh 94503b705cfSriastradh assert(active->is_vertical); 94603b705cfSriastradh 94703b705cfSriastradh while (&active->tail != left) { 94803b705cfSriastradh struct edge *right; 94903b705cfSriastradh int winding = left->dir; 95003b705cfSriastradh 95103b705cfSriastradh left->height_left -= FAST_SAMPLES_Y; 95203b705cfSriastradh if (! left->height_left) { 95303b705cfSriastradh left->prev->next = left->next; 95403b705cfSriastradh left->next->prev = left->prev; 95503b705cfSriastradh } 95603b705cfSriastradh 95703b705cfSriastradh right = left->next; 95803b705cfSriastradh do { 95903b705cfSriastradh right->height_left -= FAST_SAMPLES_Y; 96003b705cfSriastradh if (!right->height_left) { 96103b705cfSriastradh right->prev->next = right->next; 96203b705cfSriastradh right->next->prev = right->prev; 96303b705cfSriastradh } 96403b705cfSriastradh 96503b705cfSriastradh winding += right->dir; 96603b705cfSriastradh if (0 == winding) 96703b705cfSriastradh break; 96803b705cfSriastradh 96903b705cfSriastradh right = right->next; 97003b705cfSriastradh } while (1); 97103b705cfSriastradh 97203b705cfSriastradh cell_list_add_span(coverages, left->x.quo, right->x.quo); 97303b705cfSriastradh left = right->next; 97403b705cfSriastradh } 97503b705cfSriastradh} 97603b705cfSriastradh 97703b705cfSriastradhstatic void 97803b705cfSriastradhtor_fini(struct tor *converter) 97903b705cfSriastradh{ 98003b705cfSriastradh polygon_fini(converter->polygon); 98103b705cfSriastradh cell_list_fini(converter->coverages); 98203b705cfSriastradh} 98303b705cfSriastradh 98403b705cfSriastradhstatic bool 98503b705cfSriastradhtor_init(struct tor *converter, const BoxRec *box, int num_edges) 98603b705cfSriastradh{ 98703b705cfSriastradh __DBG(("%s: (%d, %d),(%d, %d) x (%d, %d), num_edges=%d\n", 98803b705cfSriastradh __FUNCTION__, 98903b705cfSriastradh box->x1, box->y1, box->x2, box->y2, 99003b705cfSriastradh FAST_SAMPLES_X, FAST_SAMPLES_Y, 99103b705cfSriastradh num_edges)); 99203b705cfSriastradh 99303b705cfSriastradh converter->xmin = box->x1; 99403b705cfSriastradh converter->ymin = box->y1; 99503b705cfSriastradh converter->xmax = box->x2; 99603b705cfSriastradh converter->ymax = box->y2; 99703b705cfSriastradh 99803b705cfSriastradh if (!cell_list_init(converter->coverages, box->x1, box->x2)) 99903b705cfSriastradh return false; 100003b705cfSriastradh 100103b705cfSriastradh active_list_reset(converter->active); 100203b705cfSriastradh if (!polygon_init(converter->polygon, 100303b705cfSriastradh num_edges, 100403b705cfSriastradh box->y1 * FAST_SAMPLES_Y, 100503b705cfSriastradh box->y2 * FAST_SAMPLES_Y)) { 100603b705cfSriastradh cell_list_fini(converter->coverages); 100703b705cfSriastradh return false; 100803b705cfSriastradh } 100903b705cfSriastradh 101003b705cfSriastradh return true; 101103b705cfSriastradh} 101203b705cfSriastradh 101303b705cfSriastradhstatic void 101403b705cfSriastradhtor_add_edge(struct tor *converter, 101503b705cfSriastradh const xTrapezoid *t, 101603b705cfSriastradh const xLineFixed *edge, 101703b705cfSriastradh int dir) 101803b705cfSriastradh{ 101903b705cfSriastradh polygon_add_edge(converter->polygon, 102003b705cfSriastradh edge->p1.x, edge->p2.x, 102103b705cfSriastradh edge->p1.y, edge->p2.y, 102203b705cfSriastradh t->top, t->bottom, 102303b705cfSriastradh dir); 102403b705cfSriastradh} 102503b705cfSriastradh 102603b705cfSriastradhstatic void 102703b705cfSriastradhstep_edges(struct active_list *active, int count) 102803b705cfSriastradh{ 102903b705cfSriastradh struct edge *edge; 103003b705cfSriastradh 103103b705cfSriastradh count *= FAST_SAMPLES_Y; 103203b705cfSriastradh for (edge = active->head.next; edge != &active->tail; edge = edge->next) { 103303b705cfSriastradh edge->height_left -= count; 103403b705cfSriastradh if (! edge->height_left) { 103503b705cfSriastradh edge->prev->next = edge->next; 103603b705cfSriastradh edge->next->prev = edge->prev; 103703b705cfSriastradh } 103803b705cfSriastradh } 103903b705cfSriastradh} 104003b705cfSriastradh 104103b705cfSriastradhstatic void 104203b705cfSriastradhtor_blt_span(struct sna *sna, 104303b705cfSriastradh struct sna_composite_spans_op *op, 104403b705cfSriastradh pixman_region16_t *clip, 104503b705cfSriastradh const BoxRec *box, 104603b705cfSriastradh int coverage) 104703b705cfSriastradh{ 104803b705cfSriastradh __DBG(("%s: %d -> %d @ %d\n", __FUNCTION__, box->x1, box->x2, coverage)); 104903b705cfSriastradh 105003b705cfSriastradh op->box(sna, op, box, AREA_TO_ALPHA(coverage)); 105103b705cfSriastradh apply_damage_box(&op->base, box); 105203b705cfSriastradh} 105303b705cfSriastradh 105403b705cfSriastradhstatic void 105503b705cfSriastradhtor_blt_span__no_damage(struct sna *sna, 105603b705cfSriastradh struct sna_composite_spans_op *op, 105703b705cfSriastradh pixman_region16_t *clip, 105803b705cfSriastradh const BoxRec *box, 105903b705cfSriastradh int coverage) 106003b705cfSriastradh{ 106103b705cfSriastradh __DBG(("%s: %d -> %d @ %d\n", __FUNCTION__, box->x1, box->x2, coverage)); 106203b705cfSriastradh 106303b705cfSriastradh op->box(sna, op, box, AREA_TO_ALPHA(coverage)); 106403b705cfSriastradh} 106503b705cfSriastradh 106603b705cfSriastradhstatic void 106703b705cfSriastradhtor_blt_span_clipped(struct sna *sna, 106803b705cfSriastradh struct sna_composite_spans_op *op, 106903b705cfSriastradh pixman_region16_t *clip, 107003b705cfSriastradh const BoxRec *box, 107103b705cfSriastradh int coverage) 107203b705cfSriastradh{ 107303b705cfSriastradh pixman_region16_t region; 107403b705cfSriastradh float opacity; 107503b705cfSriastradh 107603b705cfSriastradh opacity = AREA_TO_ALPHA(coverage); 107703b705cfSriastradh __DBG(("%s: %d -> %d @ %f\n", __FUNCTION__, box->x1, box->x2, opacity)); 107803b705cfSriastradh 107903b705cfSriastradh pixman_region_init_rects(®ion, box, 1); 108003b705cfSriastradh RegionIntersect(®ion, ®ion, clip); 108103b705cfSriastradh if (REGION_NUM_RECTS(®ion)) { 108203b705cfSriastradh op->boxes(sna, op, 108303b705cfSriastradh REGION_RECTS(®ion), 108403b705cfSriastradh REGION_NUM_RECTS(®ion), 108503b705cfSriastradh opacity); 108603b705cfSriastradh apply_damage(&op->base, ®ion); 108703b705cfSriastradh } 108803b705cfSriastradh pixman_region_fini(®ion); 108903b705cfSriastradh} 109003b705cfSriastradh 109103b705cfSriastradhstatic void 109203b705cfSriastradhtor_blt_span_mono(struct sna *sna, 109303b705cfSriastradh struct sna_composite_spans_op *op, 109403b705cfSriastradh pixman_region16_t *clip, 109503b705cfSriastradh const BoxRec *box, 109603b705cfSriastradh int coverage) 109703b705cfSriastradh{ 109803b705cfSriastradh if (coverage < FAST_SAMPLES_XY/2) 109903b705cfSriastradh return; 110003b705cfSriastradh 110103b705cfSriastradh tor_blt_span(sna, op, clip, box, FAST_SAMPLES_XY); 110203b705cfSriastradh} 110303b705cfSriastradh 110403b705cfSriastradhstatic void 110503b705cfSriastradhtor_blt_span_mono_clipped(struct sna *sna, 110603b705cfSriastradh struct sna_composite_spans_op *op, 110703b705cfSriastradh pixman_region16_t *clip, 110803b705cfSriastradh const BoxRec *box, 110903b705cfSriastradh int coverage) 111003b705cfSriastradh{ 111103b705cfSriastradh if (coverage < FAST_SAMPLES_XY/2) 111203b705cfSriastradh return; 111303b705cfSriastradh 111403b705cfSriastradh tor_blt_span_clipped(sna, op, clip, box, FAST_SAMPLES_XY); 111503b705cfSriastradh} 111603b705cfSriastradh 111703b705cfSriastradhstatic void 111803b705cfSriastradhtor_blt_span_mono_unbounded(struct sna *sna, 111903b705cfSriastradh struct sna_composite_spans_op *op, 112003b705cfSriastradh pixman_region16_t *clip, 112103b705cfSriastradh const BoxRec *box, 112203b705cfSriastradh int coverage) 112303b705cfSriastradh{ 112403b705cfSriastradh tor_blt_span(sna, op, clip, box, 112503b705cfSriastradh coverage < FAST_SAMPLES_XY/2 ? 0 : FAST_SAMPLES_XY); 112603b705cfSriastradh} 112703b705cfSriastradh 112803b705cfSriastradhstatic void 112903b705cfSriastradhtor_blt_span_mono_unbounded_clipped(struct sna *sna, 113003b705cfSriastradh struct sna_composite_spans_op *op, 113103b705cfSriastradh pixman_region16_t *clip, 113203b705cfSriastradh const BoxRec *box, 113303b705cfSriastradh int coverage) 113403b705cfSriastradh{ 113503b705cfSriastradh tor_blt_span_clipped(sna, op, clip, box, 113603b705cfSriastradh coverage < FAST_SAMPLES_XY/2 ? 0 : FAST_SAMPLES_XY); 113703b705cfSriastradh} 113803b705cfSriastradh 113903b705cfSriastradhstatic void 114003b705cfSriastradhtor_blt(struct sna *sna, 114103b705cfSriastradh struct sna_composite_spans_op *op, 114203b705cfSriastradh pixman_region16_t *clip, 114303b705cfSriastradh void (*span)(struct sna *sna, 114403b705cfSriastradh struct sna_composite_spans_op *op, 114503b705cfSriastradh pixman_region16_t *clip, 114603b705cfSriastradh const BoxRec *box, 114703b705cfSriastradh int coverage), 114803b705cfSriastradh struct cell_list *cells, 114903b705cfSriastradh int y, int height, 115003b705cfSriastradh int xmin, int xmax, 115103b705cfSriastradh int unbounded) 115203b705cfSriastradh{ 115303b705cfSriastradh struct cell *cell; 115403b705cfSriastradh BoxRec box; 115503b705cfSriastradh int cover; 115603b705cfSriastradh 115703b705cfSriastradh box.y1 = y; 115803b705cfSriastradh box.y2 = y + height; 115903b705cfSriastradh box.x1 = xmin; 116003b705cfSriastradh 116103b705cfSriastradh /* Form the spans from the coverages and areas. */ 116203b705cfSriastradh cover = 0; 116303b705cfSriastradh for (cell = cells->head.next; cell != &cells->tail; cell = cell->next) { 116403b705cfSriastradh int x = cell->x; 116503b705cfSriastradh 116603b705cfSriastradh assert(x >= xmin); 116703b705cfSriastradh assert(x < xmax); 116803b705cfSriastradh __DBG(("%s: cell=(%d, %d, %d), cover=%d, max=%d\n", __FUNCTION__, 116903b705cfSriastradh cell->x, cell->covered_height, cell->uncovered_area, 117003b705cfSriastradh cover, xmax)); 117103b705cfSriastradh 117203b705cfSriastradh if (cell->covered_height || cell->uncovered_area) { 117303b705cfSriastradh box.x2 = x; 117403b705cfSriastradh if (box.x2 > box.x1 && (unbounded || cover)) { 117503b705cfSriastradh __DBG(("%s: span (%d, %d)x(%d, %d) @ %d\n", __FUNCTION__, 117603b705cfSriastradh box.x1, box.y1, 117703b705cfSriastradh box.x2 - box.x1, 117803b705cfSriastradh box.y2 - box.y1, 117903b705cfSriastradh cover)); 118003b705cfSriastradh span(sna, op, clip, &box, cover); 118103b705cfSriastradh } 118203b705cfSriastradh box.x1 = box.x2; 118303b705cfSriastradh cover += cell->covered_height*FAST_SAMPLES_X*2; 118403b705cfSriastradh } 118503b705cfSriastradh 118603b705cfSriastradh if (cell->uncovered_area) { 118703b705cfSriastradh int area = cover - cell->uncovered_area; 118803b705cfSriastradh box.x2 = x + 1; 118903b705cfSriastradh if (unbounded || area) { 119003b705cfSriastradh __DBG(("%s: span (%d, %d)x(%d, %d) @ %d\n", __FUNCTION__, 119103b705cfSriastradh box.x1, box.y1, 119203b705cfSriastradh box.x2 - box.x1, 119303b705cfSriastradh box.y2 - box.y1, 119403b705cfSriastradh area)); 119503b705cfSriastradh span(sna, op, clip, &box, area); 119603b705cfSriastradh } 119703b705cfSriastradh box.x1 = box.x2; 119803b705cfSriastradh } 119903b705cfSriastradh } 120003b705cfSriastradh 120103b705cfSriastradh box.x2 = xmax; 120203b705cfSriastradh if (box.x2 > box.x1 && (unbounded || cover)) { 120303b705cfSriastradh __DBG(("%s: span (%d, %d)x(%d, %d) @ %d\n", __FUNCTION__, 120403b705cfSriastradh box.x1, box.y1, 120503b705cfSriastradh box.x2 - box.x1, 120603b705cfSriastradh box.y2 - box.y1, 120703b705cfSriastradh cover)); 120803b705cfSriastradh span(sna, op, clip, &box, cover); 120903b705cfSriastradh } 121003b705cfSriastradh} 121103b705cfSriastradh 121203b705cfSriastradhstatic void 121303b705cfSriastradhtor_blt_empty(struct sna *sna, 121403b705cfSriastradh struct sna_composite_spans_op *op, 121503b705cfSriastradh pixman_region16_t *clip, 121603b705cfSriastradh void (*span)(struct sna *sna, 121703b705cfSriastradh struct sna_composite_spans_op *op, 121803b705cfSriastradh pixman_region16_t *clip, 121903b705cfSriastradh const BoxRec *box, 122003b705cfSriastradh int coverage), 122103b705cfSriastradh int y, int height, 122203b705cfSriastradh int xmin, int xmax) 122303b705cfSriastradh{ 122403b705cfSriastradh BoxRec box; 122503b705cfSriastradh 122603b705cfSriastradh box.x1 = xmin; 122703b705cfSriastradh box.x2 = xmax; 122803b705cfSriastradh box.y1 = y; 122903b705cfSriastradh box.y2 = y + height; 123003b705cfSriastradh 123103b705cfSriastradh span(sna, op, clip, &box, 0); 123203b705cfSriastradh} 123303b705cfSriastradh 123403b705cfSriastradhflatten static void 123503b705cfSriastradhtor_render(struct sna *sna, 123603b705cfSriastradh struct tor *converter, 123703b705cfSriastradh struct sna_composite_spans_op *op, 123803b705cfSriastradh pixman_region16_t *clip, 123903b705cfSriastradh void (*span)(struct sna *sna, 124003b705cfSriastradh struct sna_composite_spans_op *op, 124103b705cfSriastradh pixman_region16_t *clip, 124203b705cfSriastradh const BoxRec *box, 124303b705cfSriastradh int coverage), 124403b705cfSriastradh int unbounded) 124503b705cfSriastradh{ 124603b705cfSriastradh int ymin = converter->ymin; 124703b705cfSriastradh int xmin = converter->xmin; 124803b705cfSriastradh int xmax = converter->xmax; 124903b705cfSriastradh int i, j, h = converter->ymax - ymin; 125003b705cfSriastradh struct polygon *polygon = converter->polygon; 125103b705cfSriastradh struct cell_list *coverages = converter->coverages; 125203b705cfSriastradh struct active_list *active = converter->active; 125303b705cfSriastradh struct edge *buckets[FAST_SAMPLES_Y] = { 0 }; 125403b705cfSriastradh 125503b705cfSriastradh __DBG(("%s: unbounded=%d\n", __FUNCTION__, unbounded)); 125603b705cfSriastradh 125703b705cfSriastradh /* Render each pixel row. */ 125803b705cfSriastradh for (i = 0; i < h; i = j) { 125903b705cfSriastradh int do_full_step = 0; 126003b705cfSriastradh 126103b705cfSriastradh j = i + 1; 126203b705cfSriastradh 126303b705cfSriastradh /* Determine if we can ignore this row or use the full pixel 126403b705cfSriastradh * stepper. */ 126503b705cfSriastradh if (!polygon->y_buckets[i]) { 126603b705cfSriastradh if (active->head.next == &active->tail) { 126703b705cfSriastradh active->min_height = INT_MAX; 126803b705cfSriastradh active->is_vertical = 1; 126903b705cfSriastradh for (; !polygon->y_buckets[j]; j++) 127003b705cfSriastradh ; 127103b705cfSriastradh __DBG(("%s: no new edges and no exisiting edges, skipping, %d -> %d\n", 127203b705cfSriastradh __FUNCTION__, i, j)); 127303b705cfSriastradh 127403b705cfSriastradh if (unbounded) 127503b705cfSriastradh tor_blt_empty(sna, op, clip, span, i+ymin, j-i, xmin, xmax); 127603b705cfSriastradh continue; 127703b705cfSriastradh } 127803b705cfSriastradh 127903b705cfSriastradh do_full_step = can_full_step(active); 128003b705cfSriastradh } 128103b705cfSriastradh 128203b705cfSriastradh __DBG(("%s: y=%d [%d], do_full_step=%d, new edges=%d, min_height=%d, vertical=%d\n", 128303b705cfSriastradh __FUNCTION__, 128403b705cfSriastradh i, i+ymin, do_full_step, 128503b705cfSriastradh polygon->y_buckets[i] != NULL, 128603b705cfSriastradh active->min_height, 128703b705cfSriastradh active->is_vertical)); 128803b705cfSriastradh if (do_full_step) { 128903b705cfSriastradh assert(active->is_vertical); 129003b705cfSriastradh nonzero_row(active, coverages); 129103b705cfSriastradh 129203b705cfSriastradh while (polygon->y_buckets[j] == NULL && 129303b705cfSriastradh active->min_height >= 2*FAST_SAMPLES_Y) 129403b705cfSriastradh { 129503b705cfSriastradh active->min_height -= FAST_SAMPLES_Y; 129603b705cfSriastradh j++; 129703b705cfSriastradh } 129803b705cfSriastradh if (j != i + 1) 129903b705cfSriastradh step_edges(active, j - (i + 1)); 130003b705cfSriastradh 130103b705cfSriastradh __DBG(("%s: vertical edges, full step (%d, %d)\n", 130203b705cfSriastradh __FUNCTION__, i, j)); 130303b705cfSriastradh } else { 130403b705cfSriastradh grid_scaled_y_t suby; 130503b705cfSriastradh 130603b705cfSriastradh fill_buckets(active, polygon->y_buckets[i], buckets); 130703b705cfSriastradh 130803b705cfSriastradh /* Subsample this row. */ 130903b705cfSriastradh for (suby = 0; suby < FAST_SAMPLES_Y; suby++) { 131003b705cfSriastradh if (buckets[suby]) { 131103b705cfSriastradh merge_edges(active, buckets[suby]); 131203b705cfSriastradh buckets[suby] = NULL; 131303b705cfSriastradh } 131403b705cfSriastradh 131503b705cfSriastradh nonzero_subrow(active, coverages); 131603b705cfSriastradh } 131703b705cfSriastradh } 131803b705cfSriastradh 131903b705cfSriastradh if (coverages->head.next != &coverages->tail) { 132003b705cfSriastradh tor_blt(sna, op, clip, span, coverages, 132103b705cfSriastradh i+ymin, j-i, xmin, xmax, 132203b705cfSriastradh unbounded); 132303b705cfSriastradh cell_list_reset(coverages); 132403b705cfSriastradh } else if (unbounded) 132503b705cfSriastradh tor_blt_empty(sna, op, clip, span, i+ymin, j-i, xmin, xmax); 132603b705cfSriastradh 132703b705cfSriastradh active->min_height -= FAST_SAMPLES_Y; 132803b705cfSriastradh } 132903b705cfSriastradh} 133003b705cfSriastradh 133103b705cfSriastradhstatic void 133203b705cfSriastradhinplace_row(struct active_list *active, uint8_t *row, int width) 133303b705cfSriastradh{ 133403b705cfSriastradh struct edge *left = active->head.next; 133503b705cfSriastradh 133603b705cfSriastradh assert(active->is_vertical); 133703b705cfSriastradh 133803b705cfSriastradh while (&active->tail != left) { 133903b705cfSriastradh struct edge *right; 134003b705cfSriastradh int winding = left->dir; 134103b705cfSriastradh grid_scaled_x_t lfx, rfx; 134203b705cfSriastradh int lix, rix; 134303b705cfSriastradh 134403b705cfSriastradh left->height_left -= FAST_SAMPLES_Y; 134503b705cfSriastradh if (!left->height_left) { 134603b705cfSriastradh left->prev->next = left->next; 134703b705cfSriastradh left->next->prev = left->prev; 134803b705cfSriastradh } 134903b705cfSriastradh 135003b705cfSriastradh right = left->next; 135103b705cfSriastradh do { 135203b705cfSriastradh right->height_left -= FAST_SAMPLES_Y; 135303b705cfSriastradh if (!right->height_left) { 135403b705cfSriastradh right->prev->next = right->next; 135503b705cfSriastradh right->next->prev = right->prev; 135603b705cfSriastradh } 135703b705cfSriastradh 135803b705cfSriastradh winding += right->dir; 135903b705cfSriastradh if (0 == winding && right->x.quo != right->next->x.quo) 136003b705cfSriastradh break; 136103b705cfSriastradh 136203b705cfSriastradh right = right->next; 136303b705cfSriastradh } while (1); 136403b705cfSriastradh 136503b705cfSriastradh if (left->x.quo < 0) { 136603b705cfSriastradh lix = lfx = 0; 136703b705cfSriastradh } else if (left->x.quo >= width * FAST_SAMPLES_X) { 136803b705cfSriastradh lix = width; 136903b705cfSriastradh lfx = 0; 137003b705cfSriastradh } else 137103b705cfSriastradh FAST_SAMPLES_X_TO_INT_FRAC(left->x.quo, lix, lfx); 137203b705cfSriastradh 137303b705cfSriastradh if (right->x.quo < 0) { 137403b705cfSriastradh rix = rfx = 0; 137503b705cfSriastradh } else if (right->x.quo >= width * FAST_SAMPLES_X) { 137603b705cfSriastradh rix = width; 137703b705cfSriastradh rfx = 0; 137803b705cfSriastradh } else 137903b705cfSriastradh FAST_SAMPLES_X_TO_INT_FRAC(right->x.quo, rix, rfx); 138003b705cfSriastradh if (lix == rix) { 138103b705cfSriastradh if (rfx != lfx) { 138203b705cfSriastradh assert(lix < width); 138303b705cfSriastradh row[lix] += (rfx-lfx) * 256 / FAST_SAMPLES_X; 138403b705cfSriastradh } 138503b705cfSriastradh } else { 138603b705cfSriastradh assert(lix < width); 138703b705cfSriastradh if (lfx == 0) 138803b705cfSriastradh row[lix] = 0xff; 138903b705cfSriastradh else 139003b705cfSriastradh row[lix] += 256 - lfx * 256 / FAST_SAMPLES_X; 139103b705cfSriastradh 139203b705cfSriastradh assert(rix <= width); 139303b705cfSriastradh if (rfx) { 139403b705cfSriastradh assert(rix < width); 139503b705cfSriastradh row[rix] += rfx * 256 / FAST_SAMPLES_X; 139603b705cfSriastradh } 139703b705cfSriastradh 139803b705cfSriastradh if (rix > ++lix) { 139903b705cfSriastradh uint8_t *r = row + lix; 140003b705cfSriastradh rix -= lix; 140103b705cfSriastradh#if 0 140203b705cfSriastradh if (rix == 1) 140303b705cfSriastradh *row = 0xff; 140403b705cfSriastradh else 140503b705cfSriastradh memset(row, 0xff, rix); 140603b705cfSriastradh#else 140703b705cfSriastradh if ((uintptr_t)r & 1 && rix) { 140803b705cfSriastradh *r++ = 0xff; 140903b705cfSriastradh rix--; 141003b705cfSriastradh } 141103b705cfSriastradh if ((uintptr_t)r & 2 && rix >= 2) { 141203b705cfSriastradh *(uint16_t *)r = 0xffff; 141303b705cfSriastradh r += 2; 141403b705cfSriastradh rix -= 2; 141503b705cfSriastradh } 141603b705cfSriastradh if ((uintptr_t)r & 4 && rix >= 4) { 141703b705cfSriastradh *(uint32_t *)r = 0xffffffff; 141803b705cfSriastradh r += 4; 141903b705cfSriastradh rix -= 4; 142003b705cfSriastradh } 142103b705cfSriastradh while (rix >= 8) { 142203b705cfSriastradh *(uint64_t *)r = 0xffffffffffffffff; 142303b705cfSriastradh r += 8; 142403b705cfSriastradh rix -= 8; 142503b705cfSriastradh } 142603b705cfSriastradh if (rix & 4) { 142703b705cfSriastradh *(uint32_t *)r = 0xffffffff; 142803b705cfSriastradh r += 4; 142903b705cfSriastradh } 143003b705cfSriastradh if (rix & 2) { 143103b705cfSriastradh *(uint16_t *)r = 0xffff; 143203b705cfSriastradh r += 2; 143303b705cfSriastradh } 143403b705cfSriastradh if (rix & 1) 143503b705cfSriastradh *r = 0xff; 143603b705cfSriastradh#endif 143703b705cfSriastradh } 143803b705cfSriastradh } 143903b705cfSriastradh 144003b705cfSriastradh left = right->next; 144103b705cfSriastradh } 144203b705cfSriastradh} 144303b705cfSriastradh 144403b705cfSriastradhinline static void 144503b705cfSriastradhinplace_subrow(struct active_list *active, int8_t *row, 144603b705cfSriastradh int width, int *min, int *max) 144703b705cfSriastradh{ 144803b705cfSriastradh struct edge *edge = active->head.next; 144903b705cfSriastradh grid_scaled_x_t prev_x = INT_MIN; 145003b705cfSriastradh int winding = 0, xstart = INT_MIN; 145103b705cfSriastradh 145203b705cfSriastradh while (&active->tail != edge) { 145303b705cfSriastradh struct edge *next = edge->next; 145403b705cfSriastradh 145503b705cfSriastradh winding += edge->dir; 145603b705cfSriastradh if (0 == winding) { 145703b705cfSriastradh if (edge->next->x.quo != edge->x.quo) { 145803b705cfSriastradh if (edge->x.quo <= xstart) { 145903b705cfSriastradh xstart = INT_MIN; 146003b705cfSriastradh } else { 146103b705cfSriastradh grid_scaled_x_t fx; 146203b705cfSriastradh int ix; 146303b705cfSriastradh 146403b705cfSriastradh if (xstart < FAST_SAMPLES_X * width) { 146503b705cfSriastradh FAST_SAMPLES_X_TO_INT_FRAC(xstart, ix, fx); 146603b705cfSriastradh if (ix < *min) 146703b705cfSriastradh *min = ix; 146803b705cfSriastradh 146903b705cfSriastradh row[ix++] += FAST_SAMPLES_X - fx; 147003b705cfSriastradh if (fx && ix < width) 147103b705cfSriastradh row[ix] += fx; 147203b705cfSriastradh } 147303b705cfSriastradh 147403b705cfSriastradh xstart = edge->x.quo; 147503b705cfSriastradh if (xstart < FAST_SAMPLES_X * width) { 147603b705cfSriastradh FAST_SAMPLES_X_TO_INT_FRAC(xstart, ix, fx); 147703b705cfSriastradh row[ix] -= FAST_SAMPLES_X - fx; 147803b705cfSriastradh if (fx && ix + 1 < width) 147903b705cfSriastradh row[++ix] -= fx; 148003b705cfSriastradh 148103b705cfSriastradh if (ix >= *max) 148203b705cfSriastradh *max = ix + 1; 148303b705cfSriastradh 148403b705cfSriastradh xstart = INT_MIN; 148503b705cfSriastradh } else 148603b705cfSriastradh *max = width; 148703b705cfSriastradh } 148803b705cfSriastradh } 148903b705cfSriastradh } else if (xstart < 0) { 149003b705cfSriastradh xstart = MAX(edge->x.quo, 0); 149103b705cfSriastradh } 149203b705cfSriastradh 149303b705cfSriastradh if (--edge->height_left) { 149403b705cfSriastradh if (edge->dy) { 149503b705cfSriastradh edge->x.quo += edge->dxdy.quo; 149603b705cfSriastradh edge->x.rem += edge->dxdy.rem; 149703b705cfSriastradh if (edge->x.rem >= 0) { 149803b705cfSriastradh ++edge->x.quo; 149903b705cfSriastradh edge->x.rem -= edge->dy; 150003b705cfSriastradh } 150103b705cfSriastradh } 150203b705cfSriastradh 150303b705cfSriastradh if (edge->x.quo < prev_x) { 150403b705cfSriastradh struct edge *pos = edge->prev; 150503b705cfSriastradh pos->next = next; 150603b705cfSriastradh next->prev = pos; 150703b705cfSriastradh do { 150803b705cfSriastradh pos = pos->prev; 150903b705cfSriastradh } while (edge->x.quo < pos->x.quo); 151003b705cfSriastradh pos->next->prev = edge; 151103b705cfSriastradh edge->next = pos->next; 151203b705cfSriastradh edge->prev = pos; 151303b705cfSriastradh pos->next = edge; 151403b705cfSriastradh } else 151503b705cfSriastradh prev_x = edge->x.quo; 151603b705cfSriastradh } else { 151703b705cfSriastradh edge->prev->next = next; 151803b705cfSriastradh next->prev = edge->prev; 151903b705cfSriastradh active->min_height = -1; 152003b705cfSriastradh } 152103b705cfSriastradh 152203b705cfSriastradh edge = next; 152303b705cfSriastradh } 152403b705cfSriastradh} 152503b705cfSriastradh 152603b705cfSriastradhinline static void 152703b705cfSriastradhinplace_end_subrows(struct active_list *active, uint8_t *row, 152803b705cfSriastradh int8_t *buf, int width) 152903b705cfSriastradh{ 153003b705cfSriastradh int cover = 0; 153103b705cfSriastradh 153203b705cfSriastradh while (width >= 4) { 153303b705cfSriastradh uint32_t dw; 153403b705cfSriastradh int v; 153503b705cfSriastradh 153603b705cfSriastradh dw = *(uint32_t *)buf; 153703b705cfSriastradh buf += 4; 153803b705cfSriastradh 153903b705cfSriastradh if (dw == 0) { 154003b705cfSriastradh v = cover * 256 / (FAST_SAMPLES_X * FAST_SAMPLES_Y); 154103b705cfSriastradh v -= v >> 8; 154203b705cfSriastradh v |= v << 8; 154303b705cfSriastradh dw = v | v << 16; 154403b705cfSriastradh } else { 154503b705cfSriastradh cover += (int8_t)(dw & 0xff); 154603b705cfSriastradh if (cover) { 154703b705cfSriastradh assert(cover > 0); 154803b705cfSriastradh v = cover * 256 / (FAST_SAMPLES_X * FAST_SAMPLES_Y); 154903b705cfSriastradh v -= v >> 8; 155003b705cfSriastradh dw >>= 8; 155103b705cfSriastradh dw |= v << 24; 155203b705cfSriastradh } else 155303b705cfSriastradh dw >>= 8; 155403b705cfSriastradh 155503b705cfSriastradh cover += (int8_t)(dw & 0xff); 155603b705cfSriastradh if (cover) { 155703b705cfSriastradh assert(cover > 0); 155803b705cfSriastradh v = cover * 256 / (FAST_SAMPLES_X * FAST_SAMPLES_Y); 155903b705cfSriastradh v -= v >> 8; 156003b705cfSriastradh dw >>= 8; 156103b705cfSriastradh dw |= v << 24; 156203b705cfSriastradh } else 156303b705cfSriastradh dw >>= 8; 156403b705cfSriastradh 156503b705cfSriastradh cover += (int8_t)(dw & 0xff); 156603b705cfSriastradh if (cover) { 156703b705cfSriastradh assert(cover > 0); 156803b705cfSriastradh v = cover * 256 / (FAST_SAMPLES_X * FAST_SAMPLES_Y); 156903b705cfSriastradh v -= v >> 8; 157003b705cfSriastradh dw >>= 8; 157103b705cfSriastradh dw |= v << 24; 157203b705cfSriastradh } else 157303b705cfSriastradh dw >>= 8; 157403b705cfSriastradh 157503b705cfSriastradh cover += (int8_t)(dw & 0xff); 157603b705cfSriastradh if (cover) { 157703b705cfSriastradh assert(cover > 0); 157803b705cfSriastradh v = cover * 256 / (FAST_SAMPLES_X * FAST_SAMPLES_Y); 157903b705cfSriastradh v -= v >> 8; 158003b705cfSriastradh dw >>= 8; 158103b705cfSriastradh dw |= v << 24; 158203b705cfSriastradh } else 158303b705cfSriastradh dw >>= 8; 158403b705cfSriastradh } 158503b705cfSriastradh 158603b705cfSriastradh *(uint32_t *)row = dw; 158703b705cfSriastradh row += 4; 158803b705cfSriastradh width -= 4; 158903b705cfSriastradh } 159003b705cfSriastradh 159103b705cfSriastradh while (width--) { 159203b705cfSriastradh int v; 159303b705cfSriastradh 159403b705cfSriastradh cover += *buf++; 159503b705cfSriastradh assert(cover >= 0); 159603b705cfSriastradh 159703b705cfSriastradh v = cover * 256 / (FAST_SAMPLES_X * FAST_SAMPLES_Y); 159803b705cfSriastradh v -= v >> 8; 159903b705cfSriastradh *row++ = v; 160003b705cfSriastradh } 160103b705cfSriastradh} 160203b705cfSriastradh 160303b705cfSriastradh#define TOR_INPLACE_SIZE 128 160403b705cfSriastradhstatic void 160503b705cfSriastradhtor_inplace(struct tor *converter, PixmapPtr scratch, int mono, uint8_t *buf) 160603b705cfSriastradh{ 160703b705cfSriastradh int i, j, h = converter->ymax; 160803b705cfSriastradh struct polygon *polygon = converter->polygon; 160903b705cfSriastradh struct active_list *active = converter->active; 161003b705cfSriastradh struct edge *buckets[FAST_SAMPLES_Y] = { 0 }; 161103b705cfSriastradh uint8_t *row = scratch->devPrivate.ptr; 161203b705cfSriastradh int stride = scratch->devKind; 161303b705cfSriastradh int width = scratch->drawable.width; 161403b705cfSriastradh 161503b705cfSriastradh __DBG(("%s: mono=%d, buf?=%d\n", __FUNCTION__, mono, buf != NULL)); 161603b705cfSriastradh assert(!mono); 161703b705cfSriastradh assert(converter->ymin == 0); 161803b705cfSriastradh assert(converter->xmin == 0); 161903b705cfSriastradh assert(scratch->drawable.depth == 8); 162003b705cfSriastradh 162103b705cfSriastradh /* Render each pixel row. */ 162203b705cfSriastradh for (i = 0; i < h; i = j) { 162303b705cfSriastradh int do_full_step = 0; 162403b705cfSriastradh void *ptr = buf ?: row; 162503b705cfSriastradh 162603b705cfSriastradh j = i + 1; 162703b705cfSriastradh 162803b705cfSriastradh /* Determine if we can ignore this row or use the full pixel 162903b705cfSriastradh * stepper. */ 163003b705cfSriastradh if (!polygon->y_buckets[i]) { 163103b705cfSriastradh if (active->head.next == &active->tail) { 163203b705cfSriastradh active->min_height = INT_MAX; 163303b705cfSriastradh active->is_vertical = 1; 163403b705cfSriastradh for (; !polygon->y_buckets[j]; j++) 163503b705cfSriastradh ; 163603b705cfSriastradh __DBG(("%s: no new edges and no exisiting edges, skipping, %d -> %d\n", 163703b705cfSriastradh __FUNCTION__, i, j)); 163803b705cfSriastradh 163903b705cfSriastradh memset(row, 0, stride*(j-i)); 164003b705cfSriastradh row += stride*(j-i); 164103b705cfSriastradh continue; 164203b705cfSriastradh } 164303b705cfSriastradh 164403b705cfSriastradh do_full_step = can_full_step(active); 164503b705cfSriastradh } 164603b705cfSriastradh 164703b705cfSriastradh __DBG(("%s: y=%d, do_full_step=%d, new edges=%d, min_height=%d, vertical=%d\n", 164803b705cfSriastradh __FUNCTION__, 164903b705cfSriastradh i, do_full_step, 165003b705cfSriastradh polygon->y_buckets[i] != NULL, 165103b705cfSriastradh active->min_height, 165203b705cfSriastradh active->is_vertical)); 165303b705cfSriastradh if (do_full_step) { 165403b705cfSriastradh assert(active->is_vertical); 165503b705cfSriastradh 165603b705cfSriastradh memset(ptr, 0, width); 165703b705cfSriastradh inplace_row(active, ptr, width); 165803b705cfSriastradh if (row != ptr) 165903b705cfSriastradh memcpy(row, ptr, width); 166003b705cfSriastradh 166103b705cfSriastradh while (polygon->y_buckets[j] == NULL && 166203b705cfSriastradh active->min_height >= 2*FAST_SAMPLES_Y) 166303b705cfSriastradh { 166403b705cfSriastradh active->min_height -= FAST_SAMPLES_Y; 166503b705cfSriastradh row += stride; 166603b705cfSriastradh memcpy(row, ptr, width); 166703b705cfSriastradh j++; 166803b705cfSriastradh } 166903b705cfSriastradh if (j != i + 1) 167003b705cfSriastradh step_edges(active, j - (i + 1)); 167103b705cfSriastradh 167203b705cfSriastradh __DBG(("%s: vertical edges, full step (%d, %d)\n", 167303b705cfSriastradh __FUNCTION__, i, j)); 167403b705cfSriastradh } else { 167503b705cfSriastradh grid_scaled_y_t suby; 167603b705cfSriastradh int min = width, max = 0; 167703b705cfSriastradh 167803b705cfSriastradh fill_buckets(active, polygon->y_buckets[i], buckets); 167903b705cfSriastradh 168003b705cfSriastradh /* Subsample this row. */ 168103b705cfSriastradh memset(ptr, 0, width); 168203b705cfSriastradh for (suby = 0; suby < FAST_SAMPLES_Y; suby++) { 168303b705cfSriastradh if (buckets[suby]) { 168403b705cfSriastradh merge_edges(active, buckets[suby]); 168503b705cfSriastradh buckets[suby] = NULL; 168603b705cfSriastradh } 168703b705cfSriastradh 168803b705cfSriastradh inplace_subrow(active, ptr, width, &min, &max); 168903b705cfSriastradh } 169003b705cfSriastradh assert(min >= 0 && max <= width); 169103b705cfSriastradh memset(row, 0, min); 169203b705cfSriastradh if (max > min) 169303b705cfSriastradh inplace_end_subrows(active, row+min, (int8_t*)ptr+min, max-min); 169403b705cfSriastradh if (max < width) 169503b705cfSriastradh memset(row+max, 0, width-max); 169603b705cfSriastradh } 169703b705cfSriastradh 169803b705cfSriastradh active->min_height -= FAST_SAMPLES_Y; 169903b705cfSriastradh row += stride; 170003b705cfSriastradh } 170103b705cfSriastradh} 170203b705cfSriastradh 170303b705cfSriastradhstruct mono_edge { 170403b705cfSriastradh struct mono_edge *next, *prev; 170503b705cfSriastradh 170603b705cfSriastradh int32_t height_left; 170703b705cfSriastradh int32_t dir; 170803b705cfSriastradh 170903b705cfSriastradh int32_t dy; 171003b705cfSriastradh struct quorem x; 171103b705cfSriastradh struct quorem dxdy; 171203b705cfSriastradh}; 171303b705cfSriastradh 171403b705cfSriastradhstruct mono_polygon { 171503b705cfSriastradh int num_edges; 171603b705cfSriastradh struct mono_edge *edges; 171703b705cfSriastradh struct mono_edge **y_buckets; 171803b705cfSriastradh 171903b705cfSriastradh struct mono_edge *y_buckets_embedded[64]; 172003b705cfSriastradh struct mono_edge edges_embedded[32]; 172103b705cfSriastradh}; 172203b705cfSriastradh 172303b705cfSriastradhstruct mono { 172403b705cfSriastradh /* Leftmost edge on the current scan line. */ 172503b705cfSriastradh struct mono_edge head, tail; 172603b705cfSriastradh int is_vertical; 172703b705cfSriastradh 172803b705cfSriastradh struct sna *sna; 172903b705cfSriastradh struct sna_composite_op op; 173003b705cfSriastradh pixman_region16_t clip; 173103b705cfSriastradh 173203b705cfSriastradh fastcall void (*span)(struct mono *, int, int, BoxPtr); 173303b705cfSriastradh 173403b705cfSriastradh struct mono_polygon polygon; 173503b705cfSriastradh}; 173603b705cfSriastradh 173703b705cfSriastradh#define I(x) pixman_fixed_to_int ((x) + pixman_fixed_1_minus_e/2) 173803b705cfSriastradh 173903b705cfSriastradhstatic bool 174003b705cfSriastradhmono_polygon_init(struct mono_polygon *polygon, BoxPtr box, int num_edges) 174103b705cfSriastradh{ 174203b705cfSriastradh unsigned h = box->y2 - box->y1; 174303b705cfSriastradh 174403b705cfSriastradh polygon->y_buckets = polygon->y_buckets_embedded; 174503b705cfSriastradh if (h > ARRAY_SIZE (polygon->y_buckets_embedded)) { 174603b705cfSriastradh polygon->y_buckets = malloc (h * sizeof (struct mono_edge *)); 174703b705cfSriastradh if (unlikely (NULL == polygon->y_buckets)) 174803b705cfSriastradh return false; 174903b705cfSriastradh } 175003b705cfSriastradh 175103b705cfSriastradh polygon->num_edges = 0; 175203b705cfSriastradh polygon->edges = polygon->edges_embedded; 175303b705cfSriastradh if (num_edges > (int)ARRAY_SIZE (polygon->edges_embedded)) { 175403b705cfSriastradh polygon->edges = malloc (num_edges * sizeof (struct mono_edge)); 175503b705cfSriastradh if (unlikely (polygon->edges == NULL)) { 175603b705cfSriastradh if (polygon->y_buckets != polygon->y_buckets_embedded) 175703b705cfSriastradh free(polygon->y_buckets); 175803b705cfSriastradh return false; 175903b705cfSriastradh } 176003b705cfSriastradh } 176103b705cfSriastradh 176203b705cfSriastradh memset(polygon->y_buckets, 0, h * sizeof (struct edge *)); 176303b705cfSriastradh return true; 176403b705cfSriastradh} 176503b705cfSriastradh 176603b705cfSriastradhstatic void 176703b705cfSriastradhmono_polygon_fini(struct mono_polygon *polygon) 176803b705cfSriastradh{ 176903b705cfSriastradh if (polygon->y_buckets != polygon->y_buckets_embedded) 177003b705cfSriastradh free(polygon->y_buckets); 177103b705cfSriastradh 177203b705cfSriastradh if (polygon->edges != polygon->edges_embedded) 177303b705cfSriastradh free(polygon->edges); 177403b705cfSriastradh} 177503b705cfSriastradh 177603b705cfSriastradhstatic void 177703b705cfSriastradhmono_add_line(struct mono *mono, 177803b705cfSriastradh int dst_x, int dst_y, 177903b705cfSriastradh xFixed top, xFixed bottom, 178003b705cfSriastradh const xPointFixed *p1, const xPointFixed *p2, 178103b705cfSriastradh int dir) 178203b705cfSriastradh{ 178303b705cfSriastradh struct mono_polygon *polygon = &mono->polygon; 178403b705cfSriastradh struct mono_edge *e; 178503b705cfSriastradh pixman_fixed_t dx; 178603b705cfSriastradh pixman_fixed_t dy; 178703b705cfSriastradh int y, ytop, ybot; 178803b705cfSriastradh 178903b705cfSriastradh __DBG(("%s: top=%d, bottom=%d, line=(%d, %d), (%d, %d) delta=%dx%d, dir=%d\n", 179003b705cfSriastradh __FUNCTION__, 179103b705cfSriastradh (int)top, (int)bottom, 179203b705cfSriastradh (int)p1->x, (int)p1->y, (int)p2->x, (int)p2->y, 179303b705cfSriastradh dst_x, dst_y, 179403b705cfSriastradh dir)); 179503b705cfSriastradh 179603b705cfSriastradh if (top > bottom) { 179703b705cfSriastradh const xPointFixed *t; 179803b705cfSriastradh 179903b705cfSriastradh y = top; 180003b705cfSriastradh top = bottom; 180103b705cfSriastradh bottom = y; 180203b705cfSriastradh 180303b705cfSriastradh t = p1; 180403b705cfSriastradh p1 = p2; 180503b705cfSriastradh p2 = t; 180603b705cfSriastradh 180703b705cfSriastradh dir = -dir; 180803b705cfSriastradh } 180903b705cfSriastradh 181003b705cfSriastradh y = I(top) + dst_y; 181103b705cfSriastradh ytop = MAX(y, mono->clip.extents.y1); 181203b705cfSriastradh 181303b705cfSriastradh y = I(bottom) + dst_y; 181403b705cfSriastradh ybot = MIN(y, mono->clip.extents.y2); 181503b705cfSriastradh 181603b705cfSriastradh if (ybot <= ytop) { 181703b705cfSriastradh __DBG(("discard clipped line\n")); 181803b705cfSriastradh return; 181903b705cfSriastradh } 182003b705cfSriastradh 182103b705cfSriastradh e = polygon->edges + polygon->num_edges++; 182203b705cfSriastradh e->height_left = ybot - ytop; 182303b705cfSriastradh e->dir = dir; 182403b705cfSriastradh 182503b705cfSriastradh dx = p2->x - p1->x; 182603b705cfSriastradh dy = p2->y - p1->y; 182703b705cfSriastradh 182803b705cfSriastradh if (dx == 0) { 182903b705cfSriastradh e->x.quo = p1->x; 183003b705cfSriastradh e->x.rem = 0; 183103b705cfSriastradh e->dxdy.quo = 0; 183203b705cfSriastradh e->dxdy.rem = 0; 183303b705cfSriastradh e->dy = 0; 183403b705cfSriastradh } else { 183503b705cfSriastradh e->dxdy = floored_muldivrem (dx, pixman_fixed_1, dy); 183603b705cfSriastradh e->dy = dy; 183703b705cfSriastradh 183803b705cfSriastradh e->x = floored_muldivrem ((ytop-dst_y) * pixman_fixed_1 + pixman_fixed_1_minus_e/2 - p1->y, 183903b705cfSriastradh dx, dy); 184003b705cfSriastradh e->x.quo += p1->x; 184103b705cfSriastradh e->x.rem -= dy; 184203b705cfSriastradh } 184303b705cfSriastradh e->x.quo += dst_x*pixman_fixed_1; 184403b705cfSriastradh 184503b705cfSriastradh { 184603b705cfSriastradh struct mono_edge **ptail = &polygon->y_buckets[ytop - mono->clip.extents.y1]; 184703b705cfSriastradh if (*ptail) 184803b705cfSriastradh (*ptail)->prev = e; 184903b705cfSriastradh e->next = *ptail; 185003b705cfSriastradh e->prev = NULL; 185103b705cfSriastradh *ptail = e; 185203b705cfSriastradh } 185303b705cfSriastradh} 185403b705cfSriastradh 185503b705cfSriastradhstatic struct mono_edge * 185603b705cfSriastradhmono_merge_sorted_edges(struct mono_edge *head_a, struct mono_edge *head_b) 185703b705cfSriastradh{ 185803b705cfSriastradh struct mono_edge *head, **next, *prev; 185903b705cfSriastradh int32_t x; 186003b705cfSriastradh 186103b705cfSriastradh if (head_b == NULL) 186203b705cfSriastradh return head_a; 186303b705cfSriastradh 186403b705cfSriastradh prev = head_a->prev; 186503b705cfSriastradh next = &head; 186603b705cfSriastradh if (head_a->x.quo <= head_b->x.quo) { 186703b705cfSriastradh head = head_a; 186803b705cfSriastradh } else { 186903b705cfSriastradh head = head_b; 187003b705cfSriastradh head_b->prev = prev; 187103b705cfSriastradh goto start_with_b; 187203b705cfSriastradh } 187303b705cfSriastradh 187403b705cfSriastradh do { 187503b705cfSriastradh x = head_b->x.quo; 187603b705cfSriastradh while (head_a != NULL && head_a->x.quo <= x) { 187703b705cfSriastradh prev = head_a; 187803b705cfSriastradh next = &head_a->next; 187903b705cfSriastradh head_a = head_a->next; 188003b705cfSriastradh } 188103b705cfSriastradh 188203b705cfSriastradh head_b->prev = prev; 188303b705cfSriastradh *next = head_b; 188403b705cfSriastradh if (head_a == NULL) 188503b705cfSriastradh return head; 188603b705cfSriastradh 188703b705cfSriastradhstart_with_b: 188803b705cfSriastradh x = head_a->x.quo; 188903b705cfSriastradh while (head_b != NULL && head_b->x.quo <= x) { 189003b705cfSriastradh prev = head_b; 189103b705cfSriastradh next = &head_b->next; 189203b705cfSriastradh head_b = head_b->next; 189303b705cfSriastradh } 189403b705cfSriastradh 189503b705cfSriastradh head_a->prev = prev; 189603b705cfSriastradh *next = head_a; 189703b705cfSriastradh if (head_b == NULL) 189803b705cfSriastradh return head; 189903b705cfSriastradh } while (1); 190003b705cfSriastradh} 190103b705cfSriastradh 190203b705cfSriastradhstatic struct mono_edge * 190303b705cfSriastradhmono_sort_edges(struct mono_edge *list, 190403b705cfSriastradh unsigned int level, 190503b705cfSriastradh struct mono_edge **head_out) 190603b705cfSriastradh{ 190703b705cfSriastradh struct mono_edge *head_other, *remaining; 190803b705cfSriastradh unsigned int i; 190903b705cfSriastradh 191003b705cfSriastradh head_other = list->next; 191103b705cfSriastradh 191203b705cfSriastradh if (head_other == NULL) { 191303b705cfSriastradh *head_out = list; 191403b705cfSriastradh return NULL; 191503b705cfSriastradh } 191603b705cfSriastradh 191703b705cfSriastradh remaining = head_other->next; 191803b705cfSriastradh if (list->x.quo <= head_other->x.quo) { 191903b705cfSriastradh *head_out = list; 192003b705cfSriastradh head_other->next = NULL; 192103b705cfSriastradh } else { 192203b705cfSriastradh *head_out = head_other; 192303b705cfSriastradh head_other->prev = list->prev; 192403b705cfSriastradh head_other->next = list; 192503b705cfSriastradh list->prev = head_other; 192603b705cfSriastradh list->next = NULL; 192703b705cfSriastradh } 192803b705cfSriastradh 192903b705cfSriastradh for (i = 0; i < level && remaining; i++) { 193003b705cfSriastradh remaining = mono_sort_edges(remaining, i, &head_other); 193103b705cfSriastradh *head_out = mono_merge_sorted_edges(*head_out, head_other); 193203b705cfSriastradh } 193303b705cfSriastradh 193403b705cfSriastradh return remaining; 193503b705cfSriastradh} 193603b705cfSriastradh 193703b705cfSriastradhstatic struct mono_edge *mono_filter(struct mono_edge *edges) 193803b705cfSriastradh{ 193903b705cfSriastradh struct mono_edge *e; 194003b705cfSriastradh 194103b705cfSriastradh e = edges; 194203b705cfSriastradh do { 194303b705cfSriastradh struct mono_edge *n = e->next; 194403b705cfSriastradh if (e->dir == -n->dir && 194503b705cfSriastradh e->height_left == n->height_left && 194603b705cfSriastradh *(uint64_t *)&e->x == *(uint64_t *)&n->x && 194703b705cfSriastradh *(uint64_t *)&e->dxdy == *(uint64_t *)&n->dxdy) { 194803b705cfSriastradh if (e->prev) 194903b705cfSriastradh e->prev->next = n->next; 195003b705cfSriastradh else 195103b705cfSriastradh edges = n->next; 195203b705cfSriastradh if (n->next) 195303b705cfSriastradh n->next->prev = e->prev; 195403b705cfSriastradh else 195503b705cfSriastradh break; 195603b705cfSriastradh 195703b705cfSriastradh e = n->next; 195803b705cfSriastradh } else 195903b705cfSriastradh e = e->next; 196003b705cfSriastradh } while (e->next); 196103b705cfSriastradh 196203b705cfSriastradh return edges; 196303b705cfSriastradh} 196403b705cfSriastradh 196503b705cfSriastradhstatic struct mono_edge * 196603b705cfSriastradhmono_merge_unsorted_edges(struct mono_edge *head, struct mono_edge *unsorted) 196703b705cfSriastradh{ 196803b705cfSriastradh mono_sort_edges(unsorted, UINT_MAX, &unsorted); 196903b705cfSriastradh return mono_merge_sorted_edges(head, mono_filter(unsorted)); 197003b705cfSriastradh} 197103b705cfSriastradh 197203b705cfSriastradh#if 0 197303b705cfSriastradhstatic inline void 197403b705cfSriastradh__dbg_mono_edges(const char *function, struct mono_edge *edges) 197503b705cfSriastradh{ 197603b705cfSriastradh ErrorF("%s: ", function); 197703b705cfSriastradh while (edges) { 197803b705cfSriastradh if (edges->x.quo < INT16_MAX << 16) { 197903b705cfSriastradh ErrorF("(%d.%06d)+(%d.%06d)x%d, ", 198003b705cfSriastradh edges->x.quo, edges->x.rem, 198103b705cfSriastradh edges->dxdy.quo, edges->dxdy.rem, 198203b705cfSriastradh edges->dy*edges->dir); 198303b705cfSriastradh } 198403b705cfSriastradh edges = edges->next; 198503b705cfSriastradh } 198603b705cfSriastradh ErrorF("\n"); 198703b705cfSriastradh} 198803b705cfSriastradh#define DBG_MONO_EDGES(x) __dbg_mono_edges(__FUNCTION__, x) 198903b705cfSriastradhstatic inline void 199003b705cfSriastradhVALIDATE_MONO_EDGES(struct mono_edge *edges) 199103b705cfSriastradh{ 199203b705cfSriastradh int prev_x = edges->x.quo; 199303b705cfSriastradh while ((edges = edges->next)) { 199403b705cfSriastradh assert(edges->x.quo >= prev_x); 199503b705cfSriastradh prev_x = edges->x.quo; 199603b705cfSriastradh } 199703b705cfSriastradh} 199803b705cfSriastradh 199903b705cfSriastradh#else 200003b705cfSriastradh#define DBG_MONO_EDGES(x) 200103b705cfSriastradh#define VALIDATE_MONO_EDGES(x) 200203b705cfSriastradh#endif 200303b705cfSriastradh 200403b705cfSriastradhinline static void 200503b705cfSriastradhmono_merge_edges(struct mono *c, struct mono_edge *edges) 200603b705cfSriastradh{ 200703b705cfSriastradh struct mono_edge *e; 200803b705cfSriastradh 200903b705cfSriastradh DBG_MONO_EDGES(edges); 201003b705cfSriastradh 201103b705cfSriastradh for (e = edges; c->is_vertical && e; e = e->next) 201203b705cfSriastradh c->is_vertical = e->dy == 0; 201303b705cfSriastradh 201403b705cfSriastradh c->head.next = mono_merge_unsorted_edges(c->head.next, edges); 201503b705cfSriastradh} 201603b705cfSriastradh 201703b705cfSriastradhfastcall static void 201803b705cfSriastradhmono_span(struct mono *c, int x1, int x2, BoxPtr box) 201903b705cfSriastradh{ 202003b705cfSriastradh __DBG(("%s [%d, %d]\n", __FUNCTION__, x1, x2)); 202103b705cfSriastradh 202203b705cfSriastradh box->x1 = x1; 202303b705cfSriastradh box->x2 = x2; 202403b705cfSriastradh 202503b705cfSriastradh if (c->clip.data) { 202603b705cfSriastradh pixman_region16_t region; 202703b705cfSriastradh 202803b705cfSriastradh pixman_region_init_rects(®ion, box, 1); 202903b705cfSriastradh RegionIntersect(®ion, ®ion, &c->clip); 203003b705cfSriastradh if (REGION_NUM_RECTS(®ion)) { 203103b705cfSriastradh c->op.boxes(c->sna, &c->op, 203203b705cfSriastradh REGION_RECTS(®ion), 203303b705cfSriastradh REGION_NUM_RECTS(®ion)); 203403b705cfSriastradh apply_damage(&c->op, ®ion); 203503b705cfSriastradh } 203603b705cfSriastradh pixman_region_fini(®ion); 203703b705cfSriastradh } else { 203803b705cfSriastradh c->op.box(c->sna, &c->op, box); 203903b705cfSriastradh apply_damage_box(&c->op, box); 204003b705cfSriastradh } 204103b705cfSriastradh} 204203b705cfSriastradh 204303b705cfSriastradhfastcall static void 204403b705cfSriastradhmono_span__fast(struct mono *c, int x1, int x2, BoxPtr box) 204503b705cfSriastradh{ 204603b705cfSriastradh __DBG(("%s [%d, %d]\n", __FUNCTION__, x1, x2)); 204703b705cfSriastradh 204803b705cfSriastradh box->x1 = x1; 204903b705cfSriastradh box->x2 = x2; 205003b705cfSriastradh 205103b705cfSriastradh c->op.box(c->sna, &c->op, box); 205203b705cfSriastradh} 205303b705cfSriastradh 205403b705cfSriastradhstruct mono_span_thread_boxes { 205503b705cfSriastradh const struct sna_composite_op *op; 205603b705cfSriastradh#define MONO_SPAN_MAX_BOXES (8192/sizeof(BoxRec)) 205703b705cfSriastradh BoxRec boxes[MONO_SPAN_MAX_BOXES]; 205803b705cfSriastradh int num_boxes; 205903b705cfSriastradh}; 206003b705cfSriastradh 206103b705cfSriastradhinline static void 206203b705cfSriastradhthread_mono_span_add_boxes(struct mono *c, const BoxRec *box, int count) 206303b705cfSriastradh{ 206403b705cfSriastradh struct mono_span_thread_boxes *b = c->op.priv; 206503b705cfSriastradh 206603b705cfSriastradh assert(count > 0 && count <= MONO_SPAN_MAX_BOXES); 206703b705cfSriastradh if (unlikely(b->num_boxes + count > MONO_SPAN_MAX_BOXES)) { 206803b705cfSriastradh b->op->thread_boxes(c->sna, b->op, b->boxes, b->num_boxes); 206903b705cfSriastradh b->num_boxes = 0; 207003b705cfSriastradh } 207103b705cfSriastradh 207203b705cfSriastradh memcpy(b->boxes + b->num_boxes, box, count*sizeof(BoxRec)); 207303b705cfSriastradh b->num_boxes += count; 207403b705cfSriastradh assert(b->num_boxes <= MONO_SPAN_MAX_BOXES); 207503b705cfSriastradh} 207603b705cfSriastradh 207703b705cfSriastradhfastcall static void 207803b705cfSriastradhthread_mono_span_clipped(struct mono *c, int x1, int x2, BoxPtr box) 207903b705cfSriastradh{ 208003b705cfSriastradh pixman_region16_t region; 208103b705cfSriastradh 208203b705cfSriastradh __DBG(("%s [%d, %d]\n", __FUNCTION__, x1, x2)); 208303b705cfSriastradh 208403b705cfSriastradh box->x1 = x1; 208503b705cfSriastradh box->x2 = x2; 208603b705cfSriastradh 208703b705cfSriastradh assert(c->clip.data); 208803b705cfSriastradh 208903b705cfSriastradh pixman_region_init_rects(®ion, box, 1); 209003b705cfSriastradh RegionIntersect(®ion, ®ion, &c->clip); 209103b705cfSriastradh if (REGION_NUM_RECTS(®ion)) 209203b705cfSriastradh thread_mono_span_add_boxes(c, 209303b705cfSriastradh REGION_RECTS(®ion), 209403b705cfSriastradh REGION_NUM_RECTS(®ion)); 209503b705cfSriastradh pixman_region_fini(®ion); 209603b705cfSriastradh} 209703b705cfSriastradh 209803b705cfSriastradhfastcall static void 209903b705cfSriastradhthread_mono_span(struct mono *c, int x1, int x2, BoxPtr box) 210003b705cfSriastradh{ 210103b705cfSriastradh __DBG(("%s [%d, %d]\n", __FUNCTION__, x1, x2)); 210203b705cfSriastradh 210303b705cfSriastradh box->x1 = x1; 210403b705cfSriastradh box->x2 = x2; 210503b705cfSriastradh thread_mono_span_add_boxes(c, box, 1); 210603b705cfSriastradh} 210703b705cfSriastradh 210803b705cfSriastradhinline static void 210903b705cfSriastradhmono_row(struct mono *c, int16_t y, int16_t h) 211003b705cfSriastradh{ 211103b705cfSriastradh struct mono_edge *edge = c->head.next; 211203b705cfSriastradh int prev_x = INT_MIN; 211303b705cfSriastradh int16_t xstart = INT16_MIN; 211403b705cfSriastradh int winding = 0; 211503b705cfSriastradh BoxRec box; 211603b705cfSriastradh 211703b705cfSriastradh DBG_MONO_EDGES(edge); 211803b705cfSriastradh VALIDATE_MONO_EDGES(&c->head); 211903b705cfSriastradh 212003b705cfSriastradh box.y1 = c->clip.extents.y1 + y; 212103b705cfSriastradh box.y2 = box.y1 + h; 212203b705cfSriastradh 212303b705cfSriastradh while (&c->tail != edge) { 212403b705cfSriastradh struct mono_edge *next = edge->next; 212503b705cfSriastradh int16_t xend = I(edge->x.quo); 212603b705cfSriastradh 212703b705cfSriastradh if (--edge->height_left) { 212803b705cfSriastradh if (edge->dy) { 212903b705cfSriastradh edge->x.quo += edge->dxdy.quo; 213003b705cfSriastradh edge->x.rem += edge->dxdy.rem; 213103b705cfSriastradh if (edge->x.rem >= 0) { 213203b705cfSriastradh ++edge->x.quo; 213303b705cfSriastradh edge->x.rem -= edge->dy; 213403b705cfSriastradh } 213503b705cfSriastradh } 213603b705cfSriastradh 213703b705cfSriastradh if (edge->x.quo < prev_x) { 213803b705cfSriastradh struct mono_edge *pos = edge->prev; 213903b705cfSriastradh pos->next = next; 214003b705cfSriastradh next->prev = pos; 214103b705cfSriastradh do { 214203b705cfSriastradh pos = pos->prev; 214303b705cfSriastradh } while (edge->x.quo < pos->x.quo); 214403b705cfSriastradh pos->next->prev = edge; 214503b705cfSriastradh edge->next = pos->next; 214603b705cfSriastradh edge->prev = pos; 214703b705cfSriastradh pos->next = edge; 214803b705cfSriastradh } else 214903b705cfSriastradh prev_x = edge->x.quo; 215003b705cfSriastradh } else { 215103b705cfSriastradh edge->prev->next = next; 215203b705cfSriastradh next->prev = edge->prev; 215303b705cfSriastradh } 215403b705cfSriastradh 215503b705cfSriastradh winding += edge->dir; 215603b705cfSriastradh if (winding == 0) { 215703b705cfSriastradh assert(I(next->x.quo) >= xend); 215803b705cfSriastradh if (I(next->x.quo) > xend + 1) { 215903b705cfSriastradh if (xstart < c->clip.extents.x1) 216003b705cfSriastradh xstart = c->clip.extents.x1; 216103b705cfSriastradh if (xend > c->clip.extents.x2) 216203b705cfSriastradh xend = c->clip.extents.x2; 216303b705cfSriastradh if (xend > xstart) 216403b705cfSriastradh c->span(c, xstart, xend, &box); 216503b705cfSriastradh xstart = INT16_MIN; 216603b705cfSriastradh } 216703b705cfSriastradh } else if (xstart == INT16_MIN) 216803b705cfSriastradh xstart = xend; 216903b705cfSriastradh 217003b705cfSriastradh edge = next; 217103b705cfSriastradh } 217203b705cfSriastradh 217303b705cfSriastradh DBG_MONO_EDGES(c->head.next); 217403b705cfSriastradh VALIDATE_MONO_EDGES(&c->head); 217503b705cfSriastradh} 217603b705cfSriastradh 217703b705cfSriastradhstatic bool 217803b705cfSriastradhmono_init(struct mono *c, int num_edges) 217903b705cfSriastradh{ 218003b705cfSriastradh if (!mono_polygon_init(&c->polygon, &c->clip.extents, num_edges)) 218103b705cfSriastradh return false; 218203b705cfSriastradh 218303b705cfSriastradh c->head.dy = 0; 218403b705cfSriastradh c->head.height_left = INT_MAX; 218503b705cfSriastradh c->head.x.quo = INT16_MIN << 16; 218603b705cfSriastradh c->head.prev = NULL; 218703b705cfSriastradh c->head.next = &c->tail; 218803b705cfSriastradh c->tail.prev = &c->head; 218903b705cfSriastradh c->tail.next = NULL; 219003b705cfSriastradh c->tail.x.quo = INT16_MAX << 16; 219103b705cfSriastradh c->tail.height_left = INT_MAX; 219203b705cfSriastradh c->tail.dy = 0; 219303b705cfSriastradh 219403b705cfSriastradh c->is_vertical = 1; 219503b705cfSriastradh 219603b705cfSriastradh return true; 219703b705cfSriastradh} 219803b705cfSriastradh 219903b705cfSriastradhstatic void 220003b705cfSriastradhmono_fini(struct mono *mono) 220103b705cfSriastradh{ 220203b705cfSriastradh mono_polygon_fini(&mono->polygon); 220303b705cfSriastradh} 220403b705cfSriastradh 220503b705cfSriastradhstatic void 220603b705cfSriastradhmono_step_edges(struct mono *c, int count) 220703b705cfSriastradh{ 220803b705cfSriastradh struct mono_edge *edge; 220903b705cfSriastradh 221003b705cfSriastradh for (edge = c->head.next; edge != &c->tail; edge = edge->next) { 221103b705cfSriastradh edge->height_left -= count; 221203b705cfSriastradh if (! edge->height_left) { 221303b705cfSriastradh edge->prev->next = edge->next; 221403b705cfSriastradh edge->next->prev = edge->prev; 221503b705cfSriastradh } 221603b705cfSriastradh } 221703b705cfSriastradh} 221803b705cfSriastradh 221903b705cfSriastradhflatten static void 222003b705cfSriastradhmono_render(struct mono *mono) 222103b705cfSriastradh{ 222203b705cfSriastradh struct mono_polygon *polygon = &mono->polygon; 222303b705cfSriastradh int i, j, h = mono->clip.extents.y2 - mono->clip.extents.y1; 222403b705cfSriastradh 222503b705cfSriastradh assert(mono->span); 222603b705cfSriastradh 222703b705cfSriastradh for (i = 0; i < h; i = j) { 222803b705cfSriastradh j = i + 1; 222903b705cfSriastradh 223003b705cfSriastradh if (polygon->y_buckets[i]) 223103b705cfSriastradh mono_merge_edges(mono, polygon->y_buckets[i]); 223203b705cfSriastradh 223303b705cfSriastradh if (mono->is_vertical) { 223403b705cfSriastradh struct mono_edge *e = mono->head.next; 223503b705cfSriastradh int min_height = h - i; 223603b705cfSriastradh 223703b705cfSriastradh while (e != &mono->tail) { 223803b705cfSriastradh if (e->height_left < min_height) 223903b705cfSriastradh min_height = e->height_left; 224003b705cfSriastradh e = e->next; 224103b705cfSriastradh } 224203b705cfSriastradh 224303b705cfSriastradh while (--min_height >= 1 && polygon->y_buckets[j] == NULL) 224403b705cfSriastradh j++; 224503b705cfSriastradh if (j != i + 1) 224603b705cfSriastradh mono_step_edges(mono, j - (i + 1)); 224703b705cfSriastradh } 224803b705cfSriastradh 224903b705cfSriastradh mono_row(mono, i, j-i); 225003b705cfSriastradh 225103b705cfSriastradh /* XXX recompute after dropping edges? */ 225203b705cfSriastradh if (mono->head.next == &mono->tail) 225303b705cfSriastradh mono->is_vertical = 1; 225403b705cfSriastradh } 225503b705cfSriastradh} 225603b705cfSriastradh 225703b705cfSriastradhstatic int operator_is_bounded(uint8_t op) 225803b705cfSriastradh{ 225903b705cfSriastradh switch (op) { 226003b705cfSriastradh case PictOpOver: 226103b705cfSriastradh case PictOpOutReverse: 226203b705cfSriastradh case PictOpAdd: 226303b705cfSriastradh return true; 226403b705cfSriastradh default: 226503b705cfSriastradh return false; 226603b705cfSriastradh } 226703b705cfSriastradh} 226803b705cfSriastradh 226903b705cfSriastradhinline static xFixed 227003b705cfSriastradhline_x_for_y(const xLineFixed *l, xFixed y, bool ceil) 227103b705cfSriastradh{ 227203b705cfSriastradh xFixed_32_32 ex = (xFixed_32_32)(y - l->p1.y) * (l->p2.x - l->p1.x); 227303b705cfSriastradh xFixed d = l->p2.y - l->p1.y; 227403b705cfSriastradh 227503b705cfSriastradh if (ceil) 227603b705cfSriastradh ex += (d - 1); 227703b705cfSriastradh 227803b705cfSriastradh return l->p1.x + (xFixed) (ex / d); 227903b705cfSriastradh} 228003b705cfSriastradh 228103b705cfSriastradh#define pixman_fixed_integer_floor(V) pixman_fixed_to_int(V) 228203b705cfSriastradh#define pixman_fixed_integer_ceil(V) pixman_fixed_to_int(pixman_fixed_ceil(V)) 228303b705cfSriastradh 228403b705cfSriastradhstatic void 228503b705cfSriastradhtrapezoids_bounds(int n, const xTrapezoid *t, BoxPtr box) 228603b705cfSriastradh{ 228703b705cfSriastradh xFixed x1, y1, x2, y2; 228803b705cfSriastradh 228903b705cfSriastradh /* XXX need 33 bits... */ 229003b705cfSriastradh x1 = y1 = INT_MAX / 2; 229103b705cfSriastradh x2 = y2 = INT_MIN / 2; 229203b705cfSriastradh 229303b705cfSriastradh do { 229403b705cfSriastradh xFixed fx1, fx2, v; 229503b705cfSriastradh 229603b705cfSriastradh if (!xTrapezoidValid(t)) 229703b705cfSriastradh continue; 229803b705cfSriastradh 229903b705cfSriastradh if (t->top < y1) 230003b705cfSriastradh y1 = t->top; 230103b705cfSriastradh if (t->bottom > y2) 230203b705cfSriastradh y2 = t->bottom; 230303b705cfSriastradh 230403b705cfSriastradh if (((t->left.p1.x - x1) | (t->left.p2.x - x1)) < 0) { 230503b705cfSriastradh if (pixman_fixed_floor(t->left.p1.x) == pixman_fixed_floor(t->left.p2.x)) { 230603b705cfSriastradh x1 = pixman_fixed_floor(t->left.p1.x); 230703b705cfSriastradh } else { 230803b705cfSriastradh if (t->left.p1.y == t->top) 230903b705cfSriastradh fx1 = t->left.p1.x; 231003b705cfSriastradh else 231103b705cfSriastradh fx1 = line_x_for_y(&t->left, t->top, false); 231203b705cfSriastradh 231303b705cfSriastradh if (t->left.p2.y == t->bottom) 231403b705cfSriastradh fx2 = t->left.p2.x; 231503b705cfSriastradh else 231603b705cfSriastradh fx2 = line_x_for_y(&t->left, t->bottom, false); 231703b705cfSriastradh 231803b705cfSriastradh v = min(fx1, fx2); 231903b705cfSriastradh if (v < x1) 232003b705cfSriastradh x1 = pixman_fixed_floor(v); 232103b705cfSriastradh } 232203b705cfSriastradh } 232303b705cfSriastradh 232403b705cfSriastradh if (((x2 - t->right.p1.x) | (x2 - t->right.p2.x)) < 0) { 232503b705cfSriastradh if (pixman_fixed_floor(t->right.p1.x) == pixman_fixed_floor(t->right.p2.x)) { 232603b705cfSriastradh x2 = pixman_fixed_ceil(t->right.p1.x); 232703b705cfSriastradh } else { 232803b705cfSriastradh if (t->right.p1.y == t->top) 232903b705cfSriastradh fx1 = t->right.p1.x; 233003b705cfSriastradh else 233103b705cfSriastradh fx1 = line_x_for_y(&t->right, t->top, true); 233203b705cfSriastradh 233303b705cfSriastradh if (t->right.p2.y == t->bottom) 233403b705cfSriastradh fx2 = t->right.p2.x; 233503b705cfSriastradh else 233603b705cfSriastradh fx2 = line_x_for_y(&t->right, t->bottom, true); 233703b705cfSriastradh 233803b705cfSriastradh v = max(fx1, fx2); 233903b705cfSriastradh if (v > x2) 234003b705cfSriastradh x2 = pixman_fixed_ceil(v); 234103b705cfSriastradh } 234203b705cfSriastradh } 234303b705cfSriastradh } while (t++, --n); 234403b705cfSriastradh 234503b705cfSriastradh box->x1 = pixman_fixed_to_int(x1); 234603b705cfSriastradh box->x2 = pixman_fixed_to_int(x2); 234703b705cfSriastradh box->y1 = pixman_fixed_integer_floor(y1); 234803b705cfSriastradh box->y2 = pixman_fixed_integer_ceil(y2); 234903b705cfSriastradh} 235003b705cfSriastradh 235103b705cfSriastradhstatic bool 235203b705cfSriastradhis_mono(PicturePtr dst, PictFormatPtr mask) 235303b705cfSriastradh{ 235403b705cfSriastradh return mask ? mask->depth < 8 : dst->polyEdge==PolyEdgeSharp; 235503b705cfSriastradh} 235603b705cfSriastradh 235703b705cfSriastradhstatic bool 235803b705cfSriastradhtrapezoids_inplace_fallback(struct sna *sna, 235903b705cfSriastradh CARD8 op, 236003b705cfSriastradh PicturePtr src, PicturePtr dst, PictFormatPtr mask, 236103b705cfSriastradh int ntrap, xTrapezoid *traps) 236203b705cfSriastradh{ 236303b705cfSriastradh pixman_image_t *image; 236403b705cfSriastradh BoxRec box; 236503b705cfSriastradh uint32_t color; 236603b705cfSriastradh int dx, dy; 236703b705cfSriastradh 236803b705cfSriastradh if (op != PictOpAdd) 236903b705cfSriastradh return false; 237003b705cfSriastradh 237103b705cfSriastradh if (is_mono(dst, mask)) { 237203b705cfSriastradh if (dst->format != PICT_a1) 237303b705cfSriastradh return false; 237403b705cfSriastradh } else { 237503b705cfSriastradh if (dst->format != PICT_a8) 237603b705cfSriastradh return false; 237703b705cfSriastradh } 237803b705cfSriastradh 237903b705cfSriastradh if (!sna_picture_is_solid(src, &color) || (color >> 24) != 0xff) { 238003b705cfSriastradh DBG(("%s: not an opaque solid source\n", __FUNCTION__)); 238103b705cfSriastradh return false; 238203b705cfSriastradh } 238303b705cfSriastradh 238403b705cfSriastradh box.x1 = dst->pDrawable->x; 238503b705cfSriastradh box.y1 = dst->pDrawable->y; 238603b705cfSriastradh box.x2 = dst->pDrawable->width; 238703b705cfSriastradh box.y2 = dst->pDrawable->height; 238803b705cfSriastradh if (pixman_region_contains_rectangle(dst->pCompositeClip, 238903b705cfSriastradh &box) != PIXMAN_REGION_IN) { 239003b705cfSriastradh DBG(("%s: requires clipping, drawable (%d,%d), (%d, %d), clip (%d, %d), (%d, %d)\n", __FUNCTION__, 239103b705cfSriastradh box.x1, box.y1, box.x2, box.y2, 239203b705cfSriastradh dst->pCompositeClip->extents.x1, 239303b705cfSriastradh dst->pCompositeClip->extents.y1, 239403b705cfSriastradh dst->pCompositeClip->extents.x2, 239503b705cfSriastradh dst->pCompositeClip->extents.y2)); 239603b705cfSriastradh return false; 239703b705cfSriastradh } 239803b705cfSriastradh 239903b705cfSriastradh if (is_gpu(sna, dst->pDrawable, PREFER_GPU_SPANS)) { 240003b705cfSriastradh DBG(("%s: not performing inplace as dst is already on the GPU\n", 240103b705cfSriastradh __FUNCTION__)); 240203b705cfSriastradh return false; 240303b705cfSriastradh } 240403b705cfSriastradh 240503b705cfSriastradh DBG(("%s\n", __FUNCTION__)); 240603b705cfSriastradh 240703b705cfSriastradh image = NULL; 240803b705cfSriastradh if (sna_drawable_move_to_cpu(dst->pDrawable, MOVE_READ | MOVE_WRITE)) 240903b705cfSriastradh image = image_from_pict(dst, false, &dx, &dy); 241003b705cfSriastradh if (image) { 241103b705cfSriastradh dx += dst->pDrawable->x; 241203b705cfSriastradh dy += dst->pDrawable->y; 241303b705cfSriastradh 241403b705cfSriastradh for (; ntrap; ntrap--, traps++) 241503b705cfSriastradh pixman_rasterize_trapezoid(image, 241603b705cfSriastradh (pixman_trapezoid_t *)traps, 241703b705cfSriastradh dx, dy); 241803b705cfSriastradh 241903b705cfSriastradh pixman_image_unref(image); 242003b705cfSriastradh } 242103b705cfSriastradh 242203b705cfSriastradh return true; 242303b705cfSriastradh} 242403b705cfSriastradh 242503b705cfSriastradhstruct rasterize_traps_thread { 242603b705cfSriastradh xTrapezoid *traps; 242703b705cfSriastradh char *ptr; 242803b705cfSriastradh int stride; 242903b705cfSriastradh BoxRec bounds; 243003b705cfSriastradh pixman_format_code_t format; 243103b705cfSriastradh int ntrap; 243203b705cfSriastradh}; 243303b705cfSriastradh 243403b705cfSriastradhstatic void rasterize_traps_thread(void *arg) 243503b705cfSriastradh{ 243603b705cfSriastradh struct rasterize_traps_thread *thread = arg; 243703b705cfSriastradh pixman_image_t *image; 243803b705cfSriastradh int width, height, n; 243903b705cfSriastradh 244003b705cfSriastradh width = thread->bounds.x2 - thread->bounds.x1; 244103b705cfSriastradh height = thread->bounds.y2 - thread->bounds.y1; 244203b705cfSriastradh 244303b705cfSriastradh memset(thread->ptr, 0, thread->stride*height); 244403b705cfSriastradh if (PIXMAN_FORMAT_DEPTH(thread->format) < 8) 244503b705cfSriastradh image = pixman_image_create_bits(thread->format, 244603b705cfSriastradh width, height, 244703b705cfSriastradh NULL, 0); 244803b705cfSriastradh else 244903b705cfSriastradh image = pixman_image_create_bits(thread->format, 245003b705cfSriastradh width, height, 245103b705cfSriastradh (uint32_t *)thread->ptr, 245203b705cfSriastradh thread->stride); 245303b705cfSriastradh if (image == NULL) 245403b705cfSriastradh return; 245503b705cfSriastradh 245603b705cfSriastradh for (n = 0; n < thread->ntrap; n++) 245703b705cfSriastradh pixman_rasterize_trapezoid(image, 245803b705cfSriastradh (pixman_trapezoid_t *)&thread->traps[n], 245903b705cfSriastradh -thread->bounds.x1, -thread->bounds.y1); 246003b705cfSriastradh 246103b705cfSriastradh if (PIXMAN_FORMAT_DEPTH(thread->format) < 8) { 246203b705cfSriastradh pixman_image_t *a8; 246303b705cfSriastradh 246403b705cfSriastradh a8 = pixman_image_create_bits(PIXMAN_a8, 246503b705cfSriastradh width, height, 246603b705cfSriastradh (uint32_t *)thread->ptr, 246703b705cfSriastradh thread->stride); 246803b705cfSriastradh if (a8) { 246903b705cfSriastradh pixman_image_composite(PIXMAN_OP_SRC, 247003b705cfSriastradh image, NULL, a8, 247103b705cfSriastradh 0, 0, 247203b705cfSriastradh 0, 0, 247303b705cfSriastradh 0, 0, 247403b705cfSriastradh width, height); 247503b705cfSriastradh pixman_image_unref(a8); 247603b705cfSriastradh } 247703b705cfSriastradh } 247803b705cfSriastradh 247903b705cfSriastradh pixman_image_unref(image); 248003b705cfSriastradh} 248103b705cfSriastradh 248203b705cfSriastradhinline static void trapezoid_origin(const xLineFixed *l, int16_t *x, int16_t *y) 248303b705cfSriastradh{ 248403b705cfSriastradh if (l->p1.y < l->p2.y) { 248503b705cfSriastradh *x = pixman_fixed_to_int(l->p1.x); 248603b705cfSriastradh *y = pixman_fixed_to_int(l->p1.y); 248703b705cfSriastradh } else { 248803b705cfSriastradh *x = pixman_fixed_to_int(l->p2.x); 248903b705cfSriastradh *y = pixman_fixed_to_int(l->p2.y); 249003b705cfSriastradh } 249103b705cfSriastradh} 249203b705cfSriastradh 249303b705cfSriastradhstatic void 249403b705cfSriastradhtrapezoids_fallback(struct sna *sna, 249503b705cfSriastradh CARD8 op, PicturePtr src, PicturePtr dst, 249603b705cfSriastradh PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, 249703b705cfSriastradh int ntrap, xTrapezoid * traps) 249803b705cfSriastradh{ 249903b705cfSriastradh ScreenPtr screen = dst->pDrawable->pScreen; 250003b705cfSriastradh 250103b705cfSriastradh if (maskFormat) { 250203b705cfSriastradh PixmapPtr scratch; 250303b705cfSriastradh PicturePtr mask; 250403b705cfSriastradh INT16 dst_x, dst_y; 250503b705cfSriastradh BoxRec bounds; 250603b705cfSriastradh int width, height, depth; 250703b705cfSriastradh pixman_image_t *image; 250803b705cfSriastradh pixman_format_code_t format; 250903b705cfSriastradh int error; 251003b705cfSriastradh 251103b705cfSriastradh trapezoid_origin(&traps[0].left, &dst_x, &dst_y); 251203b705cfSriastradh 251303b705cfSriastradh trapezoids_bounds(ntrap, traps, &bounds); 251403b705cfSriastradh if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) 251503b705cfSriastradh return; 251603b705cfSriastradh 251703b705cfSriastradh DBG(("%s: bounds (%d, %d), (%d, %d)\n", __FUNCTION__, 251803b705cfSriastradh bounds.x1, bounds.y1, bounds.x2, bounds.y2)); 251903b705cfSriastradh 252003b705cfSriastradh if (!sna_compute_composite_extents(&bounds, 252103b705cfSriastradh src, NULL, dst, 252203b705cfSriastradh xSrc, ySrc, 252303b705cfSriastradh 0, 0, 252403b705cfSriastradh bounds.x1, bounds.y1, 252503b705cfSriastradh bounds.x2 - bounds.x1, 252603b705cfSriastradh bounds.y2 - bounds.y1)) 252703b705cfSriastradh return; 252803b705cfSriastradh 252903b705cfSriastradh DBG(("%s: extents (%d, %d), (%d, %d)\n", __FUNCTION__, 253003b705cfSriastradh bounds.x1, bounds.y1, bounds.x2, bounds.y2)); 253103b705cfSriastradh 253203b705cfSriastradh width = bounds.x2 - bounds.x1; 253303b705cfSriastradh height = bounds.y2 - bounds.y1; 253403b705cfSriastradh bounds.x1 -= dst->pDrawable->x; 253503b705cfSriastradh bounds.y1 -= dst->pDrawable->y; 253603b705cfSriastradh bounds.x2 -= dst->pDrawable->x; 253703b705cfSriastradh bounds.y2 -= dst->pDrawable->y; 253803b705cfSriastradh depth = maskFormat->depth; 253903b705cfSriastradh if (depth == 1) { 254003b705cfSriastradh format = PIXMAN_a1; 254103b705cfSriastradh } else if (depth <= 4) { 254203b705cfSriastradh format = PIXMAN_a4; 254303b705cfSriastradh depth = 4; 254403b705cfSriastradh } else 254503b705cfSriastradh format = PIXMAN_a8; 254603b705cfSriastradh 254703b705cfSriastradh DBG(("%s: mask (%dx%d) depth=%d, format=%08x\n", 254803b705cfSriastradh __FUNCTION__, width, height, depth, format)); 254903b705cfSriastradh if (is_gpu(sna, dst->pDrawable, PREFER_GPU_RENDER) || 255003b705cfSriastradh picture_is_gpu(sna, src)) { 255103b705cfSriastradh int num_threads; 255203b705cfSriastradh 255303b705cfSriastradh scratch = sna_pixmap_create_upload(screen, 255403b705cfSriastradh width, height, 8, 255503b705cfSriastradh KGEM_BUFFER_WRITE); 255603b705cfSriastradh if (!scratch) 255703b705cfSriastradh return; 255803b705cfSriastradh 255903b705cfSriastradh num_threads = sna_use_threads(width, height, 8); 256003b705cfSriastradh if (num_threads == 1) { 256103b705cfSriastradh if (depth < 8) { 256203b705cfSriastradh image = pixman_image_create_bits(format, width, height, 256303b705cfSriastradh NULL, 0); 256403b705cfSriastradh } else { 256503b705cfSriastradh memset(scratch->devPrivate.ptr, 0, scratch->devKind*height); 256603b705cfSriastradh 256703b705cfSriastradh image = pixman_image_create_bits(format, width, height, 256803b705cfSriastradh scratch->devPrivate.ptr, 256903b705cfSriastradh scratch->devKind); 257003b705cfSriastradh } 257103b705cfSriastradh if (image) { 257203b705cfSriastradh for (; ntrap; ntrap--, traps++) 257303b705cfSriastradh pixman_rasterize_trapezoid(image, 257403b705cfSriastradh (pixman_trapezoid_t *)traps, 257503b705cfSriastradh -bounds.x1, -bounds.y1); 257603b705cfSriastradh if (depth < 8) { 257703b705cfSriastradh pixman_image_t *a8; 257803b705cfSriastradh 257903b705cfSriastradh a8 = pixman_image_create_bits(PIXMAN_a8, width, height, 258003b705cfSriastradh scratch->devPrivate.ptr, 258103b705cfSriastradh scratch->devKind); 258203b705cfSriastradh if (a8) { 258303b705cfSriastradh pixman_image_composite(PIXMAN_OP_SRC, 258403b705cfSriastradh image, NULL, a8, 258503b705cfSriastradh 0, 0, 258603b705cfSriastradh 0, 0, 258703b705cfSriastradh 0, 0, 258803b705cfSriastradh width, height); 258903b705cfSriastradh format = PIXMAN_a8; 259003b705cfSriastradh depth = 8; 259103b705cfSriastradh pixman_image_unref(a8); 259203b705cfSriastradh } 259303b705cfSriastradh } 259403b705cfSriastradh 259503b705cfSriastradh pixman_image_unref(image); 259603b705cfSriastradh } 259703b705cfSriastradh if (format != PIXMAN_a8) { 259803b705cfSriastradh sna_pixmap_destroy(scratch); 259903b705cfSriastradh return; 260003b705cfSriastradh } 260103b705cfSriastradh } else { 260203b705cfSriastradh struct rasterize_traps_thread threads[num_threads]; 260303b705cfSriastradh int y, dy, n; 260403b705cfSriastradh 260503b705cfSriastradh threads[0].ptr = scratch->devPrivate.ptr; 260603b705cfSriastradh threads[0].stride = scratch->devKind; 260703b705cfSriastradh threads[0].traps = traps; 260803b705cfSriastradh threads[0].ntrap = ntrap; 260903b705cfSriastradh threads[0].bounds = bounds; 261003b705cfSriastradh threads[0].format = format; 261103b705cfSriastradh 261203b705cfSriastradh y = bounds.y1; 261303b705cfSriastradh dy = (height + num_threads - 1) / num_threads; 261403b705cfSriastradh 261503b705cfSriastradh for (n = 1; n < num_threads; n++) { 261603b705cfSriastradh threads[n] = threads[0]; 261703b705cfSriastradh threads[n].ptr += (y - bounds.y1) * threads[n].stride; 261803b705cfSriastradh threads[n].bounds.y1 = y; 261903b705cfSriastradh threads[n].bounds.y2 = y += dy; 262003b705cfSriastradh 262103b705cfSriastradh sna_threads_run(rasterize_traps_thread, &threads[n]); 262203b705cfSriastradh } 262303b705cfSriastradh 262403b705cfSriastradh threads[0].ptr += (y - bounds.y1) * threads[0].stride; 262503b705cfSriastradh threads[0].bounds.y1 = y; 262603b705cfSriastradh threads[0].bounds.y2 = bounds.y2; 262703b705cfSriastradh rasterize_traps_thread(&threads[0]); 262803b705cfSriastradh 262903b705cfSriastradh sna_threads_wait(); 263003b705cfSriastradh 263103b705cfSriastradh format = PIXMAN_a8; 263203b705cfSriastradh depth = 8; 263303b705cfSriastradh } 263403b705cfSriastradh } else { 263503b705cfSriastradh scratch = sna_pixmap_create_unattached(screen, 263603b705cfSriastradh width, height, 263703b705cfSriastradh depth); 263803b705cfSriastradh if (!scratch) 263903b705cfSriastradh return; 264003b705cfSriastradh 264103b705cfSriastradh memset(scratch->devPrivate.ptr, 0, scratch->devKind*height); 264203b705cfSriastradh image = pixman_image_create_bits(format, width, height, 264303b705cfSriastradh scratch->devPrivate.ptr, 264403b705cfSriastradh scratch->devKind); 264503b705cfSriastradh if (image) { 264603b705cfSriastradh for (; ntrap; ntrap--, traps++) 264703b705cfSriastradh pixman_rasterize_trapezoid(image, 264803b705cfSriastradh (pixman_trapezoid_t *)traps, 264903b705cfSriastradh -bounds.x1, -bounds.y1); 265003b705cfSriastradh pixman_image_unref(image); 265103b705cfSriastradh } 265203b705cfSriastradh } 265303b705cfSriastradh 265403b705cfSriastradh mask = CreatePicture(0, &scratch->drawable, 265503b705cfSriastradh PictureMatchFormat(screen, depth, format), 265603b705cfSriastradh 0, 0, serverClient, &error); 265703b705cfSriastradh if (mask) { 265803b705cfSriastradh CompositePicture(op, src, mask, dst, 265903b705cfSriastradh xSrc + bounds.x1 - dst_x, 266003b705cfSriastradh ySrc + bounds.y1 - dst_y, 266103b705cfSriastradh 0, 0, 266203b705cfSriastradh bounds.x1, bounds.y1, 266303b705cfSriastradh width, height); 266403b705cfSriastradh FreePicture(mask, 0); 266503b705cfSriastradh } 266603b705cfSriastradh sna_pixmap_destroy(scratch); 266703b705cfSriastradh } else { 266803b705cfSriastradh if (dst->polyEdge == PolyEdgeSharp) 266903b705cfSriastradh maskFormat = PictureMatchFormat(screen, 1, PICT_a1); 267003b705cfSriastradh else 267103b705cfSriastradh maskFormat = PictureMatchFormat(screen, 8, PICT_a8); 267203b705cfSriastradh 267303b705cfSriastradh for (; ntrap; ntrap--, traps++) 267403b705cfSriastradh trapezoids_fallback(sna, op, 267503b705cfSriastradh src, dst, maskFormat, 267603b705cfSriastradh xSrc, ySrc, 1, traps); 267703b705cfSriastradh } 267803b705cfSriastradh} 267903b705cfSriastradh 268003b705cfSriastradhstatic bool 268103b705cfSriastradhcomposite_aligned_boxes(struct sna *sna, 268203b705cfSriastradh CARD8 op, 268303b705cfSriastradh PicturePtr src, 268403b705cfSriastradh PicturePtr dst, 268503b705cfSriastradh PictFormatPtr maskFormat, 268603b705cfSriastradh INT16 src_x, INT16 src_y, 268703b705cfSriastradh int ntrap, const xTrapezoid *traps, 268803b705cfSriastradh bool force_fallback) 268903b705cfSriastradh{ 269003b705cfSriastradh BoxRec stack_boxes[64], *boxes; 269103b705cfSriastradh pixman_region16_t region, clip; 269203b705cfSriastradh struct sna_composite_op tmp; 269303b705cfSriastradh bool ret = true; 269403b705cfSriastradh int dx, dy, n, num_boxes; 269503b705cfSriastradh 269603b705cfSriastradh if (NO_ALIGNED_BOXES) 269703b705cfSriastradh return false; 269803b705cfSriastradh 269903b705cfSriastradh DBG(("%s\n", __FUNCTION__)); 270003b705cfSriastradh 270103b705cfSriastradh boxes = stack_boxes; 270203b705cfSriastradh if (ntrap > (int)ARRAY_SIZE(stack_boxes)) { 270303b705cfSriastradh boxes = malloc(sizeof(BoxRec)*ntrap); 270403b705cfSriastradh if (boxes == NULL) 270503b705cfSriastradh return false; 270603b705cfSriastradh } 270703b705cfSriastradh 270803b705cfSriastradh dx = dst->pDrawable->x; 270903b705cfSriastradh dy = dst->pDrawable->y; 271003b705cfSriastradh 271103b705cfSriastradh region.extents.x1 = region.extents.y1 = 32767; 271203b705cfSriastradh region.extents.x2 = region.extents.y2 = -32767; 271303b705cfSriastradh num_boxes = 0; 271403b705cfSriastradh for (n = 0; n < ntrap; n++) { 271503b705cfSriastradh boxes[num_boxes].x1 = dx + pixman_fixed_to_int(traps[n].left.p1.x + pixman_fixed_1_minus_e/2); 271603b705cfSriastradh boxes[num_boxes].y1 = dy + pixman_fixed_to_int(traps[n].top + pixman_fixed_1_minus_e/2); 271703b705cfSriastradh boxes[num_boxes].x2 = dx + pixman_fixed_to_int(traps[n].right.p2.x + pixman_fixed_1_minus_e/2); 271803b705cfSriastradh boxes[num_boxes].y2 = dy + pixman_fixed_to_int(traps[n].bottom + pixman_fixed_1_minus_e/2); 271903b705cfSriastradh 272003b705cfSriastradh if (boxes[num_boxes].x1 >= boxes[num_boxes].x2) 272103b705cfSriastradh continue; 272203b705cfSriastradh if (boxes[num_boxes].y1 >= boxes[num_boxes].y2) 272303b705cfSriastradh continue; 272403b705cfSriastradh 272503b705cfSriastradh if (boxes[num_boxes].x1 < region.extents.x1) 272603b705cfSriastradh region.extents.x1 = boxes[num_boxes].x1; 272703b705cfSriastradh if (boxes[num_boxes].x2 > region.extents.x2) 272803b705cfSriastradh region.extents.x2 = boxes[num_boxes].x2; 272903b705cfSriastradh 273003b705cfSriastradh if (boxes[num_boxes].y1 < region.extents.y1) 273103b705cfSriastradh region.extents.y1 = boxes[num_boxes].y1; 273203b705cfSriastradh if (boxes[num_boxes].y2 > region.extents.y2) 273303b705cfSriastradh region.extents.y2 = boxes[num_boxes].y2; 273403b705cfSriastradh 273503b705cfSriastradh num_boxes++; 273603b705cfSriastradh } 273703b705cfSriastradh 273803b705cfSriastradh if (num_boxes == 0) 273903b705cfSriastradh goto free_boxes; 274003b705cfSriastradh 274103b705cfSriastradh DBG(("%s: extents (%d, %d), (%d, %d) offset of (%d, %d)\n", 274203b705cfSriastradh __FUNCTION__, 274303b705cfSriastradh region.extents.x1, region.extents.y1, 274403b705cfSriastradh region.extents.x2, region.extents.y2, 274503b705cfSriastradh region.extents.x1 - boxes[0].x1, 274603b705cfSriastradh region.extents.y1 - boxes[0].y1)); 274703b705cfSriastradh 274803b705cfSriastradh src_x += region.extents.x1 - boxes[0].x1; 274903b705cfSriastradh src_y += region.extents.y1 - boxes[0].y1; 275003b705cfSriastradh 275103b705cfSriastradh if (!sna_compute_composite_region(&clip, 275203b705cfSriastradh src, NULL, dst, 275303b705cfSriastradh src_x, src_y, 275403b705cfSriastradh 0, 0, 275503b705cfSriastradh region.extents.x1 - dx, region.extents.y1 - dy, 275603b705cfSriastradh region.extents.x2 - region.extents.x1, 275703b705cfSriastradh region.extents.y2 - region.extents.y1)) { 275803b705cfSriastradh DBG(("%s: trapezoids do not intersect drawable clips\n", 275903b705cfSriastradh __FUNCTION__)) ; 276003b705cfSriastradh goto done; 276103b705cfSriastradh } 276203b705cfSriastradh 276303b705cfSriastradh if (force_fallback || 276403b705cfSriastradh !sna->render.composite(sna, op, src, NULL, dst, 276503b705cfSriastradh src_x, src_y, 276603b705cfSriastradh 0, 0, 276703b705cfSriastradh clip.extents.x1, clip.extents.y1, 276803b705cfSriastradh clip.extents.x2 - clip.extents.x1, 276903b705cfSriastradh clip.extents.y2 - clip.extents.y1, 277003b705cfSriastradh memset(&tmp, 0, sizeof(tmp)))) { 277103b705cfSriastradh unsigned int flags; 277203b705cfSriastradh pixman_box16_t *b; 277303b705cfSriastradh int i, count; 277403b705cfSriastradh 277503b705cfSriastradh DBG(("%s: composite render op not supported\n", 277603b705cfSriastradh __FUNCTION__)); 277703b705cfSriastradh 277803b705cfSriastradh flags = MOVE_READ | MOVE_WRITE; 277903b705cfSriastradh if (n == 1 && op <= PictOpSrc) 278003b705cfSriastradh flags = MOVE_WRITE | MOVE_INPLACE_HINT; 278103b705cfSriastradh 278203b705cfSriastradh if (!sna_drawable_move_region_to_cpu(dst->pDrawable, &clip, flags)) 278303b705cfSriastradh goto done; 278403b705cfSriastradh if (dst->alphaMap && 278503b705cfSriastradh !sna_drawable_move_to_cpu(dst->alphaMap->pDrawable, 278603b705cfSriastradh MOVE_READ | MOVE_WRITE)) 278703b705cfSriastradh goto done; 278803b705cfSriastradh if (src->pDrawable) { 278903b705cfSriastradh if (!sna_drawable_move_to_cpu(src->pDrawable, 279003b705cfSriastradh MOVE_READ)) 279103b705cfSriastradh goto done; 279203b705cfSriastradh if (src->alphaMap && 279303b705cfSriastradh !sna_drawable_move_to_cpu(src->alphaMap->pDrawable, 279403b705cfSriastradh MOVE_READ)) 279503b705cfSriastradh goto done; 279603b705cfSriastradh } 279703b705cfSriastradh 279803b705cfSriastradh DBG(("%s: fbComposite()\n", __FUNCTION__)); 279903b705cfSriastradh if (maskFormat) { 280003b705cfSriastradh pixman_region_init_rects(®ion, boxes, num_boxes); 280103b705cfSriastradh RegionIntersect(®ion, ®ion, &clip); 280203b705cfSriastradh 280303b705cfSriastradh b = REGION_RECTS(®ion); 280403b705cfSriastradh count = REGION_NUM_RECTS(®ion); 280503b705cfSriastradh for (i = 0; i < count; i++) { 280603b705cfSriastradh fbComposite(op, src, NULL, dst, 280703b705cfSriastradh src_x + b[i].x1 - boxes[0].x1, 280803b705cfSriastradh src_y + b[i].y1 - boxes[0].y1, 280903b705cfSriastradh 0, 0, 281003b705cfSriastradh b[i].x1, b[i].y1, 281103b705cfSriastradh b[i].x2 - b[i].x1, b[i].y2 - b[i].y1); 281203b705cfSriastradh } 281303b705cfSriastradh pixman_region_fini(®ion); 281403b705cfSriastradh } else { 281503b705cfSriastradh for (n = 0; n < num_boxes; n++) { 281603b705cfSriastradh pixman_region_init_rects(®ion, &boxes[n], 1); 281703b705cfSriastradh RegionIntersect(®ion, ®ion, &clip); 281803b705cfSriastradh b = REGION_RECTS(®ion); 281903b705cfSriastradh count = REGION_NUM_RECTS(®ion); 282003b705cfSriastradh for (i = 0; i < count; i++) { 282103b705cfSriastradh fbComposite(op, src, NULL, dst, 282203b705cfSriastradh src_x + b[i].x1 - boxes[0].x1, 282303b705cfSriastradh src_y + b[i].y1 - boxes[0].y1, 282403b705cfSriastradh 0, 0, 282503b705cfSriastradh b[i].x1, b[i].y1, 282603b705cfSriastradh b[i].x2 - b[i].x1, b[i].y2 - b[i].y1); 282703b705cfSriastradh } 282803b705cfSriastradh pixman_region_fini(®ion); 282903b705cfSriastradh pixman_region_fini(®ion); 283003b705cfSriastradh } 283103b705cfSriastradh } 283203b705cfSriastradh ret = true; 283303b705cfSriastradh goto done; 283403b705cfSriastradh } 283503b705cfSriastradh 283603b705cfSriastradh if (maskFormat || 283703b705cfSriastradh (op == PictOpSrc || op == PictOpClear) || 283803b705cfSriastradh num_boxes == 1) { 283903b705cfSriastradh pixman_region_init_rects(®ion, boxes, num_boxes); 284003b705cfSriastradh RegionIntersect(®ion, ®ion, &clip); 284103b705cfSriastradh if (REGION_NUM_RECTS(®ion)) { 284203b705cfSriastradh tmp.boxes(sna, &tmp, 284303b705cfSriastradh REGION_RECTS(®ion), 284403b705cfSriastradh REGION_NUM_RECTS(®ion)); 284503b705cfSriastradh apply_damage(&tmp, ®ion); 284603b705cfSriastradh } 284703b705cfSriastradh pixman_region_fini(®ion); 284803b705cfSriastradh } else { 284903b705cfSriastradh for (n = 0; n < num_boxes; n++) { 285003b705cfSriastradh pixman_region_init_rects(®ion, &boxes[n], 1); 285103b705cfSriastradh RegionIntersect(®ion, ®ion, &clip); 285203b705cfSriastradh if (REGION_NUM_RECTS(®ion)) { 285303b705cfSriastradh tmp.boxes(sna, &tmp, 285403b705cfSriastradh REGION_RECTS(®ion), 285503b705cfSriastradh REGION_NUM_RECTS(®ion)); 285603b705cfSriastradh apply_damage(&tmp, ®ion); 285703b705cfSriastradh } 285803b705cfSriastradh pixman_region_fini(®ion); 285903b705cfSriastradh } 286003b705cfSriastradh } 286103b705cfSriastradh tmp.done(sna, &tmp); 286203b705cfSriastradh 286303b705cfSriastradhdone: 286403b705cfSriastradh REGION_UNINIT(NULL, &clip); 286503b705cfSriastradhfree_boxes: 286603b705cfSriastradh if (boxes != stack_boxes) 286703b705cfSriastradh free(boxes); 286803b705cfSriastradh 286903b705cfSriastradh return ret; 287003b705cfSriastradh} 287103b705cfSriastradh 287203b705cfSriastradhstatic inline int grid_coverage(int samples, pixman_fixed_t f) 287303b705cfSriastradh{ 287403b705cfSriastradh return (samples * pixman_fixed_frac(f) + pixman_fixed_1/2) / pixman_fixed_1; 287503b705cfSriastradh} 287603b705cfSriastradh 287703b705cfSriastradhinline static void 287803b705cfSriastradhcomposite_unaligned_box(struct sna *sna, 287903b705cfSriastradh struct sna_composite_spans_op *tmp, 288003b705cfSriastradh const BoxRec *box, 288103b705cfSriastradh float opacity, 288203b705cfSriastradh pixman_region16_t *clip) 288303b705cfSriastradh{ 288403b705cfSriastradh assert(opacity != 0.); 288503b705cfSriastradh 288603b705cfSriastradh if (clip) { 288703b705cfSriastradh pixman_region16_t region; 288803b705cfSriastradh 288903b705cfSriastradh pixman_region_init_rects(®ion, box, 1); 289003b705cfSriastradh RegionIntersect(®ion, ®ion, clip); 289103b705cfSriastradh if (REGION_NUM_RECTS(®ion)) 289203b705cfSriastradh tmp->boxes(sna, tmp, 289303b705cfSriastradh REGION_RECTS(®ion), 289403b705cfSriastradh REGION_NUM_RECTS(®ion), 289503b705cfSriastradh opacity); 289603b705cfSriastradh pixman_region_fini(®ion); 289703b705cfSriastradh } else 289803b705cfSriastradh tmp->box(sna, tmp, box, opacity); 289903b705cfSriastradh} 290003b705cfSriastradh 290103b705cfSriastradhinline static void 290203b705cfSriastradhcomposite_unaligned_trap_row(struct sna *sna, 290303b705cfSriastradh struct sna_composite_spans_op *tmp, 290403b705cfSriastradh const xTrapezoid *trap, int dx, 290503b705cfSriastradh int y1, int y2, int covered, 290603b705cfSriastradh pixman_region16_t *clip) 290703b705cfSriastradh{ 290803b705cfSriastradh BoxRec box; 290903b705cfSriastradh int opacity; 291003b705cfSriastradh int x1, x2; 291103b705cfSriastradh#define u8_to_float(x) ((x) * (1.f/255)) 291203b705cfSriastradh 291303b705cfSriastradh if (covered == 0) 291403b705cfSriastradh return; 291503b705cfSriastradh 291603b705cfSriastradh x1 = dx + pixman_fixed_to_int(trap->left.p1.x); 291703b705cfSriastradh x2 = dx + pixman_fixed_to_int(trap->right.p1.x); 291803b705cfSriastradh if (clip) { 291903b705cfSriastradh if (y2 > clip->extents.y2) 292003b705cfSriastradh y2 = clip->extents.y2; 292103b705cfSriastradh if (y1 < clip->extents.y1) 292203b705cfSriastradh y1 = clip->extents.y1; 292303b705cfSriastradh if (y1 >= y2) 292403b705cfSriastradh return; 292503b705cfSriastradh 292603b705cfSriastradh if (x2 < clip->extents.x1 || x1 > clip->extents.x2) 292703b705cfSriastradh return; 292803b705cfSriastradh } 292903b705cfSriastradh 293003b705cfSriastradh box.y1 = y1; 293103b705cfSriastradh box.y2 = y2; 293203b705cfSriastradh 293303b705cfSriastradh if (x1 == x2) { 293403b705cfSriastradh box.x1 = x1; 293503b705cfSriastradh box.x2 = x2 + 1; 293603b705cfSriastradh 293703b705cfSriastradh opacity = covered; 293803b705cfSriastradh opacity *= grid_coverage(SAMPLES_X, trap->right.p1.x) - grid_coverage(SAMPLES_X, trap->left.p1.x); 293903b705cfSriastradh 294003b705cfSriastradh if (opacity) 294103b705cfSriastradh composite_unaligned_box(sna, tmp, &box, 294203b705cfSriastradh u8_to_float(opacity), clip); 294303b705cfSriastradh } else { 294403b705cfSriastradh if (pixman_fixed_frac(trap->left.p1.x)) { 294503b705cfSriastradh box.x1 = x1; 294603b705cfSriastradh box.x2 = ++x1; 294703b705cfSriastradh 294803b705cfSriastradh opacity = covered; 294903b705cfSriastradh opacity *= SAMPLES_X - grid_coverage(SAMPLES_X, trap->left.p1.x); 295003b705cfSriastradh 295103b705cfSriastradh if (opacity) 295203b705cfSriastradh composite_unaligned_box(sna, tmp, &box, 295303b705cfSriastradh u8_to_float(opacity), clip); 295403b705cfSriastradh } 295503b705cfSriastradh 295603b705cfSriastradh if (x2 > x1) { 295703b705cfSriastradh box.x1 = x1; 295803b705cfSriastradh box.x2 = x2; 295903b705cfSriastradh 296003b705cfSriastradh composite_unaligned_box(sna, tmp, &box, 296103b705cfSriastradh covered == SAMPLES_Y ? 1. : u8_to_float(covered*SAMPLES_X), 296203b705cfSriastradh clip); 296303b705cfSriastradh } 296403b705cfSriastradh 296503b705cfSriastradh if (pixman_fixed_frac(trap->right.p1.x)) { 296603b705cfSriastradh box.x1 = x2; 296703b705cfSriastradh box.x2 = x2 + 1; 296803b705cfSriastradh 296903b705cfSriastradh opacity = covered; 297003b705cfSriastradh opacity *= grid_coverage(SAMPLES_X, trap->right.p1.x); 297103b705cfSriastradh 297203b705cfSriastradh if (opacity) 297303b705cfSriastradh composite_unaligned_box(sna, tmp, &box, 297403b705cfSriastradh u8_to_float(opacity), clip); 297503b705cfSriastradh } 297603b705cfSriastradh } 297703b705cfSriastradh} 297803b705cfSriastradh 297903b705cfSriastradhflatten static void 298003b705cfSriastradhcomposite_unaligned_trap(struct sna *sna, 298103b705cfSriastradh struct sna_composite_spans_op *tmp, 298203b705cfSriastradh const xTrapezoid *trap, 298303b705cfSriastradh int dx, int dy, 298403b705cfSriastradh pixman_region16_t *clip) 298503b705cfSriastradh{ 298603b705cfSriastradh int y1, y2; 298703b705cfSriastradh 298803b705cfSriastradh y1 = dy + pixman_fixed_to_int(trap->top); 298903b705cfSriastradh y2 = dy + pixman_fixed_to_int(trap->bottom); 299003b705cfSriastradh 299103b705cfSriastradh DBG(("%s: y1=%d, y2=%d\n", __FUNCTION__, y1, y2)); 299203b705cfSriastradh 299303b705cfSriastradh if (y1 == y2) { 299403b705cfSriastradh composite_unaligned_trap_row(sna, tmp, trap, dx, 299503b705cfSriastradh y1, y1 + 1, 299603b705cfSriastradh grid_coverage(SAMPLES_Y, trap->bottom) - grid_coverage(SAMPLES_Y, trap->top), 299703b705cfSriastradh clip); 299803b705cfSriastradh } else { 299903b705cfSriastradh if (pixman_fixed_frac(trap->top)) { 300003b705cfSriastradh composite_unaligned_trap_row(sna, tmp, trap, dx, 300103b705cfSriastradh y1, y1 + 1, 300203b705cfSriastradh SAMPLES_Y - grid_coverage(SAMPLES_Y, trap->top), 300303b705cfSriastradh clip); 300403b705cfSriastradh y1++; 300503b705cfSriastradh } 300603b705cfSriastradh 300703b705cfSriastradh if (y2 > y1) 300803b705cfSriastradh composite_unaligned_trap_row(sna, tmp, trap, dx, 300903b705cfSriastradh y1, y2, 301003b705cfSriastradh SAMPLES_Y, 301103b705cfSriastradh clip); 301203b705cfSriastradh 301303b705cfSriastradh if (pixman_fixed_frac(trap->bottom)) 301403b705cfSriastradh composite_unaligned_trap_row(sna, tmp, trap, dx, 301503b705cfSriastradh y2, y2 + 1, 301603b705cfSriastradh grid_coverage(SAMPLES_Y, trap->bottom), 301703b705cfSriastradh clip); 301803b705cfSriastradh } 301903b705cfSriastradh 302003b705cfSriastradh if (tmp->base.damage) { 302103b705cfSriastradh BoxRec box; 302203b705cfSriastradh 302303b705cfSriastradh box.x1 = dx + pixman_fixed_to_int(trap->left.p1.x); 302403b705cfSriastradh box.x2 = dx + pixman_fixed_to_int(trap->right.p1.x + pixman_fixed_1_minus_e); 302503b705cfSriastradh box.y1 = dy + pixman_fixed_to_int(trap->top); 302603b705cfSriastradh box.y2 = dy + pixman_fixed_to_int(trap->bottom + pixman_fixed_1_minus_e); 302703b705cfSriastradh 302803b705cfSriastradh if (clip) { 302903b705cfSriastradh pixman_region16_t region; 303003b705cfSriastradh 303103b705cfSriastradh pixman_region_init_rects(®ion, &box, 1); 303203b705cfSriastradh RegionIntersect(®ion, ®ion, clip); 303303b705cfSriastradh if (REGION_NUM_RECTS(®ion)) 303403b705cfSriastradh apply_damage(&tmp->base, ®ion); 303503b705cfSriastradh RegionUninit(®ion); 303603b705cfSriastradh } else 303703b705cfSriastradh apply_damage_box(&tmp->base, &box); 303803b705cfSriastradh } 303903b705cfSriastradh} 304003b705cfSriastradh 304103b705cfSriastradhinline static void 304203b705cfSriastradhblt_opacity(PixmapPtr scratch, 304303b705cfSriastradh int x1, int x2, 304403b705cfSriastradh int y, int h, 304503b705cfSriastradh uint8_t opacity) 304603b705cfSriastradh{ 304703b705cfSriastradh uint8_t *ptr; 304803b705cfSriastradh 304903b705cfSriastradh if (opacity == 0xff) 305003b705cfSriastradh return; 305103b705cfSriastradh 305203b705cfSriastradh if (x1 < 0) 305303b705cfSriastradh x1 = 0; 305403b705cfSriastradh if (x2 > scratch->drawable.width) 305503b705cfSriastradh x2 = scratch->drawable.width; 305603b705cfSriastradh if (x1 >= x2) 305703b705cfSriastradh return; 305803b705cfSriastradh 305903b705cfSriastradh x2 -= x1; 306003b705cfSriastradh 306103b705cfSriastradh ptr = scratch->devPrivate.ptr; 306203b705cfSriastradh ptr += scratch->devKind * y; 306303b705cfSriastradh ptr += x1; 306403b705cfSriastradh do { 306503b705cfSriastradh if (x2 == 1) 306603b705cfSriastradh *ptr = opacity; 306703b705cfSriastradh else 306803b705cfSriastradh memset(ptr, opacity, x2); 306903b705cfSriastradh ptr += scratch->devKind; 307003b705cfSriastradh } while (--h); 307103b705cfSriastradh} 307203b705cfSriastradh 307303b705cfSriastradhstatic void 307403b705cfSriastradhblt_unaligned_box_row(PixmapPtr scratch, 307503b705cfSriastradh BoxPtr extents, 307603b705cfSriastradh const xTrapezoid *trap, 307703b705cfSriastradh int y1, int y2, 307803b705cfSriastradh int covered) 307903b705cfSriastradh{ 308003b705cfSriastradh int x1, x2; 308103b705cfSriastradh 308203b705cfSriastradh if (y2 > scratch->drawable.height) 308303b705cfSriastradh y2 = scratch->drawable.height; 308403b705cfSriastradh if (y1 < 0) 308503b705cfSriastradh y1 = 0; 308603b705cfSriastradh if (y1 >= y2) 308703b705cfSriastradh return; 308803b705cfSriastradh 308903b705cfSriastradh y2 -= y1; 309003b705cfSriastradh 309103b705cfSriastradh x1 = pixman_fixed_to_int(trap->left.p1.x); 309203b705cfSriastradh x2 = pixman_fixed_to_int(trap->right.p1.x); 309303b705cfSriastradh 309403b705cfSriastradh x1 -= extents->x1; 309503b705cfSriastradh x2 -= extents->x1; 309603b705cfSriastradh 309703b705cfSriastradh if (x1 == x2) { 309803b705cfSriastradh blt_opacity(scratch, 309903b705cfSriastradh x1, x1+1, 310003b705cfSriastradh y1, y2, 310103b705cfSriastradh covered * (grid_coverage(SAMPLES_X, trap->right.p1.x) - grid_coverage(SAMPLES_X, trap->left.p1.x))); 310203b705cfSriastradh } else { 310303b705cfSriastradh if (pixman_fixed_frac(trap->left.p1.x)) { 310403b705cfSriastradh blt_opacity(scratch, 310503b705cfSriastradh x1, x1 + 1, 310603b705cfSriastradh y1, y2, 310703b705cfSriastradh covered * (SAMPLES_X - grid_coverage(SAMPLES_X, trap->left.p1.x))); 310803b705cfSriastradh x1++; 310903b705cfSriastradh } 311003b705cfSriastradh 311103b705cfSriastradh if (x2 > x1) { 311203b705cfSriastradh blt_opacity(scratch, 311303b705cfSriastradh x1, x2, 311403b705cfSriastradh y1, y2, 311503b705cfSriastradh covered*SAMPLES_X); 311603b705cfSriastradh } 311703b705cfSriastradh 311803b705cfSriastradh if (pixman_fixed_frac(trap->right.p1.x)) 311903b705cfSriastradh blt_opacity(scratch, 312003b705cfSriastradh x2, x2 + 1, 312103b705cfSriastradh y1, y2, 312203b705cfSriastradh covered * grid_coverage(SAMPLES_X, trap->right.p1.x)); 312303b705cfSriastradh } 312403b705cfSriastradh} 312503b705cfSriastradh 312603b705cfSriastradh#define ONE_HALF 0x7f 312703b705cfSriastradh#define RB_MASK 0x00ff00ff 312803b705cfSriastradh#define RB_ONE_HALF 0x007f007f 312903b705cfSriastradh#define RB_MASK_PLUS_ONE 0x01000100 313003b705cfSriastradh#define G_SHIFT 8 313103b705cfSriastradh 313203b705cfSriastradhstatic force_inline uint32_t 313303b705cfSriastradhmul8x2_8 (uint32_t a, uint8_t b) 313403b705cfSriastradh{ 313503b705cfSriastradh uint32_t t = (a & RB_MASK) * b + RB_ONE_HALF; 313603b705cfSriastradh return ((t + ((t >> G_SHIFT) & RB_MASK)) >> G_SHIFT) & RB_MASK; 313703b705cfSriastradh} 313803b705cfSriastradh 313903b705cfSriastradhstatic force_inline uint32_t 314003b705cfSriastradhadd8x2_8x2(uint32_t a, uint32_t b) 314103b705cfSriastradh{ 314203b705cfSriastradh uint32_t t = a + b; 314303b705cfSriastradh t |= RB_MASK_PLUS_ONE - ((t >> G_SHIFT) & RB_MASK); 314403b705cfSriastradh return t & RB_MASK; 314503b705cfSriastradh} 314603b705cfSriastradh 314703b705cfSriastradhstatic force_inline uint32_t 314803b705cfSriastradhlerp8x4(uint32_t src, uint8_t a, uint32_t dst) 314903b705cfSriastradh{ 315003b705cfSriastradh return (add8x2_8x2(mul8x2_8(src, a), 315103b705cfSriastradh mul8x2_8(dst, ~a)) | 315203b705cfSriastradh add8x2_8x2(mul8x2_8(src >> G_SHIFT, a), 315303b705cfSriastradh mul8x2_8(dst >> G_SHIFT, ~a)) << G_SHIFT); 315403b705cfSriastradh} 315503b705cfSriastradh 315603b705cfSriastradhinline static void 315703b705cfSriastradhlerp32_opacity(PixmapPtr scratch, 315803b705cfSriastradh uint32_t color, 315903b705cfSriastradh int16_t x, int16_t w, 316003b705cfSriastradh int16_t y, int16_t h, 316103b705cfSriastradh uint8_t opacity) 316203b705cfSriastradh{ 316303b705cfSriastradh uint32_t *ptr; 316403b705cfSriastradh int stride, i; 316503b705cfSriastradh 316603b705cfSriastradh ptr = (uint32_t*)((uint8_t *)scratch->devPrivate.ptr + scratch->devKind * y); 316703b705cfSriastradh ptr += x; 316803b705cfSriastradh stride = scratch->devKind / 4; 316903b705cfSriastradh 317003b705cfSriastradh if (opacity == 0xff) { 317103b705cfSriastradh if ((w | h) == 1) { 317203b705cfSriastradh *ptr = color; 317303b705cfSriastradh } else { 317403b705cfSriastradh if (w < 16) { 317503b705cfSriastradh do { 317603b705cfSriastradh for (i = 0; i < w; i++) 317703b705cfSriastradh ptr[i] = color; 317803b705cfSriastradh ptr += stride; 317903b705cfSriastradh } while (--h); 318003b705cfSriastradh } else { 318103b705cfSriastradh pixman_fill(ptr, stride, 32, 318203b705cfSriastradh 0, 0, w, h, color); 318303b705cfSriastradh } 318403b705cfSriastradh } 318503b705cfSriastradh } else { 318603b705cfSriastradh if ((w | h) == 1) { 318703b705cfSriastradh *ptr = lerp8x4(color, opacity, *ptr); 318803b705cfSriastradh } else if (w == 1) { 318903b705cfSriastradh do { 319003b705cfSriastradh *ptr = lerp8x4(color, opacity, *ptr); 319103b705cfSriastradh ptr += stride; 319203b705cfSriastradh } while (--h); 319303b705cfSriastradh } else{ 319403b705cfSriastradh do { 319503b705cfSriastradh for (i = 0; i < w; i++) 319603b705cfSriastradh ptr[i] = lerp8x4(color, opacity, ptr[i]); 319703b705cfSriastradh ptr += stride; 319803b705cfSriastradh } while (--h); 319903b705cfSriastradh } 320003b705cfSriastradh } 320103b705cfSriastradh} 320203b705cfSriastradh 320303b705cfSriastradhstatic void 320403b705cfSriastradhlerp32_unaligned_box_row(PixmapPtr scratch, uint32_t color, 320503b705cfSriastradh const BoxRec *extents, 320603b705cfSriastradh const xTrapezoid *trap, int16_t dx, 320703b705cfSriastradh int16_t y, int16_t h, 320803b705cfSriastradh uint8_t covered) 320903b705cfSriastradh{ 321003b705cfSriastradh int16_t x1 = pixman_fixed_to_int(trap->left.p1.x) + dx; 321103b705cfSriastradh uint16_t fx1 = grid_coverage(SAMPLES_X, trap->left.p1.x); 321203b705cfSriastradh int16_t x2 = pixman_fixed_to_int(trap->right.p2.x) + dx; 321303b705cfSriastradh uint16_t fx2 = grid_coverage(SAMPLES_X, trap->right.p2.x); 321403b705cfSriastradh 321503b705cfSriastradh if (x1 < extents->x1) 321603b705cfSriastradh x1 = extents->x1, fx1 = 0; 321703b705cfSriastradh if (x2 >= extents->x2) 321803b705cfSriastradh x2 = extents->x2, fx2 = 0; 321903b705cfSriastradh 322003b705cfSriastradh DBG(("%s: x=(%d.%d, %d.%d), y=%dx%d, covered=%d\n", __FUNCTION__, 322103b705cfSriastradh x1, fx1, x2, fx2, y, h, covered)); 322203b705cfSriastradh 322303b705cfSriastradh if (x1 < x2) { 322403b705cfSriastradh if (fx1) { 322503b705cfSriastradh lerp32_opacity(scratch, color, 322603b705cfSriastradh x1, 1, 322703b705cfSriastradh y, h, 322803b705cfSriastradh covered * (SAMPLES_X - fx1)); 322903b705cfSriastradh x1++; 323003b705cfSriastradh } 323103b705cfSriastradh 323203b705cfSriastradh if (x2 > x1) { 323303b705cfSriastradh lerp32_opacity(scratch, color, 323403b705cfSriastradh x1, x2-x1, 323503b705cfSriastradh y, h, 323603b705cfSriastradh covered*SAMPLES_X); 323703b705cfSriastradh } 323803b705cfSriastradh 323903b705cfSriastradh if (fx2) { 324003b705cfSriastradh lerp32_opacity(scratch, color, 324103b705cfSriastradh x2, 1, 324203b705cfSriastradh y, h, 324303b705cfSriastradh covered * fx2); 324403b705cfSriastradh } 324503b705cfSriastradh } else if (x1 == x2 && fx2 > fx1) { 324603b705cfSriastradh lerp32_opacity(scratch, color, 324703b705cfSriastradh x1, 1, 324803b705cfSriastradh y, h, 324903b705cfSriastradh covered * (fx2 - fx1)); 325003b705cfSriastradh } 325103b705cfSriastradh} 325203b705cfSriastradh 325303b705cfSriastradhstruct pixman_inplace { 325403b705cfSriastradh pixman_image_t *image, *source, *mask; 325503b705cfSriastradh uint32_t color; 325603b705cfSriastradh uint32_t *bits; 325703b705cfSriastradh int dx, dy; 325803b705cfSriastradh int sx, sy; 325903b705cfSriastradh uint8_t op; 326003b705cfSriastradh}; 326103b705cfSriastradh 326203b705cfSriastradhstatic force_inline uint8_t 326303b705cfSriastradhmul_8_8(uint8_t a, uint8_t b) 326403b705cfSriastradh{ 326503b705cfSriastradh uint16_t t = a * (uint16_t)b + 0x7f; 326603b705cfSriastradh return ((t >> 8) + t) >> 8; 326703b705cfSriastradh} 326803b705cfSriastradh 326903b705cfSriastradhstatic inline uint32_t multa(uint32_t s, uint8_t a, int shift) 327003b705cfSriastradh{ 327103b705cfSriastradh return mul_8_8((s >> shift) & 0xff, a) << shift; 327203b705cfSriastradh} 327303b705cfSriastradh 327403b705cfSriastradhstatic inline uint32_t mul_4x8_8(uint32_t color, uint8_t alpha) 327503b705cfSriastradh{ 327603b705cfSriastradh uint32_t v; 327703b705cfSriastradh 327803b705cfSriastradh v = 0; 327903b705cfSriastradh v |= multa(color, alpha, 24); 328003b705cfSriastradh v |= multa(color, alpha, 16); 328103b705cfSriastradh v |= multa(color, alpha, 8); 328203b705cfSriastradh v |= multa(color, alpha, 0); 328303b705cfSriastradh 328403b705cfSriastradh return v; 328503b705cfSriastradh} 328603b705cfSriastradh 328703b705cfSriastradhinline static void 328803b705cfSriastradhpixsolid_opacity(struct pixman_inplace *pi, 328903b705cfSriastradh int16_t x, int16_t w, 329003b705cfSriastradh int16_t y, int16_t h, 329103b705cfSriastradh uint8_t opacity) 329203b705cfSriastradh{ 329303b705cfSriastradh if (opacity == 0xff) 329403b705cfSriastradh *pi->bits = pi->color; 329503b705cfSriastradh else 329603b705cfSriastradh *pi->bits = mul_4x8_8(pi->color, opacity); 329703b705cfSriastradh pixman_image_composite(pi->op, pi->source, NULL, pi->image, 329803b705cfSriastradh 0, 0, 0, 0, pi->dx + x, pi->dy + y, w, h); 329903b705cfSriastradh} 330003b705cfSriastradh 330103b705cfSriastradhstatic void 330203b705cfSriastradhpixsolid_unaligned_box_row(struct pixman_inplace *pi, 330303b705cfSriastradh const BoxRec *extents, 330403b705cfSriastradh const xTrapezoid *trap, 330503b705cfSriastradh int16_t y, int16_t h, 330603b705cfSriastradh uint8_t covered) 330703b705cfSriastradh{ 330803b705cfSriastradh int16_t x1 = pixman_fixed_to_int(trap->left.p1.x); 330903b705cfSriastradh uint16_t fx1 = grid_coverage(SAMPLES_X, trap->left.p1.x); 331003b705cfSriastradh int16_t x2 = pixman_fixed_to_int(trap->right.p1.x); 331103b705cfSriastradh uint16_t fx2 = grid_coverage(SAMPLES_X, trap->right.p1.x); 331203b705cfSriastradh 331303b705cfSriastradh if (x1 < extents->x1) 331403b705cfSriastradh x1 = extents->x1, fx1 = 0; 331503b705cfSriastradh if (x2 >= extents->x2) 331603b705cfSriastradh x2 = extents->x2, fx2 = 0; 331703b705cfSriastradh 331803b705cfSriastradh if (x1 < x2) { 331903b705cfSriastradh if (fx1) { 332003b705cfSriastradh pixsolid_opacity(pi, x1, 1, y, h, 332103b705cfSriastradh covered * (SAMPLES_X - fx1)); 332203b705cfSriastradh x1++; 332303b705cfSriastradh } 332403b705cfSriastradh 332503b705cfSriastradh if (x2 > x1) 332603b705cfSriastradh pixsolid_opacity(pi, x1, x2-x1, y, h, covered*SAMPLES_X); 332703b705cfSriastradh 332803b705cfSriastradh if (fx2) 332903b705cfSriastradh pixsolid_opacity(pi, x2, 1, y, h, covered * fx2); 333003b705cfSriastradh } else if (x1 == x2 && fx2 > fx1) { 333103b705cfSriastradh pixsolid_opacity(pi, x1, 1, y, h, covered * (fx2 - fx1)); 333203b705cfSriastradh } 333303b705cfSriastradh} 333403b705cfSriastradh 333503b705cfSriastradhstatic bool 333603b705cfSriastradhcomposite_unaligned_boxes_inplace__solid(struct sna *sna, 333703b705cfSriastradh CARD8 op, uint32_t color, 333803b705cfSriastradh PicturePtr dst, 333903b705cfSriastradh int n, const xTrapezoid *t, 334003b705cfSriastradh bool force_fallback) 334103b705cfSriastradh{ 334203b705cfSriastradh PixmapPtr pixmap; 334303b705cfSriastradh int16_t dx, dy; 334403b705cfSriastradh 334503b705cfSriastradh DBG(("%s: force=%d, is_gpu=%d, op=%d, color=%x\n", __FUNCTION__, 334603b705cfSriastradh force_fallback, is_gpu(sna, dst->pDrawable, PREFER_GPU_SPANS), op, color)); 334703b705cfSriastradh 334803b705cfSriastradh if (!force_fallback && is_gpu(sna, dst->pDrawable, PREFER_GPU_SPANS)) { 334903b705cfSriastradh DBG(("%s: fallback -- can not perform operation in place, destination busy\n", 335003b705cfSriastradh __FUNCTION__)); 335103b705cfSriastradh 335203b705cfSriastradh return false; 335303b705cfSriastradh } 335403b705cfSriastradh 335503b705cfSriastradh /* XXX a8 boxes */ 335603b705cfSriastradh if (!(dst->format == PICT_a8r8g8b8 || dst->format == PICT_x8r8g8b8)) { 335703b705cfSriastradh DBG(("%s: fallback -- can not perform operation in place, unhanbled format %08lx\n", 335803b705cfSriastradh __FUNCTION__, (long)dst->format)); 335903b705cfSriastradh 336003b705cfSriastradh goto pixman; 336103b705cfSriastradh } 336203b705cfSriastradh 336303b705cfSriastradh pixmap = get_drawable_pixmap(dst->pDrawable); 336403b705cfSriastradh get_drawable_deltas(dst->pDrawable, pixmap, &dx, &dy); 336503b705cfSriastradh 336603b705cfSriastradh if (op == PictOpOver && (color >> 24) == 0xff) 336703b705cfSriastradh op = PictOpSrc; 336803b705cfSriastradh if (op == PictOpOver || op == PictOpAdd) { 336903b705cfSriastradh struct sna_pixmap *priv = sna_pixmap(pixmap); 337003b705cfSriastradh if (priv && priv->clear && priv->clear_color == 0) 337103b705cfSriastradh op = PictOpSrc; 337203b705cfSriastradh } 337303b705cfSriastradh 337403b705cfSriastradh switch (op) { 337503b705cfSriastradh case PictOpSrc: 337603b705cfSriastradh break; 337703b705cfSriastradh default: 337803b705cfSriastradh DBG(("%s: fallback -- can not perform op [%d] in place\n", 337903b705cfSriastradh __FUNCTION__, op)); 338003b705cfSriastradh goto pixman; 338103b705cfSriastradh } 338203b705cfSriastradh 338303b705cfSriastradh DBG(("%s: inplace operation on argb32 destination x %d\n", 338403b705cfSriastradh __FUNCTION__, n)); 338503b705cfSriastradh do { 338603b705cfSriastradh RegionRec clip; 338703b705cfSriastradh BoxPtr extents; 338803b705cfSriastradh int count; 338903b705cfSriastradh 339003b705cfSriastradh clip.extents.x1 = pixman_fixed_to_int(t->left.p1.x); 339103b705cfSriastradh clip.extents.x2 = pixman_fixed_to_int(t->right.p1.x + pixman_fixed_1_minus_e); 339203b705cfSriastradh clip.extents.y1 = pixman_fixed_to_int(t->top); 339303b705cfSriastradh clip.extents.y2 = pixman_fixed_to_int(t->bottom + pixman_fixed_1_minus_e); 339403b705cfSriastradh clip.data = NULL; 339503b705cfSriastradh 339603b705cfSriastradh if (!sna_compute_composite_region(&clip, 339703b705cfSriastradh NULL, NULL, dst, 339803b705cfSriastradh 0, 0, 339903b705cfSriastradh 0, 0, 340003b705cfSriastradh clip.extents.x1, clip.extents.y1, 340103b705cfSriastradh clip.extents.x2 - clip.extents.x1, 340203b705cfSriastradh clip.extents.y2 - clip.extents.y1)) 340303b705cfSriastradh continue; 340403b705cfSriastradh 340503b705cfSriastradh if (!sna_drawable_move_region_to_cpu(dst->pDrawable, &clip, 340603b705cfSriastradh MOVE_WRITE | MOVE_READ)) { 340703b705cfSriastradh RegionUninit(&clip); 340803b705cfSriastradh continue; 340903b705cfSriastradh } 341003b705cfSriastradh 341103b705cfSriastradh RegionTranslate(&clip, dx, dy); 341203b705cfSriastradh count = REGION_NUM_RECTS(&clip); 341303b705cfSriastradh extents = REGION_RECTS(&clip); 341403b705cfSriastradh while (count--) { 341503b705cfSriastradh int16_t y1 = dy + pixman_fixed_to_int(t->top); 341603b705cfSriastradh uint16_t fy1 = pixman_fixed_frac(t->top); 341703b705cfSriastradh int16_t y2 = dy + pixman_fixed_to_int(t->bottom); 341803b705cfSriastradh uint16_t fy2 = pixman_fixed_frac(t->bottom); 341903b705cfSriastradh 342003b705cfSriastradh DBG(("%s: t=(%d, %d), (%d, %d), extents (%d, %d), (%d, %d)\n", 342103b705cfSriastradh __FUNCTION__, 342203b705cfSriastradh pixman_fixed_to_int(t->left.p1.x), 342303b705cfSriastradh pixman_fixed_to_int(t->top), 342403b705cfSriastradh pixman_fixed_to_int(t->right.p2.x), 342503b705cfSriastradh pixman_fixed_to_int(t->bottom), 342603b705cfSriastradh extents->x1, extents->y1, 342703b705cfSriastradh extents->x2, extents->y2)); 342803b705cfSriastradh 342903b705cfSriastradh if (y1 < extents->y1) 343003b705cfSriastradh y1 = extents->y1, fy1 = 0; 343103b705cfSriastradh if (y2 >= extents->y2) 343203b705cfSriastradh y2 = extents->y2, fy2 = 0; 343303b705cfSriastradh 343403b705cfSriastradh if (y1 < y2) { 343503b705cfSriastradh if (fy1) { 343603b705cfSriastradh lerp32_unaligned_box_row(pixmap, color, extents, 343703b705cfSriastradh t, dx, y1, 1, 343803b705cfSriastradh SAMPLES_Y - grid_coverage(SAMPLES_Y, fy1)); 343903b705cfSriastradh y1++; 344003b705cfSriastradh } 344103b705cfSriastradh 344203b705cfSriastradh if (y2 > y1) 344303b705cfSriastradh lerp32_unaligned_box_row(pixmap, color, extents, 344403b705cfSriastradh t, dx, y1, y2 - y1, 344503b705cfSriastradh SAMPLES_Y); 344603b705cfSriastradh 344703b705cfSriastradh if (fy2) 344803b705cfSriastradh lerp32_unaligned_box_row(pixmap, color, extents, 344903b705cfSriastradh t, dx, y2, 1, 345003b705cfSriastradh grid_coverage(SAMPLES_Y, fy2)); 345103b705cfSriastradh } else if (y1 == y2 && fy2 > fy1) { 345203b705cfSriastradh lerp32_unaligned_box_row(pixmap, color, extents, 345303b705cfSriastradh t, dx, y1, 1, 345403b705cfSriastradh grid_coverage(SAMPLES_Y, fy2) - grid_coverage(SAMPLES_Y, fy1)); 345503b705cfSriastradh } 345603b705cfSriastradh extents++; 345703b705cfSriastradh } 345803b705cfSriastradh 345903b705cfSriastradh RegionUninit(&clip); 346003b705cfSriastradh } while (--n && t++); 346103b705cfSriastradh 346203b705cfSriastradh return true; 346303b705cfSriastradh 346403b705cfSriastradhpixman: 346503b705cfSriastradh do { 346603b705cfSriastradh struct pixman_inplace pi; 346703b705cfSriastradh RegionRec clip; 346803b705cfSriastradh BoxPtr extents; 346903b705cfSriastradh int count; 347003b705cfSriastradh 347103b705cfSriastradh clip.extents.x1 = pixman_fixed_to_int(t->left.p1.x); 347203b705cfSriastradh clip.extents.x2 = pixman_fixed_to_int(t->right.p1.x + pixman_fixed_1_minus_e); 347303b705cfSriastradh clip.extents.y1 = pixman_fixed_to_int(t->top); 347403b705cfSriastradh clip.extents.y2 = pixman_fixed_to_int(t->bottom + pixman_fixed_1_minus_e); 347503b705cfSriastradh clip.data = NULL; 347603b705cfSriastradh 347703b705cfSriastradh if (!sna_compute_composite_region(&clip, 347803b705cfSriastradh NULL, NULL, dst, 347903b705cfSriastradh 0, 0, 348003b705cfSriastradh 0, 0, 348103b705cfSriastradh clip.extents.x1, clip.extents.y1, 348203b705cfSriastradh clip.extents.x2 - clip.extents.x1, 348303b705cfSriastradh clip.extents.y2 - clip.extents.y1)) 348403b705cfSriastradh continue; 348503b705cfSriastradh 348603b705cfSriastradh if (!sna_drawable_move_region_to_cpu(dst->pDrawable, &clip, 348703b705cfSriastradh MOVE_WRITE | MOVE_READ)) { 348803b705cfSriastradh RegionUninit(&clip); 348903b705cfSriastradh continue; 349003b705cfSriastradh } 349103b705cfSriastradh 349203b705cfSriastradh pi.image = image_from_pict(dst, false, &pi.dx, &pi.dy); 349303b705cfSriastradh pi.source = pixman_image_create_bits(PIXMAN_a8r8g8b8, 1, 1, NULL, 0); 349403b705cfSriastradh pixman_image_set_repeat(pi.source, PIXMAN_REPEAT_NORMAL); 349503b705cfSriastradh pi.bits = pixman_image_get_data(pi.source); 349603b705cfSriastradh pi.color = color; 349703b705cfSriastradh pi.op = op; 349803b705cfSriastradh 349903b705cfSriastradh count = REGION_NUM_RECTS(&clip); 350003b705cfSriastradh extents = REGION_RECTS(&clip); 350103b705cfSriastradh while (count--) { 350203b705cfSriastradh int16_t y1 = pixman_fixed_to_int(t->top); 350303b705cfSriastradh uint16_t fy1 = pixman_fixed_frac(t->top); 350403b705cfSriastradh int16_t y2 = pixman_fixed_to_int(t->bottom); 350503b705cfSriastradh uint16_t fy2 = pixman_fixed_frac(t->bottom); 350603b705cfSriastradh 350703b705cfSriastradh if (y1 < extents->y1) 350803b705cfSriastradh y1 = extents->y1, fy1 = 0; 350903b705cfSriastradh if (y2 >= extents->y2) 351003b705cfSriastradh y2 = extents->y2, fy2 = 0; 351103b705cfSriastradh if (y1 < y2) { 351203b705cfSriastradh if (fy1) { 351303b705cfSriastradh pixsolid_unaligned_box_row(&pi, extents, t, y1, 1, 351403b705cfSriastradh SAMPLES_Y - grid_coverage(SAMPLES_Y, fy1)); 351503b705cfSriastradh y1++; 351603b705cfSriastradh } 351703b705cfSriastradh 351803b705cfSriastradh if (y2 > y1) 351903b705cfSriastradh pixsolid_unaligned_box_row(&pi, extents, t, y1, y2 - y1, 352003b705cfSriastradh SAMPLES_Y); 352103b705cfSriastradh 352203b705cfSriastradh if (fy2) 352303b705cfSriastradh pixsolid_unaligned_box_row(&pi, extents, t, y2, 1, 352403b705cfSriastradh grid_coverage(SAMPLES_Y, fy2)); 352503b705cfSriastradh } else if (y1 == y2 && fy2 > fy1) { 352603b705cfSriastradh pixsolid_unaligned_box_row(&pi, extents, t, y1, 1, 352703b705cfSriastradh grid_coverage(SAMPLES_Y, fy2) - grid_coverage(SAMPLES_Y, fy1)); 352803b705cfSriastradh } 352903b705cfSriastradh extents++; 353003b705cfSriastradh } 353103b705cfSriastradh 353203b705cfSriastradh RegionUninit(&clip); 353303b705cfSriastradh pixman_image_unref(pi.image); 353403b705cfSriastradh pixman_image_unref(pi.source); 353503b705cfSriastradh } while (--n && t++); 353603b705cfSriastradh return true; 353703b705cfSriastradh} 353803b705cfSriastradh 353903b705cfSriastradhinline static void 354003b705cfSriastradhpixmask_opacity(struct pixman_inplace *pi, 354103b705cfSriastradh int16_t x, int16_t w, 354203b705cfSriastradh int16_t y, int16_t h, 354303b705cfSriastradh uint8_t opacity) 354403b705cfSriastradh{ 354503b705cfSriastradh if (opacity == 0xff) { 354603b705cfSriastradh pixman_image_composite(pi->op, pi->source, NULL, pi->image, 354703b705cfSriastradh pi->sx + x, pi->sy + y, 354803b705cfSriastradh 0, 0, 354903b705cfSriastradh pi->dx + x, pi->dy + y, 355003b705cfSriastradh w, h); 355103b705cfSriastradh } else { 355203b705cfSriastradh *pi->bits = opacity; 355303b705cfSriastradh pixman_image_composite(pi->op, pi->source, pi->mask, pi->image, 355403b705cfSriastradh pi->sx + x, pi->sy + y, 355503b705cfSriastradh 0, 0, 355603b705cfSriastradh pi->dx + x, pi->dy + y, 355703b705cfSriastradh w, h); 355803b705cfSriastradh } 355903b705cfSriastradh} 356003b705cfSriastradh 356103b705cfSriastradhstatic void 356203b705cfSriastradhpixmask_unaligned_box_row(struct pixman_inplace *pi, 356303b705cfSriastradh const BoxRec *extents, 356403b705cfSriastradh const xTrapezoid *trap, 356503b705cfSriastradh int16_t y, int16_t h, 356603b705cfSriastradh uint8_t covered) 356703b705cfSriastradh{ 356803b705cfSriastradh int16_t x1 = pixman_fixed_to_int(trap->left.p1.x); 356903b705cfSriastradh uint16_t fx1 = grid_coverage(SAMPLES_X, trap->left.p1.x); 357003b705cfSriastradh int16_t x2 = pixman_fixed_to_int(trap->right.p1.x); 357103b705cfSriastradh uint16_t fx2 = grid_coverage(SAMPLES_X, trap->right.p1.x); 357203b705cfSriastradh 357303b705cfSriastradh if (x1 < extents->x1) 357403b705cfSriastradh x1 = extents->x1, fx1 = 0; 357503b705cfSriastradh if (x2 >= extents->x2) 357603b705cfSriastradh x2 = extents->x2, fx2 = 0; 357703b705cfSriastradh 357803b705cfSriastradh if (x1 < x2) { 357903b705cfSriastradh if (fx1) { 358003b705cfSriastradh pixmask_opacity(pi, x1, 1, y, h, 358103b705cfSriastradh covered * (SAMPLES_X - fx1)); 358203b705cfSriastradh x1++; 358303b705cfSriastradh } 358403b705cfSriastradh 358503b705cfSriastradh if (x2 > x1) 358603b705cfSriastradh pixmask_opacity(pi, x1, x2-x1, y, h, covered*SAMPLES_X); 358703b705cfSriastradh 358803b705cfSriastradh if (fx2) 358903b705cfSriastradh pixmask_opacity(pi, x2, 1, y, h, covered * fx2); 359003b705cfSriastradh } else if (x1 == x2 && fx2 > fx1) { 359103b705cfSriastradh pixmask_opacity(pi, x1, 1, y, h, covered * (fx2 - fx1)); 359203b705cfSriastradh } 359303b705cfSriastradh} 359403b705cfSriastradh 359503b705cfSriastradhstruct rectilinear_inplace_thread { 359603b705cfSriastradh pixman_image_t *dst, *src; 359703b705cfSriastradh const RegionRec *clip; 359803b705cfSriastradh const xTrapezoid *trap; 359903b705cfSriastradh int dx, dy, sx, sy; 360003b705cfSriastradh int y1, y2; 360103b705cfSriastradh CARD8 op; 360203b705cfSriastradh}; 360303b705cfSriastradh 360403b705cfSriastradhstatic void rectilinear_inplace_thread(void *arg) 360503b705cfSriastradh{ 360603b705cfSriastradh struct rectilinear_inplace_thread *thread = arg; 360703b705cfSriastradh const xTrapezoid *t = thread->trap; 360803b705cfSriastradh struct pixman_inplace pi; 360903b705cfSriastradh const BoxRec *extents; 361003b705cfSriastradh int count; 361103b705cfSriastradh 361203b705cfSriastradh pi.image = thread->dst; 361303b705cfSriastradh pi.dx = thread->dx; 361403b705cfSriastradh pi.dy = thread->dy; 361503b705cfSriastradh 361603b705cfSriastradh pi.source = thread->src; 361703b705cfSriastradh pi.sx = thread->sx; 361803b705cfSriastradh pi.sy = thread->sy; 361903b705cfSriastradh 362003b705cfSriastradh pi.mask = pixman_image_create_bits(PIXMAN_a8, 1, 1, &pi.color, 4); 362103b705cfSriastradh pixman_image_set_repeat(pi.mask, PIXMAN_REPEAT_NORMAL); 362203b705cfSriastradh pi.bits = pixman_image_get_data(pi.mask); 362303b705cfSriastradh pi.op = thread->op; 362403b705cfSriastradh 362503b705cfSriastradh count = region_count(thread->clip); 362603b705cfSriastradh extents = region_boxes(thread->clip); 362703b705cfSriastradh while (count--) { 362803b705cfSriastradh int16_t y1 = pixman_fixed_to_int(t->top); 362903b705cfSriastradh uint16_t fy1 = pixman_fixed_frac(t->top); 363003b705cfSriastradh int16_t y2 = pixman_fixed_to_int(t->bottom); 363103b705cfSriastradh uint16_t fy2 = pixman_fixed_frac(t->bottom); 363203b705cfSriastradh 363303b705cfSriastradh if (y1 < MAX(thread->y1, extents->y1)) 363403b705cfSriastradh y1 = MAX(thread->y1, extents->y1), fy1 = 0; 363503b705cfSriastradh if (y2 > MIN(thread->y2, extents->y2)) 363603b705cfSriastradh y2 = MIN(thread->y2, extents->y2), fy2 = 0; 363703b705cfSriastradh if (y1 < y2) { 363803b705cfSriastradh if (fy1) { 363903b705cfSriastradh pixmask_unaligned_box_row(&pi, extents, t, y1, 1, 364003b705cfSriastradh SAMPLES_Y - grid_coverage(SAMPLES_Y, fy1)); 364103b705cfSriastradh y1++; 364203b705cfSriastradh } 364303b705cfSriastradh 364403b705cfSriastradh if (y2 > y1) 364503b705cfSriastradh pixmask_unaligned_box_row(&pi, extents, t, y1, y2 - y1, 364603b705cfSriastradh SAMPLES_Y); 364703b705cfSriastradh 364803b705cfSriastradh if (fy2) 364903b705cfSriastradh pixmask_unaligned_box_row(&pi, extents, t, y2, 1, 365003b705cfSriastradh grid_coverage(SAMPLES_Y, fy2)); 365103b705cfSriastradh } else if (y1 == y2 && fy2 > fy1) { 365203b705cfSriastradh pixmask_unaligned_box_row(&pi, extents, t, y1, 1, 365303b705cfSriastradh grid_coverage(SAMPLES_Y, fy2) - grid_coverage(SAMPLES_Y, fy1)); 365403b705cfSriastradh } 365503b705cfSriastradh extents++; 365603b705cfSriastradh } 365703b705cfSriastradh 365803b705cfSriastradh pixman_image_unref(pi.mask); 365903b705cfSriastradh} 366003b705cfSriastradh 366103b705cfSriastradhstatic bool 366203b705cfSriastradhcomposite_unaligned_boxes_inplace(struct sna *sna, 366303b705cfSriastradh CARD8 op, 366403b705cfSriastradh PicturePtr src, int16_t src_x, int16_t src_y, 366503b705cfSriastradh PicturePtr dst, int n, const xTrapezoid *t, 366603b705cfSriastradh bool force_fallback) 366703b705cfSriastradh{ 366803b705cfSriastradh if (!force_fallback && 366903b705cfSriastradh (is_gpu(sna, dst->pDrawable, PREFER_GPU_SPANS) || 367003b705cfSriastradh picture_is_gpu(sna, src))) { 367103b705cfSriastradh DBG(("%s: fallback -- not forcing\n", __FUNCTION__)); 367203b705cfSriastradh return false; 367303b705cfSriastradh } 367403b705cfSriastradh 367503b705cfSriastradh DBG(("%s\n", __FUNCTION__)); 367603b705cfSriastradh 367703b705cfSriastradh src_x -= pixman_fixed_to_int(t[0].left.p1.x); 367803b705cfSriastradh src_y -= pixman_fixed_to_int(t[0].left.p1.y); 367903b705cfSriastradh do { 368003b705cfSriastradh RegionRec clip; 368103b705cfSriastradh BoxPtr extents; 368203b705cfSriastradh int count; 368303b705cfSriastradh int num_threads; 368403b705cfSriastradh 368503b705cfSriastradh clip.extents.x1 = pixman_fixed_to_int(t->left.p1.x); 368603b705cfSriastradh clip.extents.x2 = pixman_fixed_to_int(t->right.p1.x + pixman_fixed_1_minus_e); 368703b705cfSriastradh clip.extents.y1 = pixman_fixed_to_int(t->top); 368803b705cfSriastradh clip.extents.y2 = pixman_fixed_to_int(t->bottom + pixman_fixed_1_minus_e); 368903b705cfSriastradh clip.data = NULL; 369003b705cfSriastradh 369103b705cfSriastradh if (!sna_compute_composite_region(&clip, 369203b705cfSriastradh src, NULL, dst, 369303b705cfSriastradh clip.extents.x1 + src_x, 369403b705cfSriastradh clip.extents.y1 + src_y, 369503b705cfSriastradh 0, 0, 369603b705cfSriastradh clip.extents.x1, clip.extents.y1, 369703b705cfSriastradh clip.extents.x2 - clip.extents.x1, 369803b705cfSriastradh clip.extents.y2 - clip.extents.y1)) 369903b705cfSriastradh continue; 370003b705cfSriastradh 370103b705cfSriastradh if (!sna_drawable_move_region_to_cpu(dst->pDrawable, &clip, 370203b705cfSriastradh MOVE_WRITE | MOVE_READ)) { 370303b705cfSriastradh RegionUninit(&clip); 370403b705cfSriastradh continue; 370503b705cfSriastradh } 370603b705cfSriastradh 370703b705cfSriastradh if (src->pDrawable) { 370803b705cfSriastradh if (!sna_drawable_move_to_cpu(src->pDrawable, 370903b705cfSriastradh MOVE_READ)) { 371003b705cfSriastradh RegionUninit(&clip); 371103b705cfSriastradh continue; 371203b705cfSriastradh } 371303b705cfSriastradh if (src->alphaMap) { 371403b705cfSriastradh if (!sna_drawable_move_to_cpu(src->alphaMap->pDrawable, 371503b705cfSriastradh MOVE_READ)) { 371603b705cfSriastradh RegionUninit(&clip); 371703b705cfSriastradh continue; 371803b705cfSriastradh } 371903b705cfSriastradh } 372003b705cfSriastradh } 372103b705cfSriastradh 372203b705cfSriastradh num_threads = sna_use_threads(clip.extents.x2 - clip.extents.x1, 372303b705cfSriastradh clip.extents.y2 - clip.extents.y1, 372403b705cfSriastradh 32); 372503b705cfSriastradh if (num_threads == 1) { 372603b705cfSriastradh struct pixman_inplace pi; 372703b705cfSriastradh 372803b705cfSriastradh pi.image = image_from_pict(dst, false, &pi.dx, &pi.dy); 372903b705cfSriastradh pi.source = image_from_pict(src, false, &pi.sx, &pi.sy); 373003b705cfSriastradh pi.sx += src_x; 373103b705cfSriastradh pi.sy += src_y; 373203b705cfSriastradh pi.mask = pixman_image_create_bits(PIXMAN_a8, 1, 1, &pi.color, 4); 373303b705cfSriastradh pixman_image_set_repeat(pi.mask, PIXMAN_REPEAT_NORMAL); 373403b705cfSriastradh pi.bits = pixman_image_get_data(pi.mask); 373503b705cfSriastradh pi.op = op; 373603b705cfSriastradh 373703b705cfSriastradh count = REGION_NUM_RECTS(&clip); 373803b705cfSriastradh extents = REGION_RECTS(&clip); 373903b705cfSriastradh while (count--) { 374003b705cfSriastradh int16_t y1 = pixman_fixed_to_int(t->top); 374103b705cfSriastradh uint16_t fy1 = pixman_fixed_frac(t->top); 374203b705cfSriastradh int16_t y2 = pixman_fixed_to_int(t->bottom); 374303b705cfSriastradh uint16_t fy2 = pixman_fixed_frac(t->bottom); 374403b705cfSriastradh 374503b705cfSriastradh if (y1 < extents->y1) 374603b705cfSriastradh y1 = extents->y1, fy1 = 0; 374703b705cfSriastradh if (y2 > extents->y2) 374803b705cfSriastradh y2 = extents->y2, fy2 = 0; 374903b705cfSriastradh if (y1 < y2) { 375003b705cfSriastradh if (fy1) { 375103b705cfSriastradh pixmask_unaligned_box_row(&pi, extents, t, y1, 1, 375203b705cfSriastradh SAMPLES_Y - grid_coverage(SAMPLES_Y, fy1)); 375303b705cfSriastradh y1++; 375403b705cfSriastradh } 375503b705cfSriastradh 375603b705cfSriastradh if (y2 > y1) 375703b705cfSriastradh pixmask_unaligned_box_row(&pi, extents, t, y1, y2 - y1, 375803b705cfSriastradh SAMPLES_Y); 375903b705cfSriastradh 376003b705cfSriastradh if (fy2) 376103b705cfSriastradh pixmask_unaligned_box_row(&pi, extents, t, y2, 1, 376203b705cfSriastradh grid_coverage(SAMPLES_Y, fy2)); 376303b705cfSriastradh } else if (y1 == y2 && fy2 > fy1) { 376403b705cfSriastradh pixmask_unaligned_box_row(&pi, extents, t, y1, 1, 376503b705cfSriastradh grid_coverage(SAMPLES_Y, fy2) - grid_coverage(SAMPLES_Y, fy1)); 376603b705cfSriastradh } 376703b705cfSriastradh extents++; 376803b705cfSriastradh } 376903b705cfSriastradh 377003b705cfSriastradh pixman_image_unref(pi.image); 377103b705cfSriastradh pixman_image_unref(pi.source); 377203b705cfSriastradh pixman_image_unref(pi.mask); 377303b705cfSriastradh } else { 377403b705cfSriastradh struct rectilinear_inplace_thread thread[num_threads]; 377503b705cfSriastradh int i, y, dy; 377603b705cfSriastradh 377703b705cfSriastradh 377803b705cfSriastradh thread[0].trap = t; 377903b705cfSriastradh thread[0].dst = image_from_pict(dst, false, &thread[0].dx, &thread[0].dy); 378003b705cfSriastradh thread[0].src = image_from_pict(src, false, &thread[0].sx, &thread[0].sy); 378103b705cfSriastradh thread[0].sx += src_x; 378203b705cfSriastradh thread[0].sy += src_y; 378303b705cfSriastradh 378403b705cfSriastradh thread[0].clip = &clip; 378503b705cfSriastradh thread[0].op = op; 378603b705cfSriastradh 378703b705cfSriastradh y = clip.extents.y1; 378803b705cfSriastradh dy = (clip.extents.y2 - clip.extents.y1 + num_threads - 1) / num_threads; 378903b705cfSriastradh 379003b705cfSriastradh for (i = 1; i < num_threads; i++) { 379103b705cfSriastradh thread[i] = thread[0]; 379203b705cfSriastradh thread[i].y1 = y; 379303b705cfSriastradh thread[i].y2 = y += dy; 379403b705cfSriastradh sna_threads_run(rectilinear_inplace_thread, &thread[i]); 379503b705cfSriastradh } 379603b705cfSriastradh 379703b705cfSriastradh thread[0].y1 = y; 379803b705cfSriastradh thread[0].y2 = clip.extents.y2; 379903b705cfSriastradh rectilinear_inplace_thread(&thread[0]); 380003b705cfSriastradh 380103b705cfSriastradh sna_threads_wait(); 380203b705cfSriastradh 380303b705cfSriastradh pixman_image_unref(thread[0].dst); 380403b705cfSriastradh pixman_image_unref(thread[0].src); 380503b705cfSriastradh } 380603b705cfSriastradh 380703b705cfSriastradh RegionUninit(&clip); 380803b705cfSriastradh } while (--n && t++); 380903b705cfSriastradh 381003b705cfSriastradh return true; 381103b705cfSriastradh} 381203b705cfSriastradh 381303b705cfSriastradhstatic bool 381403b705cfSriastradhcomposite_unaligned_boxes_fallback(struct sna *sna, 381503b705cfSriastradh CARD8 op, 381603b705cfSriastradh PicturePtr src, 381703b705cfSriastradh PicturePtr dst, 381803b705cfSriastradh INT16 src_x, INT16 src_y, 381903b705cfSriastradh int ntrap, const xTrapezoid *traps, 382003b705cfSriastradh bool force_fallback) 382103b705cfSriastradh{ 382203b705cfSriastradh ScreenPtr screen = dst->pDrawable->pScreen; 382303b705cfSriastradh uint32_t color; 382403b705cfSriastradh int16_t dst_x, dst_y; 382503b705cfSriastradh int16_t dx, dy; 382603b705cfSriastradh int n; 382703b705cfSriastradh 382803b705cfSriastradh if (sna_picture_is_solid(src, &color) && 382903b705cfSriastradh composite_unaligned_boxes_inplace__solid(sna, op, color, dst, 383003b705cfSriastradh ntrap, traps, 383103b705cfSriastradh force_fallback)) 383203b705cfSriastradh return true; 383303b705cfSriastradh 383403b705cfSriastradh if (composite_unaligned_boxes_inplace(sna, op, src, src_x, src_y, 383503b705cfSriastradh dst, ntrap, traps, 383603b705cfSriastradh force_fallback)) 383703b705cfSriastradh return true; 383803b705cfSriastradh 383903b705cfSriastradh trapezoid_origin(&traps[0].left, &dst_x, &dst_y); 384003b705cfSriastradh dx = dst->pDrawable->x; 384103b705cfSriastradh dy = dst->pDrawable->y; 384203b705cfSriastradh for (n = 0; n < ntrap; n++) { 384303b705cfSriastradh const xTrapezoid *t = &traps[n]; 384403b705cfSriastradh PixmapPtr scratch; 384503b705cfSriastradh PicturePtr mask; 384603b705cfSriastradh BoxRec extents; 384703b705cfSriastradh int error; 384803b705cfSriastradh int y1, y2; 384903b705cfSriastradh 385003b705cfSriastradh extents.x1 = pixman_fixed_to_int(t->left.p1.x); 385103b705cfSriastradh extents.x2 = pixman_fixed_to_int(t->right.p1.x + pixman_fixed_1_minus_e); 385203b705cfSriastradh extents.y1 = pixman_fixed_to_int(t->top); 385303b705cfSriastradh extents.y2 = pixman_fixed_to_int(t->bottom + pixman_fixed_1_minus_e); 385403b705cfSriastradh 385503b705cfSriastradh if (!sna_compute_composite_extents(&extents, 385603b705cfSriastradh src, NULL, dst, 385703b705cfSriastradh src_x, src_y, 385803b705cfSriastradh 0, 0, 385903b705cfSriastradh extents.x1, extents.y1, 386003b705cfSriastradh extents.x2 - extents.x1, 386103b705cfSriastradh extents.y2 - extents.y1)) 386203b705cfSriastradh continue; 386303b705cfSriastradh 386403b705cfSriastradh if (force_fallback) 386503b705cfSriastradh scratch = sna_pixmap_create_unattached(screen, 386603b705cfSriastradh extents.x2 - extents.x1, 386703b705cfSriastradh extents.y2 - extents.y1, 386803b705cfSriastradh 8); 386903b705cfSriastradh else 387003b705cfSriastradh scratch = sna_pixmap_create_upload(screen, 387103b705cfSriastradh extents.x2 - extents.x1, 387203b705cfSriastradh extents.y2 - extents.y1, 387303b705cfSriastradh 8, KGEM_BUFFER_WRITE_INPLACE); 387403b705cfSriastradh if (!scratch) 387503b705cfSriastradh continue; 387603b705cfSriastradh 387703b705cfSriastradh memset(scratch->devPrivate.ptr, 0xff, 387803b705cfSriastradh scratch->devKind * (extents.y2 - extents.y1)); 387903b705cfSriastradh 388003b705cfSriastradh extents.x1 -= dx; 388103b705cfSriastradh extents.x2 -= dx; 388203b705cfSriastradh extents.y1 -= dy; 388303b705cfSriastradh extents.y2 -= dy; 388403b705cfSriastradh 388503b705cfSriastradh y1 = pixman_fixed_to_int(t->top) - extents.y1; 388603b705cfSriastradh y2 = pixman_fixed_to_int(t->bottom) - extents.y1; 388703b705cfSriastradh 388803b705cfSriastradh if (y1 == y2) { 388903b705cfSriastradh blt_unaligned_box_row(scratch, &extents, t, y1, y1 + 1, 389003b705cfSriastradh grid_coverage(SAMPLES_Y, t->bottom) - grid_coverage(SAMPLES_Y, t->top)); 389103b705cfSriastradh } else { 389203b705cfSriastradh if (pixman_fixed_frac(t->top)) { 389303b705cfSriastradh blt_unaligned_box_row(scratch, &extents, t, y1, y1 + 1, 389403b705cfSriastradh SAMPLES_Y - grid_coverage(SAMPLES_Y, t->top)); 389503b705cfSriastradh y1++; 389603b705cfSriastradh } 389703b705cfSriastradh 389803b705cfSriastradh if (y2 > y1) 389903b705cfSriastradh blt_unaligned_box_row(scratch, &extents, t, y1, y2, 390003b705cfSriastradh SAMPLES_Y); 390103b705cfSriastradh 390203b705cfSriastradh if (pixman_fixed_frac(t->bottom)) 390303b705cfSriastradh blt_unaligned_box_row(scratch, &extents, t, y2, y2+1, 390403b705cfSriastradh grid_coverage(SAMPLES_Y, t->bottom)); 390503b705cfSriastradh } 390603b705cfSriastradh 390703b705cfSriastradh mask = CreatePicture(0, &scratch->drawable, 390803b705cfSriastradh PictureMatchFormat(screen, 8, PICT_a8), 390903b705cfSriastradh 0, 0, serverClient, &error); 391003b705cfSriastradh if (mask) { 391103b705cfSriastradh CompositePicture(op, src, mask, dst, 391203b705cfSriastradh src_x + extents.x1 - dst_x, 391303b705cfSriastradh src_y + extents.y1 - dst_y, 391403b705cfSriastradh 0, 0, 391503b705cfSriastradh extents.x1, extents.y1, 391603b705cfSriastradh extents.x2 - extents.x1, 391703b705cfSriastradh extents.y2 - extents.y1); 391803b705cfSriastradh FreePicture(mask, 0); 391903b705cfSriastradh } 392003b705cfSriastradh sna_pixmap_destroy(scratch); 392103b705cfSriastradh } 392203b705cfSriastradh 392303b705cfSriastradh return true; 392403b705cfSriastradh} 392503b705cfSriastradh 392603b705cfSriastradhstatic bool 392703b705cfSriastradhcomposite_unaligned_boxes(struct sna *sna, 392803b705cfSriastradh CARD8 op, 392903b705cfSriastradh PicturePtr src, 393003b705cfSriastradh PicturePtr dst, 393103b705cfSriastradh PictFormatPtr maskFormat, 393203b705cfSriastradh INT16 src_x, INT16 src_y, 393303b705cfSriastradh int ntrap, const xTrapezoid *traps, 393403b705cfSriastradh bool force_fallback) 393503b705cfSriastradh{ 393603b705cfSriastradh BoxRec extents; 393703b705cfSriastradh struct sna_composite_spans_op tmp; 393803b705cfSriastradh struct sna_pixmap *priv; 393903b705cfSriastradh pixman_region16_t clip, *c; 394003b705cfSriastradh int16_t dst_x, dst_y; 394103b705cfSriastradh int dx, dy, n; 394203b705cfSriastradh 394303b705cfSriastradh if (NO_UNALIGNED_BOXES) 394403b705cfSriastradh return false; 394503b705cfSriastradh 394603b705cfSriastradh DBG(("%s: force_fallback=%d, mask=%x, n=%d, op=%d\n", 394703b705cfSriastradh __FUNCTION__, force_fallback, maskFormat ? (int)maskFormat->format : 0, ntrap, op)); 394803b705cfSriastradh 394903b705cfSriastradh /* need a span converter to handle overlapping traps */ 395003b705cfSriastradh if (ntrap > 1 && maskFormat) 395103b705cfSriastradh return false; 395203b705cfSriastradh 395303b705cfSriastradh if (force_fallback || 395403b705cfSriastradh !sna->render.check_composite_spans(sna, op, src, dst, 0, 0, 395503b705cfSriastradh COMPOSITE_SPANS_RECTILINEAR)) { 395603b705cfSriastradhfallback: 395703b705cfSriastradh return composite_unaligned_boxes_fallback(sna, op, src, dst, 395803b705cfSriastradh src_x, src_y, 395903b705cfSriastradh ntrap, traps, 396003b705cfSriastradh force_fallback); 396103b705cfSriastradh } 396203b705cfSriastradh 396303b705cfSriastradh trapezoid_origin(&traps[0].left, &dst_x, &dst_y); 396403b705cfSriastradh 396503b705cfSriastradh extents.x1 = pixman_fixed_to_int(traps[0].left.p1.x); 396603b705cfSriastradh extents.x2 = pixman_fixed_to_int(traps[0].right.p1.x + pixman_fixed_1_minus_e); 396703b705cfSriastradh extents.y1 = pixman_fixed_to_int(traps[0].top); 396803b705cfSriastradh extents.y2 = pixman_fixed_to_int(traps[0].bottom + pixman_fixed_1_minus_e); 396903b705cfSriastradh 397003b705cfSriastradh DBG(("%s: src=(%d, %d), dst=(%d, %d)\n", 397103b705cfSriastradh __FUNCTION__, src_x, src_y, dst_x, dst_y)); 397203b705cfSriastradh 397303b705cfSriastradh for (n = 1; n < ntrap; n++) { 397403b705cfSriastradh int x1 = pixman_fixed_to_int(traps[n].left.p1.x); 397503b705cfSriastradh int x2 = pixman_fixed_to_int(traps[n].right.p1.x + pixman_fixed_1_minus_e); 397603b705cfSriastradh int y1 = pixman_fixed_to_int(traps[n].top); 397703b705cfSriastradh int y2 = pixman_fixed_to_int(traps[n].bottom + pixman_fixed_1_minus_e); 397803b705cfSriastradh 397903b705cfSriastradh if (x1 < extents.x1) 398003b705cfSriastradh extents.x1 = x1; 398103b705cfSriastradh if (x2 > extents.x2) 398203b705cfSriastradh extents.x2 = x2; 398303b705cfSriastradh if (y1 < extents.y1) 398403b705cfSriastradh extents.y1 = y1; 398503b705cfSriastradh if (y2 > extents.y2) 398603b705cfSriastradh extents.y2 = y2; 398703b705cfSriastradh } 398803b705cfSriastradh 398903b705cfSriastradh DBG(("%s: extents (%d, %d), (%d, %d)\n", __FUNCTION__, 399003b705cfSriastradh extents.x1, extents.y1, extents.x2, extents.y2)); 399103b705cfSriastradh 399203b705cfSriastradh if (!sna_compute_composite_region(&clip, 399303b705cfSriastradh src, NULL, dst, 399403b705cfSriastradh src_x + extents.x1 - dst_x, 399503b705cfSriastradh src_y + extents.y1 - dst_y, 399603b705cfSriastradh 0, 0, 399703b705cfSriastradh extents.x1, extents.y1, 399803b705cfSriastradh extents.x2 - extents.x1, 399903b705cfSriastradh extents.y2 - extents.y1)) { 400003b705cfSriastradh DBG(("%s: trapezoids do not intersect drawable clips\n", 400103b705cfSriastradh __FUNCTION__)) ; 400203b705cfSriastradh return true; 400303b705cfSriastradh } 400403b705cfSriastradh 400503b705cfSriastradh if (!sna->render.check_composite_spans(sna, op, src, dst, 400603b705cfSriastradh clip.extents.x2 - clip.extents.x1, 400703b705cfSriastradh clip.extents.y2 - clip.extents.y1, 400803b705cfSriastradh COMPOSITE_SPANS_RECTILINEAR)) { 400903b705cfSriastradh DBG(("%s: fallback -- composite spans not supported\n", 401003b705cfSriastradh __FUNCTION__)); 401103b705cfSriastradh goto fallback; 401203b705cfSriastradh } 401303b705cfSriastradh 401403b705cfSriastradh c = NULL; 401503b705cfSriastradh if (extents.x2 - extents.x1 > clip.extents.x2 - clip.extents.x1 || 401603b705cfSriastradh extents.y2 - extents.y1 > clip.extents.y2 - clip.extents.y1) { 401703b705cfSriastradh DBG(("%s: forcing clip\n", __FUNCTION__)); 401803b705cfSriastradh c = &clip; 401903b705cfSriastradh } 402003b705cfSriastradh 402103b705cfSriastradh extents = *RegionExtents(&clip); 402203b705cfSriastradh dx = dst->pDrawable->x; 402303b705cfSriastradh dy = dst->pDrawable->y; 402403b705cfSriastradh 402503b705cfSriastradh DBG(("%s: after clip -- extents (%d, %d), (%d, %d), delta=(%d, %d) src -> (%d, %d)\n", 402603b705cfSriastradh __FUNCTION__, 402703b705cfSriastradh extents.x1, extents.y1, 402803b705cfSriastradh extents.x2, extents.y2, 402903b705cfSriastradh dx, dy, 403003b705cfSriastradh src_x + extents.x1 - dst_x - dx, 403103b705cfSriastradh src_y + extents.y1 - dst_y - dy)); 403203b705cfSriastradh 403303b705cfSriastradh switch (op) { 403403b705cfSriastradh case PictOpAdd: 403503b705cfSriastradh case PictOpOver: 403603b705cfSriastradh priv = sna_pixmap(get_drawable_pixmap(dst->pDrawable)); 403703b705cfSriastradh assert(priv != NULL); 403803b705cfSriastradh if (priv->clear && priv->clear_color == 0) { 403903b705cfSriastradh DBG(("%s: converting %d to PictOpSrc\n", 404003b705cfSriastradh __FUNCTION__, op)); 404103b705cfSriastradh op = PictOpSrc; 404203b705cfSriastradh } 404303b705cfSriastradh break; 404403b705cfSriastradh case PictOpIn: 404503b705cfSriastradh priv = sna_pixmap(get_drawable_pixmap(dst->pDrawable)); 404603b705cfSriastradh assert(priv != NULL); 404703b705cfSriastradh if (priv->clear && priv->clear_color == 0) { 404803b705cfSriastradh DBG(("%s: clear destination using In, skipping\n", 404903b705cfSriastradh __FUNCTION__)); 405003b705cfSriastradh return true; 405103b705cfSriastradh } 405203b705cfSriastradh break; 405303b705cfSriastradh } 405403b705cfSriastradh 405503b705cfSriastradh if (!sna->render.composite_spans(sna, op, src, dst, 405603b705cfSriastradh src_x + extents.x1 - dst_x - dx, 405703b705cfSriastradh src_y + extents.y1 - dst_y - dy, 405803b705cfSriastradh extents.x1, extents.y1, 405903b705cfSriastradh extents.x2 - extents.x1, 406003b705cfSriastradh extents.y2 - extents.y1, 406103b705cfSriastradh COMPOSITE_SPANS_RECTILINEAR, 406203b705cfSriastradh memset(&tmp, 0, sizeof(tmp)))) { 406303b705cfSriastradh DBG(("%s: composite spans render op not supported\n", 406403b705cfSriastradh __FUNCTION__)); 406503b705cfSriastradh REGION_UNINIT(NULL, &clip); 406603b705cfSriastradh goto fallback; 406703b705cfSriastradh } 406803b705cfSriastradh 406903b705cfSriastradh for (n = 0; n < ntrap; n++) 407003b705cfSriastradh composite_unaligned_trap(sna, &tmp, &traps[n], dx, dy, c); 407103b705cfSriastradh tmp.done(sna, &tmp); 407203b705cfSriastradh REGION_UNINIT(NULL, &clip); 407303b705cfSriastradh return true; 407403b705cfSriastradh} 407503b705cfSriastradh 407603b705cfSriastradhstatic inline int pixman_fixed_to_grid (pixman_fixed_t v) 407703b705cfSriastradh{ 407803b705cfSriastradh return (v + ((1<<(16-FAST_SAMPLES_shift))-1)/2) >> (16 - FAST_SAMPLES_shift); 407903b705cfSriastradh} 408003b705cfSriastradh 408103b705cfSriastradhstatic inline bool 408203b705cfSriastradhproject_trapezoid_onto_grid(const xTrapezoid *in, 408303b705cfSriastradh int dx, int dy, 408403b705cfSriastradh xTrapezoid *out) 408503b705cfSriastradh{ 408603b705cfSriastradh __DBG(("%s: in: L:(%d, %d), (%d, %d); R:(%d, %d), (%d, %d), [%d, %d]\n", 408703b705cfSriastradh __FUNCTION__, 408803b705cfSriastradh in->left.p1.x, in->left.p1.y, in->left.p2.x, in->left.p2.y, 408903b705cfSriastradh in->right.p1.x, in->right.p1.y, in->right.p2.x, in->right.p2.y, 409003b705cfSriastradh in->top, in->bottom)); 409103b705cfSriastradh 409203b705cfSriastradh out->left.p1.x = dx + pixman_fixed_to_grid(in->left.p1.x); 409303b705cfSriastradh out->left.p1.y = dy + pixman_fixed_to_grid(in->left.p1.y); 409403b705cfSriastradh out->left.p2.x = dx + pixman_fixed_to_grid(in->left.p2.x); 409503b705cfSriastradh out->left.p2.y = dy + pixman_fixed_to_grid(in->left.p2.y); 409603b705cfSriastradh 409703b705cfSriastradh out->right.p1.x = dx + pixman_fixed_to_grid(in->right.p1.x); 409803b705cfSriastradh out->right.p1.y = dy + pixman_fixed_to_grid(in->right.p1.y); 409903b705cfSriastradh out->right.p2.x = dx + pixman_fixed_to_grid(in->right.p2.x); 410003b705cfSriastradh out->right.p2.y = dy + pixman_fixed_to_grid(in->right.p2.y); 410103b705cfSriastradh 410203b705cfSriastradh out->top = dy + pixman_fixed_to_grid(in->top); 410303b705cfSriastradh out->bottom = dy + pixman_fixed_to_grid(in->bottom); 410403b705cfSriastradh 410503b705cfSriastradh __DBG(("%s: out: L:(%d, %d), (%d, %d); R:(%d, %d), (%d, %d), [%d, %d]\n", 410603b705cfSriastradh __FUNCTION__, 410703b705cfSriastradh out->left.p1.x, out->left.p1.y, out->left.p2.x, out->left.p2.y, 410803b705cfSriastradh out->right.p1.x, out->right.p1.y, out->right.p2.x, out->right.p2.y, 410903b705cfSriastradh out->top, out->bottom)); 411003b705cfSriastradh 411103b705cfSriastradh return xTrapezoidValid(out); 411203b705cfSriastradh} 411303b705cfSriastradh 411403b705cfSriastradhstatic span_func_t 411503b705cfSriastradhchoose_span(struct sna_composite_spans_op *tmp, 411603b705cfSriastradh PicturePtr dst, 411703b705cfSriastradh PictFormatPtr maskFormat, 411803b705cfSriastradh RegionPtr clip) 411903b705cfSriastradh{ 412003b705cfSriastradh span_func_t span; 412103b705cfSriastradh 412203b705cfSriastradh if (is_mono(dst, maskFormat)) { 412303b705cfSriastradh /* XXX An imprecise approximation */ 412403b705cfSriastradh if (maskFormat && !operator_is_bounded(tmp->base.op)) { 412503b705cfSriastradh span = tor_blt_span_mono_unbounded; 412603b705cfSriastradh if (clip->data) 412703b705cfSriastradh span = tor_blt_span_mono_unbounded_clipped; 412803b705cfSriastradh } else { 412903b705cfSriastradh span = tor_blt_span_mono; 413003b705cfSriastradh if (clip->data) 413103b705cfSriastradh span = tor_blt_span_mono_clipped; 413203b705cfSriastradh } 413303b705cfSriastradh } else { 413403b705cfSriastradh if (clip->data) 413503b705cfSriastradh span = tor_blt_span_clipped; 413603b705cfSriastradh else if (tmp->base.damage == NULL) 413703b705cfSriastradh span = tor_blt_span__no_damage; 413803b705cfSriastradh else 413903b705cfSriastradh span = tor_blt_span; 414003b705cfSriastradh } 414103b705cfSriastradh 414203b705cfSriastradh return span; 414303b705cfSriastradh} 414403b705cfSriastradh 414503b705cfSriastradhstruct mono_span_thread { 414603b705cfSriastradh struct sna *sna; 414703b705cfSriastradh const xTrapezoid *traps; 414803b705cfSriastradh const struct sna_composite_op *op; 414903b705cfSriastradh RegionPtr clip; 415003b705cfSriastradh int ntrap; 415103b705cfSriastradh BoxRec extents; 415203b705cfSriastradh int dx, dy; 415303b705cfSriastradh}; 415403b705cfSriastradh 415503b705cfSriastradhstatic void 415603b705cfSriastradhmono_span_thread(void *arg) 415703b705cfSriastradh{ 415803b705cfSriastradh struct mono_span_thread *thread = arg; 415903b705cfSriastradh struct mono mono; 416003b705cfSriastradh struct mono_span_thread_boxes boxes; 416103b705cfSriastradh const xTrapezoid *t; 416203b705cfSriastradh int n; 416303b705cfSriastradh 416403b705cfSriastradh mono.sna = thread->sna; 416503b705cfSriastradh 416603b705cfSriastradh mono.clip.extents = thread->extents; 416703b705cfSriastradh mono.clip.data = NULL; 416803b705cfSriastradh if (thread->clip->data) { 416903b705cfSriastradh RegionIntersect(&mono.clip, &mono.clip, thread->clip); 417003b705cfSriastradh if (RegionNil(&mono.clip)) 417103b705cfSriastradh return; 417203b705cfSriastradh } 417303b705cfSriastradh 417403b705cfSriastradh boxes.op = thread->op; 417503b705cfSriastradh boxes.num_boxes = 0; 417603b705cfSriastradh mono.op.priv = &boxes; 417703b705cfSriastradh 417803b705cfSriastradh if (!mono_init(&mono, 2*thread->ntrap)) { 417903b705cfSriastradh RegionUninit(&mono.clip); 418003b705cfSriastradh return; 418103b705cfSriastradh } 418203b705cfSriastradh 418303b705cfSriastradh for (n = thread->ntrap, t = thread->traps; n--; t++) { 418403b705cfSriastradh if (!xTrapezoidValid(t)) 418503b705cfSriastradh continue; 418603b705cfSriastradh 418703b705cfSriastradh if (pixman_fixed_to_int(t->top) + thread->dy >= thread->extents.y2 || 418803b705cfSriastradh pixman_fixed_to_int(t->bottom) + thread->dy <= thread->extents.y1) 418903b705cfSriastradh continue; 419003b705cfSriastradh 419103b705cfSriastradh mono_add_line(&mono, thread->dx, thread->dy, 419203b705cfSriastradh t->top, t->bottom, 419303b705cfSriastradh &t->left.p1, &t->left.p2, 1); 419403b705cfSriastradh mono_add_line(&mono, thread->dx, thread->dy, 419503b705cfSriastradh t->top, t->bottom, 419603b705cfSriastradh &t->right.p1, &t->right.p2, -1); 419703b705cfSriastradh } 419803b705cfSriastradh 419903b705cfSriastradh if (mono.clip.data == NULL) 420003b705cfSriastradh mono.span = thread_mono_span; 420103b705cfSriastradh else 420203b705cfSriastradh mono.span = thread_mono_span_clipped; 420303b705cfSriastradh 420403b705cfSriastradh mono_render(&mono); 420503b705cfSriastradh mono_fini(&mono); 420603b705cfSriastradh 420703b705cfSriastradh if (boxes.num_boxes) 420803b705cfSriastradh thread->op->thread_boxes(thread->sna, thread->op, 420903b705cfSriastradh boxes.boxes, boxes.num_boxes); 421003b705cfSriastradh RegionUninit(&mono.clip); 421103b705cfSriastradh} 421203b705cfSriastradh 421303b705cfSriastradhstatic bool 421403b705cfSriastradhmono_trapezoids_span_converter(struct sna *sna, 421503b705cfSriastradh CARD8 op, PicturePtr src, PicturePtr dst, 421603b705cfSriastradh INT16 src_x, INT16 src_y, 421703b705cfSriastradh int ntrap, xTrapezoid *traps) 421803b705cfSriastradh{ 421903b705cfSriastradh struct mono mono; 422003b705cfSriastradh BoxRec extents; 422103b705cfSriastradh int16_t dst_x, dst_y; 422203b705cfSriastradh int16_t dx, dy; 422303b705cfSriastradh bool unbounded; 422403b705cfSriastradh int num_threads, n; 422503b705cfSriastradh 422603b705cfSriastradh if (NO_SCAN_CONVERTER) 422703b705cfSriastradh return false; 422803b705cfSriastradh 422903b705cfSriastradh trapezoid_origin(&traps[0].left, &dst_x, &dst_y); 423003b705cfSriastradh 423103b705cfSriastradh trapezoids_bounds(ntrap, traps, &extents); 423203b705cfSriastradh if (extents.y1 >= extents.y2 || extents.x1 >= extents.x2) 423303b705cfSriastradh return true; 423403b705cfSriastradh 423503b705cfSriastradh DBG(("%s: extents (%d, %d), (%d, %d)\n", 423603b705cfSriastradh __FUNCTION__, extents.x1, extents.y1, extents.x2, extents.y2)); 423703b705cfSriastradh 423803b705cfSriastradh if (!sna_compute_composite_region(&mono.clip, 423903b705cfSriastradh src, NULL, dst, 424003b705cfSriastradh src_x + extents.x1 - dst_x, 424103b705cfSriastradh src_y + extents.y1 - dst_y, 424203b705cfSriastradh 0, 0, 424303b705cfSriastradh extents.x1, extents.y1, 424403b705cfSriastradh extents.x2 - extents.x1, 424503b705cfSriastradh extents.y2 - extents.y1)) { 424603b705cfSriastradh DBG(("%s: trapezoids do not intersect drawable clips\n", 424703b705cfSriastradh __FUNCTION__)) ; 424803b705cfSriastradh return true; 424903b705cfSriastradh } 425003b705cfSriastradh 425103b705cfSriastradh dx = dst->pDrawable->x; 425203b705cfSriastradh dy = dst->pDrawable->y; 425303b705cfSriastradh 425403b705cfSriastradh DBG(("%s: after clip -- extents (%d, %d), (%d, %d), delta=(%d, %d) src -> (%d, %d)\n", 425503b705cfSriastradh __FUNCTION__, 425603b705cfSriastradh mono.clip.extents.x1, mono.clip.extents.y1, 425703b705cfSriastradh mono.clip.extents.x2, mono.clip.extents.y2, 425803b705cfSriastradh dx, dy, 425903b705cfSriastradh src_x + mono.clip.extents.x1 - dst_x - dx, 426003b705cfSriastradh src_y + mono.clip.extents.y1 - dst_y - dy)); 426103b705cfSriastradh 426203b705cfSriastradh unbounded = (!sna_drawable_is_clear(dst->pDrawable) && 426303b705cfSriastradh !operator_is_bounded(op)); 426403b705cfSriastradh 426503b705cfSriastradh mono.sna = sna; 426603b705cfSriastradh if (!mono.sna->render.composite(mono.sna, op, src, NULL, dst, 426703b705cfSriastradh src_x + mono.clip.extents.x1 - dst_x - dx, 426803b705cfSriastradh src_y + mono.clip.extents.y1 - dst_y - dy, 426903b705cfSriastradh 0, 0, 427003b705cfSriastradh mono.clip.extents.x1, mono.clip.extents.y1, 427103b705cfSriastradh mono.clip.extents.x2 - mono.clip.extents.x1, 427203b705cfSriastradh mono.clip.extents.y2 - mono.clip.extents.y1, 427303b705cfSriastradh memset(&mono.op, 0, sizeof(mono.op)))) 427403b705cfSriastradh return false; 427503b705cfSriastradh 427603b705cfSriastradh num_threads = 1; 427703b705cfSriastradh if (!NO_GPU_THREADS && 427803b705cfSriastradh mono.op.thread_boxes && 427903b705cfSriastradh mono.op.damage == NULL && 428003b705cfSriastradh !unbounded) 428103b705cfSriastradh num_threads = sna_use_threads(mono.clip.extents.x2 - mono.clip.extents.x1, 428203b705cfSriastradh mono.clip.extents.y2 - mono.clip.extents.y1, 428303b705cfSriastradh 32); 428403b705cfSriastradh if (num_threads > 1) { 428503b705cfSriastradh struct mono_span_thread threads[num_threads]; 428603b705cfSriastradh int y, h; 428703b705cfSriastradh 428803b705cfSriastradh DBG(("%s: using %d threads for mono span compositing %dx%d\n", 428903b705cfSriastradh __FUNCTION__, num_threads, 429003b705cfSriastradh mono.clip.extents.x2 - mono.clip.extents.x1, 429103b705cfSriastradh mono.clip.extents.y2 - mono.clip.extents.y1)); 429203b705cfSriastradh 429303b705cfSriastradh threads[0].sna = mono.sna; 429403b705cfSriastradh threads[0].op = &mono.op; 429503b705cfSriastradh threads[0].traps = traps; 429603b705cfSriastradh threads[0].ntrap = ntrap; 429703b705cfSriastradh threads[0].extents = mono.clip.extents; 429803b705cfSriastradh threads[0].clip = &mono.clip; 429903b705cfSriastradh threads[0].dx = dx; 430003b705cfSriastradh threads[0].dy = dy; 430103b705cfSriastradh 430203b705cfSriastradh y = extents.y1; 430303b705cfSriastradh h = extents.y2 - extents.y1; 430403b705cfSriastradh h = (h + num_threads - 1) / num_threads; 430503b705cfSriastradh 430603b705cfSriastradh for (n = 1; n < num_threads; n++) { 430703b705cfSriastradh threads[n] = threads[0]; 430803b705cfSriastradh threads[n].extents.y1 = y; 430903b705cfSriastradh threads[n].extents.y2 = y += h; 431003b705cfSriastradh 431103b705cfSriastradh sna_threads_run(mono_span_thread, &threads[n]); 431203b705cfSriastradh } 431303b705cfSriastradh 431403b705cfSriastradh threads[0].extents.y1 = y; 431503b705cfSriastradh threads[0].extents.y2 = extents.y2; 431603b705cfSriastradh mono_span_thread(&threads[0]); 431703b705cfSriastradh 431803b705cfSriastradh sna_threads_wait(); 431903b705cfSriastradh mono.op.done(mono.sna, &mono.op); 432003b705cfSriastradh return true; 432103b705cfSriastradh } 432203b705cfSriastradh 432303b705cfSriastradh if (!mono_init(&mono, 2*ntrap)) 432403b705cfSriastradh return false; 432503b705cfSriastradh 432603b705cfSriastradh for (n = 0; n < ntrap; n++) { 432703b705cfSriastradh if (!xTrapezoidValid(&traps[n])) 432803b705cfSriastradh continue; 432903b705cfSriastradh 433003b705cfSriastradh if (pixman_fixed_to_int(traps[n].top) + dy >= mono.clip.extents.y2 || 433103b705cfSriastradh pixman_fixed_to_int(traps[n].bottom) + dy < mono.clip.extents.y1) 433203b705cfSriastradh continue; 433303b705cfSriastradh 433403b705cfSriastradh mono_add_line(&mono, dx, dy, 433503b705cfSriastradh traps[n].top, traps[n].bottom, 433603b705cfSriastradh &traps[n].left.p1, &traps[n].left.p2, 1); 433703b705cfSriastradh mono_add_line(&mono, dx, dy, 433803b705cfSriastradh traps[n].top, traps[n].bottom, 433903b705cfSriastradh &traps[n].right.p1, &traps[n].right.p2, -1); 434003b705cfSriastradh } 434103b705cfSriastradh 434203b705cfSriastradh if (mono.clip.data == NULL && mono.op.damage == NULL) 434303b705cfSriastradh mono.span = mono_span__fast; 434403b705cfSriastradh else 434503b705cfSriastradh mono.span = mono_span; 434603b705cfSriastradh 434703b705cfSriastradh mono_render(&mono); 434803b705cfSriastradh mono.op.done(mono.sna, &mono.op); 434903b705cfSriastradh mono_fini(&mono); 435003b705cfSriastradh 435103b705cfSriastradh if (unbounded) { 435203b705cfSriastradh xPointFixed p1, p2; 435303b705cfSriastradh 435403b705cfSriastradh if (!mono_init(&mono, 2+2*ntrap)) 435503b705cfSriastradh return false; 435603b705cfSriastradh 435703b705cfSriastradh p1.y = mono.clip.extents.y1 * pixman_fixed_1; 435803b705cfSriastradh p2.y = mono.clip.extents.y2 * pixman_fixed_1; 435903b705cfSriastradh 436003b705cfSriastradh p1.x = mono.clip.extents.x1 * pixman_fixed_1; 436103b705cfSriastradh p2.x = mono.clip.extents.x1 * pixman_fixed_1; 436203b705cfSriastradh mono_add_line(&mono, 0, 0, p1.y, p2.y, &p1, &p2, -1); 436303b705cfSriastradh 436403b705cfSriastradh p1.x = mono.clip.extents.x2 * pixman_fixed_1; 436503b705cfSriastradh p2.x = mono.clip.extents.x2 * pixman_fixed_1; 436603b705cfSriastradh mono_add_line(&mono, 0, 0, p1.y, p2.y, &p1, &p2, 1); 436703b705cfSriastradh 436803b705cfSriastradh for (n = 0; n < ntrap; n++) { 436903b705cfSriastradh if (!xTrapezoidValid(&traps[n])) 437003b705cfSriastradh continue; 437103b705cfSriastradh 437203b705cfSriastradh if (pixman_fixed_to_int(traps[n].top) + dy >= mono.clip.extents.y2 || 437303b705cfSriastradh pixman_fixed_to_int(traps[n].bottom) + dy < mono.clip.extents.y1) 437403b705cfSriastradh continue; 437503b705cfSriastradh 437603b705cfSriastradh mono_add_line(&mono, dx, dy, 437703b705cfSriastradh traps[n].top, traps[n].bottom, 437803b705cfSriastradh &traps[n].left.p1, &traps[n].left.p2, 1); 437903b705cfSriastradh mono_add_line(&mono, dx, dy, 438003b705cfSriastradh traps[n].top, traps[n].bottom, 438103b705cfSriastradh &traps[n].right.p1, &traps[n].right.p2, -1); 438203b705cfSriastradh } 438303b705cfSriastradh memset(&mono.op, 0, sizeof(mono.op)); 438403b705cfSriastradh if (mono.sna->render.composite(mono.sna, 438503b705cfSriastradh PictOpClear, 438603b705cfSriastradh mono.sna->clear, NULL, dst, 438703b705cfSriastradh 0, 0, 438803b705cfSriastradh 0, 0, 438903b705cfSriastradh mono.clip.extents.x1, mono.clip.extents.y1, 439003b705cfSriastradh mono.clip.extents.x2 - mono.clip.extents.x1, 439103b705cfSriastradh mono.clip.extents.y2 - mono.clip.extents.y1, 439203b705cfSriastradh &mono.op)) { 439303b705cfSriastradh mono_render(&mono); 439403b705cfSriastradh mono.op.done(mono.sna, &mono.op); 439503b705cfSriastradh } 439603b705cfSriastradh mono_fini(&mono); 439703b705cfSriastradh } 439803b705cfSriastradh 439903b705cfSriastradh REGION_UNINIT(NULL, &mono.clip); 440003b705cfSriastradh return true; 440103b705cfSriastradh} 440203b705cfSriastradh 440303b705cfSriastradhstruct span_thread { 440403b705cfSriastradh struct sna *sna; 440503b705cfSriastradh const struct sna_composite_spans_op *op; 440603b705cfSriastradh const xTrapezoid *traps; 440703b705cfSriastradh RegionPtr clip; 440803b705cfSriastradh span_func_t span; 440903b705cfSriastradh BoxRec extents; 441003b705cfSriastradh int dx, dy, draw_y; 441103b705cfSriastradh int ntrap; 441203b705cfSriastradh bool unbounded; 441303b705cfSriastradh}; 441403b705cfSriastradh 441503b705cfSriastradh#define SPAN_THREAD_MAX_BOXES (8192/sizeof(struct sna_opacity_box)) 441603b705cfSriastradhstruct span_thread_boxes { 441703b705cfSriastradh const struct sna_composite_spans_op *op; 441803b705cfSriastradh struct sna_opacity_box boxes[SPAN_THREAD_MAX_BOXES]; 441903b705cfSriastradh int num_boxes; 442003b705cfSriastradh}; 442103b705cfSriastradh 442203b705cfSriastradhstatic void span_thread_add_boxes(struct sna *sna, void *data, 442303b705cfSriastradh const BoxRec *box, int count, float alpha) 442403b705cfSriastradh{ 442503b705cfSriastradh struct span_thread_boxes *b = data; 442603b705cfSriastradh 442703b705cfSriastradh __DBG(("%s: adding %d boxes with alpha=%f\n", 442803b705cfSriastradh __FUNCTION__, count, alpha)); 442903b705cfSriastradh 443003b705cfSriastradh assert(count > 0 && count <= SPAN_THREAD_MAX_BOXES); 443103b705cfSriastradh if (unlikely(b->num_boxes + count > SPAN_THREAD_MAX_BOXES)) { 443203b705cfSriastradh DBG(("%s: flushing %d boxes, adding %d\n", __FUNCTION__, b->num_boxes, count)); 443303b705cfSriastradh assert(b->num_boxes <= SPAN_THREAD_MAX_BOXES); 443403b705cfSriastradh b->op->thread_boxes(sna, b->op, b->boxes, b->num_boxes); 443503b705cfSriastradh b->num_boxes = 0; 443603b705cfSriastradh } 443703b705cfSriastradh 443803b705cfSriastradh do { 443903b705cfSriastradh b->boxes[b->num_boxes].box = *box++; 444003b705cfSriastradh b->boxes[b->num_boxes].alpha = alpha; 444103b705cfSriastradh b->num_boxes++; 444203b705cfSriastradh } while (--count); 444303b705cfSriastradh assert(b->num_boxes <= SPAN_THREAD_MAX_BOXES); 444403b705cfSriastradh} 444503b705cfSriastradh 444603b705cfSriastradhstatic void 444703b705cfSriastradhspan_thread_box(struct sna *sna, 444803b705cfSriastradh struct sna_composite_spans_op *op, 444903b705cfSriastradh pixman_region16_t *clip, 445003b705cfSriastradh const BoxRec *box, 445103b705cfSriastradh int coverage) 445203b705cfSriastradh{ 445303b705cfSriastradh __DBG(("%s: %d -> %d @ %d\n", __FUNCTION__, box->x1, box->x2, coverage)); 445403b705cfSriastradh span_thread_add_boxes(sna, op, box, 1, AREA_TO_ALPHA(coverage)); 445503b705cfSriastradh} 445603b705cfSriastradh 445703b705cfSriastradhstatic void 445803b705cfSriastradhspan_thread_clipped_box(struct sna *sna, 445903b705cfSriastradh struct sna_composite_spans_op *op, 446003b705cfSriastradh pixman_region16_t *clip, 446103b705cfSriastradh const BoxRec *box, 446203b705cfSriastradh int coverage) 446303b705cfSriastradh{ 446403b705cfSriastradh pixman_region16_t region; 446503b705cfSriastradh 446603b705cfSriastradh __DBG(("%s: %d -> %d @ %f\n", __FUNCTION__, box->x1, box->x2, 446703b705cfSriastradh AREA_TO_ALPHA(coverage))); 446803b705cfSriastradh 446903b705cfSriastradh pixman_region_init_rects(®ion, box, 1); 447003b705cfSriastradh RegionIntersect(®ion, ®ion, clip); 447103b705cfSriastradh if (REGION_NUM_RECTS(®ion)) { 447203b705cfSriastradh span_thread_add_boxes(sna, op, 447303b705cfSriastradh REGION_RECTS(®ion), 447403b705cfSriastradh REGION_NUM_RECTS(®ion), 447503b705cfSriastradh AREA_TO_ALPHA(coverage)); 447603b705cfSriastradh } 447703b705cfSriastradh pixman_region_fini(®ion); 447803b705cfSriastradh} 447903b705cfSriastradh 448003b705cfSriastradhstatic span_func_t 448103b705cfSriastradhthread_choose_span(struct sna_composite_spans_op *tmp, 448203b705cfSriastradh PicturePtr dst, 448303b705cfSriastradh PictFormatPtr maskFormat, 448403b705cfSriastradh RegionPtr clip) 448503b705cfSriastradh{ 448603b705cfSriastradh span_func_t span; 448703b705cfSriastradh 448803b705cfSriastradh if (tmp->base.damage) { 448903b705cfSriastradh DBG(("%s: damaged -> no thread support\n", __FUNCTION__)); 449003b705cfSriastradh return NULL; 449103b705cfSriastradh } 449203b705cfSriastradh 449303b705cfSriastradh if (is_mono(dst, maskFormat)) { 449403b705cfSriastradh DBG(("%s: mono rendering -> no thread support\n", __FUNCTION__)); 449503b705cfSriastradh return NULL; 449603b705cfSriastradh } else { 449703b705cfSriastradh assert(tmp->thread_boxes); 449803b705cfSriastradh DBG(("%s: clipped? %d\n", __FUNCTION__, clip->data != NULL)); 449903b705cfSriastradh if (clip->data) 450003b705cfSriastradh span = span_thread_clipped_box; 450103b705cfSriastradh else 450203b705cfSriastradh span = span_thread_box; 450303b705cfSriastradh } 450403b705cfSriastradh 450503b705cfSriastradh return span; 450603b705cfSriastradh} 450703b705cfSriastradh 450803b705cfSriastradhstatic void 450903b705cfSriastradhspan_thread(void *arg) 451003b705cfSriastradh{ 451103b705cfSriastradh struct span_thread *thread = arg; 451203b705cfSriastradh struct span_thread_boxes boxes; 451303b705cfSriastradh struct tor tor; 451403b705cfSriastradh const xTrapezoid *t; 451503b705cfSriastradh int n, y1, y2; 451603b705cfSriastradh 451703b705cfSriastradh if (!tor_init(&tor, &thread->extents, 2*thread->ntrap)) 451803b705cfSriastradh return; 451903b705cfSriastradh 452003b705cfSriastradh boxes.op = thread->op; 452103b705cfSriastradh boxes.num_boxes = 0; 452203b705cfSriastradh 452303b705cfSriastradh y1 = thread->extents.y1 - thread->draw_y; 452403b705cfSriastradh y2 = thread->extents.y2 - thread->draw_y; 452503b705cfSriastradh for (n = thread->ntrap, t = thread->traps; n--; t++) { 452603b705cfSriastradh xTrapezoid tt; 452703b705cfSriastradh 452803b705cfSriastradh if (pixman_fixed_to_int(t->top) >= y2 || 452903b705cfSriastradh pixman_fixed_to_int(t->bottom) < y1) 453003b705cfSriastradh continue; 453103b705cfSriastradh 453203b705cfSriastradh if (!project_trapezoid_onto_grid(t, thread->dx, thread->dy, &tt)) 453303b705cfSriastradh continue; 453403b705cfSriastradh 453503b705cfSriastradh tor_add_edge(&tor, &tt, &tt.left, 1); 453603b705cfSriastradh tor_add_edge(&tor, &tt, &tt.right, -1); 453703b705cfSriastradh } 453803b705cfSriastradh 453903b705cfSriastradh tor_render(thread->sna, &tor, 454003b705cfSriastradh (struct sna_composite_spans_op *)&boxes, thread->clip, 454103b705cfSriastradh thread->span, thread->unbounded); 454203b705cfSriastradh 454303b705cfSriastradh tor_fini(&tor); 454403b705cfSriastradh 454503b705cfSriastradh if (boxes.num_boxes) { 454603b705cfSriastradh DBG(("%s: flushing %d boxes\n", __FUNCTION__, boxes.num_boxes)); 454703b705cfSriastradh assert(boxes.num_boxes <= SPAN_THREAD_MAX_BOXES); 454803b705cfSriastradh thread->op->thread_boxes(thread->sna, thread->op, 454903b705cfSriastradh boxes.boxes, boxes.num_boxes); 455003b705cfSriastradh } 455103b705cfSriastradh} 455203b705cfSriastradh 455303b705cfSriastradhstatic bool 455403b705cfSriastradhtrapezoid_span_converter(struct sna *sna, 455503b705cfSriastradh CARD8 op, PicturePtr src, PicturePtr dst, 455603b705cfSriastradh PictFormatPtr maskFormat, unsigned int flags, 455703b705cfSriastradh INT16 src_x, INT16 src_y, 455803b705cfSriastradh int ntrap, xTrapezoid *traps) 455903b705cfSriastradh{ 456003b705cfSriastradh struct sna_composite_spans_op tmp; 456103b705cfSriastradh BoxRec extents; 456203b705cfSriastradh pixman_region16_t clip; 456303b705cfSriastradh int16_t dst_x, dst_y; 456403b705cfSriastradh bool was_clear; 456503b705cfSriastradh int dx, dy, n; 456603b705cfSriastradh int num_threads; 456703b705cfSriastradh 456803b705cfSriastradh if (NO_SCAN_CONVERTER) 456903b705cfSriastradh return false; 457003b705cfSriastradh 457103b705cfSriastradh if (is_mono(dst, maskFormat)) 457203b705cfSriastradh return mono_trapezoids_span_converter(sna, op, src, dst, 457303b705cfSriastradh src_x, src_y, 457403b705cfSriastradh ntrap, traps); 457503b705cfSriastradh 457603b705cfSriastradh /* XXX strict adherence to the Render specification */ 457703b705cfSriastradh if (dst->polyMode == PolyModePrecise) { 457803b705cfSriastradh DBG(("%s: fallback -- precise rasterisation requested\n", 457903b705cfSriastradh __FUNCTION__)); 458003b705cfSriastradh return false; 458103b705cfSriastradh } 458203b705cfSriastradh 458303b705cfSriastradh if (!sna->render.check_composite_spans(sna, op, src, dst, 0, 0, flags)) { 458403b705cfSriastradh DBG(("%s: fallback -- composite spans not supported\n", 458503b705cfSriastradh __FUNCTION__)); 458603b705cfSriastradh return false; 458703b705cfSriastradh } 458803b705cfSriastradh 458903b705cfSriastradh trapezoid_origin(&traps[0].left, &dst_x, &dst_y); 459003b705cfSriastradh 459103b705cfSriastradh trapezoids_bounds(ntrap, traps, &extents); 459203b705cfSriastradh if (extents.y1 >= extents.y2 || extents.x1 >= extents.x2) 459303b705cfSriastradh return true; 459403b705cfSriastradh 459503b705cfSriastradh#if 0 459603b705cfSriastradh if (extents.y2 - extents.y1 < 64 && extents.x2 - extents.x1 < 64) { 459703b705cfSriastradh DBG(("%s: fallback -- traps extents too small %dx%d\n", 459803b705cfSriastradh __FUNCTION__, extents.y2 - extents.y1, extents.x2 - extents.x1)); 459903b705cfSriastradh return false; 460003b705cfSriastradh } 460103b705cfSriastradh#endif 460203b705cfSriastradh 460303b705cfSriastradh DBG(("%s: extents (%d, %d), (%d, %d)\n", 460403b705cfSriastradh __FUNCTION__, extents.x1, extents.y1, extents.x2, extents.y2)); 460503b705cfSriastradh 460603b705cfSriastradh if (!sna_compute_composite_region(&clip, 460703b705cfSriastradh src, NULL, dst, 460803b705cfSriastradh src_x + extents.x1 - dst_x, 460903b705cfSriastradh src_y + extents.y1 - dst_y, 461003b705cfSriastradh 0, 0, 461103b705cfSriastradh extents.x1, extents.y1, 461203b705cfSriastradh extents.x2 - extents.x1, 461303b705cfSriastradh extents.y2 - extents.y1)) { 461403b705cfSriastradh DBG(("%s: trapezoids do not intersect drawable clips\n", 461503b705cfSriastradh __FUNCTION__)) ; 461603b705cfSriastradh return true; 461703b705cfSriastradh } 461803b705cfSriastradh 461903b705cfSriastradh if (!sna->render.check_composite_spans(sna, op, src, dst, 462003b705cfSriastradh clip.extents.x2 - clip.extents.x1, 462103b705cfSriastradh clip.extents.y2 - clip.extents.y1, 462203b705cfSriastradh flags)) { 462303b705cfSriastradh DBG(("%s: fallback -- composite spans not supported\n", 462403b705cfSriastradh __FUNCTION__)); 462503b705cfSriastradh return false; 462603b705cfSriastradh } 462703b705cfSriastradh 462803b705cfSriastradh extents = *RegionExtents(&clip); 462903b705cfSriastradh dx = dst->pDrawable->x; 463003b705cfSriastradh dy = dst->pDrawable->y; 463103b705cfSriastradh 463203b705cfSriastradh DBG(("%s: after clip -- extents (%d, %d), (%d, %d), delta=(%d, %d) src -> (%d, %d)\n", 463303b705cfSriastradh __FUNCTION__, 463403b705cfSriastradh extents.x1, extents.y1, 463503b705cfSriastradh extents.x2, extents.y2, 463603b705cfSriastradh dx, dy, 463703b705cfSriastradh src_x + extents.x1 - dst_x - dx, 463803b705cfSriastradh src_y + extents.y1 - dst_y - dy)); 463903b705cfSriastradh 464003b705cfSriastradh was_clear = sna_drawable_is_clear(dst->pDrawable); 464103b705cfSriastradh switch (op) { 464203b705cfSriastradh case PictOpAdd: 464303b705cfSriastradh case PictOpOver: 464403b705cfSriastradh if (was_clear) 464503b705cfSriastradh op = PictOpSrc; 464603b705cfSriastradh break; 464703b705cfSriastradh case PictOpIn: 464803b705cfSriastradh if (was_clear) 464903b705cfSriastradh return true; 465003b705cfSriastradh break; 465103b705cfSriastradh } 465203b705cfSriastradh 465303b705cfSriastradh memset(&tmp, 0, sizeof(tmp)); 465403b705cfSriastradh if (!sna->render.composite_spans(sna, op, src, dst, 465503b705cfSriastradh src_x + extents.x1 - dst_x - dx, 465603b705cfSriastradh src_y + extents.y1 - dst_y - dy, 465703b705cfSriastradh extents.x1, extents.y1, 465803b705cfSriastradh extents.x2 - extents.x1, 465903b705cfSriastradh extents.y2 - extents.y1, 466003b705cfSriastradh flags, &tmp)) { 466103b705cfSriastradh DBG(("%s: fallback -- composite spans render op not supported\n", 466203b705cfSriastradh __FUNCTION__)); 466303b705cfSriastradh return false; 466403b705cfSriastradh } 466503b705cfSriastradh 466603b705cfSriastradh dx *= FAST_SAMPLES_X; 466703b705cfSriastradh dy *= FAST_SAMPLES_Y; 466803b705cfSriastradh 466903b705cfSriastradh num_threads = 1; 467003b705cfSriastradh if (!NO_GPU_THREADS && tmp.thread_boxes && 467103b705cfSriastradh thread_choose_span(&tmp, dst, maskFormat, &clip)) 467203b705cfSriastradh num_threads = sna_use_threads(extents.x2-extents.x1, 467303b705cfSriastradh extents.y2-extents.y1, 467403b705cfSriastradh 16); 467503b705cfSriastradh DBG(("%s: using %d threads\n", __FUNCTION__, num_threads)); 467603b705cfSriastradh if (num_threads == 1) { 467703b705cfSriastradh struct tor tor; 467803b705cfSriastradh 467903b705cfSriastradh if (!tor_init(&tor, &extents, 2*ntrap)) 468003b705cfSriastradh goto skip; 468103b705cfSriastradh 468203b705cfSriastradh for (n = 0; n < ntrap; n++) { 468303b705cfSriastradh xTrapezoid t; 468403b705cfSriastradh 468503b705cfSriastradh if (!project_trapezoid_onto_grid(&traps[n], dx, dy, &t)) 468603b705cfSriastradh continue; 468703b705cfSriastradh 468803b705cfSriastradh if (pixman_fixed_to_int(traps[n].top) + dst->pDrawable->y >= extents.y2 || 468903b705cfSriastradh pixman_fixed_to_int(traps[n].bottom) + dst->pDrawable->y < extents.y1) 469003b705cfSriastradh continue; 469103b705cfSriastradh 469203b705cfSriastradh tor_add_edge(&tor, &t, &t.left, 1); 469303b705cfSriastradh tor_add_edge(&tor, &t, &t.right, -1); 469403b705cfSriastradh } 469503b705cfSriastradh 469603b705cfSriastradh tor_render(sna, &tor, &tmp, &clip, 469703b705cfSriastradh choose_span(&tmp, dst, maskFormat, &clip), 469803b705cfSriastradh !was_clear && maskFormat && !operator_is_bounded(op)); 469903b705cfSriastradh 470003b705cfSriastradh tor_fini(&tor); 470103b705cfSriastradh } else { 470203b705cfSriastradh struct span_thread threads[num_threads]; 470303b705cfSriastradh int y, h; 470403b705cfSriastradh 470503b705cfSriastradh DBG(("%s: using %d threads for span compositing %dx%d\n", 470603b705cfSriastradh __FUNCTION__, num_threads, 470703b705cfSriastradh extents.x2 - extents.x1, 470803b705cfSriastradh extents.y2 - extents.y1)); 470903b705cfSriastradh 471003b705cfSriastradh threads[0].sna = sna; 471103b705cfSriastradh threads[0].op = &tmp; 471203b705cfSriastradh threads[0].traps = traps; 471303b705cfSriastradh threads[0].ntrap = ntrap; 471403b705cfSriastradh threads[0].extents = extents; 471503b705cfSriastradh threads[0].clip = &clip; 471603b705cfSriastradh threads[0].dx = dx; 471703b705cfSriastradh threads[0].dy = dy; 471803b705cfSriastradh threads[0].draw_y = dst->pDrawable->y; 471903b705cfSriastradh threads[0].unbounded = !was_clear && maskFormat && !operator_is_bounded(op); 472003b705cfSriastradh threads[0].span = thread_choose_span(&tmp, dst, maskFormat, &clip); 472103b705cfSriastradh 472203b705cfSriastradh y = extents.y1; 472303b705cfSriastradh h = extents.y2 - extents.y1; 472403b705cfSriastradh h = (h + num_threads - 1) / num_threads; 472503b705cfSriastradh 472603b705cfSriastradh for (n = 1; n < num_threads; n++) { 472703b705cfSriastradh threads[n] = threads[0]; 472803b705cfSriastradh threads[n].extents.y1 = y; 472903b705cfSriastradh threads[n].extents.y2 = y += h; 473003b705cfSriastradh 473103b705cfSriastradh sna_threads_run(span_thread, &threads[n]); 473203b705cfSriastradh } 473303b705cfSriastradh 473403b705cfSriastradh threads[0].extents.y1 = y; 473503b705cfSriastradh threads[0].extents.y2 = extents.y2; 473603b705cfSriastradh span_thread(&threads[0]); 473703b705cfSriastradh 473803b705cfSriastradh sna_threads_wait(); 473903b705cfSriastradh } 474003b705cfSriastradhskip: 474103b705cfSriastradh tmp.done(sna, &tmp); 474203b705cfSriastradh 474303b705cfSriastradh REGION_UNINIT(NULL, &clip); 474403b705cfSriastradh return true; 474503b705cfSriastradh} 474603b705cfSriastradh 474703b705cfSriastradhstatic void 474803b705cfSriastradhtor_blt_mask(struct sna *sna, 474903b705cfSriastradh struct sna_composite_spans_op *op, 475003b705cfSriastradh pixman_region16_t *clip, 475103b705cfSriastradh const BoxRec *box, 475203b705cfSriastradh int coverage) 475303b705cfSriastradh{ 475403b705cfSriastradh uint8_t *ptr = (uint8_t *)op; 475503b705cfSriastradh int stride = (intptr_t)clip; 475603b705cfSriastradh int h, w; 475703b705cfSriastradh 475803b705cfSriastradh coverage = 256 * coverage / FAST_SAMPLES_XY; 475903b705cfSriastradh coverage -= coverage >> 8; 476003b705cfSriastradh 476103b705cfSriastradh ptr += box->y1 * stride + box->x1; 476203b705cfSriastradh 476303b705cfSriastradh h = box->y2 - box->y1; 476403b705cfSriastradh w = box->x2 - box->x1; 476503b705cfSriastradh if ((w | h) == 1) { 476603b705cfSriastradh *ptr = coverage; 476703b705cfSriastradh } else if (w == 1) { 476803b705cfSriastradh do { 476903b705cfSriastradh *ptr = coverage; 477003b705cfSriastradh ptr += stride; 477103b705cfSriastradh } while (--h); 477203b705cfSriastradh } else do { 477303b705cfSriastradh memset(ptr, coverage, w); 477403b705cfSriastradh ptr += stride; 477503b705cfSriastradh } while (--h); 477603b705cfSriastradh} 477703b705cfSriastradh 477803b705cfSriastradhstatic void 477903b705cfSriastradhtor_blt_mask_mono(struct sna *sna, 478003b705cfSriastradh struct sna_composite_spans_op *op, 478103b705cfSriastradh pixman_region16_t *clip, 478203b705cfSriastradh const BoxRec *box, 478303b705cfSriastradh int coverage) 478403b705cfSriastradh{ 478503b705cfSriastradh tor_blt_mask(sna, op, clip, box, 478603b705cfSriastradh coverage < FAST_SAMPLES_XY/2 ? 0 : FAST_SAMPLES_XY); 478703b705cfSriastradh} 478803b705cfSriastradh 478903b705cfSriastradhstatic bool 479003b705cfSriastradhtrapezoid_mask_converter(CARD8 op, PicturePtr src, PicturePtr dst, 479103b705cfSriastradh PictFormatPtr maskFormat, INT16 src_x, INT16 src_y, 479203b705cfSriastradh int ntrap, xTrapezoid *traps) 479303b705cfSriastradh{ 479403b705cfSriastradh struct tor tor; 479503b705cfSriastradh ScreenPtr screen = dst->pDrawable->pScreen; 479603b705cfSriastradh PixmapPtr scratch; 479703b705cfSriastradh PicturePtr mask; 479803b705cfSriastradh BoxRec extents; 479903b705cfSriastradh int16_t dst_x, dst_y; 480003b705cfSriastradh int dx, dy; 480103b705cfSriastradh int error, n; 480203b705cfSriastradh 480303b705cfSriastradh if (NO_SCAN_CONVERTER) 480403b705cfSriastradh return false; 480503b705cfSriastradh 480603b705cfSriastradh if (dst->polyMode == PolyModePrecise && !is_mono(dst, maskFormat)) { 480703b705cfSriastradh DBG(("%s: fallback -- precise rasterisation requested\n", 480803b705cfSriastradh __FUNCTION__)); 480903b705cfSriastradh return false; 481003b705cfSriastradh } 481103b705cfSriastradh 481203b705cfSriastradh if (maskFormat == NULL && ntrap > 1) { 481303b705cfSriastradh DBG(("%s: individual rasterisation requested\n", 481403b705cfSriastradh __FUNCTION__)); 481503b705cfSriastradh do { 481603b705cfSriastradh /* XXX unwind errors? */ 481703b705cfSriastradh if (!trapezoid_mask_converter(op, src, dst, NULL, 481803b705cfSriastradh src_x, src_y, 1, traps++)) 481903b705cfSriastradh return false; 482003b705cfSriastradh } while (--ntrap); 482103b705cfSriastradh return true; 482203b705cfSriastradh } 482303b705cfSriastradh 482403b705cfSriastradh trapezoids_bounds(ntrap, traps, &extents); 482503b705cfSriastradh if (extents.y1 >= extents.y2 || extents.x1 >= extents.x2) 482603b705cfSriastradh return true; 482703b705cfSriastradh 482803b705cfSriastradh DBG(("%s: ntraps=%d, extents (%d, %d), (%d, %d)\n", 482903b705cfSriastradh __FUNCTION__, ntrap, extents.x1, extents.y1, extents.x2, extents.y2)); 483003b705cfSriastradh 483103b705cfSriastradh if (!sna_compute_composite_extents(&extents, 483203b705cfSriastradh src, NULL, dst, 483303b705cfSriastradh src_x, src_y, 483403b705cfSriastradh 0, 0, 483503b705cfSriastradh extents.x1, extents.y1, 483603b705cfSriastradh extents.x2 - extents.x1, 483703b705cfSriastradh extents.y2 - extents.y1)) 483803b705cfSriastradh return true; 483903b705cfSriastradh 484003b705cfSriastradh DBG(("%s: extents (%d, %d), (%d, %d)\n", 484103b705cfSriastradh __FUNCTION__, extents.x1, extents.y1, extents.x2, extents.y2)); 484203b705cfSriastradh 484303b705cfSriastradh extents.y2 -= extents.y1; 484403b705cfSriastradh extents.x2 -= extents.x1; 484503b705cfSriastradh extents.x1 -= dst->pDrawable->x; 484603b705cfSriastradh extents.y1 -= dst->pDrawable->y; 484703b705cfSriastradh dst_x = extents.x1; 484803b705cfSriastradh dst_y = extents.y1; 484903b705cfSriastradh dx = -extents.x1 * FAST_SAMPLES_X; 485003b705cfSriastradh dy = -extents.y1 * FAST_SAMPLES_Y; 485103b705cfSriastradh extents.x1 = extents.y1 = 0; 485203b705cfSriastradh 485303b705cfSriastradh DBG(("%s: mask (%dx%d), dx=(%d, %d)\n", 485403b705cfSriastradh __FUNCTION__, extents.x2, extents.y2, dx, dy)); 485503b705cfSriastradh scratch = sna_pixmap_create_upload(screen, 485603b705cfSriastradh extents.x2, extents.y2, 8, 485703b705cfSriastradh KGEM_BUFFER_WRITE_INPLACE); 485803b705cfSriastradh if (!scratch) 485903b705cfSriastradh return true; 486003b705cfSriastradh 486103b705cfSriastradh DBG(("%s: created buffer %p, stride %d\n", 486203b705cfSriastradh __FUNCTION__, scratch->devPrivate.ptr, scratch->devKind)); 486303b705cfSriastradh 486403b705cfSriastradh if (!tor_init(&tor, &extents, 2*ntrap)) { 486503b705cfSriastradh sna_pixmap_destroy(scratch); 486603b705cfSriastradh return true; 486703b705cfSriastradh } 486803b705cfSriastradh 486903b705cfSriastradh for (n = 0; n < ntrap; n++) { 487003b705cfSriastradh xTrapezoid t; 487103b705cfSriastradh 487203b705cfSriastradh if (!project_trapezoid_onto_grid(&traps[n], dx, dy, &t)) 487303b705cfSriastradh continue; 487403b705cfSriastradh 487503b705cfSriastradh if (pixman_fixed_to_int(traps[n].top) - dst_y >= extents.y2 || 487603b705cfSriastradh pixman_fixed_to_int(traps[n].bottom) - dst_y < 0) 487703b705cfSriastradh continue; 487803b705cfSriastradh 487903b705cfSriastradh tor_add_edge(&tor, &t, &t.left, 1); 488003b705cfSriastradh tor_add_edge(&tor, &t, &t.right, -1); 488103b705cfSriastradh } 488203b705cfSriastradh 488303b705cfSriastradh if (extents.x2 <= TOR_INPLACE_SIZE) { 488403b705cfSriastradh uint8_t buf[TOR_INPLACE_SIZE]; 488503b705cfSriastradh tor_inplace(&tor, scratch, is_mono(dst, maskFormat), 488603b705cfSriastradh scratch->usage_hint ? NULL : buf); 488703b705cfSriastradh } else { 488803b705cfSriastradh tor_render(NULL, &tor, 488903b705cfSriastradh scratch->devPrivate.ptr, 489003b705cfSriastradh (void *)(intptr_t)scratch->devKind, 489103b705cfSriastradh is_mono(dst, maskFormat) ? tor_blt_mask_mono : tor_blt_mask, 489203b705cfSriastradh true); 489303b705cfSriastradh } 489403b705cfSriastradh tor_fini(&tor); 489503b705cfSriastradh 489603b705cfSriastradh mask = CreatePicture(0, &scratch->drawable, 489703b705cfSriastradh PictureMatchFormat(screen, 8, PICT_a8), 489803b705cfSriastradh 0, 0, serverClient, &error); 489903b705cfSriastradh if (mask) { 490003b705cfSriastradh CompositePicture(op, src, mask, dst, 490103b705cfSriastradh src_x + dst_x - pixman_fixed_to_int(traps[0].left.p1.x), 490203b705cfSriastradh src_y + dst_y - pixman_fixed_to_int(traps[0].left.p1.y), 490303b705cfSriastradh 0, 0, 490403b705cfSriastradh dst_x, dst_y, 490503b705cfSriastradh extents.x2, extents.y2); 490603b705cfSriastradh FreePicture(mask, 0); 490703b705cfSriastradh } 490803b705cfSriastradh sna_pixmap_destroy(scratch); 490903b705cfSriastradh 491003b705cfSriastradh return true; 491103b705cfSriastradh} 491203b705cfSriastradh 491303b705cfSriastradhstruct inplace { 491403b705cfSriastradh uint32_t stride; 491503b705cfSriastradh uint8_t *ptr; 491603b705cfSriastradh union { 491703b705cfSriastradh uint8_t opacity; 491803b705cfSriastradh uint32_t color; 491903b705cfSriastradh }; 492003b705cfSriastradh}; 492103b705cfSriastradh 492203b705cfSriastradhstatic force_inline uint8_t coverage_opacity(int coverage, uint8_t opacity) 492303b705cfSriastradh{ 492403b705cfSriastradh coverage = coverage * 256 / FAST_SAMPLES_XY; 492503b705cfSriastradh coverage -= coverage >> 8; 492603b705cfSriastradh return opacity == 255 ? coverage : mul_8_8(coverage, opacity); 492703b705cfSriastradh} 492803b705cfSriastradh 492903b705cfSriastradhstatic void 493003b705cfSriastradhtor_blt_src(struct sna *sna, 493103b705cfSriastradh struct sna_composite_spans_op *op, 493203b705cfSriastradh pixman_region16_t *clip, 493303b705cfSriastradh const BoxRec *box, 493403b705cfSriastradh int coverage) 493503b705cfSriastradh{ 493603b705cfSriastradh struct inplace *in = (struct inplace *)op; 493703b705cfSriastradh uint8_t *ptr = in->ptr; 493803b705cfSriastradh int h, w; 493903b705cfSriastradh 494003b705cfSriastradh coverage = coverage_opacity(coverage, in->opacity); 494103b705cfSriastradh 494203b705cfSriastradh ptr += box->y1 * in->stride + box->x1; 494303b705cfSriastradh 494403b705cfSriastradh h = box->y2 - box->y1; 494503b705cfSriastradh w = box->x2 - box->x1; 494603b705cfSriastradh if ((w | h) == 1) { 494703b705cfSriastradh *ptr = coverage; 494803b705cfSriastradh } else if (w == 1) { 494903b705cfSriastradh do { 495003b705cfSriastradh *ptr = coverage; 495103b705cfSriastradh ptr += in->stride; 495203b705cfSriastradh } while (--h); 495303b705cfSriastradh } else do { 495403b705cfSriastradh memset(ptr, coverage, w); 495503b705cfSriastradh ptr += in->stride; 495603b705cfSriastradh } while (--h); 495703b705cfSriastradh} 495803b705cfSriastradh 495903b705cfSriastradhstatic void 496003b705cfSriastradhtor_blt_src_clipped(struct sna *sna, 496103b705cfSriastradh struct sna_composite_spans_op *op, 496203b705cfSriastradh pixman_region16_t *clip, 496303b705cfSriastradh const BoxRec *box, 496403b705cfSriastradh int coverage) 496503b705cfSriastradh{ 496603b705cfSriastradh pixman_region16_t region; 496703b705cfSriastradh int n; 496803b705cfSriastradh 496903b705cfSriastradh pixman_region_init_rects(®ion, box, 1); 497003b705cfSriastradh RegionIntersect(®ion, ®ion, clip); 497103b705cfSriastradh n = REGION_NUM_RECTS(®ion); 497203b705cfSriastradh box = REGION_RECTS(®ion); 497303b705cfSriastradh while (n--) 497403b705cfSriastradh tor_blt_src(sna, op, NULL, box++, coverage); 497503b705cfSriastradh pixman_region_fini(®ion); 497603b705cfSriastradh} 497703b705cfSriastradh 497803b705cfSriastradhstatic void 497903b705cfSriastradhtor_blt_in(struct sna *sna, 498003b705cfSriastradh struct sna_composite_spans_op *op, 498103b705cfSriastradh pixman_region16_t *clip, 498203b705cfSriastradh const BoxRec *box, 498303b705cfSriastradh int coverage) 498403b705cfSriastradh{ 498503b705cfSriastradh struct inplace *in = (struct inplace *)op; 498603b705cfSriastradh uint8_t *ptr = in->ptr; 498703b705cfSriastradh int h, w, i; 498803b705cfSriastradh 498903b705cfSriastradh if (coverage == 0) { 499003b705cfSriastradh tor_blt_src(sna, op, clip, box, 0); 499103b705cfSriastradh return; 499203b705cfSriastradh } 499303b705cfSriastradh 499403b705cfSriastradh coverage = coverage_opacity(coverage, in->opacity); 499503b705cfSriastradh if (coverage == 0xff) 499603b705cfSriastradh return; 499703b705cfSriastradh 499803b705cfSriastradh ptr += box->y1 * in->stride + box->x1; 499903b705cfSriastradh 500003b705cfSriastradh h = box->y2 - box->y1; 500103b705cfSriastradh w = box->x2 - box->x1; 500203b705cfSriastradh do { 500303b705cfSriastradh for (i = 0; i < w; i++) 500403b705cfSriastradh ptr[i] = mul_8_8(ptr[i], coverage); 500503b705cfSriastradh ptr += in->stride; 500603b705cfSriastradh } while (--h); 500703b705cfSriastradh} 500803b705cfSriastradh 500903b705cfSriastradhstatic void 501003b705cfSriastradhtor_blt_in_clipped(struct sna *sna, 501103b705cfSriastradh struct sna_composite_spans_op *op, 501203b705cfSriastradh pixman_region16_t *clip, 501303b705cfSriastradh const BoxRec *box, 501403b705cfSriastradh int coverage) 501503b705cfSriastradh{ 501603b705cfSriastradh pixman_region16_t region; 501703b705cfSriastradh int n; 501803b705cfSriastradh 501903b705cfSriastradh pixman_region_init_rects(®ion, box, 1); 502003b705cfSriastradh RegionIntersect(®ion, ®ion, clip); 502103b705cfSriastradh n = REGION_NUM_RECTS(®ion); 502203b705cfSriastradh box = REGION_RECTS(®ion); 502303b705cfSriastradh while (n--) 502403b705cfSriastradh tor_blt_in(sna, op, NULL, box++, coverage); 502503b705cfSriastradh pixman_region_fini(®ion); 502603b705cfSriastradh} 502703b705cfSriastradh 502803b705cfSriastradhstatic void 502903b705cfSriastradhtor_blt_add(struct sna *sna, 503003b705cfSriastradh struct sna_composite_spans_op *op, 503103b705cfSriastradh pixman_region16_t *clip, 503203b705cfSriastradh const BoxRec *box, 503303b705cfSriastradh int coverage) 503403b705cfSriastradh{ 503503b705cfSriastradh struct inplace *in = (struct inplace *)op; 503603b705cfSriastradh uint8_t *ptr = in->ptr; 503703b705cfSriastradh int h, w, v, i; 503803b705cfSriastradh 503903b705cfSriastradh if (coverage == 0) 504003b705cfSriastradh return; 504103b705cfSriastradh 504203b705cfSriastradh coverage = coverage_opacity(coverage, in->opacity); 504303b705cfSriastradh if (coverage == 0xff) { 504403b705cfSriastradh tor_blt_src(sna, op, clip, box, 0xff); 504503b705cfSriastradh return; 504603b705cfSriastradh } 504703b705cfSriastradh 504803b705cfSriastradh ptr += box->y1 * in->stride + box->x1; 504903b705cfSriastradh 505003b705cfSriastradh h = box->y2 - box->y1; 505103b705cfSriastradh w = box->x2 - box->x1; 505203b705cfSriastradh if ((w | h) == 1) { 505303b705cfSriastradh v = coverage + *ptr; 505403b705cfSriastradh *ptr = v >= 255 ? 255 : v; 505503b705cfSriastradh } else { 505603b705cfSriastradh do { 505703b705cfSriastradh for (i = 0; i < w; i++) { 505803b705cfSriastradh v = coverage + ptr[i]; 505903b705cfSriastradh ptr[i] = v >= 255 ? 255 : v; 506003b705cfSriastradh } 506103b705cfSriastradh ptr += in->stride; 506203b705cfSriastradh } while (--h); 506303b705cfSriastradh } 506403b705cfSriastradh} 506503b705cfSriastradh 506603b705cfSriastradhstatic void 506703b705cfSriastradhtor_blt_add_clipped(struct sna *sna, 506803b705cfSriastradh struct sna_composite_spans_op *op, 506903b705cfSriastradh pixman_region16_t *clip, 507003b705cfSriastradh const BoxRec *box, 507103b705cfSriastradh int coverage) 507203b705cfSriastradh{ 507303b705cfSriastradh pixman_region16_t region; 507403b705cfSriastradh int n; 507503b705cfSriastradh 507603b705cfSriastradh pixman_region_init_rects(®ion, box, 1); 507703b705cfSriastradh RegionIntersect(®ion, ®ion, clip); 507803b705cfSriastradh n = REGION_NUM_RECTS(®ion); 507903b705cfSriastradh box = REGION_RECTS(®ion); 508003b705cfSriastradh while (n--) 508103b705cfSriastradh tor_blt_add(sna, op, NULL, box++, coverage); 508203b705cfSriastradh pixman_region_fini(®ion); 508303b705cfSriastradh} 508403b705cfSriastradh 508503b705cfSriastradhstatic void 508603b705cfSriastradhtor_blt_lerp32(struct sna *sna, 508703b705cfSriastradh struct sna_composite_spans_op *op, 508803b705cfSriastradh pixman_region16_t *clip, 508903b705cfSriastradh const BoxRec *box, 509003b705cfSriastradh int coverage) 509103b705cfSriastradh{ 509203b705cfSriastradh struct inplace *in = (struct inplace *)op; 509303b705cfSriastradh uint32_t *ptr = (uint32_t *)in->ptr; 509403b705cfSriastradh int stride = in->stride / sizeof(uint32_t); 509503b705cfSriastradh int h, w, i; 509603b705cfSriastradh 509703b705cfSriastradh if (coverage == 0) 509803b705cfSriastradh return; 509903b705cfSriastradh 510003b705cfSriastradh ptr += box->y1 * stride + box->x1; 510103b705cfSriastradh 510203b705cfSriastradh h = box->y2 - box->y1; 510303b705cfSriastradh w = box->x2 - box->x1; 510403b705cfSriastradh if (coverage == FAST_SAMPLES_XY) { 510503b705cfSriastradh if ((w | h) == 1) { 510603b705cfSriastradh *ptr = in->color; 510703b705cfSriastradh } else { 510803b705cfSriastradh if (w < 16) { 510903b705cfSriastradh do { 511003b705cfSriastradh for (i = 0; i < w; i++) 511103b705cfSriastradh ptr[i] = in->color; 511203b705cfSriastradh ptr += stride; 511303b705cfSriastradh } while (--h); 511403b705cfSriastradh } else { 511503b705cfSriastradh pixman_fill(ptr, stride, 32, 511603b705cfSriastradh 0, 0, w, h, in->color); 511703b705cfSriastradh } 511803b705cfSriastradh } 511903b705cfSriastradh } else { 512003b705cfSriastradh coverage = coverage * 256 / FAST_SAMPLES_XY; 512103b705cfSriastradh coverage -= coverage >> 8; 512203b705cfSriastradh 512303b705cfSriastradh if ((w | h) == 1) { 512403b705cfSriastradh *ptr = lerp8x4(in->color, coverage, *ptr); 512503b705cfSriastradh } else if (w == 1) { 512603b705cfSriastradh do { 512703b705cfSriastradh *ptr = lerp8x4(in->color, coverage, *ptr); 512803b705cfSriastradh ptr += stride; 512903b705cfSriastradh } while (--h); 513003b705cfSriastradh } else{ 513103b705cfSriastradh do { 513203b705cfSriastradh for (i = 0; i < w; i++) 513303b705cfSriastradh ptr[i] = lerp8x4(in->color, coverage, ptr[i]); 513403b705cfSriastradh ptr += stride; 513503b705cfSriastradh } while (--h); 513603b705cfSriastradh } 513703b705cfSriastradh } 513803b705cfSriastradh} 513903b705cfSriastradh 514003b705cfSriastradhstatic void 514103b705cfSriastradhtor_blt_lerp32_clipped(struct sna *sna, 514203b705cfSriastradh struct sna_composite_spans_op *op, 514303b705cfSriastradh pixman_region16_t *clip, 514403b705cfSriastradh const BoxRec *box, 514503b705cfSriastradh int coverage) 514603b705cfSriastradh{ 514703b705cfSriastradh pixman_region16_t region; 514803b705cfSriastradh int n; 514903b705cfSriastradh 515003b705cfSriastradh pixman_region_init_rects(®ion, box, 1); 515103b705cfSriastradh RegionIntersect(®ion, ®ion, clip); 515203b705cfSriastradh n = REGION_NUM_RECTS(®ion); 515303b705cfSriastradh box = REGION_RECTS(®ion); 515403b705cfSriastradh while (n--) 515503b705cfSriastradh tor_blt_lerp32(sna, op, NULL, box++, coverage); 515603b705cfSriastradh pixman_region_fini(®ion); 515703b705cfSriastradh} 515803b705cfSriastradh 515903b705cfSriastradhstruct mono_inplace_composite { 516003b705cfSriastradh pixman_image_t *src, *dst; 516103b705cfSriastradh int dx, dy; 516203b705cfSriastradh int sx, sy; 516303b705cfSriastradh int op; 516403b705cfSriastradh}; 516503b705cfSriastradhstruct mono_inplace_fill { 516603b705cfSriastradh uint32_t *data, stride; 516703b705cfSriastradh uint32_t color; 516803b705cfSriastradh int bpp; 516903b705cfSriastradh}; 517003b705cfSriastradh 517103b705cfSriastradhfastcall static void 517203b705cfSriastradhmono_inplace_fill_box(struct sna *sna, 517303b705cfSriastradh const struct sna_composite_op *op, 517403b705cfSriastradh const BoxRec *box) 517503b705cfSriastradh{ 517603b705cfSriastradh struct mono_inplace_fill *fill = op->priv; 517703b705cfSriastradh 517803b705cfSriastradh DBG(("(%s: (%d, %d)x(%d, %d):%08x\n", 517903b705cfSriastradh __FUNCTION__, 518003b705cfSriastradh box->x1, box->y1, 518103b705cfSriastradh box->x2 - box->x1, 518203b705cfSriastradh box->y2 - box->y1, 518303b705cfSriastradh fill->color)); 518403b705cfSriastradh pixman_fill(fill->data, fill->stride, fill->bpp, 518503b705cfSriastradh box->x1, box->y1, 518603b705cfSriastradh box->x2 - box->x1, 518703b705cfSriastradh box->y2 - box->y1, 518803b705cfSriastradh fill->color); 518903b705cfSriastradh} 519003b705cfSriastradh 519103b705cfSriastradhstatic void 519203b705cfSriastradhmono_inplace_fill_boxes(struct sna *sna, 519303b705cfSriastradh const struct sna_composite_op *op, 519403b705cfSriastradh const BoxRec *box, int nbox) 519503b705cfSriastradh{ 519603b705cfSriastradh struct mono_inplace_fill *fill = op->priv; 519703b705cfSriastradh 519803b705cfSriastradh do { 519903b705cfSriastradh DBG(("(%s: (%d, %d)x(%d, %d):%08x\n", 520003b705cfSriastradh __FUNCTION__, 520103b705cfSriastradh box->x1, box->y1, 520203b705cfSriastradh box->x2 - box->x1, 520303b705cfSriastradh box->y2 - box->y1, 520403b705cfSriastradh fill->color)); 520503b705cfSriastradh pixman_fill(fill->data, fill->stride, fill->bpp, 520603b705cfSriastradh box->x1, box->y1, 520703b705cfSriastradh box->x2 - box->x1, 520803b705cfSriastradh box->y2 - box->y1, 520903b705cfSriastradh fill->color); 521003b705cfSriastradh box++; 521103b705cfSriastradh } while (--nbox); 521203b705cfSriastradh} 521303b705cfSriastradh 521403b705cfSriastradhfastcall static void 521503b705cfSriastradhmono_inplace_composite_box(struct sna *sna, 521603b705cfSriastradh const struct sna_composite_op *op, 521703b705cfSriastradh const BoxRec *box) 521803b705cfSriastradh{ 521903b705cfSriastradh struct mono_inplace_composite *c = op->priv; 522003b705cfSriastradh 522103b705cfSriastradh pixman_image_composite(c->op, c->src, NULL, c->dst, 522203b705cfSriastradh box->x1 + c->sx, box->y1 + c->sy, 522303b705cfSriastradh 0, 0, 522403b705cfSriastradh box->x1 + c->dx, box->y1 + c->dy, 522503b705cfSriastradh box->x2 - box->x1, 522603b705cfSriastradh box->y2 - box->y1); 522703b705cfSriastradh} 522803b705cfSriastradh 522903b705cfSriastradhstatic void 523003b705cfSriastradhmono_inplace_composite_boxes(struct sna *sna, 523103b705cfSriastradh const struct sna_composite_op *op, 523203b705cfSriastradh const BoxRec *box, int nbox) 523303b705cfSriastradh{ 523403b705cfSriastradh struct mono_inplace_composite *c = op->priv; 523503b705cfSriastradh 523603b705cfSriastradh do { 523703b705cfSriastradh pixman_image_composite(c->op, c->src, NULL, c->dst, 523803b705cfSriastradh box->x1 + c->sx, box->y1 + c->sy, 523903b705cfSriastradh 0, 0, 524003b705cfSriastradh box->x1 + c->dx, box->y1 + c->dy, 524103b705cfSriastradh box->x2 - box->x1, 524203b705cfSriastradh box->y2 - box->y1); 524303b705cfSriastradh box++; 524403b705cfSriastradh } while (--nbox); 524503b705cfSriastradh} 524603b705cfSriastradh 524703b705cfSriastradhstatic bool 524803b705cfSriastradhtrapezoid_spans_maybe_inplace(struct sna *sna, 524903b705cfSriastradh CARD8 op, PicturePtr src, PicturePtr dst, 525003b705cfSriastradh PictFormatPtr maskFormat) 525103b705cfSriastradh{ 525203b705cfSriastradh struct sna_pixmap *priv; 525303b705cfSriastradh 525403b705cfSriastradh if (NO_SCAN_CONVERTER) 525503b705cfSriastradh return false; 525603b705cfSriastradh 525703b705cfSriastradh if (dst->polyMode == PolyModePrecise && !is_mono(dst, maskFormat)) 525803b705cfSriastradh return false; 525903b705cfSriastradh if (dst->alphaMap) 526003b705cfSriastradh return false; 526103b705cfSriastradh 526203b705cfSriastradh if (is_mono(dst, maskFormat)) 526303b705cfSriastradh goto out; 526403b705cfSriastradh 526503b705cfSriastradh switch ((int)dst->format) { 526603b705cfSriastradh case PICT_a8: 526703b705cfSriastradh if (!sna_picture_is_solid(src, NULL)) 526803b705cfSriastradh return false; 526903b705cfSriastradh 527003b705cfSriastradh switch (op) { 527103b705cfSriastradh case PictOpIn: 527203b705cfSriastradh case PictOpAdd: 527303b705cfSriastradh case PictOpSrc: 527403b705cfSriastradh break; 527503b705cfSriastradh default: 527603b705cfSriastradh return false; 527703b705cfSriastradh } 527803b705cfSriastradh break; 527903b705cfSriastradh 528003b705cfSriastradh case PICT_x8r8g8b8: 528103b705cfSriastradh case PICT_a8r8g8b8: 528203b705cfSriastradh if (picture_is_gpu(sna, src)) 528303b705cfSriastradh return false; 528403b705cfSriastradh 528503b705cfSriastradh switch (op) { 528603b705cfSriastradh case PictOpOver: 528703b705cfSriastradh case PictOpAdd: 528803b705cfSriastradh case PictOpOutReverse: 528903b705cfSriastradh break; 529003b705cfSriastradh case PictOpSrc: 529103b705cfSriastradh if (sna_picture_is_solid(src, NULL)) 529203b705cfSriastradh break; 529303b705cfSriastradh 529403b705cfSriastradh if (!sna_drawable_is_clear(dst->pDrawable)) 529503b705cfSriastradh return false; 529603b705cfSriastradh break; 529703b705cfSriastradh default: 529803b705cfSriastradh return false; 529903b705cfSriastradh } 530003b705cfSriastradh break; 530103b705cfSriastradh default: 530203b705cfSriastradh return false; 530303b705cfSriastradh } 530403b705cfSriastradh 530503b705cfSriastradhout: 530603b705cfSriastradh priv = sna_pixmap_from_drawable(dst->pDrawable); 530703b705cfSriastradh if (priv == NULL) 530803b705cfSriastradh return true; 530903b705cfSriastradh 531003b705cfSriastradh if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo)) 531103b705cfSriastradh return false; 531203b705cfSriastradh 531303b705cfSriastradh if (DAMAGE_IS_ALL(priv->cpu_damage) || priv->gpu_damage == NULL) 531403b705cfSriastradh return true; 531503b705cfSriastradh 531603b705cfSriastradh if (priv->clear) 531703b705cfSriastradh return dst->pDrawable->width <= TOR_INPLACE_SIZE; 531803b705cfSriastradh 531903b705cfSriastradh if (kgem_bo_is_busy(priv->gpu_bo)) 532003b705cfSriastradh return false; 532103b705cfSriastradh 532203b705cfSriastradh if (priv->cpu_damage) 532303b705cfSriastradh return true; 532403b705cfSriastradh 532503b705cfSriastradh return dst->pDrawable->width <= TOR_INPLACE_SIZE; 532603b705cfSriastradh} 532703b705cfSriastradh 532803b705cfSriastradhstatic bool 532903b705cfSriastradhtrapezoid_span_mono_inplace(struct sna *sna, 533003b705cfSriastradh CARD8 op, 533103b705cfSriastradh PicturePtr src, 533203b705cfSriastradh PicturePtr dst, 533303b705cfSriastradh INT16 src_x, INT16 src_y, 533403b705cfSriastradh int ntrap, xTrapezoid *traps) 533503b705cfSriastradh{ 533603b705cfSriastradh struct mono mono; 533703b705cfSriastradh union { 533803b705cfSriastradh struct mono_inplace_fill fill; 533903b705cfSriastradh struct mono_inplace_composite composite; 534003b705cfSriastradh } inplace; 534103b705cfSriastradh int was_clear; 534203b705cfSriastradh int x, y, n; 534303b705cfSriastradh 534403b705cfSriastradh trapezoids_bounds(ntrap, traps, &mono.clip.extents); 534503b705cfSriastradh if (mono.clip.extents.y1 >= mono.clip.extents.y2 || 534603b705cfSriastradh mono.clip.extents.x1 >= mono.clip.extents.x2) 534703b705cfSriastradh return true; 534803b705cfSriastradh 534903b705cfSriastradh DBG(("%s: extents (%d, %d), (%d, %d)\n", 535003b705cfSriastradh __FUNCTION__, 535103b705cfSriastradh mono.clip.extents.x1, mono.clip.extents.y1, 535203b705cfSriastradh mono.clip.extents.x2, mono.clip.extents.y2)); 535303b705cfSriastradh 535403b705cfSriastradh if (!sna_compute_composite_region(&mono.clip, 535503b705cfSriastradh src, NULL, dst, 535603b705cfSriastradh src_x, src_y, 535703b705cfSriastradh 0, 0, 535803b705cfSriastradh mono.clip.extents.x1, mono.clip.extents.y1, 535903b705cfSriastradh mono.clip.extents.x2 - mono.clip.extents.x1, 536003b705cfSriastradh mono.clip.extents.y2 - mono.clip.extents.y1)) { 536103b705cfSriastradh DBG(("%s: trapezoids do not intersect drawable clips\n", 536203b705cfSriastradh __FUNCTION__)) ; 536303b705cfSriastradh return true; 536403b705cfSriastradh } 536503b705cfSriastradh 536603b705cfSriastradh DBG(("%s: clipped extents (%d, %d), (%d, %d)\n", 536703b705cfSriastradh __FUNCTION__, 536803b705cfSriastradh mono.clip.extents.x1, mono.clip.extents.y1, 536903b705cfSriastradh mono.clip.extents.x2, mono.clip.extents.y2)); 537003b705cfSriastradh 537103b705cfSriastradh was_clear = sna_drawable_is_clear(dst->pDrawable); 537203b705cfSriastradh if (!sna_drawable_move_region_to_cpu(dst->pDrawable, &mono.clip, 537303b705cfSriastradh MOVE_WRITE | MOVE_READ)) 537403b705cfSriastradh return true; 537503b705cfSriastradh 537603b705cfSriastradh mono.sna = sna; 537703b705cfSriastradh if (!mono_init(&mono, 2*ntrap)) 537803b705cfSriastradh return false; 537903b705cfSriastradh 538003b705cfSriastradh mono.op.damage = NULL; 538103b705cfSriastradh 538203b705cfSriastradh x = dst->pDrawable->x; 538303b705cfSriastradh y = dst->pDrawable->y; 538403b705cfSriastradh 538503b705cfSriastradh for (n = 0; n < ntrap; n++) { 538603b705cfSriastradh if (!xTrapezoidValid(&traps[n])) 538703b705cfSriastradh continue; 538803b705cfSriastradh 538903b705cfSriastradh if (pixman_fixed_to_int(traps[n].top) + y >= mono.clip.extents.y2 || 539003b705cfSriastradh pixman_fixed_to_int(traps[n].bottom) + y < mono.clip.extents.y1) 539103b705cfSriastradh continue; 539203b705cfSriastradh 539303b705cfSriastradh mono_add_line(&mono, x, y, 539403b705cfSriastradh traps[n].top, traps[n].bottom, 539503b705cfSriastradh &traps[n].left.p1, &traps[n].left.p2, 1); 539603b705cfSriastradh mono_add_line(&mono, x, y, 539703b705cfSriastradh traps[n].top, traps[n].bottom, 539803b705cfSriastradh &traps[n].right.p1, &traps[n].right.p2, -1); 539903b705cfSriastradh } 540003b705cfSriastradh 540103b705cfSriastradh if (sna_picture_is_solid(src, &inplace.fill.color) && 540203b705cfSriastradh (op == PictOpSrc || op == PictOpClear || 540303b705cfSriastradh (was_clear && (op == PictOpOver || op == PictOpAdd)) || 540403b705cfSriastradh (op == PictOpOver && inplace.fill.color >> 24 == 0xff))) { 540503b705cfSriastradh PixmapPtr pixmap; 540603b705cfSriastradh int16_t dx, dy; 540703b705cfSriastradh uint8_t *ptr; 540803b705cfSriastradh 540903b705cfSriastradhunbounded_pass: 541003b705cfSriastradh pixmap = get_drawable_pixmap(dst->pDrawable); 541103b705cfSriastradh 541203b705cfSriastradh ptr = pixmap->devPrivate.ptr; 541303b705cfSriastradh if (get_drawable_deltas(dst->pDrawable, pixmap, &dx, &dy)) 541403b705cfSriastradh ptr += dy * pixmap->devKind + dx * pixmap->drawable.bitsPerPixel / 8; 541503b705cfSriastradh inplace.fill.data = (uint32_t *)ptr; 541603b705cfSriastradh inplace.fill.stride = pixmap->devKind / sizeof(uint32_t); 541703b705cfSriastradh inplace.fill.bpp = pixmap->drawable.bitsPerPixel; 541803b705cfSriastradh 541903b705cfSriastradh if (op == PictOpClear) 542003b705cfSriastradh inplace.fill.color = 0; 542103b705cfSriastradh else if (dst->format != PICT_a8r8g8b8) 542203b705cfSriastradh inplace.fill.color = sna_rgba_to_color(inplace.fill.color, dst->format); 542303b705cfSriastradh 542403b705cfSriastradh DBG(("%s: fill %x\n", __FUNCTION__, inplace.fill.color)); 542503b705cfSriastradh 542603b705cfSriastradh mono.op.priv = &inplace.fill; 542703b705cfSriastradh mono.op.box = mono_inplace_fill_box; 542803b705cfSriastradh mono.op.boxes = mono_inplace_fill_boxes; 542903b705cfSriastradh 543003b705cfSriastradh op = 0; 543103b705cfSriastradh } else { 543203b705cfSriastradh if (src->pDrawable) { 543303b705cfSriastradh if (!sna_drawable_move_to_cpu(src->pDrawable, 543403b705cfSriastradh MOVE_READ)) { 543503b705cfSriastradh mono_fini(&mono); 543603b705cfSriastradh return false; 543703b705cfSriastradh } 543803b705cfSriastradh if (src->alphaMap && 543903b705cfSriastradh !sna_drawable_move_to_cpu(src->alphaMap->pDrawable, 544003b705cfSriastradh MOVE_READ)) { 544103b705cfSriastradh mono_fini(&mono); 544203b705cfSriastradh return false; 544303b705cfSriastradh } 544403b705cfSriastradh } 544503b705cfSriastradh 544603b705cfSriastradh inplace.composite.dst = image_from_pict(dst, false, 544703b705cfSriastradh &inplace.composite.dx, 544803b705cfSriastradh &inplace.composite.dy); 544903b705cfSriastradh inplace.composite.src = image_from_pict(src, false, 545003b705cfSriastradh &inplace.composite.sx, 545103b705cfSriastradh &inplace.composite.sy); 545203b705cfSriastradh inplace.composite.sx += 545303b705cfSriastradh src_x - pixman_fixed_to_int(traps[0].left.p1.x), 545403b705cfSriastradh inplace.composite.sy += 545503b705cfSriastradh src_y - pixman_fixed_to_int(traps[0].left.p1.y), 545603b705cfSriastradh inplace.composite.op = op; 545703b705cfSriastradh 545803b705cfSriastradh mono.op.priv = &inplace.composite; 545903b705cfSriastradh mono.op.box = mono_inplace_composite_box; 546003b705cfSriastradh mono.op.boxes = mono_inplace_composite_boxes; 546103b705cfSriastradh } 546203b705cfSriastradh 546303b705cfSriastradh if (mono.clip.data == NULL && mono.op.damage == NULL) 546403b705cfSriastradh mono.span = mono_span__fast; 546503b705cfSriastradh else 546603b705cfSriastradh mono.span = mono_span; 546703b705cfSriastradh mono_render(&mono); 546803b705cfSriastradh mono_fini(&mono); 546903b705cfSriastradh 547003b705cfSriastradh if (op) { 547103b705cfSriastradh free_pixman_pict(src, inplace.composite.src); 547203b705cfSriastradh free_pixman_pict(dst, inplace.composite.dst); 547303b705cfSriastradh 547403b705cfSriastradh if (!was_clear && !operator_is_bounded(op)) { 547503b705cfSriastradh xPointFixed p1, p2; 547603b705cfSriastradh 547703b705cfSriastradh DBG(("%s: unbounded fixup\n", __FUNCTION__)); 547803b705cfSriastradh 547903b705cfSriastradh if (!mono_init(&mono, 2+2*ntrap)) 548003b705cfSriastradh return false; 548103b705cfSriastradh 548203b705cfSriastradh p1.y = mono.clip.extents.y1 * pixman_fixed_1; 548303b705cfSriastradh p2.y = mono.clip.extents.y2 * pixman_fixed_1; 548403b705cfSriastradh 548503b705cfSriastradh p1.x = mono.clip.extents.x1 * pixman_fixed_1; 548603b705cfSriastradh p2.x = mono.clip.extents.x1 * pixman_fixed_1; 548703b705cfSriastradh mono_add_line(&mono, 0, 0, p1.y, p2.y, &p1, &p2, -1); 548803b705cfSriastradh 548903b705cfSriastradh p1.x = mono.clip.extents.x2 * pixman_fixed_1; 549003b705cfSriastradh p2.x = mono.clip.extents.x2 * pixman_fixed_1; 549103b705cfSriastradh mono_add_line(&mono, 0, 0, p1.y, p2.y, &p1, &p2, 1); 549203b705cfSriastradh 549303b705cfSriastradh for (n = 0; n < ntrap; n++) { 549403b705cfSriastradh if (!xTrapezoidValid(&traps[n])) 549503b705cfSriastradh continue; 549603b705cfSriastradh 549703b705cfSriastradh if (pixman_fixed_to_int(traps[n].top) + x >= mono.clip.extents.y2 || 549803b705cfSriastradh pixman_fixed_to_int(traps[n].bottom) + y < mono.clip.extents.y1) 549903b705cfSriastradh continue; 550003b705cfSriastradh 550103b705cfSriastradh mono_add_line(&mono, x, y, 550203b705cfSriastradh traps[n].top, traps[n].bottom, 550303b705cfSriastradh &traps[n].left.p1, &traps[n].left.p2, 1); 550403b705cfSriastradh mono_add_line(&mono, x, y, 550503b705cfSriastradh traps[n].top, traps[n].bottom, 550603b705cfSriastradh &traps[n].right.p1, &traps[n].right.p2, -1); 550703b705cfSriastradh } 550803b705cfSriastradh 550903b705cfSriastradh op = PictOpClear; 551003b705cfSriastradh goto unbounded_pass; 551103b705cfSriastradh } 551203b705cfSriastradh } 551303b705cfSriastradh 551403b705cfSriastradh return true; 551503b705cfSriastradh} 551603b705cfSriastradh 551703b705cfSriastradhstatic void 551803b705cfSriastradhpixmask_span_solid(struct sna *sna, 551903b705cfSriastradh struct sna_composite_spans_op *op, 552003b705cfSriastradh pixman_region16_t *clip, 552103b705cfSriastradh const BoxRec *box, 552203b705cfSriastradh int coverage) 552303b705cfSriastradh{ 552403b705cfSriastradh struct pixman_inplace *pi = (struct pixman_inplace *)op; 552503b705cfSriastradh if (coverage != FAST_SAMPLES_XY) { 552603b705cfSriastradh coverage = coverage * 256 / FAST_SAMPLES_XY; 552703b705cfSriastradh coverage -= coverage >> 8; 552803b705cfSriastradh *pi->bits = mul_4x8_8(pi->color, coverage); 552903b705cfSriastradh } else 553003b705cfSriastradh *pi->bits = pi->color; 553103b705cfSriastradh pixman_image_composite(pi->op, pi->source, NULL, pi->image, 553203b705cfSriastradh box->x1, box->y1, 553303b705cfSriastradh 0, 0, 553403b705cfSriastradh pi->dx + box->x1, pi->dy + box->y1, 553503b705cfSriastradh box->x2 - box->x1, box->y2 - box->y1); 553603b705cfSriastradh} 553703b705cfSriastradhstatic void 553803b705cfSriastradhpixmask_span_solid__clipped(struct sna *sna, 553903b705cfSriastradh struct sna_composite_spans_op *op, 554003b705cfSriastradh pixman_region16_t *clip, 554103b705cfSriastradh const BoxRec *box, 554203b705cfSriastradh int coverage) 554303b705cfSriastradh{ 554403b705cfSriastradh pixman_region16_t region; 554503b705cfSriastradh int n; 554603b705cfSriastradh 554703b705cfSriastradh pixman_region_init_rects(®ion, box, 1); 554803b705cfSriastradh RegionIntersect(®ion, ®ion, clip); 554903b705cfSriastradh n = REGION_NUM_RECTS(®ion); 555003b705cfSriastradh box = REGION_RECTS(®ion); 555103b705cfSriastradh while (n--) 555203b705cfSriastradh pixmask_span_solid(sna, op, NULL, box++, coverage); 555303b705cfSriastradh pixman_region_fini(®ion); 555403b705cfSriastradh} 555503b705cfSriastradh 555603b705cfSriastradhstatic void 555703b705cfSriastradhpixmask_span(struct sna *sna, 555803b705cfSriastradh struct sna_composite_spans_op *op, 555903b705cfSriastradh pixman_region16_t *clip, 556003b705cfSriastradh const BoxRec *box, 556103b705cfSriastradh int coverage) 556203b705cfSriastradh{ 556303b705cfSriastradh struct pixman_inplace *pi = (struct pixman_inplace *)op; 556403b705cfSriastradh pixman_image_t *mask = NULL; 556503b705cfSriastradh if (coverage != FAST_SAMPLES_XY) { 556603b705cfSriastradh coverage = coverage * 256 / FAST_SAMPLES_XY; 556703b705cfSriastradh coverage -= coverage >> 8; 556803b705cfSriastradh *pi->bits = coverage; 556903b705cfSriastradh mask = pi->mask; 557003b705cfSriastradh } 557103b705cfSriastradh pixman_image_composite(pi->op, pi->source, mask, pi->image, 557203b705cfSriastradh pi->sx + box->x1, pi->sy + box->y1, 557303b705cfSriastradh 0, 0, 557403b705cfSriastradh pi->dx + box->x1, pi->dy + box->y1, 557503b705cfSriastradh box->x2 - box->x1, box->y2 - box->y1); 557603b705cfSriastradh} 557703b705cfSriastradhstatic void 557803b705cfSriastradhpixmask_span__clipped(struct sna *sna, 557903b705cfSriastradh struct sna_composite_spans_op *op, 558003b705cfSriastradh pixman_region16_t *clip, 558103b705cfSriastradh const BoxRec *box, 558203b705cfSriastradh int coverage) 558303b705cfSriastradh{ 558403b705cfSriastradh pixman_region16_t region; 558503b705cfSriastradh int n; 558603b705cfSriastradh 558703b705cfSriastradh pixman_region_init_rects(®ion, box, 1); 558803b705cfSriastradh RegionIntersect(®ion, ®ion, clip); 558903b705cfSriastradh n = REGION_NUM_RECTS(®ion); 559003b705cfSriastradh box = REGION_RECTS(®ion); 559103b705cfSriastradh while (n--) 559203b705cfSriastradh pixmask_span(sna, op, NULL, box++, coverage); 559303b705cfSriastradh pixman_region_fini(®ion); 559403b705cfSriastradh} 559503b705cfSriastradh 559603b705cfSriastradhstruct inplace_x8r8g8b8_thread { 559703b705cfSriastradh xTrapezoid *traps; 559803b705cfSriastradh PicturePtr dst, src; 559903b705cfSriastradh BoxRec extents; 560003b705cfSriastradh int dx, dy; 560103b705cfSriastradh int ntrap; 560203b705cfSriastradh bool lerp, is_solid; 560303b705cfSriastradh uint32_t color; 560403b705cfSriastradh int16_t src_x, src_y; 560503b705cfSriastradh uint8_t op; 560603b705cfSriastradh}; 560703b705cfSriastradh 560803b705cfSriastradhstatic void inplace_x8r8g8b8_thread(void *arg) 560903b705cfSriastradh{ 561003b705cfSriastradh struct inplace_x8r8g8b8_thread *thread = arg; 561103b705cfSriastradh struct tor tor; 561203b705cfSriastradh span_func_t span; 561303b705cfSriastradh RegionPtr clip; 561403b705cfSriastradh int y1, y2, n; 561503b705cfSriastradh 561603b705cfSriastradh if (!tor_init(&tor, &thread->extents, 2*thread->ntrap)) 561703b705cfSriastradh return; 561803b705cfSriastradh 561903b705cfSriastradh y1 = thread->extents.y1 - thread->dst->pDrawable->y; 562003b705cfSriastradh y2 = thread->extents.y2 - thread->dst->pDrawable->y; 562103b705cfSriastradh for (n = 0; n < thread->ntrap; n++) { 562203b705cfSriastradh xTrapezoid t; 562303b705cfSriastradh 562403b705cfSriastradh if (!project_trapezoid_onto_grid(&thread->traps[n], thread->dx, thread->dy, &t)) 562503b705cfSriastradh continue; 562603b705cfSriastradh 562703b705cfSriastradh if (pixman_fixed_to_int(thread->traps[n].top) >= y2 || 562803b705cfSriastradh pixman_fixed_to_int(thread->traps[n].bottom) < y1) 562903b705cfSriastradh continue; 563003b705cfSriastradh 563103b705cfSriastradh tor_add_edge(&tor, &t, &t.left, 1); 563203b705cfSriastradh tor_add_edge(&tor, &t, &t.right, -1); 563303b705cfSriastradh } 563403b705cfSriastradh 563503b705cfSriastradh clip = thread->dst->pCompositeClip; 563603b705cfSriastradh if (thread->lerp) { 563703b705cfSriastradh struct inplace inplace; 563803b705cfSriastradh int16_t dst_x, dst_y; 563903b705cfSriastradh PixmapPtr pixmap; 564003b705cfSriastradh 564103b705cfSriastradh pixmap = get_drawable_pixmap(thread->dst->pDrawable); 564203b705cfSriastradh 564303b705cfSriastradh inplace.ptr = pixmap->devPrivate.ptr; 564403b705cfSriastradh if (get_drawable_deltas(thread->dst->pDrawable, pixmap, &dst_x, &dst_y)) 564503b705cfSriastradh inplace.ptr += dst_y * pixmap->devKind + dst_x * 4; 564603b705cfSriastradh inplace.stride = pixmap->devKind; 564703b705cfSriastradh inplace.color = thread->color; 564803b705cfSriastradh 564903b705cfSriastradh if (clip->data) 565003b705cfSriastradh span = tor_blt_lerp32_clipped; 565103b705cfSriastradh else 565203b705cfSriastradh span = tor_blt_lerp32; 565303b705cfSriastradh 565403b705cfSriastradh tor_render(NULL, &tor, (void*)&inplace, clip, span, false); 565503b705cfSriastradh } else if (thread->is_solid) { 565603b705cfSriastradh struct pixman_inplace pi; 565703b705cfSriastradh 565803b705cfSriastradh pi.image = image_from_pict(thread->dst, false, &pi.dx, &pi.dy); 565903b705cfSriastradh pi.op = thread->op; 566003b705cfSriastradh pi.color = thread->color; 566103b705cfSriastradh 566203b705cfSriastradh pi.bits = (uint32_t *)&pi.sx; 566303b705cfSriastradh pi.source = pixman_image_create_bits(PIXMAN_a8r8g8b8, 566403b705cfSriastradh 1, 1, pi.bits, 0); 566503b705cfSriastradh pixman_image_set_repeat(pi.source, PIXMAN_REPEAT_NORMAL); 566603b705cfSriastradh 566703b705cfSriastradh if (clip->data) 566803b705cfSriastradh span = pixmask_span_solid__clipped; 566903b705cfSriastradh else 567003b705cfSriastradh span = pixmask_span_solid; 567103b705cfSriastradh 567203b705cfSriastradh tor_render(NULL, &tor, (void*)&pi, clip, span, false); 567303b705cfSriastradh 567403b705cfSriastradh pixman_image_unref(pi.source); 567503b705cfSriastradh pixman_image_unref(pi.image); 567603b705cfSriastradh } else { 567703b705cfSriastradh struct pixman_inplace pi; 567803b705cfSriastradh 567903b705cfSriastradh pi.image = image_from_pict(thread->dst, false, &pi.dx, &pi.dy); 568003b705cfSriastradh pi.source = image_from_pict(thread->src, false, &pi.sx, &pi.sy); 568103b705cfSriastradh pi.sx += thread->src_x - pixman_fixed_to_int(thread->traps[0].left.p1.x); 568203b705cfSriastradh pi.sy += thread->src_y - pixman_fixed_to_int(thread->traps[0].left.p1.y); 568303b705cfSriastradh pi.mask = pixman_image_create_bits(PIXMAN_a8, 1, 1, NULL, 0); 568403b705cfSriastradh pixman_image_set_repeat(pi.mask, PIXMAN_REPEAT_NORMAL); 568503b705cfSriastradh pi.bits = pixman_image_get_data(pi.mask); 568603b705cfSriastradh pi.op = thread->op; 568703b705cfSriastradh 568803b705cfSriastradh if (clip->data) 568903b705cfSriastradh span = pixmask_span__clipped; 569003b705cfSriastradh else 569103b705cfSriastradh span = pixmask_span; 569203b705cfSriastradh 569303b705cfSriastradh tor_render(NULL, &tor, (void*)&pi, clip, span, false); 569403b705cfSriastradh 569503b705cfSriastradh pixman_image_unref(pi.mask); 569603b705cfSriastradh pixman_image_unref(pi.source); 569703b705cfSriastradh pixman_image_unref(pi.image); 569803b705cfSriastradh } 569903b705cfSriastradh 570003b705cfSriastradh tor_fini(&tor); 570103b705cfSriastradh} 570203b705cfSriastradh 570303b705cfSriastradhstatic bool 570403b705cfSriastradhtrapezoid_span_inplace__x8r8g8b8(CARD8 op, 570503b705cfSriastradh PicturePtr dst, 570603b705cfSriastradh PicturePtr src, int16_t src_x, int16_t src_y, 570703b705cfSriastradh PictFormatPtr maskFormat, 570803b705cfSriastradh int ntrap, xTrapezoid *traps) 570903b705cfSriastradh{ 571003b705cfSriastradh uint32_t color; 571103b705cfSriastradh bool lerp, is_solid; 571203b705cfSriastradh RegionRec region; 571303b705cfSriastradh int dx, dy; 571403b705cfSriastradh int num_threads, n; 571503b705cfSriastradh 571603b705cfSriastradh lerp = false; 571703b705cfSriastradh is_solid = sna_picture_is_solid(src, &color); 571803b705cfSriastradh if (is_solid) { 571903b705cfSriastradh if (op == PictOpOver && (color >> 24) == 0xff) 572003b705cfSriastradh op = PictOpSrc; 572103b705cfSriastradh if (op == PictOpOver && sna_drawable_is_clear(dst->pDrawable)) 572203b705cfSriastradh op = PictOpSrc; 572303b705cfSriastradh lerp = op == PictOpSrc; 572403b705cfSriastradh } 572503b705cfSriastradh if (!lerp) { 572603b705cfSriastradh switch (op) { 572703b705cfSriastradh case PictOpOver: 572803b705cfSriastradh case PictOpAdd: 572903b705cfSriastradh case PictOpOutReverse: 573003b705cfSriastradh break; 573103b705cfSriastradh case PictOpSrc: 573203b705cfSriastradh if (!sna_drawable_is_clear(dst->pDrawable)) 573303b705cfSriastradh return false; 573403b705cfSriastradh break; 573503b705cfSriastradh default: 573603b705cfSriastradh return false; 573703b705cfSriastradh } 573803b705cfSriastradh } 573903b705cfSriastradh 574003b705cfSriastradh if (maskFormat == NULL && ntrap > 1) { 574103b705cfSriastradh DBG(("%s: individual rasterisation requested\n", 574203b705cfSriastradh __FUNCTION__)); 574303b705cfSriastradh do { 574403b705cfSriastradh /* XXX unwind errors? */ 574503b705cfSriastradh if (!trapezoid_span_inplace__x8r8g8b8(op, dst, 574603b705cfSriastradh src, src_x, src_y, 574703b705cfSriastradh NULL, 1, traps++)) 574803b705cfSriastradh return false; 574903b705cfSriastradh } while (--ntrap); 575003b705cfSriastradh return true; 575103b705cfSriastradh } 575203b705cfSriastradh 575303b705cfSriastradh trapezoids_bounds(ntrap, traps, ®ion.extents); 575403b705cfSriastradh if (region.extents.y1 >= region.extents.y2 || 575503b705cfSriastradh region.extents.x1 >= region.extents.x2) 575603b705cfSriastradh return true; 575703b705cfSriastradh 575803b705cfSriastradh DBG(("%s: extents (%d, %d), (%d, %d)\n", 575903b705cfSriastradh __FUNCTION__, 576003b705cfSriastradh region.extents.x1, region.extents.y1, 576103b705cfSriastradh region.extents.x2, region.extents.y2)); 576203b705cfSriastradh 576303b705cfSriastradh if (!sna_compute_composite_extents(®ion.extents, 576403b705cfSriastradh src, NULL, dst, 576503b705cfSriastradh src_x, src_y, 576603b705cfSriastradh 0, 0, 576703b705cfSriastradh region.extents.x1, region.extents.y1, 576803b705cfSriastradh region.extents.x2 - region.extents.x1, 576903b705cfSriastradh region.extents.y2 - region.extents.y1)) 577003b705cfSriastradh return true; 577103b705cfSriastradh 577203b705cfSriastradh DBG(("%s: clipped extents (%d, %d), (%d, %d)\n", 577303b705cfSriastradh __FUNCTION__, 577403b705cfSriastradh region.extents.x1, region.extents.y1, 577503b705cfSriastradh region.extents.x2, region.extents.y2)); 577603b705cfSriastradh 577703b705cfSriastradh region.data = NULL; 577803b705cfSriastradh if (!sna_drawable_move_region_to_cpu(dst->pDrawable, ®ion, 577903b705cfSriastradh MOVE_WRITE | MOVE_READ)) 578003b705cfSriastradh return true; 578103b705cfSriastradh 578203b705cfSriastradh if (!is_solid && src->pDrawable) { 578303b705cfSriastradh if (!sna_drawable_move_to_cpu(src->pDrawable, 578403b705cfSriastradh MOVE_READ)) 578503b705cfSriastradh return true; 578603b705cfSriastradh 578703b705cfSriastradh if (src->alphaMap && 578803b705cfSriastradh !sna_drawable_move_to_cpu(src->alphaMap->pDrawable, 578903b705cfSriastradh MOVE_READ)) 579003b705cfSriastradh return true; 579103b705cfSriastradh } 579203b705cfSriastradh 579303b705cfSriastradh dx = dst->pDrawable->x * FAST_SAMPLES_X; 579403b705cfSriastradh dy = dst->pDrawable->y * FAST_SAMPLES_Y; 579503b705cfSriastradh 579603b705cfSriastradh num_threads = sna_use_threads(4*(region.extents.x2 - region.extents.x1), 579703b705cfSriastradh region.extents.y2 - region.extents.y1, 579803b705cfSriastradh 16); 579903b705cfSriastradh 580003b705cfSriastradh DBG(("%s: %dx%d, format=%x, op=%d, lerp?=%d, num_threads=%d\n", 580103b705cfSriastradh __FUNCTION__, 580203b705cfSriastradh region.extents.x2 - region.extents.x1, 580303b705cfSriastradh region.extents.y2 - region.extents.y1, 580403b705cfSriastradh dst->format, op, lerp, num_threads)); 580503b705cfSriastradh 580603b705cfSriastradh if (num_threads == 1) { 580703b705cfSriastradh struct tor tor; 580803b705cfSriastradh span_func_t span; 580903b705cfSriastradh 581003b705cfSriastradh if (!tor_init(&tor, ®ion.extents, 2*ntrap)) 581103b705cfSriastradh return true; 581203b705cfSriastradh 581303b705cfSriastradh for (n = 0; n < ntrap; n++) { 581403b705cfSriastradh xTrapezoid t; 581503b705cfSriastradh 581603b705cfSriastradh if (!project_trapezoid_onto_grid(&traps[n], dx, dy, &t)) 581703b705cfSriastradh continue; 581803b705cfSriastradh 581903b705cfSriastradh if (pixman_fixed_to_int(traps[n].top) >= region.extents.y2 - dst->pDrawable->y || 582003b705cfSriastradh pixman_fixed_to_int(traps[n].bottom) < region.extents.y1 - dst->pDrawable->y) 582103b705cfSriastradh continue; 582203b705cfSriastradh 582303b705cfSriastradh tor_add_edge(&tor, &t, &t.left, 1); 582403b705cfSriastradh tor_add_edge(&tor, &t, &t.right, -1); 582503b705cfSriastradh } 582603b705cfSriastradh 582703b705cfSriastradh if (lerp) { 582803b705cfSriastradh struct inplace inplace; 582903b705cfSriastradh PixmapPtr pixmap; 583003b705cfSriastradh int16_t dst_x, dst_y; 583103b705cfSriastradh 583203b705cfSriastradh pixmap = get_drawable_pixmap(dst->pDrawable); 583303b705cfSriastradh 583403b705cfSriastradh inplace.ptr = pixmap->devPrivate.ptr; 583503b705cfSriastradh if (get_drawable_deltas(dst->pDrawable, pixmap, &dst_x, &dst_y)) 583603b705cfSriastradh inplace.ptr += dst_y * pixmap->devKind + dst_x * 4; 583703b705cfSriastradh inplace.stride = pixmap->devKind; 583803b705cfSriastradh inplace.color = color; 583903b705cfSriastradh 584003b705cfSriastradh if (dst->pCompositeClip->data) 584103b705cfSriastradh span = tor_blt_lerp32_clipped; 584203b705cfSriastradh else 584303b705cfSriastradh span = tor_blt_lerp32; 584403b705cfSriastradh 584503b705cfSriastradh DBG(("%s: render inplace op=%d, color=%08x\n", 584603b705cfSriastradh __FUNCTION__, op, color)); 584703b705cfSriastradh 584803b705cfSriastradh tor_render(NULL, &tor, (void*)&inplace, 584903b705cfSriastradh dst->pCompositeClip, span, false); 585003b705cfSriastradh } else if (is_solid) { 585103b705cfSriastradh struct pixman_inplace pi; 585203b705cfSriastradh 585303b705cfSriastradh pi.image = image_from_pict(dst, false, &pi.dx, &pi.dy); 585403b705cfSriastradh pi.op = op; 585503b705cfSriastradh pi.color = color; 585603b705cfSriastradh 585703b705cfSriastradh pi.bits = (uint32_t *)&pi.sx; 585803b705cfSriastradh pi.source = pixman_image_create_bits(PIXMAN_a8r8g8b8, 585903b705cfSriastradh 1, 1, pi.bits, 0); 586003b705cfSriastradh pixman_image_set_repeat(pi.source, PIXMAN_REPEAT_NORMAL); 586103b705cfSriastradh 586203b705cfSriastradh if (dst->pCompositeClip->data) 586303b705cfSriastradh span = pixmask_span_solid__clipped; 586403b705cfSriastradh else 586503b705cfSriastradh span = pixmask_span_solid; 586603b705cfSriastradh 586703b705cfSriastradh tor_render(NULL, &tor, (void*)&pi, 586803b705cfSriastradh dst->pCompositeClip, span, 586903b705cfSriastradh false); 587003b705cfSriastradh 587103b705cfSriastradh pixman_image_unref(pi.source); 587203b705cfSriastradh pixman_image_unref(pi.image); 587303b705cfSriastradh } else { 587403b705cfSriastradh struct pixman_inplace pi; 587503b705cfSriastradh 587603b705cfSriastradh pi.image = image_from_pict(dst, false, &pi.dx, &pi.dy); 587703b705cfSriastradh pi.source = image_from_pict(src, false, &pi.sx, &pi.sy); 587803b705cfSriastradh pi.sx += src_x - pixman_fixed_to_int(traps[0].left.p1.x); 587903b705cfSriastradh pi.sy += src_y - pixman_fixed_to_int(traps[0].left.p1.y); 588003b705cfSriastradh pi.mask = pixman_image_create_bits(PIXMAN_a8, 1, 1, NULL, 0); 588103b705cfSriastradh pixman_image_set_repeat(pi.mask, PIXMAN_REPEAT_NORMAL); 588203b705cfSriastradh pi.bits = pixman_image_get_data(pi.mask); 588303b705cfSriastradh pi.op = op; 588403b705cfSriastradh 588503b705cfSriastradh if (dst->pCompositeClip->data) 588603b705cfSriastradh span = pixmask_span__clipped; 588703b705cfSriastradh else 588803b705cfSriastradh span = pixmask_span; 588903b705cfSriastradh 589003b705cfSriastradh tor_render(NULL, &tor, (void*)&pi, 589103b705cfSriastradh dst->pCompositeClip, span, 589203b705cfSriastradh false); 589303b705cfSriastradh 589403b705cfSriastradh pixman_image_unref(pi.mask); 589503b705cfSriastradh pixman_image_unref(pi.source); 589603b705cfSriastradh pixman_image_unref(pi.image); 589703b705cfSriastradh } 589803b705cfSriastradh 589903b705cfSriastradh tor_fini(&tor); 590003b705cfSriastradh } else { 590103b705cfSriastradh struct inplace_x8r8g8b8_thread threads[num_threads]; 590203b705cfSriastradh int y, h; 590303b705cfSriastradh 590403b705cfSriastradh DBG(("%s: using %d threads for inplace compositing %dx%d\n", 590503b705cfSriastradh __FUNCTION__, num_threads, 590603b705cfSriastradh region.extents.x2 - region.extents.x1, 590703b705cfSriastradh region.extents.y2 - region.extents.y1)); 590803b705cfSriastradh 590903b705cfSriastradh threads[0].traps = traps; 591003b705cfSriastradh threads[0].ntrap = ntrap; 591103b705cfSriastradh threads[0].extents = region.extents; 591203b705cfSriastradh threads[0].lerp = lerp; 591303b705cfSriastradh threads[0].is_solid = is_solid; 591403b705cfSriastradh threads[0].color = color; 591503b705cfSriastradh threads[0].dx = dx; 591603b705cfSriastradh threads[0].dy = dy; 591703b705cfSriastradh threads[0].dst = dst; 591803b705cfSriastradh threads[0].src = src; 591903b705cfSriastradh threads[0].op = op; 592003b705cfSriastradh threads[0].src_x = src_x; 592103b705cfSriastradh threads[0].src_y = src_y; 592203b705cfSriastradh 592303b705cfSriastradh y = region.extents.y1; 592403b705cfSriastradh h = region.extents.y2 - region.extents.y1; 592503b705cfSriastradh h = (h + num_threads - 1) / num_threads; 592603b705cfSriastradh 592703b705cfSriastradh for (n = 1; n < num_threads; n++) { 592803b705cfSriastradh threads[n] = threads[0]; 592903b705cfSriastradh threads[n].extents.y1 = y; 593003b705cfSriastradh threads[n].extents.y2 = y += h; 593103b705cfSriastradh 593203b705cfSriastradh sna_threads_run(inplace_x8r8g8b8_thread, &threads[n]); 593303b705cfSriastradh } 593403b705cfSriastradh 593503b705cfSriastradh threads[0].extents.y1 = y; 593603b705cfSriastradh threads[0].extents.y2 = region.extents.y2; 593703b705cfSriastradh inplace_x8r8g8b8_thread(&threads[0]); 593803b705cfSriastradh 593903b705cfSriastradh sna_threads_wait(); 594003b705cfSriastradh } 594103b705cfSriastradh 594203b705cfSriastradh return true; 594303b705cfSriastradh} 594403b705cfSriastradh 594503b705cfSriastradhstruct inplace_thread { 594603b705cfSriastradh xTrapezoid *traps; 594703b705cfSriastradh RegionPtr clip; 594803b705cfSriastradh span_func_t span; 594903b705cfSriastradh struct inplace inplace; 595003b705cfSriastradh BoxRec extents; 595103b705cfSriastradh int dx, dy; 595203b705cfSriastradh int draw_x, draw_y; 595303b705cfSriastradh bool unbounded; 595403b705cfSriastradh int ntrap; 595503b705cfSriastradh}; 595603b705cfSriastradh 595703b705cfSriastradhstatic void inplace_thread(void *arg) 595803b705cfSriastradh{ 595903b705cfSriastradh struct inplace_thread *thread = arg; 596003b705cfSriastradh struct tor tor; 596103b705cfSriastradh int n; 596203b705cfSriastradh 596303b705cfSriastradh if (!tor_init(&tor, &thread->extents, 2*thread->ntrap)) 596403b705cfSriastradh return; 596503b705cfSriastradh 596603b705cfSriastradh for (n = 0; n < thread->ntrap; n++) { 596703b705cfSriastradh xTrapezoid t; 596803b705cfSriastradh 596903b705cfSriastradh if (!project_trapezoid_onto_grid(&thread->traps[n], thread->dx, thread->dy, &t)) 597003b705cfSriastradh continue; 597103b705cfSriastradh 597203b705cfSriastradh if (pixman_fixed_to_int(thread->traps[n].top) >= thread->extents.y2 - thread->draw_y || 597303b705cfSriastradh pixman_fixed_to_int(thread->traps[n].bottom) < thread->extents.y1 - thread->draw_y) 597403b705cfSriastradh continue; 597503b705cfSriastradh 597603b705cfSriastradh tor_add_edge(&tor, &t, &t.left, 1); 597703b705cfSriastradh tor_add_edge(&tor, &t, &t.right, -1); 597803b705cfSriastradh } 597903b705cfSriastradh 598003b705cfSriastradh tor_render(NULL, &tor, (void*)&thread->inplace, 598103b705cfSriastradh thread->clip, thread->span, thread->unbounded); 598203b705cfSriastradh 598303b705cfSriastradh tor_fini(&tor); 598403b705cfSriastradh} 598503b705cfSriastradh 598603b705cfSriastradhstatic bool 598703b705cfSriastradhtrapezoid_span_inplace(struct sna *sna, 598803b705cfSriastradh CARD8 op, PicturePtr src, PicturePtr dst, 598903b705cfSriastradh PictFormatPtr maskFormat, INT16 src_x, INT16 src_y, 599003b705cfSriastradh int ntrap, xTrapezoid *traps, 599103b705cfSriastradh bool fallback) 599203b705cfSriastradh{ 599303b705cfSriastradh struct inplace inplace; 599403b705cfSriastradh span_func_t span; 599503b705cfSriastradh PixmapPtr pixmap; 599603b705cfSriastradh struct sna_pixmap *priv; 599703b705cfSriastradh RegionRec region; 599803b705cfSriastradh uint32_t color; 599903b705cfSriastradh bool unbounded; 600003b705cfSriastradh int16_t dst_x, dst_y; 600103b705cfSriastradh int dx, dy; 600203b705cfSriastradh int num_threads, n; 600303b705cfSriastradh 600403b705cfSriastradh if (NO_SCAN_CONVERTER) 600503b705cfSriastradh return false; 600603b705cfSriastradh 600703b705cfSriastradh if (dst->polyMode == PolyModePrecise && !is_mono(dst, maskFormat)) { 600803b705cfSriastradh DBG(("%s: fallback -- precise rasterisation requested\n", 600903b705cfSriastradh __FUNCTION__)); 601003b705cfSriastradh return false; 601103b705cfSriastradh } 601203b705cfSriastradh if (dst->alphaMap) { 601303b705cfSriastradh DBG(("%s: fallback -- dst alphamap\n", 601403b705cfSriastradh __FUNCTION__)); 601503b705cfSriastradh return false; 601603b705cfSriastradh } 601703b705cfSriastradh 601803b705cfSriastradh if (!fallback && is_gpu(sna, dst->pDrawable, PREFER_GPU_SPANS)) { 601903b705cfSriastradh DBG(("%s: fallback -- can not perform operation in place, destination busy\n", 602003b705cfSriastradh __FUNCTION__)); 602103b705cfSriastradh 602203b705cfSriastradh return false; 602303b705cfSriastradh } 602403b705cfSriastradh 602503b705cfSriastradh if (is_mono(dst, maskFormat)) 602603b705cfSriastradh return trapezoid_span_mono_inplace(sna, op, src, dst, 602703b705cfSriastradh src_x, src_y, ntrap, traps); 602803b705cfSriastradh 602903b705cfSriastradh if (dst->format == PICT_a8r8g8b8 || dst->format == PICT_x8r8g8b8) 603003b705cfSriastradh return trapezoid_span_inplace__x8r8g8b8(op, dst, 603103b705cfSriastradh src, src_x, src_y, 603203b705cfSriastradh maskFormat, 603303b705cfSriastradh ntrap, traps); 603403b705cfSriastradh 603503b705cfSriastradh if (!sna_picture_is_solid(src, &color)) { 603603b705cfSriastradh DBG(("%s: fallback -- can not perform operation in place, requires solid source\n", 603703b705cfSriastradh __FUNCTION__)); 603803b705cfSriastradh return false; 603903b705cfSriastradh } 604003b705cfSriastradh 604103b705cfSriastradh if (dst->format != PICT_a8) { 604203b705cfSriastradh DBG(("%s: fallback -- can not perform operation in place, format=%x\n", 604303b705cfSriastradh __FUNCTION__, dst->format)); 604403b705cfSriastradh return false; 604503b705cfSriastradh } 604603b705cfSriastradh 604703b705cfSriastradh pixmap = get_drawable_pixmap(dst->pDrawable); 604803b705cfSriastradh 604903b705cfSriastradh unbounded = false; 605003b705cfSriastradh priv = sna_pixmap(pixmap); 605103b705cfSriastradh if (priv) { 605203b705cfSriastradh switch (op) { 605303b705cfSriastradh case PictOpAdd: 605403b705cfSriastradh if (priv->clear && priv->clear_color == 0) { 605503b705cfSriastradh unbounded = true; 605603b705cfSriastradh op = PictOpSrc; 605703b705cfSriastradh } 605803b705cfSriastradh if ((color >> 24) == 0) 605903b705cfSriastradh return true; 606003b705cfSriastradh break; 606103b705cfSriastradh case PictOpIn: 606203b705cfSriastradh if (priv->clear && priv->clear_color == 0) 606303b705cfSriastradh return true; 606403b705cfSriastradh if (priv->clear && priv->clear_color == 0xff) 606503b705cfSriastradh op = PictOpSrc; 606603b705cfSriastradh unbounded = true; 606703b705cfSriastradh break; 606803b705cfSriastradh case PictOpSrc: 606903b705cfSriastradh unbounded = true; 607003b705cfSriastradh break; 607103b705cfSriastradh default: 607203b705cfSriastradh DBG(("%s: fallback -- can not perform op [%d] in place\n", 607303b705cfSriastradh __FUNCTION__, op)); 607403b705cfSriastradh return false; 607503b705cfSriastradh } 607603b705cfSriastradh } else { 607703b705cfSriastradh switch (op) { 607803b705cfSriastradh case PictOpAdd: 607903b705cfSriastradh if ((color >> 24) == 0) 608003b705cfSriastradh return true; 608103b705cfSriastradh break; 608203b705cfSriastradh case PictOpIn: 608303b705cfSriastradh case PictOpSrc: 608403b705cfSriastradh unbounded = true; 608503b705cfSriastradh break; 608603b705cfSriastradh default: 608703b705cfSriastradh DBG(("%s: fallback -- can not perform op [%d] in place\n", 608803b705cfSriastradh __FUNCTION__, op)); 608903b705cfSriastradh return false; 609003b705cfSriastradh } 609103b705cfSriastradh } 609203b705cfSriastradh 609303b705cfSriastradh DBG(("%s: format=%x, op=%d, color=%x\n", 609403b705cfSriastradh __FUNCTION__, dst->format, op, color)); 609503b705cfSriastradh 609603b705cfSriastradh if (maskFormat == NULL && ntrap > 1) { 609703b705cfSriastradh DBG(("%s: individual rasterisation requested\n", 609803b705cfSriastradh __FUNCTION__)); 609903b705cfSriastradh do { 610003b705cfSriastradh /* XXX unwind errors? */ 610103b705cfSriastradh if (!trapezoid_span_inplace(sna, op, src, dst, NULL, 610203b705cfSriastradh src_x, src_y, 1, traps++, 610303b705cfSriastradh fallback)) 610403b705cfSriastradh return false; 610503b705cfSriastradh } while (--ntrap); 610603b705cfSriastradh return true; 610703b705cfSriastradh } 610803b705cfSriastradh 610903b705cfSriastradh trapezoids_bounds(ntrap, traps, ®ion.extents); 611003b705cfSriastradh if (region.extents.y1 >= region.extents.y2 || 611103b705cfSriastradh region.extents.x1 >= region.extents.x2) 611203b705cfSriastradh return true; 611303b705cfSriastradh 611403b705cfSriastradh DBG(("%s: extents (%d, %d), (%d, %d)\n", 611503b705cfSriastradh __FUNCTION__, 611603b705cfSriastradh region.extents.x1, region.extents.y1, 611703b705cfSriastradh region.extents.x2, region.extents.y2)); 611803b705cfSriastradh 611903b705cfSriastradh if (!sna_compute_composite_extents(®ion.extents, 612003b705cfSriastradh NULL, NULL, dst, 612103b705cfSriastradh 0, 0, 612203b705cfSriastradh 0, 0, 612303b705cfSriastradh region.extents.x1, region.extents.y1, 612403b705cfSriastradh region.extents.x2 - region.extents.x1, 612503b705cfSriastradh region.extents.y2 - region.extents.y1)) 612603b705cfSriastradh return true; 612703b705cfSriastradh 612803b705cfSriastradh DBG(("%s: clipped extents (%d, %d), (%d, %d)\n", 612903b705cfSriastradh __FUNCTION__, 613003b705cfSriastradh region.extents.x1, region.extents.y1, 613103b705cfSriastradh region.extents.x2, region.extents.y2)); 613203b705cfSriastradh 613303b705cfSriastradh if (op == PictOpSrc) { 613403b705cfSriastradh if (dst->pCompositeClip->data) 613503b705cfSriastradh span = tor_blt_src_clipped; 613603b705cfSriastradh else 613703b705cfSriastradh span = tor_blt_src; 613803b705cfSriastradh } else if (op == PictOpIn) { 613903b705cfSriastradh if (dst->pCompositeClip->data) 614003b705cfSriastradh span = tor_blt_in_clipped; 614103b705cfSriastradh else 614203b705cfSriastradh span = tor_blt_in; 614303b705cfSriastradh } else { 614403b705cfSriastradh assert(op == PictOpAdd); 614503b705cfSriastradh if (dst->pCompositeClip->data) 614603b705cfSriastradh span = tor_blt_add_clipped; 614703b705cfSriastradh else 614803b705cfSriastradh span = tor_blt_add; 614903b705cfSriastradh } 615003b705cfSriastradh 615103b705cfSriastradh DBG(("%s: move-to-cpu\n", __FUNCTION__)); 615203b705cfSriastradh region.data = NULL; 615303b705cfSriastradh if (!sna_drawable_move_region_to_cpu(dst->pDrawable, ®ion, 615403b705cfSriastradh op == PictOpSrc ? MOVE_WRITE | MOVE_INPLACE_HINT : MOVE_WRITE | MOVE_READ)) 615503b705cfSriastradh return true; 615603b705cfSriastradh 615703b705cfSriastradh dx = dst->pDrawable->x * FAST_SAMPLES_X; 615803b705cfSriastradh dy = dst->pDrawable->y * FAST_SAMPLES_Y; 615903b705cfSriastradh 616003b705cfSriastradh 616103b705cfSriastradh inplace.ptr = pixmap->devPrivate.ptr; 616203b705cfSriastradh if (get_drawable_deltas(dst->pDrawable, pixmap, &dst_x, &dst_y)) 616303b705cfSriastradh inplace.ptr += dst_y * pixmap->devKind + dst_x; 616403b705cfSriastradh inplace.stride = pixmap->devKind; 616503b705cfSriastradh inplace.opacity = color >> 24; 616603b705cfSriastradh 616703b705cfSriastradh num_threads = sna_use_threads(region.extents.x2 - region.extents.x1, 616803b705cfSriastradh region.extents.y2 - region.extents.y1, 616903b705cfSriastradh 16); 617003b705cfSriastradh if (num_threads == 1) { 617103b705cfSriastradh struct tor tor; 617203b705cfSriastradh 617303b705cfSriastradh if (!tor_init(&tor, ®ion.extents, 2*ntrap)) 617403b705cfSriastradh return true; 617503b705cfSriastradh 617603b705cfSriastradh for (n = 0; n < ntrap; n++) { 617703b705cfSriastradh xTrapezoid t; 617803b705cfSriastradh 617903b705cfSriastradh if (!project_trapezoid_onto_grid(&traps[n], dx, dy, &t)) 618003b705cfSriastradh continue; 618103b705cfSriastradh 618203b705cfSriastradh if (pixman_fixed_to_int(traps[n].top) >= region.extents.y2 - dst->pDrawable->y || 618303b705cfSriastradh pixman_fixed_to_int(traps[n].bottom) < region.extents.y1 - dst->pDrawable->y) 618403b705cfSriastradh continue; 618503b705cfSriastradh 618603b705cfSriastradh tor_add_edge(&tor, &t, &t.left, 1); 618703b705cfSriastradh tor_add_edge(&tor, &t, &t.right, -1); 618803b705cfSriastradh } 618903b705cfSriastradh 619003b705cfSriastradh tor_render(NULL, &tor, (void*)&inplace, 619103b705cfSriastradh dst->pCompositeClip, span, unbounded); 619203b705cfSriastradh 619303b705cfSriastradh tor_fini(&tor); 619403b705cfSriastradh } else { 619503b705cfSriastradh struct inplace_thread threads[num_threads]; 619603b705cfSriastradh int y, h; 619703b705cfSriastradh 619803b705cfSriastradh DBG(("%s: using %d threads for inplace compositing %dx%d\n", 619903b705cfSriastradh __FUNCTION__, num_threads, 620003b705cfSriastradh region.extents.x2 - region.extents.x1, 620103b705cfSriastradh region.extents.y2 - region.extents.y1)); 620203b705cfSriastradh 620303b705cfSriastradh threads[0].traps = traps; 620403b705cfSriastradh threads[0].ntrap = ntrap; 620503b705cfSriastradh threads[0].inplace = inplace; 620603b705cfSriastradh threads[0].extents = region.extents; 620703b705cfSriastradh threads[0].clip = dst->pCompositeClip; 620803b705cfSriastradh threads[0].span = span; 620903b705cfSriastradh threads[0].unbounded = unbounded; 621003b705cfSriastradh threads[0].dx = dx; 621103b705cfSriastradh threads[0].dy = dy; 621203b705cfSriastradh threads[0].draw_x = dst->pDrawable->x; 621303b705cfSriastradh threads[0].draw_y = dst->pDrawable->y; 621403b705cfSriastradh 621503b705cfSriastradh y = region.extents.y1; 621603b705cfSriastradh h = region.extents.y2 - region.extents.y1; 621703b705cfSriastradh h = (h + num_threads - 1) / num_threads; 621803b705cfSriastradh 621903b705cfSriastradh for (n = 1; n < num_threads; n++) { 622003b705cfSriastradh threads[n] = threads[0]; 622103b705cfSriastradh threads[n].extents.y1 = y; 622203b705cfSriastradh threads[n].extents.y2 = y += h; 622303b705cfSriastradh 622403b705cfSriastradh sna_threads_run(inplace_thread, &threads[n]); 622503b705cfSriastradh } 622603b705cfSriastradh 622703b705cfSriastradh threads[0].extents.y1 = y; 622803b705cfSriastradh threads[0].extents.y2 = region.extents.y2; 622903b705cfSriastradh inplace_thread(&threads[0]); 623003b705cfSriastradh 623103b705cfSriastradh sna_threads_wait(); 623203b705cfSriastradh } 623303b705cfSriastradh 623403b705cfSriastradh return true; 623503b705cfSriastradh} 623603b705cfSriastradh 623703b705cfSriastradhstatic bool 623803b705cfSriastradhtrapezoid_span_fallback(CARD8 op, PicturePtr src, PicturePtr dst, 623903b705cfSriastradh PictFormatPtr maskFormat, INT16 src_x, INT16 src_y, 624003b705cfSriastradh int ntrap, xTrapezoid *traps) 624103b705cfSriastradh{ 624203b705cfSriastradh struct tor tor; 624303b705cfSriastradh ScreenPtr screen = dst->pDrawable->pScreen; 624403b705cfSriastradh PixmapPtr scratch; 624503b705cfSriastradh PicturePtr mask; 624603b705cfSriastradh BoxRec extents; 624703b705cfSriastradh int16_t dst_x, dst_y; 624803b705cfSriastradh int dx, dy; 624903b705cfSriastradh int error, n; 625003b705cfSriastradh 625103b705cfSriastradh if (NO_SCAN_CONVERTER) 625203b705cfSriastradh return false; 625303b705cfSriastradh 625403b705cfSriastradh if (dst->polyMode == PolyModePrecise && !is_mono(dst, maskFormat)) { 625503b705cfSriastradh DBG(("%s: fallback -- precise rasterisation requested\n", 625603b705cfSriastradh __FUNCTION__)); 625703b705cfSriastradh return false; 625803b705cfSriastradh } 625903b705cfSriastradh 626003b705cfSriastradh if (maskFormat == NULL && ntrap > 1) { 626103b705cfSriastradh DBG(("%s: individual rasterisation requested\n", 626203b705cfSriastradh __FUNCTION__)); 626303b705cfSriastradh do { 626403b705cfSriastradh /* XXX unwind errors? */ 626503b705cfSriastradh if (!trapezoid_span_fallback(op, src, dst, NULL, 626603b705cfSriastradh src_x, src_y, 1, traps++)) 626703b705cfSriastradh return false; 626803b705cfSriastradh } while (--ntrap); 626903b705cfSriastradh return true; 627003b705cfSriastradh } 627103b705cfSriastradh 627203b705cfSriastradh trapezoids_bounds(ntrap, traps, &extents); 627303b705cfSriastradh if (extents.y1 >= extents.y2 || extents.x1 >= extents.x2) 627403b705cfSriastradh return true; 627503b705cfSriastradh 627603b705cfSriastradh DBG(("%s: ntraps=%d, extents (%d, %d), (%d, %d)\n", 627703b705cfSriastradh __FUNCTION__, ntrap, extents.x1, extents.y1, extents.x2, extents.y2)); 627803b705cfSriastradh 627903b705cfSriastradh if (!sna_compute_composite_extents(&extents, 628003b705cfSriastradh src, NULL, dst, 628103b705cfSriastradh src_x, src_y, 628203b705cfSriastradh 0, 0, 628303b705cfSriastradh extents.x1, extents.y1, 628403b705cfSriastradh extents.x2 - extents.x1, 628503b705cfSriastradh extents.y2 - extents.y1)) 628603b705cfSriastradh return true; 628703b705cfSriastradh 628803b705cfSriastradh DBG(("%s: extents (%d, %d), (%d, %d)\n", 628903b705cfSriastradh __FUNCTION__, extents.x1, extents.y1, extents.x2, extents.y2)); 629003b705cfSriastradh 629103b705cfSriastradh extents.y2 -= extents.y1; 629203b705cfSriastradh extents.x2 -= extents.x1; 629303b705cfSriastradh extents.x1 -= dst->pDrawable->x; 629403b705cfSriastradh extents.y1 -= dst->pDrawable->y; 629503b705cfSriastradh dst_x = extents.x1; 629603b705cfSriastradh dst_y = extents.y1; 629703b705cfSriastradh dx = -extents.x1 * FAST_SAMPLES_X; 629803b705cfSriastradh dy = -extents.y1 * FAST_SAMPLES_Y; 629903b705cfSriastradh extents.x1 = extents.y1 = 0; 630003b705cfSriastradh 630103b705cfSriastradh DBG(("%s: mask (%dx%d), dx=(%d, %d)\n", 630203b705cfSriastradh __FUNCTION__, extents.x2, extents.y2, dx, dy)); 630303b705cfSriastradh scratch = sna_pixmap_create_unattached(screen, 630403b705cfSriastradh extents.x2, extents.y2, 8); 630503b705cfSriastradh if (!scratch) 630603b705cfSriastradh return true; 630703b705cfSriastradh 630803b705cfSriastradh DBG(("%s: created buffer %p, stride %d\n", 630903b705cfSriastradh __FUNCTION__, scratch->devPrivate.ptr, scratch->devKind)); 631003b705cfSriastradh 631103b705cfSriastradh if (!tor_init(&tor, &extents, 2*ntrap)) { 631203b705cfSriastradh sna_pixmap_destroy(scratch); 631303b705cfSriastradh return true; 631403b705cfSriastradh } 631503b705cfSriastradh 631603b705cfSriastradh for (n = 0; n < ntrap; n++) { 631703b705cfSriastradh xTrapezoid t; 631803b705cfSriastradh 631903b705cfSriastradh if (!project_trapezoid_onto_grid(&traps[n], dx, dy, &t)) 632003b705cfSriastradh continue; 632103b705cfSriastradh 632203b705cfSriastradh if (pixman_fixed_to_int(traps[n].top) - dst_y >= extents.y2 || 632303b705cfSriastradh pixman_fixed_to_int(traps[n].bottom) - dst_y < 0) 632403b705cfSriastradh continue; 632503b705cfSriastradh 632603b705cfSriastradh tor_add_edge(&tor, &t, &t.left, 1); 632703b705cfSriastradh tor_add_edge(&tor, &t, &t.right, -1); 632803b705cfSriastradh } 632903b705cfSriastradh 633003b705cfSriastradh if (extents.x2 <= TOR_INPLACE_SIZE) { 633103b705cfSriastradh tor_inplace(&tor, scratch, is_mono(dst, maskFormat), NULL); 633203b705cfSriastradh } else { 633303b705cfSriastradh tor_render(NULL, &tor, 633403b705cfSriastradh scratch->devPrivate.ptr, 633503b705cfSriastradh (void *)(intptr_t)scratch->devKind, 633603b705cfSriastradh is_mono(dst, maskFormat) ? tor_blt_mask_mono : tor_blt_mask, 633703b705cfSriastradh true); 633803b705cfSriastradh } 633903b705cfSriastradh tor_fini(&tor); 634003b705cfSriastradh 634103b705cfSriastradh mask = CreatePicture(0, &scratch->drawable, 634203b705cfSriastradh PictureMatchFormat(screen, 8, PICT_a8), 634303b705cfSriastradh 0, 0, serverClient, &error); 634403b705cfSriastradh if (mask) { 634503b705cfSriastradh RegionRec region; 634603b705cfSriastradh 634703b705cfSriastradh region.extents.x1 = dst_x + dst->pDrawable->x; 634803b705cfSriastradh region.extents.y1 = dst_y + dst->pDrawable->y; 634903b705cfSriastradh region.extents.x2 = region.extents.x1 + extents.x2; 635003b705cfSriastradh region.extents.y2 = region.extents.y1 + extents.y2; 635103b705cfSriastradh region.data = NULL; 635203b705cfSriastradh 635303b705cfSriastradh DBG(("%s: fbComposite()\n", __FUNCTION__)); 635403b705cfSriastradh sna_composite_fb(op, src, mask, dst, ®ion, 635503b705cfSriastradh src_x + dst_x - pixman_fixed_to_int(traps[0].left.p1.x), 635603b705cfSriastradh src_y + dst_y - pixman_fixed_to_int(traps[0].left.p1.y), 635703b705cfSriastradh 0, 0, 635803b705cfSriastradh dst_x, dst_y, 635903b705cfSriastradh extents.x2, extents.y2); 636003b705cfSriastradh 636103b705cfSriastradh FreePicture(mask, 0); 636203b705cfSriastradh } 636303b705cfSriastradh sna_pixmap_destroy(scratch); 636403b705cfSriastradh 636503b705cfSriastradh return true; 636603b705cfSriastradh} 636703b705cfSriastradh 636803b705cfSriastradhvoid 636903b705cfSriastradhsna_composite_trapezoids(CARD8 op, 637003b705cfSriastradh PicturePtr src, 637103b705cfSriastradh PicturePtr dst, 637203b705cfSriastradh PictFormatPtr maskFormat, 637303b705cfSriastradh INT16 xSrc, INT16 ySrc, 637403b705cfSriastradh int ntrap, xTrapezoid *traps) 637503b705cfSriastradh{ 637603b705cfSriastradh PixmapPtr pixmap = get_drawable_pixmap(dst->pDrawable); 637703b705cfSriastradh struct sna *sna = to_sna_from_pixmap(pixmap); 637803b705cfSriastradh struct sna_pixmap *priv; 637903b705cfSriastradh bool rectilinear, pixel_aligned, force_fallback; 638003b705cfSriastradh unsigned flags; 638103b705cfSriastradh int n; 638203b705cfSriastradh 638303b705cfSriastradh DBG(("%s(op=%d, src=(%d, %d), mask=%08x, ntrap=%d)\n", __FUNCTION__, 638403b705cfSriastradh op, xSrc, ySrc, 638503b705cfSriastradh maskFormat ? (int)maskFormat->format : 0, 638603b705cfSriastradh ntrap)); 638703b705cfSriastradh 638803b705cfSriastradh if (ntrap == 0) 638903b705cfSriastradh return; 639003b705cfSriastradh 639103b705cfSriastradh if (NO_ACCEL) 639203b705cfSriastradh goto fallback; 639303b705cfSriastradh 639403b705cfSriastradh if (wedged(sna)) { 639503b705cfSriastradh DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 639603b705cfSriastradh goto fallback; 639703b705cfSriastradh } 639803b705cfSriastradh 639903b705cfSriastradh if (dst->alphaMap) { 640003b705cfSriastradh DBG(("%s: fallback -- dst alpha map\n", __FUNCTION__)); 640103b705cfSriastradh goto fallback; 640203b705cfSriastradh } 640303b705cfSriastradh 640403b705cfSriastradh priv = sna_pixmap(pixmap); 640503b705cfSriastradh if (priv == NULL) { 640603b705cfSriastradh DBG(("%s: fallback -- dst is unattached\n", __FUNCTION__)); 640703b705cfSriastradh goto fallback; 640803b705cfSriastradh } 640903b705cfSriastradh 641003b705cfSriastradh force_fallback = FORCE_FALLBACK > 0; 641103b705cfSriastradh if ((too_small(priv) || DAMAGE_IS_ALL(priv->cpu_damage)) && 641203b705cfSriastradh !picture_is_gpu(sna, src) && untransformed(src)) { 641303b705cfSriastradh DBG(("%s: force fallbacks --too small, %dx%d? %d, all-cpu? %d, src-is-cpu? %d\n", 641403b705cfSriastradh __FUNCTION__, 641503b705cfSriastradh dst->pDrawable->width, 641603b705cfSriastradh dst->pDrawable->height, 641703b705cfSriastradh too_small(priv), 641803b705cfSriastradh (int)DAMAGE_IS_ALL(priv->cpu_damage), 641903b705cfSriastradh !picture_is_gpu(sna, src))); 642003b705cfSriastradh force_fallback = true; 642103b705cfSriastradh } 642203b705cfSriastradh if (FORCE_FALLBACK < 0) 642303b705cfSriastradh force_fallback = false; 642403b705cfSriastradh 642503b705cfSriastradh /* scan through for fast rectangles */ 642603b705cfSriastradh rectilinear = pixel_aligned = true; 642703b705cfSriastradh if (is_mono(dst, maskFormat)) { 642803b705cfSriastradh for (n = 0; n < ntrap && rectilinear; n++) { 642903b705cfSriastradh int lx1 = pixman_fixed_to_int(traps[n].left.p1.x + pixman_fixed_1_minus_e/2); 643003b705cfSriastradh int lx2 = pixman_fixed_to_int(traps[n].left.p2.x + pixman_fixed_1_minus_e/2); 643103b705cfSriastradh int rx1 = pixman_fixed_to_int(traps[n].right.p1.x + pixman_fixed_1_minus_e/2); 643203b705cfSriastradh int rx2 = pixman_fixed_to_int(traps[n].right.p2.x + pixman_fixed_1_minus_e/2); 643303b705cfSriastradh rectilinear &= lx1 == lx2 && rx1 == rx2; 643403b705cfSriastradh } 643503b705cfSriastradh } else if (dst->polyMode != PolyModePrecise) { 643603b705cfSriastradh for (n = 0; n < ntrap && rectilinear; n++) { 643703b705cfSriastradh int lx1 = pixman_fixed_to_grid(traps[n].left.p1.x); 643803b705cfSriastradh int lx2 = pixman_fixed_to_grid(traps[n].left.p2.x); 643903b705cfSriastradh int rx1 = pixman_fixed_to_grid(traps[n].right.p1.x); 644003b705cfSriastradh int rx2 = pixman_fixed_to_grid(traps[n].right.p2.x); 644103b705cfSriastradh int top = pixman_fixed_to_grid(traps[n].top); 644203b705cfSriastradh int bot = pixman_fixed_to_grid(traps[n].bottom); 644303b705cfSriastradh 644403b705cfSriastradh rectilinear &= lx1 == lx2 && rx1 == rx2; 644503b705cfSriastradh pixel_aligned &= ((top | bot | lx1 | lx2 | rx1 | rx2) & FAST_SAMPLES_mask) == 0; 644603b705cfSriastradh } 644703b705cfSriastradh } else { 644803b705cfSriastradh for (n = 0; n < ntrap && rectilinear; n++) { 644903b705cfSriastradh rectilinear &= 645003b705cfSriastradh traps[n].left.p1.x == traps[n].left.p2.x && 645103b705cfSriastradh traps[n].right.p1.x == traps[n].right.p2.x; 645203b705cfSriastradh pixel_aligned &= 645303b705cfSriastradh ((traps[n].top | traps[n].bottom | 645403b705cfSriastradh traps[n].left.p1.x | traps[n].left.p2.x | 645503b705cfSriastradh traps[n].right.p1.x | traps[n].right.p2.x) 645603b705cfSriastradh & pixman_fixed_1_minus_e) == 0; 645703b705cfSriastradh } 645803b705cfSriastradh } 645903b705cfSriastradh 646003b705cfSriastradh DBG(("%s: rectilinear? %d, pixel-aligned? %d\n", 646103b705cfSriastradh __FUNCTION__, rectilinear, pixel_aligned)); 646203b705cfSriastradh flags = 0; 646303b705cfSriastradh if (rectilinear) { 646403b705cfSriastradh if (pixel_aligned) { 646503b705cfSriastradh if (composite_aligned_boxes(sna, op, src, dst, 646603b705cfSriastradh maskFormat, 646703b705cfSriastradh xSrc, ySrc, 646803b705cfSriastradh ntrap, traps, 646903b705cfSriastradh force_fallback)) 647003b705cfSriastradh return; 647103b705cfSriastradh } else { 647203b705cfSriastradh if (composite_unaligned_boxes(sna, op, src, dst, 647303b705cfSriastradh maskFormat, 647403b705cfSriastradh xSrc, ySrc, 647503b705cfSriastradh ntrap, traps, 647603b705cfSriastradh force_fallback)) 647703b705cfSriastradh return; 647803b705cfSriastradh } 647903b705cfSriastradh flags |= COMPOSITE_SPANS_RECTILINEAR; 648003b705cfSriastradh } 648103b705cfSriastradh 648203b705cfSriastradh if (force_fallback) 648303b705cfSriastradh goto fallback; 648403b705cfSriastradh 648503b705cfSriastradh if (is_mono(dst, maskFormat) && 648603b705cfSriastradh mono_trapezoids_span_converter(sna, op, src, dst, 648703b705cfSriastradh xSrc, ySrc, 648803b705cfSriastradh ntrap, traps)) 648903b705cfSriastradh return; 649003b705cfSriastradh 649103b705cfSriastradh if (trapezoid_spans_maybe_inplace(sna, op, src, dst, maskFormat)) { 649203b705cfSriastradh flags |= COMPOSITE_SPANS_INPLACE_HINT; 649303b705cfSriastradh if (trapezoid_span_inplace(sna, op, src, dst, maskFormat, 649403b705cfSriastradh xSrc, ySrc, ntrap, traps, 649503b705cfSriastradh false)) 649603b705cfSriastradh return; 649703b705cfSriastradh } 649803b705cfSriastradh 649903b705cfSriastradh if (trapezoid_span_converter(sna, op, src, dst, maskFormat, flags, 650003b705cfSriastradh xSrc, ySrc, ntrap, traps)) 650103b705cfSriastradh return; 650203b705cfSriastradh 650303b705cfSriastradh if (trapezoid_span_inplace(sna, op, src, dst, maskFormat, 650403b705cfSriastradh xSrc, ySrc, ntrap, traps, 650503b705cfSriastradh false)) 650603b705cfSriastradh return; 650703b705cfSriastradh 650803b705cfSriastradh if (trapezoid_mask_converter(op, src, dst, maskFormat, 650903b705cfSriastradh xSrc, ySrc, ntrap, traps)) 651003b705cfSriastradh return; 651103b705cfSriastradh 651203b705cfSriastradhfallback: 651303b705cfSriastradh if (trapezoid_span_inplace(sna, op, src, dst, maskFormat, 651403b705cfSriastradh xSrc, ySrc, ntrap, traps, 651503b705cfSriastradh true)) 651603b705cfSriastradh return; 651703b705cfSriastradh 651803b705cfSriastradh if (trapezoid_span_fallback(op, src, dst, maskFormat, 651903b705cfSriastradh xSrc, ySrc, ntrap, traps)) 652003b705cfSriastradh return; 652103b705cfSriastradh 652203b705cfSriastradh if (trapezoids_inplace_fallback(sna, op, src, dst, maskFormat, 652303b705cfSriastradh ntrap, traps)) 652403b705cfSriastradh return; 652503b705cfSriastradh 652603b705cfSriastradh DBG(("%s: fallback mask=%08x, ntrap=%d\n", __FUNCTION__, 652703b705cfSriastradh maskFormat ? (unsigned)maskFormat->format : 0, ntrap)); 652803b705cfSriastradh trapezoids_fallback(sna, op, src, dst, maskFormat, 652903b705cfSriastradh xSrc, ySrc, 653003b705cfSriastradh ntrap, traps); 653103b705cfSriastradh} 653203b705cfSriastradh 653303b705cfSriastradhstatic inline bool 653403b705cfSriastradhproject_trap_onto_grid(const xTrap *in, 653503b705cfSriastradh int dx, int dy, 653603b705cfSriastradh xTrap *out) 653703b705cfSriastradh{ 653803b705cfSriastradh out->top.l = dx + pixman_fixed_to_grid(in->top.l); 653903b705cfSriastradh out->top.r = dx + pixman_fixed_to_grid(in->top.r); 654003b705cfSriastradh out->top.y = dy + pixman_fixed_to_grid(in->top.y); 654103b705cfSriastradh 654203b705cfSriastradh out->bot.l = dx + pixman_fixed_to_grid(in->bot.l); 654303b705cfSriastradh out->bot.r = dx + pixman_fixed_to_grid(in->bot.r); 654403b705cfSriastradh out->bot.y = dy + pixman_fixed_to_grid(in->bot.y); 654503b705cfSriastradh 654603b705cfSriastradh return out->bot.y > out->top.y; 654703b705cfSriastradh} 654803b705cfSriastradh 654903b705cfSriastradhstatic bool 655003b705cfSriastradhmono_trap_span_converter(struct sna *sna, 655103b705cfSriastradh PicturePtr dst, 655203b705cfSriastradh INT16 x, INT16 y, 655303b705cfSriastradh int ntrap, xTrap *traps) 655403b705cfSriastradh{ 655503b705cfSriastradh struct mono mono; 655603b705cfSriastradh xRenderColor white; 655703b705cfSriastradh PicturePtr src; 655803b705cfSriastradh int error; 655903b705cfSriastradh int n; 656003b705cfSriastradh 656103b705cfSriastradh white.red = white.green = white.blue = white.alpha = 0xffff; 656203b705cfSriastradh src = CreateSolidPicture(0, &white, &error); 656303b705cfSriastradh if (src == NULL) 656403b705cfSriastradh return true; 656503b705cfSriastradh 656603b705cfSriastradh mono.clip = *dst->pCompositeClip; 656703b705cfSriastradh x += dst->pDrawable->x; 656803b705cfSriastradh y += dst->pDrawable->y; 656903b705cfSriastradh 657003b705cfSriastradh DBG(("%s: after clip -- extents (%d, %d), (%d, %d), delta=(%d, %d)\n", 657103b705cfSriastradh __FUNCTION__, 657203b705cfSriastradh mono.clip.extents.x1, mono.clip.extents.y1, 657303b705cfSriastradh mono.clip.extents.x2, mono.clip.extents.y2, 657403b705cfSriastradh x, y)); 657503b705cfSriastradh 657603b705cfSriastradh mono.sna = sna; 657703b705cfSriastradh if (!mono_init(&mono, 2*ntrap)) 657803b705cfSriastradh return false; 657903b705cfSriastradh 658003b705cfSriastradh for (n = 0; n < ntrap; n++) { 658103b705cfSriastradh xPointFixed p1, p2; 658203b705cfSriastradh 658303b705cfSriastradh if (pixman_fixed_to_int(traps[n].top.y) + y >= mono.clip.extents.y2 || 658403b705cfSriastradh pixman_fixed_to_int(traps[n].bot.y) + y < mono.clip.extents.y1) 658503b705cfSriastradh continue; 658603b705cfSriastradh 658703b705cfSriastradh p1.y = traps[n].top.y; 658803b705cfSriastradh p2.y = traps[n].bot.y; 658903b705cfSriastradh 659003b705cfSriastradh p1.x = traps[n].top.l; 659103b705cfSriastradh p2.x = traps[n].bot.l; 659203b705cfSriastradh mono_add_line(&mono, x, y, 659303b705cfSriastradh traps[n].top.y, traps[n].bot.y, 659403b705cfSriastradh &p1, &p2, 1); 659503b705cfSriastradh 659603b705cfSriastradh p1.x = traps[n].top.r; 659703b705cfSriastradh p2.x = traps[n].bot.r; 659803b705cfSriastradh mono_add_line(&mono, x, y, 659903b705cfSriastradh traps[n].top.y, traps[n].bot.y, 660003b705cfSriastradh &p1, &p2, -1); 660103b705cfSriastradh } 660203b705cfSriastradh 660303b705cfSriastradh memset(&mono.op, 0, sizeof(mono.op)); 660403b705cfSriastradh if (mono.sna->render.composite(mono.sna, PictOpAdd, src, NULL, dst, 660503b705cfSriastradh 0, 0, 660603b705cfSriastradh 0, 0, 660703b705cfSriastradh mono.clip.extents.x1, mono.clip.extents.y1, 660803b705cfSriastradh mono.clip.extents.x2 - mono.clip.extents.x1, 660903b705cfSriastradh mono.clip.extents.y2 - mono.clip.extents.y1, 661003b705cfSriastradh &mono.op)) { 661103b705cfSriastradh mono_render(&mono); 661203b705cfSriastradh mono.op.done(mono.sna, &mono.op); 661303b705cfSriastradh } 661403b705cfSriastradh 661503b705cfSriastradh mono_fini(&mono); 661603b705cfSriastradh FreePicture(src, 0); 661703b705cfSriastradh return true; 661803b705cfSriastradh} 661903b705cfSriastradh 662003b705cfSriastradhstatic bool 662103b705cfSriastradhtrap_span_converter(struct sna *sna, 662203b705cfSriastradh PicturePtr dst, 662303b705cfSriastradh INT16 src_x, INT16 src_y, 662403b705cfSriastradh int ntrap, xTrap *trap) 662503b705cfSriastradh{ 662603b705cfSriastradh struct sna_composite_spans_op tmp; 662703b705cfSriastradh struct tor tor; 662803b705cfSriastradh BoxRec extents; 662903b705cfSriastradh pixman_region16_t *clip; 663003b705cfSriastradh int dx, dy, n; 663103b705cfSriastradh 663203b705cfSriastradh if (NO_SCAN_CONVERTER) 663303b705cfSriastradh return false; 663403b705cfSriastradh 663503b705cfSriastradh if (dst->pDrawable->depth < 8) 663603b705cfSriastradh return false; 663703b705cfSriastradh 663803b705cfSriastradh if (dst->polyEdge == PolyEdgeSharp) 663903b705cfSriastradh return mono_trap_span_converter(sna, dst, src_x, src_y, ntrap, trap); 664003b705cfSriastradh 664103b705cfSriastradh if (!sna->render.check_composite_spans(sna, PictOpAdd, sna->render.white_picture, dst, 664203b705cfSriastradh dst->pCompositeClip->extents.x2 - dst->pCompositeClip->extents.x1, 664303b705cfSriastradh dst->pCompositeClip->extents.y2 - dst->pCompositeClip->extents.y1, 664403b705cfSriastradh 0)) { 664503b705cfSriastradh DBG(("%s: fallback -- composite spans not supported\n", 664603b705cfSriastradh __FUNCTION__)); 664703b705cfSriastradh return false; 664803b705cfSriastradh } 664903b705cfSriastradh 665003b705cfSriastradh clip = dst->pCompositeClip; 665103b705cfSriastradh extents = *RegionExtents(clip); 665203b705cfSriastradh dx = dst->pDrawable->x; 665303b705cfSriastradh dy = dst->pDrawable->y; 665403b705cfSriastradh 665503b705cfSriastradh DBG(("%s: after clip -- extents (%d, %d), (%d, %d), delta=(%d, %d)\n", 665603b705cfSriastradh __FUNCTION__, 665703b705cfSriastradh extents.x1, extents.y1, 665803b705cfSriastradh extents.x2, extents.y2, 665903b705cfSriastradh dx, dy)); 666003b705cfSriastradh 666103b705cfSriastradh memset(&tmp, 0, sizeof(tmp)); 666203b705cfSriastradh if (!sna->render.composite_spans(sna, PictOpAdd, sna->render.white_picture, dst, 666303b705cfSriastradh 0, 0, 666403b705cfSriastradh extents.x1, extents.y1, 666503b705cfSriastradh extents.x2 - extents.x1, 666603b705cfSriastradh extents.y2 - extents.y1, 666703b705cfSriastradh 0, 666803b705cfSriastradh &tmp)) { 666903b705cfSriastradh DBG(("%s: fallback -- composite spans render op not supported\n", 667003b705cfSriastradh __FUNCTION__)); 667103b705cfSriastradh return false; 667203b705cfSriastradh } 667303b705cfSriastradh 667403b705cfSriastradh dx *= FAST_SAMPLES_X; 667503b705cfSriastradh dy *= FAST_SAMPLES_Y; 667603b705cfSriastradh if (!tor_init(&tor, &extents, 2*ntrap)) 667703b705cfSriastradh goto skip; 667803b705cfSriastradh 667903b705cfSriastradh for (n = 0; n < ntrap; n++) { 668003b705cfSriastradh xTrap t; 668103b705cfSriastradh xPointFixed p1, p2; 668203b705cfSriastradh 668303b705cfSriastradh if (!project_trap_onto_grid(&trap[n], dx, dy, &t)) 668403b705cfSriastradh continue; 668503b705cfSriastradh 668603b705cfSriastradh if (pixman_fixed_to_int(trap[n].top.y) + dst->pDrawable->y >= extents.y2 || 668703b705cfSriastradh pixman_fixed_to_int(trap[n].bot.y) + dst->pDrawable->y < extents.y1) 668803b705cfSriastradh continue; 668903b705cfSriastradh 669003b705cfSriastradh p1.y = t.top.y; 669103b705cfSriastradh p2.y = t.bot.y; 669203b705cfSriastradh p1.x = t.top.l; 669303b705cfSriastradh p2.x = t.bot.l; 669403b705cfSriastradh polygon_add_line(tor.polygon, &p1, &p2); 669503b705cfSriastradh 669603b705cfSriastradh p1.y = t.bot.y; 669703b705cfSriastradh p2.y = t.top.y; 669803b705cfSriastradh p1.x = t.top.r; 669903b705cfSriastradh p2.x = t.bot.r; 670003b705cfSriastradh polygon_add_line(tor.polygon, &p1, &p2); 670103b705cfSriastradh } 670203b705cfSriastradh 670303b705cfSriastradh tor_render(sna, &tor, &tmp, clip, 670403b705cfSriastradh choose_span(&tmp, dst, NULL, clip), false); 670503b705cfSriastradh 670603b705cfSriastradh tor_fini(&tor); 670703b705cfSriastradhskip: 670803b705cfSriastradh tmp.done(sna, &tmp); 670903b705cfSriastradh return true; 671003b705cfSriastradh} 671103b705cfSriastradh 671203b705cfSriastradhstatic void mark_damaged(PixmapPtr pixmap, struct sna_pixmap *priv, 671303b705cfSriastradh BoxPtr box, int16_t x, int16_t y) 671403b705cfSriastradh{ 671503b705cfSriastradh box->x1 += x; box->x2 += x; 671603b705cfSriastradh box->y1 += y; box->y2 += y; 671703b705cfSriastradh if (box->x1 <= 0 && box->y1 <= 0 && 671803b705cfSriastradh box->x2 >= pixmap->drawable.width && 671903b705cfSriastradh box->y2 >= pixmap->drawable.height) { 672003b705cfSriastradh sna_damage_destroy(&priv->cpu_damage); 672103b705cfSriastradh sna_damage_all(&priv->gpu_damage, 672203b705cfSriastradh pixmap->drawable.width, 672303b705cfSriastradh pixmap->drawable.height); 672403b705cfSriastradh list_del(&priv->flush_list); 672503b705cfSriastradh } else { 672603b705cfSriastradh sna_damage_add_box(&priv->gpu_damage, box); 672703b705cfSriastradh sna_damage_subtract_box(&priv->cpu_damage, box); 672803b705cfSriastradh } 672903b705cfSriastradh} 673003b705cfSriastradh 673103b705cfSriastradhstatic bool 673203b705cfSriastradhtrap_mask_converter(struct sna *sna, 673303b705cfSriastradh PicturePtr picture, 673403b705cfSriastradh INT16 x, INT16 y, 673503b705cfSriastradh int ntrap, xTrap *trap) 673603b705cfSriastradh{ 673703b705cfSriastradh struct tor tor; 673803b705cfSriastradh ScreenPtr screen = picture->pDrawable->pScreen; 673903b705cfSriastradh PixmapPtr scratch, pixmap; 674003b705cfSriastradh struct sna_pixmap *priv; 674103b705cfSriastradh BoxRec extents; 674203b705cfSriastradh span_func_t span; 674303b705cfSriastradh int dx, dy, n; 674403b705cfSriastradh 674503b705cfSriastradh if (NO_SCAN_CONVERTER) 674603b705cfSriastradh return false; 674703b705cfSriastradh 674803b705cfSriastradh pixmap = get_drawable_pixmap(picture->pDrawable); 674903b705cfSriastradh priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_WRITE); 675003b705cfSriastradh if (priv == NULL) 675103b705cfSriastradh return false; 675203b705cfSriastradh 675303b705cfSriastradh /* XXX strict adherence to the Render specification */ 675403b705cfSriastradh if (picture->polyMode == PolyModePrecise && 675503b705cfSriastradh picture->polyEdge != PolyEdgeSharp) { 675603b705cfSriastradh DBG(("%s: fallback -- precise rasterisation requested\n", 675703b705cfSriastradh __FUNCTION__)); 675803b705cfSriastradh return false; 675903b705cfSriastradh } 676003b705cfSriastradh 676103b705cfSriastradh extents = *RegionExtents(picture->pCompositeClip); 676203b705cfSriastradh for (n = 0; n < ntrap; n++) { 676303b705cfSriastradh int v; 676403b705cfSriastradh 676503b705cfSriastradh v = x + pixman_fixed_integer_floor (MIN(trap[n].top.l, trap[n].bot.l)); 676603b705cfSriastradh if (v < extents.x1) 676703b705cfSriastradh extents.x1 = v; 676803b705cfSriastradh 676903b705cfSriastradh v = x + pixman_fixed_integer_ceil (MAX(trap[n].top.r, trap[n].bot.r)); 677003b705cfSriastradh if (v > extents.x2) 677103b705cfSriastradh extents.x2 = v; 677203b705cfSriastradh 677303b705cfSriastradh v = y + pixman_fixed_integer_floor (trap[n].top.y); 677403b705cfSriastradh if (v < extents.y1) 677503b705cfSriastradh extents.y1 = v; 677603b705cfSriastradh 677703b705cfSriastradh v = y + pixman_fixed_integer_ceil (trap[n].bot.y); 677803b705cfSriastradh if (v > extents.y2) 677903b705cfSriastradh extents.y2 = v; 678003b705cfSriastradh } 678103b705cfSriastradh 678203b705cfSriastradh DBG(("%s: extents (%d, %d), (%d, %d)\n", 678303b705cfSriastradh __FUNCTION__, extents.x1, extents.y1, extents.x2, extents.y2)); 678403b705cfSriastradh 678503b705cfSriastradh scratch = sna_pixmap_create_upload(screen, 678603b705cfSriastradh extents.x2-extents.x1, 678703b705cfSriastradh extents.y2-extents.y1, 678803b705cfSriastradh 8, KGEM_BUFFER_WRITE_INPLACE); 678903b705cfSriastradh if (!scratch) 679003b705cfSriastradh return true; 679103b705cfSriastradh 679203b705cfSriastradh dx = picture->pDrawable->x; 679303b705cfSriastradh dy = picture->pDrawable->y; 679403b705cfSriastradh dx *= FAST_SAMPLES_X; 679503b705cfSriastradh dy *= FAST_SAMPLES_Y; 679603b705cfSriastradh if (!tor_init(&tor, &extents, 2*ntrap)) { 679703b705cfSriastradh sna_pixmap_destroy(scratch); 679803b705cfSriastradh return true; 679903b705cfSriastradh } 680003b705cfSriastradh 680103b705cfSriastradh for (n = 0; n < ntrap; n++) { 680203b705cfSriastradh xTrap t; 680303b705cfSriastradh xPointFixed p1, p2; 680403b705cfSriastradh 680503b705cfSriastradh if (!project_trap_onto_grid(&trap[n], dx, dy, &t)) 680603b705cfSriastradh continue; 680703b705cfSriastradh 680803b705cfSriastradh if (pixman_fixed_to_int(trap[n].top.y) + picture->pDrawable->y >= extents.y2 || 680903b705cfSriastradh pixman_fixed_to_int(trap[n].bot.y) + picture->pDrawable->y < extents.y1) 681003b705cfSriastradh continue; 681103b705cfSriastradh 681203b705cfSriastradh p1.y = t.top.y; 681303b705cfSriastradh p2.y = t.bot.y; 681403b705cfSriastradh p1.x = t.top.l; 681503b705cfSriastradh p2.x = t.bot.l; 681603b705cfSriastradh polygon_add_line(tor.polygon, &p1, &p2); 681703b705cfSriastradh 681803b705cfSriastradh p1.y = t.bot.y; 681903b705cfSriastradh p2.y = t.top.y; 682003b705cfSriastradh p1.x = t.top.r; 682103b705cfSriastradh p2.x = t.bot.r; 682203b705cfSriastradh polygon_add_line(tor.polygon, &p1, &p2); 682303b705cfSriastradh } 682403b705cfSriastradh 682503b705cfSriastradh if (picture->polyEdge == PolyEdgeSharp) 682603b705cfSriastradh span = tor_blt_mask_mono; 682703b705cfSriastradh else 682803b705cfSriastradh span = tor_blt_mask; 682903b705cfSriastradh 683003b705cfSriastradh tor_render(NULL, &tor, 683103b705cfSriastradh scratch->devPrivate.ptr, 683203b705cfSriastradh (void *)(intptr_t)scratch->devKind, 683303b705cfSriastradh span, true); 683403b705cfSriastradh 683503b705cfSriastradh tor_fini(&tor); 683603b705cfSriastradh 683703b705cfSriastradh /* XXX clip boxes */ 683803b705cfSriastradh get_drawable_deltas(picture->pDrawable, pixmap, &x, &y); 683903b705cfSriastradh sna = to_sna_from_screen(screen); 684003b705cfSriastradh sna->render.copy_boxes(sna, GXcopy, 684103b705cfSriastradh scratch, __sna_pixmap_get_bo(scratch), -extents.x1, -extents.x1, 684203b705cfSriastradh pixmap, priv->gpu_bo, x, y, 684303b705cfSriastradh &extents, 1, 0); 684403b705cfSriastradh mark_damaged(pixmap, priv, &extents ,x, y); 684503b705cfSriastradh sna_pixmap_destroy(scratch); 684603b705cfSriastradh return true; 684703b705cfSriastradh} 684803b705cfSriastradh 684903b705cfSriastradhstatic bool 685003b705cfSriastradhtrap_upload(PicturePtr picture, 685103b705cfSriastradh INT16 x, INT16 y, 685203b705cfSriastradh int ntrap, xTrap *trap) 685303b705cfSriastradh{ 685403b705cfSriastradh ScreenPtr screen = picture->pDrawable->pScreen; 685503b705cfSriastradh struct sna *sna = to_sna_from_screen(screen); 685603b705cfSriastradh PixmapPtr pixmap = get_drawable_pixmap(picture->pDrawable); 685703b705cfSriastradh PixmapPtr scratch; 685803b705cfSriastradh struct sna_pixmap *priv; 685903b705cfSriastradh BoxRec extents; 686003b705cfSriastradh pixman_image_t *image; 686103b705cfSriastradh int width, height, depth; 686203b705cfSriastradh int n; 686303b705cfSriastradh 686403b705cfSriastradh priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_WRITE); 686503b705cfSriastradh if (priv == NULL) 686603b705cfSriastradh return false; 686703b705cfSriastradh 686803b705cfSriastradh extents = *RegionExtents(picture->pCompositeClip); 686903b705cfSriastradh for (n = 0; n < ntrap; n++) { 687003b705cfSriastradh int v; 687103b705cfSriastradh 687203b705cfSriastradh v = x + pixman_fixed_integer_floor (MIN(trap[n].top.l, trap[n].bot.l)); 687303b705cfSriastradh if (v < extents.x1) 687403b705cfSriastradh extents.x1 = v; 687503b705cfSriastradh 687603b705cfSriastradh v = x + pixman_fixed_integer_ceil (MAX(trap[n].top.r, trap[n].bot.r)); 687703b705cfSriastradh if (v > extents.x2) 687803b705cfSriastradh extents.x2 = v; 687903b705cfSriastradh 688003b705cfSriastradh v = y + pixman_fixed_integer_floor (trap[n].top.y); 688103b705cfSriastradh if (v < extents.y1) 688203b705cfSriastradh extents.y1 = v; 688303b705cfSriastradh 688403b705cfSriastradh v = y + pixman_fixed_integer_ceil (trap[n].bot.y); 688503b705cfSriastradh if (v > extents.y2) 688603b705cfSriastradh extents.y2 = v; 688703b705cfSriastradh } 688803b705cfSriastradh 688903b705cfSriastradh DBG(("%s: extents (%d, %d), (%d, %d)\n", 689003b705cfSriastradh __FUNCTION__, extents.x1, extents.y1, extents.x2, extents.y2)); 689103b705cfSriastradh 689203b705cfSriastradh width = extents.x2 - extents.x1; 689303b705cfSriastradh height = extents.y2 - extents.y1; 689403b705cfSriastradh depth = picture->pDrawable->depth; 689503b705cfSriastradh 689603b705cfSriastradh DBG(("%s: tmp (%dx%d) depth=%d\n", 689703b705cfSriastradh __FUNCTION__, width, height, depth)); 689803b705cfSriastradh scratch = sna_pixmap_create_upload(screen, 689903b705cfSriastradh width, height, depth, 690003b705cfSriastradh KGEM_BUFFER_WRITE); 690103b705cfSriastradh if (!scratch) 690203b705cfSriastradh return true; 690303b705cfSriastradh 690403b705cfSriastradh memset(scratch->devPrivate.ptr, 0, scratch->devKind*height); 690503b705cfSriastradh image = pixman_image_create_bits(picture->format, width, height, 690603b705cfSriastradh scratch->devPrivate.ptr, 690703b705cfSriastradh scratch->devKind); 690803b705cfSriastradh if (image) { 690903b705cfSriastradh pixman_add_traps (image, -extents.x1, -extents.y1, 691003b705cfSriastradh ntrap, (pixman_trap_t *)trap); 691103b705cfSriastradh 691203b705cfSriastradh pixman_image_unref(image); 691303b705cfSriastradh } 691403b705cfSriastradh 691503b705cfSriastradh /* XXX clip boxes */ 691603b705cfSriastradh get_drawable_deltas(picture->pDrawable, pixmap, &x, &y); 691703b705cfSriastradh sna->render.copy_boxes(sna, GXcopy, 691803b705cfSriastradh scratch, __sna_pixmap_get_bo(scratch), -extents.x1, -extents.x1, 691903b705cfSriastradh pixmap, priv->gpu_bo, x, y, 692003b705cfSriastradh &extents, 1, 0); 692103b705cfSriastradh mark_damaged(pixmap, priv, &extents, x, y); 692203b705cfSriastradh 692303b705cfSriastradh sna_pixmap_destroy(scratch); 692403b705cfSriastradh return true; 692503b705cfSriastradh} 692603b705cfSriastradh 692703b705cfSriastradhvoid 692803b705cfSriastradhsna_add_traps(PicturePtr picture, INT16 x, INT16 y, int n, xTrap *t) 692903b705cfSriastradh{ 693003b705cfSriastradh struct sna *sna; 693103b705cfSriastradh 693203b705cfSriastradh DBG(("%s (%d, %d) x %d\n", __FUNCTION__, x, y, n)); 693303b705cfSriastradh 693403b705cfSriastradh sna = to_sna_from_drawable(picture->pDrawable); 693503b705cfSriastradh if (is_gpu(sna, picture->pDrawable, PREFER_GPU_SPANS)) { 693603b705cfSriastradh if (trap_span_converter(sna, picture, x, y, n, t)) 693703b705cfSriastradh return; 693803b705cfSriastradh } 693903b705cfSriastradh 694003b705cfSriastradh if (is_gpu(sna, picture->pDrawable, PREFER_GPU_RENDER)) { 694103b705cfSriastradh if (trap_mask_converter(sna, picture, x, y, n, t)) 694203b705cfSriastradh return; 694303b705cfSriastradh 694403b705cfSriastradh if (trap_upload(picture, x, y, n, t)) 694503b705cfSriastradh return; 694603b705cfSriastradh } 694703b705cfSriastradh 694803b705cfSriastradh DBG(("%s -- fallback\n", __FUNCTION__)); 694903b705cfSriastradh if (sna_drawable_move_to_cpu(picture->pDrawable, 695003b705cfSriastradh MOVE_READ | MOVE_WRITE)) { 695103b705cfSriastradh pixman_image_t *image; 695203b705cfSriastradh int dx, dy; 695303b705cfSriastradh 695403b705cfSriastradh if (!(image = image_from_pict(picture, false, &dx, &dy))) 695503b705cfSriastradh return; 695603b705cfSriastradh 695703b705cfSriastradh pixman_add_traps(image, x + dx, y + dy, n, (pixman_trap_t *)t); 695803b705cfSriastradh 695903b705cfSriastradh free_pixman_pict(picture, image); 696003b705cfSriastradh } 696103b705cfSriastradh} 696203b705cfSriastradh 696303b705cfSriastradhstatic inline void 696403b705cfSriastradhproject_point_onto_grid(const xPointFixed *in, 696503b705cfSriastradh int dx, int dy, 696603b705cfSriastradh xPointFixed *out) 696703b705cfSriastradh{ 696803b705cfSriastradh out->x = dx + pixman_fixed_to_grid(in->x); 696903b705cfSriastradh out->y = dy + pixman_fixed_to_grid(in->y); 697003b705cfSriastradh} 697103b705cfSriastradh 697203b705cfSriastradh#if HAS_PIXMAN_TRIANGLES 697303b705cfSriastradhstatic inline bool 697403b705cfSriastradhxTriangleValid(const xTriangle *t) 697503b705cfSriastradh{ 697603b705cfSriastradh xPointFixed v1, v2; 697703b705cfSriastradh 697803b705cfSriastradh v1.x = t->p2.x - t->p1.x; 697903b705cfSriastradh v1.y = t->p2.y - t->p1.y; 698003b705cfSriastradh 698103b705cfSriastradh v2.x = t->p3.x - t->p1.x; 698203b705cfSriastradh v2.y = t->p3.y - t->p1.y; 698303b705cfSriastradh 698403b705cfSriastradh /* if the length of any edge is zero, the area must be zero */ 698503b705cfSriastradh if (v1.x == 0 && v1.y == 0) 698603b705cfSriastradh return false; 698703b705cfSriastradh if (v2.x == 0 && v2.y == 0) 698803b705cfSriastradh return false; 698903b705cfSriastradh 699003b705cfSriastradh /* if the cross-product is zero, so it the size */ 699103b705cfSriastradh return v2.y * v1.x != v1.y * v2.x; 699203b705cfSriastradh} 699303b705cfSriastradh 699403b705cfSriastradhstatic inline bool 699503b705cfSriastradhproject_triangle_onto_grid(const xTriangle *in, 699603b705cfSriastradh int dx, int dy, 699703b705cfSriastradh xTriangle *out) 699803b705cfSriastradh{ 699903b705cfSriastradh project_point_onto_grid(&in->p1, dx, dy, &out->p1); 700003b705cfSriastradh project_point_onto_grid(&in->p2, dx, dy, &out->p2); 700103b705cfSriastradh project_point_onto_grid(&in->p3, dx, dy, &out->p3); 700203b705cfSriastradh 700303b705cfSriastradh return xTriangleValid(out); 700403b705cfSriastradh} 700503b705cfSriastradh 700603b705cfSriastradhstatic bool 700703b705cfSriastradhmono_triangles_span_converter(struct sna *sna, 700803b705cfSriastradh CARD8 op, PicturePtr src, PicturePtr dst, 700903b705cfSriastradh INT16 src_x, INT16 src_y, 701003b705cfSriastradh int count, xTriangle *tri) 701103b705cfSriastradh{ 701203b705cfSriastradh struct mono mono; 701303b705cfSriastradh BoxRec extents; 701403b705cfSriastradh int16_t dst_x, dst_y; 701503b705cfSriastradh int16_t dx, dy; 701603b705cfSriastradh bool was_clear; 701703b705cfSriastradh int n; 701803b705cfSriastradh 701903b705cfSriastradh mono.sna = sna; 702003b705cfSriastradh 702103b705cfSriastradh dst_x = pixman_fixed_to_int(tri[0].p1.x); 702203b705cfSriastradh dst_y = pixman_fixed_to_int(tri[0].p1.y); 702303b705cfSriastradh 702403b705cfSriastradh miTriangleBounds(count, tri, &extents); 702503b705cfSriastradh DBG(("%s: extents (%d, %d), (%d, %d)\n", 702603b705cfSriastradh __FUNCTION__, extents.x1, extents.y1, extents.x2, extents.y2)); 702703b705cfSriastradh 702803b705cfSriastradh if (extents.y1 >= extents.y2 || extents.x1 >= extents.x2) 702903b705cfSriastradh return true; 703003b705cfSriastradh 703103b705cfSriastradh if (!sna_compute_composite_region(&mono.clip, 703203b705cfSriastradh src, NULL, dst, 703303b705cfSriastradh src_x + extents.x1 - dst_x, 703403b705cfSriastradh src_y + extents.y1 - dst_y, 703503b705cfSriastradh 0, 0, 703603b705cfSriastradh extents.x1, extents.y1, 703703b705cfSriastradh extents.x2 - extents.x1, 703803b705cfSriastradh extents.y2 - extents.y1)) { 703903b705cfSriastradh DBG(("%s: triangles do not intersect drawable clips\n", 704003b705cfSriastradh __FUNCTION__)) ; 704103b705cfSriastradh return true; 704203b705cfSriastradh } 704303b705cfSriastradh 704403b705cfSriastradh dx = dst->pDrawable->x; 704503b705cfSriastradh dy = dst->pDrawable->y; 704603b705cfSriastradh 704703b705cfSriastradh DBG(("%s: after clip -- extents (%d, %d), (%d, %d), delta=(%d, %d) src -> (%d, %d)\n", 704803b705cfSriastradh __FUNCTION__, 704903b705cfSriastradh mono.clip.extents.x1, mono.clip.extents.y1, 705003b705cfSriastradh mono.clip.extents.x2, mono.clip.extents.y2, 705103b705cfSriastradh dx, dy, 705203b705cfSriastradh src_x + mono.clip.extents.x1 - dst_x - dx, 705303b705cfSriastradh src_y + mono.clip.extents.y1 - dst_y - dy)); 705403b705cfSriastradh 705503b705cfSriastradh was_clear = sna_drawable_is_clear(dst->pDrawable); 705603b705cfSriastradh 705703b705cfSriastradh if (mono_init(&mono, 3*count)) 705803b705cfSriastradh return false; 705903b705cfSriastradh 706003b705cfSriastradh for (n = 0; n < count; n++) { 706103b705cfSriastradh mono_add_line(&mono, dx, dy, 706203b705cfSriastradh tri[n].p1.y, tri[n].p2.y, 706303b705cfSriastradh &tri[n].p1, &tri[n].p2, 1); 706403b705cfSriastradh mono_add_line(&mono, dx, dy, 706503b705cfSriastradh tri[n].p2.y, tri[n].p3.y, 706603b705cfSriastradh &tri[n].p2, &tri[n].p3, 1); 706703b705cfSriastradh mono_add_line(&mono, dx, dy, 706803b705cfSriastradh tri[n].p3.y, tri[n].p1.y, 706903b705cfSriastradh &tri[n].p3, &tri[n].p1, 1); 707003b705cfSriastradh } 707103b705cfSriastradh 707203b705cfSriastradh memset(&mono.op, 0, sizeof(mono.op)); 707303b705cfSriastradh if (mono.sna->render.composite(mono.sna, op, src, NULL, dst, 707403b705cfSriastradh src_x + mono.clip.extents.x1 - dst_x - dx, 707503b705cfSriastradh src_y + mono.clip.extents.y1 - dst_y - dy, 707603b705cfSriastradh 0, 0, 707703b705cfSriastradh mono.clip.extents.x1, mono.clip.extents.y1, 707803b705cfSriastradh mono.clip.extents.x2 - mono.clip.extents.x1, 707903b705cfSriastradh mono.clip.extents.y2 - mono.clip.extents.y1, 708003b705cfSriastradh &mono.op)) { 708103b705cfSriastradh if (mono.clip.data == NULL && mono.op.damage == NULL) 708203b705cfSriastradh mono.span = mono_span__fast; 708303b705cfSriastradh else 708403b705cfSriastradh mono.span = mono_span; 708503b705cfSriastradh mono_render(&mono); 708603b705cfSriastradh mono.op.done(mono.sna, &mono.op); 708703b705cfSriastradh } 708803b705cfSriastradh 708903b705cfSriastradh if (!was_clear && !operator_is_bounded(op)) { 709003b705cfSriastradh xPointFixed p1, p2; 709103b705cfSriastradh 709203b705cfSriastradh if (!mono_init(&mono, 2+3*count)) 709303b705cfSriastradh return false; 709403b705cfSriastradh 709503b705cfSriastradh p1.y = mono.clip.extents.y1 * pixman_fixed_1; 709603b705cfSriastradh p2.y = mono.clip.extents.y2 * pixman_fixed_1; 709703b705cfSriastradh 709803b705cfSriastradh p1.x = mono.clip.extents.x1 * pixman_fixed_1; 709903b705cfSriastradh p2.x = mono.clip.extents.x1 * pixman_fixed_1; 710003b705cfSriastradh mono_add_line(&mono, 0, 0, p1.y, p2.y, &p1, &p2, -1); 710103b705cfSriastradh 710203b705cfSriastradh p1.x = mono.clip.extents.x2 * pixman_fixed_1; 710303b705cfSriastradh p2.x = mono.clip.extents.x2 * pixman_fixed_1; 710403b705cfSriastradh mono_add_line(&mono, 0, 0, p1.y, p2.y, &p1, &p2, 1); 710503b705cfSriastradh 710603b705cfSriastradh for (n = 0; n < count; n++) { 710703b705cfSriastradh mono_add_line(&mono, dx, dy, 710803b705cfSriastradh tri[n].p1.y, tri[n].p2.y, 710903b705cfSriastradh &tri[n].p1, &tri[n].p2, 1); 711003b705cfSriastradh mono_add_line(&mono, dx, dy, 711103b705cfSriastradh tri[n].p2.y, tri[n].p3.y, 711203b705cfSriastradh &tri[n].p2, &tri[n].p3, 1); 711303b705cfSriastradh mono_add_line(&mono, dx, dy, 711403b705cfSriastradh tri[n].p3.y, tri[n].p1.y, 711503b705cfSriastradh &tri[n].p3, &tri[n].p1, 1); 711603b705cfSriastradh } 711703b705cfSriastradh 711803b705cfSriastradh memset(&mono.op, 0, sizeof(mono.op)); 711903b705cfSriastradh if (mono.sna->render.composite(mono.sna, 712003b705cfSriastradh PictOpClear, 712103b705cfSriastradh mono.sna->clear, NULL, dst, 712203b705cfSriastradh 0, 0, 712303b705cfSriastradh 0, 0, 712403b705cfSriastradh mono.clip.extents.x1, mono.clip.extents.y1, 712503b705cfSriastradh mono.clip.extents.x2 - mono.clip.extents.x1, 712603b705cfSriastradh mono.clip.extents.y2 - mono.clip.extents.y1, 712703b705cfSriastradh &mono.op)) { 712803b705cfSriastradh if (mono.clip.data == NULL && mono.op.damage == NULL) 712903b705cfSriastradh mono.span = mono_span__fast; 713003b705cfSriastradh else 713103b705cfSriastradh mono.span = mono_span; 713203b705cfSriastradh mono_render(&mono); 713303b705cfSriastradh mono.op.done(mono.sna, &mono.op); 713403b705cfSriastradh } 713503b705cfSriastradh mono_fini(&mono); 713603b705cfSriastradh } 713703b705cfSriastradh 713803b705cfSriastradh mono_fini(&mono); 713903b705cfSriastradh REGION_UNINIT(NULL, &mono.clip); 714003b705cfSriastradh return true; 714103b705cfSriastradh} 714203b705cfSriastradh 714303b705cfSriastradhstatic bool 714403b705cfSriastradhtriangles_span_converter(struct sna *sna, 714503b705cfSriastradh CARD8 op, PicturePtr src, PicturePtr dst, 714603b705cfSriastradh PictFormatPtr maskFormat, INT16 src_x, INT16 src_y, 714703b705cfSriastradh int count, xTriangle *tri) 714803b705cfSriastradh{ 714903b705cfSriastradh struct sna_composite_spans_op tmp; 715003b705cfSriastradh struct tor tor; 715103b705cfSriastradh BoxRec extents; 715203b705cfSriastradh pixman_region16_t clip; 715303b705cfSriastradh int16_t dst_x, dst_y; 715403b705cfSriastradh int dx, dy, n; 715503b705cfSriastradh bool was_clear; 715603b705cfSriastradh 715703b705cfSriastradh if (NO_SCAN_CONVERTER) 715803b705cfSriastradh return false; 715903b705cfSriastradh 716003b705cfSriastradh if (is_mono(dst, maskFormat)) 716103b705cfSriastradh return mono_triangles_span_converter(sna, op, src, dst, 716203b705cfSriastradh src_x, src_y, 716303b705cfSriastradh count, tri); 716403b705cfSriastradh 716503b705cfSriastradh /* XXX strict adherence to the Render specification */ 716603b705cfSriastradh if (dst->polyMode == PolyModePrecise) { 716703b705cfSriastradh DBG(("%s: fallback -- precise rasterisation requested\n", 716803b705cfSriastradh __FUNCTION__)); 716903b705cfSriastradh return false; 717003b705cfSriastradh } 717103b705cfSriastradh 717203b705cfSriastradh if (!sna->render.check_composite_spans(sna, op, src, dst, 0, 0, 0)) { 717303b705cfSriastradh DBG(("%s: fallback -- composite spans not supported\n", 717403b705cfSriastradh __FUNCTION__)); 717503b705cfSriastradh return false; 717603b705cfSriastradh } 717703b705cfSriastradh 717803b705cfSriastradh dst_x = pixman_fixed_to_int(tri[0].p1.x); 717903b705cfSriastradh dst_y = pixman_fixed_to_int(tri[0].p1.y); 718003b705cfSriastradh 718103b705cfSriastradh miTriangleBounds(count, tri, &extents); 718203b705cfSriastradh DBG(("%s: extents (%d, %d), (%d, %d)\n", 718303b705cfSriastradh __FUNCTION__, extents.x1, extents.y1, extents.x2, extents.y2)); 718403b705cfSriastradh 718503b705cfSriastradh if (extents.y1 >= extents.y2 || extents.x1 >= extents.x2) 718603b705cfSriastradh return true; 718703b705cfSriastradh 718803b705cfSriastradh#if 0 718903b705cfSriastradh if (extents.y2 - extents.y1 < 64 && extents.x2 - extents.x1 < 64) { 719003b705cfSriastradh DBG(("%s: fallback -- traps extents too small %dx%d\n", 719103b705cfSriastradh __FUNCTION__, extents.y2 - extents.y1, extents.x2 - extents.x1)); 719203b705cfSriastradh return false; 719303b705cfSriastradh } 719403b705cfSriastradh#endif 719503b705cfSriastradh 719603b705cfSriastradh if (!sna_compute_composite_region(&clip, 719703b705cfSriastradh src, NULL, dst, 719803b705cfSriastradh src_x + extents.x1 - dst_x, 719903b705cfSriastradh src_y + extents.y1 - dst_y, 720003b705cfSriastradh 0, 0, 720103b705cfSriastradh extents.x1, extents.y1, 720203b705cfSriastradh extents.x2 - extents.x1, 720303b705cfSriastradh extents.y2 - extents.y1)) { 720403b705cfSriastradh DBG(("%s: triangles do not intersect drawable clips\n", 720503b705cfSriastradh __FUNCTION__)) ; 720603b705cfSriastradh return true; 720703b705cfSriastradh } 720803b705cfSriastradh 720903b705cfSriastradh if (!sna->render.check_composite_spans(sna, op, src, dst, 721003b705cfSriastradh clip.extents.x2 - clip.extents.x1, 721103b705cfSriastradh clip.extents.y2 - clip.extents.y1, 721203b705cfSriastradh 0)) { 721303b705cfSriastradh DBG(("%s: fallback -- composite spans not supported\n", 721403b705cfSriastradh __FUNCTION__)); 721503b705cfSriastradh return false; 721603b705cfSriastradh } 721703b705cfSriastradh 721803b705cfSriastradh extents = *RegionExtents(&clip); 721903b705cfSriastradh dx = dst->pDrawable->x; 722003b705cfSriastradh dy = dst->pDrawable->y; 722103b705cfSriastradh 722203b705cfSriastradh DBG(("%s: after clip -- extents (%d, %d), (%d, %d), delta=(%d, %d) src -> (%d, %d)\n", 722303b705cfSriastradh __FUNCTION__, 722403b705cfSriastradh extents.x1, extents.y1, 722503b705cfSriastradh extents.x2, extents.y2, 722603b705cfSriastradh dx, dy, 722703b705cfSriastradh src_x + extents.x1 - dst_x - dx, 722803b705cfSriastradh src_y + extents.y1 - dst_y - dy)); 722903b705cfSriastradh 723003b705cfSriastradh was_clear = sna_drawable_is_clear(dst->pDrawable); 723103b705cfSriastradh 723203b705cfSriastradh memset(&tmp, 0, sizeof(tmp)); 723303b705cfSriastradh if (!sna->render.composite_spans(sna, op, src, dst, 723403b705cfSriastradh src_x + extents.x1 - dst_x - dx, 723503b705cfSriastradh src_y + extents.y1 - dst_y - dy, 723603b705cfSriastradh extents.x1, extents.y1, 723703b705cfSriastradh extents.x2 - extents.x1, 723803b705cfSriastradh extents.y2 - extents.y1, 723903b705cfSriastradh 0, 724003b705cfSriastradh &tmp)) { 724103b705cfSriastradh DBG(("%s: fallback -- composite spans render op not supported\n", 724203b705cfSriastradh __FUNCTION__)); 724303b705cfSriastradh return false; 724403b705cfSriastradh } 724503b705cfSriastradh 724603b705cfSriastradh dx *= FAST_SAMPLES_X; 724703b705cfSriastradh dy *= FAST_SAMPLES_Y; 724803b705cfSriastradh if (!tor_init(&tor, &extents, 3*count)) 724903b705cfSriastradh goto skip; 725003b705cfSriastradh 725103b705cfSriastradh for (n = 0; n < count; n++) { 725203b705cfSriastradh xTriangle t; 725303b705cfSriastradh 725403b705cfSriastradh if (!project_triangle_onto_grid(&tri[n], dx, dy, &t)) 725503b705cfSriastradh continue; 725603b705cfSriastradh 725703b705cfSriastradh polygon_add_line(tor.polygon, &t.p1, &t.p2); 725803b705cfSriastradh polygon_add_line(tor.polygon, &t.p2, &t.p3); 725903b705cfSriastradh polygon_add_line(tor.polygon, &t.p3, &t.p1); 726003b705cfSriastradh } 726103b705cfSriastradh 726203b705cfSriastradh tor_render(sna, &tor, &tmp, &clip, 726303b705cfSriastradh choose_span(&tmp, dst, maskFormat, &clip), 726403b705cfSriastradh !was_clear && maskFormat && !operator_is_bounded(op)); 726503b705cfSriastradh 726603b705cfSriastradh tor_fini(&tor); 726703b705cfSriastradhskip: 726803b705cfSriastradh tmp.done(sna, &tmp); 726903b705cfSriastradh 727003b705cfSriastradh REGION_UNINIT(NULL, &clip); 727103b705cfSriastradh return true; 727203b705cfSriastradh} 727303b705cfSriastradh 727403b705cfSriastradhstatic bool 727503b705cfSriastradhtriangles_mask_converter(CARD8 op, PicturePtr src, PicturePtr dst, 727603b705cfSriastradh PictFormatPtr maskFormat, INT16 src_x, INT16 src_y, 727703b705cfSriastradh int count, xTriangle *tri) 727803b705cfSriastradh{ 727903b705cfSriastradh struct tor tor; 728003b705cfSriastradh void (*span)(struct sna *sna, 728103b705cfSriastradh struct sna_composite_spans_op *op, 728203b705cfSriastradh pixman_region16_t *clip, 728303b705cfSriastradh const BoxRec *box, 728403b705cfSriastradh int coverage); 728503b705cfSriastradh ScreenPtr screen = dst->pDrawable->pScreen; 728603b705cfSriastradh PixmapPtr scratch; 728703b705cfSriastradh PicturePtr mask; 728803b705cfSriastradh BoxRec extents; 728903b705cfSriastradh int16_t dst_x, dst_y; 729003b705cfSriastradh int dx, dy; 729103b705cfSriastradh int error, n; 729203b705cfSriastradh 729303b705cfSriastradh if (NO_SCAN_CONVERTER) 729403b705cfSriastradh return false; 729503b705cfSriastradh 729603b705cfSriastradh if (dst->polyMode == PolyModePrecise && !is_mono(dst, maskFormat)) { 729703b705cfSriastradh DBG(("%s: fallback -- precise rasterisation requested\n", 729803b705cfSriastradh __FUNCTION__)); 729903b705cfSriastradh return false; 730003b705cfSriastradh } 730103b705cfSriastradh 730203b705cfSriastradh if (maskFormat == NULL && count > 1) { 730303b705cfSriastradh DBG(("%s: fallback -- individual rasterisation requested\n", 730403b705cfSriastradh __FUNCTION__)); 730503b705cfSriastradh return false; 730603b705cfSriastradh } 730703b705cfSriastradh 730803b705cfSriastradh miTriangleBounds(count, tri, &extents); 730903b705cfSriastradh DBG(("%s: extents (%d, %d), (%d, %d)\n", 731003b705cfSriastradh __FUNCTION__, extents.x1, extents.y1, extents.x2, extents.y2)); 731103b705cfSriastradh 731203b705cfSriastradh if (extents.y1 >= extents.y2 || extents.x1 >= extents.x2) 731303b705cfSriastradh return true; 731403b705cfSriastradh 731503b705cfSriastradh if (!sna_compute_composite_extents(&extents, 731603b705cfSriastradh src, NULL, dst, 731703b705cfSriastradh src_x, src_y, 731803b705cfSriastradh 0, 0, 731903b705cfSriastradh extents.x1, extents.y1, 732003b705cfSriastradh extents.x2 - extents.x1, 732103b705cfSriastradh extents.y2 - extents.y1)) 732203b705cfSriastradh return true; 732303b705cfSriastradh 732403b705cfSriastradh DBG(("%s: extents (%d, %d), (%d, %d)\n", 732503b705cfSriastradh __FUNCTION__, extents.x1, extents.y1, extents.x2, extents.y2)); 732603b705cfSriastradh 732703b705cfSriastradh extents.y2 -= extents.y1; 732803b705cfSriastradh extents.x2 -= extents.x1; 732903b705cfSriastradh extents.x1 -= dst->pDrawable->x; 733003b705cfSriastradh extents.y1 -= dst->pDrawable->y; 733103b705cfSriastradh dst_x = extents.x1; 733203b705cfSriastradh dst_y = extents.y1; 733303b705cfSriastradh dx = -extents.x1 * FAST_SAMPLES_X; 733403b705cfSriastradh dy = -extents.y1 * FAST_SAMPLES_Y; 733503b705cfSriastradh extents.x1 = extents.y1 = 0; 733603b705cfSriastradh 733703b705cfSriastradh DBG(("%s: mask (%dx%d)\n", 733803b705cfSriastradh __FUNCTION__, extents.x2, extents.y2)); 733903b705cfSriastradh scratch = sna_pixmap_create_upload(screen, 734003b705cfSriastradh extents.x2, extents.y2, 8, 734103b705cfSriastradh KGEM_BUFFER_WRITE_INPLACE); 734203b705cfSriastradh if (!scratch) 734303b705cfSriastradh return true; 734403b705cfSriastradh 734503b705cfSriastradh DBG(("%s: created buffer %p, stride %d\n", 734603b705cfSriastradh __FUNCTION__, scratch->devPrivate.ptr, scratch->devKind)); 734703b705cfSriastradh 734803b705cfSriastradh if (!tor_init(&tor, &extents, 3*count)) { 734903b705cfSriastradh sna_pixmap_destroy(scratch); 735003b705cfSriastradh return true; 735103b705cfSriastradh } 735203b705cfSriastradh 735303b705cfSriastradh for (n = 0; n < count; n++) { 735403b705cfSriastradh xTriangle t; 735503b705cfSriastradh 735603b705cfSriastradh if (!project_triangle_onto_grid(&tri[n], dx, dy, &t)) 735703b705cfSriastradh continue; 735803b705cfSriastradh 735903b705cfSriastradh polygon_add_line(tor.polygon, &t.p1, &t.p2); 736003b705cfSriastradh polygon_add_line(tor.polygon, &t.p2, &t.p3); 736103b705cfSriastradh polygon_add_line(tor.polygon, &t.p3, &t.p1); 736203b705cfSriastradh } 736303b705cfSriastradh 736403b705cfSriastradh if (maskFormat ? maskFormat->depth < 8 : dst->polyEdge == PolyEdgeSharp) 736503b705cfSriastradh span = tor_blt_mask_mono; 736603b705cfSriastradh else 736703b705cfSriastradh span = tor_blt_mask; 736803b705cfSriastradh 736903b705cfSriastradh tor_render(NULL, &tor, 737003b705cfSriastradh scratch->devPrivate.ptr, 737103b705cfSriastradh (void *)(intptr_t)scratch->devKind, 737203b705cfSriastradh span, true); 737303b705cfSriastradh 737403b705cfSriastradh mask = CreatePicture(0, &scratch->drawable, 737503b705cfSriastradh PictureMatchFormat(screen, 8, PICT_a8), 737603b705cfSriastradh 0, 0, serverClient, &error); 737703b705cfSriastradh if (mask) { 737803b705cfSriastradh CompositePicture(op, src, mask, dst, 737903b705cfSriastradh src_x + dst_x - pixman_fixed_to_int(tri[0].p1.x), 738003b705cfSriastradh src_y + dst_y - pixman_fixed_to_int(tri[0].p1.y), 738103b705cfSriastradh 0, 0, 738203b705cfSriastradh dst_x, dst_y, 738303b705cfSriastradh extents.x2, extents.y2); 738403b705cfSriastradh FreePicture(mask, 0); 738503b705cfSriastradh } 738603b705cfSriastradh tor_fini(&tor); 738703b705cfSriastradh sna_pixmap_destroy(scratch); 738803b705cfSriastradh 738903b705cfSriastradh return true; 739003b705cfSriastradh} 739103b705cfSriastradh 739203b705cfSriastradhstatic void 739303b705cfSriastradhtriangles_fallback(CARD8 op, 739403b705cfSriastradh PicturePtr src, 739503b705cfSriastradh PicturePtr dst, 739603b705cfSriastradh PictFormatPtr maskFormat, 739703b705cfSriastradh INT16 xSrc, INT16 ySrc, 739803b705cfSriastradh int n, xTriangle *tri) 739903b705cfSriastradh{ 740003b705cfSriastradh ScreenPtr screen = dst->pDrawable->pScreen; 740103b705cfSriastradh 740203b705cfSriastradh DBG(("%s op=%d, count=%d\n", __FUNCTION__, op, n)); 740303b705cfSriastradh 740403b705cfSriastradh if (maskFormat) { 740503b705cfSriastradh PixmapPtr scratch; 740603b705cfSriastradh PicturePtr mask; 740703b705cfSriastradh INT16 dst_x, dst_y; 740803b705cfSriastradh BoxRec bounds; 740903b705cfSriastradh int width, height, depth; 741003b705cfSriastradh pixman_image_t *image; 741103b705cfSriastradh pixman_format_code_t format; 741203b705cfSriastradh int error; 741303b705cfSriastradh 741403b705cfSriastradh dst_x = pixman_fixed_to_int(tri[0].p1.x); 741503b705cfSriastradh dst_y = pixman_fixed_to_int(tri[0].p1.y); 741603b705cfSriastradh 741703b705cfSriastradh miTriangleBounds(n, tri, &bounds); 741803b705cfSriastradh DBG(("%s: bounds (%d, %d), (%d, %d)\n", 741903b705cfSriastradh __FUNCTION__, bounds.x1, bounds.y1, bounds.x2, bounds.y2)); 742003b705cfSriastradh 742103b705cfSriastradh if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) 742203b705cfSriastradh return; 742303b705cfSriastradh 742403b705cfSriastradh if (!sna_compute_composite_extents(&bounds, 742503b705cfSriastradh src, NULL, dst, 742603b705cfSriastradh xSrc, ySrc, 742703b705cfSriastradh 0, 0, 742803b705cfSriastradh bounds.x1, bounds.y1, 742903b705cfSriastradh bounds.x2 - bounds.x1, 743003b705cfSriastradh bounds.y2 - bounds.y1)) 743103b705cfSriastradh return; 743203b705cfSriastradh 743303b705cfSriastradh DBG(("%s: extents (%d, %d), (%d, %d)\n", 743403b705cfSriastradh __FUNCTION__, bounds.x1, bounds.y1, bounds.x2, bounds.y2)); 743503b705cfSriastradh 743603b705cfSriastradh width = bounds.x2 - bounds.x1; 743703b705cfSriastradh height = bounds.y2 - bounds.y1; 743803b705cfSriastradh bounds.x1 -= dst->pDrawable->x; 743903b705cfSriastradh bounds.y1 -= dst->pDrawable->y; 744003b705cfSriastradh depth = maskFormat->depth; 744103b705cfSriastradh format = maskFormat->format | (BitsPerPixel(depth) << 24); 744203b705cfSriastradh 744303b705cfSriastradh DBG(("%s: mask (%dx%d) depth=%d, format=%08x\n", 744403b705cfSriastradh __FUNCTION__, width, height, depth, format)); 744503b705cfSriastradh scratch = sna_pixmap_create_upload(screen, 744603b705cfSriastradh width, height, depth, 744703b705cfSriastradh KGEM_BUFFER_WRITE); 744803b705cfSriastradh if (!scratch) 744903b705cfSriastradh return; 745003b705cfSriastradh 745103b705cfSriastradh memset(scratch->devPrivate.ptr, 0, scratch->devKind*height); 745203b705cfSriastradh image = pixman_image_create_bits(format, width, height, 745303b705cfSriastradh scratch->devPrivate.ptr, 745403b705cfSriastradh scratch->devKind); 745503b705cfSriastradh if (image) { 745603b705cfSriastradh pixman_add_triangles(image, 745703b705cfSriastradh -bounds.x1, -bounds.y1, 745803b705cfSriastradh n, (pixman_triangle_t *)tri); 745903b705cfSriastradh pixman_image_unref(image); 746003b705cfSriastradh } 746103b705cfSriastradh 746203b705cfSriastradh mask = CreatePicture(0, &scratch->drawable, 746303b705cfSriastradh PictureMatchFormat(screen, depth, format), 746403b705cfSriastradh 0, 0, serverClient, &error); 746503b705cfSriastradh if (mask) { 746603b705cfSriastradh CompositePicture(op, src, mask, dst, 746703b705cfSriastradh xSrc + bounds.x1 - dst_x, 746803b705cfSriastradh ySrc + bounds.y1 - dst_y, 746903b705cfSriastradh 0, 0, 747003b705cfSriastradh bounds.x1, bounds.y1, 747103b705cfSriastradh width, height); 747203b705cfSriastradh FreePicture(mask, 0); 747303b705cfSriastradh } 747403b705cfSriastradh sna_pixmap_destroy(scratch); 747503b705cfSriastradh } else { 747603b705cfSriastradh if (dst->polyEdge == PolyEdgeSharp) 747703b705cfSriastradh maskFormat = PictureMatchFormat(screen, 1, PICT_a1); 747803b705cfSriastradh else 747903b705cfSriastradh maskFormat = PictureMatchFormat(screen, 8, PICT_a8); 748003b705cfSriastradh 748103b705cfSriastradh for (; n--; tri++) 748203b705cfSriastradh triangles_fallback(op, 748303b705cfSriastradh src, dst, maskFormat, 748403b705cfSriastradh xSrc, ySrc, 1, tri); 748503b705cfSriastradh } 748603b705cfSriastradh} 748703b705cfSriastradh 748803b705cfSriastradhvoid 748903b705cfSriastradhsna_composite_triangles(CARD8 op, 749003b705cfSriastradh PicturePtr src, 749103b705cfSriastradh PicturePtr dst, 749203b705cfSriastradh PictFormatPtr maskFormat, 749303b705cfSriastradh INT16 xSrc, INT16 ySrc, 749403b705cfSriastradh int n, xTriangle *tri) 749503b705cfSriastradh{ 749603b705cfSriastradh struct sna *sna = to_sna_from_drawable(dst->pDrawable); 749703b705cfSriastradh 749803b705cfSriastradh if (triangles_span_converter(sna, op, src, dst, maskFormat, 749903b705cfSriastradh xSrc, ySrc, 750003b705cfSriastradh n, tri)) 750103b705cfSriastradh return; 750203b705cfSriastradh 750303b705cfSriastradh if (triangles_mask_converter(op, src, dst, maskFormat, 750403b705cfSriastradh xSrc, ySrc, 750503b705cfSriastradh n, tri)) 750603b705cfSriastradh return; 750703b705cfSriastradh 750803b705cfSriastradh triangles_fallback(op, src, dst, maskFormat, xSrc, ySrc, n, tri); 750903b705cfSriastradh} 751003b705cfSriastradh 751103b705cfSriastradhstatic bool 751203b705cfSriastradhtristrip_span_converter(struct sna *sna, 751303b705cfSriastradh CARD8 op, PicturePtr src, PicturePtr dst, 751403b705cfSriastradh PictFormatPtr maskFormat, INT16 src_x, INT16 src_y, 751503b705cfSriastradh int count, xPointFixed *points) 751603b705cfSriastradh{ 751703b705cfSriastradh struct sna_composite_spans_op tmp; 751803b705cfSriastradh struct tor tor; 751903b705cfSriastradh BoxRec extents; 752003b705cfSriastradh pixman_region16_t clip; 752103b705cfSriastradh xPointFixed p[4]; 752203b705cfSriastradh int16_t dst_x, dst_y; 752303b705cfSriastradh int dx, dy; 752403b705cfSriastradh int cw, ccw, n; 752503b705cfSriastradh bool was_clear; 752603b705cfSriastradh 752703b705cfSriastradh if (NO_SCAN_CONVERTER) 752803b705cfSriastradh return false; 752903b705cfSriastradh 753003b705cfSriastradh /* XXX strict adherence to the Render specification */ 753103b705cfSriastradh if (dst->polyMode == PolyModePrecise && !is_mono(dst, maskFormat)) { 753203b705cfSriastradh DBG(("%s: fallback -- precise rasterisation requested\n", 753303b705cfSriastradh __FUNCTION__)); 753403b705cfSriastradh return false; 753503b705cfSriastradh } 753603b705cfSriastradh 753703b705cfSriastradh if (!sna->render.check_composite_spans(sna, op, src, dst, 0, 0, 0)) { 753803b705cfSriastradh DBG(("%s: fallback -- composite spans not supported\n", 753903b705cfSriastradh __FUNCTION__)); 754003b705cfSriastradh return false; 754103b705cfSriastradh } 754203b705cfSriastradh 754303b705cfSriastradh dst_x = pixman_fixed_to_int(points[0].x); 754403b705cfSriastradh dst_y = pixman_fixed_to_int(points[0].y); 754503b705cfSriastradh 754603b705cfSriastradh miPointFixedBounds(count, points, &extents); 754703b705cfSriastradh DBG(("%s: extents (%d, %d), (%d, %d)\n", 754803b705cfSriastradh __FUNCTION__, extents.x1, extents.y1, extents.x2, extents.y2)); 754903b705cfSriastradh 755003b705cfSriastradh if (extents.y1 >= extents.y2 || extents.x1 >= extents.x2) 755103b705cfSriastradh return true; 755203b705cfSriastradh 755303b705cfSriastradh#if 0 755403b705cfSriastradh if (extents.y2 - extents.y1 < 64 && extents.x2 - extents.x1 < 64) { 755503b705cfSriastradh DBG(("%s: fallback -- traps extents too small %dx%d\n", 755603b705cfSriastradh __FUNCTION__, extents.y2 - extents.y1, extents.x2 - extents.x1)); 755703b705cfSriastradh return false; 755803b705cfSriastradh } 755903b705cfSriastradh#endif 756003b705cfSriastradh 756103b705cfSriastradh if (!sna_compute_composite_region(&clip, 756203b705cfSriastradh src, NULL, dst, 756303b705cfSriastradh src_x + extents.x1 - dst_x, 756403b705cfSriastradh src_y + extents.y1 - dst_y, 756503b705cfSriastradh 0, 0, 756603b705cfSriastradh extents.x1, extents.y1, 756703b705cfSriastradh extents.x2 - extents.x1, 756803b705cfSriastradh extents.y2 - extents.y1)) { 756903b705cfSriastradh DBG(("%s: triangles do not intersect drawable clips\n", 757003b705cfSriastradh __FUNCTION__)) ; 757103b705cfSriastradh return true; 757203b705cfSriastradh } 757303b705cfSriastradh 757403b705cfSriastradh if (!sna->render.check_composite_spans(sna, op, src, dst, 757503b705cfSriastradh clip.extents.x2 - clip.extents.x1, 757603b705cfSriastradh clip.extents.y2 - clip.extents.y1, 757703b705cfSriastradh 0)) { 757803b705cfSriastradh DBG(("%s: fallback -- composite spans not supported\n", 757903b705cfSriastradh __FUNCTION__)); 758003b705cfSriastradh return false; 758103b705cfSriastradh } 758203b705cfSriastradh 758303b705cfSriastradh extents = *RegionExtents(&clip); 758403b705cfSriastradh dx = dst->pDrawable->x; 758503b705cfSriastradh dy = dst->pDrawable->y; 758603b705cfSriastradh 758703b705cfSriastradh DBG(("%s: after clip -- extents (%d, %d), (%d, %d), delta=(%d, %d) src -> (%d, %d)\n", 758803b705cfSriastradh __FUNCTION__, 758903b705cfSriastradh extents.x1, extents.y1, 759003b705cfSriastradh extents.x2, extents.y2, 759103b705cfSriastradh dx, dy, 759203b705cfSriastradh src_x + extents.x1 - dst_x - dx, 759303b705cfSriastradh src_y + extents.y1 - dst_y - dy)); 759403b705cfSriastradh 759503b705cfSriastradh was_clear = sna_drawable_is_clear(dst->pDrawable); 759603b705cfSriastradh 759703b705cfSriastradh memset(&tmp, 0, sizeof(tmp)); 759803b705cfSriastradh if (!sna->render.composite_spans(sna, op, src, dst, 759903b705cfSriastradh src_x + extents.x1 - dst_x - dx, 760003b705cfSriastradh src_y + extents.y1 - dst_y - dy, 760103b705cfSriastradh extents.x1, extents.y1, 760203b705cfSriastradh extents.x2 - extents.x1, 760303b705cfSriastradh extents.y2 - extents.y1, 760403b705cfSriastradh 0, 760503b705cfSriastradh &tmp)) { 760603b705cfSriastradh DBG(("%s: fallback -- composite spans render op not supported\n", 760703b705cfSriastradh __FUNCTION__)); 760803b705cfSriastradh return false; 760903b705cfSriastradh } 761003b705cfSriastradh 761103b705cfSriastradh dx *= FAST_SAMPLES_X; 761203b705cfSriastradh dy *= FAST_SAMPLES_Y; 761303b705cfSriastradh if (!tor_init(&tor, &extents, 2*count)) 761403b705cfSriastradh goto skip; 761503b705cfSriastradh 761603b705cfSriastradh cw = ccw = 0; 761703b705cfSriastradh project_point_onto_grid(&points[0], dx, dy, &p[cw]); 761803b705cfSriastradh project_point_onto_grid(&points[1], dx, dy, &p[2+ccw]); 761903b705cfSriastradh polygon_add_line(tor.polygon, &p[cw], &p[2+ccw]); 762003b705cfSriastradh n = 2; 762103b705cfSriastradh do { 762203b705cfSriastradh cw = !cw; 762303b705cfSriastradh project_point_onto_grid(&points[n], dx, dy, &p[cw]); 762403b705cfSriastradh polygon_add_line(tor.polygon, &p[!cw], &p[cw]); 762503b705cfSriastradh if (++n == count) 762603b705cfSriastradh break; 762703b705cfSriastradh 762803b705cfSriastradh ccw = !ccw; 762903b705cfSriastradh project_point_onto_grid(&points[n], dx, dy, &p[2+ccw]); 763003b705cfSriastradh polygon_add_line(tor.polygon, &p[2+ccw], &p[2+!ccw]); 763103b705cfSriastradh if (++n == count) 763203b705cfSriastradh break; 763303b705cfSriastradh } while (1); 763403b705cfSriastradh polygon_add_line(tor.polygon, &p[2+ccw], &p[cw]); 763503b705cfSriastradh assert(tor.polygon->num_edges <= 2*count); 763603b705cfSriastradh 763703b705cfSriastradh tor_render(sna, &tor, &tmp, &clip, 763803b705cfSriastradh choose_span(&tmp, dst, maskFormat, &clip), 763903b705cfSriastradh !was_clear && maskFormat && !operator_is_bounded(op)); 764003b705cfSriastradh 764103b705cfSriastradh tor_fini(&tor); 764203b705cfSriastradhskip: 764303b705cfSriastradh tmp.done(sna, &tmp); 764403b705cfSriastradh 764503b705cfSriastradh REGION_UNINIT(NULL, &clip); 764603b705cfSriastradh return true; 764703b705cfSriastradh} 764803b705cfSriastradh 764903b705cfSriastradhstatic void 765003b705cfSriastradhtristrip_fallback(CARD8 op, 765103b705cfSriastradh PicturePtr src, 765203b705cfSriastradh PicturePtr dst, 765303b705cfSriastradh PictFormatPtr maskFormat, 765403b705cfSriastradh INT16 xSrc, INT16 ySrc, 765503b705cfSriastradh int n, xPointFixed *points) 765603b705cfSriastradh{ 765703b705cfSriastradh ScreenPtr screen = dst->pDrawable->pScreen; 765803b705cfSriastradh 765903b705cfSriastradh if (maskFormat) { 766003b705cfSriastradh PixmapPtr scratch; 766103b705cfSriastradh PicturePtr mask; 766203b705cfSriastradh INT16 dst_x, dst_y; 766303b705cfSriastradh BoxRec bounds; 766403b705cfSriastradh int width, height, depth; 766503b705cfSriastradh pixman_image_t *image; 766603b705cfSriastradh pixman_format_code_t format; 766703b705cfSriastradh int error; 766803b705cfSriastradh 766903b705cfSriastradh dst_x = pixman_fixed_to_int(points->x); 767003b705cfSriastradh dst_y = pixman_fixed_to_int(points->y); 767103b705cfSriastradh 767203b705cfSriastradh miPointFixedBounds(n, points, &bounds); 767303b705cfSriastradh DBG(("%s: bounds (%d, %d), (%d, %d)\n", 767403b705cfSriastradh __FUNCTION__, bounds.x1, bounds.y1, bounds.x2, bounds.y2)); 767503b705cfSriastradh 767603b705cfSriastradh if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) 767703b705cfSriastradh return; 767803b705cfSriastradh 767903b705cfSriastradh if (!sna_compute_composite_extents(&bounds, 768003b705cfSriastradh src, NULL, dst, 768103b705cfSriastradh xSrc, ySrc, 768203b705cfSriastradh 0, 0, 768303b705cfSriastradh bounds.x1, bounds.y1, 768403b705cfSriastradh bounds.x2 - bounds.x1, 768503b705cfSriastradh bounds.y2 - bounds.y1)) 768603b705cfSriastradh return; 768703b705cfSriastradh 768803b705cfSriastradh DBG(("%s: extents (%d, %d), (%d, %d)\n", 768903b705cfSriastradh __FUNCTION__, bounds.x1, bounds.y1, bounds.x2, bounds.y2)); 769003b705cfSriastradh 769103b705cfSriastradh width = bounds.x2 - bounds.x1; 769203b705cfSriastradh height = bounds.y2 - bounds.y1; 769303b705cfSriastradh bounds.x1 -= dst->pDrawable->x; 769403b705cfSriastradh bounds.y1 -= dst->pDrawable->y; 769503b705cfSriastradh depth = maskFormat->depth; 769603b705cfSriastradh format = maskFormat->format | (BitsPerPixel(depth) << 24); 769703b705cfSriastradh 769803b705cfSriastradh DBG(("%s: mask (%dx%d) depth=%d, format=%08x\n", 769903b705cfSriastradh __FUNCTION__, width, height, depth, format)); 770003b705cfSriastradh scratch = sna_pixmap_create_upload(screen, 770103b705cfSriastradh width, height, depth, 770203b705cfSriastradh KGEM_BUFFER_WRITE); 770303b705cfSriastradh if (!scratch) 770403b705cfSriastradh return; 770503b705cfSriastradh 770603b705cfSriastradh memset(scratch->devPrivate.ptr, 0, scratch->devKind*height); 770703b705cfSriastradh image = pixman_image_create_bits(format, width, height, 770803b705cfSriastradh scratch->devPrivate.ptr, 770903b705cfSriastradh scratch->devKind); 771003b705cfSriastradh if (image) { 771103b705cfSriastradh xTriangle tri; 771203b705cfSriastradh xPointFixed *p[3] = { &tri.p1, &tri.p2, &tri.p3 }; 771303b705cfSriastradh int i; 771403b705cfSriastradh 771503b705cfSriastradh *p[0] = points[0]; 771603b705cfSriastradh *p[1] = points[1]; 771703b705cfSriastradh *p[2] = points[2]; 771803b705cfSriastradh pixman_add_triangles(image, 771903b705cfSriastradh -bounds.x1, -bounds.y1, 772003b705cfSriastradh 1, (pixman_triangle_t *)&tri); 772103b705cfSriastradh for (i = 3; i < n; i++) { 772203b705cfSriastradh *p[i%3] = points[i]; 772303b705cfSriastradh pixman_add_triangles(image, 772403b705cfSriastradh -bounds.x1, -bounds.y1, 772503b705cfSriastradh 1, (pixman_triangle_t *)&tri); 772603b705cfSriastradh } 772703b705cfSriastradh pixman_image_unref(image); 772803b705cfSriastradh } 772903b705cfSriastradh 773003b705cfSriastradh mask = CreatePicture(0, &scratch->drawable, 773103b705cfSriastradh PictureMatchFormat(screen, depth, format), 773203b705cfSriastradh 0, 0, serverClient, &error); 773303b705cfSriastradh if (mask) { 773403b705cfSriastradh CompositePicture(op, src, mask, dst, 773503b705cfSriastradh xSrc + bounds.x1 - dst_x, 773603b705cfSriastradh ySrc + bounds.y1 - dst_y, 773703b705cfSriastradh 0, 0, 773803b705cfSriastradh bounds.x1, bounds.y1, 773903b705cfSriastradh width, height); 774003b705cfSriastradh FreePicture(mask, 0); 774103b705cfSriastradh } 774203b705cfSriastradh sna_pixmap_destroy(scratch); 774303b705cfSriastradh } else { 774403b705cfSriastradh xTriangle tri; 774503b705cfSriastradh xPointFixed *p[3] = { &tri.p1, &tri.p2, &tri.p3 }; 774603b705cfSriastradh int i; 774703b705cfSriastradh 774803b705cfSriastradh if (dst->polyEdge == PolyEdgeSharp) 774903b705cfSriastradh maskFormat = PictureMatchFormat(screen, 1, PICT_a1); 775003b705cfSriastradh else 775103b705cfSriastradh maskFormat = PictureMatchFormat(screen, 8, PICT_a8); 775203b705cfSriastradh 775303b705cfSriastradh *p[0] = points[0]; 775403b705cfSriastradh *p[1] = points[1]; 775503b705cfSriastradh *p[2] = points[2]; 775603b705cfSriastradh triangles_fallback(op, 775703b705cfSriastradh src, dst, maskFormat, 775803b705cfSriastradh xSrc, ySrc, 1, &tri); 775903b705cfSriastradh for (i = 3; i < n; i++) { 776003b705cfSriastradh *p[i%3] = points[i]; 776103b705cfSriastradh /* Should xSrc,ySrc be updated? */ 776203b705cfSriastradh triangles_fallback(op, 776303b705cfSriastradh src, dst, maskFormat, 776403b705cfSriastradh xSrc, ySrc, 1, &tri); 776503b705cfSriastradh } 776603b705cfSriastradh } 776703b705cfSriastradh} 776803b705cfSriastradh 776903b705cfSriastradhvoid 777003b705cfSriastradhsna_composite_tristrip(CARD8 op, 777103b705cfSriastradh PicturePtr src, 777203b705cfSriastradh PicturePtr dst, 777303b705cfSriastradh PictFormatPtr maskFormat, 777403b705cfSriastradh INT16 xSrc, INT16 ySrc, 777503b705cfSriastradh int n, xPointFixed *points) 777603b705cfSriastradh{ 777703b705cfSriastradh struct sna *sna = to_sna_from_drawable(dst->pDrawable); 777803b705cfSriastradh 777903b705cfSriastradh if (tristrip_span_converter(sna, op, src, dst, maskFormat, xSrc, ySrc, n, points)) 778003b705cfSriastradh return; 778103b705cfSriastradh 778203b705cfSriastradh tristrip_fallback(op, src, dst, maskFormat, xSrc, ySrc, n, points); 778303b705cfSriastradh} 778403b705cfSriastradh 778503b705cfSriastradhstatic void 778603b705cfSriastradhtrifan_fallback(CARD8 op, 778703b705cfSriastradh PicturePtr src, 778803b705cfSriastradh PicturePtr dst, 778903b705cfSriastradh PictFormatPtr maskFormat, 779003b705cfSriastradh INT16 xSrc, INT16 ySrc, 779103b705cfSriastradh int n, xPointFixed *points) 779203b705cfSriastradh{ 779303b705cfSriastradh ScreenPtr screen = dst->pDrawable->pScreen; 779403b705cfSriastradh 779503b705cfSriastradh if (maskFormat) { 779603b705cfSriastradh PixmapPtr scratch; 779703b705cfSriastradh PicturePtr mask; 779803b705cfSriastradh INT16 dst_x, dst_y; 779903b705cfSriastradh BoxRec bounds; 780003b705cfSriastradh int width, height, depth; 780103b705cfSriastradh pixman_image_t *image; 780203b705cfSriastradh pixman_format_code_t format; 780303b705cfSriastradh int error; 780403b705cfSriastradh 780503b705cfSriastradh dst_x = pixman_fixed_to_int(points->x); 780603b705cfSriastradh dst_y = pixman_fixed_to_int(points->y); 780703b705cfSriastradh 780803b705cfSriastradh miPointFixedBounds(n, points, &bounds); 780903b705cfSriastradh DBG(("%s: bounds (%d, %d), (%d, %d)\n", 781003b705cfSriastradh __FUNCTION__, bounds.x1, bounds.y1, bounds.x2, bounds.y2)); 781103b705cfSriastradh 781203b705cfSriastradh if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) 781303b705cfSriastradh return; 781403b705cfSriastradh 781503b705cfSriastradh if (!sna_compute_composite_extents(&bounds, 781603b705cfSriastradh src, NULL, dst, 781703b705cfSriastradh xSrc, ySrc, 781803b705cfSriastradh 0, 0, 781903b705cfSriastradh bounds.x1, bounds.y1, 782003b705cfSriastradh bounds.x2 - bounds.x1, 782103b705cfSriastradh bounds.y2 - bounds.y1)) 782203b705cfSriastradh return; 782303b705cfSriastradh 782403b705cfSriastradh DBG(("%s: extents (%d, %d), (%d, %d)\n", 782503b705cfSriastradh __FUNCTION__, bounds.x1, bounds.y1, bounds.x2, bounds.y2)); 782603b705cfSriastradh 782703b705cfSriastradh width = bounds.x2 - bounds.x1; 782803b705cfSriastradh height = bounds.y2 - bounds.y1; 782903b705cfSriastradh bounds.x1 -= dst->pDrawable->x; 783003b705cfSriastradh bounds.y1 -= dst->pDrawable->y; 783103b705cfSriastradh depth = maskFormat->depth; 783203b705cfSriastradh format = maskFormat->format | (BitsPerPixel(depth) << 24); 783303b705cfSriastradh 783403b705cfSriastradh DBG(("%s: mask (%dx%d) depth=%d, format=%08x\n", 783503b705cfSriastradh __FUNCTION__, width, height, depth, format)); 783603b705cfSriastradh scratch = sna_pixmap_create_upload(screen, 783703b705cfSriastradh width, height, depth, 783803b705cfSriastradh KGEM_BUFFER_WRITE); 783903b705cfSriastradh if (!scratch) 784003b705cfSriastradh return; 784103b705cfSriastradh 784203b705cfSriastradh memset(scratch->devPrivate.ptr, 0, scratch->devKind*height); 784303b705cfSriastradh image = pixman_image_create_bits(format, width, height, 784403b705cfSriastradh scratch->devPrivate.ptr, 784503b705cfSriastradh scratch->devKind); 784603b705cfSriastradh if (image) { 784703b705cfSriastradh xTriangle tri; 784803b705cfSriastradh xPointFixed *p[3] = { &tri.p1, &tri.p2, &tri.p3 }; 784903b705cfSriastradh int i; 785003b705cfSriastradh 785103b705cfSriastradh *p[0] = points[0]; 785203b705cfSriastradh *p[1] = points[1]; 785303b705cfSriastradh *p[2] = points[2]; 785403b705cfSriastradh pixman_add_triangles(image, 785503b705cfSriastradh -bounds.x1, -bounds.y1, 785603b705cfSriastradh 1, (pixman_triangle_t *)&tri); 785703b705cfSriastradh for (i = 3; i < n; i++) { 785803b705cfSriastradh *p[2 - (i&1)] = points[i]; 785903b705cfSriastradh pixman_add_triangles(image, 786003b705cfSriastradh -bounds.x1, -bounds.y1, 786103b705cfSriastradh 1, (pixman_triangle_t *)&tri); 786203b705cfSriastradh } 786303b705cfSriastradh pixman_image_unref(image); 786403b705cfSriastradh } 786503b705cfSriastradh 786603b705cfSriastradh mask = CreatePicture(0, &scratch->drawable, 786703b705cfSriastradh PictureMatchFormat(screen, depth, format), 786803b705cfSriastradh 0, 0, serverClient, &error); 786903b705cfSriastradh if (mask) { 787003b705cfSriastradh CompositePicture(op, src, mask, dst, 787103b705cfSriastradh xSrc + bounds.x1 - dst_x, 787203b705cfSriastradh ySrc + bounds.y1 - dst_y, 787303b705cfSriastradh 0, 0, 787403b705cfSriastradh bounds.x1, bounds.y1, 787503b705cfSriastradh width, height); 787603b705cfSriastradh FreePicture(mask, 0); 787703b705cfSriastradh } 787803b705cfSriastradh sna_pixmap_destroy(scratch); 787903b705cfSriastradh } else { 788003b705cfSriastradh xTriangle tri; 788103b705cfSriastradh xPointFixed *p[3] = { &tri.p1, &tri.p2, &tri.p3 }; 788203b705cfSriastradh int i; 788303b705cfSriastradh 788403b705cfSriastradh if (dst->polyEdge == PolyEdgeSharp) 788503b705cfSriastradh maskFormat = PictureMatchFormat(screen, 1, PICT_a1); 788603b705cfSriastradh else 788703b705cfSriastradh maskFormat = PictureMatchFormat(screen, 8, PICT_a8); 788803b705cfSriastradh 788903b705cfSriastradh *p[0] = points[0]; 789003b705cfSriastradh *p[1] = points[1]; 789103b705cfSriastradh *p[2] = points[2]; 789203b705cfSriastradh triangles_fallback(op, 789303b705cfSriastradh src, dst, maskFormat, 789403b705cfSriastradh xSrc, ySrc, 1, &tri); 789503b705cfSriastradh for (i = 3; i < n; i++) { 789603b705cfSriastradh *p[2 - (i&1)] = points[i]; 789703b705cfSriastradh /* Should xSrc,ySrc be updated? */ 789803b705cfSriastradh triangles_fallback(op, 789903b705cfSriastradh src, dst, maskFormat, 790003b705cfSriastradh xSrc, ySrc, 1, &tri); 790103b705cfSriastradh } 790203b705cfSriastradh } 790303b705cfSriastradh} 790403b705cfSriastradh 790503b705cfSriastradhvoid 790603b705cfSriastradhsna_composite_trifan(CARD8 op, 790703b705cfSriastradh PicturePtr src, 790803b705cfSriastradh PicturePtr dst, 790903b705cfSriastradh PictFormatPtr maskFormat, 791003b705cfSriastradh INT16 xSrc, INT16 ySrc, 791103b705cfSriastradh int n, xPointFixed *points) 791203b705cfSriastradh{ 791303b705cfSriastradh trifan_fallback(op, src, dst, maskFormat, xSrc, ySrc, n, points); 791403b705cfSriastradh} 791503b705cfSriastradh#endif 7916