1428d7b3dSmrg/* 2428d7b3dSmrg * Copyright © 2010 Intel Corporation 3428d7b3dSmrg * 4428d7b3dSmrg * Permission is hereby granted, free of charge, to any person obtaining a 5428d7b3dSmrg * copy of this software and associated documentation files (the "Software"), 6428d7b3dSmrg * to deal in the Software without restriction, including without limitation 7428d7b3dSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8428d7b3dSmrg * and/or sell copies of the Software, and to permit persons to whom the 9428d7b3dSmrg * Software is furnished to do so, subject to the following conditions: 10428d7b3dSmrg * 11428d7b3dSmrg * The above copyright notice and this permission notice (including the next 12428d7b3dSmrg * paragraph) shall be included in all copies or substantial portions of the 13428d7b3dSmrg * Software. 14428d7b3dSmrg * 15428d7b3dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16428d7b3dSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17428d7b3dSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18428d7b3dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19428d7b3dSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20428d7b3dSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21428d7b3dSmrg * SOFTWARE. 22428d7b3dSmrg * 23428d7b3dSmrg * Authors: 24428d7b3dSmrg * Chris Wilson <chris@chris-wilson.co.uk> 25428d7b3dSmrg * 26428d7b3dSmrg */ 27428d7b3dSmrg 28428d7b3dSmrg#ifdef HAVE_CONFIG_H 29428d7b3dSmrg#include "config.h" 30428d7b3dSmrg#endif 31428d7b3dSmrg 32428d7b3dSmrg#include "sna.h" 33428d7b3dSmrg#include "sna_render.h" 34428d7b3dSmrg#include "fb/fbpict.h" 35428d7b3dSmrg 36428d7b3dSmrgstruct sna_tile_span { 37428d7b3dSmrg BoxRec box; 38428d7b3dSmrg float opacity; 39428d7b3dSmrg}; 40428d7b3dSmrg 41428d7b3dSmrgstruct sna_tile_state { 42428d7b3dSmrg int op; 43428d7b3dSmrg PicturePtr src, mask, dst; 44428d7b3dSmrg PixmapPtr dst_pixmap; 45428d7b3dSmrg uint32_t dst_format; 46428d7b3dSmrg int16_t src_x, src_y; 47428d7b3dSmrg int16_t mask_x, mask_y; 48428d7b3dSmrg int16_t dst_x, dst_y; 49428d7b3dSmrg int16_t width, height; 50428d7b3dSmrg unsigned flags; 51428d7b3dSmrg 52428d7b3dSmrg int rect_count; 53428d7b3dSmrg int rect_size; 54428d7b3dSmrg struct sna_composite_rectangles rects_embedded[16], *rects; 55428d7b3dSmrg}; 56428d7b3dSmrg 57428d7b3dSmrgstatic void 58428d7b3dSmrgsna_tiling_composite_add_rect(struct sna_tile_state *tile, 59428d7b3dSmrg const struct sna_composite_rectangles *r) 60428d7b3dSmrg{ 61428d7b3dSmrg if (tile->rect_count == tile->rect_size) { 62428d7b3dSmrg struct sna_composite_rectangles *a; 63428d7b3dSmrg int newsize = tile->rect_size * 2; 64428d7b3dSmrg 65428d7b3dSmrg if (tile->rects == tile->rects_embedded) { 66428d7b3dSmrg a = malloc (sizeof(struct sna_composite_rectangles) * newsize); 67428d7b3dSmrg if (a == NULL) 68428d7b3dSmrg return; 69428d7b3dSmrg 70428d7b3dSmrg memcpy(a, 71428d7b3dSmrg tile->rects_embedded, 72428d7b3dSmrg sizeof(struct sna_composite_rectangles) * tile->rect_count); 73428d7b3dSmrg } else { 74428d7b3dSmrg a = realloc(tile->rects, 75428d7b3dSmrg sizeof(struct sna_composite_rectangles) * newsize); 76428d7b3dSmrg if (a == NULL) 77428d7b3dSmrg return; 78428d7b3dSmrg } 79428d7b3dSmrg 80428d7b3dSmrg tile->rects = a; 81428d7b3dSmrg tile->rect_size = newsize; 82428d7b3dSmrg } 83428d7b3dSmrg 84428d7b3dSmrg tile->rects[tile->rect_count++] = *r; 85428d7b3dSmrg} 86428d7b3dSmrg 87428d7b3dSmrgfastcall static void 88428d7b3dSmrgsna_tiling_composite_blt(struct sna *sna, 89428d7b3dSmrg const struct sna_composite_op *op, 90428d7b3dSmrg const struct sna_composite_rectangles *r) 91428d7b3dSmrg{ 92428d7b3dSmrg sna_tiling_composite_add_rect(op->priv, r); 93428d7b3dSmrg (void)sna; 94428d7b3dSmrg} 95428d7b3dSmrg 96428d7b3dSmrgfastcall static void 97428d7b3dSmrgsna_tiling_composite_box(struct sna *sna, 98428d7b3dSmrg const struct sna_composite_op *op, 99428d7b3dSmrg const BoxRec *box) 100428d7b3dSmrg{ 101428d7b3dSmrg struct sna_composite_rectangles r; 102428d7b3dSmrg 103428d7b3dSmrg r.dst.x = box->x1; 104428d7b3dSmrg r.dst.y = box->y1; 105428d7b3dSmrg r.mask = r.src = r.dst; 106428d7b3dSmrg 107428d7b3dSmrg r.width = box->x2 - box->x1; 108428d7b3dSmrg r.height = box->y2 - box->y1; 109428d7b3dSmrg 110428d7b3dSmrg sna_tiling_composite_add_rect(op->priv, &r); 111428d7b3dSmrg (void)sna; 112428d7b3dSmrg} 113428d7b3dSmrg 114428d7b3dSmrgstatic void 115428d7b3dSmrgsna_tiling_composite_boxes(struct sna *sna, 116428d7b3dSmrg const struct sna_composite_op *op, 117428d7b3dSmrg const BoxRec *box, int nbox) 118428d7b3dSmrg{ 119428d7b3dSmrg while (nbox--) { 120428d7b3dSmrg struct sna_composite_rectangles r; 121428d7b3dSmrg 122428d7b3dSmrg r.dst.x = box->x1; 123428d7b3dSmrg r.dst.y = box->y1; 124428d7b3dSmrg r.mask = r.src = r.dst; 125428d7b3dSmrg 126428d7b3dSmrg r.width = box->x2 - box->x1; 127428d7b3dSmrg r.height = box->y2 - box->y1; 128428d7b3dSmrg 129428d7b3dSmrg sna_tiling_composite_add_rect(op->priv, &r); 130428d7b3dSmrg box++; 131428d7b3dSmrg } 132428d7b3dSmrg (void)sna; 133428d7b3dSmrg} 134428d7b3dSmrg 135428d7b3dSmrgstatic void 136428d7b3dSmrgsna_tiling_composite_done(struct sna *sna, 137428d7b3dSmrg const struct sna_composite_op *op) 138428d7b3dSmrg{ 139428d7b3dSmrg struct sna_tile_state *tile = op->priv; 140428d7b3dSmrg struct sna_composite_op tmp; 141428d7b3dSmrg int x, y, n, step, max_size; 142428d7b3dSmrg 143428d7b3dSmrg /* Use a small step to accommodate enlargement through tile alignment */ 144428d7b3dSmrg step = sna->render.max_3d_size; 145428d7b3dSmrg if (tile->dst_x & (8*512 / tile->dst->pDrawable->bitsPerPixel - 1) || 146428d7b3dSmrg tile->dst_y & 63) 147428d7b3dSmrg step /= 2; 148428d7b3dSmrg 149428d7b3dSmrg max_size = sna_max_tile_copy_size(sna, op->dst.bo, op->dst.bo); 150428d7b3dSmrg if (max_size == 0) 151428d7b3dSmrg goto done; 152428d7b3dSmrg 153428d7b3dSmrg while (step * step * 4 > max_size) 154428d7b3dSmrg step /= 2; 155428d7b3dSmrg 156428d7b3dSmrg DBG(("%s -- %dx%d, count=%d, step size=%d\n", __FUNCTION__, 157428d7b3dSmrg tile->width, tile->height, tile->rect_count, step)); 158428d7b3dSmrg 159428d7b3dSmrg if (tile->rect_count == 0) 160428d7b3dSmrg goto done; 161428d7b3dSmrg 162428d7b3dSmrg for (y = 0; y < tile->height; y += step) { 163428d7b3dSmrg int height = step; 164428d7b3dSmrg if (y + height > tile->height) 165428d7b3dSmrg height = tile->height - y; 166428d7b3dSmrg for (x = 0; x < tile->width; x += step) { 167428d7b3dSmrg int width = step; 168428d7b3dSmrg if (x + width > tile->width) 169428d7b3dSmrg width = tile->width - x; 170428d7b3dSmrg if (sna->render.composite(sna, tile->op, 171428d7b3dSmrg tile->src, tile->mask, tile->dst, 172428d7b3dSmrg tile->src_x + x, tile->src_y + y, 173428d7b3dSmrg tile->mask_x + x, tile->mask_y + y, 174428d7b3dSmrg tile->dst_x + x, tile->dst_y + y, 175428d7b3dSmrg width, height, 176428d7b3dSmrg COMPOSITE_PARTIAL, memset(&tmp, 0, sizeof(tmp)))) { 177428d7b3dSmrg for (n = 0; n < tile->rect_count; n++) { 178428d7b3dSmrg const struct sna_composite_rectangles *r = &tile->rects[n]; 179428d7b3dSmrg int x1, x2, dx, y1, y2, dy; 180428d7b3dSmrg 181428d7b3dSmrg x1 = r->dst.x - tile->dst_x, dx = 0; 182428d7b3dSmrg if (x1 < x) 183428d7b3dSmrg dx = x - x1, x1 = x; 184428d7b3dSmrg y1 = r->dst.y - tile->dst_y, dy = 0; 185428d7b3dSmrg if (y1 < y) 186428d7b3dSmrg dy = y - y1, y1 = y; 187428d7b3dSmrg 188428d7b3dSmrg x2 = r->dst.x + r->width - tile->dst_x; 189428d7b3dSmrg if (x2 > x + width) 190428d7b3dSmrg x2 = x + width; 191428d7b3dSmrg y2 = r->dst.y + r->height - tile->dst_y; 192428d7b3dSmrg if (y2 > y + height) 193428d7b3dSmrg y2 = y + height; 194428d7b3dSmrg 195428d7b3dSmrg DBG(("%s: rect[%d] = (%d, %d)x(%d,%d), tile=(%d,%d)x(%d, %d), blt=(%d,%d),(%d,%d), delta=(%d,%d)\n", 196428d7b3dSmrg __FUNCTION__, n, 197428d7b3dSmrg r->dst.x, r->dst.y, 198428d7b3dSmrg r->width, r->height, 199428d7b3dSmrg x, y, width, height, 200428d7b3dSmrg x1, y1, x2, y2, 201428d7b3dSmrg dx, dy)); 202428d7b3dSmrg 203428d7b3dSmrg if (y2 > y1 && x2 > x1) { 204428d7b3dSmrg struct sna_composite_rectangles rr; 205428d7b3dSmrg rr.src.x = dx + r->src.x; 206428d7b3dSmrg rr.src.y = dy + r->src.y; 207428d7b3dSmrg 208428d7b3dSmrg rr.mask.x = dx + r->mask.x; 209428d7b3dSmrg rr.mask.y = dy + r->mask.y; 210428d7b3dSmrg 211428d7b3dSmrg rr.dst.x = dx + r->dst.x; 212428d7b3dSmrg rr.dst.y = dy + r->dst.y; 213428d7b3dSmrg 214428d7b3dSmrg rr.width = x2 - x1; 215428d7b3dSmrg rr.height = y2 - y1; 216428d7b3dSmrg 217428d7b3dSmrg tmp.blt(sna, &tmp, &rr); 218428d7b3dSmrg } 219428d7b3dSmrg } 220428d7b3dSmrg tmp.done(sna, &tmp); 221428d7b3dSmrg } else { 222428d7b3dSmrg unsigned int flags; 223428d7b3dSmrg DBG(("%s -- falback\n", __FUNCTION__)); 224428d7b3dSmrg 225428d7b3dSmrg if (tile->op <= PictOpSrc) 226428d7b3dSmrg flags = MOVE_WRITE; 227428d7b3dSmrg else 228428d7b3dSmrg flags = MOVE_WRITE | MOVE_READ; 229428d7b3dSmrg if (!sna_drawable_move_to_cpu(tile->dst->pDrawable, 230428d7b3dSmrg flags)) 231428d7b3dSmrg goto done; 232428d7b3dSmrg if (tile->dst->alphaMap && 233428d7b3dSmrg !sna_drawable_move_to_cpu(tile->dst->alphaMap->pDrawable, 234428d7b3dSmrg flags)) 235428d7b3dSmrg goto done; 236428d7b3dSmrg 237428d7b3dSmrg if (tile->src->pDrawable && 238428d7b3dSmrg !sna_drawable_move_to_cpu(tile->src->pDrawable, 239428d7b3dSmrg MOVE_READ)) 240428d7b3dSmrg goto done; 241428d7b3dSmrg if (tile->src->alphaMap && 242428d7b3dSmrg !sna_drawable_move_to_cpu(tile->src->alphaMap->pDrawable, 243428d7b3dSmrg MOVE_READ)) 244428d7b3dSmrg goto done; 245428d7b3dSmrg 246428d7b3dSmrg if (tile->mask && tile->mask->pDrawable && 247428d7b3dSmrg !sna_drawable_move_to_cpu(tile->mask->pDrawable, 248428d7b3dSmrg MOVE_READ)) 249428d7b3dSmrg goto done; 250428d7b3dSmrg 251428d7b3dSmrg if (tile->mask && tile->mask->alphaMap && 252428d7b3dSmrg !sna_drawable_move_to_cpu(tile->mask->alphaMap->pDrawable, 253428d7b3dSmrg MOVE_READ)) 254428d7b3dSmrg goto done; 255428d7b3dSmrg 256428d7b3dSmrg if (sigtrap_get() == 0) { 257428d7b3dSmrg fbComposite(tile->op, 258428d7b3dSmrg tile->src, tile->mask, tile->dst, 259428d7b3dSmrg tile->src_x + x, tile->src_y + y, 260428d7b3dSmrg tile->mask_x + x, tile->mask_y + y, 261428d7b3dSmrg tile->dst_x + x, tile->dst_y + y, 262428d7b3dSmrg width, height); 263428d7b3dSmrg sigtrap_put(); 264428d7b3dSmrg } 265428d7b3dSmrg } 266428d7b3dSmrg } 267428d7b3dSmrg } 268428d7b3dSmrg 269428d7b3dSmrgdone: 270428d7b3dSmrg if (tile->rects != tile->rects_embedded) 271428d7b3dSmrg free(tile->rects); 272428d7b3dSmrg free(tile); 273428d7b3dSmrg} 274428d7b3dSmrg 275428d7b3dSmrgbool 276428d7b3dSmrgsna_tiling_composite(uint32_t op, 277428d7b3dSmrg PicturePtr src, 278428d7b3dSmrg PicturePtr mask, 279428d7b3dSmrg PicturePtr dst, 280428d7b3dSmrg int16_t src_x, int16_t src_y, 281428d7b3dSmrg int16_t mask_x, int16_t mask_y, 282428d7b3dSmrg int16_t dst_x, int16_t dst_y, 283428d7b3dSmrg int16_t width, int16_t height, 284428d7b3dSmrg struct sna_composite_op *tmp) 285428d7b3dSmrg{ 286428d7b3dSmrg struct sna_tile_state *tile; 287428d7b3dSmrg struct sna_pixmap *priv; 288428d7b3dSmrg 289428d7b3dSmrg DBG(("%s size=(%d, %d), tile=%d\n", 290428d7b3dSmrg __FUNCTION__, width, height, 291428d7b3dSmrg to_sna_from_drawable(dst->pDrawable)->render.max_3d_size)); 292428d7b3dSmrg 293428d7b3dSmrg priv = sna_pixmap(get_drawable_pixmap(dst->pDrawable)); 294428d7b3dSmrg if (priv == NULL || priv->gpu_bo == NULL) 295428d7b3dSmrg return false; 296428d7b3dSmrg 297428d7b3dSmrg tile = malloc(sizeof(*tile)); 298428d7b3dSmrg if (!tile) 299428d7b3dSmrg return false; 300428d7b3dSmrg 301428d7b3dSmrg tile->op = op; 302428d7b3dSmrg 303428d7b3dSmrg tile->src = src; 304428d7b3dSmrg tile->mask = mask; 305428d7b3dSmrg tile->dst = dst; 306428d7b3dSmrg 307428d7b3dSmrg tile->src_x = src_x; 308428d7b3dSmrg tile->src_y = src_y; 309428d7b3dSmrg tile->mask_x = mask_x; 310428d7b3dSmrg tile->mask_y = mask_y; 311428d7b3dSmrg tile->dst_x = dst_x; 312428d7b3dSmrg tile->dst_y = dst_y; 313428d7b3dSmrg tile->width = width; 314428d7b3dSmrg tile->height = height; 315428d7b3dSmrg tile->rects = tile->rects_embedded; 316428d7b3dSmrg tile->rect_count = 0; 317428d7b3dSmrg tile->rect_size = ARRAY_SIZE(tile->rects_embedded); 318428d7b3dSmrg 319428d7b3dSmrg tmp->blt = sna_tiling_composite_blt; 320428d7b3dSmrg tmp->box = sna_tiling_composite_box; 321428d7b3dSmrg tmp->boxes = sna_tiling_composite_boxes; 322428d7b3dSmrg tmp->done = sna_tiling_composite_done; 323428d7b3dSmrg 324428d7b3dSmrg tmp->priv = tile; 325428d7b3dSmrg tmp->dst.bo = priv->gpu_bo; 326428d7b3dSmrg return true; 327428d7b3dSmrg} 328428d7b3dSmrg 329428d7b3dSmrgfastcall static void 330428d7b3dSmrgsna_tiling_composite_spans_box(struct sna *sna, 331428d7b3dSmrg const struct sna_composite_spans_op *op, 332428d7b3dSmrg const BoxRec *box, float opacity) 333428d7b3dSmrg{ 334428d7b3dSmrg struct sna_tile_state *tile = op->base.priv; 335428d7b3dSmrg struct sna_tile_span *a; 336428d7b3dSmrg 337428d7b3dSmrg if (tile->rect_count == tile->rect_size) { 338428d7b3dSmrg int newsize = tile->rect_size * 2; 339428d7b3dSmrg 340428d7b3dSmrg if (tile->rects == tile->rects_embedded) { 341428d7b3dSmrg a = malloc (sizeof(struct sna_tile_span) * newsize); 342428d7b3dSmrg if (a == NULL) 343428d7b3dSmrg return; 344428d7b3dSmrg 345428d7b3dSmrg memcpy(a, 346428d7b3dSmrg tile->rects_embedded, 347428d7b3dSmrg sizeof(struct sna_tile_span) * tile->rect_count); 348428d7b3dSmrg } else { 349428d7b3dSmrg a = realloc(tile->rects, 350428d7b3dSmrg sizeof(struct sna_tile_span) * newsize); 351428d7b3dSmrg if (a == NULL) 352428d7b3dSmrg return; 353428d7b3dSmrg } 354428d7b3dSmrg 355428d7b3dSmrg tile->rects = (void *)a; 356428d7b3dSmrg tile->rect_size = newsize; 357428d7b3dSmrg } else 358428d7b3dSmrg a = (void *)tile->rects; 359428d7b3dSmrg 360428d7b3dSmrg a[tile->rect_count].box = *box; 361428d7b3dSmrg a[tile->rect_count].opacity = opacity; 362428d7b3dSmrg tile->rect_count++; 363428d7b3dSmrg (void)sna; 364428d7b3dSmrg} 365428d7b3dSmrg 366428d7b3dSmrgstatic void 367428d7b3dSmrgsna_tiling_composite_spans_boxes(struct sna *sna, 368428d7b3dSmrg const struct sna_composite_spans_op *op, 369428d7b3dSmrg const BoxRec *box, int nbox, float opacity) 370428d7b3dSmrg{ 371428d7b3dSmrg while (nbox--) 372428d7b3dSmrg sna_tiling_composite_spans_box(sna, op->base.priv, box++, opacity); 373428d7b3dSmrg (void)sna; 374428d7b3dSmrg} 375428d7b3dSmrg 376428d7b3dSmrgfastcall static void 377428d7b3dSmrgsna_tiling_composite_spans_done(struct sna *sna, 378428d7b3dSmrg const struct sna_composite_spans_op *op) 379428d7b3dSmrg{ 380428d7b3dSmrg struct sna_tile_state *tile = op->base.priv; 381428d7b3dSmrg struct sna_composite_spans_op tmp; 382428d7b3dSmrg int x, y, n, step, max_size; 383428d7b3dSmrg bool force_fallback = false; 384428d7b3dSmrg 385428d7b3dSmrg /* Use a small step to accommodate enlargement through tile alignment */ 386428d7b3dSmrg step = sna->render.max_3d_size; 387428d7b3dSmrg if (tile->dst_x & (8*512 / tile->dst->pDrawable->bitsPerPixel - 1) || 388428d7b3dSmrg tile->dst_y & 63) 389428d7b3dSmrg step /= 2; 390428d7b3dSmrg 391428d7b3dSmrg max_size = sna_max_tile_copy_size(sna, op->base.dst.bo, op->base.dst.bo); 392428d7b3dSmrg if (max_size == 0) 393428d7b3dSmrg goto done; 394428d7b3dSmrg 395428d7b3dSmrg while (step * step * 4 > max_size) 396428d7b3dSmrg step /= 2; 397428d7b3dSmrg 398428d7b3dSmrg DBG(("%s -- %dx%d, count=%d, step size=%d\n", __FUNCTION__, 399428d7b3dSmrg tile->width, tile->height, tile->rect_count, step)); 400428d7b3dSmrg 401428d7b3dSmrg if (tile->rect_count == 0) 402428d7b3dSmrg goto done; 403428d7b3dSmrg 404428d7b3dSmrg for (y = 0; y < tile->height; y += step) { 405428d7b3dSmrg int height = step; 406428d7b3dSmrg if (y + height > tile->height) 407428d7b3dSmrg height = tile->height - y; 408428d7b3dSmrg for (x = 0; x < tile->width; x += step) { 409428d7b3dSmrg const struct sna_tile_span *r = (void *)tile->rects; 410428d7b3dSmrg int width = step; 411428d7b3dSmrg if (x + width > tile->width) 412428d7b3dSmrg width = tile->width - x; 413428d7b3dSmrg if (!force_fallback && 414428d7b3dSmrg sna->render.composite_spans(sna, tile->op, 415428d7b3dSmrg tile->src, tile->dst, 416428d7b3dSmrg tile->src_x + x, tile->src_y + y, 417428d7b3dSmrg tile->dst_x + x, tile->dst_y + y, 418428d7b3dSmrg width, height, tile->flags, 419428d7b3dSmrg memset(&tmp, 0, sizeof(tmp)))) { 420428d7b3dSmrg for (n = 0; n < tile->rect_count; n++) { 421428d7b3dSmrg BoxRec b; 422428d7b3dSmrg 423428d7b3dSmrg b.x1 = r->box.x1 - tile->dst_x; 424428d7b3dSmrg if (b.x1 < x) 425428d7b3dSmrg b.x1 = x; 426428d7b3dSmrg 427428d7b3dSmrg b.y1 = r->box.y1 - tile->dst_y; 428428d7b3dSmrg if (b.y1 < y) 429428d7b3dSmrg b.y1 = y; 430428d7b3dSmrg 431428d7b3dSmrg b.x2 = r->box.x2 - tile->dst_x; 432428d7b3dSmrg if (b.x2 > x + width) 433428d7b3dSmrg b.x2 = x + width; 434428d7b3dSmrg 435428d7b3dSmrg b.y2 = r->box.y2 - tile->dst_y; 436428d7b3dSmrg if (b.y2 > y + height) 437428d7b3dSmrg b.y2 = y + height; 438428d7b3dSmrg 439428d7b3dSmrg DBG(("%s: rect[%d] = (%d, %d)x(%d,%d), tile=(%d,%d)x(%d, %d), blt=(%d,%d),(%d,%d)\n", 440428d7b3dSmrg __FUNCTION__, n, 441428d7b3dSmrg r->box.x1, r->box.y1, 442428d7b3dSmrg r->box.x2-r->box.x1, r->box.y2-r->box.y1, 443428d7b3dSmrg x, y, width, height, 444428d7b3dSmrg b.x1, b.y1, b.x2, b.y2)); 445428d7b3dSmrg 446428d7b3dSmrg if (b.y2 > b.y1 && b.x2 > b.x1) 447428d7b3dSmrg tmp.box(sna, &tmp, &b, r->opacity); 448428d7b3dSmrg r++; 449428d7b3dSmrg } 450428d7b3dSmrg tmp.done(sna, &tmp); 451428d7b3dSmrg } else { 452428d7b3dSmrg unsigned int flags; 453428d7b3dSmrg 454428d7b3dSmrg DBG(("%s -- falback\n", __FUNCTION__)); 455428d7b3dSmrg 456428d7b3dSmrg if (tile->op <= PictOpSrc) 457428d7b3dSmrg flags = MOVE_WRITE; 458428d7b3dSmrg else 459428d7b3dSmrg flags = MOVE_WRITE | MOVE_READ; 460428d7b3dSmrg if (!sna_drawable_move_to_cpu(tile->dst->pDrawable, 461428d7b3dSmrg flags)) 462428d7b3dSmrg goto done; 463428d7b3dSmrg if (tile->dst->alphaMap && 464428d7b3dSmrg !sna_drawable_move_to_cpu(tile->dst->alphaMap->pDrawable, 465428d7b3dSmrg flags)) 466428d7b3dSmrg goto done; 467428d7b3dSmrg 468428d7b3dSmrg if (tile->src->pDrawable && 469428d7b3dSmrg !sna_drawable_move_to_cpu(tile->src->pDrawable, 470428d7b3dSmrg MOVE_READ)) 471428d7b3dSmrg goto done; 472428d7b3dSmrg if (tile->src->alphaMap && 473428d7b3dSmrg !sna_drawable_move_to_cpu(tile->src->alphaMap->pDrawable, 474428d7b3dSmrg MOVE_READ)) 475428d7b3dSmrg goto done; 476428d7b3dSmrg 477428d7b3dSmrg for (n = 0; n < tile->rect_count; n++) { 478428d7b3dSmrg BoxRec b; 479428d7b3dSmrg 480428d7b3dSmrg b.x1 = r->box.x1 - tile->dst_x; 481428d7b3dSmrg if (b.x1 < x) 482428d7b3dSmrg b.x1 = x; 483428d7b3dSmrg 484428d7b3dSmrg b.y1 = r->box.y1 - tile->dst_y; 485428d7b3dSmrg if (b.y1 < y) 486428d7b3dSmrg b.y1 = y; 487428d7b3dSmrg 488428d7b3dSmrg b.x2 = r->box.x2 - tile->dst_x; 489428d7b3dSmrg if (b.x2 > x + width) 490428d7b3dSmrg b.x2 = x + width; 491428d7b3dSmrg 492428d7b3dSmrg b.y2 = r->box.y2 - tile->dst_y; 493428d7b3dSmrg if (b.y2 > y + height) 494428d7b3dSmrg b.y2 = y + height; 495428d7b3dSmrg 496428d7b3dSmrg DBG(("%s: rect[%d] = (%d, %d)x(%d,%d), tile=(%d,%d)x(%d, %d), blt=(%d,%d),(%d,%d)\n", 497428d7b3dSmrg __FUNCTION__, n, 498428d7b3dSmrg r->box.x1, r->box.y1, 499428d7b3dSmrg r->box.x2-r->box.x1, r->box.y2-r->box.y1, 500428d7b3dSmrg x, y, width, height, 501428d7b3dSmrg b.x1, b.y1, b.x2, b.y2)); 502428d7b3dSmrg 503428d7b3dSmrg if (b.y2 > b.y1 && b.x2 > b.x1) { 504428d7b3dSmrg xRenderColor alpha; 505428d7b3dSmrg PicturePtr mask; 506428d7b3dSmrg int error; 507428d7b3dSmrg 508428d7b3dSmrg alpha.red = alpha.green = alpha.blue = 0; 509428d7b3dSmrg alpha.alpha = r->opacity * 0xffff; 510428d7b3dSmrg 511428d7b3dSmrg mask = CreateSolidPicture(0, &alpha, &error); 512428d7b3dSmrg if (!mask) 513428d7b3dSmrg goto done; 514428d7b3dSmrg 515428d7b3dSmrg if (sigtrap_get() == 0) { 516428d7b3dSmrg fbComposite(tile->op, 517428d7b3dSmrg tile->src, mask, tile->dst, 518428d7b3dSmrg tile->src_x + x, tile->src_y + y, 519428d7b3dSmrg 0, 0, 520428d7b3dSmrg tile->dst_x + x, tile->dst_y + y, 521428d7b3dSmrg width, height); 522428d7b3dSmrg sigtrap_put(); 523428d7b3dSmrg } 524428d7b3dSmrg 525428d7b3dSmrg FreePicture(mask, 0); 526428d7b3dSmrg } 527428d7b3dSmrg r++; 528428d7b3dSmrg } 529428d7b3dSmrg 530428d7b3dSmrg force_fallback = true; 531428d7b3dSmrg } 532428d7b3dSmrg } 533428d7b3dSmrg } 534428d7b3dSmrg 535428d7b3dSmrgdone: 536428d7b3dSmrg if (tile->rects != tile->rects_embedded) 537428d7b3dSmrg free(tile->rects); 538428d7b3dSmrg free(tile); 539428d7b3dSmrg} 540428d7b3dSmrg 541428d7b3dSmrgbool 542428d7b3dSmrgsna_tiling_composite_spans(uint32_t op, 543428d7b3dSmrg PicturePtr src, 544428d7b3dSmrg PicturePtr dst, 545428d7b3dSmrg int16_t src_x, int16_t src_y, 546428d7b3dSmrg int16_t dst_x, int16_t dst_y, 547428d7b3dSmrg int16_t width, int16_t height, 548428d7b3dSmrg unsigned flags, 549428d7b3dSmrg struct sna_composite_spans_op *tmp) 550428d7b3dSmrg{ 551428d7b3dSmrg struct sna_tile_state *tile; 552428d7b3dSmrg struct sna_pixmap *priv; 553428d7b3dSmrg 554428d7b3dSmrg DBG(("%s size=(%d, %d), tile=%d\n", 555428d7b3dSmrg __FUNCTION__, width, height, 556428d7b3dSmrg to_sna_from_drawable(dst->pDrawable)->render.max_3d_size)); 557428d7b3dSmrg 558428d7b3dSmrg priv = sna_pixmap(get_drawable_pixmap(dst->pDrawable)); 559428d7b3dSmrg if (priv == NULL || priv->gpu_bo == NULL) 560428d7b3dSmrg return false; 561428d7b3dSmrg 562428d7b3dSmrg tile = malloc(sizeof(*tile)); 563428d7b3dSmrg if (!tile) 564428d7b3dSmrg return false; 565428d7b3dSmrg 566428d7b3dSmrg tile->op = op; 567428d7b3dSmrg tile->flags = flags; 568428d7b3dSmrg 569428d7b3dSmrg tile->src = src; 570428d7b3dSmrg tile->mask = NULL; 571428d7b3dSmrg tile->dst = dst; 572428d7b3dSmrg 573428d7b3dSmrg tile->src_x = src_x; 574428d7b3dSmrg tile->src_y = src_y; 575428d7b3dSmrg tile->mask_x = 0; 576428d7b3dSmrg tile->mask_y = 0; 577428d7b3dSmrg tile->dst_x = dst_x; 578428d7b3dSmrg tile->dst_y = dst_y; 579428d7b3dSmrg tile->width = width; 580428d7b3dSmrg tile->height = height; 581428d7b3dSmrg tile->rects = tile->rects_embedded; 582428d7b3dSmrg tile->rect_count = 0; 583428d7b3dSmrg tile->rect_size = ARRAY_SIZE(tile->rects_embedded); 584428d7b3dSmrg 585428d7b3dSmrg tmp->box = sna_tiling_composite_spans_box; 586428d7b3dSmrg tmp->boxes = sna_tiling_composite_spans_boxes; 587428d7b3dSmrg tmp->done = sna_tiling_composite_spans_done; 588428d7b3dSmrg 589428d7b3dSmrg tmp->base.priv = tile; 590428d7b3dSmrg tmp->base.dst.bo = priv->gpu_bo; 591428d7b3dSmrg return true; 592428d7b3dSmrg} 593428d7b3dSmrg 594428d7b3dSmrgbool 595428d7b3dSmrgsna_tiling_fill_boxes(struct sna *sna, 596428d7b3dSmrg CARD8 op, 597428d7b3dSmrg PictFormat format, 598428d7b3dSmrg const xRenderColor *color, 599428d7b3dSmrg const DrawableRec *dst, struct kgem_bo *dst_bo, 600428d7b3dSmrg const BoxRec *box, int n) 601428d7b3dSmrg{ 602428d7b3dSmrg RegionRec region, tile, this; 603428d7b3dSmrg struct kgem_bo *bo; 604428d7b3dSmrg int step, max_size; 605428d7b3dSmrg bool ret = false; 606428d7b3dSmrg 607428d7b3dSmrg pixman_region_init_rects(®ion, box, n); 608428d7b3dSmrg 609428d7b3dSmrg /* Use a small step to accommodate enlargement through tile alignment */ 610428d7b3dSmrg step = sna->render.max_3d_size; 611428d7b3dSmrg if (region.extents.x1 & (8*512 / dst->bitsPerPixel - 1) || 612428d7b3dSmrg region.extents.y1 & 63) 613428d7b3dSmrg step /= 2; 614428d7b3dSmrg 615428d7b3dSmrg max_size = sna_max_tile_copy_size(sna, dst_bo, dst_bo); 616428d7b3dSmrg if (max_size == 0) 617428d7b3dSmrg goto done; 618428d7b3dSmrg 619428d7b3dSmrg while (step * step * 4 > max_size) 620428d7b3dSmrg step /= 2; 621428d7b3dSmrg 622428d7b3dSmrg DBG(("%s (op=%d, format=%x, color=(%04x,%04x,%04x, %04x), tile.size=%d, box=%dx[(%d, %d), (%d, %d)])\n", 623428d7b3dSmrg __FUNCTION__, op, (int)format, 624428d7b3dSmrg color->red, color->green, color->blue, color->alpha, 625428d7b3dSmrg step, n, 626428d7b3dSmrg region.extents.x1, region.extents.y1, 627428d7b3dSmrg region.extents.x2, region.extents.y2)); 628428d7b3dSmrg 629428d7b3dSmrg for (tile.extents.y1 = tile.extents.y2 = region.extents.y1; 630428d7b3dSmrg tile.extents.y2 < region.extents.y2; 631428d7b3dSmrg tile.extents.y1 = tile.extents.y2) { 632428d7b3dSmrg int y2 = tile.extents.y1 + step; 633428d7b3dSmrg if (y2 > region.extents.y2) 634428d7b3dSmrg y2 = region.extents.y2; 635428d7b3dSmrg tile.extents.y2 = y2; 636428d7b3dSmrg 637428d7b3dSmrg for (tile.extents.x1 = tile.extents.x2 = region.extents.x1; 638428d7b3dSmrg tile.extents.x2 < region.extents.x2; 639428d7b3dSmrg tile.extents.x1 = tile.extents.x2) { 640428d7b3dSmrg DrawableRec tmp; 641428d7b3dSmrg int x2 = tile.extents.x1 + step; 642428d7b3dSmrg if (x2 > region.extents.x2) 643428d7b3dSmrg x2 = region.extents.x2; 644428d7b3dSmrg tile.extents.x2 = x2; 645428d7b3dSmrg 646428d7b3dSmrg tile.data = NULL; 647428d7b3dSmrg 648428d7b3dSmrg RegionNull(&this); 649428d7b3dSmrg RegionIntersect(&this, ®ion, &tile); 650428d7b3dSmrg if (RegionNil(&this)) 651428d7b3dSmrg continue; 652428d7b3dSmrg 653428d7b3dSmrg tmp.width = this.extents.x2 - this.extents.x1; 654428d7b3dSmrg tmp.height = this.extents.y2 - this.extents.y1; 655428d7b3dSmrg tmp.depth = dst->depth; 656428d7b3dSmrg tmp.bitsPerPixel = dst->bitsPerPixel; 657428d7b3dSmrg 658428d7b3dSmrg bo = kgem_create_2d(&sna->kgem, 659428d7b3dSmrg tmp.width, 660428d7b3dSmrg tmp.height, 661428d7b3dSmrg dst->bitsPerPixel, 662428d7b3dSmrg kgem_choose_tiling(&sna->kgem, 663428d7b3dSmrg I915_TILING_X, 664428d7b3dSmrg tmp.width, 665428d7b3dSmrg tmp.height, 666428d7b3dSmrg dst->bitsPerPixel), 667428d7b3dSmrg CREATE_TEMPORARY); 668428d7b3dSmrg if (bo) { 669428d7b3dSmrg int16_t dx = this.extents.x1; 670428d7b3dSmrg int16_t dy = this.extents.y1; 671428d7b3dSmrg 672428d7b3dSmrg assert(kgem_bo_can_blt(&sna->kgem, bo)); 673428d7b3dSmrg 674428d7b3dSmrg if (op > PictOpSrc && 675428d7b3dSmrg !sna->render.copy_boxes(sna, GXcopy, 676428d7b3dSmrg dst, dst_bo, 0, 0, 677428d7b3dSmrg &tmp, bo, -dx, -dy, 678428d7b3dSmrg region_rects(&this), region_num_rects(&this), 0)) 679428d7b3dSmrg goto err; 680428d7b3dSmrg 681428d7b3dSmrg RegionTranslate(&this, -dx, -dy); 682428d7b3dSmrg if (!sna->render.fill_boxes(sna, op, format, color, &tmp, bo, 683428d7b3dSmrg region_rects(&this), region_num_rects(&this))) 684428d7b3dSmrg goto err; 685428d7b3dSmrg 686428d7b3dSmrg if (!sna->render.copy_boxes(sna, GXcopy, 687428d7b3dSmrg &tmp, bo, 0, 0, 688428d7b3dSmrg dst, dst_bo, dx, dy, 689428d7b3dSmrg region_rects(&this), region_num_rects(&this), 0)) 690428d7b3dSmrg goto err; 691428d7b3dSmrg 692428d7b3dSmrg kgem_bo_destroy(&sna->kgem, bo); 693428d7b3dSmrg } 694428d7b3dSmrg RegionUninit(&this); 695428d7b3dSmrg } 696428d7b3dSmrg } 697428d7b3dSmrg 698428d7b3dSmrg ret = true; 699428d7b3dSmrg goto done; 700428d7b3dSmrgerr: 701428d7b3dSmrg kgem_bo_destroy(&sna->kgem, bo); 702428d7b3dSmrg RegionUninit(&this); 703428d7b3dSmrgdone: 704428d7b3dSmrg pixman_region_fini(®ion); 705428d7b3dSmrg return ret; 706428d7b3dSmrg} 707428d7b3dSmrg 708428d7b3dSmrgfastcall static void 709428d7b3dSmrgtiling_blt(struct sna *sna, 710428d7b3dSmrg const struct sna_composite_op *op, 711428d7b3dSmrg const struct sna_composite_rectangles *r) 712428d7b3dSmrg{ 713428d7b3dSmrg int x1, x2, y1, y2; 714428d7b3dSmrg int src_x, src_y; 715428d7b3dSmrg BoxRec box; 716428d7b3dSmrg 717428d7b3dSmrg DBG(("%s: src=(%d, %d), dst=(%d, %d), size=(%d, %d)\n", 718428d7b3dSmrg __FUNCTION__, 719428d7b3dSmrg r->src.x, r->src.y, 720428d7b3dSmrg r->dst.x, r->dst.y, 721428d7b3dSmrg r->width, r->height)); 722428d7b3dSmrg 723428d7b3dSmrg /* XXX higher layer should have clipped? */ 724428d7b3dSmrg 725428d7b3dSmrg x1 = r->dst.x + op->dst.x; 726428d7b3dSmrg y1 = r->dst.y + op->dst.y; 727428d7b3dSmrg x2 = x1 + r->width; 728428d7b3dSmrg y2 = y1 + r->height; 729428d7b3dSmrg 730428d7b3dSmrg src_x = r->src.x - x1 + op->u.blt.sx; 731428d7b3dSmrg src_y = r->src.y - y1 + op->u.blt.sy; 732428d7b3dSmrg 733428d7b3dSmrg /* clip against dst */ 734428d7b3dSmrg if (x1 < 0) 735428d7b3dSmrg x1 = 0; 736428d7b3dSmrg if (y1 < 0) 737428d7b3dSmrg y1 = 0; 738428d7b3dSmrg 739428d7b3dSmrg if (x2 > op->dst.width) 740428d7b3dSmrg x2 = op->dst.width; 741428d7b3dSmrg 742428d7b3dSmrg if (y2 > op->dst.height) 743428d7b3dSmrg y2 = op->dst.height; 744428d7b3dSmrg 745428d7b3dSmrg DBG(("%s: box=(%d, %d), (%d, %d)\n", __FUNCTION__, x1, y1, x2, y2)); 746428d7b3dSmrg 747428d7b3dSmrg if (x2 <= x1 || y2 <= y1) 748428d7b3dSmrg return; 749428d7b3dSmrg 750428d7b3dSmrg box.x1 = x1; box.y1 = y1; 751428d7b3dSmrg box.x2 = x2; box.y2 = y2; 752428d7b3dSmrg sna_tiling_blt_copy_boxes(sna, GXcopy, 753428d7b3dSmrg op->src.bo, src_x, src_y, 754428d7b3dSmrg op->dst.bo, 0, 0, 755428d7b3dSmrg op->u.blt.bpp, 756428d7b3dSmrg &box, 1); 757428d7b3dSmrg} 758428d7b3dSmrg 759428d7b3dSmrgfastcall static void 760428d7b3dSmrgtiling_blt_box(struct sna *sna, 761428d7b3dSmrg const struct sna_composite_op *op, 762428d7b3dSmrg const BoxRec *box) 763428d7b3dSmrg{ 764428d7b3dSmrg DBG(("%s: box (%d, %d), (%d, %d)\n", 765428d7b3dSmrg __FUNCTION__, box->x1, box->y1, box->x2, box->y2)); 766428d7b3dSmrg sna_tiling_blt_copy_boxes(sna, GXcopy, 767428d7b3dSmrg op->src.bo, op->u.blt.sx, op->u.blt.sy, 768428d7b3dSmrg op->dst.bo, op->dst.x, op->dst.y, 769428d7b3dSmrg op->u.blt.bpp, 770428d7b3dSmrg box, 1); 771428d7b3dSmrg} 772428d7b3dSmrg 773428d7b3dSmrgstatic void 774428d7b3dSmrgtiling_blt_boxes(struct sna *sna, 775428d7b3dSmrg const struct sna_composite_op *op, 776428d7b3dSmrg const BoxRec *box, int nbox) 777428d7b3dSmrg{ 778428d7b3dSmrg DBG(("%s: nbox=%d\n", __FUNCTION__, nbox)); 779428d7b3dSmrg sna_tiling_blt_copy_boxes(sna, GXcopy, 780428d7b3dSmrg op->src.bo, op->u.blt.sx, op->u.blt.sy, 781428d7b3dSmrg op->dst.bo, op->dst.x, op->dst.y, 782428d7b3dSmrg op->u.blt.bpp, 783428d7b3dSmrg box, nbox); 784428d7b3dSmrg} 785428d7b3dSmrg 786428d7b3dSmrgstatic bool 787428d7b3dSmrgsna_tiling_blt_copy_boxes__with_alpha(struct sna *sna, uint8_t alu, 788428d7b3dSmrg struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy, 789428d7b3dSmrg struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy, 790428d7b3dSmrg int bpp, int alpha_fixup, 791428d7b3dSmrg const BoxRec *box, int nbox) 792428d7b3dSmrg{ 793428d7b3dSmrg RegionRec region, tile, this; 794428d7b3dSmrg struct kgem_bo *bo; 795428d7b3dSmrg int max_size, step; 796428d7b3dSmrg bool ret = false; 797428d7b3dSmrg 798428d7b3dSmrg if (wedged(sna) || 799428d7b3dSmrg !kgem_bo_can_blt(&sna->kgem, src_bo) || 800428d7b3dSmrg !kgem_bo_can_blt(&sna->kgem, dst_bo)) { 801428d7b3dSmrg /* XXX */ 802428d7b3dSmrg DBG(("%s: tiling blt fail: src?=%d, dst?=%d\n", 803428d7b3dSmrg __FUNCTION__, 804428d7b3dSmrg kgem_bo_can_blt(&sna->kgem, src_bo), 805428d7b3dSmrg kgem_bo_can_blt(&sna->kgem, dst_bo))); 806428d7b3dSmrg return false; 807428d7b3dSmrg } 808428d7b3dSmrg 809428d7b3dSmrg max_size = sna_max_tile_copy_size(sna, src_bo, dst_bo); 810428d7b3dSmrg if (max_size == 0) 811428d7b3dSmrg return false; 812428d7b3dSmrg 813428d7b3dSmrg pixman_region_init_rects(®ion, box, nbox); 814428d7b3dSmrg 815428d7b3dSmrg /* Use a small step to accommodate enlargement through tile alignment */ 816428d7b3dSmrg step = sna->render.max_3d_size; 817428d7b3dSmrg if (region.extents.x1 & (8*512 / bpp - 1) || region.extents.y1 & 63) 818428d7b3dSmrg step /= 2; 819428d7b3dSmrg while (step * step * 4 > max_size) 820428d7b3dSmrg step /= 2; 821428d7b3dSmrg if (sna->kgem.gen < 033) 822428d7b3dSmrg step /= 2; /* accommodate severe fence restrictions */ 823428d7b3dSmrg if (step == 0) { 824428d7b3dSmrg DBG(("%s: tiles cannot fit into aperture\n", __FUNCTION__)); 825428d7b3dSmrg return false; 826428d7b3dSmrg } 827428d7b3dSmrg 828428d7b3dSmrg DBG(("%s (alu=%d), tile.size=%d, box=%dx[(%d, %d), (%d, %d)])\n", 829428d7b3dSmrg __FUNCTION__, alu, step, nbox, 830428d7b3dSmrg region.extents.x1, region.extents.y1, 831428d7b3dSmrg region.extents.x2, region.extents.y2)); 832428d7b3dSmrg 833428d7b3dSmrg for (tile.extents.y1 = tile.extents.y2 = region.extents.y1; 834428d7b3dSmrg tile.extents.y2 < region.extents.y2; 835428d7b3dSmrg tile.extents.y1 = tile.extents.y2) { 836428d7b3dSmrg int y2 = tile.extents.y1 + step; 837428d7b3dSmrg if (y2 > region.extents.y2) 838428d7b3dSmrg y2 = region.extents.y2; 839428d7b3dSmrg tile.extents.y2 = y2; 840428d7b3dSmrg 841428d7b3dSmrg for (tile.extents.x1 = tile.extents.x2 = region.extents.x1; 842428d7b3dSmrg tile.extents.x2 < region.extents.x2; 843428d7b3dSmrg tile.extents.x1 = tile.extents.x2) { 844428d7b3dSmrg int w, h; 845428d7b3dSmrg int x2 = tile.extents.x1 + step; 846428d7b3dSmrg if (x2 > region.extents.x2) 847428d7b3dSmrg x2 = region.extents.x2; 848428d7b3dSmrg tile.extents.x2 = x2; 849428d7b3dSmrg 850428d7b3dSmrg tile.data = NULL; 851428d7b3dSmrg 852428d7b3dSmrg RegionNull(&this); 853428d7b3dSmrg RegionIntersect(&this, ®ion, &tile); 854428d7b3dSmrg if (RegionNil(&this)) 855428d7b3dSmrg continue; 856428d7b3dSmrg 857428d7b3dSmrg w = this.extents.x2 - this.extents.x1; 858428d7b3dSmrg h = this.extents.y2 - this.extents.y1; 859428d7b3dSmrg bo = kgem_create_2d(&sna->kgem, w, h, bpp, 860428d7b3dSmrg kgem_choose_tiling(&sna->kgem, 861428d7b3dSmrg I915_TILING_X, 862428d7b3dSmrg w, h, bpp), 863428d7b3dSmrg CREATE_TEMPORARY); 864428d7b3dSmrg if (bo) { 865428d7b3dSmrg int16_t dx = this.extents.x1; 866428d7b3dSmrg int16_t dy = this.extents.y1; 867428d7b3dSmrg 868428d7b3dSmrg assert(kgem_bo_can_blt(&sna->kgem, bo)); 869428d7b3dSmrg 870428d7b3dSmrg if (!sna_blt_copy_boxes(sna, GXcopy, 871428d7b3dSmrg src_bo, src_dx, src_dy, 872428d7b3dSmrg bo, -dx, -dy, 873428d7b3dSmrg bpp, region_rects(&this), region_num_rects(&this))) 874428d7b3dSmrg goto err; 875428d7b3dSmrg 876428d7b3dSmrg if (!sna_blt_copy_boxes__with_alpha(sna, alu, 877428d7b3dSmrg bo, -dx, -dy, 878428d7b3dSmrg dst_bo, dst_dx, dst_dy, 879428d7b3dSmrg bpp, alpha_fixup, 880428d7b3dSmrg region_rects(&this), region_num_rects(&this))) 881428d7b3dSmrg goto err; 882428d7b3dSmrg 883428d7b3dSmrg kgem_bo_destroy(&sna->kgem, bo); 884428d7b3dSmrg } 885428d7b3dSmrg RegionUninit(&this); 886428d7b3dSmrg } 887428d7b3dSmrg } 888428d7b3dSmrg 889428d7b3dSmrg ret = true; 890428d7b3dSmrg goto done; 891428d7b3dSmrgerr: 892428d7b3dSmrg kgem_bo_destroy(&sna->kgem, bo); 893428d7b3dSmrg RegionUninit(&this); 894428d7b3dSmrgdone: 895428d7b3dSmrg pixman_region_fini(®ion); 896428d7b3dSmrg return ret; 897428d7b3dSmrg} 898428d7b3dSmrg 899428d7b3dSmrgfastcall static void 900428d7b3dSmrgtiling_blt__with_alpha(struct sna *sna, 901428d7b3dSmrg const struct sna_composite_op *op, 902428d7b3dSmrg const struct sna_composite_rectangles *r) 903428d7b3dSmrg{ 904428d7b3dSmrg int x1, x2, y1, y2; 905428d7b3dSmrg int src_x, src_y; 906428d7b3dSmrg BoxRec box; 907428d7b3dSmrg 908428d7b3dSmrg DBG(("%s: src=(%d, %d), dst=(%d, %d), size=(%d, %d)\n", 909428d7b3dSmrg __FUNCTION__, 910428d7b3dSmrg r->src.x, r->src.y, 911428d7b3dSmrg r->dst.x, r->dst.y, 912428d7b3dSmrg r->width, r->height)); 913428d7b3dSmrg 914428d7b3dSmrg /* XXX higher layer should have clipped? */ 915428d7b3dSmrg 916428d7b3dSmrg x1 = r->dst.x + op->dst.x; 917428d7b3dSmrg y1 = r->dst.y + op->dst.y; 918428d7b3dSmrg x2 = x1 + r->width; 919428d7b3dSmrg y2 = y1 + r->height; 920428d7b3dSmrg 921428d7b3dSmrg src_x = r->src.x - x1 + op->u.blt.sx; 922428d7b3dSmrg src_y = r->src.y - y1 + op->u.blt.sy; 923428d7b3dSmrg 924428d7b3dSmrg /* clip against dst */ 925428d7b3dSmrg if (x1 < 0) 926428d7b3dSmrg x1 = 0; 927428d7b3dSmrg if (y1 < 0) 928428d7b3dSmrg y1 = 0; 929428d7b3dSmrg 930428d7b3dSmrg if (x2 > op->dst.width) 931428d7b3dSmrg x2 = op->dst.width; 932428d7b3dSmrg 933428d7b3dSmrg if (y2 > op->dst.height) 934428d7b3dSmrg y2 = op->dst.height; 935428d7b3dSmrg 936428d7b3dSmrg DBG(("%s: box=(%d, %d), (%d, %d)\n", __FUNCTION__, x1, y1, x2, y2)); 937428d7b3dSmrg 938428d7b3dSmrg if (x2 <= x1 || y2 <= y1) 939428d7b3dSmrg return; 940428d7b3dSmrg 941428d7b3dSmrg box.x1 = x1; box.y1 = y1; 942428d7b3dSmrg box.x2 = x2; box.y2 = y2; 943428d7b3dSmrg sna_tiling_blt_copy_boxes__with_alpha(sna, GXcopy, 944428d7b3dSmrg op->src.bo, src_x, src_y, 945428d7b3dSmrg op->dst.bo, 0, 0, 946428d7b3dSmrg op->u.blt.bpp, op->u.blt.pixel, 947428d7b3dSmrg &box, 1); 948428d7b3dSmrg} 949428d7b3dSmrg 950428d7b3dSmrgfastcall static void 951428d7b3dSmrgtiling_blt_box__with_alpha(struct sna *sna, 952428d7b3dSmrg const struct sna_composite_op *op, 953428d7b3dSmrg const BoxRec *box) 954428d7b3dSmrg{ 955428d7b3dSmrg DBG(("%s: box (%d, %d), (%d, %d)\n", 956428d7b3dSmrg __FUNCTION__, box->x1, box->y1, box->x2, box->y2)); 957428d7b3dSmrg sna_tiling_blt_copy_boxes__with_alpha(sna, GXcopy, 958428d7b3dSmrg op->src.bo, op->u.blt.sx, op->u.blt.sy, 959428d7b3dSmrg op->dst.bo, op->dst.x, op->dst.y, 960428d7b3dSmrg op->u.blt.bpp, op->u.blt.pixel, 961428d7b3dSmrg box, 1); 962428d7b3dSmrg} 963428d7b3dSmrg 964428d7b3dSmrgstatic void 965428d7b3dSmrgtiling_blt_boxes__with_alpha(struct sna *sna, 966428d7b3dSmrg const struct sna_composite_op *op, 967428d7b3dSmrg const BoxRec *box, int nbox) 968428d7b3dSmrg{ 969428d7b3dSmrg DBG(("%s: nbox=%d\n", __FUNCTION__, nbox)); 970428d7b3dSmrg sna_tiling_blt_copy_boxes__with_alpha(sna, GXcopy, 971428d7b3dSmrg op->src.bo, op->u.blt.sx, op->u.blt.sy, 972428d7b3dSmrg op->dst.bo, op->dst.x, op->dst.y, 973428d7b3dSmrg op->u.blt.bpp, op->u.blt.pixel, 974428d7b3dSmrg box, nbox); 975428d7b3dSmrg} 976428d7b3dSmrg 977428d7b3dSmrgstatic void nop_done(struct sna *sna, const struct sna_composite_op *op) 978428d7b3dSmrg{ 979428d7b3dSmrg assert(sna->kgem.nbatch <= KGEM_BATCH_SIZE(&sna->kgem)); 980428d7b3dSmrg (void)op; 981428d7b3dSmrg} 982428d7b3dSmrg 983428d7b3dSmrgbool 984428d7b3dSmrgsna_tiling_blt_composite(struct sna *sna, 985428d7b3dSmrg struct sna_composite_op *op, 986428d7b3dSmrg struct kgem_bo *bo, 987428d7b3dSmrg int bpp, 988428d7b3dSmrg uint32_t alpha_fixup) 989428d7b3dSmrg{ 990428d7b3dSmrg assert(op->dst.bo); 991428d7b3dSmrg assert(kgem_bo_can_blt(&sna->kgem, op->dst.bo)); 992428d7b3dSmrg assert(kgem_bo_can_blt(&sna->kgem, bo)); 993428d7b3dSmrg 994428d7b3dSmrg op->src.bo = bo; 995428d7b3dSmrg op->u.blt.bpp = bpp; 996428d7b3dSmrg op->u.blt.pixel = alpha_fixup; 997428d7b3dSmrg 998428d7b3dSmrg if (alpha_fixup) { 999428d7b3dSmrg op->blt = tiling_blt__with_alpha; 1000428d7b3dSmrg op->box = tiling_blt_box__with_alpha; 1001428d7b3dSmrg op->boxes = tiling_blt_boxes__with_alpha; 1002428d7b3dSmrg } else { 1003428d7b3dSmrg op->blt = tiling_blt; 1004428d7b3dSmrg op->box = tiling_blt_box; 1005428d7b3dSmrg op->boxes = tiling_blt_boxes; 1006428d7b3dSmrg } 1007428d7b3dSmrg op->done = nop_done; 1008428d7b3dSmrg 1009428d7b3dSmrg return true; 1010428d7b3dSmrg} 1011428d7b3dSmrg 1012428d7b3dSmrgbool sna_tiling_blt_copy_boxes(struct sna *sna, uint8_t alu, 1013428d7b3dSmrg struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy, 1014428d7b3dSmrg struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy, 1015428d7b3dSmrg int bpp, const BoxRec *box, int nbox) 1016428d7b3dSmrg{ 1017428d7b3dSmrg RegionRec region, tile, this; 1018428d7b3dSmrg struct kgem_bo *bo; 1019428d7b3dSmrg int max_size, step; 1020428d7b3dSmrg bool ret = false; 1021428d7b3dSmrg 1022428d7b3dSmrg DBG(("%s: alu=%d, src size=%d, dst size=%d\n", __FUNCTION__, 1023428d7b3dSmrg alu, kgem_bo_size(src_bo), kgem_bo_size(dst_bo))); 1024428d7b3dSmrg 1025428d7b3dSmrg if (wedged(sna) || 1026428d7b3dSmrg !kgem_bo_can_blt(&sna->kgem, src_bo) || 1027428d7b3dSmrg !kgem_bo_can_blt(&sna->kgem, dst_bo)) { 1028428d7b3dSmrg /* XXX */ 1029428d7b3dSmrg DBG(("%s: tiling blt fail: src?=%d, dst?=%d\n", 1030428d7b3dSmrg __FUNCTION__, 1031428d7b3dSmrg kgem_bo_can_blt(&sna->kgem, src_bo), 1032428d7b3dSmrg kgem_bo_can_blt(&sna->kgem, dst_bo))); 1033428d7b3dSmrg return false; 1034428d7b3dSmrg } 1035428d7b3dSmrg 1036428d7b3dSmrg max_size = sna_max_tile_copy_size(sna, src_bo, dst_bo); 1037428d7b3dSmrg if (max_size == 0) 1038428d7b3dSmrg return false; 1039428d7b3dSmrg 1040428d7b3dSmrg pixman_region_init_rects(®ion, box, nbox); 1041428d7b3dSmrg 1042428d7b3dSmrg /* Use a small step to accommodate enlargement through tile alignment */ 1043428d7b3dSmrg step = sna->render.max_3d_size; 1044428d7b3dSmrg if (region.extents.x1 & (8*512 / bpp - 1) || region.extents.y1 & 63) 1045428d7b3dSmrg step /= 2; 1046428d7b3dSmrg while (step * step * 4 > max_size) 1047428d7b3dSmrg step /= 2; 1048428d7b3dSmrg if (sna->kgem.gen < 033) 1049428d7b3dSmrg step /= 2; /* accommodate severe fence restrictions */ 1050428d7b3dSmrg if (step == 0) { 1051428d7b3dSmrg DBG(("%s: tiles cannot fit into aperture\n", __FUNCTION__)); 1052428d7b3dSmrg return false; 1053428d7b3dSmrg } 1054428d7b3dSmrg 1055428d7b3dSmrg DBG(("%s (alu=%d), tile.size=%d, box=%dx[(%d, %d), (%d, %d)])\n", 1056428d7b3dSmrg __FUNCTION__, alu, step, nbox, 1057428d7b3dSmrg region.extents.x1, region.extents.y1, 1058428d7b3dSmrg region.extents.x2, region.extents.y2)); 1059428d7b3dSmrg 1060428d7b3dSmrg for (tile.extents.y1 = tile.extents.y2 = region.extents.y1; 1061428d7b3dSmrg tile.extents.y2 < region.extents.y2; 1062428d7b3dSmrg tile.extents.y1 = tile.extents.y2) { 1063428d7b3dSmrg int y2 = tile.extents.y1 + step; 1064428d7b3dSmrg if (y2 > region.extents.y2) 1065428d7b3dSmrg y2 = region.extents.y2; 1066428d7b3dSmrg tile.extents.y2 = y2; 1067428d7b3dSmrg 1068428d7b3dSmrg for (tile.extents.x1 = tile.extents.x2 = region.extents.x1; 1069428d7b3dSmrg tile.extents.x2 < region.extents.x2; 1070428d7b3dSmrg tile.extents.x1 = tile.extents.x2) { 1071428d7b3dSmrg int w, h; 1072428d7b3dSmrg int x2 = tile.extents.x1 + step; 1073428d7b3dSmrg if (x2 > region.extents.x2) 1074428d7b3dSmrg x2 = region.extents.x2; 1075428d7b3dSmrg tile.extents.x2 = x2; 1076428d7b3dSmrg 1077428d7b3dSmrg tile.data = NULL; 1078428d7b3dSmrg 1079428d7b3dSmrg RegionNull(&this); 1080428d7b3dSmrg RegionIntersect(&this, ®ion, &tile); 1081428d7b3dSmrg if (RegionNil(&this)) 1082428d7b3dSmrg continue; 1083428d7b3dSmrg 1084428d7b3dSmrg w = this.extents.x2 - this.extents.x1; 1085428d7b3dSmrg h = this.extents.y2 - this.extents.y1; 1086428d7b3dSmrg bo = kgem_create_2d(&sna->kgem, w, h, bpp, 1087428d7b3dSmrg kgem_choose_tiling(&sna->kgem, 1088428d7b3dSmrg I915_TILING_X, 1089428d7b3dSmrg w, h, bpp), 1090428d7b3dSmrg CREATE_TEMPORARY); 1091428d7b3dSmrg if (bo) { 1092428d7b3dSmrg int16_t dx = this.extents.x1; 1093428d7b3dSmrg int16_t dy = this.extents.y1; 1094428d7b3dSmrg 1095428d7b3dSmrg assert(kgem_bo_can_blt(&sna->kgem, bo)); 1096428d7b3dSmrg 1097428d7b3dSmrg if (!sna_blt_copy_boxes(sna, GXcopy, 1098428d7b3dSmrg src_bo, src_dx, src_dy, 1099428d7b3dSmrg bo, -dx, -dy, 1100428d7b3dSmrg bpp, region_rects(&this), region_num_rects(&this))) 1101428d7b3dSmrg goto err; 1102428d7b3dSmrg 1103428d7b3dSmrg if (!sna_blt_copy_boxes(sna, alu, 1104428d7b3dSmrg bo, -dx, -dy, 1105428d7b3dSmrg dst_bo, dst_dx, dst_dy, 1106428d7b3dSmrg bpp, region_rects(&this), region_num_rects(&this))) 1107428d7b3dSmrg goto err; 1108428d7b3dSmrg 1109428d7b3dSmrg kgem_bo_destroy(&sna->kgem, bo); 1110428d7b3dSmrg } 1111428d7b3dSmrg RegionUninit(&this); 1112428d7b3dSmrg } 1113428d7b3dSmrg } 1114428d7b3dSmrg 1115428d7b3dSmrg ret = true; 1116428d7b3dSmrg goto done; 1117428d7b3dSmrgerr: 1118428d7b3dSmrg kgem_bo_destroy(&sna->kgem, bo); 1119428d7b3dSmrg RegionUninit(&this); 1120428d7b3dSmrgdone: 1121428d7b3dSmrg pixman_region_fini(®ion); 1122428d7b3dSmrg return ret; 1123428d7b3dSmrg} 1124428d7b3dSmrg 1125428d7b3dSmrgbool 1126428d7b3dSmrgsna_tiling_copy_boxes(struct sna *sna, uint8_t alu, 1127428d7b3dSmrg const DrawableRec *src, struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy, 1128428d7b3dSmrg const DrawableRec *dst, struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy, 1129428d7b3dSmrg const BoxRec *box, int n) 1130428d7b3dSmrg{ 1131428d7b3dSmrg BoxRec extents, tile, stack[64], *clipped, *c; 1132428d7b3dSmrg DrawableRec p; 1133428d7b3dSmrg int i, step, tiling; 1134428d7b3dSmrg bool create = true; 1135428d7b3dSmrg bool ret = false; 1136428d7b3dSmrg 1137428d7b3dSmrg extents = box[0]; 1138428d7b3dSmrg for (i = 1; i < n; i++) { 1139428d7b3dSmrg if (box[i].x1 < extents.x1) 1140428d7b3dSmrg extents.x1 = box[i].x1; 1141428d7b3dSmrg if (box[i].y1 < extents.y1) 1142428d7b3dSmrg extents.y1 = box[i].y1; 1143428d7b3dSmrg 1144428d7b3dSmrg if (box[i].x2 > extents.x2) 1145428d7b3dSmrg extents.x2 = box[i].x2; 1146428d7b3dSmrg if (box[i].y2 > extents.y2) 1147428d7b3dSmrg extents.y2 = box[i].y2; 1148428d7b3dSmrg } 1149428d7b3dSmrg 1150428d7b3dSmrg tiling = I915_TILING_X; 1151428d7b3dSmrg if (!kgem_bo_can_blt(&sna->kgem, src_bo) || 1152428d7b3dSmrg !kgem_bo_can_blt(&sna->kgem, dst_bo)) 1153428d7b3dSmrg tiling = I915_TILING_Y; 1154428d7b3dSmrg 1155428d7b3dSmrg create = (src_bo->pitch > sna->render.max_3d_pitch || 1156428d7b3dSmrg dst_bo->pitch > sna->render.max_3d_pitch); 1157428d7b3dSmrg 1158428d7b3dSmrg step = sna->render.max_3d_size / 2; 1159428d7b3dSmrg if (create) { 1160428d7b3dSmrg while (step * step * 4 > sna->kgem.max_upload_tile_size) 1161428d7b3dSmrg step /= 2; 1162428d7b3dSmrg } 1163428d7b3dSmrg 1164428d7b3dSmrg DBG(("%s: tiling copy %dx%d, %s %dx%d %c tiles\n", __FUNCTION__, 1165428d7b3dSmrg extents.x2-extents.x1, extents.y2-extents.y1, 1166428d7b3dSmrg create ? "creating" : "using", 1167428d7b3dSmrg step, step, tiling == I915_TILING_X ? 'X' : 'Y')); 1168428d7b3dSmrg 1169428d7b3dSmrg if (n > ARRAY_SIZE(stack)) { 1170428d7b3dSmrg clipped = malloc(sizeof(BoxRec) * n); 1171428d7b3dSmrg if (clipped == NULL) 1172428d7b3dSmrg goto tiled_error; 1173428d7b3dSmrg } else 1174428d7b3dSmrg clipped = stack; 1175428d7b3dSmrg 1176428d7b3dSmrg p.depth = src->depth; 1177428d7b3dSmrg p.bitsPerPixel = src->bitsPerPixel; 1178428d7b3dSmrg 1179428d7b3dSmrg for (tile.y1 = extents.y1; tile.y1 < extents.y2; tile.y1 = tile.y2) { 1180428d7b3dSmrg int y2 = tile.y1 + step; 1181428d7b3dSmrg if (y2 > extents.y2) 1182428d7b3dSmrg y2 = extents.y2; 1183428d7b3dSmrg tile.y2 = y2; 1184428d7b3dSmrg 1185428d7b3dSmrg for (tile.x1 = extents.x1; tile.x1 < extents.x2; tile.x1 = tile.x2) { 1186428d7b3dSmrg struct kgem_bo *tmp_bo; 1187428d7b3dSmrg int x2 = tile.x1 + step; 1188428d7b3dSmrg if (x2 > extents.x2) 1189428d7b3dSmrg x2 = extents.x2; 1190428d7b3dSmrg tile.x2 = x2; 1191428d7b3dSmrg 1192428d7b3dSmrg c = clipped; 1193428d7b3dSmrg for (i = 0; i < n; i++) { 1194428d7b3dSmrg *c = box[i]; 1195428d7b3dSmrg if (!box_intersect(c, &tile)) 1196428d7b3dSmrg continue; 1197428d7b3dSmrg 1198428d7b3dSmrg DBG(("%s: box(%d, %d), (%d, %d), src=(%d, %d), dst=(%d, %d)\n", 1199428d7b3dSmrg __FUNCTION__, 1200428d7b3dSmrg c->x1, c->y1, 1201428d7b3dSmrg c->x2, c->y2, 1202428d7b3dSmrg src_dx, src_dy, 1203428d7b3dSmrg c->x1 - tile.x1, 1204428d7b3dSmrg c->y1 - tile.y1)); 1205428d7b3dSmrg c++; 1206428d7b3dSmrg } 1207428d7b3dSmrg if (c == clipped) 1208428d7b3dSmrg continue; 1209428d7b3dSmrg 1210428d7b3dSmrg p.width = tile.x2 - tile.x1; 1211428d7b3dSmrg p.height = tile.y2 - tile.y1; 1212428d7b3dSmrg 1213428d7b3dSmrg DBG(("%s: tile (%d, %d), (%d, %d)\n", 1214428d7b3dSmrg __FUNCTION__, tile.x1, tile.y1, tile.x2, tile.y2)); 1215428d7b3dSmrg 1216428d7b3dSmrg if (create) { 1217428d7b3dSmrg tmp_bo = kgem_create_2d(&sna->kgem, 1218428d7b3dSmrg p.width, 1219428d7b3dSmrg p.height, 1220428d7b3dSmrg p.bitsPerPixel, 1221428d7b3dSmrg tiling, CREATE_TEMPORARY); 1222428d7b3dSmrg if (!tmp_bo) 1223428d7b3dSmrg goto tiled_error; 1224428d7b3dSmrg 1225428d7b3dSmrg i = (sna->render.copy_boxes(sna, GXcopy, 1226428d7b3dSmrg src, src_bo, src_dx, src_dy, 1227428d7b3dSmrg &p, tmp_bo, -tile.x1, -tile.y1, 1228428d7b3dSmrg clipped, c - clipped, 0) && 1229428d7b3dSmrg sna->render.copy_boxes(sna, alu, 1230428d7b3dSmrg &p, tmp_bo, -tile.x1, -tile.y1, 1231428d7b3dSmrg dst, dst_bo, dst_dx, dst_dy, 1232428d7b3dSmrg clipped, c - clipped, 0)); 1233428d7b3dSmrg 1234428d7b3dSmrg kgem_bo_destroy(&sna->kgem, tmp_bo); 1235428d7b3dSmrg } else { 1236428d7b3dSmrg i = sna->render.copy_boxes(sna, GXcopy, 1237428d7b3dSmrg src, src_bo, src_dx, src_dy, 1238428d7b3dSmrg dst, dst_bo, dst_dx, dst_dy, 1239428d7b3dSmrg clipped, c - clipped, 0); 1240428d7b3dSmrg } 1241428d7b3dSmrg 1242428d7b3dSmrg if (!i) 1243428d7b3dSmrg goto tiled_error; 1244428d7b3dSmrg } 1245428d7b3dSmrg } 1246428d7b3dSmrg 1247428d7b3dSmrg ret = true; 1248428d7b3dSmrgtiled_error: 1249428d7b3dSmrg if (clipped != stack) 1250428d7b3dSmrg free(clipped); 1251428d7b3dSmrg 1252428d7b3dSmrg return ret; 1253428d7b3dSmrg} 1254