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