static bool sna_tiling_blt_copy_boxes__with_alpha(struct sna *sna, uint8_t alu, struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy, struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy, int bpp, int alpha_fixup, const BoxRec *box, int nbox) { RegionRec region, tile, this; struct kgem_bo *bo; int max_size, step; bool ret = false; if (wedged(sna) || !kgem_bo_can_blt(&sna->kgem, src_bo) || !kgem_bo_can_blt(&sna->kgem, dst_bo)) { /* XXX */ DBG(("%s: tiling blt fail: src?=%d, dst?=%d\n", __FUNCTION__, kgem_bo_can_blt(&sna->kgem, src_bo), kgem_bo_can_blt(&sna->kgem, dst_bo))); return false; } max_size = sna->kgem.aperture_high * PAGE_SIZE; max_size -= MAX(kgem_bo_size(src_bo), kgem_bo_size(dst_bo)); if (max_size <= 0) { DBG(("%s: tiles cannot fit into aperture\n", __FUNCTION__)); return false; } if (max_size > sna->kgem.max_copy_tile_size) max_size = sna->kgem.max_copy_tile_size; pixman_region_init_rects(®ion, box, nbox); /* Use a small step to accommodate enlargement through tile alignment */ step = sna->render.max_3d_size; if (region.extents.x1 & (8*512 / bpp - 1) || region.extents.y1 & 63) step /= 2; while (step * step * 4 > max_size) step /= 2; if (sna->kgem.gen < 033) step /= 2; /* accommodate severe fence restrictions */ if (step == 0) { DBG(("%s: tiles cannot fit into aperture\n", __FUNCTION__)); return false; } DBG(("%s (alu=%d), tile.size=%d, box=%dx[(%d, %d), (%d, %d)])\n", __FUNCTION__, alu, step, nbox, region.extents.x1, region.extents.y1, region.extents.x2, region.extents.y2)); for (tile.extents.y1 = tile.extents.y2 = region.extents.y1; tile.extents.y2 < region.extents.y2; tile.extents.y1 = tile.extents.y2) { int y2 = tile.extents.y1 + step; if (y2 > region.extents.y2) y2 = region.extents.y2; tile.extents.y2 = y2; for (tile.extents.x1 = tile.extents.x2 = region.extents.x1; tile.extents.x2 < region.extents.x2; tile.extents.x1 = tile.extents.x2) { int w, h; int x2 = tile.extents.x1 + step; if (x2 > region.extents.x2) x2 = region.extents.x2; tile.extents.x2 = x2; tile.data = NULL; RegionNull(&this); RegionIntersect(&this, ®ion, &tile); if (RegionNil(&this)) continue; w = this.extents.x2 - this.extents.x1; h = this.extents.y2 - this.extents.y1; bo = kgem_create_2d(&sna->kgem, w, h, bpp, kgem_choose_tiling(&sna->kgem, I915_TILING_X, w, h, bpp), CREATE_TEMPORARY); if (bo) { int16_t dx = this.extents.x1; int16_t dy = this.extents.y1; assert(bo->pitch <= 8192); assert(bo->tiling != I915_TILING_Y); if (!sna_blt_copy_boxes(sna, GXcopy, src_bo, src_dx, src_dy, bo, -dx, -dy, bpp, REGION_RECTS(&this), REGION_NUM_RECTS(&this))) goto err; if (!sna_blt_copy_boxes__with_alpha(sna, alu, bo, -dx, -dy, dst_bo, dst_dx, dst_dy, bpp, alpha_fixup, REGION_RECTS(&this), REGION_NUM_RECTS(&this))) goto err; kgem_bo_destroy(&sna->kgem, bo); } RegionUninit(&this); } } ret = true; goto done; err: kgem_bo_destroy(&sna->kgem, bo); RegionUninit(&this); done: pixman_region_fini(®ion); return ret; }
bool sna_tiling_blt_copy_boxes(struct sna *sna, uint8_t alu, struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy, struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy, int bpp, const BoxRec *box, int nbox) { RegionRec region, tile, this; struct kgem_bo *bo; int step; bool ret = false; if (!kgem_bo_can_blt(&sna->kgem, src_bo) || !kgem_bo_can_blt(&sna->kgem, dst_bo)) { /* XXX */ DBG(("%s: tiling blt fail: src?=%d, dst?=%d\n", __FUNCTION__, kgem_bo_can_blt(&sna->kgem, src_bo), kgem_bo_can_blt(&sna->kgem, dst_bo))); return false; } pixman_region_init_rects(®ion, box, nbox); /* Use a small step to accommodate enlargement through tile alignment */ step = sna->render.max_3d_size; if (region.extents.x1 & (8*512 / bpp - 1) || region.extents.y1 & 63) step /= 2; while (step * step * 4 > sna->kgem.max_copy_tile_size) step /= 2; DBG(("%s (alu=%d), tile.size=%d, box=%dx[(%d, %d), (%d, %d)])\n", __FUNCTION__, alu, step, nbox, region.extents.x1, region.extents.y1, region.extents.x2, region.extents.y2)); for (tile.extents.y1 = tile.extents.y2 = region.extents.y1; tile.extents.y2 < region.extents.y2; tile.extents.y1 = tile.extents.y2) { tile.extents.y2 = tile.extents.y1 + step; if (tile.extents.y2 > region.extents.y2) tile.extents.y2 = region.extents.y2; for (tile.extents.x1 = tile.extents.x2 = region.extents.x1; tile.extents.x2 < region.extents.x2; tile.extents.x1 = tile.extents.x2) { int w, h; tile.extents.x2 = tile.extents.x1 + step; if (tile.extents.x2 > region.extents.x2) tile.extents.x2 = region.extents.x2; tile.data = NULL; RegionNull(&this); RegionIntersect(&this, ®ion, &tile); if (!RegionNotEmpty(&this)) continue; w = this.extents.x2 - this.extents.x1; h = this.extents.y2 - this.extents.y1; bo = kgem_create_2d(&sna->kgem, w, h, bpp, kgem_choose_tiling(&sna->kgem, I915_TILING_X, w, h, bpp), CREATE_TEMPORARY); if (bo) { int16_t dx = this.extents.x1; int16_t dy = this.extents.y1; assert(bo->pitch <= 8192); assert(bo->tiling != I915_TILING_Y); if (!sna_blt_copy_boxes(sna, alu, src_bo, src_dx, src_dy, bo, -dx, -dy, bpp, REGION_RECTS(&this), REGION_NUM_RECTS(&this))) goto err; if (!sna_blt_copy_boxes(sna, alu, bo, -dx, -dy, dst_bo, dst_dx, dst_dy, bpp, REGION_RECTS(&this), REGION_NUM_RECTS(&this))) goto err; kgem_bo_destroy(&sna->kgem, bo); } RegionUninit(&this); } } ret = true; goto done; err: kgem_bo_destroy(&sna->kgem, bo); RegionUninit(&this); done: pixman_region_fini(®ion); return ret; }