103b705cfSriastradh/* 203b705cfSriastradh * Copyright © 2010 Intel Corporation 303b705cfSriastradh * 403b705cfSriastradh * Permission is hereby granted, free of charge, to any person obtaining a 503b705cfSriastradh * copy of this software and associated documentation files (the "Software"), 603b705cfSriastradh * to deal in the Software without restriction, including without limitation 703b705cfSriastradh * the rights to use, copy, modify, merge, publish, distribute, sublicense, 803b705cfSriastradh * and/or sell copies of the Software, and to permit persons to whom the 903b705cfSriastradh * Software is furnished to do so, subject to the following conditions: 1003b705cfSriastradh * 1103b705cfSriastradh * The above copyright notice and this permission notice (including the next 1203b705cfSriastradh * paragraph) shall be included in all copies or substantial portions of the 1303b705cfSriastradh * Software. 1403b705cfSriastradh * 1503b705cfSriastradh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1603b705cfSriastradh * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1703b705cfSriastradh * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1803b705cfSriastradh * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1903b705cfSriastradh * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2003b705cfSriastradh * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 2103b705cfSriastradh * SOFTWARE. 2203b705cfSriastradh * 2303b705cfSriastradh * Authors: 2403b705cfSriastradh * Chris Wilson <chris@chris-wilson.co.uk> 2503b705cfSriastradh * 2603b705cfSriastradh */ 2703b705cfSriastradh 2803b705cfSriastradh#ifdef HAVE_CONFIG_H 2903b705cfSriastradh#include "config.h" 3003b705cfSriastradh#endif 3103b705cfSriastradh 3203b705cfSriastradh#include "sna.h" 3303b705cfSriastradh#include "sna_render.h" 3403b705cfSriastradh#include "fb/fbpict.h" 3503b705cfSriastradh 3603b705cfSriastradhstruct sna_tile_span { 3703b705cfSriastradh BoxRec box; 3803b705cfSriastradh float opacity; 3903b705cfSriastradh}; 4003b705cfSriastradh 4103b705cfSriastradhstruct sna_tile_state { 4203b705cfSriastradh int op; 4303b705cfSriastradh PicturePtr src, mask, dst; 4403b705cfSriastradh PixmapPtr dst_pixmap; 4503b705cfSriastradh uint32_t dst_format; 4603b705cfSriastradh int16_t src_x, src_y; 4703b705cfSriastradh int16_t mask_x, mask_y; 4803b705cfSriastradh int16_t dst_x, dst_y; 4903b705cfSriastradh int16_t width, height; 5003b705cfSriastradh unsigned flags; 5103b705cfSriastradh 5203b705cfSriastradh int rect_count; 5303b705cfSriastradh int rect_size; 5403b705cfSriastradh struct sna_composite_rectangles rects_embedded[16], *rects; 5503b705cfSriastradh}; 5603b705cfSriastradh 5703b705cfSriastradhstatic void 5803b705cfSriastradhsna_tiling_composite_add_rect(struct sna_tile_state *tile, 5903b705cfSriastradh const struct sna_composite_rectangles *r) 6003b705cfSriastradh{ 6103b705cfSriastradh if (tile->rect_count == tile->rect_size) { 6203b705cfSriastradh struct sna_composite_rectangles *a; 6303b705cfSriastradh int newsize = tile->rect_size * 2; 6403b705cfSriastradh 6503b705cfSriastradh if (tile->rects == tile->rects_embedded) { 6603b705cfSriastradh a = malloc (sizeof(struct sna_composite_rectangles) * newsize); 6703b705cfSriastradh if (a == NULL) 6803b705cfSriastradh return; 6903b705cfSriastradh 7003b705cfSriastradh memcpy(a, 7103b705cfSriastradh tile->rects_embedded, 7203b705cfSriastradh sizeof(struct sna_composite_rectangles) * tile->rect_count); 7303b705cfSriastradh } else { 7403b705cfSriastradh a = realloc(tile->rects, 7503b705cfSriastradh sizeof(struct sna_composite_rectangles) * newsize); 7603b705cfSriastradh if (a == NULL) 7703b705cfSriastradh return; 7803b705cfSriastradh } 7903b705cfSriastradh 8003b705cfSriastradh tile->rects = a; 8103b705cfSriastradh tile->rect_size = newsize; 8203b705cfSriastradh } 8303b705cfSriastradh 8403b705cfSriastradh tile->rects[tile->rect_count++] = *r; 8503b705cfSriastradh} 8603b705cfSriastradh 8703b705cfSriastradhfastcall static void 8803b705cfSriastradhsna_tiling_composite_blt(struct sna *sna, 8903b705cfSriastradh const struct sna_composite_op *op, 9003b705cfSriastradh const struct sna_composite_rectangles *r) 9103b705cfSriastradh{ 9203b705cfSriastradh sna_tiling_composite_add_rect(op->priv, r); 9303b705cfSriastradh (void)sna; 9403b705cfSriastradh} 9503b705cfSriastradh 9603b705cfSriastradhfastcall static void 9703b705cfSriastradhsna_tiling_composite_box(struct sna *sna, 9803b705cfSriastradh const struct sna_composite_op *op, 9903b705cfSriastradh const BoxRec *box) 10003b705cfSriastradh{ 10103b705cfSriastradh struct sna_composite_rectangles r; 10203b705cfSriastradh 10303b705cfSriastradh r.dst.x = box->x1; 10403b705cfSriastradh r.dst.y = box->y1; 10503b705cfSriastradh r.mask = r.src = r.dst; 10603b705cfSriastradh 10703b705cfSriastradh r.width = box->x2 - box->x1; 10803b705cfSriastradh r.height = box->y2 - box->y1; 10903b705cfSriastradh 11003b705cfSriastradh sna_tiling_composite_add_rect(op->priv, &r); 11103b705cfSriastradh (void)sna; 11203b705cfSriastradh} 11303b705cfSriastradh 11403b705cfSriastradhstatic void 11503b705cfSriastradhsna_tiling_composite_boxes(struct sna *sna, 11603b705cfSriastradh const struct sna_composite_op *op, 11703b705cfSriastradh const BoxRec *box, int nbox) 11803b705cfSriastradh{ 11903b705cfSriastradh while (nbox--) { 12003b705cfSriastradh struct sna_composite_rectangles r; 12103b705cfSriastradh 12203b705cfSriastradh r.dst.x = box->x1; 12303b705cfSriastradh r.dst.y = box->y1; 12403b705cfSriastradh r.mask = r.src = r.dst; 12503b705cfSriastradh 12603b705cfSriastradh r.width = box->x2 - box->x1; 12703b705cfSriastradh r.height = box->y2 - box->y1; 12803b705cfSriastradh 12903b705cfSriastradh sna_tiling_composite_add_rect(op->priv, &r); 13003b705cfSriastradh box++; 13103b705cfSriastradh } 13203b705cfSriastradh (void)sna; 13303b705cfSriastradh} 13403b705cfSriastradh 13503b705cfSriastradhstatic void 13603b705cfSriastradhsna_tiling_composite_done(struct sna *sna, 13703b705cfSriastradh const struct sna_composite_op *op) 13803b705cfSriastradh{ 13903b705cfSriastradh struct sna_tile_state *tile = op->priv; 14003b705cfSriastradh struct sna_composite_op tmp; 14142542f5fSchristos int x, y, n, step, max_size; 14203b705cfSriastradh 14303b705cfSriastradh /* Use a small step to accommodate enlargement through tile alignment */ 14403b705cfSriastradh step = sna->render.max_3d_size; 14503b705cfSriastradh if (tile->dst_x & (8*512 / tile->dst->pDrawable->bitsPerPixel - 1) || 14603b705cfSriastradh tile->dst_y & 63) 14703b705cfSriastradh step /= 2; 14842542f5fSchristos 14942542f5fSchristos max_size = sna_max_tile_copy_size(sna, op->dst.bo, op->dst.bo); 15042542f5fSchristos if (max_size == 0) 15142542f5fSchristos goto done; 15242542f5fSchristos 15342542f5fSchristos while (step * step * 4 > max_size) 15403b705cfSriastradh step /= 2; 15503b705cfSriastradh 15603b705cfSriastradh DBG(("%s -- %dx%d, count=%d, step size=%d\n", __FUNCTION__, 15703b705cfSriastradh tile->width, tile->height, tile->rect_count, step)); 15803b705cfSriastradh 15903b705cfSriastradh if (tile->rect_count == 0) 16003b705cfSriastradh goto done; 16103b705cfSriastradh 16203b705cfSriastradh for (y = 0; y < tile->height; y += step) { 16303b705cfSriastradh int height = step; 16403b705cfSriastradh if (y + height > tile->height) 16503b705cfSriastradh height = tile->height - y; 16603b705cfSriastradh for (x = 0; x < tile->width; x += step) { 16703b705cfSriastradh int width = step; 16803b705cfSriastradh if (x + width > tile->width) 16903b705cfSriastradh width = tile->width - x; 17003b705cfSriastradh if (sna->render.composite(sna, tile->op, 17103b705cfSriastradh tile->src, tile->mask, tile->dst, 17203b705cfSriastradh tile->src_x + x, tile->src_y + y, 17303b705cfSriastradh tile->mask_x + x, tile->mask_y + y, 17403b705cfSriastradh tile->dst_x + x, tile->dst_y + y, 17503b705cfSriastradh width, height, 17642542f5fSchristos COMPOSITE_PARTIAL, memset(&tmp, 0, sizeof(tmp)))) { 17703b705cfSriastradh for (n = 0; n < tile->rect_count; n++) { 17803b705cfSriastradh const struct sna_composite_rectangles *r = &tile->rects[n]; 17903b705cfSriastradh int x1, x2, dx, y1, y2, dy; 18003b705cfSriastradh 18103b705cfSriastradh x1 = r->dst.x - tile->dst_x, dx = 0; 18203b705cfSriastradh if (x1 < x) 18303b705cfSriastradh dx = x - x1, x1 = x; 18403b705cfSriastradh y1 = r->dst.y - tile->dst_y, dy = 0; 18503b705cfSriastradh if (y1 < y) 18603b705cfSriastradh dy = y - y1, y1 = y; 18703b705cfSriastradh 18803b705cfSriastradh x2 = r->dst.x + r->width - tile->dst_x; 18903b705cfSriastradh if (x2 > x + width) 19003b705cfSriastradh x2 = x + width; 19103b705cfSriastradh y2 = r->dst.y + r->height - tile->dst_y; 19203b705cfSriastradh if (y2 > y + height) 19303b705cfSriastradh y2 = y + height; 19403b705cfSriastradh 19503b705cfSriastradh DBG(("%s: rect[%d] = (%d, %d)x(%d,%d), tile=(%d,%d)x(%d, %d), blt=(%d,%d),(%d,%d), delta=(%d,%d)\n", 19603b705cfSriastradh __FUNCTION__, n, 19703b705cfSriastradh r->dst.x, r->dst.y, 19803b705cfSriastradh r->width, r->height, 19903b705cfSriastradh x, y, width, height, 20003b705cfSriastradh x1, y1, x2, y2, 20103b705cfSriastradh dx, dy)); 20203b705cfSriastradh 20303b705cfSriastradh if (y2 > y1 && x2 > x1) { 20403b705cfSriastradh struct sna_composite_rectangles rr; 20503b705cfSriastradh rr.src.x = dx + r->src.x; 20603b705cfSriastradh rr.src.y = dy + r->src.y; 20703b705cfSriastradh 20803b705cfSriastradh rr.mask.x = dx + r->mask.x; 20903b705cfSriastradh rr.mask.y = dy + r->mask.y; 21003b705cfSriastradh 21103b705cfSriastradh rr.dst.x = dx + r->dst.x; 21203b705cfSriastradh rr.dst.y = dy + r->dst.y; 21303b705cfSriastradh 21403b705cfSriastradh rr.width = x2 - x1; 21503b705cfSriastradh rr.height = y2 - y1; 21603b705cfSriastradh 21703b705cfSriastradh tmp.blt(sna, &tmp, &rr); 21803b705cfSriastradh } 21903b705cfSriastradh } 22003b705cfSriastradh tmp.done(sna, &tmp); 22103b705cfSriastradh } else { 22203b705cfSriastradh unsigned int flags; 22303b705cfSriastradh DBG(("%s -- falback\n", __FUNCTION__)); 22403b705cfSriastradh 22503b705cfSriastradh if (tile->op <= PictOpSrc) 22603b705cfSriastradh flags = MOVE_WRITE; 22703b705cfSriastradh else 22803b705cfSriastradh flags = MOVE_WRITE | MOVE_READ; 22903b705cfSriastradh if (!sna_drawable_move_to_cpu(tile->dst->pDrawable, 23003b705cfSriastradh flags)) 23103b705cfSriastradh goto done; 23203b705cfSriastradh if (tile->dst->alphaMap && 23303b705cfSriastradh !sna_drawable_move_to_cpu(tile->dst->alphaMap->pDrawable, 23403b705cfSriastradh flags)) 23503b705cfSriastradh goto done; 23603b705cfSriastradh 23703b705cfSriastradh if (tile->src->pDrawable && 23803b705cfSriastradh !sna_drawable_move_to_cpu(tile->src->pDrawable, 23903b705cfSriastradh MOVE_READ)) 24003b705cfSriastradh goto done; 24103b705cfSriastradh if (tile->src->alphaMap && 24203b705cfSriastradh !sna_drawable_move_to_cpu(tile->src->alphaMap->pDrawable, 24303b705cfSriastradh MOVE_READ)) 24403b705cfSriastradh goto done; 24503b705cfSriastradh 24603b705cfSriastradh if (tile->mask && tile->mask->pDrawable && 24703b705cfSriastradh !sna_drawable_move_to_cpu(tile->mask->pDrawable, 24803b705cfSriastradh MOVE_READ)) 24903b705cfSriastradh goto done; 25003b705cfSriastradh 25103b705cfSriastradh if (tile->mask && tile->mask->alphaMap && 25203b705cfSriastradh !sna_drawable_move_to_cpu(tile->mask->alphaMap->pDrawable, 25303b705cfSriastradh MOVE_READ)) 25403b705cfSriastradh goto done; 25503b705cfSriastradh 25642542f5fSchristos if (sigtrap_get() == 0) { 25742542f5fSchristos fbComposite(tile->op, 25842542f5fSchristos tile->src, tile->mask, tile->dst, 25942542f5fSchristos tile->src_x + x, tile->src_y + y, 26042542f5fSchristos tile->mask_x + x, tile->mask_y + y, 26142542f5fSchristos tile->dst_x + x, tile->dst_y + y, 26242542f5fSchristos width, height); 26342542f5fSchristos sigtrap_put(); 26442542f5fSchristos } 26503b705cfSriastradh } 26603b705cfSriastradh } 26703b705cfSriastradh } 26803b705cfSriastradh 26903b705cfSriastradhdone: 27003b705cfSriastradh if (tile->rects != tile->rects_embedded) 27103b705cfSriastradh free(tile->rects); 27203b705cfSriastradh free(tile); 27303b705cfSriastradh} 27403b705cfSriastradh 27503b705cfSriastradhbool 27603b705cfSriastradhsna_tiling_composite(uint32_t op, 27703b705cfSriastradh PicturePtr src, 27803b705cfSriastradh PicturePtr mask, 27903b705cfSriastradh PicturePtr dst, 28003b705cfSriastradh int16_t src_x, int16_t src_y, 28103b705cfSriastradh int16_t mask_x, int16_t mask_y, 28203b705cfSriastradh int16_t dst_x, int16_t dst_y, 28303b705cfSriastradh int16_t width, int16_t height, 28403b705cfSriastradh struct sna_composite_op *tmp) 28503b705cfSriastradh{ 28603b705cfSriastradh struct sna_tile_state *tile; 28703b705cfSriastradh struct sna_pixmap *priv; 28803b705cfSriastradh 28903b705cfSriastradh DBG(("%s size=(%d, %d), tile=%d\n", 29003b705cfSriastradh __FUNCTION__, width, height, 29103b705cfSriastradh to_sna_from_drawable(dst->pDrawable)->render.max_3d_size)); 29203b705cfSriastradh 29303b705cfSriastradh priv = sna_pixmap(get_drawable_pixmap(dst->pDrawable)); 29403b705cfSriastradh if (priv == NULL || priv->gpu_bo == NULL) 29503b705cfSriastradh return false; 29603b705cfSriastradh 29703b705cfSriastradh tile = malloc(sizeof(*tile)); 29803b705cfSriastradh if (!tile) 29903b705cfSriastradh return false; 30003b705cfSriastradh 30103b705cfSriastradh tile->op = op; 30203b705cfSriastradh 30303b705cfSriastradh tile->src = src; 30403b705cfSriastradh tile->mask = mask; 30503b705cfSriastradh tile->dst = dst; 30603b705cfSriastradh 30703b705cfSriastradh tile->src_x = src_x; 30803b705cfSriastradh tile->src_y = src_y; 30903b705cfSriastradh tile->mask_x = mask_x; 31003b705cfSriastradh tile->mask_y = mask_y; 31103b705cfSriastradh tile->dst_x = dst_x; 31203b705cfSriastradh tile->dst_y = dst_y; 31303b705cfSriastradh tile->width = width; 31403b705cfSriastradh tile->height = height; 31503b705cfSriastradh tile->rects = tile->rects_embedded; 31603b705cfSriastradh tile->rect_count = 0; 31703b705cfSriastradh tile->rect_size = ARRAY_SIZE(tile->rects_embedded); 31803b705cfSriastradh 31903b705cfSriastradh tmp->blt = sna_tiling_composite_blt; 32003b705cfSriastradh tmp->box = sna_tiling_composite_box; 32103b705cfSriastradh tmp->boxes = sna_tiling_composite_boxes; 32203b705cfSriastradh tmp->done = sna_tiling_composite_done; 32303b705cfSriastradh 32403b705cfSriastradh tmp->priv = tile; 32542542f5fSchristos tmp->dst.bo = priv->gpu_bo; 32603b705cfSriastradh return true; 32703b705cfSriastradh} 32803b705cfSriastradh 32903b705cfSriastradhfastcall static void 33003b705cfSriastradhsna_tiling_composite_spans_box(struct sna *sna, 33103b705cfSriastradh const struct sna_composite_spans_op *op, 33203b705cfSriastradh const BoxRec *box, float opacity) 33303b705cfSriastradh{ 33403b705cfSriastradh struct sna_tile_state *tile = op->base.priv; 33503b705cfSriastradh struct sna_tile_span *a; 33603b705cfSriastradh 33703b705cfSriastradh if (tile->rect_count == tile->rect_size) { 33803b705cfSriastradh int newsize = tile->rect_size * 2; 33903b705cfSriastradh 34003b705cfSriastradh if (tile->rects == tile->rects_embedded) { 34103b705cfSriastradh a = malloc (sizeof(struct sna_tile_span) * newsize); 34203b705cfSriastradh if (a == NULL) 34303b705cfSriastradh return; 34403b705cfSriastradh 34503b705cfSriastradh memcpy(a, 34603b705cfSriastradh tile->rects_embedded, 34703b705cfSriastradh sizeof(struct sna_tile_span) * tile->rect_count); 34803b705cfSriastradh } else { 34903b705cfSriastradh a = realloc(tile->rects, 35003b705cfSriastradh sizeof(struct sna_tile_span) * newsize); 35103b705cfSriastradh if (a == NULL) 35203b705cfSriastradh return; 35303b705cfSriastradh } 35403b705cfSriastradh 35503b705cfSriastradh tile->rects = (void *)a; 35603b705cfSriastradh tile->rect_size = newsize; 35703b705cfSriastradh } else 35803b705cfSriastradh a = (void *)tile->rects; 35903b705cfSriastradh 36003b705cfSriastradh a[tile->rect_count].box = *box; 36103b705cfSriastradh a[tile->rect_count].opacity = opacity; 36203b705cfSriastradh tile->rect_count++; 36303b705cfSriastradh (void)sna; 36403b705cfSriastradh} 36503b705cfSriastradh 36603b705cfSriastradhstatic void 36703b705cfSriastradhsna_tiling_composite_spans_boxes(struct sna *sna, 36803b705cfSriastradh const struct sna_composite_spans_op *op, 36903b705cfSriastradh const BoxRec *box, int nbox, float opacity) 37003b705cfSriastradh{ 37103b705cfSriastradh while (nbox--) 372fe8aea9eSmrg sna_tiling_composite_spans_box(sna, op, box++, opacity); 37303b705cfSriastradh} 37403b705cfSriastradh 37503b705cfSriastradhfastcall static void 37603b705cfSriastradhsna_tiling_composite_spans_done(struct sna *sna, 37703b705cfSriastradh const struct sna_composite_spans_op *op) 37803b705cfSriastradh{ 37903b705cfSriastradh struct sna_tile_state *tile = op->base.priv; 38003b705cfSriastradh struct sna_composite_spans_op tmp; 38142542f5fSchristos int x, y, n, step, max_size; 38203b705cfSriastradh bool force_fallback = false; 38303b705cfSriastradh 38403b705cfSriastradh /* Use a small step to accommodate enlargement through tile alignment */ 38503b705cfSriastradh step = sna->render.max_3d_size; 38603b705cfSriastradh if (tile->dst_x & (8*512 / tile->dst->pDrawable->bitsPerPixel - 1) || 38703b705cfSriastradh tile->dst_y & 63) 38803b705cfSriastradh step /= 2; 38942542f5fSchristos 39042542f5fSchristos max_size = sna_max_tile_copy_size(sna, op->base.dst.bo, op->base.dst.bo); 39142542f5fSchristos if (max_size == 0) 39242542f5fSchristos goto done; 39342542f5fSchristos 39442542f5fSchristos while (step * step * 4 > max_size) 39503b705cfSriastradh step /= 2; 39603b705cfSriastradh 39703b705cfSriastradh DBG(("%s -- %dx%d, count=%d, step size=%d\n", __FUNCTION__, 39803b705cfSriastradh tile->width, tile->height, tile->rect_count, step)); 39903b705cfSriastradh 40003b705cfSriastradh if (tile->rect_count == 0) 40103b705cfSriastradh goto done; 40203b705cfSriastradh 40303b705cfSriastradh for (y = 0; y < tile->height; y += step) { 40403b705cfSriastradh int height = step; 40503b705cfSriastradh if (y + height > tile->height) 40603b705cfSriastradh height = tile->height - y; 40703b705cfSriastradh for (x = 0; x < tile->width; x += step) { 40803b705cfSriastradh const struct sna_tile_span *r = (void *)tile->rects; 40903b705cfSriastradh int width = step; 41003b705cfSriastradh if (x + width > tile->width) 41103b705cfSriastradh width = tile->width - x; 41203b705cfSriastradh if (!force_fallback && 41303b705cfSriastradh sna->render.composite_spans(sna, tile->op, 41403b705cfSriastradh tile->src, tile->dst, 41503b705cfSriastradh tile->src_x + x, tile->src_y + y, 41603b705cfSriastradh tile->dst_x + x, tile->dst_y + y, 41703b705cfSriastradh width, height, tile->flags, 41803b705cfSriastradh memset(&tmp, 0, sizeof(tmp)))) { 41903b705cfSriastradh for (n = 0; n < tile->rect_count; n++) { 42003b705cfSriastradh BoxRec b; 42103b705cfSriastradh 42203b705cfSriastradh b.x1 = r->box.x1 - tile->dst_x; 42303b705cfSriastradh if (b.x1 < x) 42403b705cfSriastradh b.x1 = x; 42503b705cfSriastradh 42603b705cfSriastradh b.y1 = r->box.y1 - tile->dst_y; 42703b705cfSriastradh if (b.y1 < y) 42803b705cfSriastradh b.y1 = y; 42903b705cfSriastradh 43003b705cfSriastradh b.x2 = r->box.x2 - tile->dst_x; 43103b705cfSriastradh if (b.x2 > x + width) 43203b705cfSriastradh b.x2 = x + width; 43303b705cfSriastradh 43403b705cfSriastradh b.y2 = r->box.y2 - tile->dst_y; 43503b705cfSriastradh if (b.y2 > y + height) 43603b705cfSriastradh b.y2 = y + height; 43703b705cfSriastradh 43803b705cfSriastradh DBG(("%s: rect[%d] = (%d, %d)x(%d,%d), tile=(%d,%d)x(%d, %d), blt=(%d,%d),(%d,%d)\n", 43903b705cfSriastradh __FUNCTION__, n, 44003b705cfSriastradh r->box.x1, r->box.y1, 44103b705cfSriastradh r->box.x2-r->box.x1, r->box.y2-r->box.y1, 44203b705cfSriastradh x, y, width, height, 44303b705cfSriastradh b.x1, b.y1, b.x2, b.y2)); 44403b705cfSriastradh 44503b705cfSriastradh if (b.y2 > b.y1 && b.x2 > b.x1) 44603b705cfSriastradh tmp.box(sna, &tmp, &b, r->opacity); 44703b705cfSriastradh r++; 44803b705cfSriastradh } 44903b705cfSriastradh tmp.done(sna, &tmp); 45003b705cfSriastradh } else { 45103b705cfSriastradh unsigned int flags; 45203b705cfSriastradh 45303b705cfSriastradh DBG(("%s -- falback\n", __FUNCTION__)); 45403b705cfSriastradh 45503b705cfSriastradh if (tile->op <= PictOpSrc) 45603b705cfSriastradh flags = MOVE_WRITE; 45703b705cfSriastradh else 45803b705cfSriastradh flags = MOVE_WRITE | MOVE_READ; 45903b705cfSriastradh if (!sna_drawable_move_to_cpu(tile->dst->pDrawable, 46003b705cfSriastradh flags)) 46103b705cfSriastradh goto done; 46203b705cfSriastradh if (tile->dst->alphaMap && 46303b705cfSriastradh !sna_drawable_move_to_cpu(tile->dst->alphaMap->pDrawable, 46403b705cfSriastradh flags)) 46503b705cfSriastradh goto done; 46603b705cfSriastradh 46703b705cfSriastradh if (tile->src->pDrawable && 46803b705cfSriastradh !sna_drawable_move_to_cpu(tile->src->pDrawable, 46903b705cfSriastradh MOVE_READ)) 47003b705cfSriastradh goto done; 47103b705cfSriastradh if (tile->src->alphaMap && 47203b705cfSriastradh !sna_drawable_move_to_cpu(tile->src->alphaMap->pDrawable, 47303b705cfSriastradh MOVE_READ)) 47403b705cfSriastradh goto done; 47503b705cfSriastradh 47603b705cfSriastradh for (n = 0; n < tile->rect_count; n++) { 47703b705cfSriastradh BoxRec b; 47803b705cfSriastradh 47903b705cfSriastradh b.x1 = r->box.x1 - tile->dst_x; 48003b705cfSriastradh if (b.x1 < x) 48103b705cfSriastradh b.x1 = x; 48203b705cfSriastradh 48303b705cfSriastradh b.y1 = r->box.y1 - tile->dst_y; 48403b705cfSriastradh if (b.y1 < y) 48503b705cfSriastradh b.y1 = y; 48603b705cfSriastradh 48703b705cfSriastradh b.x2 = r->box.x2 - tile->dst_x; 48803b705cfSriastradh if (b.x2 > x + width) 48903b705cfSriastradh b.x2 = x + width; 49003b705cfSriastradh 49103b705cfSriastradh b.y2 = r->box.y2 - tile->dst_y; 49203b705cfSriastradh if (b.y2 > y + height) 49303b705cfSriastradh b.y2 = y + height; 49403b705cfSriastradh 49503b705cfSriastradh DBG(("%s: rect[%d] = (%d, %d)x(%d,%d), tile=(%d,%d)x(%d, %d), blt=(%d,%d),(%d,%d)\n", 49603b705cfSriastradh __FUNCTION__, n, 49703b705cfSriastradh r->box.x1, r->box.y1, 49803b705cfSriastradh r->box.x2-r->box.x1, r->box.y2-r->box.y1, 49903b705cfSriastradh x, y, width, height, 50003b705cfSriastradh b.x1, b.y1, b.x2, b.y2)); 50103b705cfSriastradh 50203b705cfSriastradh if (b.y2 > b.y1 && b.x2 > b.x1) { 50303b705cfSriastradh xRenderColor alpha; 50403b705cfSriastradh PicturePtr mask; 50503b705cfSriastradh int error; 50603b705cfSriastradh 50703b705cfSriastradh alpha.red = alpha.green = alpha.blue = 0; 50803b705cfSriastradh alpha.alpha = r->opacity * 0xffff; 50903b705cfSriastradh 51003b705cfSriastradh mask = CreateSolidPicture(0, &alpha, &error); 51103b705cfSriastradh if (!mask) 51203b705cfSriastradh goto done; 51303b705cfSriastradh 51442542f5fSchristos if (sigtrap_get() == 0) { 51542542f5fSchristos fbComposite(tile->op, 51642542f5fSchristos tile->src, mask, tile->dst, 51742542f5fSchristos tile->src_x + x, tile->src_y + y, 51842542f5fSchristos 0, 0, 51942542f5fSchristos tile->dst_x + x, tile->dst_y + y, 52042542f5fSchristos width, height); 52142542f5fSchristos sigtrap_put(); 52242542f5fSchristos } 52303b705cfSriastradh 52403b705cfSriastradh FreePicture(mask, 0); 52503b705cfSriastradh } 52603b705cfSriastradh r++; 52703b705cfSriastradh } 52803b705cfSriastradh 52903b705cfSriastradh force_fallback = true; 53003b705cfSriastradh } 53103b705cfSriastradh } 53203b705cfSriastradh } 53303b705cfSriastradh 53403b705cfSriastradhdone: 53503b705cfSriastradh if (tile->rects != tile->rects_embedded) 53603b705cfSriastradh free(tile->rects); 53703b705cfSriastradh free(tile); 53803b705cfSriastradh} 53903b705cfSriastradh 54003b705cfSriastradhbool 54103b705cfSriastradhsna_tiling_composite_spans(uint32_t op, 54203b705cfSriastradh PicturePtr src, 54303b705cfSriastradh PicturePtr dst, 54403b705cfSriastradh int16_t src_x, int16_t src_y, 54503b705cfSriastradh int16_t dst_x, int16_t dst_y, 54603b705cfSriastradh int16_t width, int16_t height, 54703b705cfSriastradh unsigned flags, 54803b705cfSriastradh struct sna_composite_spans_op *tmp) 54903b705cfSriastradh{ 55003b705cfSriastradh struct sna_tile_state *tile; 55103b705cfSriastradh struct sna_pixmap *priv; 55203b705cfSriastradh 55303b705cfSriastradh DBG(("%s size=(%d, %d), tile=%d\n", 55403b705cfSriastradh __FUNCTION__, width, height, 55503b705cfSriastradh to_sna_from_drawable(dst->pDrawable)->render.max_3d_size)); 55603b705cfSriastradh 55703b705cfSriastradh priv = sna_pixmap(get_drawable_pixmap(dst->pDrawable)); 55803b705cfSriastradh if (priv == NULL || priv->gpu_bo == NULL) 55903b705cfSriastradh return false; 56003b705cfSriastradh 56103b705cfSriastradh tile = malloc(sizeof(*tile)); 56203b705cfSriastradh if (!tile) 56303b705cfSriastradh return false; 56403b705cfSriastradh 56503b705cfSriastradh tile->op = op; 56603b705cfSriastradh tile->flags = flags; 56703b705cfSriastradh 56803b705cfSriastradh tile->src = src; 56903b705cfSriastradh tile->mask = NULL; 57003b705cfSriastradh tile->dst = dst; 57103b705cfSriastradh 57203b705cfSriastradh tile->src_x = src_x; 57303b705cfSriastradh tile->src_y = src_y; 57403b705cfSriastradh tile->mask_x = 0; 57503b705cfSriastradh tile->mask_y = 0; 57603b705cfSriastradh tile->dst_x = dst_x; 57703b705cfSriastradh tile->dst_y = dst_y; 57803b705cfSriastradh tile->width = width; 57903b705cfSriastradh tile->height = height; 58003b705cfSriastradh tile->rects = tile->rects_embedded; 58103b705cfSriastradh tile->rect_count = 0; 58203b705cfSriastradh tile->rect_size = ARRAY_SIZE(tile->rects_embedded); 583fe8aea9eSmrg COMPILE_TIME_ASSERT(sizeof(tile->rects_embedded[0]) >= sizeof(struct sna_tile_span)); 58403b705cfSriastradh 58503b705cfSriastradh tmp->box = sna_tiling_composite_spans_box; 58603b705cfSriastradh tmp->boxes = sna_tiling_composite_spans_boxes; 58703b705cfSriastradh tmp->done = sna_tiling_composite_spans_done; 58803b705cfSriastradh 58903b705cfSriastradh tmp->base.priv = tile; 59042542f5fSchristos tmp->base.dst.bo = priv->gpu_bo; 59103b705cfSriastradh return true; 59203b705cfSriastradh} 59303b705cfSriastradh 59403b705cfSriastradhbool 59503b705cfSriastradhsna_tiling_fill_boxes(struct sna *sna, 59603b705cfSriastradh CARD8 op, 59703b705cfSriastradh PictFormat format, 59803b705cfSriastradh const xRenderColor *color, 59942542f5fSchristos const DrawableRec *dst, struct kgem_bo *dst_bo, 60003b705cfSriastradh const BoxRec *box, int n) 60103b705cfSriastradh{ 60203b705cfSriastradh RegionRec region, tile, this; 60303b705cfSriastradh struct kgem_bo *bo; 60442542f5fSchristos int step, max_size; 60503b705cfSriastradh bool ret = false; 60603b705cfSriastradh 60703b705cfSriastradh pixman_region_init_rects(®ion, box, n); 60803b705cfSriastradh 60903b705cfSriastradh /* Use a small step to accommodate enlargement through tile alignment */ 61003b705cfSriastradh step = sna->render.max_3d_size; 61142542f5fSchristos if (region.extents.x1 & (8*512 / dst->bitsPerPixel - 1) || 61203b705cfSriastradh region.extents.y1 & 63) 61303b705cfSriastradh step /= 2; 61442542f5fSchristos 61542542f5fSchristos max_size = sna_max_tile_copy_size(sna, dst_bo, dst_bo); 61642542f5fSchristos if (max_size == 0) 61742542f5fSchristos goto done; 61842542f5fSchristos 61942542f5fSchristos while (step * step * 4 > max_size) 62003b705cfSriastradh step /= 2; 62103b705cfSriastradh 62203b705cfSriastradh DBG(("%s (op=%d, format=%x, color=(%04x,%04x,%04x, %04x), tile.size=%d, box=%dx[(%d, %d), (%d, %d)])\n", 62303b705cfSriastradh __FUNCTION__, op, (int)format, 62403b705cfSriastradh color->red, color->green, color->blue, color->alpha, 62503b705cfSriastradh step, n, 62603b705cfSriastradh region.extents.x1, region.extents.y1, 62703b705cfSriastradh region.extents.x2, region.extents.y2)); 62803b705cfSriastradh 62903b705cfSriastradh for (tile.extents.y1 = tile.extents.y2 = region.extents.y1; 63003b705cfSriastradh tile.extents.y2 < region.extents.y2; 63103b705cfSriastradh tile.extents.y1 = tile.extents.y2) { 63203b705cfSriastradh int y2 = tile.extents.y1 + step; 63303b705cfSriastradh if (y2 > region.extents.y2) 63403b705cfSriastradh y2 = region.extents.y2; 63503b705cfSriastradh tile.extents.y2 = y2; 63603b705cfSriastradh 63703b705cfSriastradh for (tile.extents.x1 = tile.extents.x2 = region.extents.x1; 63803b705cfSriastradh tile.extents.x2 < region.extents.x2; 63903b705cfSriastradh tile.extents.x1 = tile.extents.x2) { 64042542f5fSchristos DrawableRec tmp; 64103b705cfSriastradh int x2 = tile.extents.x1 + step; 64203b705cfSriastradh if (x2 > region.extents.x2) 64303b705cfSriastradh x2 = region.extents.x2; 64403b705cfSriastradh tile.extents.x2 = x2; 64503b705cfSriastradh 64603b705cfSriastradh tile.data = NULL; 64703b705cfSriastradh 64803b705cfSriastradh RegionNull(&this); 64903b705cfSriastradh RegionIntersect(&this, ®ion, &tile); 65003b705cfSriastradh if (RegionNil(&this)) 65103b705cfSriastradh continue; 65203b705cfSriastradh 65342542f5fSchristos tmp.width = this.extents.x2 - this.extents.x1; 65442542f5fSchristos tmp.height = this.extents.y2 - this.extents.y1; 65542542f5fSchristos tmp.depth = dst->depth; 65642542f5fSchristos tmp.bitsPerPixel = dst->bitsPerPixel; 65703b705cfSriastradh 65803b705cfSriastradh bo = kgem_create_2d(&sna->kgem, 65942542f5fSchristos tmp.width, 66042542f5fSchristos tmp.height, 66142542f5fSchristos dst->bitsPerPixel, 66203b705cfSriastradh kgem_choose_tiling(&sna->kgem, 66303b705cfSriastradh I915_TILING_X, 66442542f5fSchristos tmp.width, 66542542f5fSchristos tmp.height, 66642542f5fSchristos dst->bitsPerPixel), 66703b705cfSriastradh CREATE_TEMPORARY); 66803b705cfSriastradh if (bo) { 66903b705cfSriastradh int16_t dx = this.extents.x1; 67003b705cfSriastradh int16_t dy = this.extents.y1; 67103b705cfSriastradh 67203b705cfSriastradh assert(kgem_bo_can_blt(&sna->kgem, bo)); 67303b705cfSriastradh 67442542f5fSchristos if (op > PictOpSrc && 67542542f5fSchristos !sna->render.copy_boxes(sna, GXcopy, 67642542f5fSchristos dst, dst_bo, 0, 0, 67742542f5fSchristos &tmp, bo, -dx, -dy, 67842542f5fSchristos region_rects(&this), region_num_rects(&this), 0)) 67903b705cfSriastradh goto err; 68003b705cfSriastradh 68103b705cfSriastradh RegionTranslate(&this, -dx, -dy); 68242542f5fSchristos if (!sna->render.fill_boxes(sna, op, format, color, &tmp, bo, 68342542f5fSchristos region_rects(&this), region_num_rects(&this))) 68403b705cfSriastradh goto err; 68503b705cfSriastradh 68603b705cfSriastradh if (!sna->render.copy_boxes(sna, GXcopy, 68742542f5fSchristos &tmp, bo, 0, 0, 68842542f5fSchristos dst, dst_bo, dx, dy, 68942542f5fSchristos region_rects(&this), region_num_rects(&this), 0)) 69003b705cfSriastradh goto err; 69103b705cfSriastradh 69203b705cfSriastradh kgem_bo_destroy(&sna->kgem, bo); 69303b705cfSriastradh } 69403b705cfSriastradh RegionUninit(&this); 69503b705cfSriastradh } 69603b705cfSriastradh } 69703b705cfSriastradh 69803b705cfSriastradh ret = true; 69903b705cfSriastradh goto done; 70003b705cfSriastradherr: 70103b705cfSriastradh kgem_bo_destroy(&sna->kgem, bo); 70203b705cfSriastradh RegionUninit(&this); 70303b705cfSriastradhdone: 70403b705cfSriastradh pixman_region_fini(®ion); 70503b705cfSriastradh return ret; 70603b705cfSriastradh} 70703b705cfSriastradh 70842542f5fSchristosfastcall static void 70942542f5fSchristostiling_blt(struct sna *sna, 71042542f5fSchristos const struct sna_composite_op *op, 71142542f5fSchristos const struct sna_composite_rectangles *r) 71242542f5fSchristos{ 71342542f5fSchristos int x1, x2, y1, y2; 71442542f5fSchristos int src_x, src_y; 71542542f5fSchristos BoxRec box; 71642542f5fSchristos 71742542f5fSchristos DBG(("%s: src=(%d, %d), dst=(%d, %d), size=(%d, %d)\n", 71842542f5fSchristos __FUNCTION__, 71942542f5fSchristos r->src.x, r->src.y, 72042542f5fSchristos r->dst.x, r->dst.y, 72142542f5fSchristos r->width, r->height)); 72242542f5fSchristos 72342542f5fSchristos /* XXX higher layer should have clipped? */ 72442542f5fSchristos 72542542f5fSchristos x1 = r->dst.x + op->dst.x; 72642542f5fSchristos y1 = r->dst.y + op->dst.y; 72742542f5fSchristos x2 = x1 + r->width; 72842542f5fSchristos y2 = y1 + r->height; 72942542f5fSchristos 73042542f5fSchristos src_x = r->src.x - x1 + op->u.blt.sx; 73142542f5fSchristos src_y = r->src.y - y1 + op->u.blt.sy; 73242542f5fSchristos 73342542f5fSchristos /* clip against dst */ 73442542f5fSchristos if (x1 < 0) 73542542f5fSchristos x1 = 0; 73642542f5fSchristos if (y1 < 0) 73742542f5fSchristos y1 = 0; 73842542f5fSchristos 73942542f5fSchristos if (x2 > op->dst.width) 74042542f5fSchristos x2 = op->dst.width; 74142542f5fSchristos 74242542f5fSchristos if (y2 > op->dst.height) 74342542f5fSchristos y2 = op->dst.height; 74442542f5fSchristos 74542542f5fSchristos DBG(("%s: box=(%d, %d), (%d, %d)\n", __FUNCTION__, x1, y1, x2, y2)); 74642542f5fSchristos 74742542f5fSchristos if (x2 <= x1 || y2 <= y1) 74842542f5fSchristos return; 74942542f5fSchristos 75042542f5fSchristos box.x1 = x1; box.y1 = y1; 75142542f5fSchristos box.x2 = x2; box.y2 = y2; 75242542f5fSchristos sna_tiling_blt_copy_boxes(sna, GXcopy, 75342542f5fSchristos op->src.bo, src_x, src_y, 75442542f5fSchristos op->dst.bo, 0, 0, 75542542f5fSchristos op->u.blt.bpp, 75642542f5fSchristos &box, 1); 75742542f5fSchristos} 75842542f5fSchristos 75942542f5fSchristosfastcall static void 76042542f5fSchristostiling_blt_box(struct sna *sna, 76142542f5fSchristos const struct sna_composite_op *op, 76242542f5fSchristos const BoxRec *box) 76342542f5fSchristos{ 76442542f5fSchristos DBG(("%s: box (%d, %d), (%d, %d)\n", 76542542f5fSchristos __FUNCTION__, box->x1, box->y1, box->x2, box->y2)); 76642542f5fSchristos sna_tiling_blt_copy_boxes(sna, GXcopy, 76742542f5fSchristos op->src.bo, op->u.blt.sx, op->u.blt.sy, 76842542f5fSchristos op->dst.bo, op->dst.x, op->dst.y, 76942542f5fSchristos op->u.blt.bpp, 77042542f5fSchristos box, 1); 77142542f5fSchristos} 77242542f5fSchristos 77342542f5fSchristosstatic void 77442542f5fSchristostiling_blt_boxes(struct sna *sna, 77542542f5fSchristos const struct sna_composite_op *op, 77642542f5fSchristos const BoxRec *box, int nbox) 77742542f5fSchristos{ 77842542f5fSchristos DBG(("%s: nbox=%d\n", __FUNCTION__, nbox)); 77942542f5fSchristos sna_tiling_blt_copy_boxes(sna, GXcopy, 78042542f5fSchristos op->src.bo, op->u.blt.sx, op->u.blt.sy, 78142542f5fSchristos op->dst.bo, op->dst.x, op->dst.y, 78242542f5fSchristos op->u.blt.bpp, 78342542f5fSchristos box, nbox); 78442542f5fSchristos} 78542542f5fSchristos 78642542f5fSchristosstatic bool 78742542f5fSchristossna_tiling_blt_copy_boxes__with_alpha(struct sna *sna, uint8_t alu, 78842542f5fSchristos struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy, 78942542f5fSchristos struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy, 79042542f5fSchristos int bpp, int alpha_fixup, 79142542f5fSchristos const BoxRec *box, int nbox) 79242542f5fSchristos{ 79342542f5fSchristos RegionRec region, tile, this; 79442542f5fSchristos struct kgem_bo *bo; 79542542f5fSchristos int max_size, step; 79642542f5fSchristos bool ret = false; 79742542f5fSchristos 79842542f5fSchristos if (wedged(sna) || 79942542f5fSchristos !kgem_bo_can_blt(&sna->kgem, src_bo) || 80042542f5fSchristos !kgem_bo_can_blt(&sna->kgem, dst_bo)) { 80142542f5fSchristos /* XXX */ 80242542f5fSchristos DBG(("%s: tiling blt fail: src?=%d, dst?=%d\n", 80342542f5fSchristos __FUNCTION__, 80442542f5fSchristos kgem_bo_can_blt(&sna->kgem, src_bo), 80542542f5fSchristos kgem_bo_can_blt(&sna->kgem, dst_bo))); 80642542f5fSchristos return false; 80742542f5fSchristos } 80842542f5fSchristos 80942542f5fSchristos max_size = sna_max_tile_copy_size(sna, src_bo, dst_bo); 81042542f5fSchristos if (max_size == 0) 81142542f5fSchristos return false; 81242542f5fSchristos 81342542f5fSchristos pixman_region_init_rects(®ion, box, nbox); 81442542f5fSchristos 81542542f5fSchristos /* Use a small step to accommodate enlargement through tile alignment */ 81642542f5fSchristos step = sna->render.max_3d_size; 81742542f5fSchristos if (region.extents.x1 & (8*512 / bpp - 1) || region.extents.y1 & 63) 81842542f5fSchristos step /= 2; 81942542f5fSchristos while (step * step * 4 > max_size) 82042542f5fSchristos step /= 2; 82142542f5fSchristos if (sna->kgem.gen < 033) 82242542f5fSchristos step /= 2; /* accommodate severe fence restrictions */ 82342542f5fSchristos if (step == 0) { 82442542f5fSchristos DBG(("%s: tiles cannot fit into aperture\n", __FUNCTION__)); 82542542f5fSchristos return false; 82642542f5fSchristos } 82742542f5fSchristos 82842542f5fSchristos DBG(("%s (alu=%d), tile.size=%d, box=%dx[(%d, %d), (%d, %d)])\n", 82942542f5fSchristos __FUNCTION__, alu, step, nbox, 83042542f5fSchristos region.extents.x1, region.extents.y1, 83142542f5fSchristos region.extents.x2, region.extents.y2)); 83242542f5fSchristos 83342542f5fSchristos for (tile.extents.y1 = tile.extents.y2 = region.extents.y1; 83442542f5fSchristos tile.extents.y2 < region.extents.y2; 83542542f5fSchristos tile.extents.y1 = tile.extents.y2) { 83642542f5fSchristos int y2 = tile.extents.y1 + step; 83742542f5fSchristos if (y2 > region.extents.y2) 83842542f5fSchristos y2 = region.extents.y2; 83942542f5fSchristos tile.extents.y2 = y2; 84042542f5fSchristos 84142542f5fSchristos for (tile.extents.x1 = tile.extents.x2 = region.extents.x1; 84242542f5fSchristos tile.extents.x2 < region.extents.x2; 84342542f5fSchristos tile.extents.x1 = tile.extents.x2) { 84442542f5fSchristos int w, h; 84542542f5fSchristos int x2 = tile.extents.x1 + step; 84642542f5fSchristos if (x2 > region.extents.x2) 84742542f5fSchristos x2 = region.extents.x2; 84842542f5fSchristos tile.extents.x2 = x2; 84942542f5fSchristos 85042542f5fSchristos tile.data = NULL; 85142542f5fSchristos 85242542f5fSchristos RegionNull(&this); 85342542f5fSchristos RegionIntersect(&this, ®ion, &tile); 85442542f5fSchristos if (RegionNil(&this)) 85542542f5fSchristos continue; 85642542f5fSchristos 85742542f5fSchristos w = this.extents.x2 - this.extents.x1; 85842542f5fSchristos h = this.extents.y2 - this.extents.y1; 85942542f5fSchristos bo = kgem_create_2d(&sna->kgem, w, h, bpp, 86042542f5fSchristos kgem_choose_tiling(&sna->kgem, 86142542f5fSchristos I915_TILING_X, 86242542f5fSchristos w, h, bpp), 86342542f5fSchristos CREATE_TEMPORARY); 86442542f5fSchristos if (bo) { 86542542f5fSchristos int16_t dx = this.extents.x1; 86642542f5fSchristos int16_t dy = this.extents.y1; 86742542f5fSchristos 86842542f5fSchristos assert(kgem_bo_can_blt(&sna->kgem, bo)); 86942542f5fSchristos 87042542f5fSchristos if (!sna_blt_copy_boxes(sna, GXcopy, 87142542f5fSchristos src_bo, src_dx, src_dy, 87242542f5fSchristos bo, -dx, -dy, 87342542f5fSchristos bpp, region_rects(&this), region_num_rects(&this))) 87442542f5fSchristos goto err; 87542542f5fSchristos 87642542f5fSchristos if (!sna_blt_copy_boxes__with_alpha(sna, alu, 87742542f5fSchristos bo, -dx, -dy, 87842542f5fSchristos dst_bo, dst_dx, dst_dy, 87942542f5fSchristos bpp, alpha_fixup, 88042542f5fSchristos region_rects(&this), region_num_rects(&this))) 88142542f5fSchristos goto err; 88242542f5fSchristos 88342542f5fSchristos kgem_bo_destroy(&sna->kgem, bo); 88442542f5fSchristos } 88542542f5fSchristos RegionUninit(&this); 88642542f5fSchristos } 88742542f5fSchristos } 88842542f5fSchristos 88942542f5fSchristos ret = true; 89042542f5fSchristos goto done; 89142542f5fSchristoserr: 89242542f5fSchristos kgem_bo_destroy(&sna->kgem, bo); 89342542f5fSchristos RegionUninit(&this); 89442542f5fSchristosdone: 89542542f5fSchristos pixman_region_fini(®ion); 89642542f5fSchristos return ret; 89742542f5fSchristos} 89842542f5fSchristos 89942542f5fSchristosfastcall static void 90042542f5fSchristostiling_blt__with_alpha(struct sna *sna, 90142542f5fSchristos const struct sna_composite_op *op, 90242542f5fSchristos const struct sna_composite_rectangles *r) 90342542f5fSchristos{ 90442542f5fSchristos int x1, x2, y1, y2; 90542542f5fSchristos int src_x, src_y; 90642542f5fSchristos BoxRec box; 90742542f5fSchristos 90842542f5fSchristos DBG(("%s: src=(%d, %d), dst=(%d, %d), size=(%d, %d)\n", 90942542f5fSchristos __FUNCTION__, 91042542f5fSchristos r->src.x, r->src.y, 91142542f5fSchristos r->dst.x, r->dst.y, 91242542f5fSchristos r->width, r->height)); 91342542f5fSchristos 91442542f5fSchristos /* XXX higher layer should have clipped? */ 91542542f5fSchristos 91642542f5fSchristos x1 = r->dst.x + op->dst.x; 91742542f5fSchristos y1 = r->dst.y + op->dst.y; 91842542f5fSchristos x2 = x1 + r->width; 91942542f5fSchristos y2 = y1 + r->height; 92042542f5fSchristos 92142542f5fSchristos src_x = r->src.x - x1 + op->u.blt.sx; 92242542f5fSchristos src_y = r->src.y - y1 + op->u.blt.sy; 92342542f5fSchristos 92442542f5fSchristos /* clip against dst */ 92542542f5fSchristos if (x1 < 0) 92642542f5fSchristos x1 = 0; 92742542f5fSchristos if (y1 < 0) 92842542f5fSchristos y1 = 0; 92942542f5fSchristos 93042542f5fSchristos if (x2 > op->dst.width) 93142542f5fSchristos x2 = op->dst.width; 93242542f5fSchristos 93342542f5fSchristos if (y2 > op->dst.height) 93442542f5fSchristos y2 = op->dst.height; 93542542f5fSchristos 93642542f5fSchristos DBG(("%s: box=(%d, %d), (%d, %d)\n", __FUNCTION__, x1, y1, x2, y2)); 93742542f5fSchristos 93842542f5fSchristos if (x2 <= x1 || y2 <= y1) 93942542f5fSchristos return; 94042542f5fSchristos 94142542f5fSchristos box.x1 = x1; box.y1 = y1; 94242542f5fSchristos box.x2 = x2; box.y2 = y2; 94342542f5fSchristos sna_tiling_blt_copy_boxes__with_alpha(sna, GXcopy, 94442542f5fSchristos op->src.bo, src_x, src_y, 94542542f5fSchristos op->dst.bo, 0, 0, 94642542f5fSchristos op->u.blt.bpp, op->u.blt.pixel, 94742542f5fSchristos &box, 1); 94842542f5fSchristos} 94942542f5fSchristos 95042542f5fSchristosfastcall static void 95142542f5fSchristostiling_blt_box__with_alpha(struct sna *sna, 95242542f5fSchristos const struct sna_composite_op *op, 95342542f5fSchristos const BoxRec *box) 95442542f5fSchristos{ 95542542f5fSchristos DBG(("%s: box (%d, %d), (%d, %d)\n", 95642542f5fSchristos __FUNCTION__, box->x1, box->y1, box->x2, box->y2)); 95742542f5fSchristos sna_tiling_blt_copy_boxes__with_alpha(sna, GXcopy, 95842542f5fSchristos op->src.bo, op->u.blt.sx, op->u.blt.sy, 95942542f5fSchristos op->dst.bo, op->dst.x, op->dst.y, 96042542f5fSchristos op->u.blt.bpp, op->u.blt.pixel, 96142542f5fSchristos box, 1); 96242542f5fSchristos} 96342542f5fSchristos 96442542f5fSchristosstatic void 96542542f5fSchristostiling_blt_boxes__with_alpha(struct sna *sna, 96642542f5fSchristos const struct sna_composite_op *op, 96742542f5fSchristos const BoxRec *box, int nbox) 96842542f5fSchristos{ 96942542f5fSchristos DBG(("%s: nbox=%d\n", __FUNCTION__, nbox)); 97042542f5fSchristos sna_tiling_blt_copy_boxes__with_alpha(sna, GXcopy, 97142542f5fSchristos op->src.bo, op->u.blt.sx, op->u.blt.sy, 97242542f5fSchristos op->dst.bo, op->dst.x, op->dst.y, 97342542f5fSchristos op->u.blt.bpp, op->u.blt.pixel, 97442542f5fSchristos box, nbox); 97542542f5fSchristos} 97642542f5fSchristos 97742542f5fSchristosstatic void nop_done(struct sna *sna, const struct sna_composite_op *op) 97842542f5fSchristos{ 97942542f5fSchristos assert(sna->kgem.nbatch <= KGEM_BATCH_SIZE(&sna->kgem)); 98042542f5fSchristos (void)op; 98142542f5fSchristos} 98242542f5fSchristos 98342542f5fSchristosbool 98442542f5fSchristossna_tiling_blt_composite(struct sna *sna, 98542542f5fSchristos struct sna_composite_op *op, 98642542f5fSchristos struct kgem_bo *bo, 98742542f5fSchristos int bpp, 98842542f5fSchristos uint32_t alpha_fixup) 98942542f5fSchristos{ 99042542f5fSchristos assert(op->dst.bo); 99142542f5fSchristos assert(kgem_bo_can_blt(&sna->kgem, op->dst.bo)); 99242542f5fSchristos assert(kgem_bo_can_blt(&sna->kgem, bo)); 99342542f5fSchristos 99442542f5fSchristos op->src.bo = bo; 99542542f5fSchristos op->u.blt.bpp = bpp; 99642542f5fSchristos op->u.blt.pixel = alpha_fixup; 99742542f5fSchristos 99842542f5fSchristos if (alpha_fixup) { 99942542f5fSchristos op->blt = tiling_blt__with_alpha; 100042542f5fSchristos op->box = tiling_blt_box__with_alpha; 100142542f5fSchristos op->boxes = tiling_blt_boxes__with_alpha; 100242542f5fSchristos } else { 100342542f5fSchristos op->blt = tiling_blt; 100442542f5fSchristos op->box = tiling_blt_box; 100542542f5fSchristos op->boxes = tiling_blt_boxes; 100642542f5fSchristos } 100742542f5fSchristos op->done = nop_done; 100842542f5fSchristos 100942542f5fSchristos return true; 101042542f5fSchristos} 101142542f5fSchristos 101203b705cfSriastradhbool sna_tiling_blt_copy_boxes(struct sna *sna, uint8_t alu, 101303b705cfSriastradh struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy, 101403b705cfSriastradh struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy, 101503b705cfSriastradh int bpp, const BoxRec *box, int nbox) 101603b705cfSriastradh{ 101703b705cfSriastradh RegionRec region, tile, this; 101803b705cfSriastradh struct kgem_bo *bo; 101903b705cfSriastradh int max_size, step; 102003b705cfSriastradh bool ret = false; 102103b705cfSriastradh 102242542f5fSchristos DBG(("%s: alu=%d, src size=%d, dst size=%d\n", __FUNCTION__, 102342542f5fSchristos alu, kgem_bo_size(src_bo), kgem_bo_size(dst_bo))); 102442542f5fSchristos 102542542f5fSchristos if (wedged(sna) || 102642542f5fSchristos !kgem_bo_can_blt(&sna->kgem, src_bo) || 102703b705cfSriastradh !kgem_bo_can_blt(&sna->kgem, dst_bo)) { 102803b705cfSriastradh /* XXX */ 102903b705cfSriastradh DBG(("%s: tiling blt fail: src?=%d, dst?=%d\n", 103003b705cfSriastradh __FUNCTION__, 103103b705cfSriastradh kgem_bo_can_blt(&sna->kgem, src_bo), 103203b705cfSriastradh kgem_bo_can_blt(&sna->kgem, dst_bo))); 103303b705cfSriastradh return false; 103403b705cfSriastradh } 103503b705cfSriastradh 103642542f5fSchristos max_size = sna_max_tile_copy_size(sna, src_bo, dst_bo); 103742542f5fSchristos if (max_size == 0) 103803b705cfSriastradh return false; 103903b705cfSriastradh 104003b705cfSriastradh pixman_region_init_rects(®ion, box, nbox); 104103b705cfSriastradh 104203b705cfSriastradh /* Use a small step to accommodate enlargement through tile alignment */ 104303b705cfSriastradh step = sna->render.max_3d_size; 104403b705cfSriastradh if (region.extents.x1 & (8*512 / bpp - 1) || region.extents.y1 & 63) 104503b705cfSriastradh step /= 2; 104603b705cfSriastradh while (step * step * 4 > max_size) 104703b705cfSriastradh step /= 2; 104842542f5fSchristos if (sna->kgem.gen < 033) 104942542f5fSchristos step /= 2; /* accommodate severe fence restrictions */ 105003b705cfSriastradh if (step == 0) { 105103b705cfSriastradh DBG(("%s: tiles cannot fit into aperture\n", __FUNCTION__)); 105203b705cfSriastradh return false; 105303b705cfSriastradh } 105403b705cfSriastradh 105503b705cfSriastradh DBG(("%s (alu=%d), tile.size=%d, box=%dx[(%d, %d), (%d, %d)])\n", 105603b705cfSriastradh __FUNCTION__, alu, step, nbox, 105703b705cfSriastradh region.extents.x1, region.extents.y1, 105803b705cfSriastradh region.extents.x2, region.extents.y2)); 105903b705cfSriastradh 106003b705cfSriastradh for (tile.extents.y1 = tile.extents.y2 = region.extents.y1; 106103b705cfSriastradh tile.extents.y2 < region.extents.y2; 106203b705cfSriastradh tile.extents.y1 = tile.extents.y2) { 106303b705cfSriastradh int y2 = tile.extents.y1 + step; 106403b705cfSriastradh if (y2 > region.extents.y2) 106503b705cfSriastradh y2 = region.extents.y2; 106603b705cfSriastradh tile.extents.y2 = y2; 106703b705cfSriastradh 106803b705cfSriastradh for (tile.extents.x1 = tile.extents.x2 = region.extents.x1; 106903b705cfSriastradh tile.extents.x2 < region.extents.x2; 107003b705cfSriastradh tile.extents.x1 = tile.extents.x2) { 107103b705cfSriastradh int w, h; 107203b705cfSriastradh int x2 = tile.extents.x1 + step; 107303b705cfSriastradh if (x2 > region.extents.x2) 107403b705cfSriastradh x2 = region.extents.x2; 107503b705cfSriastradh tile.extents.x2 = x2; 107603b705cfSriastradh 107703b705cfSriastradh tile.data = NULL; 107803b705cfSriastradh 107903b705cfSriastradh RegionNull(&this); 108003b705cfSriastradh RegionIntersect(&this, ®ion, &tile); 108103b705cfSriastradh if (RegionNil(&this)) 108203b705cfSriastradh continue; 108303b705cfSriastradh 108403b705cfSriastradh w = this.extents.x2 - this.extents.x1; 108503b705cfSriastradh h = this.extents.y2 - this.extents.y1; 108603b705cfSriastradh bo = kgem_create_2d(&sna->kgem, w, h, bpp, 108703b705cfSriastradh kgem_choose_tiling(&sna->kgem, 108803b705cfSriastradh I915_TILING_X, 108903b705cfSriastradh w, h, bpp), 109003b705cfSriastradh CREATE_TEMPORARY); 109103b705cfSriastradh if (bo) { 109203b705cfSriastradh int16_t dx = this.extents.x1; 109303b705cfSriastradh int16_t dy = this.extents.y1; 109403b705cfSriastradh 109542542f5fSchristos assert(kgem_bo_can_blt(&sna->kgem, bo)); 109603b705cfSriastradh 109742542f5fSchristos if (!sna_blt_copy_boxes(sna, GXcopy, 109803b705cfSriastradh src_bo, src_dx, src_dy, 109903b705cfSriastradh bo, -dx, -dy, 110042542f5fSchristos bpp, region_rects(&this), region_num_rects(&this))) 110103b705cfSriastradh goto err; 110203b705cfSriastradh 110303b705cfSriastradh if (!sna_blt_copy_boxes(sna, alu, 110403b705cfSriastradh bo, -dx, -dy, 110503b705cfSriastradh dst_bo, dst_dx, dst_dy, 110642542f5fSchristos bpp, region_rects(&this), region_num_rects(&this))) 110703b705cfSriastradh goto err; 110803b705cfSriastradh 110903b705cfSriastradh kgem_bo_destroy(&sna->kgem, bo); 111003b705cfSriastradh } 111103b705cfSriastradh RegionUninit(&this); 111203b705cfSriastradh } 111303b705cfSriastradh } 111403b705cfSriastradh 111503b705cfSriastradh ret = true; 111603b705cfSriastradh goto done; 111703b705cfSriastradherr: 111803b705cfSriastradh kgem_bo_destroy(&sna->kgem, bo); 111903b705cfSriastradh RegionUninit(&this); 112003b705cfSriastradhdone: 112103b705cfSriastradh pixman_region_fini(®ion); 112203b705cfSriastradh return ret; 112303b705cfSriastradh} 112403b705cfSriastradh 112503b705cfSriastradhbool 112603b705cfSriastradhsna_tiling_copy_boxes(struct sna *sna, uint8_t alu, 112742542f5fSchristos const DrawableRec *src, struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy, 112842542f5fSchristos const DrawableRec *dst, struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy, 112903b705cfSriastradh const BoxRec *box, int n) 113003b705cfSriastradh{ 113103b705cfSriastradh BoxRec extents, tile, stack[64], *clipped, *c; 113242542f5fSchristos DrawableRec p; 113303b705cfSriastradh int i, step, tiling; 113403b705cfSriastradh bool create = true; 113503b705cfSriastradh bool ret = false; 113603b705cfSriastradh 113703b705cfSriastradh extents = box[0]; 113803b705cfSriastradh for (i = 1; i < n; i++) { 113903b705cfSriastradh if (box[i].x1 < extents.x1) 114003b705cfSriastradh extents.x1 = box[i].x1; 114103b705cfSriastradh if (box[i].y1 < extents.y1) 114203b705cfSriastradh extents.y1 = box[i].y1; 114303b705cfSriastradh 114403b705cfSriastradh if (box[i].x2 > extents.x2) 114503b705cfSriastradh extents.x2 = box[i].x2; 114603b705cfSriastradh if (box[i].y2 > extents.y2) 114703b705cfSriastradh extents.y2 = box[i].y2; 114803b705cfSriastradh } 114903b705cfSriastradh 115003b705cfSriastradh tiling = I915_TILING_X; 115103b705cfSriastradh if (!kgem_bo_can_blt(&sna->kgem, src_bo) || 115203b705cfSriastradh !kgem_bo_can_blt(&sna->kgem, dst_bo)) 115303b705cfSriastradh tiling = I915_TILING_Y; 115403b705cfSriastradh 115503b705cfSriastradh create = (src_bo->pitch > sna->render.max_3d_pitch || 115603b705cfSriastradh dst_bo->pitch > sna->render.max_3d_pitch); 115703b705cfSriastradh 115803b705cfSriastradh step = sna->render.max_3d_size / 2; 115903b705cfSriastradh if (create) { 116003b705cfSriastradh while (step * step * 4 > sna->kgem.max_upload_tile_size) 116103b705cfSriastradh step /= 2; 116203b705cfSriastradh } 116303b705cfSriastradh 116403b705cfSriastradh DBG(("%s: tiling copy %dx%d, %s %dx%d %c tiles\n", __FUNCTION__, 116503b705cfSriastradh extents.x2-extents.x1, extents.y2-extents.y1, 116603b705cfSriastradh create ? "creating" : "using", 116703b705cfSriastradh step, step, tiling == I915_TILING_X ? 'X' : 'Y')); 116803b705cfSriastradh 116903b705cfSriastradh if (n > ARRAY_SIZE(stack)) { 117003b705cfSriastradh clipped = malloc(sizeof(BoxRec) * n); 117103b705cfSriastradh if (clipped == NULL) 117203b705cfSriastradh goto tiled_error; 117303b705cfSriastradh } else 117403b705cfSriastradh clipped = stack; 117503b705cfSriastradh 117642542f5fSchristos p.depth = src->depth; 117742542f5fSchristos p.bitsPerPixel = src->bitsPerPixel; 117803b705cfSriastradh 117903b705cfSriastradh for (tile.y1 = extents.y1; tile.y1 < extents.y2; tile.y1 = tile.y2) { 118003b705cfSriastradh int y2 = tile.y1 + step; 118103b705cfSriastradh if (y2 > extents.y2) 118203b705cfSriastradh y2 = extents.y2; 118303b705cfSriastradh tile.y2 = y2; 118403b705cfSriastradh 118503b705cfSriastradh for (tile.x1 = extents.x1; tile.x1 < extents.x2; tile.x1 = tile.x2) { 118603b705cfSriastradh struct kgem_bo *tmp_bo; 118703b705cfSriastradh int x2 = tile.x1 + step; 118803b705cfSriastradh if (x2 > extents.x2) 118903b705cfSriastradh x2 = extents.x2; 119003b705cfSriastradh tile.x2 = x2; 119103b705cfSriastradh 119203b705cfSriastradh c = clipped; 119303b705cfSriastradh for (i = 0; i < n; i++) { 119403b705cfSriastradh *c = box[i]; 119503b705cfSriastradh if (!box_intersect(c, &tile)) 119603b705cfSriastradh continue; 119703b705cfSriastradh 119803b705cfSriastradh DBG(("%s: box(%d, %d), (%d, %d), src=(%d, %d), dst=(%d, %d)\n", 119903b705cfSriastradh __FUNCTION__, 120003b705cfSriastradh c->x1, c->y1, 120103b705cfSriastradh c->x2, c->y2, 120203b705cfSriastradh src_dx, src_dy, 120303b705cfSriastradh c->x1 - tile.x1, 120403b705cfSriastradh c->y1 - tile.y1)); 120503b705cfSriastradh c++; 120603b705cfSriastradh } 120703b705cfSriastradh if (c == clipped) 120803b705cfSriastradh continue; 120903b705cfSriastradh 121042542f5fSchristos p.width = tile.x2 - tile.x1; 121142542f5fSchristos p.height = tile.y2 - tile.y1; 121203b705cfSriastradh 121303b705cfSriastradh DBG(("%s: tile (%d, %d), (%d, %d)\n", 121403b705cfSriastradh __FUNCTION__, tile.x1, tile.y1, tile.x2, tile.y2)); 121503b705cfSriastradh 121603b705cfSriastradh if (create) { 121703b705cfSriastradh tmp_bo = kgem_create_2d(&sna->kgem, 121842542f5fSchristos p.width, 121942542f5fSchristos p.height, 122042542f5fSchristos p.bitsPerPixel, 122103b705cfSriastradh tiling, CREATE_TEMPORARY); 122203b705cfSriastradh if (!tmp_bo) 122303b705cfSriastradh goto tiled_error; 122403b705cfSriastradh 122503b705cfSriastradh i = (sna->render.copy_boxes(sna, GXcopy, 122603b705cfSriastradh src, src_bo, src_dx, src_dy, 122703b705cfSriastradh &p, tmp_bo, -tile.x1, -tile.y1, 122803b705cfSriastradh clipped, c - clipped, 0) && 122903b705cfSriastradh sna->render.copy_boxes(sna, alu, 123003b705cfSriastradh &p, tmp_bo, -tile.x1, -tile.y1, 123103b705cfSriastradh dst, dst_bo, dst_dx, dst_dy, 123203b705cfSriastradh clipped, c - clipped, 0)); 123303b705cfSriastradh 123403b705cfSriastradh kgem_bo_destroy(&sna->kgem, tmp_bo); 123503b705cfSriastradh } else { 123603b705cfSriastradh i = sna->render.copy_boxes(sna, GXcopy, 123703b705cfSriastradh src, src_bo, src_dx, src_dy, 123803b705cfSriastradh dst, dst_bo, dst_dx, dst_dy, 123903b705cfSriastradh clipped, c - clipped, 0); 124003b705cfSriastradh } 124103b705cfSriastradh 124203b705cfSriastradh if (!i) 124303b705cfSriastradh goto tiled_error; 124403b705cfSriastradh } 124503b705cfSriastradh } 124603b705cfSriastradh 124703b705cfSriastradh ret = true; 124803b705cfSriastradhtiled_error: 124903b705cfSriastradh if (clipped != stack) 125003b705cfSriastradh free(clipped); 125103b705cfSriastradh 125203b705cfSriastradh return ret; 125303b705cfSriastradh} 1254