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, &region, 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, &region, 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							     &region, 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						     &region, 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