sna_trapezoids.c revision 42542f5f
103b705cfSriastradh/* 203b705cfSriastradh * Copyright (c) 2007 David Turner 303b705cfSriastradh * Copyright (c) 2008 M Joonas Pihlaja 403b705cfSriastradh * Copyright (c) 2011 Intel Corporation 503b705cfSriastradh * 603b705cfSriastradh * Permission is hereby granted, free of charge, to any person obtaining a 703b705cfSriastradh * copy of this software and associated documentation files (the "Software"), 803b705cfSriastradh * to deal in the Software without restriction, including without limitation 903b705cfSriastradh * the rights to use, copy, modify, merge, publish, distribute, sublicense, 1003b705cfSriastradh * and/or sell copies of the Software, and to permit persons to whom the 1103b705cfSriastradh * Software is furnished to do so, subject to the following conditions: 1203b705cfSriastradh * 1303b705cfSriastradh * The above copyright notice and this permission notice (including the next 1403b705cfSriastradh * paragraph) shall be included in all copies or substantial portions of the 1503b705cfSriastradh * Software. 1603b705cfSriastradh * 1703b705cfSriastradh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1803b705cfSriastradh * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1903b705cfSriastradh * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 2003b705cfSriastradh * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2103b705cfSriastradh * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2203b705cfSriastradh * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 2303b705cfSriastradh * SOFTWARE. 2403b705cfSriastradh * 2503b705cfSriastradh * Authors: 2603b705cfSriastradh * Chris Wilson <chris@chris-wilson.co.uk> 2703b705cfSriastradh * 2803b705cfSriastradh */ 2903b705cfSriastradh 3003b705cfSriastradh#ifdef HAVE_CONFIG_H 3103b705cfSriastradh#include "config.h" 3203b705cfSriastradh#endif 3303b705cfSriastradh 3403b705cfSriastradh#include "sna.h" 3503b705cfSriastradh#include "sna_render.h" 3603b705cfSriastradh#include "sna_render_inline.h" 3742542f5fSchristos#include "sna_trapezoids.h" 3803b705cfSriastradh#include "fb/fbpict.h" 3903b705cfSriastradh 4003b705cfSriastradh#include <mipict.h> 4103b705cfSriastradh 4203b705cfSriastradh/* TODO: Emit unantialiased and MSAA triangles. */ 4303b705cfSriastradh 4403b705cfSriastradh#ifndef MAX 4503b705cfSriastradh#define MAX(x,y) ((x) >= (y) ? (x) : (y)) 4603b705cfSriastradh#endif 4703b705cfSriastradh 4803b705cfSriastradh#ifndef MIN 4903b705cfSriastradh#define MIN(x,y) ((x) <= (y) ? (x) : (y)) 5003b705cfSriastradh#endif 5103b705cfSriastradh 5203b705cfSriastradh#define region_count(r) ((r)->data ? (r)->data->numRects : 1) 5303b705cfSriastradh#define region_boxes(r) ((r)->data ? (BoxPtr)((r)->data + 1) : &(r)->extents) 5403b705cfSriastradh 5542542f5fSchristosinline static xFixed 5642542f5fSchristosline_x_for_y(const xLineFixed *l, xFixed y, bool ceil) 5703b705cfSriastradh{ 5842542f5fSchristos xFixed_32_32 ex = (xFixed_32_32)(y - l->p1.y) * (l->p2.x - l->p1.x); 5942542f5fSchristos xFixed d = l->p2.y - l->p1.y; 6003b705cfSriastradh 6142542f5fSchristos if (ceil) 6242542f5fSchristos ex += (d - 1); 6303b705cfSriastradh 6442542f5fSchristos return l->p1.x + (xFixed) (ex / d); 6503b705cfSriastradh} 6603b705cfSriastradh 6742542f5fSchristosbool trapezoids_bounds(int n, const xTrapezoid *t, BoxPtr box) 6803b705cfSriastradh{ 6942542f5fSchristos xFixed x1, y1, x2, y2; 7003b705cfSriastradh 7142542f5fSchristos /* XXX need 33 bits... */ 7242542f5fSchristos x1 = y1 = INT_MAX / 2; 7342542f5fSchristos x2 = y2 = INT_MIN / 2; 7403b705cfSriastradh 7542542f5fSchristos do { 7642542f5fSchristos xFixed fx1, fx2, v; 7703b705cfSriastradh 7842542f5fSchristos if (!xTrapezoidValid(t)) 7942542f5fSchristos continue; 8003b705cfSriastradh 8142542f5fSchristos if (t->top < y1) 8242542f5fSchristos y1 = t->top; 8342542f5fSchristos if (t->bottom > y2) 8442542f5fSchristos y2 = t->bottom; 8503b705cfSriastradh 8642542f5fSchristos if (((t->left.p1.x - x1) | (t->left.p2.x - x1)) < 0) { 8742542f5fSchristos if (pixman_fixed_floor(t->left.p1.x) == pixman_fixed_floor(t->left.p2.x)) { 8842542f5fSchristos x1 = pixman_fixed_floor(t->left.p1.x); 8942542f5fSchristos } else { 9042542f5fSchristos if (t->left.p1.y == t->top) 9142542f5fSchristos fx1 = t->left.p1.x; 9242542f5fSchristos else 9342542f5fSchristos fx1 = line_x_for_y(&t->left, t->top, false); 9403b705cfSriastradh 9542542f5fSchristos if (t->left.p2.y == t->bottom) 9642542f5fSchristos fx2 = t->left.p2.x; 9742542f5fSchristos else 9842542f5fSchristos fx2 = line_x_for_y(&t->left, t->bottom, false); 9903b705cfSriastradh 10042542f5fSchristos v = min(fx1, fx2); 10142542f5fSchristos if (v < x1) 10242542f5fSchristos x1 = pixman_fixed_floor(v); 10342542f5fSchristos } 10442542f5fSchristos } 10503b705cfSriastradh 10642542f5fSchristos if (((x2 - t->right.p1.x) | (x2 - t->right.p2.x)) < 0) { 10742542f5fSchristos if (pixman_fixed_floor(t->right.p1.x) == pixman_fixed_floor(t->right.p2.x)) { 10842542f5fSchristos x2 = pixman_fixed_ceil(t->right.p1.x); 10942542f5fSchristos } else { 11042542f5fSchristos if (t->right.p1.y == t->top) 11142542f5fSchristos fx1 = t->right.p1.x; 11242542f5fSchristos else 11342542f5fSchristos fx1 = line_x_for_y(&t->right, t->top, true); 11403b705cfSriastradh 11542542f5fSchristos if (t->right.p2.y == t->bottom) 11642542f5fSchristos fx2 = t->right.p2.x; 11742542f5fSchristos else 11842542f5fSchristos fx2 = line_x_for_y(&t->right, t->bottom, true); 11903b705cfSriastradh 12042542f5fSchristos v = max(fx1, fx2); 12142542f5fSchristos if (v > x2) 12242542f5fSchristos x2 = pixman_fixed_ceil(v); 12342542f5fSchristos } 12442542f5fSchristos } 12542542f5fSchristos } while (t++, --n); 12603b705cfSriastradh 12742542f5fSchristos box->x1 = pixman_fixed_to_int(x1); 12842542f5fSchristos box->x2 = pixman_fixed_to_int(x2); 12942542f5fSchristos box->y1 = pixman_fixed_integer_floor(y1); 13042542f5fSchristos box->y2 = pixman_fixed_integer_ceil(y2); 13103b705cfSriastradh 13242542f5fSchristos return box->x2 > box->x1 && box->y2 > box->y1; 13342542f5fSchristos} 13403b705cfSriastradh 13542542f5fSchristosstatic bool 13642542f5fSchristostrapezoids_inplace_fallback(struct sna *sna, 13742542f5fSchristos CARD8 op, 13842542f5fSchristos PicturePtr src, PicturePtr dst, PictFormatPtr mask, 13942542f5fSchristos int ntrap, xTrapezoid *traps) 14042542f5fSchristos{ 14142542f5fSchristos pixman_image_t *image; 14242542f5fSchristos BoxRec box; 14342542f5fSchristos uint32_t color; 14442542f5fSchristos int dx, dy; 14503b705cfSriastradh 14642542f5fSchristos if (op != PictOpAdd) 14742542f5fSchristos return false; 14803b705cfSriastradh 14942542f5fSchristos if (is_mono(dst, mask)) { 15042542f5fSchristos if (dst->format != PICT_a1) 15142542f5fSchristos return false; 15242542f5fSchristos } else { 15342542f5fSchristos if (dst->format != PICT_a8) 15442542f5fSchristos return false; 15542542f5fSchristos } 15603b705cfSriastradh 15742542f5fSchristos if (!sna_picture_is_solid(src, &color) || (color >> 24) != 0xff) { 15842542f5fSchristos DBG(("%s: not an opaque solid source\n", __FUNCTION__)); 15942542f5fSchristos return false; 16042542f5fSchristos } 16103b705cfSriastradh 16242542f5fSchristos box.x1 = dst->pDrawable->x; 16342542f5fSchristos box.y1 = dst->pDrawable->y; 16442542f5fSchristos box.x2 = dst->pDrawable->width; 16542542f5fSchristos box.y2 = dst->pDrawable->height; 16642542f5fSchristos if (pixman_region_contains_rectangle(dst->pCompositeClip, 16742542f5fSchristos &box) != PIXMAN_REGION_IN) { 16842542f5fSchristos DBG(("%s: requires clipping, drawable (%d,%d), (%d, %d), clip (%d, %d), (%d, %d)\n", __FUNCTION__, 16942542f5fSchristos box.x1, box.y1, box.x2, box.y2, 17042542f5fSchristos dst->pCompositeClip->extents.x1, 17142542f5fSchristos dst->pCompositeClip->extents.y1, 17242542f5fSchristos dst->pCompositeClip->extents.x2, 17342542f5fSchristos dst->pCompositeClip->extents.y2)); 17442542f5fSchristos return false; 17542542f5fSchristos } 17603b705cfSriastradh 17742542f5fSchristos if (is_gpu(sna, dst->pDrawable, PREFER_GPU_SPANS)) { 17842542f5fSchristos DBG(("%s: not performing inplace as dst is already on the GPU\n", 17942542f5fSchristos __FUNCTION__)); 18042542f5fSchristos return false; 18142542f5fSchristos } 18203b705cfSriastradh 18342542f5fSchristos DBG(("%s\n", __FUNCTION__)); 18403b705cfSriastradh 18542542f5fSchristos image = NULL; 18642542f5fSchristos if (sna_drawable_move_to_cpu(dst->pDrawable, MOVE_READ | MOVE_WRITE)) 18742542f5fSchristos image = image_from_pict(dst, false, &dx, &dy); 18842542f5fSchristos if (image) { 18942542f5fSchristos dx += dst->pDrawable->x; 19042542f5fSchristos dy += dst->pDrawable->y; 19103b705cfSriastradh 19242542f5fSchristos if (sigtrap_get() == 0) { 19342542f5fSchristos for (; ntrap; ntrap--, traps++) 19442542f5fSchristos if (xTrapezoidValid(traps)) 19542542f5fSchristos pixman_rasterize_trapezoid(image, 19642542f5fSchristos (pixman_trapezoid_t *)traps, 19742542f5fSchristos dx, dy); 19842542f5fSchristos sigtrap_put(); 19942542f5fSchristos } 20003b705cfSriastradh 20142542f5fSchristos pixman_image_unref(image); 20203b705cfSriastradh } 20303b705cfSriastradh 20442542f5fSchristos return true; 20503b705cfSriastradh} 20603b705cfSriastradh 20742542f5fSchristosstruct rasterize_traps_thread { 20842542f5fSchristos xTrapezoid *traps; 20942542f5fSchristos char *ptr; 21042542f5fSchristos int stride; 21142542f5fSchristos BoxRec bounds; 21242542f5fSchristos pixman_format_code_t format; 21342542f5fSchristos int ntrap; 21442542f5fSchristos}; 21503b705cfSriastradh 21642542f5fSchristosstatic void rasterize_traps_thread(void *arg) 21703b705cfSriastradh{ 21842542f5fSchristos struct rasterize_traps_thread *thread = arg; 21942542f5fSchristos pixman_image_t *image; 22042542f5fSchristos int width, height, n; 22103b705cfSriastradh 22242542f5fSchristos width = thread->bounds.x2 - thread->bounds.x1; 22342542f5fSchristos height = thread->bounds.y2 - thread->bounds.y1; 22403b705cfSriastradh 22542542f5fSchristos memset(thread->ptr, 0, thread->stride*height); 22642542f5fSchristos if (PIXMAN_FORMAT_DEPTH(thread->format) < 8) 22742542f5fSchristos image = pixman_image_create_bits(thread->format, 22842542f5fSchristos width, height, 22942542f5fSchristos NULL, 0); 23042542f5fSchristos else 23142542f5fSchristos image = pixman_image_create_bits(thread->format, 23242542f5fSchristos width, height, 23342542f5fSchristos (uint32_t *)thread->ptr, 23442542f5fSchristos thread->stride); 23542542f5fSchristos if (image == NULL) 23642542f5fSchristos return; 23703b705cfSriastradh 23842542f5fSchristos for (n = 0; n < thread->ntrap; n++) 23942542f5fSchristos if (xTrapezoidValid(&thread->traps[n])) 24042542f5fSchristos pixman_rasterize_trapezoid(image, 24142542f5fSchristos (pixman_trapezoid_t *)&thread->traps[n], 24242542f5fSchristos -thread->bounds.x1, -thread->bounds.y1); 24342542f5fSchristos 24442542f5fSchristos if (PIXMAN_FORMAT_DEPTH(thread->format) < 8) { 24542542f5fSchristos pixman_image_t *a8; 24603b705cfSriastradh 24742542f5fSchristos a8 = pixman_image_create_bits(PIXMAN_a8, 24842542f5fSchristos width, height, 24942542f5fSchristos (uint32_t *)thread->ptr, 25042542f5fSchristos thread->stride); 25142542f5fSchristos if (a8) { 25242542f5fSchristos pixman_image_composite(PIXMAN_OP_SRC, 25342542f5fSchristos image, NULL, a8, 25442542f5fSchristos 0, 0, 25542542f5fSchristos 0, 0, 25642542f5fSchristos 0, 0, 25742542f5fSchristos width, height); 25842542f5fSchristos pixman_image_unref(a8); 25942542f5fSchristos } 26042542f5fSchristos } 26103b705cfSriastradh 26242542f5fSchristos pixman_image_unref(image); 26303b705cfSriastradh} 26403b705cfSriastradh 26542542f5fSchristosstatic void 26642542f5fSchristostrapezoids_fallback(struct sna *sna, 26742542f5fSchristos CARD8 op, PicturePtr src, PicturePtr dst, 26842542f5fSchristos PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, 26942542f5fSchristos int ntrap, xTrapezoid * traps) 27003b705cfSriastradh{ 27142542f5fSchristos ScreenPtr screen = dst->pDrawable->pScreen; 27203b705cfSriastradh 27342542f5fSchristos if (maskFormat) { 27442542f5fSchristos PixmapPtr scratch; 27542542f5fSchristos PicturePtr mask; 27642542f5fSchristos INT16 dst_x, dst_y; 27742542f5fSchristos BoxRec bounds; 27842542f5fSchristos int width, height, depth; 27942542f5fSchristos pixman_image_t *image; 28042542f5fSchristos pixman_format_code_t format; 28142542f5fSchristos int error; 28203b705cfSriastradh 28342542f5fSchristos trapezoid_origin(&traps[0].left, &dst_x, &dst_y); 28403b705cfSriastradh 28542542f5fSchristos if (!trapezoids_bounds(ntrap, traps, &bounds)) 28642542f5fSchristos return; 28703b705cfSriastradh 28842542f5fSchristos DBG(("%s: bounds (%d, %d), (%d, %d)\n", __FUNCTION__, 28942542f5fSchristos bounds.x1, bounds.y1, bounds.x2, bounds.y2)); 29003b705cfSriastradh 29142542f5fSchristos if (!sna_compute_composite_extents(&bounds, 29242542f5fSchristos src, NULL, dst, 29342542f5fSchristos xSrc, ySrc, 29442542f5fSchristos 0, 0, 29542542f5fSchristos bounds.x1, bounds.y1, 29642542f5fSchristos bounds.x2 - bounds.x1, 29742542f5fSchristos bounds.y2 - bounds.y1)) 29842542f5fSchristos return; 29903b705cfSriastradh 30042542f5fSchristos DBG(("%s: extents (%d, %d), (%d, %d)\n", __FUNCTION__, 30142542f5fSchristos bounds.x1, bounds.y1, bounds.x2, bounds.y2)); 30203b705cfSriastradh 30342542f5fSchristos width = bounds.x2 - bounds.x1; 30442542f5fSchristos height = bounds.y2 - bounds.y1; 30542542f5fSchristos bounds.x1 -= dst->pDrawable->x; 30642542f5fSchristos bounds.y1 -= dst->pDrawable->y; 30742542f5fSchristos bounds.x2 -= dst->pDrawable->x; 30842542f5fSchristos bounds.y2 -= dst->pDrawable->y; 30942542f5fSchristos depth = maskFormat->depth; 31042542f5fSchristos if (depth == 1) { 31142542f5fSchristos format = PIXMAN_a1; 31242542f5fSchristos } else if (depth <= 4) { 31342542f5fSchristos format = PIXMAN_a4; 31442542f5fSchristos depth = 4; 31542542f5fSchristos } else 31642542f5fSchristos format = PIXMAN_a8; 31703b705cfSriastradh 31842542f5fSchristos DBG(("%s: mask (%dx%d) depth=%d, format=%08x\n", 31942542f5fSchristos __FUNCTION__, width, height, depth, format)); 32042542f5fSchristos if (is_gpu(sna, dst->pDrawable, PREFER_GPU_RENDER) || 32142542f5fSchristos picture_is_gpu(sna, src, PREFER_GPU_RENDER)) { 32242542f5fSchristos int num_threads; 32303b705cfSriastradh 32442542f5fSchristos scratch = sna_pixmap_create_upload(screen, 32542542f5fSchristos width, height, 8, 32642542f5fSchristos KGEM_BUFFER_WRITE); 32742542f5fSchristos if (!scratch) 32842542f5fSchristos return; 32903b705cfSriastradh 33042542f5fSchristos num_threads = sna_use_threads(width, height, 8); 33142542f5fSchristos if (num_threads == 1) { 33242542f5fSchristos if (depth < 8) { 33342542f5fSchristos image = pixman_image_create_bits(format, width, height, 33442542f5fSchristos NULL, 0); 33542542f5fSchristos } else { 33642542f5fSchristos memset(scratch->devPrivate.ptr, 0, scratch->devKind*height); 33703b705cfSriastradh 33842542f5fSchristos image = pixman_image_create_bits(format, width, height, 33942542f5fSchristos scratch->devPrivate.ptr, 34042542f5fSchristos scratch->devKind); 34142542f5fSchristos } 34242542f5fSchristos if (image) { 34342542f5fSchristos for (; ntrap; ntrap--, traps++) 34442542f5fSchristos if (xTrapezoidValid(traps)) 34542542f5fSchristos pixman_rasterize_trapezoid(image, 34642542f5fSchristos (pixman_trapezoid_t *)traps, 34742542f5fSchristos -bounds.x1, -bounds.y1); 34842542f5fSchristos if (depth < 8) { 34942542f5fSchristos pixman_image_t *a8; 35003b705cfSriastradh 35142542f5fSchristos a8 = pixman_image_create_bits(PIXMAN_a8, width, height, 35242542f5fSchristos scratch->devPrivate.ptr, 35342542f5fSchristos scratch->devKind); 35442542f5fSchristos if (a8) { 35542542f5fSchristos pixman_image_composite(PIXMAN_OP_SRC, 35642542f5fSchristos image, NULL, a8, 35742542f5fSchristos 0, 0, 35842542f5fSchristos 0, 0, 35942542f5fSchristos 0, 0, 36042542f5fSchristos width, height); 36142542f5fSchristos format = PIXMAN_a8; 36242542f5fSchristos depth = 8; 36342542f5fSchristos pixman_image_unref(a8); 36442542f5fSchristos } 36542542f5fSchristos } 36603b705cfSriastradh 36742542f5fSchristos pixman_image_unref(image); 36842542f5fSchristos } 36942542f5fSchristos if (format != PIXMAN_a8) { 37042542f5fSchristos sna_pixmap_destroy(scratch); 37142542f5fSchristos return; 37242542f5fSchristos } 37342542f5fSchristos } else { 37442542f5fSchristos struct rasterize_traps_thread threads[num_threads]; 37542542f5fSchristos int y, dy, n; 37603b705cfSriastradh 37742542f5fSchristos threads[0].ptr = scratch->devPrivate.ptr; 37842542f5fSchristos threads[0].stride = scratch->devKind; 37942542f5fSchristos threads[0].traps = traps; 38042542f5fSchristos threads[0].ntrap = ntrap; 38142542f5fSchristos threads[0].bounds = bounds; 38242542f5fSchristos threads[0].format = format; 38303b705cfSriastradh 38442542f5fSchristos y = bounds.y1; 38542542f5fSchristos dy = (height + num_threads - 1) / num_threads; 38642542f5fSchristos num_threads -= (num_threads-1) * dy >= bounds.y2 - bounds.y1; 38703b705cfSriastradh 38842542f5fSchristos if (sigtrap_get() == 0) { 38942542f5fSchristos for (n = 1; n < num_threads; n++) { 39042542f5fSchristos threads[n] = threads[0]; 39142542f5fSchristos threads[n].ptr += (y - bounds.y1) * threads[n].stride; 39242542f5fSchristos threads[n].bounds.y1 = y; 39342542f5fSchristos threads[n].bounds.y2 = y += dy; 39403b705cfSriastradh 39542542f5fSchristos sna_threads_run(n, rasterize_traps_thread, &threads[n]); 39642542f5fSchristos } 39703b705cfSriastradh 39842542f5fSchristos assert(y < threads[0].bounds.y2); 39942542f5fSchristos threads[0].ptr += (y - bounds.y1) * threads[0].stride; 40042542f5fSchristos threads[0].bounds.y1 = y; 40142542f5fSchristos rasterize_traps_thread(&threads[0]); 40203b705cfSriastradh 40342542f5fSchristos sna_threads_wait(); 40442542f5fSchristos sigtrap_put(); 40542542f5fSchristos } else 40642542f5fSchristos sna_threads_kill(); 40703b705cfSriastradh 40842542f5fSchristos format = PIXMAN_a8; 40942542f5fSchristos depth = 8; 41042542f5fSchristos } 41103b705cfSriastradh } else { 41242542f5fSchristos scratch = sna_pixmap_create_unattached(screen, 41342542f5fSchristos width, height, 41442542f5fSchristos depth); 41542542f5fSchristos if (!scratch) 41642542f5fSchristos return; 41703b705cfSriastradh 41842542f5fSchristos memset(scratch->devPrivate.ptr, 0, scratch->devKind*height); 41942542f5fSchristos image = pixman_image_create_bits(format, width, height, 42042542f5fSchristos scratch->devPrivate.ptr, 42142542f5fSchristos scratch->devKind); 42242542f5fSchristos if (image) { 42342542f5fSchristos for (; ntrap; ntrap--, traps++) 42442542f5fSchristos if (xTrapezoidValid(traps)) 42542542f5fSchristos pixman_rasterize_trapezoid(image, 42642542f5fSchristos (pixman_trapezoid_t *)traps, 42742542f5fSchristos -bounds.x1, -bounds.y1); 42842542f5fSchristos pixman_image_unref(image); 42903b705cfSriastradh } 43003b705cfSriastradh } 43103b705cfSriastradh 43242542f5fSchristos mask = CreatePicture(0, &scratch->drawable, 43342542f5fSchristos PictureMatchFormat(screen, depth, format), 43442542f5fSchristos 0, 0, serverClient, &error); 43542542f5fSchristos if (mask) { 43642542f5fSchristos CompositePicture(op, src, mask, dst, 43742542f5fSchristos xSrc + bounds.x1 - dst_x, 43842542f5fSchristos ySrc + bounds.y1 - dst_y, 43942542f5fSchristos 0, 0, 44042542f5fSchristos bounds.x1, bounds.y1, 44142542f5fSchristos width, height); 44242542f5fSchristos FreePicture(mask, 0); 44303b705cfSriastradh } 44442542f5fSchristos sna_pixmap_destroy(scratch); 44503b705cfSriastradh } else { 44642542f5fSchristos if (dst->polyEdge == PolyEdgeSharp) 44742542f5fSchristos maskFormat = PictureMatchFormat(screen, 1, PICT_a1); 44842542f5fSchristos else 44942542f5fSchristos maskFormat = PictureMatchFormat(screen, 8, PICT_a8); 45003b705cfSriastradh 45142542f5fSchristos for (; ntrap; ntrap--, traps++) 45242542f5fSchristos trapezoids_fallback(sna, op, 45342542f5fSchristos src, dst, maskFormat, 45442542f5fSchristos xSrc, ySrc, 1, traps); 45503b705cfSriastradh } 45603b705cfSriastradh} 45703b705cfSriastradh 45803b705cfSriastradhstatic bool 45942542f5fSchristostrapezoid_spans_maybe_inplace(struct sna *sna, 46042542f5fSchristos CARD8 op, PicturePtr src, PicturePtr dst, 46142542f5fSchristos PictFormatPtr maskFormat) 46203b705cfSriastradh{ 46342542f5fSchristos struct sna_pixmap *priv; 46403b705cfSriastradh 46503b705cfSriastradh if (NO_SCAN_CONVERTER) 46603b705cfSriastradh return false; 46703b705cfSriastradh 46842542f5fSchristos if (dst->alphaMap) 46903b705cfSriastradh return false; 47042542f5fSchristos if (is_mono(dst, maskFormat)) 47142542f5fSchristos goto out; 47203b705cfSriastradh 47342542f5fSchristos switch ((int)dst->format) { 47442542f5fSchristos case PICT_a8: 47542542f5fSchristos if (!sna_picture_is_solid(src, NULL)) 47642542f5fSchristos return false; 47703b705cfSriastradh 47842542f5fSchristos switch (op) { 47942542f5fSchristos case PictOpIn: 48042542f5fSchristos case PictOpAdd: 48142542f5fSchristos case PictOpSrc: 48242542f5fSchristos break; 48342542f5fSchristos default: 48442542f5fSchristos return false; 48542542f5fSchristos } 48642542f5fSchristos break; 48703b705cfSriastradh 48842542f5fSchristos case PICT_x8r8g8b8: 48942542f5fSchristos case PICT_a8r8g8b8: 49042542f5fSchristos if (picture_is_gpu(sna, src, 0)) 49142542f5fSchristos return false; 49203b705cfSriastradh 49342542f5fSchristos switch (op) { 49442542f5fSchristos case PictOpOver: 49542542f5fSchristos case PictOpAdd: 49642542f5fSchristos case PictOpOutReverse: 49742542f5fSchristos break; 49842542f5fSchristos case PictOpSrc: 49942542f5fSchristos if (sna_picture_is_solid(src, NULL)) 50042542f5fSchristos break; 50103b705cfSriastradh 50242542f5fSchristos if (!sna_drawable_is_clear(dst->pDrawable)) 50342542f5fSchristos return false; 50442542f5fSchristos break; 50542542f5fSchristos default: 50642542f5fSchristos return false; 50742542f5fSchristos } 50842542f5fSchristos break; 50942542f5fSchristos default: 51042542f5fSchristos return false; 51142542f5fSchristos } 51203b705cfSriastradh 51342542f5fSchristosout: 51442542f5fSchristos priv = sna_pixmap_from_drawable(dst->pDrawable); 51542542f5fSchristos if (priv == NULL) { 51642542f5fSchristos DBG(("%s? yes -- unattached\n", __FUNCTION__)); 51703b705cfSriastradh return true; 51842542f5fSchristos } 51903b705cfSriastradh 52042542f5fSchristos if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo)) { 52142542f5fSchristos DBG(("%s? no -- CPU bo is busy\n", __FUNCTION__)); 52242542f5fSchristos return false; 52342542f5fSchristos } 52403b705cfSriastradh 52542542f5fSchristos if (DAMAGE_IS_ALL(priv->cpu_damage) || priv->gpu_damage == NULL) { 52642542f5fSchristos DBG(("%s? yes -- damaged on CPU only (all? %d)\n", __FUNCTION__, DAMAGE_IS_ALL(priv->cpu_damage))); 52703b705cfSriastradh return true; 52803b705cfSriastradh } 52903b705cfSriastradh 53042542f5fSchristos if (priv->clear) { 53142542f5fSchristos DBG(("%s? clear, %s\n", __FUNCTION__, 53242542f5fSchristos dst->pDrawable->width <= TOR_INPLACE_SIZE ? "yes" : "no")); 53342542f5fSchristos return dst->pDrawable->width <= TOR_INPLACE_SIZE; 53403b705cfSriastradh } 53503b705cfSriastradh 53642542f5fSchristos if (kgem_bo_is_busy(priv->gpu_bo)) { 53742542f5fSchristos DBG(("%s? no, GPU bo is busy\n", __FUNCTION__)); 53842542f5fSchristos return false; 53903b705cfSriastradh } 54042542f5fSchristos 54142542f5fSchristos if (priv->cpu_damage) { 54242542f5fSchristos DBG(("%s? yes, idle GPU bo and damage on idle CPU\n", __FUNCTION__)); 54342542f5fSchristos return true; 54403b705cfSriastradh } 54503b705cfSriastradh 54642542f5fSchristos DBG(("%s? small enough? %s\n", __FUNCTION__, 54742542f5fSchristos dst->pDrawable->width <= TOR_INPLACE_SIZE ? "yes" : "no")); 54842542f5fSchristos return dst->pDrawable->width <= TOR_INPLACE_SIZE; 54903b705cfSriastradh} 55003b705cfSriastradh 55103b705cfSriastradhvoid 55203b705cfSriastradhsna_composite_trapezoids(CARD8 op, 55303b705cfSriastradh PicturePtr src, 55403b705cfSriastradh PicturePtr dst, 55503b705cfSriastradh PictFormatPtr maskFormat, 55603b705cfSriastradh INT16 xSrc, INT16 ySrc, 55703b705cfSriastradh int ntrap, xTrapezoid *traps) 55803b705cfSriastradh{ 55903b705cfSriastradh PixmapPtr pixmap = get_drawable_pixmap(dst->pDrawable); 56003b705cfSriastradh struct sna *sna = to_sna_from_pixmap(pixmap); 56103b705cfSriastradh struct sna_pixmap *priv; 56242542f5fSchristos bool force_fallback = false; 56342542f5fSchristos bool rectilinear, pixel_aligned; 56403b705cfSriastradh unsigned flags; 56503b705cfSriastradh int n; 56603b705cfSriastradh 56703b705cfSriastradh DBG(("%s(op=%d, src=(%d, %d), mask=%08x, ntrap=%d)\n", __FUNCTION__, 56803b705cfSriastradh op, xSrc, ySrc, 56903b705cfSriastradh maskFormat ? (int)maskFormat->format : 0, 57003b705cfSriastradh ntrap)); 57103b705cfSriastradh 57203b705cfSriastradh if (ntrap == 0) 57303b705cfSriastradh return; 57403b705cfSriastradh 57503b705cfSriastradh if (NO_ACCEL) 57642542f5fSchristos goto force_fallback; 57742542f5fSchristos 57842542f5fSchristos if (FORCE_FALLBACK > 0) 57942542f5fSchristos goto force_fallback; 58003b705cfSriastradh 58103b705cfSriastradh if (wedged(sna)) { 58203b705cfSriastradh DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 58342542f5fSchristos goto force_fallback; 58403b705cfSriastradh } 58503b705cfSriastradh 58603b705cfSriastradh if (dst->alphaMap) { 58703b705cfSriastradh DBG(("%s: fallback -- dst alpha map\n", __FUNCTION__)); 58842542f5fSchristos goto force_fallback; 58903b705cfSriastradh } 59003b705cfSriastradh 59103b705cfSriastradh priv = sna_pixmap(pixmap); 59203b705cfSriastradh if (priv == NULL) { 59303b705cfSriastradh DBG(("%s: fallback -- dst is unattached\n", __FUNCTION__)); 59442542f5fSchristos goto force_fallback; 59503b705cfSriastradh } 59603b705cfSriastradh 59742542f5fSchristos if (FORCE_FALLBACK == 0 && 59842542f5fSchristos !is_gpu_dst(priv) && !picture_is_gpu(sna, src, 0) && untransformed(src)) { 59942542f5fSchristos DBG(("%s: force fallbacks -- (!gpu dst, %dx%d? %d) && (src-is-cpu? %d && untransformed? %d)\n", 60042542f5fSchristos __FUNCTION__, dst->pDrawable->width, dst->pDrawable->height, 60142542f5fSchristos !is_gpu_dst(priv), !picture_is_gpu(sna, src, 0), untransformed(src))); 60242542f5fSchristos 60342542f5fSchristosforce_fallback: 60403b705cfSriastradh force_fallback = true; 60503b705cfSriastradh } 60603b705cfSriastradh 60703b705cfSriastradh /* scan through for fast rectangles */ 60803b705cfSriastradh rectilinear = pixel_aligned = true; 60903b705cfSriastradh if (is_mono(dst, maskFormat)) { 61003b705cfSriastradh for (n = 0; n < ntrap && rectilinear; n++) { 61103b705cfSriastradh int lx1 = pixman_fixed_to_int(traps[n].left.p1.x + pixman_fixed_1_minus_e/2); 61203b705cfSriastradh int lx2 = pixman_fixed_to_int(traps[n].left.p2.x + pixman_fixed_1_minus_e/2); 61303b705cfSriastradh int rx1 = pixman_fixed_to_int(traps[n].right.p1.x + pixman_fixed_1_minus_e/2); 61403b705cfSriastradh int rx2 = pixman_fixed_to_int(traps[n].right.p2.x + pixman_fixed_1_minus_e/2); 61503b705cfSriastradh rectilinear &= lx1 == lx2 && rx1 == rx2; 61603b705cfSriastradh } 61703b705cfSriastradh } else if (dst->polyMode != PolyModePrecise) { 61803b705cfSriastradh for (n = 0; n < ntrap && rectilinear; n++) { 61942542f5fSchristos int lx1 = pixman_fixed_to_fast(traps[n].left.p1.x); 62042542f5fSchristos int lx2 = pixman_fixed_to_fast(traps[n].left.p2.x); 62142542f5fSchristos int rx1 = pixman_fixed_to_fast(traps[n].right.p1.x); 62242542f5fSchristos int rx2 = pixman_fixed_to_fast(traps[n].right.p2.x); 62342542f5fSchristos int top = pixman_fixed_to_fast(traps[n].top); 62442542f5fSchristos int bot = pixman_fixed_to_fast(traps[n].bottom); 62503b705cfSriastradh 62603b705cfSriastradh rectilinear &= lx1 == lx2 && rx1 == rx2; 62703b705cfSriastradh pixel_aligned &= ((top | bot | lx1 | lx2 | rx1 | rx2) & FAST_SAMPLES_mask) == 0; 62803b705cfSriastradh } 62903b705cfSriastradh } else { 63003b705cfSriastradh for (n = 0; n < ntrap && rectilinear; n++) { 63103b705cfSriastradh rectilinear &= 63203b705cfSriastradh traps[n].left.p1.x == traps[n].left.p2.x && 63303b705cfSriastradh traps[n].right.p1.x == traps[n].right.p2.x; 63403b705cfSriastradh pixel_aligned &= 63503b705cfSriastradh ((traps[n].top | traps[n].bottom | 63603b705cfSriastradh traps[n].left.p1.x | traps[n].left.p2.x | 63703b705cfSriastradh traps[n].right.p1.x | traps[n].right.p2.x) 63803b705cfSriastradh & pixman_fixed_1_minus_e) == 0; 63903b705cfSriastradh } 64003b705cfSriastradh } 64103b705cfSriastradh 64242542f5fSchristos DBG(("%s: rectilinear? %d, pixel-aligned? %d, mono? %d precise? %d\n", 64342542f5fSchristos __FUNCTION__, rectilinear, pixel_aligned, 64442542f5fSchristos is_mono(dst, maskFormat), is_precise(dst, maskFormat))); 64542542f5fSchristos 64603b705cfSriastradh flags = 0; 64703b705cfSriastradh if (rectilinear) { 64803b705cfSriastradh if (pixel_aligned) { 64903b705cfSriastradh if (composite_aligned_boxes(sna, op, src, dst, 65003b705cfSriastradh maskFormat, 65103b705cfSriastradh xSrc, ySrc, 65203b705cfSriastradh ntrap, traps, 65303b705cfSriastradh force_fallback)) 65403b705cfSriastradh return; 65503b705cfSriastradh } else { 65603b705cfSriastradh if (composite_unaligned_boxes(sna, op, src, dst, 65703b705cfSriastradh maskFormat, 65803b705cfSriastradh xSrc, ySrc, 65903b705cfSriastradh ntrap, traps, 66003b705cfSriastradh force_fallback)) 66103b705cfSriastradh return; 66203b705cfSriastradh } 66303b705cfSriastradh flags |= COMPOSITE_SPANS_RECTILINEAR; 66403b705cfSriastradh } 66503b705cfSriastradh 66603b705cfSriastradh if (force_fallback) 66703b705cfSriastradh goto fallback; 66803b705cfSriastradh 66903b705cfSriastradh if (is_mono(dst, maskFormat) && 67003b705cfSriastradh mono_trapezoids_span_converter(sna, op, src, dst, 67103b705cfSriastradh xSrc, ySrc, 67203b705cfSriastradh ntrap, traps)) 67303b705cfSriastradh return; 67442542f5fSchristos 67542542f5fSchristos if (trapezoid_spans_maybe_inplace(sna, op, src, dst, maskFormat)) { 67642542f5fSchristos flags |= COMPOSITE_SPANS_INPLACE_HINT; 67742542f5fSchristos if (trapezoid_span_inplace(sna, op, src, dst, maskFormat, flags, 67842542f5fSchristos xSrc, ySrc, ntrap, traps, 67942542f5fSchristos false)) 68042542f5fSchristos return; 68103b705cfSriastradh } 68203b705cfSriastradh 68342542f5fSchristos if (trapezoid_span_converter(sna, op, src, dst, maskFormat, flags, 68442542f5fSchristos xSrc, ySrc, ntrap, traps)) 68542542f5fSchristos return; 68603b705cfSriastradh 68742542f5fSchristos if (trapezoid_span_inplace(sna, op, src, dst, maskFormat, flags, 68842542f5fSchristos xSrc, ySrc, ntrap, traps, 68942542f5fSchristos false)) 69042542f5fSchristos return; 69103b705cfSriastradh 69242542f5fSchristos if (trapezoid_mask_converter(op, src, dst, maskFormat, flags, 69342542f5fSchristos xSrc, ySrc, ntrap, traps)) 69442542f5fSchristos return; 69503b705cfSriastradh 69642542f5fSchristosfallback: 69742542f5fSchristos if (trapezoid_span_inplace(sna, op, src, dst, maskFormat, flags, 69842542f5fSchristos xSrc, ySrc, ntrap, traps, 69942542f5fSchristos true)) 70042542f5fSchristos return; 70103b705cfSriastradh 70242542f5fSchristos if (trapezoid_span_fallback(op, src, dst, maskFormat, flags, 70342542f5fSchristos xSrc, ySrc, ntrap, traps)) 70442542f5fSchristos return; 70503b705cfSriastradh 70642542f5fSchristos if (trapezoids_inplace_fallback(sna, op, src, dst, maskFormat, 70742542f5fSchristos ntrap, traps)) 70842542f5fSchristos return; 70903b705cfSriastradh 71042542f5fSchristos DBG(("%s: fallback mask=%08x, ntrap=%d\n", __FUNCTION__, 71142542f5fSchristos maskFormat ? (unsigned)maskFormat->format : 0, ntrap)); 71242542f5fSchristos trapezoids_fallback(sna, op, src, dst, maskFormat, 71342542f5fSchristos xSrc, ySrc, 71442542f5fSchristos ntrap, traps); 71542542f5fSchristos} 71603b705cfSriastradh 71742542f5fSchristosstatic void mark_damaged(PixmapPtr pixmap, struct sna_pixmap *priv, 71842542f5fSchristos BoxPtr box, int16_t x, int16_t y) 71942542f5fSchristos{ 72042542f5fSchristos box->x1 += x; box->x2 += x; 72142542f5fSchristos box->y1 += y; box->y2 += y; 72242542f5fSchristos if (box->x1 <= 0 && box->y1 <= 0 && 72342542f5fSchristos box->x2 >= pixmap->drawable.width && 72442542f5fSchristos box->y2 >= pixmap->drawable.height) { 72542542f5fSchristos sna_damage_destroy(&priv->cpu_damage); 72642542f5fSchristos sna_damage_all(&priv->gpu_damage, pixmap); 72742542f5fSchristos list_del(&priv->flush_list); 72842542f5fSchristos } else { 72942542f5fSchristos sna_damage_add_box(&priv->gpu_damage, box); 73042542f5fSchristos sna_damage_subtract_box(&priv->cpu_damage, box); 73142542f5fSchristos } 73203b705cfSriastradh} 73303b705cfSriastradh 73403b705cfSriastradhstatic bool 73503b705cfSriastradhtrap_upload(PicturePtr picture, 73603b705cfSriastradh INT16 x, INT16 y, 73703b705cfSriastradh int ntrap, xTrap *trap) 73803b705cfSriastradh{ 73903b705cfSriastradh ScreenPtr screen = picture->pDrawable->pScreen; 74003b705cfSriastradh struct sna *sna = to_sna_from_screen(screen); 74103b705cfSriastradh PixmapPtr pixmap = get_drawable_pixmap(picture->pDrawable); 74203b705cfSriastradh PixmapPtr scratch; 74303b705cfSriastradh struct sna_pixmap *priv; 74403b705cfSriastradh BoxRec extents; 74503b705cfSriastradh pixman_image_t *image; 74603b705cfSriastradh int width, height, depth; 74703b705cfSriastradh int n; 74803b705cfSriastradh 74903b705cfSriastradh priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_WRITE); 75003b705cfSriastradh if (priv == NULL) 75103b705cfSriastradh return false; 75203b705cfSriastradh 75303b705cfSriastradh extents = *RegionExtents(picture->pCompositeClip); 75403b705cfSriastradh for (n = 0; n < ntrap; n++) { 75503b705cfSriastradh int v; 75603b705cfSriastradh 75703b705cfSriastradh v = x + pixman_fixed_integer_floor (MIN(trap[n].top.l, trap[n].bot.l)); 75803b705cfSriastradh if (v < extents.x1) 75903b705cfSriastradh extents.x1 = v; 76003b705cfSriastradh 76103b705cfSriastradh v = x + pixman_fixed_integer_ceil (MAX(trap[n].top.r, trap[n].bot.r)); 76203b705cfSriastradh if (v > extents.x2) 76303b705cfSriastradh extents.x2 = v; 76403b705cfSriastradh 76503b705cfSriastradh v = y + pixman_fixed_integer_floor (trap[n].top.y); 76603b705cfSriastradh if (v < extents.y1) 76703b705cfSriastradh extents.y1 = v; 76803b705cfSriastradh 76903b705cfSriastradh v = y + pixman_fixed_integer_ceil (trap[n].bot.y); 77003b705cfSriastradh if (v > extents.y2) 77103b705cfSriastradh extents.y2 = v; 77203b705cfSriastradh } 77303b705cfSriastradh 77403b705cfSriastradh DBG(("%s: extents (%d, %d), (%d, %d)\n", 77503b705cfSriastradh __FUNCTION__, extents.x1, extents.y1, extents.x2, extents.y2)); 77603b705cfSriastradh 77703b705cfSriastradh width = extents.x2 - extents.x1; 77803b705cfSriastradh height = extents.y2 - extents.y1; 77903b705cfSriastradh depth = picture->pDrawable->depth; 78003b705cfSriastradh 78103b705cfSriastradh DBG(("%s: tmp (%dx%d) depth=%d\n", 78203b705cfSriastradh __FUNCTION__, width, height, depth)); 78303b705cfSriastradh scratch = sna_pixmap_create_upload(screen, 78403b705cfSriastradh width, height, depth, 78503b705cfSriastradh KGEM_BUFFER_WRITE); 78603b705cfSriastradh if (!scratch) 78703b705cfSriastradh return true; 78803b705cfSriastradh 78903b705cfSriastradh memset(scratch->devPrivate.ptr, 0, scratch->devKind*height); 79042542f5fSchristos image = pixman_image_create_bits((pixman_format_code_t)picture->format, 79142542f5fSchristos width, height, 79203b705cfSriastradh scratch->devPrivate.ptr, 79303b705cfSriastradh scratch->devKind); 79403b705cfSriastradh if (image) { 79503b705cfSriastradh pixman_add_traps (image, -extents.x1, -extents.y1, 79603b705cfSriastradh ntrap, (pixman_trap_t *)trap); 79703b705cfSriastradh 79803b705cfSriastradh pixman_image_unref(image); 79903b705cfSriastradh } 80003b705cfSriastradh 80103b705cfSriastradh /* XXX clip boxes */ 80203b705cfSriastradh get_drawable_deltas(picture->pDrawable, pixmap, &x, &y); 80303b705cfSriastradh sna->render.copy_boxes(sna, GXcopy, 80442542f5fSchristos &scratch->drawable, __sna_pixmap_get_bo(scratch), -extents.x1, -extents.x1, 80542542f5fSchristos &pixmap->drawable, priv->gpu_bo, x, y, 80603b705cfSriastradh &extents, 1, 0); 80703b705cfSriastradh mark_damaged(pixmap, priv, &extents, x, y); 80803b705cfSriastradh 80903b705cfSriastradh sna_pixmap_destroy(scratch); 81003b705cfSriastradh return true; 81103b705cfSriastradh} 81203b705cfSriastradh 81303b705cfSriastradhvoid 81403b705cfSriastradhsna_add_traps(PicturePtr picture, INT16 x, INT16 y, int n, xTrap *t) 81503b705cfSriastradh{ 81603b705cfSriastradh struct sna *sna; 81703b705cfSriastradh 81803b705cfSriastradh DBG(("%s (%d, %d) x %d\n", __FUNCTION__, x, y, n)); 81903b705cfSriastradh 82003b705cfSriastradh sna = to_sna_from_drawable(picture->pDrawable); 82103b705cfSriastradh if (is_gpu(sna, picture->pDrawable, PREFER_GPU_SPANS)) { 82203b705cfSriastradh if (trap_span_converter(sna, picture, x, y, n, t)) 82303b705cfSriastradh return; 82403b705cfSriastradh } 82503b705cfSriastradh 82603b705cfSriastradh if (is_gpu(sna, picture->pDrawable, PREFER_GPU_RENDER)) { 82703b705cfSriastradh if (trap_mask_converter(sna, picture, x, y, n, t)) 82803b705cfSriastradh return; 82903b705cfSriastradh 83003b705cfSriastradh if (trap_upload(picture, x, y, n, t)) 83103b705cfSriastradh return; 83203b705cfSriastradh } 83303b705cfSriastradh 83403b705cfSriastradh DBG(("%s -- fallback\n", __FUNCTION__)); 83503b705cfSriastradh if (sna_drawable_move_to_cpu(picture->pDrawable, 83603b705cfSriastradh MOVE_READ | MOVE_WRITE)) { 83703b705cfSriastradh pixman_image_t *image; 83803b705cfSriastradh int dx, dy; 83903b705cfSriastradh 84003b705cfSriastradh if (!(image = image_from_pict(picture, false, &dx, &dy))) 84103b705cfSriastradh return; 84203b705cfSriastradh 84342542f5fSchristos if (sigtrap_get() == 0) { 84442542f5fSchristos pixman_add_traps(image, x + dx, y + dy, n, (pixman_trap_t *)t); 84542542f5fSchristos sigtrap_put(); 84642542f5fSchristos } 84703b705cfSriastradh 84803b705cfSriastradh free_pixman_pict(picture, image); 84903b705cfSriastradh } 85003b705cfSriastradh} 85103b705cfSriastradh 85203b705cfSriastradh#if HAS_PIXMAN_TRIANGLES 85303b705cfSriastradhstatic void 85403b705cfSriastradhtriangles_fallback(CARD8 op, 85503b705cfSriastradh PicturePtr src, 85603b705cfSriastradh PicturePtr dst, 85703b705cfSriastradh PictFormatPtr maskFormat, 85803b705cfSriastradh INT16 xSrc, INT16 ySrc, 85903b705cfSriastradh int n, xTriangle *tri) 86003b705cfSriastradh{ 86103b705cfSriastradh ScreenPtr screen = dst->pDrawable->pScreen; 86203b705cfSriastradh 86303b705cfSriastradh DBG(("%s op=%d, count=%d\n", __FUNCTION__, op, n)); 86403b705cfSriastradh 86503b705cfSriastradh if (maskFormat) { 86603b705cfSriastradh PixmapPtr scratch; 86703b705cfSriastradh PicturePtr mask; 86803b705cfSriastradh INT16 dst_x, dst_y; 86903b705cfSriastradh BoxRec bounds; 87003b705cfSriastradh int width, height, depth; 87103b705cfSriastradh pixman_image_t *image; 87203b705cfSriastradh pixman_format_code_t format; 87303b705cfSriastradh int error; 87403b705cfSriastradh 87503b705cfSriastradh dst_x = pixman_fixed_to_int(tri[0].p1.x); 87603b705cfSriastradh dst_y = pixman_fixed_to_int(tri[0].p1.y); 87703b705cfSriastradh 87803b705cfSriastradh miTriangleBounds(n, tri, &bounds); 87903b705cfSriastradh DBG(("%s: bounds (%d, %d), (%d, %d)\n", 88003b705cfSriastradh __FUNCTION__, bounds.x1, bounds.y1, bounds.x2, bounds.y2)); 88103b705cfSriastradh 88203b705cfSriastradh if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) 88303b705cfSriastradh return; 88403b705cfSriastradh 88503b705cfSriastradh if (!sna_compute_composite_extents(&bounds, 88603b705cfSriastradh src, NULL, dst, 88703b705cfSriastradh xSrc, ySrc, 88803b705cfSriastradh 0, 0, 88903b705cfSriastradh bounds.x1, bounds.y1, 89003b705cfSriastradh bounds.x2 - bounds.x1, 89103b705cfSriastradh bounds.y2 - bounds.y1)) 89203b705cfSriastradh return; 89303b705cfSriastradh 89403b705cfSriastradh DBG(("%s: extents (%d, %d), (%d, %d)\n", 89503b705cfSriastradh __FUNCTION__, bounds.x1, bounds.y1, bounds.x2, bounds.y2)); 89603b705cfSriastradh 89703b705cfSriastradh width = bounds.x2 - bounds.x1; 89803b705cfSriastradh height = bounds.y2 - bounds.y1; 89903b705cfSriastradh bounds.x1 -= dst->pDrawable->x; 90003b705cfSriastradh bounds.y1 -= dst->pDrawable->y; 90103b705cfSriastradh depth = maskFormat->depth; 90203b705cfSriastradh format = maskFormat->format | (BitsPerPixel(depth) << 24); 90303b705cfSriastradh 90403b705cfSriastradh DBG(("%s: mask (%dx%d) depth=%d, format=%08x\n", 90503b705cfSriastradh __FUNCTION__, width, height, depth, format)); 90603b705cfSriastradh scratch = sna_pixmap_create_upload(screen, 90703b705cfSriastradh width, height, depth, 90803b705cfSriastradh KGEM_BUFFER_WRITE); 90903b705cfSriastradh if (!scratch) 91003b705cfSriastradh return; 91103b705cfSriastradh 91242542f5fSchristos memset(scratch->devPrivate.ptr, 0, (size_t)scratch->devKind*height); 91303b705cfSriastradh image = pixman_image_create_bits(format, width, height, 91403b705cfSriastradh scratch->devPrivate.ptr, 91503b705cfSriastradh scratch->devKind); 91603b705cfSriastradh if (image) { 91703b705cfSriastradh pixman_add_triangles(image, 91803b705cfSriastradh -bounds.x1, -bounds.y1, 91903b705cfSriastradh n, (pixman_triangle_t *)tri); 92003b705cfSriastradh pixman_image_unref(image); 92103b705cfSriastradh } 92203b705cfSriastradh 92303b705cfSriastradh mask = CreatePicture(0, &scratch->drawable, 92403b705cfSriastradh PictureMatchFormat(screen, depth, format), 92503b705cfSriastradh 0, 0, serverClient, &error); 92603b705cfSriastradh if (mask) { 92703b705cfSriastradh CompositePicture(op, src, mask, dst, 92803b705cfSriastradh xSrc + bounds.x1 - dst_x, 92903b705cfSriastradh ySrc + bounds.y1 - dst_y, 93003b705cfSriastradh 0, 0, 93103b705cfSriastradh bounds.x1, bounds.y1, 93203b705cfSriastradh width, height); 93303b705cfSriastradh FreePicture(mask, 0); 93403b705cfSriastradh } 93503b705cfSriastradh sna_pixmap_destroy(scratch); 93603b705cfSriastradh } else { 93703b705cfSriastradh if (dst->polyEdge == PolyEdgeSharp) 93803b705cfSriastradh maskFormat = PictureMatchFormat(screen, 1, PICT_a1); 93903b705cfSriastradh else 94003b705cfSriastradh maskFormat = PictureMatchFormat(screen, 8, PICT_a8); 94103b705cfSriastradh 94203b705cfSriastradh for (; n--; tri++) 94303b705cfSriastradh triangles_fallback(op, 94403b705cfSriastradh src, dst, maskFormat, 94503b705cfSriastradh xSrc, ySrc, 1, tri); 94603b705cfSriastradh } 94703b705cfSriastradh} 94803b705cfSriastradh 94903b705cfSriastradhvoid 95003b705cfSriastradhsna_composite_triangles(CARD8 op, 95103b705cfSriastradh PicturePtr src, 95203b705cfSriastradh PicturePtr dst, 95303b705cfSriastradh PictFormatPtr maskFormat, 95403b705cfSriastradh INT16 xSrc, INT16 ySrc, 95503b705cfSriastradh int n, xTriangle *tri) 95603b705cfSriastradh{ 95703b705cfSriastradh struct sna *sna = to_sna_from_drawable(dst->pDrawable); 95803b705cfSriastradh 95903b705cfSriastradh if (triangles_span_converter(sna, op, src, dst, maskFormat, 96003b705cfSriastradh xSrc, ySrc, 96103b705cfSriastradh n, tri)) 96203b705cfSriastradh return; 96303b705cfSriastradh 96403b705cfSriastradh if (triangles_mask_converter(op, src, dst, maskFormat, 96503b705cfSriastradh xSrc, ySrc, 96603b705cfSriastradh n, tri)) 96703b705cfSriastradh return; 96803b705cfSriastradh 96903b705cfSriastradh triangles_fallback(op, src, dst, maskFormat, xSrc, ySrc, n, tri); 97003b705cfSriastradh} 97103b705cfSriastradh 97203b705cfSriastradhstatic void 97303b705cfSriastradhtristrip_fallback(CARD8 op, 97403b705cfSriastradh PicturePtr src, 97503b705cfSriastradh PicturePtr dst, 97603b705cfSriastradh PictFormatPtr maskFormat, 97703b705cfSriastradh INT16 xSrc, INT16 ySrc, 97803b705cfSriastradh int n, xPointFixed *points) 97903b705cfSriastradh{ 98003b705cfSriastradh ScreenPtr screen = dst->pDrawable->pScreen; 98103b705cfSriastradh 98203b705cfSriastradh if (maskFormat) { 98303b705cfSriastradh PixmapPtr scratch; 98403b705cfSriastradh PicturePtr mask; 98503b705cfSriastradh INT16 dst_x, dst_y; 98603b705cfSriastradh BoxRec bounds; 98703b705cfSriastradh int width, height, depth; 98803b705cfSriastradh pixman_image_t *image; 98903b705cfSriastradh pixman_format_code_t format; 99003b705cfSriastradh int error; 99103b705cfSriastradh 99203b705cfSriastradh dst_x = pixman_fixed_to_int(points->x); 99303b705cfSriastradh dst_y = pixman_fixed_to_int(points->y); 99403b705cfSriastradh 99503b705cfSriastradh miPointFixedBounds(n, points, &bounds); 99603b705cfSriastradh DBG(("%s: bounds (%d, %d), (%d, %d)\n", 99703b705cfSriastradh __FUNCTION__, bounds.x1, bounds.y1, bounds.x2, bounds.y2)); 99803b705cfSriastradh 99903b705cfSriastradh if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) 100003b705cfSriastradh return; 100103b705cfSriastradh 100203b705cfSriastradh if (!sna_compute_composite_extents(&bounds, 100303b705cfSriastradh src, NULL, dst, 100403b705cfSriastradh xSrc, ySrc, 100503b705cfSriastradh 0, 0, 100603b705cfSriastradh bounds.x1, bounds.y1, 100703b705cfSriastradh bounds.x2 - bounds.x1, 100803b705cfSriastradh bounds.y2 - bounds.y1)) 100903b705cfSriastradh return; 101003b705cfSriastradh 101103b705cfSriastradh DBG(("%s: extents (%d, %d), (%d, %d)\n", 101203b705cfSriastradh __FUNCTION__, bounds.x1, bounds.y1, bounds.x2, bounds.y2)); 101303b705cfSriastradh 101403b705cfSriastradh width = bounds.x2 - bounds.x1; 101503b705cfSriastradh height = bounds.y2 - bounds.y1; 101603b705cfSriastradh bounds.x1 -= dst->pDrawable->x; 101703b705cfSriastradh bounds.y1 -= dst->pDrawable->y; 101803b705cfSriastradh depth = maskFormat->depth; 101903b705cfSriastradh format = maskFormat->format | (BitsPerPixel(depth) << 24); 102003b705cfSriastradh 102103b705cfSriastradh DBG(("%s: mask (%dx%d) depth=%d, format=%08x\n", 102203b705cfSriastradh __FUNCTION__, width, height, depth, format)); 102303b705cfSriastradh scratch = sna_pixmap_create_upload(screen, 102403b705cfSriastradh width, height, depth, 102503b705cfSriastradh KGEM_BUFFER_WRITE); 102603b705cfSriastradh if (!scratch) 102703b705cfSriastradh return; 102803b705cfSriastradh 102903b705cfSriastradh memset(scratch->devPrivate.ptr, 0, scratch->devKind*height); 103003b705cfSriastradh image = pixman_image_create_bits(format, width, height, 103103b705cfSriastradh scratch->devPrivate.ptr, 103203b705cfSriastradh scratch->devKind); 103303b705cfSriastradh if (image) { 103403b705cfSriastradh xTriangle tri; 103503b705cfSriastradh xPointFixed *p[3] = { &tri.p1, &tri.p2, &tri.p3 }; 103603b705cfSriastradh int i; 103703b705cfSriastradh 103803b705cfSriastradh *p[0] = points[0]; 103903b705cfSriastradh *p[1] = points[1]; 104003b705cfSriastradh *p[2] = points[2]; 104103b705cfSriastradh pixman_add_triangles(image, 104203b705cfSriastradh -bounds.x1, -bounds.y1, 104303b705cfSriastradh 1, (pixman_triangle_t *)&tri); 104403b705cfSriastradh for (i = 3; i < n; i++) { 104503b705cfSriastradh *p[i%3] = points[i]; 104603b705cfSriastradh pixman_add_triangles(image, 104703b705cfSriastradh -bounds.x1, -bounds.y1, 104803b705cfSriastradh 1, (pixman_triangle_t *)&tri); 104903b705cfSriastradh } 105003b705cfSriastradh pixman_image_unref(image); 105103b705cfSriastradh } 105203b705cfSriastradh 105303b705cfSriastradh mask = CreatePicture(0, &scratch->drawable, 105403b705cfSriastradh PictureMatchFormat(screen, depth, format), 105503b705cfSriastradh 0, 0, serverClient, &error); 105603b705cfSriastradh if (mask) { 105703b705cfSriastradh CompositePicture(op, src, mask, dst, 105803b705cfSriastradh xSrc + bounds.x1 - dst_x, 105903b705cfSriastradh ySrc + bounds.y1 - dst_y, 106003b705cfSriastradh 0, 0, 106103b705cfSriastradh bounds.x1, bounds.y1, 106203b705cfSriastradh width, height); 106303b705cfSriastradh FreePicture(mask, 0); 106403b705cfSriastradh } 106503b705cfSriastradh sna_pixmap_destroy(scratch); 106603b705cfSriastradh } else { 106703b705cfSriastradh xTriangle tri; 106803b705cfSriastradh xPointFixed *p[3] = { &tri.p1, &tri.p2, &tri.p3 }; 106903b705cfSriastradh int i; 107003b705cfSriastradh 107103b705cfSriastradh if (dst->polyEdge == PolyEdgeSharp) 107203b705cfSriastradh maskFormat = PictureMatchFormat(screen, 1, PICT_a1); 107303b705cfSriastradh else 107403b705cfSriastradh maskFormat = PictureMatchFormat(screen, 8, PICT_a8); 107503b705cfSriastradh 107603b705cfSriastradh *p[0] = points[0]; 107703b705cfSriastradh *p[1] = points[1]; 107803b705cfSriastradh *p[2] = points[2]; 107903b705cfSriastradh triangles_fallback(op, 108003b705cfSriastradh src, dst, maskFormat, 108103b705cfSriastradh xSrc, ySrc, 1, &tri); 108203b705cfSriastradh for (i = 3; i < n; i++) { 108303b705cfSriastradh *p[i%3] = points[i]; 108403b705cfSriastradh /* Should xSrc,ySrc be updated? */ 108503b705cfSriastradh triangles_fallback(op, 108603b705cfSriastradh src, dst, maskFormat, 108703b705cfSriastradh xSrc, ySrc, 1, &tri); 108803b705cfSriastradh } 108903b705cfSriastradh } 109003b705cfSriastradh} 109103b705cfSriastradh 109203b705cfSriastradhvoid 109303b705cfSriastradhsna_composite_tristrip(CARD8 op, 109403b705cfSriastradh PicturePtr src, 109503b705cfSriastradh PicturePtr dst, 109603b705cfSriastradh PictFormatPtr maskFormat, 109703b705cfSriastradh INT16 xSrc, INT16 ySrc, 109803b705cfSriastradh int n, xPointFixed *points) 109903b705cfSriastradh{ 110003b705cfSriastradh struct sna *sna = to_sna_from_drawable(dst->pDrawable); 110103b705cfSriastradh 110203b705cfSriastradh if (tristrip_span_converter(sna, op, src, dst, maskFormat, xSrc, ySrc, n, points)) 110303b705cfSriastradh return; 110403b705cfSriastradh 110503b705cfSriastradh tristrip_fallback(op, src, dst, maskFormat, xSrc, ySrc, n, points); 110603b705cfSriastradh} 110703b705cfSriastradh 110803b705cfSriastradhstatic void 110903b705cfSriastradhtrifan_fallback(CARD8 op, 111003b705cfSriastradh PicturePtr src, 111103b705cfSriastradh PicturePtr dst, 111203b705cfSriastradh PictFormatPtr maskFormat, 111303b705cfSriastradh INT16 xSrc, INT16 ySrc, 111403b705cfSriastradh int n, xPointFixed *points) 111503b705cfSriastradh{ 111603b705cfSriastradh ScreenPtr screen = dst->pDrawable->pScreen; 111703b705cfSriastradh 111803b705cfSriastradh if (maskFormat) { 111903b705cfSriastradh PixmapPtr scratch; 112003b705cfSriastradh PicturePtr mask; 112103b705cfSriastradh INT16 dst_x, dst_y; 112203b705cfSriastradh BoxRec bounds; 112303b705cfSriastradh int width, height, depth; 112403b705cfSriastradh pixman_image_t *image; 112503b705cfSriastradh pixman_format_code_t format; 112603b705cfSriastradh int error; 112703b705cfSriastradh 112803b705cfSriastradh dst_x = pixman_fixed_to_int(points->x); 112903b705cfSriastradh dst_y = pixman_fixed_to_int(points->y); 113003b705cfSriastradh 113103b705cfSriastradh miPointFixedBounds(n, points, &bounds); 113203b705cfSriastradh DBG(("%s: bounds (%d, %d), (%d, %d)\n", 113303b705cfSriastradh __FUNCTION__, bounds.x1, bounds.y1, bounds.x2, bounds.y2)); 113403b705cfSriastradh 113503b705cfSriastradh if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) 113603b705cfSriastradh return; 113703b705cfSriastradh 113803b705cfSriastradh if (!sna_compute_composite_extents(&bounds, 113903b705cfSriastradh src, NULL, dst, 114003b705cfSriastradh xSrc, ySrc, 114103b705cfSriastradh 0, 0, 114203b705cfSriastradh bounds.x1, bounds.y1, 114303b705cfSriastradh bounds.x2 - bounds.x1, 114403b705cfSriastradh bounds.y2 - bounds.y1)) 114503b705cfSriastradh return; 114603b705cfSriastradh 114703b705cfSriastradh DBG(("%s: extents (%d, %d), (%d, %d)\n", 114803b705cfSriastradh __FUNCTION__, bounds.x1, bounds.y1, bounds.x2, bounds.y2)); 114903b705cfSriastradh 115003b705cfSriastradh width = bounds.x2 - bounds.x1; 115103b705cfSriastradh height = bounds.y2 - bounds.y1; 115203b705cfSriastradh bounds.x1 -= dst->pDrawable->x; 115303b705cfSriastradh bounds.y1 -= dst->pDrawable->y; 115403b705cfSriastradh depth = maskFormat->depth; 115503b705cfSriastradh format = maskFormat->format | (BitsPerPixel(depth) << 24); 115603b705cfSriastradh 115703b705cfSriastradh DBG(("%s: mask (%dx%d) depth=%d, format=%08x\n", 115803b705cfSriastradh __FUNCTION__, width, height, depth, format)); 115903b705cfSriastradh scratch = sna_pixmap_create_upload(screen, 116003b705cfSriastradh width, height, depth, 116103b705cfSriastradh KGEM_BUFFER_WRITE); 116203b705cfSriastradh if (!scratch) 116303b705cfSriastradh return; 116403b705cfSriastradh 116503b705cfSriastradh memset(scratch->devPrivate.ptr, 0, scratch->devKind*height); 116603b705cfSriastradh image = pixman_image_create_bits(format, width, height, 116703b705cfSriastradh scratch->devPrivate.ptr, 116803b705cfSriastradh scratch->devKind); 116903b705cfSriastradh if (image) { 117003b705cfSriastradh xTriangle tri; 117103b705cfSriastradh xPointFixed *p[3] = { &tri.p1, &tri.p2, &tri.p3 }; 117203b705cfSriastradh int i; 117303b705cfSriastradh 117403b705cfSriastradh *p[0] = points[0]; 117503b705cfSriastradh *p[1] = points[1]; 117603b705cfSriastradh *p[2] = points[2]; 117703b705cfSriastradh pixman_add_triangles(image, 117803b705cfSriastradh -bounds.x1, -bounds.y1, 117903b705cfSriastradh 1, (pixman_triangle_t *)&tri); 118003b705cfSriastradh for (i = 3; i < n; i++) { 118103b705cfSriastradh *p[2 - (i&1)] = points[i]; 118203b705cfSriastradh pixman_add_triangles(image, 118303b705cfSriastradh -bounds.x1, -bounds.y1, 118403b705cfSriastradh 1, (pixman_triangle_t *)&tri); 118503b705cfSriastradh } 118603b705cfSriastradh pixman_image_unref(image); 118703b705cfSriastradh } 118803b705cfSriastradh 118903b705cfSriastradh mask = CreatePicture(0, &scratch->drawable, 119003b705cfSriastradh PictureMatchFormat(screen, depth, format), 119103b705cfSriastradh 0, 0, serverClient, &error); 119203b705cfSriastradh if (mask) { 119303b705cfSriastradh CompositePicture(op, src, mask, dst, 119403b705cfSriastradh xSrc + bounds.x1 - dst_x, 119503b705cfSriastradh ySrc + bounds.y1 - dst_y, 119603b705cfSriastradh 0, 0, 119703b705cfSriastradh bounds.x1, bounds.y1, 119803b705cfSriastradh width, height); 119903b705cfSriastradh FreePicture(mask, 0); 120003b705cfSriastradh } 120103b705cfSriastradh sna_pixmap_destroy(scratch); 120203b705cfSriastradh } else { 120303b705cfSriastradh xTriangle tri; 120403b705cfSriastradh xPointFixed *p[3] = { &tri.p1, &tri.p2, &tri.p3 }; 120503b705cfSriastradh int i; 120603b705cfSriastradh 120703b705cfSriastradh if (dst->polyEdge == PolyEdgeSharp) 120803b705cfSriastradh maskFormat = PictureMatchFormat(screen, 1, PICT_a1); 120903b705cfSriastradh else 121003b705cfSriastradh maskFormat = PictureMatchFormat(screen, 8, PICT_a8); 121103b705cfSriastradh 121203b705cfSriastradh *p[0] = points[0]; 121303b705cfSriastradh *p[1] = points[1]; 121403b705cfSriastradh *p[2] = points[2]; 121503b705cfSriastradh triangles_fallback(op, 121603b705cfSriastradh src, dst, maskFormat, 121703b705cfSriastradh xSrc, ySrc, 1, &tri); 121803b705cfSriastradh for (i = 3; i < n; i++) { 121903b705cfSriastradh *p[2 - (i&1)] = points[i]; 122003b705cfSriastradh /* Should xSrc,ySrc be updated? */ 122103b705cfSriastradh triangles_fallback(op, 122203b705cfSriastradh src, dst, maskFormat, 122303b705cfSriastradh xSrc, ySrc, 1, &tri); 122403b705cfSriastradh } 122503b705cfSriastradh } 122603b705cfSriastradh} 122703b705cfSriastradh 122803b705cfSriastradhvoid 122903b705cfSriastradhsna_composite_trifan(CARD8 op, 123003b705cfSriastradh PicturePtr src, 123103b705cfSriastradh PicturePtr dst, 123203b705cfSriastradh PictFormatPtr maskFormat, 123303b705cfSriastradh INT16 xSrc, INT16 ySrc, 123403b705cfSriastradh int n, xPointFixed *points) 123503b705cfSriastradh{ 123603b705cfSriastradh trifan_fallback(op, src, dst, maskFormat, xSrc, ySrc, n, points); 123703b705cfSriastradh} 123803b705cfSriastradh#endif 1239