sna_blt.c revision 42542f5f
103b705cfSriastradh/* 203b705cfSriastradh * Based on code from intel_uxa.c and i830_xaa.c 303b705cfSriastradh * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. 403b705cfSriastradh * Copyright (c) 2005 Jesse Barnes <jbarnes@virtuousgeek.org> 503b705cfSriastradh * Copyright (c) 2009-2011 Intel Corporation 603b705cfSriastradh * 703b705cfSriastradh * Permission is hereby granted, free of charge, to any person obtaining a 803b705cfSriastradh * copy of this software and associated documentation files (the "Software"), 903b705cfSriastradh * to deal in the Software without restriction, including without limitation 1003b705cfSriastradh * the rights to use, copy, modify, merge, publish, distribute, sublicense, 1103b705cfSriastradh * and/or sell copies of the Software, and to permit persons to whom the 1203b705cfSriastradh * Software is furnished to do so, subject to the following conditions: 1303b705cfSriastradh * 1403b705cfSriastradh * The above copyright notice and this permission notice (including the next 1503b705cfSriastradh * paragraph) shall be included in all copies or substantial portions of the 1603b705cfSriastradh * Software. 1703b705cfSriastradh * 1803b705cfSriastradh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1903b705cfSriastradh * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2003b705cfSriastradh * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 2103b705cfSriastradh * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2203b705cfSriastradh * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2303b705cfSriastradh * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 2403b705cfSriastradh * SOFTWARE. 2503b705cfSriastradh * 2603b705cfSriastradh * Authors: 2703b705cfSriastradh * Chris Wilson <chris@chris-wilson.co.uk> 2803b705cfSriastradh * 2903b705cfSriastradh */ 3003b705cfSriastradh 3103b705cfSriastradh#ifdef HAVE_CONFIG_H 3203b705cfSriastradh#include "config.h" 3303b705cfSriastradh#endif 3403b705cfSriastradh 3503b705cfSriastradh#include "sna.h" 3603b705cfSriastradh#include "sna_render.h" 3703b705cfSriastradh#include "sna_render_inline.h" 3803b705cfSriastradh#include "sna_reg.h" 3903b705cfSriastradh#include "rop.h" 4003b705cfSriastradh 4103b705cfSriastradh#define NO_BLT_COMPOSITE 0 4203b705cfSriastradh#define NO_BLT_COPY 0 4303b705cfSriastradh#define NO_BLT_COPY_BOXES 0 4403b705cfSriastradh#define NO_BLT_FILL 0 4503b705cfSriastradh#define NO_BLT_FILL_BOXES 0 4603b705cfSriastradh 4742542f5fSchristos#ifndef PICT_TYPE_BGRA 4842542f5fSchristos#define PICT_TYPE_BGRA 8 4942542f5fSchristos#endif 5042542f5fSchristos 5103b705cfSriastradhstatic const uint8_t copy_ROP[] = { 5203b705cfSriastradh ROP_0, /* GXclear */ 5303b705cfSriastradh ROP_DSa, /* GXand */ 5403b705cfSriastradh ROP_SDna, /* GXandReverse */ 5503b705cfSriastradh ROP_S, /* GXcopy */ 5603b705cfSriastradh ROP_DSna, /* GXandInverted */ 5703b705cfSriastradh ROP_D, /* GXnoop */ 5803b705cfSriastradh ROP_DSx, /* GXxor */ 5903b705cfSriastradh ROP_DSo, /* GXor */ 6003b705cfSriastradh ROP_DSon, /* GXnor */ 6103b705cfSriastradh ROP_DSxn, /* GXequiv */ 6203b705cfSriastradh ROP_Dn, /* GXinvert */ 6303b705cfSriastradh ROP_SDno, /* GXorReverse */ 6403b705cfSriastradh ROP_Sn, /* GXcopyInverted */ 6503b705cfSriastradh ROP_DSno, /* GXorInverted */ 6603b705cfSriastradh ROP_DSan, /* GXnand */ 6703b705cfSriastradh ROP_1 /* GXset */ 6803b705cfSriastradh}; 6903b705cfSriastradh 7003b705cfSriastradhstatic const uint8_t fill_ROP[] = { 7103b705cfSriastradh ROP_0, 7203b705cfSriastradh ROP_DPa, 7303b705cfSriastradh ROP_PDna, 7403b705cfSriastradh ROP_P, 7503b705cfSriastradh ROP_DPna, 7603b705cfSriastradh ROP_D, 7703b705cfSriastradh ROP_DPx, 7803b705cfSriastradh ROP_DPo, 7903b705cfSriastradh ROP_DPon, 8003b705cfSriastradh ROP_PDxn, 8103b705cfSriastradh ROP_Dn, 8203b705cfSriastradh ROP_PDno, 8303b705cfSriastradh ROP_Pn, 8403b705cfSriastradh ROP_DPno, 8503b705cfSriastradh ROP_DPan, 8603b705cfSriastradh ROP_1 8703b705cfSriastradh}; 8803b705cfSriastradh 8903b705cfSriastradhstatic void nop_done(struct sna *sna, const struct sna_composite_op *op) 9003b705cfSriastradh{ 9103b705cfSriastradh assert(sna->kgem.nbatch <= KGEM_BATCH_SIZE(&sna->kgem)); 9242542f5fSchristos if (sna->kgem.nexec > 1 && __kgem_ring_empty(&sna->kgem)) { 9342542f5fSchristos DBG(("%s: flushing BLT operation on empty ring\n", __FUNCTION__)); 9403b705cfSriastradh _kgem_submit(&sna->kgem); 9542542f5fSchristos } 9603b705cfSriastradh (void)op; 9703b705cfSriastradh} 9803b705cfSriastradh 9903b705cfSriastradhstatic void gen6_blt_copy_done(struct sna *sna, const struct sna_composite_op *op) 10003b705cfSriastradh{ 10103b705cfSriastradh struct kgem *kgem = &sna->kgem; 10203b705cfSriastradh 10303b705cfSriastradh assert(kgem->nbatch <= KGEM_BATCH_SIZE(kgem)); 10403b705cfSriastradh if (kgem->nexec > 1 && __kgem_ring_empty(kgem)) { 10542542f5fSchristos DBG(("%s: flushing BLT operation on empty ring\n", __FUNCTION__)); 10603b705cfSriastradh _kgem_submit(kgem); 10703b705cfSriastradh return; 10803b705cfSriastradh } 10903b705cfSriastradh 11003b705cfSriastradh if (kgem_check_batch(kgem, 3)) { 11103b705cfSriastradh uint32_t *b = kgem->batch + kgem->nbatch; 11242542f5fSchristos assert(sna->kgem.mode == KGEM_BLT); 11303b705cfSriastradh b[0] = XY_SETUP_CLIP; 11403b705cfSriastradh b[1] = b[2] = 0; 11503b705cfSriastradh kgem->nbatch += 3; 11603b705cfSriastradh assert(kgem->nbatch < kgem->surface); 11703b705cfSriastradh } 11803b705cfSriastradh assert(sna->kgem.nbatch <= KGEM_BATCH_SIZE(&sna->kgem)); 11903b705cfSriastradh (void)op; 12003b705cfSriastradh} 12103b705cfSriastradh 12203b705cfSriastradhstatic bool sna_blt_fill_init(struct sna *sna, 12303b705cfSriastradh struct sna_blt_state *blt, 12403b705cfSriastradh struct kgem_bo *bo, 12503b705cfSriastradh int bpp, 12603b705cfSriastradh uint8_t alu, 12703b705cfSriastradh uint32_t pixel) 12803b705cfSriastradh{ 12903b705cfSriastradh struct kgem *kgem = &sna->kgem; 13003b705cfSriastradh 13103b705cfSriastradh assert(kgem_bo_can_blt (kgem, bo)); 13203b705cfSriastradh assert(bo->tiling != I915_TILING_Y); 13303b705cfSriastradh blt->bo[0] = bo; 13403b705cfSriastradh 13503b705cfSriastradh blt->br13 = bo->pitch; 13603b705cfSriastradh blt->cmd = XY_SCANLINE_BLT; 13703b705cfSriastradh if (kgem->gen >= 040 && bo->tiling) { 13803b705cfSriastradh blt->cmd |= BLT_DST_TILED; 13903b705cfSriastradh blt->br13 >>= 2; 14003b705cfSriastradh } 14103b705cfSriastradh assert(blt->br13 <= MAXSHORT); 14203b705cfSriastradh 14303b705cfSriastradh if (alu == GXclear) 14403b705cfSriastradh pixel = 0; 14503b705cfSriastradh else if (alu == GXcopy) { 14603b705cfSriastradh if (pixel == 0) 14703b705cfSriastradh alu = GXclear; 14803b705cfSriastradh else if (pixel == -1) 14903b705cfSriastradh alu = GXset; 15003b705cfSriastradh } 15103b705cfSriastradh 15203b705cfSriastradh blt->br13 |= 1<<31 | (fill_ROP[alu] << 16); 15303b705cfSriastradh switch (bpp) { 15403b705cfSriastradh default: assert(0); 15503b705cfSriastradh case 32: blt->br13 |= 1 << 25; /* RGB8888 */ 15603b705cfSriastradh case 16: blt->br13 |= 1 << 24; /* RGB565 */ 15703b705cfSriastradh case 8: break; 15803b705cfSriastradh } 15903b705cfSriastradh 16003b705cfSriastradh blt->pixel = pixel; 16103b705cfSriastradh blt->bpp = bpp; 16242542f5fSchristos blt->alu = alu; 16303b705cfSriastradh 16403b705cfSriastradh kgem_set_mode(kgem, KGEM_BLT, bo); 16542542f5fSchristos if (!kgem_check_batch(kgem, 14) || 16603b705cfSriastradh !kgem_check_bo_fenced(kgem, bo)) { 16703b705cfSriastradh kgem_submit(kgem); 16803b705cfSriastradh if (!kgem_check_bo_fenced(kgem, bo)) 16903b705cfSriastradh return false; 17003b705cfSriastradh _kgem_set_mode(kgem, KGEM_BLT); 17103b705cfSriastradh } 17203b705cfSriastradh 17303b705cfSriastradh if (sna->blt_state.fill_bo != bo->unique_id || 17403b705cfSriastradh sna->blt_state.fill_pixel != pixel || 17503b705cfSriastradh sna->blt_state.fill_alu != alu) 17603b705cfSriastradh { 17703b705cfSriastradh uint32_t *b; 17803b705cfSriastradh 17903b705cfSriastradh if (!kgem_check_reloc(kgem, 1)) { 18003b705cfSriastradh _kgem_submit(kgem); 18142542f5fSchristos if (!kgem_check_bo_fenced(kgem, bo)) 18242542f5fSchristos return false; 18303b705cfSriastradh _kgem_set_mode(kgem, KGEM_BLT); 18403b705cfSriastradh } 18503b705cfSriastradh 18642542f5fSchristos assert(sna->kgem.mode == KGEM_BLT); 18703b705cfSriastradh b = kgem->batch + kgem->nbatch; 18842542f5fSchristos if (sna->kgem.gen >= 0100) { 18942542f5fSchristos b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 8; 19042542f5fSchristos if (bpp == 32) 19142542f5fSchristos b[0] |= BLT_WRITE_ALPHA | BLT_WRITE_RGB; 19242542f5fSchristos if (bo->tiling) 19342542f5fSchristos b[0] |= BLT_DST_TILED; 19442542f5fSchristos b[1] = blt->br13; 19542542f5fSchristos b[2] = 0; 19642542f5fSchristos b[3] = 0; 19742542f5fSchristos *(uint64_t *)(b+4) = 19842542f5fSchristos kgem_add_reloc64(kgem, kgem->nbatch + 4, bo, 19942542f5fSchristos I915_GEM_DOMAIN_RENDER << 16 | 20042542f5fSchristos I915_GEM_DOMAIN_RENDER | 20142542f5fSchristos KGEM_RELOC_FENCED, 20242542f5fSchristos 0); 20342542f5fSchristos b[6] = pixel; 20442542f5fSchristos b[7] = pixel; 20542542f5fSchristos b[8] = 0; 20642542f5fSchristos b[9] = 0; 20742542f5fSchristos kgem->nbatch += 10; 20842542f5fSchristos } else { 20942542f5fSchristos b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 7; 21042542f5fSchristos if (bpp == 32) 21142542f5fSchristos b[0] |= BLT_WRITE_ALPHA | BLT_WRITE_RGB; 21242542f5fSchristos if (bo->tiling && kgem->gen >= 040) 21342542f5fSchristos b[0] |= BLT_DST_TILED; 21442542f5fSchristos b[1] = blt->br13; 21542542f5fSchristos b[2] = 0; 21642542f5fSchristos b[3] = 0; 21742542f5fSchristos b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4, bo, 21842542f5fSchristos I915_GEM_DOMAIN_RENDER << 16 | 21942542f5fSchristos I915_GEM_DOMAIN_RENDER | 22042542f5fSchristos KGEM_RELOC_FENCED, 22142542f5fSchristos 0); 22242542f5fSchristos b[5] = pixel; 22342542f5fSchristos b[6] = pixel; 22442542f5fSchristos b[7] = 0; 22542542f5fSchristos b[8] = 0; 22642542f5fSchristos kgem->nbatch += 9; 22742542f5fSchristos } 22803b705cfSriastradh assert(kgem->nbatch < kgem->surface); 22903b705cfSriastradh 23003b705cfSriastradh sna->blt_state.fill_bo = bo->unique_id; 23103b705cfSriastradh sna->blt_state.fill_pixel = pixel; 23203b705cfSriastradh sna->blt_state.fill_alu = alu; 23303b705cfSriastradh } 23403b705cfSriastradh 23503b705cfSriastradh return true; 23603b705cfSriastradh} 23703b705cfSriastradh 23803b705cfSriastradhnoinline static void sna_blt_fill_begin(struct sna *sna, 23903b705cfSriastradh const struct sna_blt_state *blt) 24003b705cfSriastradh{ 24103b705cfSriastradh struct kgem *kgem = &sna->kgem; 24203b705cfSriastradh uint32_t *b; 24303b705cfSriastradh 24442542f5fSchristos if (kgem->nreloc) { 24542542f5fSchristos _kgem_submit(kgem); 24642542f5fSchristos _kgem_set_mode(kgem, KGEM_BLT); 24742542f5fSchristos assert(kgem->nbatch == 0); 24842542f5fSchristos } 24903b705cfSriastradh 25042542f5fSchristos assert(kgem->mode == KGEM_BLT); 25142542f5fSchristos b = kgem->batch + kgem->nbatch; 25242542f5fSchristos if (sna->kgem.gen >= 0100) { 25342542f5fSchristos b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 8; 25442542f5fSchristos if (blt->bpp == 32) 25542542f5fSchristos b[0] |= BLT_WRITE_ALPHA | BLT_WRITE_RGB; 25642542f5fSchristos if (blt->bo[0]->tiling) 25742542f5fSchristos b[0] |= BLT_DST_TILED; 25842542f5fSchristos b[1] = blt->br13; 25942542f5fSchristos b[2] = 0; 26042542f5fSchristos b[3] = 0; 26142542f5fSchristos *(uint32_t *)(b+4) = 26242542f5fSchristos kgem_add_reloc64(kgem, kgem->nbatch + 4, blt->bo[0], 26342542f5fSchristos I915_GEM_DOMAIN_RENDER << 16 | 26442542f5fSchristos I915_GEM_DOMAIN_RENDER | 26542542f5fSchristos KGEM_RELOC_FENCED, 26642542f5fSchristos 0); 26742542f5fSchristos b[6] = blt->pixel; 26842542f5fSchristos b[7] = blt->pixel; 26942542f5fSchristos b[8] = 0; 27042542f5fSchristos b[9] = 0; 27142542f5fSchristos kgem->nbatch += 10; 27242542f5fSchristos } else { 27342542f5fSchristos b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 7; 27442542f5fSchristos if (blt->bpp == 32) 27542542f5fSchristos b[0] |= BLT_WRITE_ALPHA | BLT_WRITE_RGB; 27642542f5fSchristos if (blt->bo[0]->tiling && kgem->gen >= 040) 27742542f5fSchristos b[0] |= BLT_DST_TILED; 27842542f5fSchristos b[1] = blt->br13; 27942542f5fSchristos b[2] = 0; 28042542f5fSchristos b[3] = 0; 28142542f5fSchristos b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4, blt->bo[0], 28242542f5fSchristos I915_GEM_DOMAIN_RENDER << 16 | 28342542f5fSchristos I915_GEM_DOMAIN_RENDER | 28442542f5fSchristos KGEM_RELOC_FENCED, 28542542f5fSchristos 0); 28642542f5fSchristos b[5] = blt->pixel; 28742542f5fSchristos b[6] = blt->pixel; 28842542f5fSchristos b[7] = 0; 28942542f5fSchristos b[8] = 0; 29042542f5fSchristos kgem->nbatch += 9; 29142542f5fSchristos } 29203b705cfSriastradh} 29303b705cfSriastradh 29403b705cfSriastradhinline static void sna_blt_fill_one(struct sna *sna, 29503b705cfSriastradh const struct sna_blt_state *blt, 29603b705cfSriastradh int16_t x, int16_t y, 29703b705cfSriastradh int16_t width, int16_t height) 29803b705cfSriastradh{ 29903b705cfSriastradh struct kgem *kgem = &sna->kgem; 30003b705cfSriastradh uint32_t *b; 30103b705cfSriastradh 30203b705cfSriastradh DBG(("%s: (%d, %d) x (%d, %d): %08x\n", 30303b705cfSriastradh __FUNCTION__, x, y, width, height, blt->pixel)); 30403b705cfSriastradh 30503b705cfSriastradh assert(x >= 0); 30603b705cfSriastradh assert(y >= 0); 30703b705cfSriastradh assert((y+height) * blt->bo[0]->pitch <= kgem_bo_size(blt->bo[0])); 30803b705cfSriastradh 30903b705cfSriastradh if (!kgem_check_batch(kgem, 3)) 31003b705cfSriastradh sna_blt_fill_begin(sna, blt); 31103b705cfSriastradh 31242542f5fSchristos assert(sna->kgem.mode == KGEM_BLT); 31303b705cfSriastradh b = kgem->batch + kgem->nbatch; 31403b705cfSriastradh kgem->nbatch += 3; 31503b705cfSriastradh assert(kgem->nbatch < kgem->surface); 31603b705cfSriastradh 31703b705cfSriastradh b[0] = blt->cmd; 31803b705cfSriastradh b[1] = y << 16 | x; 31903b705cfSriastradh b[2] = b[1] + (height << 16 | width); 32003b705cfSriastradh} 32103b705cfSriastradh 32203b705cfSriastradhstatic bool sna_blt_copy_init(struct sna *sna, 32303b705cfSriastradh struct sna_blt_state *blt, 32403b705cfSriastradh struct kgem_bo *src, 32503b705cfSriastradh struct kgem_bo *dst, 32603b705cfSriastradh int bpp, 32703b705cfSriastradh uint8_t alu) 32803b705cfSriastradh{ 32903b705cfSriastradh struct kgem *kgem = &sna->kgem; 33003b705cfSriastradh 33103b705cfSriastradh assert(kgem_bo_can_blt (kgem, src)); 33203b705cfSriastradh assert(kgem_bo_can_blt (kgem, dst)); 33303b705cfSriastradh 33403b705cfSriastradh blt->bo[0] = src; 33503b705cfSriastradh blt->bo[1] = dst; 33603b705cfSriastradh 33742542f5fSchristos blt->cmd = XY_SRC_COPY_BLT_CMD | (kgem->gen >= 0100 ? 8 : 6); 33803b705cfSriastradh if (bpp == 32) 33903b705cfSriastradh blt->cmd |= BLT_WRITE_ALPHA | BLT_WRITE_RGB; 34003b705cfSriastradh 34103b705cfSriastradh blt->pitch[0] = src->pitch; 34203b705cfSriastradh if (kgem->gen >= 040 && src->tiling) { 34303b705cfSriastradh blt->cmd |= BLT_SRC_TILED; 34403b705cfSriastradh blt->pitch[0] >>= 2; 34503b705cfSriastradh } 34603b705cfSriastradh assert(blt->pitch[0] <= MAXSHORT); 34703b705cfSriastradh 34803b705cfSriastradh blt->pitch[1] = dst->pitch; 34903b705cfSriastradh if (kgem->gen >= 040 && dst->tiling) { 35003b705cfSriastradh blt->cmd |= BLT_DST_TILED; 35103b705cfSriastradh blt->pitch[1] >>= 2; 35203b705cfSriastradh } 35303b705cfSriastradh assert(blt->pitch[1] <= MAXSHORT); 35403b705cfSriastradh 35503b705cfSriastradh blt->overwrites = alu == GXcopy || alu == GXclear || alu == GXset; 35603b705cfSriastradh blt->br13 = (copy_ROP[alu] << 16) | blt->pitch[1]; 35703b705cfSriastradh switch (bpp) { 35803b705cfSriastradh default: assert(0); 35903b705cfSriastradh case 32: blt->br13 |= 1 << 25; /* RGB8888 */ 36003b705cfSriastradh case 16: blt->br13 |= 1 << 24; /* RGB565 */ 36103b705cfSriastradh case 8: break; 36203b705cfSriastradh } 36303b705cfSriastradh 36403b705cfSriastradh kgem_set_mode(kgem, KGEM_BLT, dst); 36503b705cfSriastradh if (!kgem_check_many_bo_fenced(kgem, src, dst, NULL)) { 36603b705cfSriastradh kgem_submit(kgem); 36703b705cfSriastradh if (!kgem_check_many_bo_fenced(kgem, src, dst, NULL)) 36803b705cfSriastradh return false; 36903b705cfSriastradh _kgem_set_mode(kgem, KGEM_BLT); 37003b705cfSriastradh } 37103b705cfSriastradh 37203b705cfSriastradh sna->blt_state.fill_bo = 0; 37303b705cfSriastradh return true; 37403b705cfSriastradh} 37503b705cfSriastradh 37603b705cfSriastradhstatic bool sna_blt_alpha_fixup_init(struct sna *sna, 37703b705cfSriastradh struct sna_blt_state *blt, 37803b705cfSriastradh struct kgem_bo *src, 37903b705cfSriastradh struct kgem_bo *dst, 38003b705cfSriastradh int bpp, uint32_t alpha) 38103b705cfSriastradh{ 38203b705cfSriastradh struct kgem *kgem = &sna->kgem; 38303b705cfSriastradh 38442542f5fSchristos DBG(("%s: dst handle=%d, src handle=%d, bpp=%d, fixup=%08x\n", 38542542f5fSchristos __FUNCTION__, dst->handle, src->handle, bpp, alpha)); 38642542f5fSchristos assert(kgem_bo_can_blt(kgem, src)); 38742542f5fSchristos assert(kgem_bo_can_blt(kgem, dst)); 38803b705cfSriastradh 38903b705cfSriastradh blt->bo[0] = src; 39003b705cfSriastradh blt->bo[1] = dst; 39103b705cfSriastradh 39242542f5fSchristos blt->cmd = XY_FULL_MONO_PATTERN_BLT | (kgem->gen >= 0100 ? 12 : 10); 39303b705cfSriastradh blt->pitch[0] = src->pitch; 39403b705cfSriastradh if (kgem->gen >= 040 && src->tiling) { 39503b705cfSriastradh blt->cmd |= BLT_SRC_TILED; 39603b705cfSriastradh blt->pitch[0] >>= 2; 39703b705cfSriastradh } 39803b705cfSriastradh assert(blt->pitch[0] <= MAXSHORT); 39903b705cfSriastradh 40003b705cfSriastradh blt->pitch[1] = dst->pitch; 40103b705cfSriastradh if (kgem->gen >= 040 && dst->tiling) { 40203b705cfSriastradh blt->cmd |= BLT_DST_TILED; 40303b705cfSriastradh blt->pitch[1] >>= 2; 40403b705cfSriastradh } 40503b705cfSriastradh assert(blt->pitch[1] <= MAXSHORT); 40603b705cfSriastradh 40703b705cfSriastradh blt->overwrites = 1; 40803b705cfSriastradh blt->br13 = (0xfc << 16) | blt->pitch[1]; 40903b705cfSriastradh switch (bpp) { 41003b705cfSriastradh default: assert(0); 41103b705cfSriastradh case 32: blt->cmd |= BLT_WRITE_ALPHA | BLT_WRITE_RGB; 41203b705cfSriastradh blt->br13 |= 1 << 25; /* RGB8888 */ 41303b705cfSriastradh case 16: blt->br13 |= 1 << 24; /* RGB565 */ 41403b705cfSriastradh case 8: break; 41503b705cfSriastradh } 41603b705cfSriastradh blt->pixel = alpha; 41703b705cfSriastradh 41803b705cfSriastradh kgem_set_mode(kgem, KGEM_BLT, dst); 41903b705cfSriastradh if (!kgem_check_many_bo_fenced(kgem, src, dst, NULL)) { 42003b705cfSriastradh kgem_submit(kgem); 42103b705cfSriastradh if (!kgem_check_many_bo_fenced(kgem, src, dst, NULL)) 42203b705cfSriastradh return false; 42303b705cfSriastradh _kgem_set_mode(kgem, KGEM_BLT); 42403b705cfSriastradh } 42503b705cfSriastradh 42603b705cfSriastradh sna->blt_state.fill_bo = 0; 42703b705cfSriastradh return true; 42803b705cfSriastradh} 42903b705cfSriastradh 43003b705cfSriastradhstatic void sna_blt_alpha_fixup_one(struct sna *sna, 43103b705cfSriastradh const struct sna_blt_state *blt, 43203b705cfSriastradh int src_x, int src_y, 43303b705cfSriastradh int width, int height, 43403b705cfSriastradh int dst_x, int dst_y) 43503b705cfSriastradh{ 43603b705cfSriastradh struct kgem *kgem = &sna->kgem; 43703b705cfSriastradh uint32_t *b; 43803b705cfSriastradh 43903b705cfSriastradh DBG(("%s: (%d, %d) -> (%d, %d) x (%d, %d)\n", 44003b705cfSriastradh __FUNCTION__, src_x, src_y, dst_x, dst_y, width, height)); 44103b705cfSriastradh 44203b705cfSriastradh assert(src_x >= 0); 44303b705cfSriastradh assert(src_y >= 0); 44403b705cfSriastradh assert((src_y + height) * blt->bo[0]->pitch <= kgem_bo_size(blt->bo[0])); 44503b705cfSriastradh assert(dst_x >= 0); 44603b705cfSriastradh assert(dst_y >= 0); 44703b705cfSriastradh assert((dst_y + height) * blt->bo[1]->pitch <= kgem_bo_size(blt->bo[1])); 44803b705cfSriastradh assert(width > 0); 44903b705cfSriastradh assert(height > 0); 45003b705cfSriastradh 45142542f5fSchristos if (!kgem_check_batch(kgem, 14) || 45203b705cfSriastradh !kgem_check_reloc(kgem, 2)) { 45303b705cfSriastradh _kgem_submit(kgem); 45403b705cfSriastradh _kgem_set_mode(kgem, KGEM_BLT); 45503b705cfSriastradh } 45603b705cfSriastradh 45742542f5fSchristos assert(sna->kgem.mode == KGEM_BLT); 45803b705cfSriastradh b = kgem->batch + kgem->nbatch; 45903b705cfSriastradh b[0] = blt->cmd; 46003b705cfSriastradh b[1] = blt->br13; 46103b705cfSriastradh b[2] = (dst_y << 16) | dst_x; 46203b705cfSriastradh b[3] = ((dst_y + height) << 16) | (dst_x + width); 46342542f5fSchristos if (sna->kgem.gen >= 0100) { 46442542f5fSchristos *(uint64_t *)(b+4) = 46542542f5fSchristos kgem_add_reloc64(kgem, kgem->nbatch + 4, blt->bo[1], 46642542f5fSchristos I915_GEM_DOMAIN_RENDER << 16 | 46742542f5fSchristos I915_GEM_DOMAIN_RENDER | 46842542f5fSchristos KGEM_RELOC_FENCED, 46942542f5fSchristos 0); 47042542f5fSchristos b[6] = blt->pitch[0]; 47142542f5fSchristos b[7] = (src_y << 16) | src_x; 47242542f5fSchristos *(uint64_t *)(b+8) = 47342542f5fSchristos kgem_add_reloc64(kgem, kgem->nbatch + 8, blt->bo[0], 47442542f5fSchristos I915_GEM_DOMAIN_RENDER << 16 | 47542542f5fSchristos KGEM_RELOC_FENCED, 47642542f5fSchristos 0); 47742542f5fSchristos b[10] = blt->pixel; 47842542f5fSchristos b[11] = blt->pixel; 47942542f5fSchristos b[12] = 0; 48042542f5fSchristos b[13] = 0; 48142542f5fSchristos kgem->nbatch += 14; 48242542f5fSchristos } else { 48342542f5fSchristos b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4, blt->bo[1], 48442542f5fSchristos I915_GEM_DOMAIN_RENDER << 16 | 48542542f5fSchristos I915_GEM_DOMAIN_RENDER | 48642542f5fSchristos KGEM_RELOC_FENCED, 48742542f5fSchristos 0); 48842542f5fSchristos b[5] = blt->pitch[0]; 48942542f5fSchristos b[6] = (src_y << 16) | src_x; 49042542f5fSchristos b[7] = kgem_add_reloc(kgem, kgem->nbatch + 7, blt->bo[0], 49142542f5fSchristos I915_GEM_DOMAIN_RENDER << 16 | 49242542f5fSchristos KGEM_RELOC_FENCED, 49342542f5fSchristos 0); 49442542f5fSchristos b[8] = blt->pixel; 49542542f5fSchristos b[9] = blt->pixel; 49642542f5fSchristos b[10] = 0; 49742542f5fSchristos b[11] = 0; 49842542f5fSchristos kgem->nbatch += 12; 49942542f5fSchristos } 50003b705cfSriastradh assert(kgem->nbatch < kgem->surface); 50103b705cfSriastradh} 50203b705cfSriastradh 50303b705cfSriastradhstatic void sna_blt_copy_one(struct sna *sna, 50403b705cfSriastradh const struct sna_blt_state *blt, 50503b705cfSriastradh int src_x, int src_y, 50603b705cfSriastradh int width, int height, 50703b705cfSriastradh int dst_x, int dst_y) 50803b705cfSriastradh{ 50903b705cfSriastradh struct kgem *kgem = &sna->kgem; 51003b705cfSriastradh uint32_t *b; 51103b705cfSriastradh 51203b705cfSriastradh DBG(("%s: (%d, %d) -> (%d, %d) x (%d, %d)\n", 51303b705cfSriastradh __FUNCTION__, src_x, src_y, dst_x, dst_y, width, height)); 51403b705cfSriastradh 51503b705cfSriastradh assert(src_x >= 0); 51603b705cfSriastradh assert(src_y >= 0); 51703b705cfSriastradh assert((src_y + height) * blt->bo[0]->pitch <= kgem_bo_size(blt->bo[0])); 51803b705cfSriastradh assert(dst_x >= 0); 51903b705cfSriastradh assert(dst_y >= 0); 52003b705cfSriastradh assert((dst_y + height) * blt->bo[1]->pitch <= kgem_bo_size(blt->bo[1])); 52103b705cfSriastradh assert(width > 0); 52203b705cfSriastradh assert(height > 0); 52303b705cfSriastradh 52403b705cfSriastradh /* Compare against a previous fill */ 52542542f5fSchristos if (blt->overwrites && 52603b705cfSriastradh kgem->reloc[kgem->nreloc-1].target_handle == blt->bo[1]->target_handle) { 52742542f5fSchristos if (sna->kgem.gen >= 0100) { 52842542f5fSchristos if (kgem->nbatch >= 7 && 52942542f5fSchristos kgem->batch[kgem->nbatch-7] == (XY_COLOR_BLT | (blt->cmd & (BLT_DST_TILED | BLT_WRITE_ALPHA | BLT_WRITE_RGB)) | 5) && 53042542f5fSchristos kgem->batch[kgem->nbatch-5] == ((uint32_t)dst_y << 16 | (uint16_t)dst_x) && 53142542f5fSchristos kgem->batch[kgem->nbatch-4] == ((uint32_t)(dst_y+height) << 16 | (uint16_t)(dst_x+width))) { 53242542f5fSchristos DBG(("%s: replacing last fill\n", __FUNCTION__)); 53342542f5fSchristos if (kgem_check_batch(kgem, 3)) { 53442542f5fSchristos assert(kgem->mode == KGEM_BLT); 53542542f5fSchristos b = kgem->batch + kgem->nbatch - 7; 53642542f5fSchristos b[0] = blt->cmd; 53742542f5fSchristos b[1] = blt->br13; 53842542f5fSchristos b[6] = (src_y << 16) | src_x; 53942542f5fSchristos b[7] = blt->pitch[0]; 54042542f5fSchristos *(uint64_t *)(b+8) = 54142542f5fSchristos kgem_add_reloc64(kgem, kgem->nbatch + 8 - 7, blt->bo[0], 54242542f5fSchristos I915_GEM_DOMAIN_RENDER << 16 | 54342542f5fSchristos KGEM_RELOC_FENCED, 54442542f5fSchristos 0); 54542542f5fSchristos kgem->nbatch += 3; 54642542f5fSchristos assert(kgem->nbatch < kgem->surface); 54742542f5fSchristos return; 54842542f5fSchristos } 54942542f5fSchristos kgem->nbatch -= 7; 55042542f5fSchristos kgem->nreloc--; 55142542f5fSchristos } 55242542f5fSchristos } else { 55342542f5fSchristos if (kgem->nbatch >= 6 && 55442542f5fSchristos kgem->batch[kgem->nbatch-6] == (XY_COLOR_BLT | (blt->cmd & (BLT_DST_TILED | BLT_WRITE_ALPHA | BLT_WRITE_RGB)) | 4) && 55542542f5fSchristos kgem->batch[kgem->nbatch-4] == ((uint32_t)dst_y << 16 | (uint16_t)dst_x) && 55642542f5fSchristos kgem->batch[kgem->nbatch-3] == ((uint32_t)(dst_y+height) << 16 | (uint16_t)(dst_x+width))) { 55742542f5fSchristos DBG(("%s: replacing last fill\n", __FUNCTION__)); 55842542f5fSchristos if (kgem_check_batch(kgem, 8-6)) { 55942542f5fSchristos assert(kgem->mode == KGEM_BLT); 56042542f5fSchristos b = kgem->batch + kgem->nbatch - 6; 56142542f5fSchristos b[0] = blt->cmd; 56242542f5fSchristos b[1] = blt->br13; 56342542f5fSchristos b[5] = (src_y << 16) | src_x; 56442542f5fSchristos b[6] = blt->pitch[0]; 56542542f5fSchristos b[7] = kgem_add_reloc(kgem, kgem->nbatch + 7 - 6, blt->bo[0], 56642542f5fSchristos I915_GEM_DOMAIN_RENDER << 16 | 56742542f5fSchristos KGEM_RELOC_FENCED, 56842542f5fSchristos 0); 56942542f5fSchristos kgem->nbatch += 8 - 6; 57042542f5fSchristos assert(kgem->nbatch < kgem->surface); 57142542f5fSchristos return; 57242542f5fSchristos } 57342542f5fSchristos kgem->nbatch -= 6; 57442542f5fSchristos kgem->nreloc--; 57542542f5fSchristos } 57603b705cfSriastradh } 57703b705cfSriastradh } 57803b705cfSriastradh 57942542f5fSchristos if (!kgem_check_batch(kgem, 10) || 58003b705cfSriastradh !kgem_check_reloc(kgem, 2)) { 58103b705cfSriastradh _kgem_submit(kgem); 58203b705cfSriastradh _kgem_set_mode(kgem, KGEM_BLT); 58303b705cfSriastradh } 58403b705cfSriastradh 58542542f5fSchristos assert(sna->kgem.mode == KGEM_BLT); 58603b705cfSriastradh b = kgem->batch + kgem->nbatch; 58703b705cfSriastradh b[0] = blt->cmd; 58803b705cfSriastradh b[1] = blt->br13; 58903b705cfSriastradh b[2] = (dst_y << 16) | dst_x; 59003b705cfSriastradh b[3] = ((dst_y + height) << 16) | (dst_x + width); 59142542f5fSchristos if (kgem->gen >= 0100) { 59242542f5fSchristos *(uint64_t *)(b+4) = 59342542f5fSchristos kgem_add_reloc64(kgem, kgem->nbatch + 4, blt->bo[1], 59442542f5fSchristos I915_GEM_DOMAIN_RENDER << 16 | 59542542f5fSchristos I915_GEM_DOMAIN_RENDER | 59642542f5fSchristos KGEM_RELOC_FENCED, 59742542f5fSchristos 0); 59842542f5fSchristos b[6] = (src_y << 16) | src_x; 59942542f5fSchristos b[7] = blt->pitch[0]; 60042542f5fSchristos *(uint64_t *)(b+8) = 60142542f5fSchristos kgem_add_reloc64(kgem, kgem->nbatch + 8, blt->bo[0], 60242542f5fSchristos I915_GEM_DOMAIN_RENDER << 16 | 60342542f5fSchristos KGEM_RELOC_FENCED, 60442542f5fSchristos 0); 60542542f5fSchristos kgem->nbatch += 10; 60642542f5fSchristos } else { 60742542f5fSchristos b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4, blt->bo[1], 60842542f5fSchristos I915_GEM_DOMAIN_RENDER << 16 | 60942542f5fSchristos I915_GEM_DOMAIN_RENDER | 61042542f5fSchristos KGEM_RELOC_FENCED, 61142542f5fSchristos 0); 61242542f5fSchristos b[5] = (src_y << 16) | src_x; 61342542f5fSchristos b[6] = blt->pitch[0]; 61442542f5fSchristos b[7] = kgem_add_reloc(kgem, kgem->nbatch + 7, blt->bo[0], 61542542f5fSchristos I915_GEM_DOMAIN_RENDER << 16 | 61642542f5fSchristos KGEM_RELOC_FENCED, 61742542f5fSchristos 0); 61842542f5fSchristos kgem->nbatch += 8; 61942542f5fSchristos } 62003b705cfSriastradh assert(kgem->nbatch < kgem->surface); 62103b705cfSriastradh} 62203b705cfSriastradh 62303b705cfSriastradhbool 62403b705cfSriastradhsna_get_rgba_from_pixel(uint32_t pixel, 62503b705cfSriastradh uint16_t *red, 62603b705cfSriastradh uint16_t *green, 62703b705cfSriastradh uint16_t *blue, 62803b705cfSriastradh uint16_t *alpha, 62903b705cfSriastradh uint32_t format) 63003b705cfSriastradh{ 63103b705cfSriastradh int rbits, bbits, gbits, abits; 63203b705cfSriastradh int rshift, bshift, gshift, ashift; 63303b705cfSriastradh 63403b705cfSriastradh rbits = PICT_FORMAT_R(format); 63503b705cfSriastradh gbits = PICT_FORMAT_G(format); 63603b705cfSriastradh bbits = PICT_FORMAT_B(format); 63703b705cfSriastradh abits = PICT_FORMAT_A(format); 63803b705cfSriastradh 63903b705cfSriastradh if (PICT_FORMAT_TYPE(format) == PICT_TYPE_A) { 64003b705cfSriastradh rshift = gshift = bshift = ashift = 0; 64103b705cfSriastradh } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) { 64203b705cfSriastradh bshift = 0; 64303b705cfSriastradh gshift = bbits; 64403b705cfSriastradh rshift = gshift + gbits; 64503b705cfSriastradh ashift = rshift + rbits; 64603b705cfSriastradh } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ABGR) { 64703b705cfSriastradh rshift = 0; 64803b705cfSriastradh gshift = rbits; 64903b705cfSriastradh bshift = gshift + gbits; 65003b705cfSriastradh ashift = bshift + bbits; 65103b705cfSriastradh } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_BGRA) { 65203b705cfSriastradh ashift = 0; 65303b705cfSriastradh rshift = abits; 65403b705cfSriastradh if (abits == 0) 65503b705cfSriastradh rshift = PICT_FORMAT_BPP(format) - (rbits+gbits+bbits); 65603b705cfSriastradh gshift = rshift + rbits; 65703b705cfSriastradh bshift = gshift + gbits; 65803b705cfSriastradh } else { 65903b705cfSriastradh return false; 66003b705cfSriastradh } 66103b705cfSriastradh 66203b705cfSriastradh if (rbits) { 66303b705cfSriastradh *red = ((pixel >> rshift) & ((1 << rbits) - 1)) << (16 - rbits); 66403b705cfSriastradh while (rbits < 16) { 66503b705cfSriastradh *red |= *red >> rbits; 66603b705cfSriastradh rbits <<= 1; 66703b705cfSriastradh } 66803b705cfSriastradh } else 66903b705cfSriastradh *red = 0; 67003b705cfSriastradh 67103b705cfSriastradh if (gbits) { 67203b705cfSriastradh *green = ((pixel >> gshift) & ((1 << gbits) - 1)) << (16 - gbits); 67303b705cfSriastradh while (gbits < 16) { 67403b705cfSriastradh *green |= *green >> gbits; 67503b705cfSriastradh gbits <<= 1; 67603b705cfSriastradh } 67703b705cfSriastradh } else 67803b705cfSriastradh *green = 0; 67903b705cfSriastradh 68003b705cfSriastradh if (bbits) { 68103b705cfSriastradh *blue = ((pixel >> bshift) & ((1 << bbits) - 1)) << (16 - bbits); 68203b705cfSriastradh while (bbits < 16) { 68303b705cfSriastradh *blue |= *blue >> bbits; 68403b705cfSriastradh bbits <<= 1; 68503b705cfSriastradh } 68603b705cfSriastradh } else 68703b705cfSriastradh *blue = 0; 68803b705cfSriastradh 68903b705cfSriastradh if (abits) { 69003b705cfSriastradh *alpha = ((pixel >> ashift) & ((1 << abits) - 1)) << (16 - abits); 69103b705cfSriastradh while (abits < 16) { 69203b705cfSriastradh *alpha |= *alpha >> abits; 69303b705cfSriastradh abits <<= 1; 69403b705cfSriastradh } 69503b705cfSriastradh } else 69603b705cfSriastradh *alpha = 0xffff; 69703b705cfSriastradh 69803b705cfSriastradh return true; 69903b705cfSriastradh} 70003b705cfSriastradh 70103b705cfSriastradhbool 70203b705cfSriastradh_sna_get_pixel_from_rgba(uint32_t * pixel, 70303b705cfSriastradh uint16_t red, 70403b705cfSriastradh uint16_t green, 70503b705cfSriastradh uint16_t blue, 70603b705cfSriastradh uint16_t alpha, 70703b705cfSriastradh uint32_t format) 70803b705cfSriastradh{ 70903b705cfSriastradh int rbits, bbits, gbits, abits; 71003b705cfSriastradh int rshift, bshift, gshift, ashift; 71103b705cfSriastradh 71203b705cfSriastradh rbits = PICT_FORMAT_R(format); 71303b705cfSriastradh gbits = PICT_FORMAT_G(format); 71403b705cfSriastradh bbits = PICT_FORMAT_B(format); 71503b705cfSriastradh abits = PICT_FORMAT_A(format); 71603b705cfSriastradh if (abits == 0) 71703b705cfSriastradh abits = PICT_FORMAT_BPP(format) - (rbits+gbits+bbits); 71803b705cfSriastradh 71903b705cfSriastradh if (PICT_FORMAT_TYPE(format) == PICT_TYPE_A) { 72003b705cfSriastradh *pixel = alpha >> (16 - abits); 72103b705cfSriastradh return true; 72203b705cfSriastradh } 72303b705cfSriastradh 72403b705cfSriastradh if (!PICT_FORMAT_COLOR(format)) 72503b705cfSriastradh return false; 72603b705cfSriastradh 72703b705cfSriastradh if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) { 72803b705cfSriastradh bshift = 0; 72903b705cfSriastradh gshift = bbits; 73003b705cfSriastradh rshift = gshift + gbits; 73103b705cfSriastradh ashift = rshift + rbits; 73203b705cfSriastradh } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ABGR) { 73303b705cfSriastradh rshift = 0; 73403b705cfSriastradh gshift = rbits; 73503b705cfSriastradh bshift = gshift + gbits; 73603b705cfSriastradh ashift = bshift + bbits; 73703b705cfSriastradh } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_BGRA) { 73803b705cfSriastradh ashift = 0; 73903b705cfSriastradh rshift = abits; 74003b705cfSriastradh gshift = rshift + rbits; 74103b705cfSriastradh bshift = gshift + gbits; 74203b705cfSriastradh } else 74303b705cfSriastradh return false; 74403b705cfSriastradh 74503b705cfSriastradh *pixel = 0; 74603b705cfSriastradh *pixel |= (blue >> (16 - bbits)) << bshift; 74703b705cfSriastradh *pixel |= (green >> (16 - gbits)) << gshift; 74803b705cfSriastradh *pixel |= (red >> (16 - rbits)) << rshift; 74903b705cfSriastradh *pixel |= (alpha >> (16 - abits)) << ashift; 75003b705cfSriastradh 75103b705cfSriastradh return true; 75203b705cfSriastradh} 75303b705cfSriastradh 75403b705cfSriastradhuint32_t 75503b705cfSriastradhsna_rgba_for_color(uint32_t color, int depth) 75603b705cfSriastradh{ 75703b705cfSriastradh return color_convert(color, sna_format_for_depth(depth), PICT_a8r8g8b8); 75803b705cfSriastradh} 75903b705cfSriastradh 76003b705cfSriastradhuint32_t 76103b705cfSriastradhsna_rgba_to_color(uint32_t rgba, uint32_t format) 76203b705cfSriastradh{ 76303b705cfSriastradh return color_convert(rgba, PICT_a8r8g8b8, format); 76403b705cfSriastradh} 76503b705cfSriastradh 76603b705cfSriastradhstatic uint32_t 76703b705cfSriastradhget_pixel(PicturePtr picture) 76803b705cfSriastradh{ 76903b705cfSriastradh PixmapPtr pixmap = get_drawable_pixmap(picture->pDrawable); 77003b705cfSriastradh 77103b705cfSriastradh DBG(("%s: %p\n", __FUNCTION__, pixmap)); 77203b705cfSriastradh 77303b705cfSriastradh if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ)) 77403b705cfSriastradh return 0; 77503b705cfSriastradh 77603b705cfSriastradh switch (pixmap->drawable.bitsPerPixel) { 77703b705cfSriastradh case 32: return *(uint32_t *)pixmap->devPrivate.ptr; 77803b705cfSriastradh case 16: return *(uint16_t *)pixmap->devPrivate.ptr; 77903b705cfSriastradh default: return *(uint8_t *)pixmap->devPrivate.ptr; 78003b705cfSriastradh } 78103b705cfSriastradh} 78203b705cfSriastradh 78303b705cfSriastradhstatic uint32_t 78403b705cfSriastradhget_solid_color(PicturePtr picture, uint32_t format) 78503b705cfSriastradh{ 78603b705cfSriastradh if (picture->pSourcePict) { 78703b705cfSriastradh PictSolidFill *fill = (PictSolidFill *)picture->pSourcePict; 78803b705cfSriastradh return color_convert(fill->color, PICT_a8r8g8b8, format); 78903b705cfSriastradh } else 79003b705cfSriastradh return color_convert(get_pixel(picture), picture->format, format); 79103b705cfSriastradh} 79203b705cfSriastradh 79303b705cfSriastradhstatic bool 79403b705cfSriastradhis_solid(PicturePtr picture) 79503b705cfSriastradh{ 79603b705cfSriastradh if (picture->pSourcePict) { 79703b705cfSriastradh if (picture->pSourcePict->type == SourcePictTypeSolidFill) 79803b705cfSriastradh return true; 79903b705cfSriastradh } 80003b705cfSriastradh 80103b705cfSriastradh if (picture->pDrawable) { 80203b705cfSriastradh if (picture->pDrawable->width == 1 && 80303b705cfSriastradh picture->pDrawable->height == 1 && 80403b705cfSriastradh picture->repeat) 80503b705cfSriastradh return true; 80603b705cfSriastradh } 80703b705cfSriastradh 80803b705cfSriastradh return false; 80903b705cfSriastradh} 81003b705cfSriastradh 81103b705cfSriastradhbool 81203b705cfSriastradhsna_picture_is_solid(PicturePtr picture, uint32_t *color) 81303b705cfSriastradh{ 81403b705cfSriastradh if (!is_solid(picture)) 81503b705cfSriastradh return false; 81603b705cfSriastradh 81703b705cfSriastradh if (color) 81803b705cfSriastradh *color = get_solid_color(picture, PICT_a8r8g8b8); 81903b705cfSriastradh return true; 82003b705cfSriastradh} 82103b705cfSriastradh 82242542f5fSchristosstatic bool 82342542f5fSchristospixel_is_transparent(uint32_t pixel, uint32_t format) 82442542f5fSchristos{ 82542542f5fSchristos unsigned int abits; 82642542f5fSchristos 82742542f5fSchristos abits = PICT_FORMAT_A(format); 82842542f5fSchristos if (!abits) 82942542f5fSchristos return false; 83042542f5fSchristos 83142542f5fSchristos if (PICT_FORMAT_TYPE(format) == PICT_TYPE_A || 83242542f5fSchristos PICT_FORMAT_TYPE(format) == PICT_TYPE_BGRA) { 83342542f5fSchristos return (pixel & ((1 << abits) - 1)) == 0; 83442542f5fSchristos } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB || 83542542f5fSchristos PICT_FORMAT_TYPE(format) == PICT_TYPE_ABGR) { 83642542f5fSchristos unsigned int ashift = PICT_FORMAT_BPP(format) - abits; 83742542f5fSchristos return (pixel >> ashift) == 0; 83842542f5fSchristos } else 83942542f5fSchristos return false; 84042542f5fSchristos} 84142542f5fSchristos 84203b705cfSriastradhstatic bool 84303b705cfSriastradhpixel_is_opaque(uint32_t pixel, uint32_t format) 84403b705cfSriastradh{ 84503b705cfSriastradh unsigned int abits; 84603b705cfSriastradh 84703b705cfSriastradh abits = PICT_FORMAT_A(format); 84803b705cfSriastradh if (!abits) 84903b705cfSriastradh return true; 85003b705cfSriastradh 85103b705cfSriastradh if (PICT_FORMAT_TYPE(format) == PICT_TYPE_A || 85203b705cfSriastradh PICT_FORMAT_TYPE(format) == PICT_TYPE_BGRA) { 85303b705cfSriastradh return (pixel & ((1 << abits) - 1)) == (unsigned)((1 << abits) - 1); 85403b705cfSriastradh } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB || 85503b705cfSriastradh PICT_FORMAT_TYPE(format) == PICT_TYPE_ABGR) { 85603b705cfSriastradh unsigned int ashift = PICT_FORMAT_BPP(format) - abits; 85703b705cfSriastradh return (pixel >> ashift) == (unsigned)((1 << abits) - 1); 85803b705cfSriastradh } else 85903b705cfSriastradh return false; 86003b705cfSriastradh} 86103b705cfSriastradh 86203b705cfSriastradhstatic bool 86303b705cfSriastradhpixel_is_white(uint32_t pixel, uint32_t format) 86403b705cfSriastradh{ 86503b705cfSriastradh switch (PICT_FORMAT_TYPE(format)) { 86603b705cfSriastradh case PICT_TYPE_A: 86703b705cfSriastradh case PICT_TYPE_ARGB: 86803b705cfSriastradh case PICT_TYPE_ABGR: 86903b705cfSriastradh case PICT_TYPE_BGRA: 87003b705cfSriastradh return pixel == ((1U << PICT_FORMAT_BPP(format)) - 1); 87103b705cfSriastradh default: 87203b705cfSriastradh return false; 87303b705cfSriastradh } 87403b705cfSriastradh} 87503b705cfSriastradh 87603b705cfSriastradhstatic bool 87703b705cfSriastradhis_opaque_solid(PicturePtr picture) 87803b705cfSriastradh{ 87903b705cfSriastradh if (picture->pSourcePict) { 88003b705cfSriastradh PictSolidFill *fill = (PictSolidFill *) picture->pSourcePict; 88103b705cfSriastradh return (fill->color >> 24) == 0xff; 88203b705cfSriastradh } else 88303b705cfSriastradh return pixel_is_opaque(get_pixel(picture), picture->format); 88403b705cfSriastradh} 88503b705cfSriastradh 88603b705cfSriastradhstatic bool 88703b705cfSriastradhis_white(PicturePtr picture) 88803b705cfSriastradh{ 88903b705cfSriastradh if (picture->pSourcePict) { 89003b705cfSriastradh PictSolidFill *fill = (PictSolidFill *) picture->pSourcePict; 89103b705cfSriastradh return fill->color == 0xffffffff; 89203b705cfSriastradh } else 89303b705cfSriastradh return pixel_is_white(get_pixel(picture), picture->format); 89403b705cfSriastradh} 89503b705cfSriastradh 89642542f5fSchristosstatic bool 89742542f5fSchristosis_transparent(PicturePtr picture) 89842542f5fSchristos{ 89942542f5fSchristos if (picture->pSourcePict) { 90042542f5fSchristos PictSolidFill *fill = (PictSolidFill *) picture->pSourcePict; 90142542f5fSchristos return fill->color == 0; 90242542f5fSchristos } else 90342542f5fSchristos return pixel_is_transparent(get_pixel(picture), picture->format); 90442542f5fSchristos} 90542542f5fSchristos 90603b705cfSriastradhbool 90703b705cfSriastradhsna_composite_mask_is_opaque(PicturePtr mask) 90803b705cfSriastradh{ 90903b705cfSriastradh if (mask->componentAlpha && PICT_FORMAT_RGB(mask->format)) 91003b705cfSriastradh return is_solid(mask) && is_white(mask); 91103b705cfSriastradh else if (!PICT_FORMAT_A(mask->format)) 91203b705cfSriastradh return true; 91303b705cfSriastradh else 91403b705cfSriastradh return is_solid(mask) && is_opaque_solid(mask); 91503b705cfSriastradh} 91603b705cfSriastradh 91703b705cfSriastradhfastcall 91803b705cfSriastradhstatic void blt_composite_fill(struct sna *sna, 91903b705cfSriastradh const struct sna_composite_op *op, 92003b705cfSriastradh const struct sna_composite_rectangles *r) 92103b705cfSriastradh{ 92203b705cfSriastradh int x1, x2, y1, y2; 92303b705cfSriastradh 92403b705cfSriastradh x1 = r->dst.x + op->dst.x; 92503b705cfSriastradh y1 = r->dst.y + op->dst.y; 92603b705cfSriastradh x2 = x1 + r->width; 92703b705cfSriastradh y2 = y1 + r->height; 92803b705cfSriastradh 92903b705cfSriastradh if (x1 < 0) 93003b705cfSriastradh x1 = 0; 93103b705cfSriastradh if (y1 < 0) 93203b705cfSriastradh y1 = 0; 93303b705cfSriastradh 93403b705cfSriastradh if (x2 > op->dst.width) 93503b705cfSriastradh x2 = op->dst.width; 93603b705cfSriastradh if (y2 > op->dst.height) 93703b705cfSriastradh y2 = op->dst.height; 93803b705cfSriastradh 93903b705cfSriastradh if (x2 <= x1 || y2 <= y1) 94003b705cfSriastradh return; 94103b705cfSriastradh 94203b705cfSriastradh sna_blt_fill_one(sna, &op->u.blt, x1, y1, x2-x1, y2-y1); 94303b705cfSriastradh} 94403b705cfSriastradh 94503b705cfSriastradhfastcall 94603b705cfSriastradhstatic void blt_composite_fill__cpu(struct sna *sna, 94703b705cfSriastradh const struct sna_composite_op *op, 94803b705cfSriastradh const struct sna_composite_rectangles *r) 94903b705cfSriastradh{ 95003b705cfSriastradh int x1, x2, y1, y2; 95103b705cfSriastradh 95203b705cfSriastradh x1 = r->dst.x + op->dst.x; 95303b705cfSriastradh y1 = r->dst.y + op->dst.y; 95403b705cfSriastradh x2 = x1 + r->width; 95503b705cfSriastradh y2 = y1 + r->height; 95603b705cfSriastradh 95703b705cfSriastradh if (x1 < 0) 95803b705cfSriastradh x1 = 0; 95903b705cfSriastradh if (y1 < 0) 96003b705cfSriastradh y1 = 0; 96103b705cfSriastradh 96203b705cfSriastradh if (x2 > op->dst.width) 96303b705cfSriastradh x2 = op->dst.width; 96403b705cfSriastradh if (y2 > op->dst.height) 96503b705cfSriastradh y2 = op->dst.height; 96603b705cfSriastradh 96703b705cfSriastradh if (x2 <= x1 || y2 <= y1) 96803b705cfSriastradh return; 96903b705cfSriastradh 97042542f5fSchristos assert(op->dst.pixmap->devPrivate.ptr); 97142542f5fSchristos assert(op->dst.pixmap->devKind); 97203b705cfSriastradh pixman_fill(op->dst.pixmap->devPrivate.ptr, 97303b705cfSriastradh op->dst.pixmap->devKind / sizeof(uint32_t), 97403b705cfSriastradh op->dst.pixmap->drawable.bitsPerPixel, 97503b705cfSriastradh x1, y1, x2-x1, y2-y1, 97603b705cfSriastradh op->u.blt.pixel); 97703b705cfSriastradh} 97803b705cfSriastradh 97942542f5fSchristosfastcall static void 98042542f5fSchristosblt_composite_fill_box_no_offset__cpu(struct sna *sna, 98142542f5fSchristos const struct sna_composite_op *op, 98242542f5fSchristos const BoxRec *box) 98342542f5fSchristos{ 98442542f5fSchristos assert(box->x1 >= 0); 98542542f5fSchristos assert(box->y1 >= 0); 98642542f5fSchristos assert(box->x2 <= op->dst.pixmap->drawable.width); 98742542f5fSchristos assert(box->y2 <= op->dst.pixmap->drawable.height); 98842542f5fSchristos 98942542f5fSchristos assert(op->dst.pixmap->devPrivate.ptr); 99042542f5fSchristos assert(op->dst.pixmap->devKind); 99142542f5fSchristos pixman_fill(op->dst.pixmap->devPrivate.ptr, 99242542f5fSchristos op->dst.pixmap->devKind / sizeof(uint32_t), 99342542f5fSchristos op->dst.pixmap->drawable.bitsPerPixel, 99442542f5fSchristos box->x1, box->y1, box->x2-box->x1, box->y2-box->y1, 99542542f5fSchristos op->u.blt.pixel); 99642542f5fSchristos} 99742542f5fSchristos 99842542f5fSchristosstatic void 99942542f5fSchristosblt_composite_fill_boxes_no_offset__cpu(struct sna *sna, 100042542f5fSchristos const struct sna_composite_op *op, 100142542f5fSchristos const BoxRec *box, int n) 100242542f5fSchristos{ 100342542f5fSchristos do { 100442542f5fSchristos assert(box->x1 >= 0); 100542542f5fSchristos assert(box->y1 >= 0); 100642542f5fSchristos assert(box->x2 <= op->dst.pixmap->drawable.width); 100742542f5fSchristos assert(box->y2 <= op->dst.pixmap->drawable.height); 100842542f5fSchristos 100942542f5fSchristos assert(op->dst.pixmap->devPrivate.ptr); 101042542f5fSchristos assert(op->dst.pixmap->devKind); 101142542f5fSchristos pixman_fill(op->dst.pixmap->devPrivate.ptr, 101242542f5fSchristos op->dst.pixmap->devKind / sizeof(uint32_t), 101342542f5fSchristos op->dst.pixmap->drawable.bitsPerPixel, 101442542f5fSchristos box->x1, box->y1, box->x2-box->x1, box->y2-box->y1, 101542542f5fSchristos op->u.blt.pixel); 101642542f5fSchristos box++; 101742542f5fSchristos } while (--n); 101842542f5fSchristos} 101942542f5fSchristos 102003b705cfSriastradhfastcall static void 102103b705cfSriastradhblt_composite_fill_box__cpu(struct sna *sna, 102203b705cfSriastradh const struct sna_composite_op *op, 102303b705cfSriastradh const BoxRec *box) 102403b705cfSriastradh{ 102542542f5fSchristos assert(box->x1 + op->dst.x >= 0); 102642542f5fSchristos assert(box->y1 + op->dst.y >= 0); 102742542f5fSchristos assert(box->x2 + op->dst.x <= op->dst.pixmap->drawable.width); 102842542f5fSchristos assert(box->y2 + op->dst.y <= op->dst.pixmap->drawable.height); 102942542f5fSchristos 103042542f5fSchristos assert(op->dst.pixmap->devPrivate.ptr); 103142542f5fSchristos assert(op->dst.pixmap->devKind); 103203b705cfSriastradh pixman_fill(op->dst.pixmap->devPrivate.ptr, 103303b705cfSriastradh op->dst.pixmap->devKind / sizeof(uint32_t), 103403b705cfSriastradh op->dst.pixmap->drawable.bitsPerPixel, 103542542f5fSchristos box->x1 + op->dst.x, box->y1 + op->dst.y, 103642542f5fSchristos box->x2 - box->x1, box->y2 - box->y1, 103703b705cfSriastradh op->u.blt.pixel); 103803b705cfSriastradh} 103903b705cfSriastradh 104003b705cfSriastradhstatic void 104103b705cfSriastradhblt_composite_fill_boxes__cpu(struct sna *sna, 104203b705cfSriastradh const struct sna_composite_op *op, 104303b705cfSriastradh const BoxRec *box, int n) 104403b705cfSriastradh{ 104503b705cfSriastradh do { 104642542f5fSchristos assert(box->x1 + op->dst.x >= 0); 104742542f5fSchristos assert(box->y1 + op->dst.y >= 0); 104842542f5fSchristos assert(box->x2 + op->dst.x <= op->dst.pixmap->drawable.width); 104942542f5fSchristos assert(box->y2 + op->dst.y <= op->dst.pixmap->drawable.height); 105042542f5fSchristos 105142542f5fSchristos assert(op->dst.pixmap->devPrivate.ptr); 105242542f5fSchristos assert(op->dst.pixmap->devKind); 105303b705cfSriastradh pixman_fill(op->dst.pixmap->devPrivate.ptr, 105403b705cfSriastradh op->dst.pixmap->devKind / sizeof(uint32_t), 105503b705cfSriastradh op->dst.pixmap->drawable.bitsPerPixel, 105642542f5fSchristos box->x1 + op->dst.x, box->y1 + op->dst.y, 105742542f5fSchristos box->x2 - box->x1, box->y2 - box->y1, 105803b705cfSriastradh op->u.blt.pixel); 105903b705cfSriastradh box++; 106003b705cfSriastradh } while (--n); 106103b705cfSriastradh} 106203b705cfSriastradh 106303b705cfSriastradhinline static void _sna_blt_fill_box(struct sna *sna, 106403b705cfSriastradh const struct sna_blt_state *blt, 106503b705cfSriastradh const BoxRec *box) 106603b705cfSriastradh{ 106703b705cfSriastradh struct kgem *kgem = &sna->kgem; 106803b705cfSriastradh uint32_t *b; 106903b705cfSriastradh 107003b705cfSriastradh DBG(("%s: (%d, %d), (%d, %d): %08x\n", __FUNCTION__, 107103b705cfSriastradh box->x1, box->y1, box->x2, box->y2, 107203b705cfSriastradh blt->pixel)); 107303b705cfSriastradh 107403b705cfSriastradh assert(box->x1 >= 0); 107503b705cfSriastradh assert(box->y1 >= 0); 107603b705cfSriastradh assert(box->y2 * blt->bo[0]->pitch <= kgem_bo_size(blt->bo[0])); 107703b705cfSriastradh 107803b705cfSriastradh if (!kgem_check_batch(kgem, 3)) 107903b705cfSriastradh sna_blt_fill_begin(sna, blt); 108003b705cfSriastradh 108142542f5fSchristos assert(sna->kgem.mode == KGEM_BLT); 108203b705cfSriastradh b = kgem->batch + kgem->nbatch; 108303b705cfSriastradh kgem->nbatch += 3; 108403b705cfSriastradh assert(kgem->nbatch < kgem->surface); 108503b705cfSriastradh 108603b705cfSriastradh b[0] = blt->cmd; 108703b705cfSriastradh *(uint64_t *)(b+1) = *(const uint64_t *)box; 108803b705cfSriastradh} 108903b705cfSriastradh 109003b705cfSriastradhinline static void _sna_blt_fill_boxes(struct sna *sna, 109103b705cfSriastradh const struct sna_blt_state *blt, 109203b705cfSriastradh const BoxRec *box, 109303b705cfSriastradh int nbox) 109403b705cfSriastradh{ 109503b705cfSriastradh struct kgem *kgem = &sna->kgem; 109603b705cfSriastradh uint32_t cmd = blt->cmd; 109703b705cfSriastradh 109803b705cfSriastradh DBG(("%s: %08x x %d\n", __FUNCTION__, blt->pixel, nbox)); 109903b705cfSriastradh 110003b705cfSriastradh if (!kgem_check_batch(kgem, 3)) 110103b705cfSriastradh sna_blt_fill_begin(sna, blt); 110203b705cfSriastradh 110303b705cfSriastradh do { 110403b705cfSriastradh uint32_t *b = kgem->batch + kgem->nbatch; 110503b705cfSriastradh int nbox_this_time; 110603b705cfSriastradh 110742542f5fSchristos assert(sna->kgem.mode == KGEM_BLT); 110803b705cfSriastradh nbox_this_time = nbox; 110903b705cfSriastradh if (3*nbox_this_time > kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) 111003b705cfSriastradh nbox_this_time = (kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) / 3; 111103b705cfSriastradh assert(nbox_this_time); 111203b705cfSriastradh nbox -= nbox_this_time; 111303b705cfSriastradh 111403b705cfSriastradh kgem->nbatch += 3 * nbox_this_time; 111503b705cfSriastradh assert(kgem->nbatch < kgem->surface); 111603b705cfSriastradh while (nbox_this_time >= 8) { 111703b705cfSriastradh b[0] = cmd; *(uint64_t *)(b+1) = *(const uint64_t *)box++; 111803b705cfSriastradh b[3] = cmd; *(uint64_t *)(b+4) = *(const uint64_t *)box++; 111903b705cfSriastradh b[6] = cmd; *(uint64_t *)(b+7) = *(const uint64_t *)box++; 112003b705cfSriastradh b[9] = cmd; *(uint64_t *)(b+10) = *(const uint64_t *)box++; 112103b705cfSriastradh b[12] = cmd; *(uint64_t *)(b+13) = *(const uint64_t *)box++; 112203b705cfSriastradh b[15] = cmd; *(uint64_t *)(b+16) = *(const uint64_t *)box++; 112303b705cfSriastradh b[18] = cmd; *(uint64_t *)(b+19) = *(const uint64_t *)box++; 112403b705cfSriastradh b[21] = cmd; *(uint64_t *)(b+22) = *(const uint64_t *)box++; 112503b705cfSriastradh b += 24; 112603b705cfSriastradh nbox_this_time -= 8; 112703b705cfSriastradh } 112803b705cfSriastradh if (nbox_this_time & 4) { 112903b705cfSriastradh b[0] = cmd; *(uint64_t *)(b+1) = *(const uint64_t *)box++; 113003b705cfSriastradh b[3] = cmd; *(uint64_t *)(b+4) = *(const uint64_t *)box++; 113103b705cfSriastradh b[6] = cmd; *(uint64_t *)(b+7) = *(const uint64_t *)box++; 113203b705cfSriastradh b[9] = cmd; *(uint64_t *)(b+10) = *(const uint64_t *)box++; 113303b705cfSriastradh b += 12; 113403b705cfSriastradh } 113503b705cfSriastradh if (nbox_this_time & 2) { 113603b705cfSriastradh b[0] = cmd; *(uint64_t *)(b+1) = *(const uint64_t *)box++; 113703b705cfSriastradh b[3] = cmd; *(uint64_t *)(b+4) = *(const uint64_t *)box++; 113803b705cfSriastradh b += 6; 113903b705cfSriastradh } 114003b705cfSriastradh if (nbox_this_time & 1) { 114103b705cfSriastradh b[0] = cmd; *(uint64_t *)(b+1) = *(const uint64_t *)box++; 114203b705cfSriastradh } 114303b705cfSriastradh 114403b705cfSriastradh if (!nbox) 114503b705cfSriastradh return; 114603b705cfSriastradh 114703b705cfSriastradh sna_blt_fill_begin(sna, blt); 114803b705cfSriastradh } while (1); 114903b705cfSriastradh} 115003b705cfSriastradh 115142542f5fSchristosstatic inline void _sna_blt_maybe_clear(const struct sna_composite_op *op, const BoxRec *box) 115242542f5fSchristos{ 115342542f5fSchristos if (box->x2 - box->x1 >= op->dst.width && 115442542f5fSchristos box->y2 - box->y1 >= op->dst.height) { 115542542f5fSchristos struct sna_pixmap *priv = sna_pixmap(op->dst.pixmap); 115642542f5fSchristos if (op->dst.bo == priv->gpu_bo) { 115742542f5fSchristos priv->clear = true; 115842542f5fSchristos priv->clear_color = op->u.blt.pixel; 115942542f5fSchristos DBG(("%s: pixmap=%ld marking clear [%08x]\n", 116042542f5fSchristos __FUNCTION__, 116142542f5fSchristos op->dst.pixmap->drawable.serialNumber, 116242542f5fSchristos op->u.blt.pixel)); 116342542f5fSchristos } 116442542f5fSchristos } 116542542f5fSchristos} 116642542f5fSchristos 116703b705cfSriastradhfastcall static void blt_composite_fill_box_no_offset(struct sna *sna, 116803b705cfSriastradh const struct sna_composite_op *op, 116903b705cfSriastradh const BoxRec *box) 117003b705cfSriastradh{ 117103b705cfSriastradh _sna_blt_fill_box(sna, &op->u.blt, box); 117242542f5fSchristos _sna_blt_maybe_clear(op, box); 117303b705cfSriastradh} 117403b705cfSriastradh 117503b705cfSriastradhstatic void blt_composite_fill_boxes_no_offset(struct sna *sna, 117603b705cfSriastradh const struct sna_composite_op *op, 117703b705cfSriastradh const BoxRec *box, int n) 117803b705cfSriastradh{ 117903b705cfSriastradh _sna_blt_fill_boxes(sna, &op->u.blt, box, n); 118003b705cfSriastradh} 118103b705cfSriastradh 118203b705cfSriastradhstatic void blt_composite_fill_boxes_no_offset__thread(struct sna *sna, 118303b705cfSriastradh const struct sna_composite_op *op, 118403b705cfSriastradh const BoxRec *box, int nbox) 118503b705cfSriastradh{ 118603b705cfSriastradh struct kgem *kgem = &sna->kgem; 118703b705cfSriastradh const struct sna_blt_state *blt = &op->u.blt; 118803b705cfSriastradh uint32_t cmd = blt->cmd; 118903b705cfSriastradh 119003b705cfSriastradh DBG(("%s: %08x x %d\n", __FUNCTION__, blt->pixel, nbox)); 119103b705cfSriastradh 119203b705cfSriastradh sna_vertex_lock(&sna->render); 119342542f5fSchristos assert(kgem->mode == KGEM_BLT); 119403b705cfSriastradh if (!kgem_check_batch(kgem, 3)) { 119503b705cfSriastradh sna_vertex_wait__locked(&sna->render); 119603b705cfSriastradh sna_blt_fill_begin(sna, blt); 119703b705cfSriastradh } 119803b705cfSriastradh 119903b705cfSriastradh do { 120003b705cfSriastradh uint32_t *b = kgem->batch + kgem->nbatch; 120103b705cfSriastradh int nbox_this_time; 120203b705cfSriastradh 120342542f5fSchristos assert(sna->kgem.mode == KGEM_BLT); 120403b705cfSriastradh nbox_this_time = nbox; 120503b705cfSriastradh if (3*nbox_this_time > kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) 120603b705cfSriastradh nbox_this_time = (kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) / 3; 120703b705cfSriastradh assert(nbox_this_time); 120803b705cfSriastradh nbox -= nbox_this_time; 120903b705cfSriastradh 121003b705cfSriastradh kgem->nbatch += 3 * nbox_this_time; 121103b705cfSriastradh assert(kgem->nbatch < kgem->surface); 121203b705cfSriastradh sna_vertex_acquire__locked(&sna->render); 121303b705cfSriastradh sna_vertex_unlock(&sna->render); 121403b705cfSriastradh 121503b705cfSriastradh while (nbox_this_time >= 8) { 121603b705cfSriastradh b[0] = cmd; *(uint64_t *)(b+1) = *(const uint64_t *)box++; 121703b705cfSriastradh b[3] = cmd; *(uint64_t *)(b+4) = *(const uint64_t *)box++; 121803b705cfSriastradh b[6] = cmd; *(uint64_t *)(b+7) = *(const uint64_t *)box++; 121903b705cfSriastradh b[9] = cmd; *(uint64_t *)(b+10) = *(const uint64_t *)box++; 122003b705cfSriastradh b[12] = cmd; *(uint64_t *)(b+13) = *(const uint64_t *)box++; 122103b705cfSriastradh b[15] = cmd; *(uint64_t *)(b+16) = *(const uint64_t *)box++; 122203b705cfSriastradh b[18] = cmd; *(uint64_t *)(b+19) = *(const uint64_t *)box++; 122303b705cfSriastradh b[21] = cmd; *(uint64_t *)(b+22) = *(const uint64_t *)box++; 122403b705cfSriastradh b += 24; 122503b705cfSriastradh nbox_this_time -= 8; 122603b705cfSriastradh } 122703b705cfSriastradh if (nbox_this_time & 4) { 122803b705cfSriastradh b[0] = cmd; *(uint64_t *)(b+1) = *(const uint64_t *)box++; 122903b705cfSriastradh b[3] = cmd; *(uint64_t *)(b+4) = *(const uint64_t *)box++; 123003b705cfSriastradh b[6] = cmd; *(uint64_t *)(b+7) = *(const uint64_t *)box++; 123103b705cfSriastradh b[9] = cmd; *(uint64_t *)(b+10) = *(const uint64_t *)box++; 123203b705cfSriastradh b += 12; 123303b705cfSriastradh } 123403b705cfSriastradh if (nbox_this_time & 2) { 123503b705cfSriastradh b[0] = cmd; *(uint64_t *)(b+1) = *(const uint64_t *)box++; 123603b705cfSriastradh b[3] = cmd; *(uint64_t *)(b+4) = *(const uint64_t *)box++; 123703b705cfSriastradh b += 6; 123803b705cfSriastradh } 123903b705cfSriastradh if (nbox_this_time & 1) { 124003b705cfSriastradh b[0] = cmd; *(uint64_t *)(b+1) = *(const uint64_t *)box++; 124103b705cfSriastradh } 124203b705cfSriastradh 124303b705cfSriastradh sna_vertex_lock(&sna->render); 124403b705cfSriastradh sna_vertex_release__locked(&sna->render); 124503b705cfSriastradh if (!nbox) 124603b705cfSriastradh break; 124703b705cfSriastradh 124803b705cfSriastradh sna_vertex_wait__locked(&sna->render); 124903b705cfSriastradh sna_blt_fill_begin(sna, blt); 125003b705cfSriastradh } while (1); 125103b705cfSriastradh sna_vertex_unlock(&sna->render); 125203b705cfSriastradh} 125303b705cfSriastradh 125403b705cfSriastradhfastcall static void blt_composite_fill_box(struct sna *sna, 125503b705cfSriastradh const struct sna_composite_op *op, 125603b705cfSriastradh const BoxRec *box) 125703b705cfSriastradh{ 125803b705cfSriastradh sna_blt_fill_one(sna, &op->u.blt, 125903b705cfSriastradh box->x1 + op->dst.x, 126003b705cfSriastradh box->y1 + op->dst.y, 126103b705cfSriastradh box->x2 - box->x1, 126203b705cfSriastradh box->y2 - box->y1); 126342542f5fSchristos _sna_blt_maybe_clear(op, box); 126403b705cfSriastradh} 126503b705cfSriastradh 126603b705cfSriastradhstatic void blt_composite_fill_boxes(struct sna *sna, 126703b705cfSriastradh const struct sna_composite_op *op, 126803b705cfSriastradh const BoxRec *box, int n) 126903b705cfSriastradh{ 127003b705cfSriastradh do { 127103b705cfSriastradh sna_blt_fill_one(sna, &op->u.blt, 127203b705cfSriastradh box->x1 + op->dst.x, box->y1 + op->dst.y, 127303b705cfSriastradh box->x2 - box->x1, box->y2 - box->y1); 127403b705cfSriastradh box++; 127503b705cfSriastradh } while (--n); 127603b705cfSriastradh} 127703b705cfSriastradh 127803b705cfSriastradhstatic inline uint64_t add4(const BoxRec *b, int16_t x, int16_t y) 127903b705cfSriastradh{ 128003b705cfSriastradh union { 128103b705cfSriastradh uint64_t v; 128203b705cfSriastradh int16_t i[4]; 128303b705cfSriastradh } vi; 128403b705cfSriastradh vi.v = *(uint64_t *)b; 128503b705cfSriastradh vi.i[0] += x; 128603b705cfSriastradh vi.i[1] += y; 128703b705cfSriastradh vi.i[2] += x; 128803b705cfSriastradh vi.i[3] += y; 128903b705cfSriastradh return vi.v; 129003b705cfSriastradh} 129103b705cfSriastradh 129203b705cfSriastradhstatic void blt_composite_fill_boxes__thread(struct sna *sna, 129303b705cfSriastradh const struct sna_composite_op *op, 129403b705cfSriastradh const BoxRec *box, int nbox) 129503b705cfSriastradh{ 129603b705cfSriastradh struct kgem *kgem = &sna->kgem; 129703b705cfSriastradh const struct sna_blt_state *blt = &op->u.blt; 129803b705cfSriastradh uint32_t cmd = blt->cmd; 129903b705cfSriastradh int16_t dx = op->dst.x; 130003b705cfSriastradh int16_t dy = op->dst.y; 130103b705cfSriastradh 130203b705cfSriastradh DBG(("%s: %08x x %d\n", __FUNCTION__, blt->pixel, nbox)); 130303b705cfSriastradh 130403b705cfSriastradh sna_vertex_lock(&sna->render); 130542542f5fSchristos assert(kgem->mode == KGEM_BLT); 130603b705cfSriastradh if (!kgem_check_batch(kgem, 3)) { 130703b705cfSriastradh sna_vertex_wait__locked(&sna->render); 130803b705cfSriastradh sna_blt_fill_begin(sna, blt); 130903b705cfSriastradh } 131003b705cfSriastradh 131103b705cfSriastradh do { 131203b705cfSriastradh uint32_t *b = kgem->batch + kgem->nbatch; 131303b705cfSriastradh int nbox_this_time; 131403b705cfSriastradh 131542542f5fSchristos assert(sna->kgem.mode == KGEM_BLT); 131603b705cfSriastradh nbox_this_time = nbox; 131703b705cfSriastradh if (3*nbox_this_time > kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) 131803b705cfSriastradh nbox_this_time = (kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) / 3; 131903b705cfSriastradh assert(nbox_this_time); 132003b705cfSriastradh nbox -= nbox_this_time; 132103b705cfSriastradh 132203b705cfSriastradh kgem->nbatch += 3 * nbox_this_time; 132303b705cfSriastradh assert(kgem->nbatch < kgem->surface); 132403b705cfSriastradh sna_vertex_acquire__locked(&sna->render); 132503b705cfSriastradh sna_vertex_unlock(&sna->render); 132603b705cfSriastradh 132703b705cfSriastradh while (nbox_this_time >= 8) { 132803b705cfSriastradh b[0] = cmd; *(uint64_t *)(b+1) = add4(box++, dx, dy); 132903b705cfSriastradh b[3] = cmd; *(uint64_t *)(b+4) = add4(box++, dx, dy); 133003b705cfSriastradh b[6] = cmd; *(uint64_t *)(b+7) = add4(box++, dx, dy); 133103b705cfSriastradh b[9] = cmd; *(uint64_t *)(b+10) = add4(box++, dx, dy); 133203b705cfSriastradh b[12] = cmd; *(uint64_t *)(b+13) = add4(box++, dx, dy); 133303b705cfSriastradh b[15] = cmd; *(uint64_t *)(b+16) = add4(box++, dx, dy); 133403b705cfSriastradh b[18] = cmd; *(uint64_t *)(b+19) = add4(box++, dx, dy); 133503b705cfSriastradh b[21] = cmd; *(uint64_t *)(b+22) = add4(box++, dx, dy); 133603b705cfSriastradh b += 24; 133703b705cfSriastradh nbox_this_time -= 8; 133803b705cfSriastradh } 133903b705cfSriastradh if (nbox_this_time & 4) { 134003b705cfSriastradh b[0] = cmd; *(uint64_t *)(b+1) = add4(box++, dx, dy); 134103b705cfSriastradh b[3] = cmd; *(uint64_t *)(b+4) = add4(box++, dx, dy); 134203b705cfSriastradh b[6] = cmd; *(uint64_t *)(b+7) = add4(box++, dx, dy); 134303b705cfSriastradh b[9] = cmd; *(uint64_t *)(b+10) = add4(box++, dx, dy); 134403b705cfSriastradh b += 12; 134503b705cfSriastradh } 134603b705cfSriastradh if (nbox_this_time & 2) { 134703b705cfSriastradh b[0] = cmd; *(uint64_t *)(b+1) = add4(box++, dx, dy); 134803b705cfSriastradh b[3] = cmd; *(uint64_t *)(b+4) = add4(box++, dx, dy); 134903b705cfSriastradh b += 6; 135003b705cfSriastradh } 135103b705cfSriastradh if (nbox_this_time & 1) { 135203b705cfSriastradh b[0] = cmd; *(uint64_t *)(b+1) = add4(box++, dx, dy); 135303b705cfSriastradh } 135403b705cfSriastradh 135503b705cfSriastradh sna_vertex_lock(&sna->render); 135603b705cfSriastradh sna_vertex_release__locked(&sna->render); 135703b705cfSriastradh if (!nbox) 135803b705cfSriastradh break; 135903b705cfSriastradh 136003b705cfSriastradh sna_vertex_wait__locked(&sna->render); 136103b705cfSriastradh sna_blt_fill_begin(sna, blt); 136203b705cfSriastradh } while (1); 136303b705cfSriastradh sna_vertex_unlock(&sna->render); 136403b705cfSriastradh} 136503b705cfSriastradh 136603b705cfSriastradhfastcall 136703b705cfSriastradhstatic void blt_composite_nop(struct sna *sna, 136803b705cfSriastradh const struct sna_composite_op *op, 136903b705cfSriastradh const struct sna_composite_rectangles *r) 137003b705cfSriastradh{ 137103b705cfSriastradh} 137203b705cfSriastradh 137303b705cfSriastradhfastcall static void blt_composite_nop_box(struct sna *sna, 137403b705cfSriastradh const struct sna_composite_op *op, 137503b705cfSriastradh const BoxRec *box) 137603b705cfSriastradh{ 137703b705cfSriastradh} 137803b705cfSriastradh 137903b705cfSriastradhstatic void blt_composite_nop_boxes(struct sna *sna, 138003b705cfSriastradh const struct sna_composite_op *op, 138103b705cfSriastradh const BoxRec *box, int n) 138203b705cfSriastradh{ 138303b705cfSriastradh} 138403b705cfSriastradh 138503b705cfSriastradhstatic bool 138603b705cfSriastradhbegin_blt(struct sna *sna, 138703b705cfSriastradh struct sna_composite_op *op) 138803b705cfSriastradh{ 138903b705cfSriastradh if (!kgem_check_bo_fenced(&sna->kgem, op->dst.bo)) { 139003b705cfSriastradh kgem_submit(&sna->kgem); 139103b705cfSriastradh if (!kgem_check_bo_fenced(&sna->kgem, op->dst.bo)) 139203b705cfSriastradh return false; 139303b705cfSriastradh 139403b705cfSriastradh _kgem_set_mode(&sna->kgem, KGEM_BLT); 139503b705cfSriastradh } 139603b705cfSriastradh 139703b705cfSriastradh return true; 139803b705cfSriastradh} 139903b705cfSriastradh 140003b705cfSriastradhstatic bool 140103b705cfSriastradhprepare_blt_nop(struct sna *sna, 140203b705cfSriastradh struct sna_composite_op *op) 140303b705cfSriastradh{ 140403b705cfSriastradh DBG(("%s\n", __FUNCTION__)); 140503b705cfSriastradh 140603b705cfSriastradh op->blt = blt_composite_nop; 140703b705cfSriastradh op->box = blt_composite_nop_box; 140803b705cfSriastradh op->boxes = blt_composite_nop_boxes; 140903b705cfSriastradh op->done = nop_done; 141003b705cfSriastradh return true; 141103b705cfSriastradh} 141203b705cfSriastradh 141303b705cfSriastradhstatic bool 141403b705cfSriastradhprepare_blt_clear(struct sna *sna, 141503b705cfSriastradh struct sna_composite_op *op) 141603b705cfSriastradh{ 141703b705cfSriastradh DBG(("%s\n", __FUNCTION__)); 141803b705cfSriastradh 141903b705cfSriastradh if (op->dst.bo == NULL) { 142003b705cfSriastradh op->blt = blt_composite_fill__cpu; 142142542f5fSchristos if (op->dst.x|op->dst.y) { 142242542f5fSchristos op->box = blt_composite_fill_box__cpu; 142342542f5fSchristos op->boxes = blt_composite_fill_boxes__cpu; 142442542f5fSchristos op->thread_boxes = blt_composite_fill_boxes__cpu; 142542542f5fSchristos } else { 142642542f5fSchristos op->box = blt_composite_fill_box_no_offset__cpu; 142742542f5fSchristos op->boxes = blt_composite_fill_boxes_no_offset__cpu; 142842542f5fSchristos op->thread_boxes = blt_composite_fill_boxes_no_offset__cpu; 142942542f5fSchristos } 143003b705cfSriastradh op->done = nop_done; 143103b705cfSriastradh op->u.blt.pixel = 0; 143203b705cfSriastradh return true; 143303b705cfSriastradh } 143403b705cfSriastradh 143503b705cfSriastradh op->blt = blt_composite_fill; 143603b705cfSriastradh if (op->dst.x|op->dst.y) { 143703b705cfSriastradh op->box = blt_composite_fill_box; 143803b705cfSriastradh op->boxes = blt_composite_fill_boxes; 143903b705cfSriastradh op->thread_boxes = blt_composite_fill_boxes__thread; 144003b705cfSriastradh } else { 144103b705cfSriastradh op->box = blt_composite_fill_box_no_offset; 144203b705cfSriastradh op->boxes = blt_composite_fill_boxes_no_offset; 144303b705cfSriastradh op->thread_boxes = blt_composite_fill_boxes_no_offset__thread; 144403b705cfSriastradh } 144503b705cfSriastradh op->done = nop_done; 144603b705cfSriastradh 144703b705cfSriastradh if (!sna_blt_fill_init(sna, &op->u.blt, 144842542f5fSchristos op->dst.bo, 144942542f5fSchristos op->dst.pixmap->drawable.bitsPerPixel, 145042542f5fSchristos GXclear, 0)) 145103b705cfSriastradh return false; 145203b705cfSriastradh 145303b705cfSriastradh return begin_blt(sna, op); 145403b705cfSriastradh} 145503b705cfSriastradh 145603b705cfSriastradhstatic bool 145703b705cfSriastradhprepare_blt_fill(struct sna *sna, 145803b705cfSriastradh struct sna_composite_op *op, 145903b705cfSriastradh uint32_t pixel) 146003b705cfSriastradh{ 146103b705cfSriastradh DBG(("%s\n", __FUNCTION__)); 146203b705cfSriastradh 146303b705cfSriastradh if (op->dst.bo == NULL) { 146403b705cfSriastradh op->u.blt.pixel = pixel; 146503b705cfSriastradh op->blt = blt_composite_fill__cpu; 146642542f5fSchristos if (op->dst.x|op->dst.y) { 146742542f5fSchristos op->box = blt_composite_fill_box__cpu; 146842542f5fSchristos op->boxes = blt_composite_fill_boxes__cpu; 146942542f5fSchristos op->thread_boxes = blt_composite_fill_boxes__cpu; 147042542f5fSchristos } else { 147142542f5fSchristos op->box = blt_composite_fill_box_no_offset__cpu; 147242542f5fSchristos op->boxes = blt_composite_fill_boxes_no_offset__cpu; 147342542f5fSchristos op->thread_boxes = blt_composite_fill_boxes_no_offset__cpu; 147442542f5fSchristos } 147503b705cfSriastradh op->done = nop_done; 147603b705cfSriastradh return true; 147703b705cfSriastradh } 147803b705cfSriastradh 147903b705cfSriastradh op->blt = blt_composite_fill; 148003b705cfSriastradh if (op->dst.x|op->dst.y) { 148103b705cfSriastradh op->box = blt_composite_fill_box; 148203b705cfSriastradh op->boxes = blt_composite_fill_boxes; 148303b705cfSriastradh op->thread_boxes = blt_composite_fill_boxes__thread; 148403b705cfSriastradh } else { 148503b705cfSriastradh op->box = blt_composite_fill_box_no_offset; 148603b705cfSriastradh op->boxes = blt_composite_fill_boxes_no_offset; 148703b705cfSriastradh op->thread_boxes = blt_composite_fill_boxes_no_offset__thread; 148803b705cfSriastradh } 148903b705cfSriastradh op->done = nop_done; 149003b705cfSriastradh 149103b705cfSriastradh if (!sna_blt_fill_init(sna, &op->u.blt, op->dst.bo, 149203b705cfSriastradh op->dst.pixmap->drawable.bitsPerPixel, 149303b705cfSriastradh GXcopy, pixel)) 149403b705cfSriastradh return false; 149503b705cfSriastradh 149603b705cfSriastradh return begin_blt(sna, op); 149703b705cfSriastradh} 149803b705cfSriastradh 149903b705cfSriastradhfastcall static void 150003b705cfSriastradhblt_composite_copy(struct sna *sna, 150103b705cfSriastradh const struct sna_composite_op *op, 150203b705cfSriastradh const struct sna_composite_rectangles *r) 150303b705cfSriastradh{ 150403b705cfSriastradh int x1, x2, y1, y2; 150503b705cfSriastradh int src_x, src_y; 150603b705cfSriastradh 150703b705cfSriastradh DBG(("%s: src=(%d, %d), dst=(%d, %d), size=(%d, %d)\n", 150803b705cfSriastradh __FUNCTION__, 150903b705cfSriastradh r->src.x, r->src.y, 151003b705cfSriastradh r->dst.x, r->dst.y, 151103b705cfSriastradh r->width, r->height)); 151203b705cfSriastradh 151303b705cfSriastradh /* XXX higher layer should have clipped? */ 151403b705cfSriastradh 151503b705cfSriastradh x1 = r->dst.x + op->dst.x; 151603b705cfSriastradh y1 = r->dst.y + op->dst.y; 151703b705cfSriastradh x2 = x1 + r->width; 151803b705cfSriastradh y2 = y1 + r->height; 151903b705cfSriastradh 152042542f5fSchristos src_x = r->src.x - x1 + op->u.blt.sx; 152142542f5fSchristos src_y = r->src.y - y1 + op->u.blt.sy; 152203b705cfSriastradh 152303b705cfSriastradh /* clip against dst */ 152403b705cfSriastradh if (x1 < 0) 152503b705cfSriastradh x1 = 0; 152603b705cfSriastradh if (y1 < 0) 152703b705cfSriastradh y1 = 0; 152803b705cfSriastradh 152903b705cfSriastradh if (x2 > op->dst.width) 153003b705cfSriastradh x2 = op->dst.width; 153103b705cfSriastradh 153203b705cfSriastradh if (y2 > op->dst.height) 153303b705cfSriastradh y2 = op->dst.height; 153403b705cfSriastradh 153503b705cfSriastradh DBG(("%s: box=(%d, %d), (%d, %d)\n", __FUNCTION__, x1, y1, x2, y2)); 153603b705cfSriastradh 153703b705cfSriastradh if (x2 <= x1 || y2 <= y1) 153803b705cfSriastradh return; 153903b705cfSriastradh 154003b705cfSriastradh sna_blt_copy_one(sna, &op->u.blt, 154103b705cfSriastradh x1 + src_x, y1 + src_y, 154203b705cfSriastradh x2 - x1, y2 - y1, 154303b705cfSriastradh x1, y1); 154403b705cfSriastradh} 154503b705cfSriastradh 154603b705cfSriastradhfastcall static void blt_composite_copy_box(struct sna *sna, 154703b705cfSriastradh const struct sna_composite_op *op, 154803b705cfSriastradh const BoxRec *box) 154903b705cfSriastradh{ 155003b705cfSriastradh DBG(("%s: box (%d, %d), (%d, %d)\n", 155103b705cfSriastradh __FUNCTION__, box->x1, box->y1, box->x2, box->y2)); 155203b705cfSriastradh sna_blt_copy_one(sna, &op->u.blt, 155303b705cfSriastradh box->x1 + op->u.blt.sx, 155403b705cfSriastradh box->y1 + op->u.blt.sy, 155503b705cfSriastradh box->x2 - box->x1, 155603b705cfSriastradh box->y2 - box->y1, 155703b705cfSriastradh box->x1 + op->dst.x, 155803b705cfSriastradh box->y1 + op->dst.y); 155903b705cfSriastradh} 156003b705cfSriastradh 156103b705cfSriastradhstatic void blt_composite_copy_boxes(struct sna *sna, 156203b705cfSriastradh const struct sna_composite_op *op, 156303b705cfSriastradh const BoxRec *box, int nbox) 156403b705cfSriastradh{ 156503b705cfSriastradh DBG(("%s: nbox=%d\n", __FUNCTION__, nbox)); 156603b705cfSriastradh do { 156703b705cfSriastradh DBG(("%s: box (%d, %d), (%d, %d)\n", 156803b705cfSriastradh __FUNCTION__, box->x1, box->y1, box->x2, box->y2)); 156903b705cfSriastradh sna_blt_copy_one(sna, &op->u.blt, 157003b705cfSriastradh box->x1 + op->u.blt.sx, box->y1 + op->u.blt.sy, 157103b705cfSriastradh box->x2 - box->x1, box->y2 - box->y1, 157203b705cfSriastradh box->x1 + op->dst.x, box->y1 + op->dst.y); 157303b705cfSriastradh box++; 157403b705cfSriastradh } while(--nbox); 157503b705cfSriastradh} 157603b705cfSriastradh 157703b705cfSriastradhstatic inline uint32_t add2(uint32_t v, int16_t x, int16_t y) 157803b705cfSriastradh{ 157903b705cfSriastradh x += v & 0xffff; 158003b705cfSriastradh y += v >> 16; 158103b705cfSriastradh return (uint16_t)y << 16 | x; 158203b705cfSriastradh} 158303b705cfSriastradh 158403b705cfSriastradhstatic void blt_composite_copy_boxes__thread(struct sna *sna, 158503b705cfSriastradh const struct sna_composite_op *op, 158603b705cfSriastradh const BoxRec *box, int nbox) 158703b705cfSriastradh{ 158803b705cfSriastradh struct kgem *kgem = &sna->kgem; 158903b705cfSriastradh int dst_dx = op->dst.x; 159003b705cfSriastradh int dst_dy = op->dst.y; 159103b705cfSriastradh int src_dx = op->src.offset[0]; 159203b705cfSriastradh int src_dy = op->src.offset[1]; 159303b705cfSriastradh uint32_t cmd = op->u.blt.cmd; 159403b705cfSriastradh uint32_t br13 = op->u.blt.br13; 159503b705cfSriastradh struct kgem_bo *src_bo = op->u.blt.bo[0]; 159603b705cfSriastradh struct kgem_bo *dst_bo = op->u.blt.bo[1]; 159703b705cfSriastradh int src_pitch = op->u.blt.pitch[0]; 159803b705cfSriastradh 159903b705cfSriastradh DBG(("%s: nbox=%d\n", __FUNCTION__, nbox)); 160003b705cfSriastradh 160103b705cfSriastradh sna_vertex_lock(&sna->render); 160203b705cfSriastradh 160303b705cfSriastradh if ((dst_dx | dst_dy) == 0) { 160403b705cfSriastradh uint64_t hdr = (uint64_t)br13 << 32 | cmd; 160503b705cfSriastradh do { 160603b705cfSriastradh int nbox_this_time; 160703b705cfSriastradh 160803b705cfSriastradh nbox_this_time = nbox; 160903b705cfSriastradh if (8*nbox_this_time > kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) 161003b705cfSriastradh nbox_this_time = (kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) / 8; 161103b705cfSriastradh if (2*nbox_this_time > KGEM_RELOC_SIZE(kgem) - kgem->nreloc) 161203b705cfSriastradh nbox_this_time = (KGEM_RELOC_SIZE(kgem) - kgem->nreloc)/2; 161303b705cfSriastradh assert(nbox_this_time); 161403b705cfSriastradh nbox -= nbox_this_time; 161503b705cfSriastradh 161642542f5fSchristos assert(sna->kgem.mode == KGEM_BLT); 161703b705cfSriastradh do { 161803b705cfSriastradh uint32_t *b = kgem->batch + kgem->nbatch; 161903b705cfSriastradh 162003b705cfSriastradh DBG((" %s: box=(%d, %d)x(%d, %d)\n", 162103b705cfSriastradh __FUNCTION__, 162203b705cfSriastradh box->x1, box->y1, 162303b705cfSriastradh box->x2 - box->x1, box->y2 - box->y1)); 162403b705cfSriastradh 162503b705cfSriastradh assert(box->x1 + src_dx >= 0); 162603b705cfSriastradh assert(box->y1 + src_dy >= 0); 162703b705cfSriastradh assert(box->x1 + src_dx <= INT16_MAX); 162803b705cfSriastradh assert(box->y1 + src_dy <= INT16_MAX); 162903b705cfSriastradh 163003b705cfSriastradh assert(box->x1 >= 0); 163103b705cfSriastradh assert(box->y1 >= 0); 163203b705cfSriastradh 163303b705cfSriastradh *(uint64_t *)&b[0] = hdr; 163403b705cfSriastradh *(uint64_t *)&b[2] = *(const uint64_t *)box; 163503b705cfSriastradh b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4, dst_bo, 163603b705cfSriastradh I915_GEM_DOMAIN_RENDER << 16 | 163703b705cfSriastradh I915_GEM_DOMAIN_RENDER | 163803b705cfSriastradh KGEM_RELOC_FENCED, 163903b705cfSriastradh 0); 164003b705cfSriastradh b[5] = add2(b[2], src_dx, src_dy); 164103b705cfSriastradh b[6] = src_pitch; 164203b705cfSriastradh b[7] = kgem_add_reloc(kgem, kgem->nbatch + 7, src_bo, 164303b705cfSriastradh I915_GEM_DOMAIN_RENDER << 16 | 164403b705cfSriastradh KGEM_RELOC_FENCED, 164503b705cfSriastradh 0); 164603b705cfSriastradh kgem->nbatch += 8; 164703b705cfSriastradh assert(kgem->nbatch < kgem->surface); 164803b705cfSriastradh box++; 164903b705cfSriastradh } while (--nbox_this_time); 165003b705cfSriastradh 165103b705cfSriastradh if (!nbox) 165203b705cfSriastradh break; 165303b705cfSriastradh 165403b705cfSriastradh _kgem_submit(kgem); 165503b705cfSriastradh _kgem_set_mode(kgem, KGEM_BLT); 165603b705cfSriastradh } while (1); 165703b705cfSriastradh } else { 165803b705cfSriastradh do { 165903b705cfSriastradh int nbox_this_time; 166003b705cfSriastradh 166103b705cfSriastradh nbox_this_time = nbox; 166203b705cfSriastradh if (8*nbox_this_time > kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) 166303b705cfSriastradh nbox_this_time = (kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) / 8; 166403b705cfSriastradh if (2*nbox_this_time > KGEM_RELOC_SIZE(kgem) - kgem->nreloc) 166503b705cfSriastradh nbox_this_time = (KGEM_RELOC_SIZE(kgem) - kgem->nreloc)/2; 166603b705cfSriastradh assert(nbox_this_time); 166703b705cfSriastradh nbox -= nbox_this_time; 166803b705cfSriastradh 166942542f5fSchristos assert(sna->kgem.mode == KGEM_BLT); 167003b705cfSriastradh do { 167103b705cfSriastradh uint32_t *b = kgem->batch + kgem->nbatch; 167203b705cfSriastradh 167303b705cfSriastradh DBG((" %s: box=(%d, %d)x(%d, %d)\n", 167403b705cfSriastradh __FUNCTION__, 167503b705cfSriastradh box->x1, box->y1, 167603b705cfSriastradh box->x2 - box->x1, box->y2 - box->y1)); 167703b705cfSriastradh 167803b705cfSriastradh assert(box->x1 + src_dx >= 0); 167903b705cfSriastradh assert(box->y1 + src_dy >= 0); 168003b705cfSriastradh 168103b705cfSriastradh assert(box->x1 + dst_dx >= 0); 168203b705cfSriastradh assert(box->y1 + dst_dy >= 0); 168303b705cfSriastradh 168403b705cfSriastradh b[0] = cmd; 168503b705cfSriastradh b[1] = br13; 168603b705cfSriastradh b[2] = ((box->y1 + dst_dy) << 16) | (box->x1 + dst_dx); 168703b705cfSriastradh b[3] = ((box->y2 + dst_dy) << 16) | (box->x2 + dst_dx); 168803b705cfSriastradh b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4, dst_bo, 168903b705cfSriastradh I915_GEM_DOMAIN_RENDER << 16 | 169003b705cfSriastradh I915_GEM_DOMAIN_RENDER | 169103b705cfSriastradh KGEM_RELOC_FENCED, 169203b705cfSriastradh 0); 169303b705cfSriastradh b[5] = ((box->y1 + src_dy) << 16) | (box->x1 + src_dx); 169403b705cfSriastradh b[6] = src_pitch; 169503b705cfSriastradh b[7] = kgem_add_reloc(kgem, kgem->nbatch + 7, src_bo, 169603b705cfSriastradh I915_GEM_DOMAIN_RENDER << 16 | 169703b705cfSriastradh KGEM_RELOC_FENCED, 169803b705cfSriastradh 0); 169903b705cfSriastradh kgem->nbatch += 8; 170003b705cfSriastradh assert(kgem->nbatch < kgem->surface); 170103b705cfSriastradh box++; 170203b705cfSriastradh } while (--nbox_this_time); 170303b705cfSriastradh 170403b705cfSriastradh if (!nbox) 170503b705cfSriastradh break; 170603b705cfSriastradh 170703b705cfSriastradh _kgem_submit(kgem); 170803b705cfSriastradh _kgem_set_mode(kgem, KGEM_BLT); 170903b705cfSriastradh } while (1); 171003b705cfSriastradh } 171103b705cfSriastradh sna_vertex_unlock(&sna->render); 171203b705cfSriastradh} 171303b705cfSriastradh 171442542f5fSchristosstatic void blt_composite_copy_boxes__thread64(struct sna *sna, 171542542f5fSchristos const struct sna_composite_op *op, 171642542f5fSchristos const BoxRec *box, int nbox) 171703b705cfSriastradh{ 171842542f5fSchristos struct kgem *kgem = &sna->kgem; 171942542f5fSchristos int dst_dx = op->dst.x; 172042542f5fSchristos int dst_dy = op->dst.y; 172142542f5fSchristos int src_dx = op->src.offset[0]; 172242542f5fSchristos int src_dy = op->src.offset[1]; 172342542f5fSchristos uint32_t cmd = op->u.blt.cmd; 172442542f5fSchristos uint32_t br13 = op->u.blt.br13; 172542542f5fSchristos struct kgem_bo *src_bo = op->u.blt.bo[0]; 172642542f5fSchristos struct kgem_bo *dst_bo = op->u.blt.bo[1]; 172742542f5fSchristos int src_pitch = op->u.blt.pitch[0]; 172803b705cfSriastradh 172942542f5fSchristos DBG(("%s: nbox=%d\n", __FUNCTION__, nbox)); 173003b705cfSriastradh 173142542f5fSchristos sna_vertex_lock(&sna->render); 173203b705cfSriastradh 173342542f5fSchristos if ((dst_dx | dst_dy) == 0) { 173442542f5fSchristos uint64_t hdr = (uint64_t)br13 << 32 | cmd; 173542542f5fSchristos do { 173642542f5fSchristos int nbox_this_time; 173703b705cfSriastradh 173842542f5fSchristos nbox_this_time = nbox; 173942542f5fSchristos if (10*nbox_this_time > kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) 174042542f5fSchristos nbox_this_time = (kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) / 10; 174142542f5fSchristos if (2*nbox_this_time > KGEM_RELOC_SIZE(kgem) - kgem->nreloc) 174242542f5fSchristos nbox_this_time = (KGEM_RELOC_SIZE(kgem) - kgem->nreloc)/2; 174342542f5fSchristos assert(nbox_this_time); 174442542f5fSchristos nbox -= nbox_this_time; 174503b705cfSriastradh 174642542f5fSchristos assert(kgem->mode == KGEM_BLT); 174742542f5fSchristos do { 174842542f5fSchristos uint32_t *b = kgem->batch + kgem->nbatch; 174903b705cfSriastradh 175042542f5fSchristos DBG((" %s: box=(%d, %d)x(%d, %d)\n", 175142542f5fSchristos __FUNCTION__, 175242542f5fSchristos box->x1, box->y1, 175342542f5fSchristos box->x2 - box->x1, box->y2 - box->y1)); 175403b705cfSriastradh 175542542f5fSchristos assert(box->x1 + src_dx >= 0); 175642542f5fSchristos assert(box->y1 + src_dy >= 0); 175742542f5fSchristos assert(box->x1 + src_dx <= INT16_MAX); 175842542f5fSchristos assert(box->y1 + src_dy <= INT16_MAX); 175903b705cfSriastradh 176042542f5fSchristos assert(box->x1 >= 0); 176142542f5fSchristos assert(box->y1 >= 0); 176203b705cfSriastradh 176342542f5fSchristos *(uint64_t *)&b[0] = hdr; 176442542f5fSchristos *(uint64_t *)&b[2] = *(const uint64_t *)box; 176542542f5fSchristos *(uint64_t *)(b+4) = 176642542f5fSchristos kgem_add_reloc64(kgem, kgem->nbatch + 4, dst_bo, 176742542f5fSchristos I915_GEM_DOMAIN_RENDER << 16 | 176842542f5fSchristos I915_GEM_DOMAIN_RENDER | 176942542f5fSchristos KGEM_RELOC_FENCED, 177042542f5fSchristos 0); 177142542f5fSchristos b[6] = add2(b[2], src_dx, src_dy); 177242542f5fSchristos b[7] = src_pitch; 177342542f5fSchristos *(uint64_t *)(b+8) = 177442542f5fSchristos kgem_add_reloc64(kgem, kgem->nbatch + 8, src_bo, 177542542f5fSchristos I915_GEM_DOMAIN_RENDER << 16 | 177642542f5fSchristos KGEM_RELOC_FENCED, 177742542f5fSchristos 0); 177842542f5fSchristos kgem->nbatch += 10; 177942542f5fSchristos assert(kgem->nbatch < kgem->surface); 178042542f5fSchristos box++; 178142542f5fSchristos } while (--nbox_this_time); 178203b705cfSriastradh 178342542f5fSchristos if (!nbox) 178442542f5fSchristos break; 178503b705cfSriastradh 178642542f5fSchristos _kgem_submit(kgem); 178742542f5fSchristos _kgem_set_mode(kgem, KGEM_BLT); 178842542f5fSchristos } while (1); 178942542f5fSchristos } else { 179042542f5fSchristos do { 179142542f5fSchristos int nbox_this_time; 179242542f5fSchristos 179342542f5fSchristos nbox_this_time = nbox; 179442542f5fSchristos if (10*nbox_this_time > kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) 179542542f5fSchristos nbox_this_time = (kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) / 10; 179642542f5fSchristos if (2*nbox_this_time > KGEM_RELOC_SIZE(kgem) - kgem->nreloc) 179742542f5fSchristos nbox_this_time = (KGEM_RELOC_SIZE(kgem) - kgem->nreloc)/2; 179842542f5fSchristos assert(nbox_this_time); 179942542f5fSchristos nbox -= nbox_this_time; 180042542f5fSchristos 180142542f5fSchristos assert(kgem->mode == KGEM_BLT); 180242542f5fSchristos do { 180342542f5fSchristos uint32_t *b = kgem->batch + kgem->nbatch; 180442542f5fSchristos 180542542f5fSchristos DBG((" %s: box=(%d, %d)x(%d, %d)\n", 180642542f5fSchristos __FUNCTION__, 180742542f5fSchristos box->x1, box->y1, 180842542f5fSchristos box->x2 - box->x1, box->y2 - box->y1)); 180942542f5fSchristos 181042542f5fSchristos assert(box->x1 + src_dx >= 0); 181142542f5fSchristos assert(box->y1 + src_dy >= 0); 181242542f5fSchristos 181342542f5fSchristos assert(box->x1 + dst_dx >= 0); 181442542f5fSchristos assert(box->y1 + dst_dy >= 0); 181542542f5fSchristos 181642542f5fSchristos b[0] = cmd; 181742542f5fSchristos b[1] = br13; 181842542f5fSchristos b[2] = ((box->y1 + dst_dy) << 16) | (box->x1 + dst_dx); 181942542f5fSchristos b[3] = ((box->y2 + dst_dy) << 16) | (box->x2 + dst_dx); 182042542f5fSchristos *(uint64_t *)(b+4) = 182142542f5fSchristos kgem_add_reloc64(kgem, kgem->nbatch + 4, dst_bo, 182242542f5fSchristos I915_GEM_DOMAIN_RENDER << 16 | 182342542f5fSchristos I915_GEM_DOMAIN_RENDER | 182442542f5fSchristos KGEM_RELOC_FENCED, 182542542f5fSchristos 0); 182642542f5fSchristos b[6] = ((box->y1 + src_dy) << 16) | (box->x1 + src_dx); 182742542f5fSchristos b[7] = src_pitch; 182842542f5fSchristos *(uint64_t *)(b+8) = 182942542f5fSchristos kgem_add_reloc64(kgem, kgem->nbatch + 8, src_bo, 183042542f5fSchristos I915_GEM_DOMAIN_RENDER << 16 | 183142542f5fSchristos KGEM_RELOC_FENCED, 183242542f5fSchristos 0); 183342542f5fSchristos kgem->nbatch += 10; 183442542f5fSchristos assert(kgem->nbatch < kgem->surface); 183542542f5fSchristos box++; 183642542f5fSchristos } while (--nbox_this_time); 183742542f5fSchristos 183842542f5fSchristos if (!nbox) 183942542f5fSchristos break; 184042542f5fSchristos 184142542f5fSchristos _kgem_submit(kgem); 184242542f5fSchristos _kgem_set_mode(kgem, KGEM_BLT); 184342542f5fSchristos } while (1); 184442542f5fSchristos } 184542542f5fSchristos sna_vertex_unlock(&sna->render); 184642542f5fSchristos} 184742542f5fSchristos 184842542f5fSchristosfastcall static void 184942542f5fSchristosblt_composite_copy_with_alpha(struct sna *sna, 185042542f5fSchristos const struct sna_composite_op *op, 185142542f5fSchristos const struct sna_composite_rectangles *r) 185242542f5fSchristos{ 185342542f5fSchristos int x1, x2, y1, y2; 185442542f5fSchristos int src_x, src_y; 185542542f5fSchristos 185642542f5fSchristos DBG(("%s: src=(%d, %d), dst=(%d, %d), size=(%d, %d)\n", 185742542f5fSchristos __FUNCTION__, 185842542f5fSchristos r->src.x, r->src.y, 185942542f5fSchristos r->dst.x, r->dst.y, 186042542f5fSchristos r->width, r->height)); 186142542f5fSchristos 186242542f5fSchristos /* XXX higher layer should have clipped? */ 186342542f5fSchristos 186442542f5fSchristos x1 = r->dst.x + op->dst.x; 186542542f5fSchristos y1 = r->dst.y + op->dst.y; 186642542f5fSchristos x2 = x1 + r->width; 186742542f5fSchristos y2 = y1 + r->height; 186842542f5fSchristos 186942542f5fSchristos src_x = r->src.x - x1 + op->u.blt.sx; 187042542f5fSchristos src_y = r->src.y - y1 + op->u.blt.sy; 187142542f5fSchristos 187242542f5fSchristos /* clip against dst */ 187342542f5fSchristos if (x1 < 0) 187442542f5fSchristos x1 = 0; 187542542f5fSchristos if (y1 < 0) 187642542f5fSchristos y1 = 0; 187742542f5fSchristos 187842542f5fSchristos if (x2 > op->dst.width) 187942542f5fSchristos x2 = op->dst.width; 188042542f5fSchristos 188142542f5fSchristos if (y2 > op->dst.height) 188242542f5fSchristos y2 = op->dst.height; 188342542f5fSchristos 188442542f5fSchristos DBG(("%s: box=(%d, %d), (%d, %d)\n", __FUNCTION__, x1, y1, x2, y2)); 188542542f5fSchristos 188642542f5fSchristos if (x2 <= x1 || y2 <= y1) 188742542f5fSchristos return; 188842542f5fSchristos 188942542f5fSchristos sna_blt_alpha_fixup_one(sna, &op->u.blt, 189042542f5fSchristos x1 + src_x, y1 + src_y, 189142542f5fSchristos x2 - x1, y2 - y1, 189242542f5fSchristos x1, y1); 189342542f5fSchristos} 189442542f5fSchristos 189542542f5fSchristosfastcall static void 189642542f5fSchristosblt_composite_copy_box_with_alpha(struct sna *sna, 189742542f5fSchristos const struct sna_composite_op *op, 189842542f5fSchristos const BoxRec *box) 189942542f5fSchristos{ 190042542f5fSchristos DBG(("%s: box (%d, %d), (%d, %d)\n", 190142542f5fSchristos __FUNCTION__, box->x1, box->y1, box->x2, box->y2)); 190242542f5fSchristos sna_blt_alpha_fixup_one(sna, &op->u.blt, 190342542f5fSchristos box->x1 + op->u.blt.sx, 190442542f5fSchristos box->y1 + op->u.blt.sy, 190542542f5fSchristos box->x2 - box->x1, 190642542f5fSchristos box->y2 - box->y1, 190742542f5fSchristos box->x1 + op->dst.x, 190842542f5fSchristos box->y1 + op->dst.y); 190942542f5fSchristos} 191042542f5fSchristos 191142542f5fSchristosstatic void 191242542f5fSchristosblt_composite_copy_boxes_with_alpha(struct sna *sna, 191342542f5fSchristos const struct sna_composite_op *op, 191442542f5fSchristos const BoxRec *box, int nbox) 191503b705cfSriastradh{ 191603b705cfSriastradh DBG(("%s: nbox=%d\n", __FUNCTION__, nbox)); 191703b705cfSriastradh do { 191803b705cfSriastradh DBG(("%s: box (%d, %d), (%d, %d)\n", 191903b705cfSriastradh __FUNCTION__, box->x1, box->y1, box->x2, box->y2)); 192003b705cfSriastradh sna_blt_alpha_fixup_one(sna, &op->u.blt, 192103b705cfSriastradh box->x1 + op->u.blt.sx, box->y1 + op->u.blt.sy, 192203b705cfSriastradh box->x2 - box->x1, box->y2 - box->y1, 192303b705cfSriastradh box->x1 + op->dst.x, box->y1 + op->dst.y); 192403b705cfSriastradh box++; 192503b705cfSriastradh } while(--nbox); 192603b705cfSriastradh} 192703b705cfSriastradh 192803b705cfSriastradhstatic bool 192903b705cfSriastradhprepare_blt_copy(struct sna *sna, 193003b705cfSriastradh struct sna_composite_op *op, 193103b705cfSriastradh struct kgem_bo *bo, 193203b705cfSriastradh uint32_t alpha_fixup) 193303b705cfSriastradh{ 193403b705cfSriastradh PixmapPtr src = op->u.blt.src_pixmap; 193503b705cfSriastradh 193603b705cfSriastradh assert(op->dst.bo); 193703b705cfSriastradh assert(kgem_bo_can_blt(&sna->kgem, op->dst.bo)); 193803b705cfSriastradh assert(kgem_bo_can_blt(&sna->kgem, bo)); 193903b705cfSriastradh 194042542f5fSchristos kgem_set_mode(&sna->kgem, KGEM_BLT, op->dst.bo); 194103b705cfSriastradh if (!kgem_check_many_bo_fenced(&sna->kgem, op->dst.bo, bo, NULL)) { 194203b705cfSriastradh kgem_submit(&sna->kgem); 194303b705cfSriastradh if (!kgem_check_many_bo_fenced(&sna->kgem, 194403b705cfSriastradh op->dst.bo, bo, NULL)) { 194503b705cfSriastradh DBG(("%s: fallback -- no room in aperture\n", __FUNCTION__)); 194642542f5fSchristos return sna_tiling_blt_composite(sna, op, bo, 194742542f5fSchristos src->drawable.bitsPerPixel, 194842542f5fSchristos alpha_fixup); 194903b705cfSriastradh } 195003b705cfSriastradh _kgem_set_mode(&sna->kgem, KGEM_BLT); 195103b705cfSriastradh } 195203b705cfSriastradh 195303b705cfSriastradh DBG(("%s\n", __FUNCTION__)); 195403b705cfSriastradh 195503b705cfSriastradh if (sna->kgem.gen >= 060 && op->dst.bo == bo) 195603b705cfSriastradh op->done = gen6_blt_copy_done; 195703b705cfSriastradh else 195803b705cfSriastradh op->done = nop_done; 195903b705cfSriastradh 196003b705cfSriastradh if (alpha_fixup) { 196103b705cfSriastradh op->blt = blt_composite_copy_with_alpha; 196203b705cfSriastradh op->box = blt_composite_copy_box_with_alpha; 196303b705cfSriastradh op->boxes = blt_composite_copy_boxes_with_alpha; 196403b705cfSriastradh 196503b705cfSriastradh if (!sna_blt_alpha_fixup_init(sna, &op->u.blt, bo, op->dst.bo, 196603b705cfSriastradh src->drawable.bitsPerPixel, 196703b705cfSriastradh alpha_fixup)) 196803b705cfSriastradh return false; 196903b705cfSriastradh } else { 197003b705cfSriastradh op->blt = blt_composite_copy; 197103b705cfSriastradh op->box = blt_composite_copy_box; 197203b705cfSriastradh op->boxes = blt_composite_copy_boxes; 197342542f5fSchristos if (sna->kgem.gen >= 0100) 197442542f5fSchristos op->thread_boxes = blt_composite_copy_boxes__thread64; 197542542f5fSchristos else 197642542f5fSchristos op->thread_boxes = blt_composite_copy_boxes__thread; 197703b705cfSriastradh 197803b705cfSriastradh if (!sna_blt_copy_init(sna, &op->u.blt, bo, op->dst.bo, 197903b705cfSriastradh src->drawable.bitsPerPixel, 198003b705cfSriastradh GXcopy)) 198103b705cfSriastradh return false; 198203b705cfSriastradh } 198303b705cfSriastradh 198403b705cfSriastradh return true; 198503b705cfSriastradh} 198603b705cfSriastradh 198703b705cfSriastradhfastcall static void 198803b705cfSriastradhblt_put_composite__cpu(struct sna *sna, 198903b705cfSriastradh const struct sna_composite_op *op, 199003b705cfSriastradh const struct sna_composite_rectangles *r) 199103b705cfSriastradh{ 199203b705cfSriastradh PixmapPtr dst = op->dst.pixmap; 199303b705cfSriastradh PixmapPtr src = op->u.blt.src_pixmap; 199442542f5fSchristos assert(src->devPrivate.ptr); 199542542f5fSchristos assert(src->devKind); 199642542f5fSchristos assert(dst->devPrivate.ptr); 199742542f5fSchristos assert(dst->devKind); 199803b705cfSriastradh memcpy_blt(src->devPrivate.ptr, dst->devPrivate.ptr, 199903b705cfSriastradh src->drawable.bitsPerPixel, src->devKind, dst->devKind, 200003b705cfSriastradh r->src.x + op->u.blt.sx, r->src.y + op->u.blt.sy, 200103b705cfSriastradh r->dst.x + op->dst.x, r->dst.y + op->dst.y, 200203b705cfSriastradh r->width, r->height); 200303b705cfSriastradh} 200403b705cfSriastradh 200503b705cfSriastradhfastcall static void 200603b705cfSriastradhblt_put_composite_box__cpu(struct sna *sna, 200703b705cfSriastradh const struct sna_composite_op *op, 200803b705cfSriastradh const BoxRec *box) 200903b705cfSriastradh{ 201003b705cfSriastradh PixmapPtr dst = op->dst.pixmap; 201103b705cfSriastradh PixmapPtr src = op->u.blt.src_pixmap; 201242542f5fSchristos assert(src->devPrivate.ptr); 201342542f5fSchristos assert(src->devKind); 201442542f5fSchristos assert(dst->devPrivate.ptr); 201542542f5fSchristos assert(dst->devKind); 201603b705cfSriastradh memcpy_blt(src->devPrivate.ptr, dst->devPrivate.ptr, 201703b705cfSriastradh src->drawable.bitsPerPixel, src->devKind, dst->devKind, 201803b705cfSriastradh box->x1 + op->u.blt.sx, box->y1 + op->u.blt.sy, 201903b705cfSriastradh box->x1 + op->dst.x, box->y1 + op->dst.y, 202003b705cfSriastradh box->x2-box->x1, box->y2-box->y1); 202103b705cfSriastradh} 202203b705cfSriastradh 202303b705cfSriastradhstatic void 202403b705cfSriastradhblt_put_composite_boxes__cpu(struct sna *sna, 202503b705cfSriastradh const struct sna_composite_op *op, 202603b705cfSriastradh const BoxRec *box, int n) 202703b705cfSriastradh{ 202803b705cfSriastradh PixmapPtr dst = op->dst.pixmap; 202903b705cfSriastradh PixmapPtr src = op->u.blt.src_pixmap; 203042542f5fSchristos assert(src->devPrivate.ptr); 203142542f5fSchristos assert(src->devKind); 203242542f5fSchristos assert(dst->devPrivate.ptr); 203342542f5fSchristos assert(dst->devKind); 203403b705cfSriastradh do { 203503b705cfSriastradh memcpy_blt(src->devPrivate.ptr, dst->devPrivate.ptr, 203603b705cfSriastradh src->drawable.bitsPerPixel, src->devKind, dst->devKind, 203703b705cfSriastradh box->x1 + op->u.blt.sx, box->y1 + op->u.blt.sy, 203803b705cfSriastradh box->x1 + op->dst.x, box->y1 + op->dst.y, 203903b705cfSriastradh box->x2-box->x1, box->y2-box->y1); 204003b705cfSriastradh box++; 204103b705cfSriastradh } while (--n); 204203b705cfSriastradh} 204303b705cfSriastradh 204403b705cfSriastradhfastcall static void 204503b705cfSriastradhblt_put_composite_with_alpha__cpu(struct sna *sna, 204603b705cfSriastradh const struct sna_composite_op *op, 204703b705cfSriastradh const struct sna_composite_rectangles *r) 204803b705cfSriastradh{ 204903b705cfSriastradh PixmapPtr dst = op->dst.pixmap; 205003b705cfSriastradh PixmapPtr src = op->u.blt.src_pixmap; 205142542f5fSchristos assert(src->devPrivate.ptr); 205242542f5fSchristos assert(src->devKind); 205342542f5fSchristos assert(dst->devPrivate.ptr); 205442542f5fSchristos assert(dst->devKind); 205503b705cfSriastradh memcpy_xor(src->devPrivate.ptr, dst->devPrivate.ptr, 205603b705cfSriastradh src->drawable.bitsPerPixel, src->devKind, dst->devKind, 205703b705cfSriastradh r->src.x + op->u.blt.sx, r->src.y + op->u.blt.sy, 205803b705cfSriastradh r->dst.x + op->dst.x, r->dst.y + op->dst.y, 205903b705cfSriastradh r->width, r->height, 206003b705cfSriastradh 0xffffffff, op->u.blt.pixel); 206103b705cfSriastradh 206203b705cfSriastradh} 206303b705cfSriastradh 206403b705cfSriastradhfastcall static void 206503b705cfSriastradhblt_put_composite_box_with_alpha__cpu(struct sna *sna, 206603b705cfSriastradh const struct sna_composite_op *op, 206703b705cfSriastradh const BoxRec *box) 206803b705cfSriastradh{ 206903b705cfSriastradh PixmapPtr dst = op->dst.pixmap; 207003b705cfSriastradh PixmapPtr src = op->u.blt.src_pixmap; 207142542f5fSchristos assert(src->devPrivate.ptr); 207242542f5fSchristos assert(src->devKind); 207342542f5fSchristos assert(dst->devPrivate.ptr); 207442542f5fSchristos assert(dst->devKind); 207503b705cfSriastradh memcpy_xor(src->devPrivate.ptr, dst->devPrivate.ptr, 207603b705cfSriastradh src->drawable.bitsPerPixel, src->devKind, dst->devKind, 207703b705cfSriastradh box->x1 + op->u.blt.sx, box->y1 + op->u.blt.sy, 207803b705cfSriastradh box->x1 + op->dst.x, box->y1 + op->dst.y, 207903b705cfSriastradh box->x2-box->x1, box->y2-box->y1, 208003b705cfSriastradh 0xffffffff, op->u.blt.pixel); 208103b705cfSriastradh} 208203b705cfSriastradh 208303b705cfSriastradhstatic void 208403b705cfSriastradhblt_put_composite_boxes_with_alpha__cpu(struct sna *sna, 208503b705cfSriastradh const struct sna_composite_op *op, 208603b705cfSriastradh const BoxRec *box, int n) 208703b705cfSriastradh{ 208803b705cfSriastradh PixmapPtr dst = op->dst.pixmap; 208903b705cfSriastradh PixmapPtr src = op->u.blt.src_pixmap; 209042542f5fSchristos assert(src->devPrivate.ptr); 209142542f5fSchristos assert(src->devKind); 209242542f5fSchristos assert(dst->devPrivate.ptr); 209342542f5fSchristos assert(dst->devKind); 209403b705cfSriastradh do { 209503b705cfSriastradh memcpy_xor(src->devPrivate.ptr, dst->devPrivate.ptr, 209603b705cfSriastradh src->drawable.bitsPerPixel, src->devKind, dst->devKind, 209703b705cfSriastradh box->x1 + op->u.blt.sx, box->y1 + op->u.blt.sy, 209803b705cfSriastradh box->x1 + op->dst.x, box->y1 + op->dst.y, 209903b705cfSriastradh box->x2-box->x1, box->y2-box->y1, 210003b705cfSriastradh 0xffffffff, op->u.blt.pixel); 210103b705cfSriastradh box++; 210203b705cfSriastradh } while (--n); 210303b705cfSriastradh} 210403b705cfSriastradh 210503b705cfSriastradhfastcall static void 210603b705cfSriastradhblt_put_composite(struct sna *sna, 210703b705cfSriastradh const struct sna_composite_op *op, 210803b705cfSriastradh const struct sna_composite_rectangles *r) 210903b705cfSriastradh{ 211003b705cfSriastradh PixmapPtr dst = op->dst.pixmap; 211103b705cfSriastradh PixmapPtr src = op->u.blt.src_pixmap; 211203b705cfSriastradh struct sna_pixmap *dst_priv = sna_pixmap(dst); 211303b705cfSriastradh int pitch = src->devKind; 211403b705cfSriastradh char *data = src->devPrivate.ptr; 211503b705cfSriastradh int bpp = src->drawable.bitsPerPixel; 211603b705cfSriastradh 211703b705cfSriastradh int16_t dst_x = r->dst.x + op->dst.x; 211803b705cfSriastradh int16_t dst_y = r->dst.y + op->dst.y; 211903b705cfSriastradh int16_t src_x = r->src.x + op->u.blt.sx; 212003b705cfSriastradh int16_t src_y = r->src.y + op->u.blt.sy; 212103b705cfSriastradh 212203b705cfSriastradh if (!dst_priv->pinned && 212303b705cfSriastradh dst_x <= 0 && dst_y <= 0 && 212403b705cfSriastradh dst_x + r->width >= op->dst.width && 212503b705cfSriastradh dst_y + r->height >= op->dst.height) { 212603b705cfSriastradh data += (src_x - dst_x) * bpp / 8; 212703b705cfSriastradh data += (src_y - dst_y) * pitch; 212803b705cfSriastradh 212942542f5fSchristos assert(op->dst.bo == dst_priv->gpu_bo); 213042542f5fSchristos sna_replace(sna, op->dst.pixmap, data, pitch); 213103b705cfSriastradh } else { 213203b705cfSriastradh BoxRec box; 213303b705cfSriastradh bool ok; 213403b705cfSriastradh 213503b705cfSriastradh box.x1 = dst_x; 213603b705cfSriastradh box.y1 = dst_y; 213703b705cfSriastradh box.x2 = dst_x + r->width; 213803b705cfSriastradh box.y2 = dst_y + r->height; 213903b705cfSriastradh 214003b705cfSriastradh ok = sna_write_boxes(sna, dst, 214103b705cfSriastradh dst_priv->gpu_bo, 0, 0, 214203b705cfSriastradh data, pitch, src_x, src_y, 214303b705cfSriastradh &box, 1); 214403b705cfSriastradh assert(ok); 214503b705cfSriastradh (void)ok; 214603b705cfSriastradh } 214703b705cfSriastradh} 214803b705cfSriastradh 214903b705cfSriastradhfastcall static void blt_put_composite_box(struct sna *sna, 215003b705cfSriastradh const struct sna_composite_op *op, 215103b705cfSriastradh const BoxRec *box) 215203b705cfSriastradh{ 215303b705cfSriastradh PixmapPtr src = op->u.blt.src_pixmap; 215403b705cfSriastradh struct sna_pixmap *dst_priv = sna_pixmap(op->dst.pixmap); 215503b705cfSriastradh 215603b705cfSriastradh DBG(("%s: src=(%d, %d), dst=(%d, %d)\n", __FUNCTION__, 215703b705cfSriastradh op->u.blt.sx, op->u.blt.sy, 215803b705cfSriastradh op->dst.x, op->dst.y)); 215903b705cfSriastradh 216042542f5fSchristos assert(src->devPrivate.ptr); 216142542f5fSchristos assert(src->devKind); 216203b705cfSriastradh if (!dst_priv->pinned && 216303b705cfSriastradh box->x2 - box->x1 == op->dst.width && 216403b705cfSriastradh box->y2 - box->y1 == op->dst.height) { 216503b705cfSriastradh int pitch = src->devKind; 216603b705cfSriastradh int bpp = src->drawable.bitsPerPixel / 8; 216703b705cfSriastradh char *data = src->devPrivate.ptr; 216803b705cfSriastradh 216903b705cfSriastradh data += (box->y1 + op->u.blt.sy) * pitch; 217003b705cfSriastradh data += (box->x1 + op->u.blt.sx) * bpp; 217103b705cfSriastradh 217242542f5fSchristos assert(op->dst.bo == dst_priv->gpu_bo); 217342542f5fSchristos sna_replace(sna, op->dst.pixmap, data, pitch); 217403b705cfSriastradh } else { 217503b705cfSriastradh bool ok; 217603b705cfSriastradh 217703b705cfSriastradh ok = sna_write_boxes(sna, op->dst.pixmap, 217803b705cfSriastradh op->dst.bo, op->dst.x, op->dst.y, 217903b705cfSriastradh src->devPrivate.ptr, 218003b705cfSriastradh src->devKind, 218103b705cfSriastradh op->u.blt.sx, op->u.blt.sy, 218203b705cfSriastradh box, 1); 218303b705cfSriastradh assert(ok); 218403b705cfSriastradh (void)ok; 218503b705cfSriastradh } 218603b705cfSriastradh} 218703b705cfSriastradh 218803b705cfSriastradhstatic void blt_put_composite_boxes(struct sna *sna, 218903b705cfSriastradh const struct sna_composite_op *op, 219003b705cfSriastradh const BoxRec *box, int n) 219103b705cfSriastradh{ 219203b705cfSriastradh PixmapPtr src = op->u.blt.src_pixmap; 219303b705cfSriastradh struct sna_pixmap *dst_priv = sna_pixmap(op->dst.pixmap); 219403b705cfSriastradh 219503b705cfSriastradh DBG(("%s: src=(%d, %d), dst=(%d, %d), [(%d, %d), (%d, %d) x %d]\n", __FUNCTION__, 219603b705cfSriastradh op->u.blt.sx, op->u.blt.sy, 219703b705cfSriastradh op->dst.x, op->dst.y, 219803b705cfSriastradh box->x1, box->y1, box->x2, box->y2, n)); 219903b705cfSriastradh 220042542f5fSchristos assert(src->devPrivate.ptr); 220142542f5fSchristos assert(src->devKind); 220203b705cfSriastradh if (n == 1 && !dst_priv->pinned && 220303b705cfSriastradh box->x2 - box->x1 == op->dst.width && 220403b705cfSriastradh box->y2 - box->y1 == op->dst.height) { 220503b705cfSriastradh int pitch = src->devKind; 220603b705cfSriastradh int bpp = src->drawable.bitsPerPixel / 8; 220703b705cfSriastradh char *data = src->devPrivate.ptr; 220803b705cfSriastradh 220903b705cfSriastradh data += (box->y1 + op->u.blt.sy) * pitch; 221003b705cfSriastradh data += (box->x1 + op->u.blt.sx) * bpp; 221103b705cfSriastradh 221242542f5fSchristos assert(op->dst.bo == dst_priv->gpu_bo); 221342542f5fSchristos sna_replace(sna, op->dst.pixmap, data, pitch); 221403b705cfSriastradh } else { 221503b705cfSriastradh bool ok; 221603b705cfSriastradh 221703b705cfSriastradh ok = sna_write_boxes(sna, op->dst.pixmap, 221803b705cfSriastradh op->dst.bo, op->dst.x, op->dst.y, 221903b705cfSriastradh src->devPrivate.ptr, 222003b705cfSriastradh src->devKind, 222103b705cfSriastradh op->u.blt.sx, op->u.blt.sy, 222203b705cfSriastradh box, n); 222303b705cfSriastradh assert(ok); 222403b705cfSriastradh (void)ok; 222503b705cfSriastradh } 222603b705cfSriastradh} 222703b705cfSriastradh 222803b705cfSriastradhfastcall static void 222903b705cfSriastradhblt_put_composite_with_alpha(struct sna *sna, 223003b705cfSriastradh const struct sna_composite_op *op, 223103b705cfSriastradh const struct sna_composite_rectangles *r) 223203b705cfSriastradh{ 223303b705cfSriastradh PixmapPtr dst = op->dst.pixmap; 223403b705cfSriastradh PixmapPtr src = op->u.blt.src_pixmap; 223503b705cfSriastradh struct sna_pixmap *dst_priv = sna_pixmap(dst); 223603b705cfSriastradh int pitch = src->devKind; 223703b705cfSriastradh char *data = src->devPrivate.ptr; 223803b705cfSriastradh 223903b705cfSriastradh int16_t dst_x = r->dst.x + op->dst.x; 224003b705cfSriastradh int16_t dst_y = r->dst.y + op->dst.y; 224103b705cfSriastradh int16_t src_x = r->src.x + op->u.blt.sx; 224203b705cfSriastradh int16_t src_y = r->src.y + op->u.blt.sy; 224303b705cfSriastradh 224442542f5fSchristos assert(src->devPrivate.ptr); 224542542f5fSchristos assert(src->devKind); 224642542f5fSchristos 224703b705cfSriastradh if (!dst_priv->pinned && 224803b705cfSriastradh dst_x <= 0 && dst_y <= 0 && 224903b705cfSriastradh dst_x + r->width >= op->dst.width && 225003b705cfSriastradh dst_y + r->height >= op->dst.height) { 225103b705cfSriastradh int bpp = dst->drawable.bitsPerPixel / 8; 225203b705cfSriastradh 225303b705cfSriastradh data += (src_x - dst_x) * bpp; 225403b705cfSriastradh data += (src_y - dst_y) * pitch; 225503b705cfSriastradh 225642542f5fSchristos assert(op->dst.bo == dst_priv->gpu_bo); 225742542f5fSchristos sna_replace__xor(sna, op->dst.pixmap, data, pitch, 225842542f5fSchristos 0xffffffff, op->u.blt.pixel); 225903b705cfSriastradh } else { 226003b705cfSriastradh BoxRec box; 226103b705cfSriastradh 226203b705cfSriastradh box.x1 = dst_x; 226303b705cfSriastradh box.y1 = dst_y; 226403b705cfSriastradh box.x2 = dst_x + r->width; 226503b705cfSriastradh box.y2 = dst_y + r->height; 226603b705cfSriastradh 226703b705cfSriastradh sna_write_boxes__xor(sna, dst, 226803b705cfSriastradh dst_priv->gpu_bo, 0, 0, 226903b705cfSriastradh data, pitch, src_x, src_y, 227003b705cfSriastradh &box, 1, 227103b705cfSriastradh 0xffffffff, op->u.blt.pixel); 227203b705cfSriastradh } 227303b705cfSriastradh} 227403b705cfSriastradh 227503b705cfSriastradhfastcall static void 227603b705cfSriastradhblt_put_composite_box_with_alpha(struct sna *sna, 227703b705cfSriastradh const struct sna_composite_op *op, 227803b705cfSriastradh const BoxRec *box) 227903b705cfSriastradh{ 228003b705cfSriastradh PixmapPtr src = op->u.blt.src_pixmap; 228103b705cfSriastradh struct sna_pixmap *dst_priv = sna_pixmap(op->dst.pixmap); 228203b705cfSriastradh 228303b705cfSriastradh DBG(("%s: src=(%d, %d), dst=(%d, %d)\n", __FUNCTION__, 228403b705cfSriastradh op->u.blt.sx, op->u.blt.sy, 228503b705cfSriastradh op->dst.x, op->dst.y)); 228603b705cfSriastradh 228742542f5fSchristos assert(src->devPrivate.ptr); 228842542f5fSchristos assert(src->devKind); 228942542f5fSchristos 229003b705cfSriastradh if (!dst_priv->pinned && 229103b705cfSriastradh box->x2 - box->x1 == op->dst.width && 229203b705cfSriastradh box->y2 - box->y1 == op->dst.height) { 229303b705cfSriastradh int pitch = src->devKind; 229403b705cfSriastradh int bpp = src->drawable.bitsPerPixel / 8; 229503b705cfSriastradh char *data = src->devPrivate.ptr; 229603b705cfSriastradh 229703b705cfSriastradh data += (box->y1 + op->u.blt.sy) * pitch; 229803b705cfSriastradh data += (box->x1 + op->u.blt.sx) * bpp; 229903b705cfSriastradh 230042542f5fSchristos assert(op->dst.bo == dst_priv->gpu_bo); 230142542f5fSchristos sna_replace__xor(sna, op->dst.pixmap, data, pitch, 230242542f5fSchristos 0xffffffff, op->u.blt.pixel); 230303b705cfSriastradh } else { 230403b705cfSriastradh sna_write_boxes__xor(sna, op->dst.pixmap, 230503b705cfSriastradh op->dst.bo, op->dst.x, op->dst.y, 230603b705cfSriastradh src->devPrivate.ptr, 230703b705cfSriastradh src->devKind, 230803b705cfSriastradh op->u.blt.sx, op->u.blt.sy, 230903b705cfSriastradh box, 1, 231003b705cfSriastradh 0xffffffff, op->u.blt.pixel); 231103b705cfSriastradh } 231203b705cfSriastradh} 231303b705cfSriastradh 231403b705cfSriastradhstatic void 231503b705cfSriastradhblt_put_composite_boxes_with_alpha(struct sna *sna, 231603b705cfSriastradh const struct sna_composite_op *op, 231703b705cfSriastradh const BoxRec *box, int n) 231803b705cfSriastradh{ 231903b705cfSriastradh PixmapPtr src = op->u.blt.src_pixmap; 232003b705cfSriastradh struct sna_pixmap *dst_priv = sna_pixmap(op->dst.pixmap); 232103b705cfSriastradh 232203b705cfSriastradh DBG(("%s: src=(%d, %d), dst=(%d, %d), [(%d, %d), (%d, %d) x %d]\n", __FUNCTION__, 232303b705cfSriastradh op->u.blt.sx, op->u.blt.sy, 232403b705cfSriastradh op->dst.x, op->dst.y, 232503b705cfSriastradh box->x1, box->y1, box->x2, box->y2, n)); 232603b705cfSriastradh 232742542f5fSchristos assert(src->devPrivate.ptr); 232842542f5fSchristos assert(src->devKind); 232942542f5fSchristos 233003b705cfSriastradh if (n == 1 && !dst_priv->pinned && 233103b705cfSriastradh box->x2 - box->x1 == op->dst.width && 233203b705cfSriastradh box->y2 - box->y1 == op->dst.height) { 233303b705cfSriastradh int pitch = src->devKind; 233403b705cfSriastradh int bpp = src->drawable.bitsPerPixel / 8; 233503b705cfSriastradh char *data = src->devPrivate.ptr; 233603b705cfSriastradh 233703b705cfSriastradh data += (box->y1 + op->u.blt.sy) * pitch; 233803b705cfSriastradh data += (box->x1 + op->u.blt.sx) * bpp; 233903b705cfSriastradh 234042542f5fSchristos assert(dst_priv->gpu_bo == op->dst.bo); 234142542f5fSchristos sna_replace__xor(sna, op->dst.pixmap, data, pitch, 234242542f5fSchristos 0xffffffff, op->u.blt.pixel); 234303b705cfSriastradh } else { 234403b705cfSriastradh sna_write_boxes__xor(sna, op->dst.pixmap, 234503b705cfSriastradh op->dst.bo, op->dst.x, op->dst.y, 234603b705cfSriastradh src->devPrivate.ptr, 234703b705cfSriastradh src->devKind, 234803b705cfSriastradh op->u.blt.sx, op->u.blt.sy, 234903b705cfSriastradh box, n, 235003b705cfSriastradh 0xffffffff, op->u.blt.pixel); 235103b705cfSriastradh } 235203b705cfSriastradh} 235303b705cfSriastradh 235403b705cfSriastradhstatic bool 235503b705cfSriastradhprepare_blt_put(struct sna *sna, 235603b705cfSriastradh struct sna_composite_op *op, 235703b705cfSriastradh uint32_t alpha_fixup) 235803b705cfSriastradh{ 235903b705cfSriastradh DBG(("%s\n", __FUNCTION__)); 236003b705cfSriastradh 236142542f5fSchristos assert(!sna_pixmap(op->dst.pixmap)->clear); 236242542f5fSchristos 236303b705cfSriastradh if (op->dst.bo) { 236403b705cfSriastradh assert(op->dst.bo == sna_pixmap(op->dst.pixmap)->gpu_bo); 236503b705cfSriastradh if (alpha_fixup) { 236603b705cfSriastradh op->u.blt.pixel = alpha_fixup; 236703b705cfSriastradh op->blt = blt_put_composite_with_alpha; 236803b705cfSriastradh op->box = blt_put_composite_box_with_alpha; 236903b705cfSriastradh op->boxes = blt_put_composite_boxes_with_alpha; 237003b705cfSriastradh } else { 237103b705cfSriastradh op->blt = blt_put_composite; 237203b705cfSriastradh op->box = blt_put_composite_box; 237303b705cfSriastradh op->boxes = blt_put_composite_boxes; 237403b705cfSriastradh } 237503b705cfSriastradh } else { 237603b705cfSriastradh if (alpha_fixup) { 237703b705cfSriastradh op->u.blt.pixel = alpha_fixup; 237803b705cfSriastradh op->blt = blt_put_composite_with_alpha__cpu; 237903b705cfSriastradh op->box = blt_put_composite_box_with_alpha__cpu; 238003b705cfSriastradh op->boxes = blt_put_composite_boxes_with_alpha__cpu; 238103b705cfSriastradh } else { 238203b705cfSriastradh op->blt = blt_put_composite__cpu; 238303b705cfSriastradh op->box = blt_put_composite_box__cpu; 238403b705cfSriastradh op->boxes = blt_put_composite_boxes__cpu; 238503b705cfSriastradh } 238603b705cfSriastradh } 238703b705cfSriastradh op->done = nop_done; 238803b705cfSriastradh 238903b705cfSriastradh return true; 239003b705cfSriastradh} 239103b705cfSriastradh 239203b705cfSriastradhstatic bool 239303b705cfSriastradhis_clear(PixmapPtr pixmap) 239403b705cfSriastradh{ 239503b705cfSriastradh struct sna_pixmap *priv = sna_pixmap(pixmap); 239603b705cfSriastradh return priv && priv->clear; 239703b705cfSriastradh} 239803b705cfSriastradh 239942542f5fSchristosstatic inline uint32_t 240042542f5fSchristosover(uint32_t src, uint32_t dst) 240142542f5fSchristos{ 240242542f5fSchristos uint32_t a = ~src >> 24; 240342542f5fSchristos 240442542f5fSchristos#define G_SHIFT 8 240542542f5fSchristos#define RB_MASK 0xff00ff 240642542f5fSchristos#define RB_ONE_HALF 0x800080 240742542f5fSchristos#define RB_MASK_PLUS_ONE 0x10000100 240842542f5fSchristos 240942542f5fSchristos#define UN8_rb_MUL_UN8(x, a, t) do { \ 241042542f5fSchristos t = ((x) & RB_MASK) * (a); \ 241142542f5fSchristos t += RB_ONE_HALF; \ 241242542f5fSchristos x = (t + ((t >> G_SHIFT) & RB_MASK)) >> G_SHIFT; \ 241342542f5fSchristos x &= RB_MASK; \ 241442542f5fSchristos} while (0) 241542542f5fSchristos 241642542f5fSchristos#define UN8_rb_ADD_UN8_rb(x, y, t) do { \ 241742542f5fSchristos t = ((x) + (y)); \ 241842542f5fSchristos t |= RB_MASK_PLUS_ONE - ((t >> G_SHIFT) & RB_MASK); \ 241942542f5fSchristos x = (t & RB_MASK); \ 242042542f5fSchristos} while (0) 242142542f5fSchristos 242242542f5fSchristos#define UN8x4_MUL_UN8_ADD_UN8x4(x, a, y) do { \ 242342542f5fSchristos uint32_t r1__, r2__, r3__, t__; \ 242442542f5fSchristos \ 242542542f5fSchristos r1__ = (x); \ 242642542f5fSchristos r2__ = (y) & RB_MASK; \ 242742542f5fSchristos UN8_rb_MUL_UN8(r1__, (a), t__); \ 242842542f5fSchristos UN8_rb_ADD_UN8_rb(r1__, r2__, t__); \ 242942542f5fSchristos \ 243042542f5fSchristos r2__ = (x) >> G_SHIFT; \ 243142542f5fSchristos r3__ = ((y) >> G_SHIFT) & RB_MASK; \ 243242542f5fSchristos UN8_rb_MUL_UN8(r2__, (a), t__); \ 243342542f5fSchristos UN8_rb_ADD_UN8_rb(r2__, r3__, t__); \ 243442542f5fSchristos \ 243542542f5fSchristos (x) = r1__ | (r2__ << G_SHIFT); \ 243642542f5fSchristos} while (0) 243742542f5fSchristos 243842542f5fSchristos UN8x4_MUL_UN8_ADD_UN8x4(dst, a, src); 243942542f5fSchristos 244042542f5fSchristos return dst; 244142542f5fSchristos} 244242542f5fSchristos 244342542f5fSchristosstatic inline uint32_t 244442542f5fSchristosadd(uint32_t src, uint32_t dst) 244542542f5fSchristos{ 244642542f5fSchristos#define UN8x4_ADD_UN8x4(x, y) do { \ 244742542f5fSchristos uint32_t r1__, r2__, r3__, t__; \ 244842542f5fSchristos \ 244942542f5fSchristos r1__ = (x) & RB_MASK; \ 245042542f5fSchristos r2__ = (y) & RB_MASK; \ 245142542f5fSchristos UN8_rb_ADD_UN8_rb(r1__, r2__, t__); \ 245242542f5fSchristos \ 245342542f5fSchristos r2__ = ((x) >> G_SHIFT) & RB_MASK; \ 245442542f5fSchristos r3__ = ((y) >> G_SHIFT) & RB_MASK; \ 245542542f5fSchristos UN8_rb_ADD_UN8_rb(r2__, r3__, t__); \ 245642542f5fSchristos \ 245742542f5fSchristos x = r1__ | (r2__ << G_SHIFT); \ 245842542f5fSchristos} while (0) 245942542f5fSchristos 246042542f5fSchristos UN8x4_ADD_UN8x4(src, dst); 246142542f5fSchristos return src; 246242542f5fSchristos} 246342542f5fSchristos 246403b705cfSriastradhbool 246503b705cfSriastradhsna_blt_composite(struct sna *sna, 246603b705cfSriastradh uint32_t op, 246703b705cfSriastradh PicturePtr src, 246803b705cfSriastradh PicturePtr dst, 246903b705cfSriastradh int16_t x, int16_t y, 247003b705cfSriastradh int16_t dst_x, int16_t dst_y, 247103b705cfSriastradh int16_t width, int16_t height, 247242542f5fSchristos unsigned flags, 247342542f5fSchristos struct sna_composite_op *tmp) 247403b705cfSriastradh{ 247503b705cfSriastradh PictFormat src_format = src->format; 247603b705cfSriastradh PixmapPtr src_pixmap; 247703b705cfSriastradh struct kgem_bo *bo; 247803b705cfSriastradh int16_t tx, ty; 247903b705cfSriastradh BoxRec dst_box, src_box; 248003b705cfSriastradh uint32_t alpha_fixup; 248103b705cfSriastradh uint32_t color, hint; 248203b705cfSriastradh bool was_clear; 248303b705cfSriastradh bool ret; 248403b705cfSriastradh 248503b705cfSriastradh#if DEBUG_NO_BLT || NO_BLT_COMPOSITE 248603b705cfSriastradh return false; 248703b705cfSriastradh#endif 248803b705cfSriastradh DBG(("%s (%d, %d), (%d, %d), %dx%d\n", 248903b705cfSriastradh __FUNCTION__, x, y, dst_x, dst_y, width, height)); 249003b705cfSriastradh 249103b705cfSriastradh switch (dst->pDrawable->bitsPerPixel) { 249203b705cfSriastradh case 8: 249303b705cfSriastradh case 16: 249403b705cfSriastradh case 32: 249503b705cfSriastradh break; 249603b705cfSriastradh default: 249703b705cfSriastradh DBG(("%s: unhandled bpp: %d\n", __FUNCTION__, 249803b705cfSriastradh dst->pDrawable->bitsPerPixel)); 249903b705cfSriastradh return false; 250003b705cfSriastradh } 250103b705cfSriastradh 250203b705cfSriastradh tmp->dst.pixmap = get_drawable_pixmap(dst->pDrawable); 250342542f5fSchristos was_clear = is_clear(tmp->dst.pixmap); 250403b705cfSriastradh 250503b705cfSriastradh if (width | height) { 250603b705cfSriastradh dst_box.x1 = dst_x; 250703b705cfSriastradh dst_box.x2 = bound(dst_x, width); 250803b705cfSriastradh dst_box.y1 = dst_y; 250903b705cfSriastradh dst_box.y2 = bound(dst_y, height); 251003b705cfSriastradh } else 251103b705cfSriastradh sna_render_picture_extents(dst, &dst_box); 251203b705cfSriastradh 251303b705cfSriastradh tmp->dst.format = dst->format; 251403b705cfSriastradh tmp->dst.width = tmp->dst.pixmap->drawable.width; 251503b705cfSriastradh tmp->dst.height = tmp->dst.pixmap->drawable.height; 251603b705cfSriastradh get_drawable_deltas(dst->pDrawable, tmp->dst.pixmap, 251703b705cfSriastradh &tmp->dst.x, &tmp->dst.y); 251803b705cfSriastradh 251903b705cfSriastradh if (op == PictOpClear) { 252003b705cfSriastradhclear: 252142542f5fSchristos if (was_clear && sna_pixmap(tmp->dst.pixmap)->clear_color == 0) { 252242542f5fSchristos sna_pixmap(tmp->dst.pixmap)->clear = true; 252303b705cfSriastradh return prepare_blt_nop(sna, tmp); 252442542f5fSchristos } 252503b705cfSriastradh 252603b705cfSriastradh hint = 0; 252703b705cfSriastradh if (can_render(sna)) { 252803b705cfSriastradh hint |= PREFER_GPU; 252942542f5fSchristos if ((flags & COMPOSITE_PARTIAL) == 0) { 253042542f5fSchristos hint |= IGNORE_DAMAGE; 253142542f5fSchristos if (width == tmp->dst.pixmap->drawable.width && 253203b705cfSriastradh height == tmp->dst.pixmap->drawable.height) 253303b705cfSriastradh hint |= REPLACES; 253403b705cfSriastradh } 253503b705cfSriastradh } 253603b705cfSriastradh tmp->dst.bo = sna_drawable_use_bo(dst->pDrawable, hint, 253703b705cfSriastradh &dst_box, &tmp->damage); 253842542f5fSchristos if (tmp->dst.bo) { 253942542f5fSchristos if (!kgem_bo_can_blt(&sna->kgem, tmp->dst.bo)) { 254042542f5fSchristos DBG(("%s: can not blit to dst, tiling? %d, pitch? %d\n", 254142542f5fSchristos __FUNCTION__, tmp->dst.bo->tiling, tmp->dst.bo->pitch)); 254242542f5fSchristos return false; 254342542f5fSchristos } 254442542f5fSchristos if (hint & REPLACES) 254542542f5fSchristos kgem_bo_undo(&sna->kgem, tmp->dst.bo); 254642542f5fSchristos } else { 254703b705cfSriastradh RegionRec region; 254803b705cfSriastradh 254903b705cfSriastradh region.extents = dst_box; 255003b705cfSriastradh region.data = NULL; 255103b705cfSriastradh 255242542f5fSchristos hint = MOVE_WRITE | MOVE_INPLACE_HINT; 255342542f5fSchristos if (flags & COMPOSITE_PARTIAL) 255442542f5fSchristos hint |= MOVE_READ; 255542542f5fSchristos if (!sna_drawable_move_region_to_cpu(dst->pDrawable, ®ion, hint)) 255603b705cfSriastradh return false; 255742542f5fSchristos } 255803b705cfSriastradh 255903b705cfSriastradh return prepare_blt_clear(sna, tmp); 256003b705cfSriastradh } 256103b705cfSriastradh 256203b705cfSriastradh if (is_solid(src)) { 256342542f5fSchristos if ((op == PictOpOver || op == PictOpAdd) && is_transparent(src)) { 256442542f5fSchristos sna_pixmap(tmp->dst.pixmap)->clear = was_clear; 256542542f5fSchristos return prepare_blt_nop(sna, tmp); 256642542f5fSchristos } 256703b705cfSriastradh if (op == PictOpOver && is_opaque_solid(src)) 256803b705cfSriastradh op = PictOpSrc; 256903b705cfSriastradh if (op == PictOpAdd && is_white(src)) 257003b705cfSriastradh op = PictOpSrc; 257142542f5fSchristos if (was_clear && (op == PictOpAdd || op == PictOpOver)) { 257242542f5fSchristos if (sna_pixmap(tmp->dst.pixmap)->clear_color == 0) 257342542f5fSchristos op = PictOpSrc; 257442542f5fSchristos if (op == PictOpOver) { 257542542f5fSchristos color = over(get_solid_color(src, PICT_a8r8g8b8), 257642542f5fSchristos color_convert(sna_pixmap(tmp->dst.pixmap)->clear_color, 257742542f5fSchristos dst->format, PICT_a8r8g8b8)); 257842542f5fSchristos op = PictOpSrc; 257942542f5fSchristos DBG(("%s: precomputing solid OVER (%08x, %08x) -> %08x\n", 258042542f5fSchristos __FUNCTION__, get_solid_color(src, PICT_a8r8g8b8), 258142542f5fSchristos color_convert(sna_pixmap(tmp->dst.pixmap)->clear_color, 258242542f5fSchristos dst->format, PICT_a8r8g8b8), 258342542f5fSchristos color)); 258442542f5fSchristos } 258542542f5fSchristos if (op == PictOpAdd) { 258642542f5fSchristos color = add(get_solid_color(src, PICT_a8r8g8b8), 258742542f5fSchristos color_convert(sna_pixmap(tmp->dst.pixmap)->clear_color, 258842542f5fSchristos dst->format, PICT_a8r8g8b8)); 258942542f5fSchristos op = PictOpSrc; 259042542f5fSchristos DBG(("%s: precomputing solid ADD (%08x, %08x) -> %08x\n", 259142542f5fSchristos __FUNCTION__, get_solid_color(src, PICT_a8r8g8b8), 259242542f5fSchristos color_convert(sna_pixmap(tmp->dst.pixmap)->clear_color, 259342542f5fSchristos dst->format, PICT_a8r8g8b8), 259442542f5fSchristos color)); 259542542f5fSchristos } 259642542f5fSchristos } 259703b705cfSriastradh if (op == PictOpOutReverse && is_opaque_solid(src)) 259803b705cfSriastradh goto clear; 259903b705cfSriastradh 260003b705cfSriastradh if (op != PictOpSrc) { 260103b705cfSriastradh DBG(("%s: unsupported op [%d] for blitting\n", 260203b705cfSriastradh __FUNCTION__, op)); 260303b705cfSriastradh return false; 260403b705cfSriastradh } 260503b705cfSriastradh 260603b705cfSriastradh color = get_solid_color(src, tmp->dst.format); 260703b705cfSriastradhfill: 260803b705cfSriastradh if (color == 0) 260903b705cfSriastradh goto clear; 261003b705cfSriastradh 261142542f5fSchristos if (was_clear && sna_pixmap(tmp->dst.pixmap)->clear_color == color) { 261242542f5fSchristos sna_pixmap(tmp->dst.pixmap)->clear = true; 261342542f5fSchristos return prepare_blt_nop(sna, tmp); 261442542f5fSchristos } 261542542f5fSchristos 261603b705cfSriastradh hint = 0; 261703b705cfSriastradh if (can_render(sna)) { 261803b705cfSriastradh hint |= PREFER_GPU; 261942542f5fSchristos if ((flags & COMPOSITE_PARTIAL) == 0) { 262042542f5fSchristos hint |= IGNORE_DAMAGE; 262142542f5fSchristos if (width == tmp->dst.pixmap->drawable.width && 262203b705cfSriastradh height == tmp->dst.pixmap->drawable.height) 262303b705cfSriastradh hint |= REPLACES; 262442542f5fSchristos } 262503b705cfSriastradh } 262603b705cfSriastradh tmp->dst.bo = sna_drawable_use_bo(dst->pDrawable, hint, 262703b705cfSriastradh &dst_box, &tmp->damage); 262842542f5fSchristos if (tmp->dst.bo) { 262942542f5fSchristos if (!kgem_bo_can_blt(&sna->kgem, tmp->dst.bo)) { 263042542f5fSchristos DBG(("%s: can not blit to dst, tiling? %d, pitch? %d\n", 263142542f5fSchristos __FUNCTION__, tmp->dst.bo->tiling, tmp->dst.bo->pitch)); 263242542f5fSchristos return false; 263342542f5fSchristos } 263442542f5fSchristos if (hint & REPLACES) 263542542f5fSchristos kgem_bo_undo(&sna->kgem, tmp->dst.bo); 263642542f5fSchristos } else { 263703b705cfSriastradh RegionRec region; 263803b705cfSriastradh 263903b705cfSriastradh region.extents = dst_box; 264003b705cfSriastradh region.data = NULL; 264103b705cfSriastradh 264242542f5fSchristos hint = MOVE_WRITE | MOVE_INPLACE_HINT; 264342542f5fSchristos if (flags & COMPOSITE_PARTIAL) 264442542f5fSchristos hint |= MOVE_READ; 264542542f5fSchristos if (!sna_drawable_move_region_to_cpu(dst->pDrawable, ®ion, hint)) 264603b705cfSriastradh return false; 264742542f5fSchristos } 264803b705cfSriastradh 264903b705cfSriastradh return prepare_blt_fill(sna, tmp, color); 265003b705cfSriastradh } 265103b705cfSriastradh 265203b705cfSriastradh if (!src->pDrawable) { 265303b705cfSriastradh DBG(("%s: unsupported procedural source\n", 265403b705cfSriastradh __FUNCTION__)); 265503b705cfSriastradh return false; 265603b705cfSriastradh } 265703b705cfSriastradh 265803b705cfSriastradh if (src->filter == PictFilterConvolution) { 265903b705cfSriastradh DBG(("%s: convolutions filters not handled\n", 266003b705cfSriastradh __FUNCTION__)); 266103b705cfSriastradh return false; 266203b705cfSriastradh } 266303b705cfSriastradh 266403b705cfSriastradh if (op == PictOpOver && PICT_FORMAT_A(src_format) == 0) 266503b705cfSriastradh op = PictOpSrc; 266603b705cfSriastradh 266703b705cfSriastradh if (op != PictOpSrc) { 266803b705cfSriastradh DBG(("%s: unsupported op [%d] for blitting\n", 266903b705cfSriastradh __FUNCTION__, op)); 267003b705cfSriastradh return false; 267103b705cfSriastradh } 267203b705cfSriastradh 267342542f5fSchristos if (!sna_transform_is_imprecise_integer_translation(src->transform, src->filter, 267442542f5fSchristos dst->polyMode == PolyModePrecise, 267542542f5fSchristos &tx, &ty)) { 267603b705cfSriastradh DBG(("%s: source transform is not an integer translation\n", 267703b705cfSriastradh __FUNCTION__)); 267803b705cfSriastradh return false; 267903b705cfSriastradh } 268042542f5fSchristos DBG(("%s: converting transform to integer translation? (%d, %d)\n", 268142542f5fSchristos __FUNCTION__, src->transform != NULL, tx, ty)); 268203b705cfSriastradh x += tx; 268303b705cfSriastradh y += ty; 268403b705cfSriastradh 268503b705cfSriastradh if ((x >= src->pDrawable->width || 268603b705cfSriastradh y >= src->pDrawable->height || 268703b705cfSriastradh x + width <= 0 || 268803b705cfSriastradh y + height <= 0) && 268903b705cfSriastradh (!src->repeat || src->repeatType == RepeatNone)) { 269003b705cfSriastradh DBG(("%s: source is outside of valid area, converting to clear\n", 269103b705cfSriastradh __FUNCTION__)); 269203b705cfSriastradh goto clear; 269303b705cfSriastradh } 269403b705cfSriastradh 269503b705cfSriastradh src_pixmap = get_drawable_pixmap(src->pDrawable); 269603b705cfSriastradh if (is_clear(src_pixmap)) { 269742542f5fSchristos if (src->repeat || 269842542f5fSchristos (x >= 0 && y >= 0 && 269942542f5fSchristos x + width < src_pixmap->drawable.width && 270042542f5fSchristos y + height < src_pixmap->drawable.height)) { 270142542f5fSchristos color = color_convert(sna_pixmap(src_pixmap)->clear_color, 270242542f5fSchristos src->format, tmp->dst.format); 270342542f5fSchristos goto fill; 270442542f5fSchristos } 270503b705cfSriastradh } 270603b705cfSriastradh 270703b705cfSriastradh alpha_fixup = 0; 270803b705cfSriastradh if (!(dst->format == src_format || 270903b705cfSriastradh dst->format == alphaless(src_format) || 271003b705cfSriastradh (alphaless(dst->format) == alphaless(src_format) && 271103b705cfSriastradh sna_get_pixel_from_rgba(&alpha_fixup, 271203b705cfSriastradh 0, 0, 0, 0xffff, 271303b705cfSriastradh dst->format)))) { 271403b705cfSriastradh DBG(("%s: incompatible src/dst formats src=%08x, dst=%08x\n", 271503b705cfSriastradh __FUNCTION__, (unsigned)src_format, dst->format)); 271603b705cfSriastradh return false; 271703b705cfSriastradh } 271803b705cfSriastradh 271903b705cfSriastradh /* XXX tiling? fixup extend none? */ 272003b705cfSriastradh if (x < 0 || y < 0 || 272103b705cfSriastradh x + width > src->pDrawable->width || 272203b705cfSriastradh y + height > src->pDrawable->height) { 272303b705cfSriastradh DBG(("%s: source extends outside (%d, %d), (%d, %d) of valid drawable %dx%d, repeat=%d\n", 272403b705cfSriastradh __FUNCTION__, 272503b705cfSriastradh x, y, x+width, y+width, src->pDrawable->width, src->pDrawable->height, src->repeatType)); 272603b705cfSriastradh if (src->repeat && src->repeatType == RepeatNormal) { 272703b705cfSriastradh x = x % src->pDrawable->width; 272803b705cfSriastradh y = y % src->pDrawable->height; 272903b705cfSriastradh if (x < 0) 273003b705cfSriastradh x += src->pDrawable->width; 273103b705cfSriastradh if (y < 0) 273203b705cfSriastradh y += src->pDrawable->height; 273303b705cfSriastradh if (x + width > src->pDrawable->width || 273403b705cfSriastradh y + height > src->pDrawable->height) 273503b705cfSriastradh return false; 273603b705cfSriastradh } else 273703b705cfSriastradh return false; 273803b705cfSriastradh } 273903b705cfSriastradh 274003b705cfSriastradh get_drawable_deltas(src->pDrawable, src_pixmap, &tx, &ty); 274103b705cfSriastradh x += tx + src->pDrawable->x; 274203b705cfSriastradh y += ty + src->pDrawable->y; 274303b705cfSriastradh if (x < 0 || y < 0 || 274403b705cfSriastradh x + width > src_pixmap->drawable.width || 274503b705cfSriastradh y + height > src_pixmap->drawable.height) { 274603b705cfSriastradh DBG(("%s: source extends outside (%d, %d), (%d, %d) of valid pixmap %dx%d\n", 274703b705cfSriastradh __FUNCTION__, 274803b705cfSriastradh x, y, x+width, y+width, src_pixmap->drawable.width, src_pixmap->drawable.height)); 274903b705cfSriastradh return false; 275003b705cfSriastradh } 275103b705cfSriastradh 275203b705cfSriastradh tmp->u.blt.src_pixmap = src_pixmap; 275303b705cfSriastradh tmp->u.blt.sx = x - dst_x; 275403b705cfSriastradh tmp->u.blt.sy = y - dst_y; 275503b705cfSriastradh DBG(("%s: blt dst offset (%d, %d), source offset (%d, %d), with alpha fixup? %x\n", 275603b705cfSriastradh __FUNCTION__, 275703b705cfSriastradh tmp->dst.x, tmp->dst.y, tmp->u.blt.sx, tmp->u.blt.sy, alpha_fixup)); 275803b705cfSriastradh 275903b705cfSriastradh src_box.x1 = x; 276003b705cfSriastradh src_box.y1 = y; 276103b705cfSriastradh src_box.x2 = x + width; 276203b705cfSriastradh src_box.y2 = y + height; 276303b705cfSriastradh bo = __sna_render_pixmap_bo(sna, src_pixmap, &src_box, true); 276403b705cfSriastradh if (bo && !kgem_bo_can_blt(&sna->kgem, bo)) { 276503b705cfSriastradh DBG(("%s: can not blit from src size=%dx%d, tiling? %d, pitch? %d\n", 276603b705cfSriastradh __FUNCTION__, 276703b705cfSriastradh src_pixmap->drawable.width < sna->render.max_3d_size, 276803b705cfSriastradh src_pixmap->drawable.height < sna->render.max_3d_size, 276903b705cfSriastradh bo->tiling, bo->pitch)); 277003b705cfSriastradh 277103b705cfSriastradh if (src_pixmap->drawable.width <= sna->render.max_3d_size && 277203b705cfSriastradh src_pixmap->drawable.height <= sna->render.max_3d_size && 277303b705cfSriastradh bo->pitch <= sna->render.max_3d_pitch && 277442542f5fSchristos (flags & COMPOSITE_FALLBACK) == 0) 277503b705cfSriastradh { 277603b705cfSriastradh return false; 277703b705cfSriastradh } 277803b705cfSriastradh 277903b705cfSriastradh bo = NULL; 278003b705cfSriastradh } 278103b705cfSriastradh 278203b705cfSriastradh hint = 0; 278303b705cfSriastradh if (bo || can_render(sna)) { 278403b705cfSriastradh hint |= PREFER_GPU; 278542542f5fSchristos if ((flags & COMPOSITE_PARTIAL) == 0) { 278642542f5fSchristos hint |= IGNORE_DAMAGE; 278742542f5fSchristos if (width == tmp->dst.pixmap->drawable.width && 278803b705cfSriastradh height == tmp->dst.pixmap->drawable.height) 278903b705cfSriastradh hint |= REPLACES; 279003b705cfSriastradh } 279103b705cfSriastradh if (bo) 279203b705cfSriastradh hint |= FORCE_GPU; 279303b705cfSriastradh } 279403b705cfSriastradh tmp->dst.bo = sna_drawable_use_bo(dst->pDrawable, hint, 279503b705cfSriastradh &dst_box, &tmp->damage); 279603b705cfSriastradh 279742542f5fSchristos if (tmp->dst.bo && hint & REPLACES) { 279842542f5fSchristos struct sna_pixmap *priv = sna_pixmap(tmp->dst.pixmap); 279942542f5fSchristos kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo); 280042542f5fSchristos } 280142542f5fSchristos 280242542f5fSchristos if (tmp->dst.pixmap == src_pixmap) 280342542f5fSchristos bo = __sna_render_pixmap_bo(sna, src_pixmap, &src_box, true); 280403b705cfSriastradh 280503b705cfSriastradh ret = false; 280603b705cfSriastradh if (bo) { 280703b705cfSriastradh if (!tmp->dst.bo) { 280803b705cfSriastradh DBG(("%s: fallback -- unaccelerated read back\n", 280903b705cfSriastradh __FUNCTION__)); 281042542f5fSchristosfallback: 281142542f5fSchristos if (flags & COMPOSITE_FALLBACK || !kgem_bo_is_busy(bo)) 281203b705cfSriastradh goto put; 281342542f5fSchristos } else if (!kgem_bo_can_blt(&sna->kgem, bo)) { 281442542f5fSchristos DBG(("%s: fallback -- cannot blit from source\n", 281542542f5fSchristos __FUNCTION__)); 281642542f5fSchristos goto fallback; 281703b705cfSriastradh } else if (bo->snoop && tmp->dst.bo->snoop) { 281803b705cfSriastradh DBG(("%s: fallback -- can not copy between snooped bo\n", 281903b705cfSriastradh __FUNCTION__)); 282003b705cfSriastradh goto put; 282103b705cfSriastradh } else if (!kgem_bo_can_blt(&sna->kgem, tmp->dst.bo)) { 282203b705cfSriastradh DBG(("%s: fallback -- unaccelerated upload\n", 282303b705cfSriastradh __FUNCTION__)); 282442542f5fSchristos goto fallback; 282503b705cfSriastradh } else { 282603b705cfSriastradh ret = prepare_blt_copy(sna, tmp, bo, alpha_fixup); 282742542f5fSchristos if (!ret) 282842542f5fSchristos goto fallback; 282903b705cfSriastradh } 283003b705cfSriastradh } else { 283103b705cfSriastradh RegionRec region; 283203b705cfSriastradh 283303b705cfSriastradhput: 283403b705cfSriastradh if (tmp->dst.bo == sna_pixmap(tmp->dst.pixmap)->cpu_bo) { 283542542f5fSchristos DBG(("%s: dropping upload into CPU bo\n", __FUNCTION__)); 283603b705cfSriastradh tmp->dst.bo = NULL; 283703b705cfSriastradh tmp->damage = NULL; 283803b705cfSriastradh } 283903b705cfSriastradh 284003b705cfSriastradh if (tmp->dst.bo == NULL) { 284103b705cfSriastradh hint = MOVE_INPLACE_HINT | MOVE_WRITE; 284242542f5fSchristos if (flags & COMPOSITE_PARTIAL) 284303b705cfSriastradh hint |= MOVE_READ; 284403b705cfSriastradh 284503b705cfSriastradh region.extents = dst_box; 284603b705cfSriastradh region.data = NULL; 284703b705cfSriastradh if (!sna_drawable_move_region_to_cpu(dst->pDrawable, 284803b705cfSriastradh ®ion, hint)) 284903b705cfSriastradh return false; 285003b705cfSriastradh 285103b705cfSriastradh assert(tmp->damage == NULL); 285203b705cfSriastradh } 285303b705cfSriastradh 285403b705cfSriastradh region.extents = src_box; 285503b705cfSriastradh region.data = NULL; 285603b705cfSriastradh if (!sna_drawable_move_region_to_cpu(&src_pixmap->drawable, 285703b705cfSriastradh ®ion, MOVE_READ)) 285803b705cfSriastradh return false; 285903b705cfSriastradh 286003b705cfSriastradh ret = prepare_blt_put(sna, tmp, alpha_fixup); 286103b705cfSriastradh } 286203b705cfSriastradh 286303b705cfSriastradh return ret; 286403b705cfSriastradh} 286503b705cfSriastradh 286603b705cfSriastradhstatic void convert_done(struct sna *sna, const struct sna_composite_op *op) 286703b705cfSriastradh{ 286803b705cfSriastradh struct kgem *kgem = &sna->kgem; 286903b705cfSriastradh 287003b705cfSriastradh assert(kgem->nbatch <= KGEM_BATCH_SIZE(kgem)); 287142542f5fSchristos if (kgem->nexec > 1 && __kgem_ring_empty(kgem)) { 287242542f5fSchristos DBG(("%s: flushing BLT operation on empty ring\n", __FUNCTION__)); 287303b705cfSriastradh _kgem_submit(kgem); 287442542f5fSchristos } 287503b705cfSriastradh 287603b705cfSriastradh kgem_bo_destroy(kgem, op->src.bo); 287703b705cfSriastradh sna_render_composite_redirect_done(sna, op); 287803b705cfSriastradh} 287903b705cfSriastradh 288003b705cfSriastradhstatic void gen6_convert_done(struct sna *sna, const struct sna_composite_op *op) 288103b705cfSriastradh{ 288203b705cfSriastradh struct kgem *kgem = &sna->kgem; 288303b705cfSriastradh 288403b705cfSriastradh if (kgem_check_batch(kgem, 3)) { 288503b705cfSriastradh uint32_t *b = kgem->batch + kgem->nbatch; 288642542f5fSchristos assert(sna->kgem.mode == KGEM_BLT); 288703b705cfSriastradh b[0] = XY_SETUP_CLIP; 288803b705cfSriastradh b[1] = b[2] = 0; 288903b705cfSriastradh kgem->nbatch += 3; 289003b705cfSriastradh assert(kgem->nbatch < kgem->surface); 289103b705cfSriastradh } 289203b705cfSriastradh 289303b705cfSriastradh convert_done(sna, op); 289403b705cfSriastradh} 289503b705cfSriastradh 289603b705cfSriastradhbool 289703b705cfSriastradhsna_blt_composite__convert(struct sna *sna, 289803b705cfSriastradh int x, int y, 289903b705cfSriastradh int width, int height, 290003b705cfSriastradh struct sna_composite_op *tmp) 290103b705cfSriastradh{ 290203b705cfSriastradh uint32_t alpha_fixup; 290303b705cfSriastradh int sx, sy; 290403b705cfSriastradh uint8_t op; 290503b705cfSriastradh 290603b705cfSriastradh#if DEBUG_NO_BLT || NO_BLT_COMPOSITE 290703b705cfSriastradh return false; 290803b705cfSriastradh#endif 290903b705cfSriastradh 291003b705cfSriastradh DBG(("%s src=%d, dst=%d (redirect? %d)\n", __FUNCTION__, 291103b705cfSriastradh tmp->src.bo->handle, tmp->dst.bo->handle, 291203b705cfSriastradh tmp->redirect.real_bo ? tmp->redirect.real_bo->handle : 0)); 291303b705cfSriastradh 291403b705cfSriastradh if (!kgem_bo_can_blt(&sna->kgem, tmp->dst.bo) || 291503b705cfSriastradh !kgem_bo_can_blt(&sna->kgem, tmp->src.bo)) { 291603b705cfSriastradh DBG(("%s: cannot blt from src or to dst\n", __FUNCTION__)); 291703b705cfSriastradh return false; 291803b705cfSriastradh } 291903b705cfSriastradh 292003b705cfSriastradh if (tmp->src.transform) { 292103b705cfSriastradh DBG(("%s: transforms not handled by the BLT\n", __FUNCTION__)); 292203b705cfSriastradh return false; 292303b705cfSriastradh } 292403b705cfSriastradh 292503b705cfSriastradh if (tmp->src.filter == PictFilterConvolution) { 292603b705cfSriastradh DBG(("%s: convolutions filters not handled\n", 292703b705cfSriastradh __FUNCTION__)); 292803b705cfSriastradh return false; 292903b705cfSriastradh } 293003b705cfSriastradh 293103b705cfSriastradh op = tmp->op; 293203b705cfSriastradh if (op == PictOpOver && PICT_FORMAT_A(tmp->src.pict_format) == 0) 293303b705cfSriastradh op = PictOpSrc; 293403b705cfSriastradh if (op != PictOpSrc) { 293503b705cfSriastradh DBG(("%s: unsupported op [%d] for blitting\n", 293603b705cfSriastradh __FUNCTION__, op)); 293703b705cfSriastradh return false; 293803b705cfSriastradh } 293903b705cfSriastradh 294003b705cfSriastradh alpha_fixup = 0; 294103b705cfSriastradh if (!(tmp->dst.format == tmp->src.pict_format || 294203b705cfSriastradh tmp->dst.format == alphaless(tmp->src.pict_format) || 294303b705cfSriastradh (alphaless(tmp->dst.format) == alphaless(tmp->src.pict_format) && 294403b705cfSriastradh sna_get_pixel_from_rgba(&alpha_fixup, 294503b705cfSriastradh 0, 0, 0, 0xffff, 294603b705cfSriastradh tmp->dst.format)))) { 294703b705cfSriastradh DBG(("%s: incompatible src/dst formats src=%08x, dst=%08x\n", 294803b705cfSriastradh __FUNCTION__, 294903b705cfSriastradh (unsigned)tmp->src.pict_format, 295003b705cfSriastradh (unsigned)tmp->dst.format)); 295103b705cfSriastradh return false; 295203b705cfSriastradh } 295303b705cfSriastradh 295403b705cfSriastradh sx = tmp->src.offset[0]; 295503b705cfSriastradh sy = tmp->src.offset[1]; 295603b705cfSriastradh 295703b705cfSriastradh x += sx; 295803b705cfSriastradh y += sy; 295903b705cfSriastradh if (x < 0 || y < 0 || 296003b705cfSriastradh x + width > tmp->src.width || 296103b705cfSriastradh y + height > tmp->src.height) { 296203b705cfSriastradh DBG(("%s: source extends outside (%d, %d), (%d, %d) of valid drawable %dx%d\n", 296303b705cfSriastradh __FUNCTION__, 296403b705cfSriastradh x, y, x+width, y+width, tmp->src.width, tmp->src.height)); 296503b705cfSriastradh if (tmp->src.repeat == RepeatNormal) { 296603b705cfSriastradh int xx = x % tmp->src.width; 296703b705cfSriastradh int yy = y % tmp->src.height; 296803b705cfSriastradh if (xx < 0) 296903b705cfSriastradh xx += tmp->src.width; 297003b705cfSriastradh if (yy < 0) 297103b705cfSriastradh yy += tmp->src.height; 297203b705cfSriastradh if (xx + width > tmp->src.width || 297303b705cfSriastradh yy + height > tmp->src.height) 297403b705cfSriastradh return false; 297503b705cfSriastradh 297603b705cfSriastradh sx += xx - x; 297703b705cfSriastradh sy += yy - y; 297803b705cfSriastradh } else 297903b705cfSriastradh return false; 298003b705cfSriastradh } 298103b705cfSriastradh 298242542f5fSchristos DBG(("%s: blt dst offset (%d, %d), source offset (%d, %d), with alpha fixup? %x\n", 298342542f5fSchristos __FUNCTION__, 298442542f5fSchristos tmp->dst.x, tmp->dst.y, sx, sy, alpha_fixup)); 298542542f5fSchristos 298642542f5fSchristos tmp->u.blt.src_pixmap = NULL; 298742542f5fSchristos tmp->u.blt.sx = sx; 298842542f5fSchristos tmp->u.blt.sy = sy; 298942542f5fSchristos 299042542f5fSchristos kgem_set_mode(&sna->kgem, KGEM_BLT, tmp->dst.bo); 299103b705cfSriastradh if (!kgem_check_many_bo_fenced(&sna->kgem, tmp->dst.bo, tmp->src.bo, NULL)) { 299203b705cfSriastradh kgem_submit(&sna->kgem); 299303b705cfSriastradh if (!kgem_check_many_bo_fenced(&sna->kgem, 299403b705cfSriastradh tmp->dst.bo, tmp->src.bo, NULL)) { 299503b705cfSriastradh DBG(("%s: fallback -- no room in aperture\n", __FUNCTION__)); 299642542f5fSchristos return sna_tiling_blt_composite(sna, tmp, tmp->src.bo, 299742542f5fSchristos PICT_FORMAT_BPP(tmp->src.pict_format), 299842542f5fSchristos alpha_fixup); 299903b705cfSriastradh } 300003b705cfSriastradh _kgem_set_mode(&sna->kgem, KGEM_BLT); 300103b705cfSriastradh } 300203b705cfSriastradh 300303b705cfSriastradh if (alpha_fixup) { 300403b705cfSriastradh tmp->blt = blt_composite_copy_with_alpha; 300503b705cfSriastradh tmp->box = blt_composite_copy_box_with_alpha; 300603b705cfSriastradh tmp->boxes = blt_composite_copy_boxes_with_alpha; 300703b705cfSriastradh 300803b705cfSriastradh if (!sna_blt_alpha_fixup_init(sna, &tmp->u.blt, 300903b705cfSriastradh tmp->src.bo, tmp->dst.bo, 301003b705cfSriastradh PICT_FORMAT_BPP(tmp->src.pict_format), 301103b705cfSriastradh alpha_fixup)) 301203b705cfSriastradh return false; 301303b705cfSriastradh } else { 301403b705cfSriastradh tmp->blt = blt_composite_copy; 301503b705cfSriastradh tmp->box = blt_composite_copy_box; 301603b705cfSriastradh tmp->boxes = blt_composite_copy_boxes; 301703b705cfSriastradh tmp->thread_boxes = blt_composite_copy_boxes__thread; 301803b705cfSriastradh 301903b705cfSriastradh if (!sna_blt_copy_init(sna, &tmp->u.blt, 302003b705cfSriastradh tmp->src.bo, tmp->dst.bo, 302103b705cfSriastradh PICT_FORMAT_BPP(tmp->src.pict_format), 302203b705cfSriastradh GXcopy)) 302303b705cfSriastradh return false; 302403b705cfSriastradh } 302503b705cfSriastradh 302603b705cfSriastradh tmp->done = convert_done; 302703b705cfSriastradh if (sna->kgem.gen >= 060 && tmp->src.bo == tmp->dst.bo) 302803b705cfSriastradh tmp->done = gen6_convert_done; 302903b705cfSriastradh 303003b705cfSriastradh return true; 303103b705cfSriastradh} 303203b705cfSriastradh 303303b705cfSriastradhstatic void sna_blt_fill_op_blt(struct sna *sna, 303403b705cfSriastradh const struct sna_fill_op *op, 303503b705cfSriastradh int16_t x, int16_t y, 303603b705cfSriastradh int16_t width, int16_t height) 303703b705cfSriastradh{ 303842542f5fSchristos if (sna->blt_state.fill_bo != op->base.u.blt.bo[0]->unique_id) { 303942542f5fSchristos const struct sna_blt_state *blt = &op->base.u.blt; 304042542f5fSchristos 304142542f5fSchristos sna_blt_fill_begin(sna, blt); 304242542f5fSchristos 304342542f5fSchristos sna->blt_state.fill_bo = blt->bo[0]->unique_id; 304442542f5fSchristos sna->blt_state.fill_pixel = blt->pixel; 304542542f5fSchristos sna->blt_state.fill_alu = blt->alu; 304642542f5fSchristos } 304742542f5fSchristos 304803b705cfSriastradh sna_blt_fill_one(sna, &op->base.u.blt, x, y, width, height); 304903b705cfSriastradh} 305003b705cfSriastradh 305103b705cfSriastradhfastcall static void sna_blt_fill_op_box(struct sna *sna, 305203b705cfSriastradh const struct sna_fill_op *op, 305303b705cfSriastradh const BoxRec *box) 305403b705cfSriastradh{ 305542542f5fSchristos if (sna->blt_state.fill_bo != op->base.u.blt.bo[0]->unique_id) { 305642542f5fSchristos const struct sna_blt_state *blt = &op->base.u.blt; 305742542f5fSchristos 305842542f5fSchristos sna_blt_fill_begin(sna, blt); 305942542f5fSchristos 306042542f5fSchristos sna->blt_state.fill_bo = blt->bo[0]->unique_id; 306142542f5fSchristos sna->blt_state.fill_pixel = blt->pixel; 306242542f5fSchristos sna->blt_state.fill_alu = blt->alu; 306342542f5fSchristos } 306442542f5fSchristos 306503b705cfSriastradh _sna_blt_fill_box(sna, &op->base.u.blt, box); 306603b705cfSriastradh} 306703b705cfSriastradh 306803b705cfSriastradhfastcall static void sna_blt_fill_op_boxes(struct sna *sna, 306903b705cfSriastradh const struct sna_fill_op *op, 307003b705cfSriastradh const BoxRec *box, 307103b705cfSriastradh int nbox) 307203b705cfSriastradh{ 307342542f5fSchristos if (sna->blt_state.fill_bo != op->base.u.blt.bo[0]->unique_id) { 307442542f5fSchristos const struct sna_blt_state *blt = &op->base.u.blt; 307542542f5fSchristos 307642542f5fSchristos sna_blt_fill_begin(sna, blt); 307742542f5fSchristos 307842542f5fSchristos sna->blt_state.fill_bo = blt->bo[0]->unique_id; 307942542f5fSchristos sna->blt_state.fill_pixel = blt->pixel; 308042542f5fSchristos sna->blt_state.fill_alu = blt->alu; 308142542f5fSchristos } 308242542f5fSchristos 308303b705cfSriastradh _sna_blt_fill_boxes(sna, &op->base.u.blt, box, nbox); 308403b705cfSriastradh} 308503b705cfSriastradh 308642542f5fSchristosstatic inline uint64_t pt_add(uint32_t cmd, const DDXPointRec *pt, int16_t dx, int16_t dy) 308742542f5fSchristos{ 308842542f5fSchristos union { 308942542f5fSchristos DDXPointRec pt; 309042542f5fSchristos uint32_t i; 309142542f5fSchristos } u; 309242542f5fSchristos 309342542f5fSchristos u.pt.x = pt->x + dx; 309442542f5fSchristos u.pt.y = pt->y + dy; 309542542f5fSchristos 309642542f5fSchristos return cmd | (uint64_t)u.i<<32; 309742542f5fSchristos} 309842542f5fSchristos 309942542f5fSchristosfastcall static void sna_blt_fill_op_points(struct sna *sna, 310042542f5fSchristos const struct sna_fill_op *op, 310142542f5fSchristos int16_t dx, int16_t dy, 310242542f5fSchristos const DDXPointRec *p, int n) 310342542f5fSchristos{ 310442542f5fSchristos const struct sna_blt_state *blt = &op->base.u.blt; 310542542f5fSchristos struct kgem *kgem = &sna->kgem; 310642542f5fSchristos uint32_t cmd; 310742542f5fSchristos 310842542f5fSchristos DBG(("%s: %08x x %d\n", __FUNCTION__, blt->pixel, n)); 310942542f5fSchristos 311042542f5fSchristos if (sna->blt_state.fill_bo != op->base.u.blt.bo[0]->unique_id) { 311142542f5fSchristos sna_blt_fill_begin(sna, blt); 311242542f5fSchristos 311342542f5fSchristos sna->blt_state.fill_bo = blt->bo[0]->unique_id; 311442542f5fSchristos sna->blt_state.fill_pixel = blt->pixel; 311542542f5fSchristos sna->blt_state.fill_alu = blt->alu; 311642542f5fSchristos } 311742542f5fSchristos 311842542f5fSchristos if (!kgem_check_batch(kgem, 2)) 311942542f5fSchristos sna_blt_fill_begin(sna, blt); 312042542f5fSchristos 312142542f5fSchristos cmd = XY_PIXEL_BLT; 312242542f5fSchristos if (kgem->gen >= 040 && op->base.u.blt.bo[0]->tiling) 312342542f5fSchristos cmd |= BLT_DST_TILED; 312442542f5fSchristos 312542542f5fSchristos do { 312642542f5fSchristos uint32_t *b = kgem->batch + kgem->nbatch; 312742542f5fSchristos int n_this_time; 312842542f5fSchristos 312942542f5fSchristos assert(sna->kgem.mode == KGEM_BLT); 313042542f5fSchristos n_this_time = n; 313142542f5fSchristos if (2*n_this_time > kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) 313242542f5fSchristos n_this_time = (kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) / 2; 313342542f5fSchristos assert(n_this_time); 313442542f5fSchristos n -= n_this_time; 313542542f5fSchristos 313642542f5fSchristos kgem->nbatch += 2 * n_this_time; 313742542f5fSchristos assert(kgem->nbatch < kgem->surface); 313842542f5fSchristos 313942542f5fSchristos if ((dx|dy) == 0) { 314042542f5fSchristos while (n_this_time >= 8) { 314142542f5fSchristos *((uint64_t *)b + 0) = pt_add(cmd, p+0, 0, 0); 314242542f5fSchristos *((uint64_t *)b + 1) = pt_add(cmd, p+1, 0, 0); 314342542f5fSchristos *((uint64_t *)b + 2) = pt_add(cmd, p+2, 0, 0); 314442542f5fSchristos *((uint64_t *)b + 3) = pt_add(cmd, p+3, 0, 0); 314542542f5fSchristos *((uint64_t *)b + 4) = pt_add(cmd, p+4, 0, 0); 314642542f5fSchristos *((uint64_t *)b + 5) = pt_add(cmd, p+5, 0, 0); 314742542f5fSchristos *((uint64_t *)b + 6) = pt_add(cmd, p+6, 0, 0); 314842542f5fSchristos *((uint64_t *)b + 7) = pt_add(cmd, p+7, 0, 0); 314942542f5fSchristos b += 16; 315042542f5fSchristos n_this_time -= 8; 315142542f5fSchristos p += 8; 315242542f5fSchristos } 315342542f5fSchristos if (n_this_time & 4) { 315442542f5fSchristos *((uint64_t *)b + 0) = pt_add(cmd, p+0, 0, 0); 315542542f5fSchristos *((uint64_t *)b + 1) = pt_add(cmd, p+1, 0, 0); 315642542f5fSchristos *((uint64_t *)b + 2) = pt_add(cmd, p+2, 0, 0); 315742542f5fSchristos *((uint64_t *)b + 3) = pt_add(cmd, p+3, 0, 0); 315842542f5fSchristos b += 8; 315942542f5fSchristos p += 4; 316042542f5fSchristos } 316142542f5fSchristos if (n_this_time & 2) { 316242542f5fSchristos *((uint64_t *)b + 0) = pt_add(cmd, p+0, 0, 0); 316342542f5fSchristos *((uint64_t *)b + 1) = pt_add(cmd, p+1, 0, 0); 316442542f5fSchristos b += 4; 316542542f5fSchristos p += 2; 316642542f5fSchristos } 316742542f5fSchristos if (n_this_time & 1) 316842542f5fSchristos *((uint64_t *)b + 0) = pt_add(cmd, p++, 0, 0); 316942542f5fSchristos } else { 317042542f5fSchristos while (n_this_time >= 8) { 317142542f5fSchristos *((uint64_t *)b + 0) = pt_add(cmd, p+0, dx, dy); 317242542f5fSchristos *((uint64_t *)b + 1) = pt_add(cmd, p+1, dx, dy); 317342542f5fSchristos *((uint64_t *)b + 2) = pt_add(cmd, p+2, dx, dy); 317442542f5fSchristos *((uint64_t *)b + 3) = pt_add(cmd, p+3, dx, dy); 317542542f5fSchristos *((uint64_t *)b + 4) = pt_add(cmd, p+4, dx, dy); 317642542f5fSchristos *((uint64_t *)b + 5) = pt_add(cmd, p+5, dx, dy); 317742542f5fSchristos *((uint64_t *)b + 6) = pt_add(cmd, p+6, dx, dy); 317842542f5fSchristos *((uint64_t *)b + 7) = pt_add(cmd, p+7, dx, dy); 317942542f5fSchristos b += 16; 318042542f5fSchristos n_this_time -= 8; 318142542f5fSchristos p += 8; 318242542f5fSchristos } 318342542f5fSchristos if (n_this_time & 4) { 318442542f5fSchristos *((uint64_t *)b + 0) = pt_add(cmd, p+0, dx, dy); 318542542f5fSchristos *((uint64_t *)b + 1) = pt_add(cmd, p+1, dx, dy); 318642542f5fSchristos *((uint64_t *)b + 2) = pt_add(cmd, p+2, dx, dy); 318742542f5fSchristos *((uint64_t *)b + 3) = pt_add(cmd, p+3, dx, dy); 318842542f5fSchristos b += 8; 318942542f5fSchristos p += 8; 319042542f5fSchristos } 319142542f5fSchristos if (n_this_time & 2) { 319242542f5fSchristos *((uint64_t *)b + 0) = pt_add(cmd, p+0, dx, dy); 319342542f5fSchristos *((uint64_t *)b + 1) = pt_add(cmd, p+1, dx, dy); 319442542f5fSchristos b += 4; 319542542f5fSchristos p += 2; 319642542f5fSchristos } 319742542f5fSchristos if (n_this_time & 1) 319842542f5fSchristos *((uint64_t *)b + 0) = pt_add(cmd, p++, dx, dy); 319942542f5fSchristos } 320042542f5fSchristos 320142542f5fSchristos if (!n) 320242542f5fSchristos return; 320342542f5fSchristos 320442542f5fSchristos sna_blt_fill_begin(sna, blt); 320542542f5fSchristos } while (1); 320642542f5fSchristos} 320742542f5fSchristos 320803b705cfSriastradhbool sna_blt_fill(struct sna *sna, uint8_t alu, 320903b705cfSriastradh struct kgem_bo *bo, int bpp, 321003b705cfSriastradh uint32_t pixel, 321103b705cfSriastradh struct sna_fill_op *fill) 321203b705cfSriastradh{ 321303b705cfSriastradh#if DEBUG_NO_BLT || NO_BLT_FILL 321403b705cfSriastradh return false; 321503b705cfSriastradh#endif 321603b705cfSriastradh 321703b705cfSriastradh DBG(("%s(alu=%d, pixel=%x, bpp=%d)\n", __FUNCTION__, alu, pixel, bpp)); 321803b705cfSriastradh 321903b705cfSriastradh if (!kgem_bo_can_blt(&sna->kgem, bo)) { 322003b705cfSriastradh DBG(("%s: rejected due to incompatible Y-tiling\n", 322103b705cfSriastradh __FUNCTION__)); 322203b705cfSriastradh return false; 322303b705cfSriastradh } 322403b705cfSriastradh 322503b705cfSriastradh if (!sna_blt_fill_init(sna, &fill->base.u.blt, 322603b705cfSriastradh bo, bpp, alu, pixel)) 322703b705cfSriastradh return false; 322803b705cfSriastradh 322903b705cfSriastradh fill->blt = sna_blt_fill_op_blt; 323003b705cfSriastradh fill->box = sna_blt_fill_op_box; 323103b705cfSriastradh fill->boxes = sna_blt_fill_op_boxes; 323242542f5fSchristos fill->points = sna_blt_fill_op_points; 323303b705cfSriastradh fill->done = 323403b705cfSriastradh (void (*)(struct sna *, const struct sna_fill_op *))nop_done; 323503b705cfSriastradh return true; 323603b705cfSriastradh} 323703b705cfSriastradh 323803b705cfSriastradhstatic void sna_blt_copy_op_blt(struct sna *sna, 323903b705cfSriastradh const struct sna_copy_op *op, 324003b705cfSriastradh int16_t src_x, int16_t src_y, 324103b705cfSriastradh int16_t width, int16_t height, 324203b705cfSriastradh int16_t dst_x, int16_t dst_y) 324303b705cfSriastradh{ 324403b705cfSriastradh sna_blt_copy_one(sna, &op->base.u.blt, 324503b705cfSriastradh src_x, src_y, 324603b705cfSriastradh width, height, 324703b705cfSriastradh dst_x, dst_y); 324803b705cfSriastradh} 324903b705cfSriastradh 325003b705cfSriastradhbool sna_blt_copy(struct sna *sna, uint8_t alu, 325103b705cfSriastradh struct kgem_bo *src, 325203b705cfSriastradh struct kgem_bo *dst, 325303b705cfSriastradh int bpp, 325403b705cfSriastradh struct sna_copy_op *op) 325503b705cfSriastradh{ 325603b705cfSriastradh#if DEBUG_NO_BLT || NO_BLT_COPY 325703b705cfSriastradh return false; 325803b705cfSriastradh#endif 325903b705cfSriastradh 326003b705cfSriastradh if (!kgem_bo_can_blt(&sna->kgem, src)) 326103b705cfSriastradh return false; 326203b705cfSriastradh 326303b705cfSriastradh if (!kgem_bo_can_blt(&sna->kgem, dst)) 326403b705cfSriastradh return false; 326503b705cfSriastradh 326603b705cfSriastradh if (!sna_blt_copy_init(sna, &op->base.u.blt, 326703b705cfSriastradh src, dst, 326803b705cfSriastradh bpp, alu)) 326903b705cfSriastradh return false; 327003b705cfSriastradh 327103b705cfSriastradh op->blt = sna_blt_copy_op_blt; 327203b705cfSriastradh if (sna->kgem.gen >= 060 && src == dst) 327303b705cfSriastradh op->done = (void (*)(struct sna *, const struct sna_copy_op *)) 327403b705cfSriastradh gen6_blt_copy_done; 327503b705cfSriastradh else 327603b705cfSriastradh op->done = (void (*)(struct sna *, const struct sna_copy_op *)) 327703b705cfSriastradh nop_done; 327803b705cfSriastradh return true; 327903b705cfSriastradh} 328003b705cfSriastradh 328103b705cfSriastradhstatic bool sna_blt_fill_box(struct sna *sna, uint8_t alu, 328203b705cfSriastradh struct kgem_bo *bo, int bpp, 328303b705cfSriastradh uint32_t color, 328403b705cfSriastradh const BoxRec *box) 328503b705cfSriastradh{ 328603b705cfSriastradh struct kgem *kgem = &sna->kgem; 328703b705cfSriastradh uint32_t br13, cmd, *b; 328803b705cfSriastradh bool overwrites; 328903b705cfSriastradh 329003b705cfSriastradh assert(kgem_bo_can_blt (kgem, bo)); 329103b705cfSriastradh 329203b705cfSriastradh DBG(("%s: box=((%d, %d), (%d, %d))\n", __FUNCTION__, 329303b705cfSriastradh box->x1, box->y1, box->x2, box->y2)); 329403b705cfSriastradh 329503b705cfSriastradh assert(box->x1 >= 0); 329603b705cfSriastradh assert(box->y1 >= 0); 329703b705cfSriastradh 329842542f5fSchristos cmd = XY_COLOR_BLT | (kgem->gen >= 0100 ? 5 : 4); 329903b705cfSriastradh br13 = bo->pitch; 330003b705cfSriastradh if (kgem->gen >= 040 && bo->tiling) { 330103b705cfSriastradh cmd |= BLT_DST_TILED; 330203b705cfSriastradh br13 >>= 2; 330303b705cfSriastradh } 330403b705cfSriastradh assert(br13 <= MAXSHORT); 330503b705cfSriastradh 330603b705cfSriastradh br13 |= fill_ROP[alu] << 16; 330703b705cfSriastradh switch (bpp) { 330803b705cfSriastradh default: assert(0); 330903b705cfSriastradh case 32: cmd |= BLT_WRITE_ALPHA | BLT_WRITE_RGB; 331003b705cfSriastradh br13 |= 1 << 25; /* RGB8888 */ 331103b705cfSriastradh case 16: br13 |= 1 << 24; /* RGB565 */ 331203b705cfSriastradh case 8: break; 331303b705cfSriastradh } 331403b705cfSriastradh 331503b705cfSriastradh /* All too frequently one blt completely overwrites the previous */ 331603b705cfSriastradh overwrites = alu == GXcopy || alu == GXclear || alu == GXset; 331742542f5fSchristos if (overwrites) { 331842542f5fSchristos if (sna->kgem.gen >= 0100) { 331942542f5fSchristos if (kgem->nbatch >= 7 && 332042542f5fSchristos kgem->batch[kgem->nbatch-7] == cmd && 332142542f5fSchristos *(uint64_t *)&kgem->batch[kgem->nbatch-5] == *(const uint64_t *)box && 332242542f5fSchristos kgem->reloc[kgem->nreloc-1].target_handle == bo->target_handle) { 332342542f5fSchristos DBG(("%s: replacing last fill\n", __FUNCTION__)); 332442542f5fSchristos kgem->batch[kgem->nbatch-6] = br13; 332542542f5fSchristos kgem->batch[kgem->nbatch-1] = color; 332642542f5fSchristos return true; 332742542f5fSchristos } 332842542f5fSchristos if (kgem->nbatch >= 10 && 332942542f5fSchristos (kgem->batch[kgem->nbatch-10] & 0xffc00000) == XY_SRC_COPY_BLT_CMD && 333042542f5fSchristos *(uint64_t *)&kgem->batch[kgem->nbatch-8] == *(const uint64_t *)box && 333142542f5fSchristos kgem->reloc[kgem->nreloc-2].target_handle == bo->target_handle) { 333242542f5fSchristos DBG(("%s: replacing last copy\n", __FUNCTION__)); 333342542f5fSchristos kgem->batch[kgem->nbatch-10] = cmd; 333442542f5fSchristos kgem->batch[kgem->nbatch-8] = br13; 333542542f5fSchristos kgem->batch[kgem->nbatch-4] = color; 333642542f5fSchristos /* Keep the src bo as part of the execlist, just remove 333742542f5fSchristos * its relocation entry. 333842542f5fSchristos */ 333942542f5fSchristos kgem->nreloc--; 334042542f5fSchristos kgem->nbatch -= 3; 334142542f5fSchristos return true; 334242542f5fSchristos } 334342542f5fSchristos } else { 334442542f5fSchristos if (kgem->nbatch >= 6 && 334542542f5fSchristos kgem->batch[kgem->nbatch-6] == cmd && 334642542f5fSchristos *(uint64_t *)&kgem->batch[kgem->nbatch-4] == *(const uint64_t *)box && 334742542f5fSchristos kgem->reloc[kgem->nreloc-1].target_handle == bo->target_handle) { 334842542f5fSchristos DBG(("%s: replacing last fill\n", __FUNCTION__)); 334942542f5fSchristos kgem->batch[kgem->nbatch-5] = br13; 335042542f5fSchristos kgem->batch[kgem->nbatch-1] = color; 335142542f5fSchristos return true; 335242542f5fSchristos } 335342542f5fSchristos if (kgem->nbatch >= 8 && 335442542f5fSchristos (kgem->batch[kgem->nbatch-8] & 0xffc00000) == XY_SRC_COPY_BLT_CMD && 335542542f5fSchristos *(uint64_t *)&kgem->batch[kgem->nbatch-6] == *(const uint64_t *)box && 335642542f5fSchristos kgem->reloc[kgem->nreloc-2].target_handle == bo->target_handle) { 335742542f5fSchristos DBG(("%s: replacing last copy\n", __FUNCTION__)); 335842542f5fSchristos kgem->batch[kgem->nbatch-8] = cmd; 335942542f5fSchristos kgem->batch[kgem->nbatch-7] = br13; 336042542f5fSchristos kgem->batch[kgem->nbatch-3] = color; 336142542f5fSchristos /* Keep the src bo as part of the execlist, just remove 336242542f5fSchristos * its relocation entry. 336342542f5fSchristos */ 336442542f5fSchristos kgem->nreloc--; 336542542f5fSchristos kgem->nbatch -= 2; 336642542f5fSchristos return true; 336742542f5fSchristos } 336842542f5fSchristos } 336903b705cfSriastradh } 337003b705cfSriastradh 337103b705cfSriastradh /* If we are currently emitting SCANLINES, keep doing so */ 337203b705cfSriastradh if (sna->blt_state.fill_bo == bo->unique_id && 337303b705cfSriastradh sna->blt_state.fill_pixel == color && 337403b705cfSriastradh (sna->blt_state.fill_alu == alu || 337503b705cfSriastradh sna->blt_state.fill_alu == ~alu)) { 337603b705cfSriastradh DBG(("%s: matching last fill, converting to scanlines\n", 337703b705cfSriastradh __FUNCTION__)); 337803b705cfSriastradh return false; 337903b705cfSriastradh } 338003b705cfSriastradh 338103b705cfSriastradh kgem_set_mode(kgem, KGEM_BLT, bo); 338242542f5fSchristos if (!kgem_check_batch(kgem, 7) || 338303b705cfSriastradh !kgem_check_reloc(kgem, 1) || 338403b705cfSriastradh !kgem_check_bo_fenced(kgem, bo)) { 338503b705cfSriastradh kgem_submit(kgem); 338642542f5fSchristos if (!kgem_check_bo_fenced(&sna->kgem, bo)) 338742542f5fSchristos return false; 338842542f5fSchristos 338903b705cfSriastradh _kgem_set_mode(kgem, KGEM_BLT); 339003b705cfSriastradh } 339103b705cfSriastradh 339242542f5fSchristos assert(kgem_check_batch(kgem, 6)); 339342542f5fSchristos assert(kgem_check_reloc(kgem, 1)); 339442542f5fSchristos 339542542f5fSchristos assert(sna->kgem.mode == KGEM_BLT); 339603b705cfSriastradh b = kgem->batch + kgem->nbatch; 339703b705cfSriastradh b[0] = cmd; 339803b705cfSriastradh b[1] = br13; 339903b705cfSriastradh *(uint64_t *)(b+2) = *(const uint64_t *)box; 340042542f5fSchristos if (kgem->gen >= 0100) { 340142542f5fSchristos *(uint64_t *)(b+4) = 340242542f5fSchristos kgem_add_reloc64(kgem, kgem->nbatch + 4, bo, 340342542f5fSchristos I915_GEM_DOMAIN_RENDER << 16 | 340442542f5fSchristos I915_GEM_DOMAIN_RENDER | 340542542f5fSchristos KGEM_RELOC_FENCED, 340642542f5fSchristos 0); 340742542f5fSchristos b[6] = color; 340842542f5fSchristos kgem->nbatch += 7; 340942542f5fSchristos } else { 341042542f5fSchristos b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4, bo, 341142542f5fSchristos I915_GEM_DOMAIN_RENDER << 16 | 341242542f5fSchristos I915_GEM_DOMAIN_RENDER | 341342542f5fSchristos KGEM_RELOC_FENCED, 341442542f5fSchristos 0); 341542542f5fSchristos b[5] = color; 341642542f5fSchristos kgem->nbatch += 6; 341742542f5fSchristos } 341803b705cfSriastradh assert(kgem->nbatch < kgem->surface); 341903b705cfSriastradh 342003b705cfSriastradh sna->blt_state.fill_bo = bo->unique_id; 342103b705cfSriastradh sna->blt_state.fill_pixel = color; 342203b705cfSriastradh sna->blt_state.fill_alu = ~alu; 342303b705cfSriastradh return true; 342403b705cfSriastradh} 342503b705cfSriastradh 342603b705cfSriastradhbool sna_blt_fill_boxes(struct sna *sna, uint8_t alu, 342703b705cfSriastradh struct kgem_bo *bo, int bpp, 342803b705cfSriastradh uint32_t pixel, 342903b705cfSriastradh const BoxRec *box, int nbox) 343003b705cfSriastradh{ 343103b705cfSriastradh struct kgem *kgem = &sna->kgem; 343203b705cfSriastradh uint32_t br13, cmd; 343303b705cfSriastradh 343403b705cfSriastradh#if DEBUG_NO_BLT || NO_BLT_FILL_BOXES 343503b705cfSriastradh return false; 343603b705cfSriastradh#endif 343703b705cfSriastradh 343803b705cfSriastradh DBG(("%s (%d, %08x, %d) x %d\n", 343903b705cfSriastradh __FUNCTION__, bpp, pixel, alu, nbox)); 344003b705cfSriastradh 344103b705cfSriastradh if (!kgem_bo_can_blt(kgem, bo)) { 344203b705cfSriastradh DBG(("%s: fallback -- cannot blt to dst\n", __FUNCTION__)); 344303b705cfSriastradh return false; 344403b705cfSriastradh } 344503b705cfSriastradh 344603b705cfSriastradh if (alu == GXclear) 344703b705cfSriastradh pixel = 0; 344803b705cfSriastradh else if (alu == GXcopy) { 344903b705cfSriastradh if (pixel == 0) 345003b705cfSriastradh alu = GXclear; 345103b705cfSriastradh else if (pixel == -1) 345203b705cfSriastradh alu = GXset; 345303b705cfSriastradh } 345403b705cfSriastradh 345503b705cfSriastradh if (nbox == 1 && sna_blt_fill_box(sna, alu, bo, bpp, pixel, box)) 345603b705cfSriastradh return true; 345703b705cfSriastradh 345803b705cfSriastradh br13 = bo->pitch; 345903b705cfSriastradh cmd = XY_SCANLINE_BLT; 346003b705cfSriastradh if (kgem->gen >= 040 && bo->tiling) { 346103b705cfSriastradh cmd |= 1 << 11; 346203b705cfSriastradh br13 >>= 2; 346303b705cfSriastradh } 346403b705cfSriastradh assert(br13 <= MAXSHORT); 346503b705cfSriastradh 346603b705cfSriastradh br13 |= 1<<31 | fill_ROP[alu] << 16; 346703b705cfSriastradh switch (bpp) { 346803b705cfSriastradh default: assert(0); 346903b705cfSriastradh case 32: br13 |= 1 << 25; /* RGB8888 */ 347003b705cfSriastradh case 16: br13 |= 1 << 24; /* RGB565 */ 347103b705cfSriastradh case 8: break; 347203b705cfSriastradh } 347303b705cfSriastradh 347403b705cfSriastradh kgem_set_mode(kgem, KGEM_BLT, bo); 347542542f5fSchristos if (!kgem_check_batch(kgem, 14) || 347603b705cfSriastradh !kgem_check_bo_fenced(kgem, bo)) { 347703b705cfSriastradh kgem_submit(kgem); 347803b705cfSriastradh if (!kgem_check_bo_fenced(&sna->kgem, bo)) 347903b705cfSriastradh return false; 348003b705cfSriastradh _kgem_set_mode(kgem, KGEM_BLT); 348103b705cfSriastradh } 348203b705cfSriastradh 348303b705cfSriastradh if (sna->blt_state.fill_bo != bo->unique_id || 348403b705cfSriastradh sna->blt_state.fill_pixel != pixel || 348503b705cfSriastradh sna->blt_state.fill_alu != alu) 348603b705cfSriastradh { 348703b705cfSriastradh uint32_t *b; 348803b705cfSriastradh 348903b705cfSriastradh if (!kgem_check_reloc(kgem, 1)) { 349003b705cfSriastradh _kgem_submit(kgem); 349142542f5fSchristos if (!kgem_check_bo_fenced(&sna->kgem, bo)) 349242542f5fSchristos return false; 349303b705cfSriastradh _kgem_set_mode(kgem, KGEM_BLT); 349403b705cfSriastradh } 349503b705cfSriastradh 349642542f5fSchristos assert(sna->kgem.mode == KGEM_BLT); 349703b705cfSriastradh b = kgem->batch + kgem->nbatch; 349842542f5fSchristos if (kgem->gen >= 0100) { 349942542f5fSchristos b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 8; 350042542f5fSchristos if (bpp == 32) 350142542f5fSchristos b[0] |= BLT_WRITE_ALPHA | BLT_WRITE_RGB; 350242542f5fSchristos if (bo->tiling) 350342542f5fSchristos b[0] |= BLT_DST_TILED; 350442542f5fSchristos b[1] = br13; 350542542f5fSchristos b[2] = 0; 350642542f5fSchristos b[3] = 0; 350742542f5fSchristos *(uint64_t *)(b+4) = 350842542f5fSchristos kgem_add_reloc64(kgem, kgem->nbatch + 4, bo, 350942542f5fSchristos I915_GEM_DOMAIN_RENDER << 16 | 351042542f5fSchristos I915_GEM_DOMAIN_RENDER | 351142542f5fSchristos KGEM_RELOC_FENCED, 351242542f5fSchristos 0); 351342542f5fSchristos b[6] = pixel; 351442542f5fSchristos b[7] = pixel; 351542542f5fSchristos b[8] = 0; 351642542f5fSchristos b[9] = 0; 351742542f5fSchristos kgem->nbatch += 10; 351842542f5fSchristos } else { 351942542f5fSchristos b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 7; 352042542f5fSchristos if (bpp == 32) 352142542f5fSchristos b[0] |= BLT_WRITE_ALPHA | BLT_WRITE_RGB; 352242542f5fSchristos if (bo->tiling && kgem->gen >= 040) 352342542f5fSchristos b[0] |= BLT_DST_TILED; 352442542f5fSchristos b[1] = br13; 352542542f5fSchristos b[2] = 0; 352642542f5fSchristos b[3] = 0; 352742542f5fSchristos b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4, bo, 352842542f5fSchristos I915_GEM_DOMAIN_RENDER << 16 | 352942542f5fSchristos I915_GEM_DOMAIN_RENDER | 353042542f5fSchristos KGEM_RELOC_FENCED, 353142542f5fSchristos 0); 353242542f5fSchristos b[5] = pixel; 353342542f5fSchristos b[6] = pixel; 353442542f5fSchristos b[7] = 0; 353542542f5fSchristos b[8] = 0; 353642542f5fSchristos kgem->nbatch += 9; 353742542f5fSchristos } 353803b705cfSriastradh assert(kgem->nbatch < kgem->surface); 353903b705cfSriastradh 354003b705cfSriastradh sna->blt_state.fill_bo = bo->unique_id; 354103b705cfSriastradh sna->blt_state.fill_pixel = pixel; 354203b705cfSriastradh sna->blt_state.fill_alu = alu; 354303b705cfSriastradh } 354403b705cfSriastradh 354503b705cfSriastradh do { 354603b705cfSriastradh int nbox_this_time; 354703b705cfSriastradh 354803b705cfSriastradh nbox_this_time = nbox; 354903b705cfSriastradh if (3*nbox_this_time > kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) 355003b705cfSriastradh nbox_this_time = (kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) / 3; 355103b705cfSriastradh assert(nbox_this_time); 355203b705cfSriastradh nbox -= nbox_this_time; 355303b705cfSriastradh 355442542f5fSchristos assert(sna->kgem.mode == KGEM_BLT); 355503b705cfSriastradh do { 355603b705cfSriastradh uint32_t *b; 355703b705cfSriastradh 355803b705cfSriastradh DBG(("%s: (%d, %d), (%d, %d): %08x\n", 355903b705cfSriastradh __FUNCTION__, 356003b705cfSriastradh box->x1, box->y1, 356103b705cfSriastradh box->x2, box->y2, 356203b705cfSriastradh pixel)); 356303b705cfSriastradh 356403b705cfSriastradh assert(box->x1 >= 0); 356503b705cfSriastradh assert(box->y1 >= 0); 356603b705cfSriastradh assert(box->y2 * bo->pitch <= kgem_bo_size(bo)); 356703b705cfSriastradh 356803b705cfSriastradh b = kgem->batch + kgem->nbatch; 356903b705cfSriastradh kgem->nbatch += 3; 357003b705cfSriastradh assert(kgem->nbatch < kgem->surface); 357103b705cfSriastradh b[0] = cmd; 357203b705cfSriastradh *(uint64_t *)(b+1) = *(const uint64_t *)box; 357303b705cfSriastradh box++; 357403b705cfSriastradh } while (--nbox_this_time); 357503b705cfSriastradh 357603b705cfSriastradh if (nbox) { 357703b705cfSriastradh uint32_t *b; 357803b705cfSriastradh 357903b705cfSriastradh _kgem_submit(kgem); 358003b705cfSriastradh _kgem_set_mode(kgem, KGEM_BLT); 358103b705cfSriastradh 358242542f5fSchristos assert(sna->kgem.mode == KGEM_BLT); 358303b705cfSriastradh b = kgem->batch + kgem->nbatch; 358442542f5fSchristos if (kgem->gen >= 0100) { 358542542f5fSchristos b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 8; 358642542f5fSchristos if (bpp == 32) 358742542f5fSchristos b[0] |= BLT_WRITE_ALPHA | BLT_WRITE_RGB; 358842542f5fSchristos if (bo->tiling) 358942542f5fSchristos b[0] |= BLT_DST_TILED; 359042542f5fSchristos b[1] = br13; 359142542f5fSchristos b[2] = 0; 359242542f5fSchristos b[3] = 0; 359342542f5fSchristos *(uint64_t *)(b+4) = 359442542f5fSchristos kgem_add_reloc64(kgem, kgem->nbatch + 4, bo, 359542542f5fSchristos I915_GEM_DOMAIN_RENDER << 16 | 359642542f5fSchristos I915_GEM_DOMAIN_RENDER | 359742542f5fSchristos KGEM_RELOC_FENCED, 359842542f5fSchristos 0); 359942542f5fSchristos b[6] = pixel; 360042542f5fSchristos b[7] = pixel; 360142542f5fSchristos b[8] = 0; 360242542f5fSchristos b[9] = 0; 360342542f5fSchristos kgem->nbatch += 10; 360442542f5fSchristos } else { 360542542f5fSchristos b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 7; 360642542f5fSchristos if (bpp == 32) 360742542f5fSchristos b[0] |= BLT_WRITE_ALPHA | BLT_WRITE_RGB; 360842542f5fSchristos if (bo->tiling && kgem->gen >= 040) 360942542f5fSchristos b[0] |= BLT_DST_TILED; 361042542f5fSchristos b[1] = br13; 361142542f5fSchristos b[2] = 0; 361242542f5fSchristos b[3] = 0; 361342542f5fSchristos b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4, bo, 361442542f5fSchristos I915_GEM_DOMAIN_RENDER << 16 | 361542542f5fSchristos I915_GEM_DOMAIN_RENDER | 361642542f5fSchristos KGEM_RELOC_FENCED, 361742542f5fSchristos 0); 361842542f5fSchristos b[5] = pixel; 361942542f5fSchristos b[6] = pixel; 362042542f5fSchristos b[7] = 0; 362142542f5fSchristos b[8] = 0; 362242542f5fSchristos kgem->nbatch += 9; 362342542f5fSchristos } 362403b705cfSriastradh assert(kgem->nbatch < kgem->surface); 362503b705cfSriastradh } 362603b705cfSriastradh } while (nbox); 362703b705cfSriastradh 362842542f5fSchristos if (kgem->nexec > 1 && __kgem_ring_empty(kgem)) { 362942542f5fSchristos DBG(("%s: flushing BLT operation on empty ring\n", __FUNCTION__)); 363003b705cfSriastradh _kgem_submit(kgem); 363142542f5fSchristos } 363203b705cfSriastradh 363303b705cfSriastradh return true; 363403b705cfSriastradh} 363503b705cfSriastradh 363603b705cfSriastradhbool sna_blt_copy_boxes(struct sna *sna, uint8_t alu, 363703b705cfSriastradh struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy, 363803b705cfSriastradh struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy, 363903b705cfSriastradh int bpp, const BoxRec *box, int nbox) 364003b705cfSriastradh{ 364103b705cfSriastradh struct kgem *kgem = &sna->kgem; 364203b705cfSriastradh unsigned src_pitch, br13, cmd; 364303b705cfSriastradh 364403b705cfSriastradh#if DEBUG_NO_BLT || NO_BLT_COPY_BOXES 364503b705cfSriastradh return false; 364603b705cfSriastradh#endif 364703b705cfSriastradh 364803b705cfSriastradh DBG(("%s src=(%d, %d) -> (%d, %d) x %d, tiling=(%d, %d), pitch=(%d, %d)\n", 364903b705cfSriastradh __FUNCTION__, src_dx, src_dy, dst_dx, dst_dy, nbox, 365003b705cfSriastradh src_bo->tiling, dst_bo->tiling, 365103b705cfSriastradh src_bo->pitch, dst_bo->pitch)); 365242542f5fSchristos assert(nbox); 365303b705cfSriastradh 365442542f5fSchristos if (wedged(sna) || !kgem_bo_can_blt(kgem, src_bo) || !kgem_bo_can_blt(kgem, dst_bo)) { 365503b705cfSriastradh DBG(("%s: cannot blt to src? %d or dst? %d\n", 365603b705cfSriastradh __FUNCTION__, 365703b705cfSriastradh kgem_bo_can_blt(kgem, src_bo), 365803b705cfSriastradh kgem_bo_can_blt(kgem, dst_bo))); 365903b705cfSriastradh return false; 366003b705cfSriastradh } 366103b705cfSriastradh 366203b705cfSriastradh cmd = XY_SRC_COPY_BLT_CMD; 366303b705cfSriastradh if (bpp == 32) 366403b705cfSriastradh cmd |= BLT_WRITE_ALPHA | BLT_WRITE_RGB; 366503b705cfSriastradh 366603b705cfSriastradh src_pitch = src_bo->pitch; 366703b705cfSriastradh if (kgem->gen >= 040 && src_bo->tiling) { 366803b705cfSriastradh cmd |= BLT_SRC_TILED; 366903b705cfSriastradh src_pitch >>= 2; 367003b705cfSriastradh } 367103b705cfSriastradh assert(src_pitch <= MAXSHORT); 367203b705cfSriastradh 367303b705cfSriastradh br13 = dst_bo->pitch; 367403b705cfSriastradh if (kgem->gen >= 040 && dst_bo->tiling) { 367503b705cfSriastradh cmd |= BLT_DST_TILED; 367603b705cfSriastradh br13 >>= 2; 367703b705cfSriastradh } 367803b705cfSriastradh assert(br13 <= MAXSHORT); 367903b705cfSriastradh 368003b705cfSriastradh br13 |= copy_ROP[alu] << 16; 368103b705cfSriastradh switch (bpp) { 368203b705cfSriastradh default: assert(0); 368303b705cfSriastradh case 32: br13 |= 1 << 25; /* RGB8888 */ 368403b705cfSriastradh case 16: br13 |= 1 << 24; /* RGB565 */ 368503b705cfSriastradh case 8: break; 368603b705cfSriastradh } 368703b705cfSriastradh 368803b705cfSriastradh /* Compare first box against a previous fill */ 368942542f5fSchristos if ((alu == GXcopy || alu == GXclear || alu == GXset) && 369042542f5fSchristos kgem->reloc[kgem->nreloc-1].target_handle == dst_bo->target_handle) { 369142542f5fSchristos if (kgem->gen >= 0100) { 369242542f5fSchristos if (kgem->nbatch >= 7 && 369342542f5fSchristos kgem->batch[kgem->nbatch-7] == (XY_COLOR_BLT | (cmd & (BLT_DST_TILED | BLT_WRITE_ALPHA | BLT_WRITE_RGB)) | 5) && 369442542f5fSchristos kgem->batch[kgem->nbatch-5] == ((uint32_t)(box->y1 + dst_dy) << 16 | (uint16_t)(box->x1 + dst_dx)) && 369542542f5fSchristos kgem->batch[kgem->nbatch-4] == ((uint32_t)(box->y2 + dst_dy) << 16 | (uint16_t)(box->x2 + dst_dx))) { 369642542f5fSchristos DBG(("%s: deleting last fill\n", __FUNCTION__)); 369742542f5fSchristos kgem->nbatch -= 7; 369842542f5fSchristos kgem->nreloc--; 369942542f5fSchristos } 370042542f5fSchristos } else { 370142542f5fSchristos if (kgem->nbatch >= 6 && 370242542f5fSchristos kgem->batch[kgem->nbatch-6] == (XY_COLOR_BLT | (cmd & (BLT_DST_TILED | BLT_WRITE_ALPHA | BLT_WRITE_RGB)) | 4) && 370342542f5fSchristos kgem->batch[kgem->nbatch-4] == ((uint32_t)(box->y1 + dst_dy) << 16 | (uint16_t)(box->x1 + dst_dx)) && 370442542f5fSchristos kgem->batch[kgem->nbatch-3] == ((uint32_t)(box->y2 + dst_dy) << 16 | (uint16_t)(box->x2 + dst_dx))) { 370542542f5fSchristos DBG(("%s: deleting last fill\n", __FUNCTION__)); 370642542f5fSchristos kgem->nbatch -= 6; 370742542f5fSchristos kgem->nreloc--; 370842542f5fSchristos } 370942542f5fSchristos } 371003b705cfSriastradh } 371103b705cfSriastradh 371203b705cfSriastradh kgem_set_mode(kgem, KGEM_BLT, dst_bo); 371342542f5fSchristos if (!kgem_check_batch(kgem, 10) || 371403b705cfSriastradh !kgem_check_reloc(kgem, 2) || 371503b705cfSriastradh !kgem_check_many_bo_fenced(kgem, dst_bo, src_bo, NULL)) { 371603b705cfSriastradh kgem_submit(kgem); 371742542f5fSchristos if (!kgem_check_many_bo_fenced(kgem, dst_bo, src_bo, NULL)) { 371842542f5fSchristos DBG(("%s: not enough room in aperture, fallback to tiling copy\n", __FUNCTION__)); 371903b705cfSriastradh return sna_tiling_blt_copy_boxes(sna, alu, 372003b705cfSriastradh src_bo, src_dx, src_dy, 372103b705cfSriastradh dst_bo, dst_dx, dst_dy, 372203b705cfSriastradh bpp, box, nbox); 372342542f5fSchristos } 372403b705cfSriastradh _kgem_set_mode(kgem, KGEM_BLT); 372503b705cfSriastradh } 372603b705cfSriastradh 372703b705cfSriastradh if ((dst_dx | dst_dy) == 0) { 372842542f5fSchristos if (kgem->gen >= 0100) { 372942542f5fSchristos uint64_t hdr = (uint64_t)br13 << 32 | cmd | 8; 373003b705cfSriastradh do { 373142542f5fSchristos int nbox_this_time; 373242542f5fSchristos 373342542f5fSchristos nbox_this_time = nbox; 373442542f5fSchristos if (10*nbox_this_time > kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) 373542542f5fSchristos nbox_this_time = (kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) / 8; 373642542f5fSchristos if (2*nbox_this_time > KGEM_RELOC_SIZE(kgem) - kgem->nreloc) 373742542f5fSchristos nbox_this_time = (KGEM_RELOC_SIZE(kgem) - kgem->nreloc)/2; 373842542f5fSchristos assert(nbox_this_time); 373942542f5fSchristos nbox -= nbox_this_time; 374042542f5fSchristos 374142542f5fSchristos assert(sna->kgem.mode == KGEM_BLT); 374242542f5fSchristos do { 374342542f5fSchristos uint32_t *b = kgem->batch + kgem->nbatch; 374442542f5fSchristos 374542542f5fSchristos DBG((" %s: box=(%d, %d)x(%d, %d)\n", 374642542f5fSchristos __FUNCTION__, 374742542f5fSchristos box->x1, box->y1, 374842542f5fSchristos box->x2 - box->x1, box->y2 - box->y1)); 374942542f5fSchristos 375042542f5fSchristos assert(box->x1 + src_dx >= 0); 375142542f5fSchristos assert(box->y1 + src_dy >= 0); 375242542f5fSchristos assert(box->x1 + src_dx <= INT16_MAX); 375342542f5fSchristos assert(box->y1 + src_dy <= INT16_MAX); 375442542f5fSchristos 375542542f5fSchristos assert(box->x1 >= 0); 375642542f5fSchristos assert(box->y1 >= 0); 375742542f5fSchristos 375842542f5fSchristos *(uint64_t *)&b[0] = hdr; 375942542f5fSchristos *(uint64_t *)&b[2] = *(const uint64_t *)box; 376042542f5fSchristos *(uint64_t *)(b+4) = 376142542f5fSchristos kgem_add_reloc64(kgem, kgem->nbatch + 4, dst_bo, 376242542f5fSchristos I915_GEM_DOMAIN_RENDER << 16 | 376342542f5fSchristos I915_GEM_DOMAIN_RENDER | 376442542f5fSchristos KGEM_RELOC_FENCED, 376542542f5fSchristos 0); 376642542f5fSchristos b[6] = add2(b[2], src_dx, src_dy); 376742542f5fSchristos b[7] = src_pitch; 376842542f5fSchristos *(uint64_t *)(b+8) = 376942542f5fSchristos kgem_add_reloc64(kgem, kgem->nbatch + 8, src_bo, 377042542f5fSchristos I915_GEM_DOMAIN_RENDER << 16 | 377142542f5fSchristos KGEM_RELOC_FENCED, 377242542f5fSchristos 0); 377342542f5fSchristos kgem->nbatch += 10; 377442542f5fSchristos assert(kgem->nbatch < kgem->surface); 377542542f5fSchristos box++; 377642542f5fSchristos } while (--nbox_this_time); 377742542f5fSchristos 377842542f5fSchristos if (!nbox) 377942542f5fSchristos break; 378042542f5fSchristos 378142542f5fSchristos _kgem_submit(kgem); 378242542f5fSchristos _kgem_set_mode(kgem, KGEM_BLT); 378342542f5fSchristos } while (1); 378442542f5fSchristos } else { 378542542f5fSchristos uint64_t hdr = (uint64_t)br13 << 32 | cmd | 6; 378642542f5fSchristos do { 378742542f5fSchristos int nbox_this_time; 378842542f5fSchristos 378942542f5fSchristos nbox_this_time = nbox; 379042542f5fSchristos if (8*nbox_this_time > kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) 379142542f5fSchristos nbox_this_time = (kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) / 8; 379242542f5fSchristos if (2*nbox_this_time > KGEM_RELOC_SIZE(kgem) - kgem->nreloc) 379342542f5fSchristos nbox_this_time = (KGEM_RELOC_SIZE(kgem) - kgem->nreloc)/2; 379442542f5fSchristos assert(nbox_this_time); 379542542f5fSchristos nbox -= nbox_this_time; 379642542f5fSchristos 379742542f5fSchristos assert(sna->kgem.mode == KGEM_BLT); 379842542f5fSchristos do { 379942542f5fSchristos uint32_t *b = kgem->batch + kgem->nbatch; 380042542f5fSchristos 380142542f5fSchristos DBG((" %s: box=(%d, %d)x(%d, %d)\n", 380242542f5fSchristos __FUNCTION__, 380342542f5fSchristos box->x1, box->y1, 380442542f5fSchristos box->x2 - box->x1, box->y2 - box->y1)); 380542542f5fSchristos 380642542f5fSchristos assert(box->x1 + src_dx >= 0); 380742542f5fSchristos assert(box->y1 + src_dy >= 0); 380842542f5fSchristos assert(box->x1 + src_dx <= INT16_MAX); 380942542f5fSchristos assert(box->y1 + src_dy <= INT16_MAX); 381042542f5fSchristos 381142542f5fSchristos assert(box->x1 >= 0); 381242542f5fSchristos assert(box->y1 >= 0); 381342542f5fSchristos 381442542f5fSchristos *(uint64_t *)&b[0] = hdr; 381542542f5fSchristos *(uint64_t *)&b[2] = *(const uint64_t *)box; 381642542f5fSchristos b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4, dst_bo, 381742542f5fSchristos I915_GEM_DOMAIN_RENDER << 16 | 381842542f5fSchristos I915_GEM_DOMAIN_RENDER | 381942542f5fSchristos KGEM_RELOC_FENCED, 382042542f5fSchristos 0); 382142542f5fSchristos b[5] = add2(b[2], src_dx, src_dy); 382242542f5fSchristos b[6] = src_pitch; 382342542f5fSchristos b[7] = kgem_add_reloc(kgem, kgem->nbatch + 7, src_bo, 382442542f5fSchristos I915_GEM_DOMAIN_RENDER << 16 | 382542542f5fSchristos KGEM_RELOC_FENCED, 382642542f5fSchristos 0); 382742542f5fSchristos kgem->nbatch += 8; 382842542f5fSchristos assert(kgem->nbatch < kgem->surface); 382942542f5fSchristos box++; 383042542f5fSchristos } while (--nbox_this_time); 383142542f5fSchristos 383242542f5fSchristos if (!nbox) 383342542f5fSchristos break; 383442542f5fSchristos 383542542f5fSchristos _kgem_submit(kgem); 383642542f5fSchristos _kgem_set_mode(kgem, KGEM_BLT); 383742542f5fSchristos } while (1); 383842542f5fSchristos } 383942542f5fSchristos } else { 384042542f5fSchristos if (kgem->gen >= 0100) { 384142542f5fSchristos cmd |= 8; 384242542f5fSchristos do { 384342542f5fSchristos int nbox_this_time; 384442542f5fSchristos 384542542f5fSchristos nbox_this_time = nbox; 384642542f5fSchristos if (10*nbox_this_time > kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) 384742542f5fSchristos nbox_this_time = (kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) / 8; 384842542f5fSchristos if (2*nbox_this_time > KGEM_RELOC_SIZE(kgem) - kgem->nreloc) 384942542f5fSchristos nbox_this_time = (KGEM_RELOC_SIZE(kgem) - kgem->nreloc)/2; 385042542f5fSchristos assert(nbox_this_time); 385142542f5fSchristos nbox -= nbox_this_time; 385242542f5fSchristos 385342542f5fSchristos assert(sna->kgem.mode == KGEM_BLT); 385442542f5fSchristos do { 385542542f5fSchristos uint32_t *b = kgem->batch + kgem->nbatch; 385642542f5fSchristos 385742542f5fSchristos DBG((" %s: box=(%d, %d)x(%d, %d)\n", 385842542f5fSchristos __FUNCTION__, 385942542f5fSchristos box->x1, box->y1, 386042542f5fSchristos box->x2 - box->x1, box->y2 - box->y1)); 386142542f5fSchristos 386242542f5fSchristos assert(box->x1 + src_dx >= 0); 386342542f5fSchristos assert(box->y1 + src_dy >= 0); 386442542f5fSchristos 386542542f5fSchristos assert(box->x1 + dst_dx >= 0); 386642542f5fSchristos assert(box->y1 + dst_dy >= 0); 386742542f5fSchristos 386842542f5fSchristos b[0] = cmd; 386942542f5fSchristos b[1] = br13; 387042542f5fSchristos b[2] = ((box->y1 + dst_dy) << 16) | (box->x1 + dst_dx); 387142542f5fSchristos b[3] = ((box->y2 + dst_dy) << 16) | (box->x2 + dst_dx); 387242542f5fSchristos *(uint64_t *)(b+4) = 387342542f5fSchristos kgem_add_reloc64(kgem, kgem->nbatch + 4, dst_bo, 387442542f5fSchristos I915_GEM_DOMAIN_RENDER << 16 | 387542542f5fSchristos I915_GEM_DOMAIN_RENDER | 387642542f5fSchristos KGEM_RELOC_FENCED, 387742542f5fSchristos 0); 387842542f5fSchristos b[6] = ((box->y1 + src_dy) << 16) | (box->x1 + src_dx); 387942542f5fSchristos b[7] = src_pitch; 388042542f5fSchristos *(uint64_t *)(b+8) = 388142542f5fSchristos kgem_add_reloc64(kgem, kgem->nbatch + 8, src_bo, 388242542f5fSchristos I915_GEM_DOMAIN_RENDER << 16 | 388342542f5fSchristos KGEM_RELOC_FENCED, 388442542f5fSchristos 0); 388542542f5fSchristos kgem->nbatch += 10; 388642542f5fSchristos assert(kgem->nbatch < kgem->surface); 388742542f5fSchristos box++; 388842542f5fSchristos } while (--nbox_this_time); 388942542f5fSchristos 389042542f5fSchristos if (!nbox) 389142542f5fSchristos break; 389242542f5fSchristos 389342542f5fSchristos _kgem_submit(kgem); 389442542f5fSchristos _kgem_set_mode(kgem, KGEM_BLT); 389542542f5fSchristos } while (1); 389642542f5fSchristos } else { 389742542f5fSchristos cmd |= 6; 389842542f5fSchristos do { 389942542f5fSchristos int nbox_this_time; 390042542f5fSchristos 390142542f5fSchristos nbox_this_time = nbox; 390242542f5fSchristos if (8*nbox_this_time > kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) 390342542f5fSchristos nbox_this_time = (kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) / 8; 390442542f5fSchristos if (2*nbox_this_time > KGEM_RELOC_SIZE(kgem) - kgem->nreloc) 390542542f5fSchristos nbox_this_time = (KGEM_RELOC_SIZE(kgem) - kgem->nreloc)/2; 390642542f5fSchristos assert(nbox_this_time); 390742542f5fSchristos nbox -= nbox_this_time; 390842542f5fSchristos 390942542f5fSchristos assert(sna->kgem.mode == KGEM_BLT); 391042542f5fSchristos do { 391142542f5fSchristos uint32_t *b = kgem->batch + kgem->nbatch; 391242542f5fSchristos 391342542f5fSchristos DBG((" %s: box=(%d, %d)x(%d, %d)\n", 391442542f5fSchristos __FUNCTION__, 391542542f5fSchristos box->x1, box->y1, 391642542f5fSchristos box->x2 - box->x1, box->y2 - box->y1)); 391742542f5fSchristos 391842542f5fSchristos assert(box->x1 + src_dx >= 0); 391942542f5fSchristos assert(box->y1 + src_dy >= 0); 392042542f5fSchristos 392142542f5fSchristos assert(box->x1 + dst_dx >= 0); 392242542f5fSchristos assert(box->y1 + dst_dy >= 0); 392342542f5fSchristos 392442542f5fSchristos b[0] = cmd; 392542542f5fSchristos b[1] = br13; 392642542f5fSchristos b[2] = ((box->y1 + dst_dy) << 16) | (box->x1 + dst_dx); 392742542f5fSchristos b[3] = ((box->y2 + dst_dy) << 16) | (box->x2 + dst_dx); 392842542f5fSchristos b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4, dst_bo, 392942542f5fSchristos I915_GEM_DOMAIN_RENDER << 16 | 393042542f5fSchristos I915_GEM_DOMAIN_RENDER | 393142542f5fSchristos KGEM_RELOC_FENCED, 393242542f5fSchristos 0); 393342542f5fSchristos b[5] = ((box->y1 + src_dy) << 16) | (box->x1 + src_dx); 393442542f5fSchristos b[6] = src_pitch; 393542542f5fSchristos b[7] = kgem_add_reloc(kgem, kgem->nbatch + 7, src_bo, 393642542f5fSchristos I915_GEM_DOMAIN_RENDER << 16 | 393742542f5fSchristos KGEM_RELOC_FENCED, 393842542f5fSchristos 0); 393942542f5fSchristos kgem->nbatch += 8; 394042542f5fSchristos assert(kgem->nbatch < kgem->surface); 394142542f5fSchristos box++; 394242542f5fSchristos } while (--nbox_this_time); 394342542f5fSchristos 394442542f5fSchristos if (!nbox) 394542542f5fSchristos break; 394642542f5fSchristos 394742542f5fSchristos _kgem_submit(kgem); 394842542f5fSchristos _kgem_set_mode(kgem, KGEM_BLT); 394942542f5fSchristos } while (1); 395042542f5fSchristos } 395142542f5fSchristos } 395203b705cfSriastradh 395342542f5fSchristos if (kgem->nexec > 1 && __kgem_ring_empty(kgem)) { 395442542f5fSchristos DBG(("%s: flushing BLT operation on empty ring\n", __FUNCTION__)); 395542542f5fSchristos _kgem_submit(kgem); 395642542f5fSchristos } else if (kgem->gen >= 060 && src_bo == dst_bo && kgem_check_batch(kgem, 3)) { 395742542f5fSchristos uint32_t *b = kgem->batch + kgem->nbatch; 395842542f5fSchristos assert(sna->kgem.mode == KGEM_BLT); 395942542f5fSchristos b[0] = XY_SETUP_CLIP; 396042542f5fSchristos b[1] = b[2] = 0; 396142542f5fSchristos kgem->nbatch += 3; 396242542f5fSchristos assert(kgem->nbatch < kgem->surface); 396342542f5fSchristos } 396403b705cfSriastradh 396542542f5fSchristos sna->blt_state.fill_bo = 0; 396642542f5fSchristos return true; 396742542f5fSchristos} 396803b705cfSriastradh 396942542f5fSchristosbool sna_blt_copy_boxes__with_alpha(struct sna *sna, uint8_t alu, 397042542f5fSchristos struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy, 397142542f5fSchristos struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy, 397242542f5fSchristos int bpp, int alpha_fixup, 397342542f5fSchristos const BoxRec *box, int nbox) 397442542f5fSchristos{ 397542542f5fSchristos struct kgem *kgem = &sna->kgem; 397642542f5fSchristos unsigned src_pitch, br13, cmd; 397703b705cfSriastradh 397842542f5fSchristos#if DEBUG_NO_BLT || NO_BLT_COPY_BOXES 397942542f5fSchristos return false; 398042542f5fSchristos#endif 398103b705cfSriastradh 398242542f5fSchristos DBG(("%s src=(%d, %d) -> (%d, %d) x %d, tiling=(%d, %d), pitch=(%d, %d)\n", 398342542f5fSchristos __FUNCTION__, src_dx, src_dy, dst_dx, dst_dy, nbox, 398442542f5fSchristos src_bo->tiling, dst_bo->tiling, 398542542f5fSchristos src_bo->pitch, dst_bo->pitch)); 398603b705cfSriastradh 398742542f5fSchristos if (wedged(sna) || !kgem_bo_can_blt(kgem, src_bo) || !kgem_bo_can_blt(kgem, dst_bo)) { 398842542f5fSchristos DBG(("%s: cannot blt to src? %d or dst? %d\n", 398942542f5fSchristos __FUNCTION__, 399042542f5fSchristos kgem_bo_can_blt(kgem, src_bo), 399142542f5fSchristos kgem_bo_can_blt(kgem, dst_bo))); 399242542f5fSchristos return false; 399342542f5fSchristos } 399403b705cfSriastradh 399542542f5fSchristos cmd = XY_FULL_MONO_PATTERN_BLT | (kgem->gen >= 0100 ? 12 : 10); 399642542f5fSchristos src_pitch = src_bo->pitch; 399742542f5fSchristos if (kgem->gen >= 040 && src_bo->tiling) { 399842542f5fSchristos cmd |= BLT_SRC_TILED; 399942542f5fSchristos src_pitch >>= 2; 400042542f5fSchristos } 400142542f5fSchristos assert(src_pitch <= MAXSHORT); 400203b705cfSriastradh 400342542f5fSchristos br13 = dst_bo->pitch; 400442542f5fSchristos if (kgem->gen >= 040 && dst_bo->tiling) { 400542542f5fSchristos cmd |= BLT_DST_TILED; 400642542f5fSchristos br13 >>= 2; 400742542f5fSchristos } 400842542f5fSchristos assert(br13 <= MAXSHORT); 400903b705cfSriastradh 401042542f5fSchristos br13 |= copy_ROP[alu] << 16; 401142542f5fSchristos switch (bpp) { 401242542f5fSchristos default: assert(0); 401342542f5fSchristos case 32: br13 |= 1 << 25; /* RGB8888 */ 401442542f5fSchristos case 16: br13 |= 1 << 24; /* RGB565 */ 401542542f5fSchristos case 8: break; 401642542f5fSchristos } 401703b705cfSriastradh 401842542f5fSchristos kgem_set_mode(kgem, KGEM_BLT, dst_bo); 401942542f5fSchristos if (!kgem_check_many_bo_fenced(kgem, dst_bo, src_bo, NULL)) { 402042542f5fSchristos DBG(("%s: cannot fit src+dst into aperture\n", __FUNCTION__)); 402142542f5fSchristos return false; 402242542f5fSchristos } 402303b705cfSriastradh 402442542f5fSchristos /* Compare first box against a previous fill */ 402542542f5fSchristos if ((alu == GXcopy || alu == GXclear || alu == GXset) && 402642542f5fSchristos kgem->reloc[kgem->nreloc-1].target_handle == dst_bo->target_handle) { 402742542f5fSchristos if (kgem->gen >= 0100) { 402842542f5fSchristos if (kgem->nbatch >= 7 && 402942542f5fSchristos kgem->batch[kgem->nbatch-7] == (XY_COLOR_BLT | (cmd & (BLT_WRITE_ALPHA | BLT_WRITE_RGB)) | 5) && 403042542f5fSchristos kgem->batch[kgem->nbatch-5] == ((uint32_t)(box->y1 + dst_dy) << 16 | (uint16_t)(box->x1 + dst_dx)) && 403142542f5fSchristos kgem->batch[kgem->nbatch-4] == ((uint32_t)(box->y2 + dst_dy) << 16 | (uint16_t)(box->x2 + dst_dx))) { 403242542f5fSchristos DBG(("%s: deleting last fill\n", __FUNCTION__)); 403342542f5fSchristos kgem->nbatch -= 7; 403442542f5fSchristos kgem->nreloc--; 403542542f5fSchristos } 403642542f5fSchristos } else { 403742542f5fSchristos if (kgem->nbatch >= 6 && 403842542f5fSchristos kgem->batch[kgem->nbatch-6] == (XY_COLOR_BLT | (cmd & (BLT_WRITE_ALPHA | BLT_WRITE_RGB)) | 4) && 403942542f5fSchristos kgem->batch[kgem->nbatch-4] == ((uint32_t)(box->y1 + dst_dy) << 16 | (uint16_t)(box->x1 + dst_dx)) && 404042542f5fSchristos kgem->batch[kgem->nbatch-3] == ((uint32_t)(box->y2 + dst_dy) << 16 | (uint16_t)(box->x2 + dst_dx))) { 404142542f5fSchristos DBG(("%s: deleting last fill\n", __FUNCTION__)); 404242542f5fSchristos kgem->nbatch -= 6; 404342542f5fSchristos kgem->nreloc--; 404442542f5fSchristos } 404542542f5fSchristos } 404642542f5fSchristos } 404703b705cfSriastradh 404842542f5fSchristos while (nbox--) { 404942542f5fSchristos uint32_t *b; 405003b705cfSriastradh 405142542f5fSchristos if (!kgem_check_batch(kgem, 14) || 405242542f5fSchristos !kgem_check_reloc(kgem, 2)) { 405303b705cfSriastradh _kgem_submit(kgem); 405403b705cfSriastradh _kgem_set_mode(kgem, KGEM_BLT); 405542542f5fSchristos } 405642542f5fSchristos 405742542f5fSchristos assert(sna->kgem.mode == KGEM_BLT); 405842542f5fSchristos b = kgem->batch + kgem->nbatch; 405942542f5fSchristos b[0] = cmd; 406042542f5fSchristos b[1] = br13; 406142542f5fSchristos b[2] = (box->y1 + dst_dy) << 16 | (box->x1 + dst_dx); 406242542f5fSchristos b[3] = (box->y2 + dst_dy) << 16 | (box->x2 + dst_dx); 406342542f5fSchristos if (sna->kgem.gen >= 0100) { 406442542f5fSchristos *(uint64_t *)(b+4) = 406542542f5fSchristos kgem_add_reloc64(kgem, kgem->nbatch + 4, dst_bo, 406642542f5fSchristos I915_GEM_DOMAIN_RENDER << 16 | 406742542f5fSchristos I915_GEM_DOMAIN_RENDER | 406842542f5fSchristos KGEM_RELOC_FENCED, 406942542f5fSchristos 0); 407042542f5fSchristos b[6] = src_pitch; 407142542f5fSchristos b[7] = (box->y1 + src_dy) << 16 | (box->x1 + src_dx); 407242542f5fSchristos *(uint64_t *)(b+8) = 407342542f5fSchristos kgem_add_reloc64(kgem, kgem->nbatch + 8, src_bo, 407442542f5fSchristos I915_GEM_DOMAIN_RENDER << 16 | 407542542f5fSchristos KGEM_RELOC_FENCED, 407642542f5fSchristos 0); 407742542f5fSchristos b[10] = alpha_fixup; 407842542f5fSchristos b[11] = alpha_fixup; 407942542f5fSchristos b[12] = 0; 408042542f5fSchristos b[13] = 0; 408142542f5fSchristos kgem->nbatch += 14; 408242542f5fSchristos } else { 408342542f5fSchristos b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4, dst_bo, 408442542f5fSchristos I915_GEM_DOMAIN_RENDER << 16 | 408542542f5fSchristos I915_GEM_DOMAIN_RENDER | 408642542f5fSchristos KGEM_RELOC_FENCED, 408742542f5fSchristos 0); 408842542f5fSchristos b[5] = src_pitch; 408942542f5fSchristos b[6] = (box->y1 + src_dy) << 16 | (box->x1 + src_dx); 409042542f5fSchristos b[7] = kgem_add_reloc(kgem, kgem->nbatch + 7, src_bo, 409142542f5fSchristos I915_GEM_DOMAIN_RENDER << 16 | 409242542f5fSchristos KGEM_RELOC_FENCED, 409342542f5fSchristos 0); 409442542f5fSchristos b[8] = alpha_fixup; 409542542f5fSchristos b[9] = alpha_fixup; 409642542f5fSchristos b[10] = 0; 409742542f5fSchristos b[11] = 0; 409842542f5fSchristos kgem->nbatch += 12; 409942542f5fSchristos } 410042542f5fSchristos assert(kgem->nbatch < kgem->surface); 410142542f5fSchristos box++; 410203b705cfSriastradh } 410303b705cfSriastradh 410403b705cfSriastradh if (kgem->nexec > 1 && __kgem_ring_empty(kgem)) { 410542542f5fSchristos DBG(("%s: flushing BLT operation on empty ring\n", __FUNCTION__)); 410603b705cfSriastradh _kgem_submit(kgem); 410703b705cfSriastradh } 410803b705cfSriastradh 410903b705cfSriastradh sna->blt_state.fill_bo = 0; 411003b705cfSriastradh return true; 411103b705cfSriastradh} 411203b705cfSriastradh 411303b705cfSriastradhstatic void box_extents(const BoxRec *box, int n, BoxRec *extents) 411403b705cfSriastradh{ 411503b705cfSriastradh *extents = *box; 411603b705cfSriastradh while (--n) { 411703b705cfSriastradh box++; 411803b705cfSriastradh if (box->x1 < extents->x1) 411903b705cfSriastradh extents->x1 = box->x1; 412003b705cfSriastradh if (box->y1 < extents->y1) 412103b705cfSriastradh extents->y1 = box->y1; 412203b705cfSriastradh 412303b705cfSriastradh if (box->x2 > extents->x2) 412403b705cfSriastradh extents->x2 = box->x2; 412503b705cfSriastradh if (box->y2 > extents->y2) 412603b705cfSriastradh extents->y2 = box->y2; 412703b705cfSriastradh } 412803b705cfSriastradh} 412903b705cfSriastradh 413003b705cfSriastradhbool sna_blt_copy_boxes_fallback(struct sna *sna, uint8_t alu, 413142542f5fSchristos const DrawableRec *src, struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy, 413242542f5fSchristos const DrawableRec *dst, struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy, 413303b705cfSriastradh const BoxRec *box, int nbox) 413403b705cfSriastradh{ 413503b705cfSriastradh struct kgem_bo *free_bo = NULL; 413603b705cfSriastradh bool ret; 413703b705cfSriastradh 413803b705cfSriastradh DBG(("%s: alu=%d, n=%d\n", __FUNCTION__, alu, nbox)); 413903b705cfSriastradh 414042542f5fSchristos if (!sna_blt_compare_depth(src, dst)) { 414103b705cfSriastradh DBG(("%s: mismatching depths %d -> %d\n", 414242542f5fSchristos __FUNCTION__, src->depth, dst->depth)); 414303b705cfSriastradh return false; 414403b705cfSriastradh } 414503b705cfSriastradh 414603b705cfSriastradh if (src_bo == dst_bo) { 414703b705cfSriastradh DBG(("%s: dst == src\n", __FUNCTION__)); 414803b705cfSriastradh 414903b705cfSriastradh if (src_bo->tiling == I915_TILING_Y && 415003b705cfSriastradh kgem_bo_blt_pitch_is_ok(&sna->kgem, src_bo)) { 415103b705cfSriastradh struct kgem_bo *bo; 415203b705cfSriastradh 415303b705cfSriastradh DBG(("%s: src is Y-tiled\n", __FUNCTION__)); 415403b705cfSriastradh 415542542f5fSchristos if (src->type != DRAWABLE_PIXMAP) 415642542f5fSchristos return false; 415742542f5fSchristos 415842542f5fSchristos assert(sna_pixmap((PixmapPtr)src)->gpu_bo == src_bo); 415942542f5fSchristos bo = sna_pixmap_change_tiling((PixmapPtr)src, I915_TILING_X); 416003b705cfSriastradh if (bo == NULL) { 416103b705cfSriastradh BoxRec extents; 416203b705cfSriastradh 416303b705cfSriastradh DBG(("%s: y-tiling conversion failed\n", 416403b705cfSriastradh __FUNCTION__)); 416503b705cfSriastradh 416603b705cfSriastradh box_extents(box, nbox, &extents); 416703b705cfSriastradh free_bo = kgem_create_2d(&sna->kgem, 416803b705cfSriastradh extents.x2 - extents.x1, 416903b705cfSriastradh extents.y2 - extents.y1, 417042542f5fSchristos src->bitsPerPixel, 417103b705cfSriastradh I915_TILING_X, 0); 417203b705cfSriastradh if (free_bo == NULL) { 417303b705cfSriastradh DBG(("%s: fallback -- temp allocation failed\n", 417403b705cfSriastradh __FUNCTION__)); 417503b705cfSriastradh return false; 417603b705cfSriastradh } 417703b705cfSriastradh 417803b705cfSriastradh if (!sna_blt_copy_boxes(sna, GXcopy, 417903b705cfSriastradh src_bo, src_dx, src_dy, 418003b705cfSriastradh free_bo, -extents.x1, -extents.y1, 418142542f5fSchristos src->bitsPerPixel, 418203b705cfSriastradh box, nbox)) { 418303b705cfSriastradh DBG(("%s: fallback -- temp copy failed\n", 418403b705cfSriastradh __FUNCTION__)); 418503b705cfSriastradh kgem_bo_destroy(&sna->kgem, free_bo); 418603b705cfSriastradh return false; 418703b705cfSriastradh } 418803b705cfSriastradh 418903b705cfSriastradh src_dx = -extents.x1; 419003b705cfSriastradh src_dy = -extents.y1; 419103b705cfSriastradh src_bo = free_bo; 419203b705cfSriastradh } else 419303b705cfSriastradh dst_bo = src_bo = bo; 419403b705cfSriastradh } 419503b705cfSriastradh } else { 419603b705cfSriastradh if (src_bo->tiling == I915_TILING_Y && 419703b705cfSriastradh kgem_bo_blt_pitch_is_ok(&sna->kgem, src_bo)) { 419803b705cfSriastradh DBG(("%s: src is y-tiled\n", __FUNCTION__)); 419942542f5fSchristos if (src->type != DRAWABLE_PIXMAP) 420042542f5fSchristos return false; 420142542f5fSchristos assert(sna_pixmap((PixmapPtr)src)->gpu_bo == src_bo); 420242542f5fSchristos src_bo = sna_pixmap_change_tiling((PixmapPtr)src, I915_TILING_X); 420303b705cfSriastradh if (src_bo == NULL) { 420403b705cfSriastradh DBG(("%s: fallback -- src y-tiling conversion failed\n", 420503b705cfSriastradh __FUNCTION__)); 420603b705cfSriastradh return false; 420703b705cfSriastradh } 420803b705cfSriastradh } 420903b705cfSriastradh 421003b705cfSriastradh if (dst_bo->tiling == I915_TILING_Y && 421103b705cfSriastradh kgem_bo_blt_pitch_is_ok(&sna->kgem, dst_bo)) { 421203b705cfSriastradh DBG(("%s: dst is y-tiled\n", __FUNCTION__)); 421342542f5fSchristos if (dst->type != DRAWABLE_PIXMAP) 421442542f5fSchristos return false; 421542542f5fSchristos assert(sna_pixmap((PixmapPtr)dst)->gpu_bo == dst_bo); 421642542f5fSchristos dst_bo = sna_pixmap_change_tiling((PixmapPtr)dst, I915_TILING_X); 421703b705cfSriastradh if (dst_bo == NULL) { 421803b705cfSriastradh DBG(("%s: fallback -- dst y-tiling conversion failed\n", 421903b705cfSriastradh __FUNCTION__)); 422003b705cfSriastradh return false; 422103b705cfSriastradh } 422203b705cfSriastradh } 422303b705cfSriastradh } 422403b705cfSriastradh 422503b705cfSriastradh ret = sna_blt_copy_boxes(sna, alu, 422603b705cfSriastradh src_bo, src_dx, src_dy, 422703b705cfSriastradh dst_bo, dst_dx, dst_dy, 422842542f5fSchristos dst->bitsPerPixel, 422903b705cfSriastradh box, nbox); 423003b705cfSriastradh 423103b705cfSriastradh if (free_bo) 423203b705cfSriastradh kgem_bo_destroy(&sna->kgem, free_bo); 423303b705cfSriastradh 423403b705cfSriastradh return ret; 423503b705cfSriastradh} 4236