sna_blt.c revision 03b705cf
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
4703b705cfSriastradhstatic const uint8_t copy_ROP[] = {
4803b705cfSriastradh	ROP_0,                  /* GXclear */
4903b705cfSriastradh	ROP_DSa,                /* GXand */
5003b705cfSriastradh	ROP_SDna,               /* GXandReverse */
5103b705cfSriastradh	ROP_S,                  /* GXcopy */
5203b705cfSriastradh	ROP_DSna,               /* GXandInverted */
5303b705cfSriastradh	ROP_D,                  /* GXnoop */
5403b705cfSriastradh	ROP_DSx,                /* GXxor */
5503b705cfSriastradh	ROP_DSo,                /* GXor */
5603b705cfSriastradh	ROP_DSon,               /* GXnor */
5703b705cfSriastradh	ROP_DSxn,               /* GXequiv */
5803b705cfSriastradh	ROP_Dn,                 /* GXinvert */
5903b705cfSriastradh	ROP_SDno,               /* GXorReverse */
6003b705cfSriastradh	ROP_Sn,                 /* GXcopyInverted */
6103b705cfSriastradh	ROP_DSno,               /* GXorInverted */
6203b705cfSriastradh	ROP_DSan,               /* GXnand */
6303b705cfSriastradh	ROP_1                   /* GXset */
6403b705cfSriastradh};
6503b705cfSriastradh
6603b705cfSriastradhstatic const uint8_t fill_ROP[] = {
6703b705cfSriastradh	ROP_0,
6803b705cfSriastradh	ROP_DPa,
6903b705cfSriastradh	ROP_PDna,
7003b705cfSriastradh	ROP_P,
7103b705cfSriastradh	ROP_DPna,
7203b705cfSriastradh	ROP_D,
7303b705cfSriastradh	ROP_DPx,
7403b705cfSriastradh	ROP_DPo,
7503b705cfSriastradh	ROP_DPon,
7603b705cfSriastradh	ROP_PDxn,
7703b705cfSriastradh	ROP_Dn,
7803b705cfSriastradh	ROP_PDno,
7903b705cfSriastradh	ROP_Pn,
8003b705cfSriastradh	ROP_DPno,
8103b705cfSriastradh	ROP_DPan,
8203b705cfSriastradh	ROP_1
8303b705cfSriastradh};
8403b705cfSriastradh
8503b705cfSriastradhstatic void nop_done(struct sna *sna, const struct sna_composite_op *op)
8603b705cfSriastradh{
8703b705cfSriastradh	assert(sna->kgem.nbatch <= KGEM_BATCH_SIZE(&sna->kgem));
8803b705cfSriastradh	if (sna->kgem.nexec > 1 && __kgem_ring_empty(&sna->kgem))
8903b705cfSriastradh		_kgem_submit(&sna->kgem);
9003b705cfSriastradh	(void)op;
9103b705cfSriastradh}
9203b705cfSriastradh
9303b705cfSriastradhstatic void gen6_blt_copy_done(struct sna *sna, const struct sna_composite_op *op)
9403b705cfSriastradh{
9503b705cfSriastradh	struct kgem *kgem = &sna->kgem;
9603b705cfSriastradh
9703b705cfSriastradh	assert(kgem->nbatch <= KGEM_BATCH_SIZE(kgem));
9803b705cfSriastradh	if (kgem->nexec > 1 && __kgem_ring_empty(kgem)) {
9903b705cfSriastradh		_kgem_submit(kgem);
10003b705cfSriastradh		return;
10103b705cfSriastradh	}
10203b705cfSriastradh
10303b705cfSriastradh	if (kgem_check_batch(kgem, 3)) {
10403b705cfSriastradh		uint32_t *b = kgem->batch + kgem->nbatch;
10503b705cfSriastradh		b[0] = XY_SETUP_CLIP;
10603b705cfSriastradh		b[1] = b[2] = 0;
10703b705cfSriastradh		kgem->nbatch += 3;
10803b705cfSriastradh		assert(kgem->nbatch < kgem->surface);
10903b705cfSriastradh	}
11003b705cfSriastradh	assert(sna->kgem.nbatch <= KGEM_BATCH_SIZE(&sna->kgem));
11103b705cfSriastradh	(void)op;
11203b705cfSriastradh}
11303b705cfSriastradh
11403b705cfSriastradhstatic bool sna_blt_fill_init(struct sna *sna,
11503b705cfSriastradh			      struct sna_blt_state *blt,
11603b705cfSriastradh			      struct kgem_bo *bo,
11703b705cfSriastradh			      int bpp,
11803b705cfSriastradh			      uint8_t alu,
11903b705cfSriastradh			      uint32_t pixel)
12003b705cfSriastradh{
12103b705cfSriastradh	struct kgem *kgem = &sna->kgem;
12203b705cfSriastradh
12303b705cfSriastradh	assert(kgem_bo_can_blt (kgem, bo));
12403b705cfSriastradh	assert(bo->tiling != I915_TILING_Y);
12503b705cfSriastradh	blt->bo[0] = bo;
12603b705cfSriastradh
12703b705cfSriastradh	blt->br13 = bo->pitch;
12803b705cfSriastradh	blt->cmd = XY_SCANLINE_BLT;
12903b705cfSriastradh	if (kgem->gen >= 040 && bo->tiling) {
13003b705cfSriastradh		blt->cmd |= BLT_DST_TILED;
13103b705cfSriastradh		blt->br13 >>= 2;
13203b705cfSriastradh	}
13303b705cfSriastradh	assert(blt->br13 <= MAXSHORT);
13403b705cfSriastradh
13503b705cfSriastradh	if (alu == GXclear)
13603b705cfSriastradh		pixel = 0;
13703b705cfSriastradh	else if (alu == GXcopy) {
13803b705cfSriastradh		if (pixel == 0)
13903b705cfSriastradh			alu = GXclear;
14003b705cfSriastradh		else if (pixel == -1)
14103b705cfSriastradh			alu = GXset;
14203b705cfSriastradh	}
14303b705cfSriastradh
14403b705cfSriastradh	blt->br13 |= 1<<31 | (fill_ROP[alu] << 16);
14503b705cfSriastradh	switch (bpp) {
14603b705cfSriastradh	default: assert(0);
14703b705cfSriastradh	case 32: blt->br13 |= 1 << 25; /* RGB8888 */
14803b705cfSriastradh	case 16: blt->br13 |= 1 << 24; /* RGB565 */
14903b705cfSriastradh	case 8: break;
15003b705cfSriastradh	}
15103b705cfSriastradh
15203b705cfSriastradh	blt->pixel = pixel;
15303b705cfSriastradh	blt->bpp = bpp;
15403b705cfSriastradh
15503b705cfSriastradh	kgem_set_mode(kgem, KGEM_BLT, bo);
15603b705cfSriastradh	if (!kgem_check_batch(kgem, 12) ||
15703b705cfSriastradh	    !kgem_check_bo_fenced(kgem, bo)) {
15803b705cfSriastradh		kgem_submit(kgem);
15903b705cfSriastradh		if (!kgem_check_bo_fenced(kgem, bo))
16003b705cfSriastradh			return false;
16103b705cfSriastradh		_kgem_set_mode(kgem, KGEM_BLT);
16203b705cfSriastradh	}
16303b705cfSriastradh
16403b705cfSriastradh	if (sna->blt_state.fill_bo != bo->unique_id ||
16503b705cfSriastradh	    sna->blt_state.fill_pixel != pixel ||
16603b705cfSriastradh	    sna->blt_state.fill_alu != alu)
16703b705cfSriastradh	{
16803b705cfSriastradh		uint32_t *b;
16903b705cfSriastradh
17003b705cfSriastradh		if (!kgem_check_reloc(kgem, 1)) {
17103b705cfSriastradh			_kgem_submit(kgem);
17203b705cfSriastradh			_kgem_set_mode(kgem, KGEM_BLT);
17303b705cfSriastradh		}
17403b705cfSriastradh
17503b705cfSriastradh		b = kgem->batch + kgem->nbatch;
17603b705cfSriastradh		b[0] = XY_SETUP_MONO_PATTERN_SL_BLT;
17703b705cfSriastradh		if (bpp == 32)
17803b705cfSriastradh			b[0] |= BLT_WRITE_ALPHA | BLT_WRITE_RGB;
17903b705cfSriastradh		b[1] = blt->br13;
18003b705cfSriastradh		b[2] = 0;
18103b705cfSriastradh		b[3] = 0;
18203b705cfSriastradh		b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4, bo,
18303b705cfSriastradh				      I915_GEM_DOMAIN_RENDER << 16 |
18403b705cfSriastradh				      I915_GEM_DOMAIN_RENDER |
18503b705cfSriastradh				      KGEM_RELOC_FENCED,
18603b705cfSriastradh				      0);
18703b705cfSriastradh		b[5] = pixel;
18803b705cfSriastradh		b[6] = pixel;
18903b705cfSriastradh		b[7] = 0;
19003b705cfSriastradh		b[8] = 0;
19103b705cfSriastradh		kgem->nbatch += 9;
19203b705cfSriastradh		assert(kgem->nbatch < kgem->surface);
19303b705cfSriastradh
19403b705cfSriastradh		sna->blt_state.fill_bo = bo->unique_id;
19503b705cfSriastradh		sna->blt_state.fill_pixel = pixel;
19603b705cfSriastradh		sna->blt_state.fill_alu = alu;
19703b705cfSriastradh	}
19803b705cfSriastradh
19903b705cfSriastradh	return true;
20003b705cfSriastradh}
20103b705cfSriastradh
20203b705cfSriastradhnoinline static void sna_blt_fill_begin(struct sna *sna,
20303b705cfSriastradh					const struct sna_blt_state *blt)
20403b705cfSriastradh{
20503b705cfSriastradh	struct kgem *kgem = &sna->kgem;
20603b705cfSriastradh	uint32_t *b;
20703b705cfSriastradh
20803b705cfSriastradh	_kgem_submit(kgem);
20903b705cfSriastradh	_kgem_set_mode(kgem, KGEM_BLT);
21003b705cfSriastradh
21103b705cfSriastradh	assert(kgem->nbatch == 0);
21203b705cfSriastradh	b = kgem->batch;
21303b705cfSriastradh	b[0] = XY_SETUP_MONO_PATTERN_SL_BLT;
21403b705cfSriastradh	if (blt->bpp == 32)
21503b705cfSriastradh		b[0] |= BLT_WRITE_ALPHA | BLT_WRITE_RGB;
21603b705cfSriastradh	b[1] = blt->br13;
21703b705cfSriastradh	b[2] = 0;
21803b705cfSriastradh	b[3] = 0;
21903b705cfSriastradh	b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4, blt->bo[0],
22003b705cfSriastradh			      I915_GEM_DOMAIN_RENDER << 16 |
22103b705cfSriastradh			      I915_GEM_DOMAIN_RENDER |
22203b705cfSriastradh			      KGEM_RELOC_FENCED,
22303b705cfSriastradh			      0);
22403b705cfSriastradh	b[5] = blt->pixel;
22503b705cfSriastradh	b[6] = blt->pixel;
22603b705cfSriastradh	b[7] = 0;
22703b705cfSriastradh	b[8] = 0;
22803b705cfSriastradh	kgem->nbatch = 9;
22903b705cfSriastradh}
23003b705cfSriastradh
23103b705cfSriastradhinline static void sna_blt_fill_one(struct sna *sna,
23203b705cfSriastradh				    const struct sna_blt_state *blt,
23303b705cfSriastradh				    int16_t x, int16_t y,
23403b705cfSriastradh				    int16_t width, int16_t height)
23503b705cfSriastradh{
23603b705cfSriastradh	struct kgem *kgem = &sna->kgem;
23703b705cfSriastradh	uint32_t *b;
23803b705cfSriastradh
23903b705cfSriastradh	DBG(("%s: (%d, %d) x (%d, %d): %08x\n",
24003b705cfSriastradh	     __FUNCTION__, x, y, width, height, blt->pixel));
24103b705cfSriastradh
24203b705cfSriastradh	assert(x >= 0);
24303b705cfSriastradh	assert(y >= 0);
24403b705cfSriastradh	assert((y+height) * blt->bo[0]->pitch <= kgem_bo_size(blt->bo[0]));
24503b705cfSriastradh
24603b705cfSriastradh	if (!kgem_check_batch(kgem, 3))
24703b705cfSriastradh		sna_blt_fill_begin(sna, blt);
24803b705cfSriastradh
24903b705cfSriastradh	b = kgem->batch + kgem->nbatch;
25003b705cfSriastradh	kgem->nbatch += 3;
25103b705cfSriastradh	assert(kgem->nbatch < kgem->surface);
25203b705cfSriastradh
25303b705cfSriastradh	b[0] = blt->cmd;
25403b705cfSriastradh	b[1] = y << 16 | x;
25503b705cfSriastradh	b[2] = b[1] + (height << 16 | width);
25603b705cfSriastradh}
25703b705cfSriastradh
25803b705cfSriastradhstatic bool sna_blt_copy_init(struct sna *sna,
25903b705cfSriastradh			      struct sna_blt_state *blt,
26003b705cfSriastradh			      struct kgem_bo *src,
26103b705cfSriastradh			      struct kgem_bo *dst,
26203b705cfSriastradh			      int bpp,
26303b705cfSriastradh			      uint8_t alu)
26403b705cfSriastradh{
26503b705cfSriastradh	struct kgem *kgem = &sna->kgem;
26603b705cfSriastradh
26703b705cfSriastradh	assert(kgem_bo_can_blt (kgem, src));
26803b705cfSriastradh	assert(kgem_bo_can_blt (kgem, dst));
26903b705cfSriastradh
27003b705cfSriastradh	blt->bo[0] = src;
27103b705cfSriastradh	blt->bo[1] = dst;
27203b705cfSriastradh
27303b705cfSriastradh	blt->cmd = XY_SRC_COPY_BLT_CMD;
27403b705cfSriastradh	if (bpp == 32)
27503b705cfSriastradh		blt->cmd |= BLT_WRITE_ALPHA | BLT_WRITE_RGB;
27603b705cfSriastradh
27703b705cfSriastradh	blt->pitch[0] = src->pitch;
27803b705cfSriastradh	if (kgem->gen >= 040 && src->tiling) {
27903b705cfSriastradh		blt->cmd |= BLT_SRC_TILED;
28003b705cfSriastradh		blt->pitch[0] >>= 2;
28103b705cfSriastradh	}
28203b705cfSriastradh	assert(blt->pitch[0] <= MAXSHORT);
28303b705cfSriastradh
28403b705cfSriastradh	blt->pitch[1] = dst->pitch;
28503b705cfSriastradh	if (kgem->gen >= 040 && dst->tiling) {
28603b705cfSriastradh		blt->cmd |= BLT_DST_TILED;
28703b705cfSriastradh		blt->pitch[1] >>= 2;
28803b705cfSriastradh	}
28903b705cfSriastradh	assert(blt->pitch[1] <= MAXSHORT);
29003b705cfSriastradh
29103b705cfSriastradh	blt->overwrites = alu == GXcopy || alu == GXclear || alu == GXset;
29203b705cfSriastradh	blt->br13 = (copy_ROP[alu] << 16) | blt->pitch[1];
29303b705cfSriastradh	switch (bpp) {
29403b705cfSriastradh	default: assert(0);
29503b705cfSriastradh	case 32: blt->br13 |= 1 << 25; /* RGB8888 */
29603b705cfSriastradh	case 16: blt->br13 |= 1 << 24; /* RGB565 */
29703b705cfSriastradh	case 8: break;
29803b705cfSriastradh	}
29903b705cfSriastradh
30003b705cfSriastradh	kgem_set_mode(kgem, KGEM_BLT, dst);
30103b705cfSriastradh	if (!kgem_check_many_bo_fenced(kgem, src, dst, NULL)) {
30203b705cfSriastradh		kgem_submit(kgem);
30303b705cfSriastradh		if (!kgem_check_many_bo_fenced(kgem, src, dst, NULL))
30403b705cfSriastradh			return false;
30503b705cfSriastradh		_kgem_set_mode(kgem, KGEM_BLT);
30603b705cfSriastradh	}
30703b705cfSriastradh
30803b705cfSriastradh	sna->blt_state.fill_bo = 0;
30903b705cfSriastradh	return true;
31003b705cfSriastradh}
31103b705cfSriastradh
31203b705cfSriastradhstatic bool sna_blt_alpha_fixup_init(struct sna *sna,
31303b705cfSriastradh				     struct sna_blt_state *blt,
31403b705cfSriastradh				     struct kgem_bo *src,
31503b705cfSriastradh				     struct kgem_bo *dst,
31603b705cfSriastradh				     int bpp, uint32_t alpha)
31703b705cfSriastradh{
31803b705cfSriastradh	struct kgem *kgem = &sna->kgem;
31903b705cfSriastradh
32003b705cfSriastradh	assert(kgem_bo_can_blt (kgem, src));
32103b705cfSriastradh	assert(kgem_bo_can_blt (kgem, dst));
32203b705cfSriastradh
32303b705cfSriastradh	blt->bo[0] = src;
32403b705cfSriastradh	blt->bo[1] = dst;
32503b705cfSriastradh
32603b705cfSriastradh	blt->cmd = XY_FULL_MONO_PATTERN_BLT;
32703b705cfSriastradh	blt->pitch[0] = src->pitch;
32803b705cfSriastradh	if (kgem->gen >= 040 && src->tiling) {
32903b705cfSriastradh		blt->cmd |= BLT_SRC_TILED;
33003b705cfSriastradh		blt->pitch[0] >>= 2;
33103b705cfSriastradh	}
33203b705cfSriastradh	assert(blt->pitch[0] <= MAXSHORT);
33303b705cfSriastradh
33403b705cfSriastradh	blt->pitch[1] = dst->pitch;
33503b705cfSriastradh	if (kgem->gen >= 040 && dst->tiling) {
33603b705cfSriastradh		blt->cmd |= BLT_DST_TILED;
33703b705cfSriastradh		blt->pitch[1] >>= 2;
33803b705cfSriastradh	}
33903b705cfSriastradh	assert(blt->pitch[1] <= MAXSHORT);
34003b705cfSriastradh
34103b705cfSriastradh	blt->overwrites = 1;
34203b705cfSriastradh	blt->br13 = (0xfc << 16) | blt->pitch[1];
34303b705cfSriastradh	switch (bpp) {
34403b705cfSriastradh	default: assert(0);
34503b705cfSriastradh	case 32: blt->cmd |= BLT_WRITE_ALPHA | BLT_WRITE_RGB;
34603b705cfSriastradh		 blt->br13 |= 1 << 25; /* RGB8888 */
34703b705cfSriastradh	case 16: blt->br13 |= 1 << 24; /* RGB565 */
34803b705cfSriastradh	case 8: break;
34903b705cfSriastradh	}
35003b705cfSriastradh	blt->pixel = alpha;
35103b705cfSriastradh
35203b705cfSriastradh	kgem_set_mode(kgem, KGEM_BLT, dst);
35303b705cfSriastradh	if (!kgem_check_many_bo_fenced(kgem, src, dst, NULL)) {
35403b705cfSriastradh		kgem_submit(kgem);
35503b705cfSriastradh		if (!kgem_check_many_bo_fenced(kgem, src, dst, NULL))
35603b705cfSriastradh			return false;
35703b705cfSriastradh		_kgem_set_mode(kgem, KGEM_BLT);
35803b705cfSriastradh	}
35903b705cfSriastradh
36003b705cfSriastradh	sna->blt_state.fill_bo = 0;
36103b705cfSriastradh	return true;
36203b705cfSriastradh}
36303b705cfSriastradh
36403b705cfSriastradhstatic void sna_blt_alpha_fixup_one(struct sna *sna,
36503b705cfSriastradh				    const struct sna_blt_state *blt,
36603b705cfSriastradh				    int src_x, int src_y,
36703b705cfSriastradh				    int width, int height,
36803b705cfSriastradh				    int dst_x, int dst_y)
36903b705cfSriastradh{
37003b705cfSriastradh	struct kgem *kgem = &sna->kgem;
37103b705cfSriastradh	uint32_t *b;
37203b705cfSriastradh
37303b705cfSriastradh	DBG(("%s: (%d, %d) -> (%d, %d) x (%d, %d)\n",
37403b705cfSriastradh	     __FUNCTION__, src_x, src_y, dst_x, dst_y, width, height));
37503b705cfSriastradh
37603b705cfSriastradh	assert(src_x >= 0);
37703b705cfSriastradh	assert(src_y >= 0);
37803b705cfSriastradh	assert((src_y + height) * blt->bo[0]->pitch <= kgem_bo_size(blt->bo[0]));
37903b705cfSriastradh	assert(dst_x >= 0);
38003b705cfSriastradh	assert(dst_y >= 0);
38103b705cfSriastradh	assert((dst_y + height) * blt->bo[1]->pitch <= kgem_bo_size(blt->bo[1]));
38203b705cfSriastradh	assert(width > 0);
38303b705cfSriastradh	assert(height > 0);
38403b705cfSriastradh
38503b705cfSriastradh	if (!kgem_check_batch(kgem, 12) ||
38603b705cfSriastradh	    !kgem_check_reloc(kgem, 2)) {
38703b705cfSriastradh		_kgem_submit(kgem);
38803b705cfSriastradh		_kgem_set_mode(kgem, KGEM_BLT);
38903b705cfSriastradh	}
39003b705cfSriastradh
39103b705cfSriastradh	b = kgem->batch + kgem->nbatch;
39203b705cfSriastradh	b[0] = blt->cmd;
39303b705cfSriastradh	b[1] = blt->br13;
39403b705cfSriastradh	b[2] = (dst_y << 16) | dst_x;
39503b705cfSriastradh	b[3] = ((dst_y + height) << 16) | (dst_x + width);
39603b705cfSriastradh	b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4,
39703b705cfSriastradh			      blt->bo[1],
39803b705cfSriastradh			      I915_GEM_DOMAIN_RENDER << 16 |
39903b705cfSriastradh			      I915_GEM_DOMAIN_RENDER |
40003b705cfSriastradh			      KGEM_RELOC_FENCED,
40103b705cfSriastradh			      0);
40203b705cfSriastradh	b[5] = blt->pitch[0];
40303b705cfSriastradh	b[6] = (src_y << 16) | src_x;
40403b705cfSriastradh	b[7] = kgem_add_reloc(kgem, kgem->nbatch + 7,
40503b705cfSriastradh			      blt->bo[0],
40603b705cfSriastradh			      I915_GEM_DOMAIN_RENDER << 16 |
40703b705cfSriastradh			      KGEM_RELOC_FENCED,
40803b705cfSriastradh			      0);
40903b705cfSriastradh	b[8] = blt->pixel;
41003b705cfSriastradh	b[9] = blt->pixel;
41103b705cfSriastradh	b[10] = 0;
41203b705cfSriastradh	b[11] = 0;
41303b705cfSriastradh	kgem->nbatch += 12;
41403b705cfSriastradh	assert(kgem->nbatch < kgem->surface);
41503b705cfSriastradh}
41603b705cfSriastradh
41703b705cfSriastradhstatic void sna_blt_copy_one(struct sna *sna,
41803b705cfSriastradh			     const struct sna_blt_state *blt,
41903b705cfSriastradh			     int src_x, int src_y,
42003b705cfSriastradh			     int width, int height,
42103b705cfSriastradh			     int dst_x, int dst_y)
42203b705cfSriastradh{
42303b705cfSriastradh	struct kgem *kgem = &sna->kgem;
42403b705cfSriastradh	uint32_t *b;
42503b705cfSriastradh
42603b705cfSriastradh	DBG(("%s: (%d, %d) -> (%d, %d) x (%d, %d)\n",
42703b705cfSriastradh	     __FUNCTION__, src_x, src_y, dst_x, dst_y, width, height));
42803b705cfSriastradh
42903b705cfSriastradh	assert(src_x >= 0);
43003b705cfSriastradh	assert(src_y >= 0);
43103b705cfSriastradh	assert((src_y + height) * blt->bo[0]->pitch <= kgem_bo_size(blt->bo[0]));
43203b705cfSriastradh	assert(dst_x >= 0);
43303b705cfSriastradh	assert(dst_y >= 0);
43403b705cfSriastradh	assert((dst_y + height) * blt->bo[1]->pitch <= kgem_bo_size(blt->bo[1]));
43503b705cfSriastradh	assert(width > 0);
43603b705cfSriastradh	assert(height > 0);
43703b705cfSriastradh
43803b705cfSriastradh	/* Compare against a previous fill */
43903b705cfSriastradh	if (kgem->nbatch >= 6 &&
44003b705cfSriastradh	    blt->overwrites &&
44103b705cfSriastradh	    kgem->batch[kgem->nbatch-6] == (XY_COLOR_BLT | (blt->cmd & (BLT_WRITE_ALPHA | BLT_WRITE_RGB))) &&
44203b705cfSriastradh	    kgem->batch[kgem->nbatch-4] == ((uint32_t)dst_y << 16 | (uint16_t)dst_x) &&
44303b705cfSriastradh	    kgem->batch[kgem->nbatch-3] == ((uint32_t)(dst_y+height) << 16 | (uint16_t)(dst_x+width)) &&
44403b705cfSriastradh	    kgem->reloc[kgem->nreloc-1].target_handle == blt->bo[1]->target_handle) {
44503b705cfSriastradh		DBG(("%s: replacing last fill\n", __FUNCTION__));
44603b705cfSriastradh		if (kgem_check_batch(kgem, 8-6)) {
44703b705cfSriastradh			b = kgem->batch + kgem->nbatch - 6;
44803b705cfSriastradh			b[0] = blt->cmd;
44903b705cfSriastradh			b[1] = blt->br13;
45003b705cfSriastradh			b[5] = (src_y << 16) | src_x;
45103b705cfSriastradh			b[6] = blt->pitch[0];
45203b705cfSriastradh			b[7] = kgem_add_reloc(kgem, kgem->nbatch + 7 - 6,
45303b705cfSriastradh					      blt->bo[0],
45403b705cfSriastradh					      I915_GEM_DOMAIN_RENDER << 16 |
45503b705cfSriastradh					      KGEM_RELOC_FENCED,
45603b705cfSriastradh					      0);
45703b705cfSriastradh			kgem->nbatch += 8 - 6;
45803b705cfSriastradh			assert(kgem->nbatch < kgem->surface);
45903b705cfSriastradh			return;
46003b705cfSriastradh		}
46103b705cfSriastradh		kgem->nbatch -= 6;
46203b705cfSriastradh		kgem->nreloc--;
46303b705cfSriastradh	}
46403b705cfSriastradh
46503b705cfSriastradh	if (!kgem_check_batch(kgem, 8) ||
46603b705cfSriastradh	    !kgem_check_reloc(kgem, 2)) {
46703b705cfSriastradh		_kgem_submit(kgem);
46803b705cfSriastradh		_kgem_set_mode(kgem, KGEM_BLT);
46903b705cfSriastradh	}
47003b705cfSriastradh
47103b705cfSriastradh	b = kgem->batch + kgem->nbatch;
47203b705cfSriastradh	b[0] = blt->cmd;
47303b705cfSriastradh	b[1] = blt->br13;
47403b705cfSriastradh	b[2] = (dst_y << 16) | dst_x;
47503b705cfSriastradh	b[3] = ((dst_y + height) << 16) | (dst_x + width);
47603b705cfSriastradh	b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4,
47703b705cfSriastradh			      blt->bo[1],
47803b705cfSriastradh			      I915_GEM_DOMAIN_RENDER << 16 |
47903b705cfSriastradh			      I915_GEM_DOMAIN_RENDER |
48003b705cfSriastradh			      KGEM_RELOC_FENCED,
48103b705cfSriastradh			      0);
48203b705cfSriastradh	b[5] = (src_y << 16) | src_x;
48303b705cfSriastradh	b[6] = blt->pitch[0];
48403b705cfSriastradh	b[7] = kgem_add_reloc(kgem, kgem->nbatch + 7,
48503b705cfSriastradh			      blt->bo[0],
48603b705cfSriastradh			      I915_GEM_DOMAIN_RENDER << 16 |
48703b705cfSriastradh			      KGEM_RELOC_FENCED,
48803b705cfSriastradh			      0);
48903b705cfSriastradh	kgem->nbatch += 8;
49003b705cfSriastradh	assert(kgem->nbatch < kgem->surface);
49103b705cfSriastradh}
49203b705cfSriastradh
49303b705cfSriastradhbool
49403b705cfSriastradhsna_get_rgba_from_pixel(uint32_t pixel,
49503b705cfSriastradh			uint16_t *red,
49603b705cfSriastradh			uint16_t *green,
49703b705cfSriastradh			uint16_t *blue,
49803b705cfSriastradh			uint16_t *alpha,
49903b705cfSriastradh			uint32_t format)
50003b705cfSriastradh{
50103b705cfSriastradh	int rbits, bbits, gbits, abits;
50203b705cfSriastradh	int rshift, bshift, gshift, ashift;
50303b705cfSriastradh
50403b705cfSriastradh	rbits = PICT_FORMAT_R(format);
50503b705cfSriastradh	gbits = PICT_FORMAT_G(format);
50603b705cfSriastradh	bbits = PICT_FORMAT_B(format);
50703b705cfSriastradh	abits = PICT_FORMAT_A(format);
50803b705cfSriastradh
50903b705cfSriastradh	if (PICT_FORMAT_TYPE(format) == PICT_TYPE_A) {
51003b705cfSriastradh		rshift = gshift = bshift = ashift = 0;
51103b705cfSriastradh	} else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
51203b705cfSriastradh		bshift = 0;
51303b705cfSriastradh		gshift = bbits;
51403b705cfSriastradh		rshift = gshift + gbits;
51503b705cfSriastradh		ashift = rshift + rbits;
51603b705cfSriastradh	} else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ABGR) {
51703b705cfSriastradh		rshift = 0;
51803b705cfSriastradh		gshift = rbits;
51903b705cfSriastradh		bshift = gshift + gbits;
52003b705cfSriastradh		ashift = bshift + bbits;
52103b705cfSriastradh	} else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_BGRA) {
52203b705cfSriastradh		ashift = 0;
52303b705cfSriastradh		rshift = abits;
52403b705cfSriastradh		if (abits == 0)
52503b705cfSriastradh			rshift = PICT_FORMAT_BPP(format) - (rbits+gbits+bbits);
52603b705cfSriastradh		gshift = rshift + rbits;
52703b705cfSriastradh		bshift = gshift + gbits;
52803b705cfSriastradh	} else {
52903b705cfSriastradh		return false;
53003b705cfSriastradh	}
53103b705cfSriastradh
53203b705cfSriastradh	if (rbits) {
53303b705cfSriastradh		*red = ((pixel >> rshift) & ((1 << rbits) - 1)) << (16 - rbits);
53403b705cfSriastradh		while (rbits < 16) {
53503b705cfSriastradh			*red |= *red >> rbits;
53603b705cfSriastradh			rbits <<= 1;
53703b705cfSriastradh		}
53803b705cfSriastradh	} else
53903b705cfSriastradh		*red = 0;
54003b705cfSriastradh
54103b705cfSriastradh	if (gbits) {
54203b705cfSriastradh		*green = ((pixel >> gshift) & ((1 << gbits) - 1)) << (16 - gbits);
54303b705cfSriastradh		while (gbits < 16) {
54403b705cfSriastradh			*green |= *green >> gbits;
54503b705cfSriastradh			gbits <<= 1;
54603b705cfSriastradh		}
54703b705cfSriastradh	} else
54803b705cfSriastradh		*green = 0;
54903b705cfSriastradh
55003b705cfSriastradh	if (bbits) {
55103b705cfSriastradh		*blue = ((pixel >> bshift) & ((1 << bbits) - 1)) << (16 - bbits);
55203b705cfSriastradh		while (bbits < 16) {
55303b705cfSriastradh			*blue |= *blue >> bbits;
55403b705cfSriastradh			bbits <<= 1;
55503b705cfSriastradh		}
55603b705cfSriastradh	} else
55703b705cfSriastradh		*blue = 0;
55803b705cfSriastradh
55903b705cfSriastradh	if (abits) {
56003b705cfSriastradh		*alpha = ((pixel >> ashift) & ((1 << abits) - 1)) << (16 - abits);
56103b705cfSriastradh		while (abits < 16) {
56203b705cfSriastradh			*alpha |= *alpha >> abits;
56303b705cfSriastradh			abits <<= 1;
56403b705cfSriastradh		}
56503b705cfSriastradh	} else
56603b705cfSriastradh		*alpha = 0xffff;
56703b705cfSriastradh
56803b705cfSriastradh	return true;
56903b705cfSriastradh}
57003b705cfSriastradh
57103b705cfSriastradhbool
57203b705cfSriastradh_sna_get_pixel_from_rgba(uint32_t * pixel,
57303b705cfSriastradh			uint16_t red,
57403b705cfSriastradh			uint16_t green,
57503b705cfSriastradh			uint16_t blue,
57603b705cfSriastradh			uint16_t alpha,
57703b705cfSriastradh			uint32_t format)
57803b705cfSriastradh{
57903b705cfSriastradh	int rbits, bbits, gbits, abits;
58003b705cfSriastradh	int rshift, bshift, gshift, ashift;
58103b705cfSriastradh
58203b705cfSriastradh	rbits = PICT_FORMAT_R(format);
58303b705cfSriastradh	gbits = PICT_FORMAT_G(format);
58403b705cfSriastradh	bbits = PICT_FORMAT_B(format);
58503b705cfSriastradh	abits = PICT_FORMAT_A(format);
58603b705cfSriastradh	if (abits == 0)
58703b705cfSriastradh	    abits = PICT_FORMAT_BPP(format) - (rbits+gbits+bbits);
58803b705cfSriastradh
58903b705cfSriastradh	if (PICT_FORMAT_TYPE(format) == PICT_TYPE_A) {
59003b705cfSriastradh		*pixel = alpha >> (16 - abits);
59103b705cfSriastradh		return true;
59203b705cfSriastradh	}
59303b705cfSriastradh
59403b705cfSriastradh	if (!PICT_FORMAT_COLOR(format))
59503b705cfSriastradh		return false;
59603b705cfSriastradh
59703b705cfSriastradh	if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
59803b705cfSriastradh		bshift = 0;
59903b705cfSriastradh		gshift = bbits;
60003b705cfSriastradh		rshift = gshift + gbits;
60103b705cfSriastradh		ashift = rshift + rbits;
60203b705cfSriastradh	} else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ABGR) {
60303b705cfSriastradh		rshift = 0;
60403b705cfSriastradh		gshift = rbits;
60503b705cfSriastradh		bshift = gshift + gbits;
60603b705cfSriastradh		ashift = bshift + bbits;
60703b705cfSriastradh	} else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_BGRA) {
60803b705cfSriastradh		ashift = 0;
60903b705cfSriastradh		rshift = abits;
61003b705cfSriastradh		gshift = rshift + rbits;
61103b705cfSriastradh		bshift = gshift + gbits;
61203b705cfSriastradh	} else
61303b705cfSriastradh		return false;
61403b705cfSriastradh
61503b705cfSriastradh	*pixel = 0;
61603b705cfSriastradh	*pixel |= (blue  >> (16 - bbits)) << bshift;
61703b705cfSriastradh	*pixel |= (green >> (16 - gbits)) << gshift;
61803b705cfSriastradh	*pixel |= (red   >> (16 - rbits)) << rshift;
61903b705cfSriastradh	*pixel |= (alpha >> (16 - abits)) << ashift;
62003b705cfSriastradh
62103b705cfSriastradh	return true;
62203b705cfSriastradh}
62303b705cfSriastradh
62403b705cfSriastradhuint32_t
62503b705cfSriastradhsna_rgba_for_color(uint32_t color, int depth)
62603b705cfSriastradh{
62703b705cfSriastradh	return color_convert(color, sna_format_for_depth(depth), PICT_a8r8g8b8);
62803b705cfSriastradh}
62903b705cfSriastradh
63003b705cfSriastradhuint32_t
63103b705cfSriastradhsna_rgba_to_color(uint32_t rgba, uint32_t format)
63203b705cfSriastradh{
63303b705cfSriastradh	return color_convert(rgba, PICT_a8r8g8b8, format);
63403b705cfSriastradh}
63503b705cfSriastradh
63603b705cfSriastradhstatic uint32_t
63703b705cfSriastradhget_pixel(PicturePtr picture)
63803b705cfSriastradh{
63903b705cfSriastradh	PixmapPtr pixmap = get_drawable_pixmap(picture->pDrawable);
64003b705cfSriastradh
64103b705cfSriastradh	DBG(("%s: %p\n", __FUNCTION__, pixmap));
64203b705cfSriastradh
64303b705cfSriastradh	if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ))
64403b705cfSriastradh		return 0;
64503b705cfSriastradh
64603b705cfSriastradh	switch (pixmap->drawable.bitsPerPixel) {
64703b705cfSriastradh	case 32: return *(uint32_t *)pixmap->devPrivate.ptr;
64803b705cfSriastradh	case 16: return *(uint16_t *)pixmap->devPrivate.ptr;
64903b705cfSriastradh	default: return *(uint8_t *)pixmap->devPrivate.ptr;
65003b705cfSriastradh	}
65103b705cfSriastradh}
65203b705cfSriastradh
65303b705cfSriastradhstatic uint32_t
65403b705cfSriastradhget_solid_color(PicturePtr picture, uint32_t format)
65503b705cfSriastradh{
65603b705cfSriastradh	if (picture->pSourcePict) {
65703b705cfSriastradh		PictSolidFill *fill = (PictSolidFill *)picture->pSourcePict;
65803b705cfSriastradh		return color_convert(fill->color, PICT_a8r8g8b8, format);
65903b705cfSriastradh	} else
66003b705cfSriastradh		return color_convert(get_pixel(picture), picture->format, format);
66103b705cfSriastradh}
66203b705cfSriastradh
66303b705cfSriastradhstatic bool
66403b705cfSriastradhis_solid(PicturePtr picture)
66503b705cfSriastradh{
66603b705cfSriastradh	if (picture->pSourcePict) {
66703b705cfSriastradh		if (picture->pSourcePict->type == SourcePictTypeSolidFill)
66803b705cfSriastradh			return true;
66903b705cfSriastradh	}
67003b705cfSriastradh
67103b705cfSriastradh	if (picture->pDrawable) {
67203b705cfSriastradh		if (picture->pDrawable->width  == 1 &&
67303b705cfSriastradh		    picture->pDrawable->height == 1 &&
67403b705cfSriastradh		    picture->repeat)
67503b705cfSriastradh			return true;
67603b705cfSriastradh	}
67703b705cfSriastradh
67803b705cfSriastradh	return false;
67903b705cfSriastradh}
68003b705cfSriastradh
68103b705cfSriastradhbool
68203b705cfSriastradhsna_picture_is_solid(PicturePtr picture, uint32_t *color)
68303b705cfSriastradh{
68403b705cfSriastradh	if (!is_solid(picture))
68503b705cfSriastradh		return false;
68603b705cfSriastradh
68703b705cfSriastradh	if (color)
68803b705cfSriastradh		*color = get_solid_color(picture, PICT_a8r8g8b8);
68903b705cfSriastradh	return true;
69003b705cfSriastradh}
69103b705cfSriastradh
69203b705cfSriastradhstatic bool
69303b705cfSriastradhpixel_is_opaque(uint32_t pixel, uint32_t format)
69403b705cfSriastradh{
69503b705cfSriastradh	unsigned int abits;
69603b705cfSriastradh
69703b705cfSriastradh	abits = PICT_FORMAT_A(format);
69803b705cfSriastradh	if (!abits)
69903b705cfSriastradh		return true;
70003b705cfSriastradh
70103b705cfSriastradh	if (PICT_FORMAT_TYPE(format) == PICT_TYPE_A ||
70203b705cfSriastradh	    PICT_FORMAT_TYPE(format) == PICT_TYPE_BGRA) {
70303b705cfSriastradh		return (pixel & ((1 << abits) - 1)) == (unsigned)((1 << abits) - 1);
70403b705cfSriastradh	} else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB ||
70503b705cfSriastradh		   PICT_FORMAT_TYPE(format) == PICT_TYPE_ABGR) {
70603b705cfSriastradh		unsigned int ashift = PICT_FORMAT_BPP(format) - abits;
70703b705cfSriastradh		return (pixel >> ashift) == (unsigned)((1 << abits) - 1);
70803b705cfSriastradh	} else
70903b705cfSriastradh		return false;
71003b705cfSriastradh}
71103b705cfSriastradh
71203b705cfSriastradhstatic bool
71303b705cfSriastradhpixel_is_white(uint32_t pixel, uint32_t format)
71403b705cfSriastradh{
71503b705cfSriastradh	switch (PICT_FORMAT_TYPE(format)) {
71603b705cfSriastradh	case PICT_TYPE_A:
71703b705cfSriastradh	case PICT_TYPE_ARGB:
71803b705cfSriastradh	case PICT_TYPE_ABGR:
71903b705cfSriastradh	case PICT_TYPE_BGRA:
72003b705cfSriastradh		return pixel == ((1U << PICT_FORMAT_BPP(format)) - 1);
72103b705cfSriastradh	default:
72203b705cfSriastradh		return false;
72303b705cfSriastradh	}
72403b705cfSriastradh}
72503b705cfSriastradh
72603b705cfSriastradhstatic bool
72703b705cfSriastradhis_opaque_solid(PicturePtr picture)
72803b705cfSriastradh{
72903b705cfSriastradh	if (picture->pSourcePict) {
73003b705cfSriastradh		PictSolidFill *fill = (PictSolidFill *) picture->pSourcePict;
73103b705cfSriastradh		return (fill->color >> 24) == 0xff;
73203b705cfSriastradh	} else
73303b705cfSriastradh		return pixel_is_opaque(get_pixel(picture), picture->format);
73403b705cfSriastradh}
73503b705cfSriastradh
73603b705cfSriastradhstatic bool
73703b705cfSriastradhis_white(PicturePtr picture)
73803b705cfSriastradh{
73903b705cfSriastradh	if (picture->pSourcePict) {
74003b705cfSriastradh		PictSolidFill *fill = (PictSolidFill *) picture->pSourcePict;
74103b705cfSriastradh		return fill->color == 0xffffffff;
74203b705cfSriastradh	} else
74303b705cfSriastradh		return pixel_is_white(get_pixel(picture), picture->format);
74403b705cfSriastradh}
74503b705cfSriastradh
74603b705cfSriastradhbool
74703b705cfSriastradhsna_composite_mask_is_opaque(PicturePtr mask)
74803b705cfSriastradh{
74903b705cfSriastradh	if (mask->componentAlpha && PICT_FORMAT_RGB(mask->format))
75003b705cfSriastradh		return is_solid(mask) && is_white(mask);
75103b705cfSriastradh	else if (!PICT_FORMAT_A(mask->format))
75203b705cfSriastradh		return true;
75303b705cfSriastradh	else
75403b705cfSriastradh		return is_solid(mask) && is_opaque_solid(mask);
75503b705cfSriastradh}
75603b705cfSriastradh
75703b705cfSriastradhfastcall
75803b705cfSriastradhstatic void blt_composite_fill(struct sna *sna,
75903b705cfSriastradh			       const struct sna_composite_op *op,
76003b705cfSriastradh			       const struct sna_composite_rectangles *r)
76103b705cfSriastradh{
76203b705cfSriastradh	int x1, x2, y1, y2;
76303b705cfSriastradh
76403b705cfSriastradh	x1 = r->dst.x + op->dst.x;
76503b705cfSriastradh	y1 = r->dst.y + op->dst.y;
76603b705cfSriastradh	x2 = x1 + r->width;
76703b705cfSriastradh	y2 = y1 + r->height;
76803b705cfSriastradh
76903b705cfSriastradh	if (x1 < 0)
77003b705cfSriastradh		x1 = 0;
77103b705cfSriastradh	if (y1 < 0)
77203b705cfSriastradh		y1 = 0;
77303b705cfSriastradh
77403b705cfSriastradh	if (x2 > op->dst.width)
77503b705cfSriastradh		x2 = op->dst.width;
77603b705cfSriastradh	if (y2 > op->dst.height)
77703b705cfSriastradh		y2 = op->dst.height;
77803b705cfSriastradh
77903b705cfSriastradh	if (x2 <= x1 || y2 <= y1)
78003b705cfSriastradh		return;
78103b705cfSriastradh
78203b705cfSriastradh	sna_blt_fill_one(sna, &op->u.blt, x1, y1, x2-x1, y2-y1);
78303b705cfSriastradh}
78403b705cfSriastradh
78503b705cfSriastradhfastcall
78603b705cfSriastradhstatic void blt_composite_fill__cpu(struct sna *sna,
78703b705cfSriastradh				    const struct sna_composite_op *op,
78803b705cfSriastradh				    const struct sna_composite_rectangles *r)
78903b705cfSriastradh{
79003b705cfSriastradh	int x1, x2, y1, y2;
79103b705cfSriastradh
79203b705cfSriastradh	x1 = r->dst.x + op->dst.x;
79303b705cfSriastradh	y1 = r->dst.y + op->dst.y;
79403b705cfSriastradh	x2 = x1 + r->width;
79503b705cfSriastradh	y2 = y1 + r->height;
79603b705cfSriastradh
79703b705cfSriastradh	if (x1 < 0)
79803b705cfSriastradh		x1 = 0;
79903b705cfSriastradh	if (y1 < 0)
80003b705cfSriastradh		y1 = 0;
80103b705cfSriastradh
80203b705cfSriastradh	if (x2 > op->dst.width)
80303b705cfSriastradh		x2 = op->dst.width;
80403b705cfSriastradh	if (y2 > op->dst.height)
80503b705cfSriastradh		y2 = op->dst.height;
80603b705cfSriastradh
80703b705cfSriastradh	if (x2 <= x1 || y2 <= y1)
80803b705cfSriastradh		return;
80903b705cfSriastradh
81003b705cfSriastradh	pixman_fill(op->dst.pixmap->devPrivate.ptr,
81103b705cfSriastradh		    op->dst.pixmap->devKind / sizeof(uint32_t),
81203b705cfSriastradh		    op->dst.pixmap->drawable.bitsPerPixel,
81303b705cfSriastradh		    x1, y1, x2-x1, y2-y1,
81403b705cfSriastradh		    op->u.blt.pixel);
81503b705cfSriastradh}
81603b705cfSriastradh
81703b705cfSriastradhfastcall static void
81803b705cfSriastradhblt_composite_fill_box__cpu(struct sna *sna,
81903b705cfSriastradh			    const struct sna_composite_op *op,
82003b705cfSriastradh			    const BoxRec *box)
82103b705cfSriastradh{
82203b705cfSriastradh	pixman_fill(op->dst.pixmap->devPrivate.ptr,
82303b705cfSriastradh		    op->dst.pixmap->devKind / sizeof(uint32_t),
82403b705cfSriastradh		    op->dst.pixmap->drawable.bitsPerPixel,
82503b705cfSriastradh		    box->x1, box->y1, box->x2-box->x1, box->y2-box->y1,
82603b705cfSriastradh		    op->u.blt.pixel);
82703b705cfSriastradh}
82803b705cfSriastradh
82903b705cfSriastradhstatic void
83003b705cfSriastradhblt_composite_fill_boxes__cpu(struct sna *sna,
83103b705cfSriastradh			      const struct sna_composite_op *op,
83203b705cfSriastradh			      const BoxRec *box, int n)
83303b705cfSriastradh{
83403b705cfSriastradh	do {
83503b705cfSriastradh		pixman_fill(op->dst.pixmap->devPrivate.ptr,
83603b705cfSriastradh			    op->dst.pixmap->devKind / sizeof(uint32_t),
83703b705cfSriastradh			    op->dst.pixmap->drawable.bitsPerPixel,
83803b705cfSriastradh			    box->x1, box->y1, box->x2-box->x1, box->y2-box->y1,
83903b705cfSriastradh			    op->u.blt.pixel);
84003b705cfSriastradh		box++;
84103b705cfSriastradh	} while (--n);
84203b705cfSriastradh}
84303b705cfSriastradh
84403b705cfSriastradhinline static void _sna_blt_fill_box(struct sna *sna,
84503b705cfSriastradh				     const struct sna_blt_state *blt,
84603b705cfSriastradh				     const BoxRec *box)
84703b705cfSriastradh{
84803b705cfSriastradh	struct kgem *kgem = &sna->kgem;
84903b705cfSriastradh	uint32_t *b;
85003b705cfSriastradh
85103b705cfSriastradh	DBG(("%s: (%d, %d), (%d, %d): %08x\n", __FUNCTION__,
85203b705cfSriastradh	     box->x1, box->y1, box->x2, box->y2,
85303b705cfSriastradh	     blt->pixel));
85403b705cfSriastradh
85503b705cfSriastradh	assert(box->x1 >= 0);
85603b705cfSriastradh	assert(box->y1 >= 0);
85703b705cfSriastradh	assert(box->y2 * blt->bo[0]->pitch <= kgem_bo_size(blt->bo[0]));
85803b705cfSriastradh
85903b705cfSriastradh	if (!kgem_check_batch(kgem, 3))
86003b705cfSriastradh		sna_blt_fill_begin(sna, blt);
86103b705cfSriastradh
86203b705cfSriastradh	b = kgem->batch + kgem->nbatch;
86303b705cfSriastradh	kgem->nbatch += 3;
86403b705cfSriastradh	assert(kgem->nbatch < kgem->surface);
86503b705cfSriastradh
86603b705cfSriastradh	b[0] = blt->cmd;
86703b705cfSriastradh	*(uint64_t *)(b+1) = *(const uint64_t *)box;
86803b705cfSriastradh}
86903b705cfSriastradh
87003b705cfSriastradhinline static void _sna_blt_fill_boxes(struct sna *sna,
87103b705cfSriastradh				       const struct sna_blt_state *blt,
87203b705cfSriastradh				       const BoxRec *box,
87303b705cfSriastradh				       int nbox)
87403b705cfSriastradh{
87503b705cfSriastradh	struct kgem *kgem = &sna->kgem;
87603b705cfSriastradh	uint32_t cmd = blt->cmd;
87703b705cfSriastradh
87803b705cfSriastradh	DBG(("%s: %08x x %d\n", __FUNCTION__, blt->pixel, nbox));
87903b705cfSriastradh
88003b705cfSriastradh	if (!kgem_check_batch(kgem, 3))
88103b705cfSriastradh		sna_blt_fill_begin(sna, blt);
88203b705cfSriastradh
88303b705cfSriastradh	do {
88403b705cfSriastradh		uint32_t *b = kgem->batch + kgem->nbatch;
88503b705cfSriastradh		int nbox_this_time;
88603b705cfSriastradh
88703b705cfSriastradh		nbox_this_time = nbox;
88803b705cfSriastradh		if (3*nbox_this_time > kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED)
88903b705cfSriastradh			nbox_this_time = (kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) / 3;
89003b705cfSriastradh		assert(nbox_this_time);
89103b705cfSriastradh		nbox -= nbox_this_time;
89203b705cfSriastradh
89303b705cfSriastradh		kgem->nbatch += 3 * nbox_this_time;
89403b705cfSriastradh		assert(kgem->nbatch < kgem->surface);
89503b705cfSriastradh		while (nbox_this_time >= 8) {
89603b705cfSriastradh			b[0] = cmd; *(uint64_t *)(b+1) = *(const uint64_t *)box++;
89703b705cfSriastradh			b[3] = cmd; *(uint64_t *)(b+4) = *(const uint64_t *)box++;
89803b705cfSriastradh			b[6] = cmd; *(uint64_t *)(b+7) = *(const uint64_t *)box++;
89903b705cfSriastradh			b[9] = cmd; *(uint64_t *)(b+10) = *(const uint64_t *)box++;
90003b705cfSriastradh			b[12] = cmd; *(uint64_t *)(b+13) = *(const uint64_t *)box++;
90103b705cfSriastradh			b[15] = cmd; *(uint64_t *)(b+16) = *(const uint64_t *)box++;
90203b705cfSriastradh			b[18] = cmd; *(uint64_t *)(b+19) = *(const uint64_t *)box++;
90303b705cfSriastradh			b[21] = cmd; *(uint64_t *)(b+22) = *(const uint64_t *)box++;
90403b705cfSriastradh			b += 24;
90503b705cfSriastradh			nbox_this_time -= 8;
90603b705cfSriastradh		}
90703b705cfSriastradh		if (nbox_this_time & 4) {
90803b705cfSriastradh			b[0] = cmd; *(uint64_t *)(b+1) = *(const uint64_t *)box++;
90903b705cfSriastradh			b[3] = cmd; *(uint64_t *)(b+4) = *(const uint64_t *)box++;
91003b705cfSriastradh			b[6] = cmd; *(uint64_t *)(b+7) = *(const uint64_t *)box++;
91103b705cfSriastradh			b[9] = cmd; *(uint64_t *)(b+10) = *(const uint64_t *)box++;
91203b705cfSriastradh			b += 12;
91303b705cfSriastradh		}
91403b705cfSriastradh		if (nbox_this_time & 2) {
91503b705cfSriastradh			b[0] = cmd; *(uint64_t *)(b+1) = *(const uint64_t *)box++;
91603b705cfSriastradh			b[3] = cmd; *(uint64_t *)(b+4) = *(const uint64_t *)box++;
91703b705cfSriastradh			b += 6;
91803b705cfSriastradh		}
91903b705cfSriastradh		if (nbox_this_time & 1) {
92003b705cfSriastradh			b[0] = cmd; *(uint64_t *)(b+1) = *(const uint64_t *)box++;
92103b705cfSriastradh		}
92203b705cfSriastradh
92303b705cfSriastradh		if (!nbox)
92403b705cfSriastradh			return;
92503b705cfSriastradh
92603b705cfSriastradh		sna_blt_fill_begin(sna, blt);
92703b705cfSriastradh	} while (1);
92803b705cfSriastradh}
92903b705cfSriastradh
93003b705cfSriastradhfastcall static void blt_composite_fill_box_no_offset(struct sna *sna,
93103b705cfSriastradh						      const struct sna_composite_op *op,
93203b705cfSriastradh						      const BoxRec *box)
93303b705cfSriastradh{
93403b705cfSriastradh	_sna_blt_fill_box(sna, &op->u.blt, box);
93503b705cfSriastradh}
93603b705cfSriastradh
93703b705cfSriastradhstatic void blt_composite_fill_boxes_no_offset(struct sna *sna,
93803b705cfSriastradh					       const struct sna_composite_op *op,
93903b705cfSriastradh					       const BoxRec *box, int n)
94003b705cfSriastradh{
94103b705cfSriastradh	_sna_blt_fill_boxes(sna, &op->u.blt, box, n);
94203b705cfSriastradh}
94303b705cfSriastradh
94403b705cfSriastradhstatic void blt_composite_fill_boxes_no_offset__thread(struct sna *sna,
94503b705cfSriastradh						       const struct sna_composite_op *op,
94603b705cfSriastradh						       const BoxRec *box, int nbox)
94703b705cfSriastradh{
94803b705cfSriastradh	struct kgem *kgem = &sna->kgem;
94903b705cfSriastradh	const struct sna_blt_state *blt = &op->u.blt;
95003b705cfSriastradh	uint32_t cmd = blt->cmd;
95103b705cfSriastradh
95203b705cfSriastradh	DBG(("%s: %08x x %d\n", __FUNCTION__, blt->pixel, nbox));
95303b705cfSriastradh
95403b705cfSriastradh	sna_vertex_lock(&sna->render);
95503b705cfSriastradh	if (!kgem_check_batch(kgem, 3)) {
95603b705cfSriastradh		sna_vertex_wait__locked(&sna->render);
95703b705cfSriastradh		sna_blt_fill_begin(sna, blt);
95803b705cfSriastradh	}
95903b705cfSriastradh
96003b705cfSriastradh	do {
96103b705cfSriastradh		uint32_t *b = kgem->batch + kgem->nbatch;
96203b705cfSriastradh		int nbox_this_time;
96303b705cfSriastradh
96403b705cfSriastradh		nbox_this_time = nbox;
96503b705cfSriastradh		if (3*nbox_this_time > kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED)
96603b705cfSriastradh			nbox_this_time = (kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) / 3;
96703b705cfSriastradh		assert(nbox_this_time);
96803b705cfSriastradh		nbox -= nbox_this_time;
96903b705cfSriastradh
97003b705cfSriastradh		kgem->nbatch += 3 * nbox_this_time;
97103b705cfSriastradh		assert(kgem->nbatch < kgem->surface);
97203b705cfSriastradh		sna_vertex_acquire__locked(&sna->render);
97303b705cfSriastradh		sna_vertex_unlock(&sna->render);
97403b705cfSriastradh
97503b705cfSriastradh		while (nbox_this_time >= 8) {
97603b705cfSriastradh			b[0] = cmd; *(uint64_t *)(b+1) = *(const uint64_t *)box++;
97703b705cfSriastradh			b[3] = cmd; *(uint64_t *)(b+4) = *(const uint64_t *)box++;
97803b705cfSriastradh			b[6] = cmd; *(uint64_t *)(b+7) = *(const uint64_t *)box++;
97903b705cfSriastradh			b[9] = cmd; *(uint64_t *)(b+10) = *(const uint64_t *)box++;
98003b705cfSriastradh			b[12] = cmd; *(uint64_t *)(b+13) = *(const uint64_t *)box++;
98103b705cfSriastradh			b[15] = cmd; *(uint64_t *)(b+16) = *(const uint64_t *)box++;
98203b705cfSriastradh			b[18] = cmd; *(uint64_t *)(b+19) = *(const uint64_t *)box++;
98303b705cfSriastradh			b[21] = cmd; *(uint64_t *)(b+22) = *(const uint64_t *)box++;
98403b705cfSriastradh			b += 24;
98503b705cfSriastradh			nbox_this_time -= 8;
98603b705cfSriastradh		}
98703b705cfSriastradh		if (nbox_this_time & 4) {
98803b705cfSriastradh			b[0] = cmd; *(uint64_t *)(b+1) = *(const uint64_t *)box++;
98903b705cfSriastradh			b[3] = cmd; *(uint64_t *)(b+4) = *(const uint64_t *)box++;
99003b705cfSriastradh			b[6] = cmd; *(uint64_t *)(b+7) = *(const uint64_t *)box++;
99103b705cfSriastradh			b[9] = cmd; *(uint64_t *)(b+10) = *(const uint64_t *)box++;
99203b705cfSriastradh			b += 12;
99303b705cfSriastradh		}
99403b705cfSriastradh		if (nbox_this_time & 2) {
99503b705cfSriastradh			b[0] = cmd; *(uint64_t *)(b+1) = *(const uint64_t *)box++;
99603b705cfSriastradh			b[3] = cmd; *(uint64_t *)(b+4) = *(const uint64_t *)box++;
99703b705cfSriastradh			b += 6;
99803b705cfSriastradh		}
99903b705cfSriastradh		if (nbox_this_time & 1) {
100003b705cfSriastradh			b[0] = cmd; *(uint64_t *)(b+1) = *(const uint64_t *)box++;
100103b705cfSriastradh		}
100203b705cfSriastradh
100303b705cfSriastradh		sna_vertex_lock(&sna->render);
100403b705cfSriastradh		sna_vertex_release__locked(&sna->render);
100503b705cfSriastradh		if (!nbox)
100603b705cfSriastradh			break;
100703b705cfSriastradh
100803b705cfSriastradh		sna_vertex_wait__locked(&sna->render);
100903b705cfSriastradh		sna_blt_fill_begin(sna, blt);
101003b705cfSriastradh	} while (1);
101103b705cfSriastradh	sna_vertex_unlock(&sna->render);
101203b705cfSriastradh}
101303b705cfSriastradh
101403b705cfSriastradhfastcall static void blt_composite_fill_box(struct sna *sna,
101503b705cfSriastradh					    const struct sna_composite_op *op,
101603b705cfSriastradh					    const BoxRec *box)
101703b705cfSriastradh{
101803b705cfSriastradh	sna_blt_fill_one(sna, &op->u.blt,
101903b705cfSriastradh			 box->x1 + op->dst.x,
102003b705cfSriastradh			 box->y1 + op->dst.y,
102103b705cfSriastradh			 box->x2 - box->x1,
102203b705cfSriastradh			 box->y2 - box->y1);
102303b705cfSriastradh}
102403b705cfSriastradh
102503b705cfSriastradhstatic void blt_composite_fill_boxes(struct sna *sna,
102603b705cfSriastradh				     const struct sna_composite_op *op,
102703b705cfSriastradh				     const BoxRec *box, int n)
102803b705cfSriastradh{
102903b705cfSriastradh	do {
103003b705cfSriastradh		sna_blt_fill_one(sna, &op->u.blt,
103103b705cfSriastradh				 box->x1 + op->dst.x, box->y1 + op->dst.y,
103203b705cfSriastradh				 box->x2 - box->x1, box->y2 - box->y1);
103303b705cfSriastradh		box++;
103403b705cfSriastradh	} while (--n);
103503b705cfSriastradh}
103603b705cfSriastradh
103703b705cfSriastradhstatic inline uint64_t add4(const BoxRec *b, int16_t x, int16_t y)
103803b705cfSriastradh{
103903b705cfSriastradh	union {
104003b705cfSriastradh		uint64_t v;
104103b705cfSriastradh		int16_t i[4];
104203b705cfSriastradh	} vi;
104303b705cfSriastradh	vi.v = *(uint64_t *)b;
104403b705cfSriastradh	vi.i[0] += x;
104503b705cfSriastradh	vi.i[1] += y;
104603b705cfSriastradh	vi.i[2] += x;
104703b705cfSriastradh	vi.i[3] += y;
104803b705cfSriastradh	return vi.v;
104903b705cfSriastradh}
105003b705cfSriastradh
105103b705cfSriastradhstatic void blt_composite_fill_boxes__thread(struct sna *sna,
105203b705cfSriastradh					     const struct sna_composite_op *op,
105303b705cfSriastradh					     const BoxRec *box, int nbox)
105403b705cfSriastradh{
105503b705cfSriastradh	struct kgem *kgem = &sna->kgem;
105603b705cfSriastradh	const struct sna_blt_state *blt = &op->u.blt;
105703b705cfSriastradh	uint32_t cmd = blt->cmd;
105803b705cfSriastradh	int16_t dx = op->dst.x;
105903b705cfSriastradh	int16_t dy = op->dst.y;
106003b705cfSriastradh
106103b705cfSriastradh	DBG(("%s: %08x x %d\n", __FUNCTION__, blt->pixel, nbox));
106203b705cfSriastradh
106303b705cfSriastradh	sna_vertex_lock(&sna->render);
106403b705cfSriastradh	if (!kgem_check_batch(kgem, 3)) {
106503b705cfSriastradh		sna_vertex_wait__locked(&sna->render);
106603b705cfSriastradh		sna_blt_fill_begin(sna, blt);
106703b705cfSriastradh	}
106803b705cfSriastradh
106903b705cfSriastradh	do {
107003b705cfSriastradh		uint32_t *b = kgem->batch + kgem->nbatch;
107103b705cfSriastradh		int nbox_this_time;
107203b705cfSriastradh
107303b705cfSriastradh		nbox_this_time = nbox;
107403b705cfSriastradh		if (3*nbox_this_time > kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED)
107503b705cfSriastradh			nbox_this_time = (kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) / 3;
107603b705cfSriastradh		assert(nbox_this_time);
107703b705cfSriastradh		nbox -= nbox_this_time;
107803b705cfSriastradh
107903b705cfSriastradh		kgem->nbatch += 3 * nbox_this_time;
108003b705cfSriastradh		assert(kgem->nbatch < kgem->surface);
108103b705cfSriastradh		sna_vertex_acquire__locked(&sna->render);
108203b705cfSriastradh		sna_vertex_unlock(&sna->render);
108303b705cfSriastradh
108403b705cfSriastradh		while (nbox_this_time >= 8) {
108503b705cfSriastradh			b[0] = cmd; *(uint64_t *)(b+1) = add4(box++, dx, dy);
108603b705cfSriastradh			b[3] = cmd; *(uint64_t *)(b+4) = add4(box++, dx, dy);
108703b705cfSriastradh			b[6] = cmd; *(uint64_t *)(b+7) = add4(box++, dx, dy);
108803b705cfSriastradh			b[9] = cmd; *(uint64_t *)(b+10) = add4(box++, dx, dy);
108903b705cfSriastradh			b[12] = cmd; *(uint64_t *)(b+13) = add4(box++, dx, dy);
109003b705cfSriastradh			b[15] = cmd; *(uint64_t *)(b+16) = add4(box++, dx, dy);
109103b705cfSriastradh			b[18] = cmd; *(uint64_t *)(b+19) = add4(box++, dx, dy);
109203b705cfSriastradh			b[21] = cmd; *(uint64_t *)(b+22) = add4(box++, dx, dy);
109303b705cfSriastradh			b += 24;
109403b705cfSriastradh			nbox_this_time -= 8;
109503b705cfSriastradh		}
109603b705cfSriastradh		if (nbox_this_time & 4) {
109703b705cfSriastradh			b[0] = cmd; *(uint64_t *)(b+1) = add4(box++, dx, dy);
109803b705cfSriastradh			b[3] = cmd; *(uint64_t *)(b+4) = add4(box++, dx, dy);
109903b705cfSriastradh			b[6] = cmd; *(uint64_t *)(b+7) = add4(box++, dx, dy);
110003b705cfSriastradh			b[9] = cmd; *(uint64_t *)(b+10) = add4(box++, dx, dy);
110103b705cfSriastradh			b += 12;
110203b705cfSriastradh		}
110303b705cfSriastradh		if (nbox_this_time & 2) {
110403b705cfSriastradh			b[0] = cmd; *(uint64_t *)(b+1) = add4(box++, dx, dy);
110503b705cfSriastradh			b[3] = cmd; *(uint64_t *)(b+4) = add4(box++, dx, dy);
110603b705cfSriastradh			b += 6;
110703b705cfSriastradh		}
110803b705cfSriastradh		if (nbox_this_time & 1) {
110903b705cfSriastradh			b[0] = cmd; *(uint64_t *)(b+1) = add4(box++, dx, dy);
111003b705cfSriastradh		}
111103b705cfSriastradh
111203b705cfSriastradh		sna_vertex_lock(&sna->render);
111303b705cfSriastradh		sna_vertex_release__locked(&sna->render);
111403b705cfSriastradh		if (!nbox)
111503b705cfSriastradh			break;
111603b705cfSriastradh
111703b705cfSriastradh		sna_vertex_wait__locked(&sna->render);
111803b705cfSriastradh		sna_blt_fill_begin(sna, blt);
111903b705cfSriastradh	} while (1);
112003b705cfSriastradh	sna_vertex_unlock(&sna->render);
112103b705cfSriastradh}
112203b705cfSriastradh
112303b705cfSriastradhfastcall
112403b705cfSriastradhstatic void blt_composite_nop(struct sna *sna,
112503b705cfSriastradh			       const struct sna_composite_op *op,
112603b705cfSriastradh			       const struct sna_composite_rectangles *r)
112703b705cfSriastradh{
112803b705cfSriastradh}
112903b705cfSriastradh
113003b705cfSriastradhfastcall static void blt_composite_nop_box(struct sna *sna,
113103b705cfSriastradh					   const struct sna_composite_op *op,
113203b705cfSriastradh					   const BoxRec *box)
113303b705cfSriastradh{
113403b705cfSriastradh}
113503b705cfSriastradh
113603b705cfSriastradhstatic void blt_composite_nop_boxes(struct sna *sna,
113703b705cfSriastradh				    const struct sna_composite_op *op,
113803b705cfSriastradh				    const BoxRec *box, int n)
113903b705cfSriastradh{
114003b705cfSriastradh}
114103b705cfSriastradh
114203b705cfSriastradhstatic bool
114303b705cfSriastradhbegin_blt(struct sna *sna,
114403b705cfSriastradh	  struct sna_composite_op *op)
114503b705cfSriastradh{
114603b705cfSriastradh	if (!kgem_check_bo_fenced(&sna->kgem, op->dst.bo)) {
114703b705cfSriastradh		kgem_submit(&sna->kgem);
114803b705cfSriastradh		if (!kgem_check_bo_fenced(&sna->kgem, op->dst.bo))
114903b705cfSriastradh			return false;
115003b705cfSriastradh
115103b705cfSriastradh		_kgem_set_mode(&sna->kgem, KGEM_BLT);
115203b705cfSriastradh	}
115303b705cfSriastradh
115403b705cfSriastradh	return true;
115503b705cfSriastradh}
115603b705cfSriastradh
115703b705cfSriastradhstatic bool
115803b705cfSriastradhprepare_blt_nop(struct sna *sna,
115903b705cfSriastradh		struct sna_composite_op *op)
116003b705cfSriastradh{
116103b705cfSriastradh	DBG(("%s\n", __FUNCTION__));
116203b705cfSriastradh
116303b705cfSriastradh	op->blt   = blt_composite_nop;
116403b705cfSriastradh	op->box   = blt_composite_nop_box;
116503b705cfSriastradh	op->boxes = blt_composite_nop_boxes;
116603b705cfSriastradh	op->done  = nop_done;
116703b705cfSriastradh	return true;
116803b705cfSriastradh}
116903b705cfSriastradh
117003b705cfSriastradhstatic bool
117103b705cfSriastradhprepare_blt_clear(struct sna *sna,
117203b705cfSriastradh		  struct sna_composite_op *op)
117303b705cfSriastradh{
117403b705cfSriastradh	DBG(("%s\n", __FUNCTION__));
117503b705cfSriastradh
117603b705cfSriastradh	if (op->dst.bo == NULL) {
117703b705cfSriastradh		op->blt   = blt_composite_fill__cpu;
117803b705cfSriastradh		op->box   = blt_composite_fill_box__cpu;
117903b705cfSriastradh		op->boxes = blt_composite_fill_boxes__cpu;
118003b705cfSriastradh		op->thread_boxes = blt_composite_fill_boxes__cpu;
118103b705cfSriastradh		op->done  = nop_done;
118203b705cfSriastradh		op->u.blt.pixel = 0;
118303b705cfSriastradh		return true;
118403b705cfSriastradh	}
118503b705cfSriastradh
118603b705cfSriastradh	op->blt = blt_composite_fill;
118703b705cfSriastradh	if (op->dst.x|op->dst.y) {
118803b705cfSriastradh		op->box   = blt_composite_fill_box;
118903b705cfSriastradh		op->boxes = blt_composite_fill_boxes;
119003b705cfSriastradh		op->thread_boxes = blt_composite_fill_boxes__thread;
119103b705cfSriastradh	} else {
119203b705cfSriastradh		op->box   = blt_composite_fill_box_no_offset;
119303b705cfSriastradh		op->boxes = blt_composite_fill_boxes_no_offset;
119403b705cfSriastradh		op->thread_boxes = blt_composite_fill_boxes_no_offset__thread;
119503b705cfSriastradh	}
119603b705cfSriastradh	op->done = nop_done;
119703b705cfSriastradh
119803b705cfSriastradh	if (!sna_blt_fill_init(sna, &op->u.blt,
119903b705cfSriastradh				 op->dst.bo,
120003b705cfSriastradh				 op->dst.pixmap->drawable.bitsPerPixel,
120103b705cfSriastradh				 GXclear, 0))
120203b705cfSriastradh		return false;
120303b705cfSriastradh
120403b705cfSriastradh	return begin_blt(sna, op);
120503b705cfSriastradh}
120603b705cfSriastradh
120703b705cfSriastradhstatic bool
120803b705cfSriastradhprepare_blt_fill(struct sna *sna,
120903b705cfSriastradh		 struct sna_composite_op *op,
121003b705cfSriastradh		 uint32_t pixel)
121103b705cfSriastradh{
121203b705cfSriastradh	DBG(("%s\n", __FUNCTION__));
121303b705cfSriastradh
121403b705cfSriastradh	if (op->dst.bo == NULL) {
121503b705cfSriastradh		op->u.blt.pixel = pixel;
121603b705cfSriastradh		op->blt = blt_composite_fill__cpu;
121703b705cfSriastradh		op->box   = blt_composite_fill_box__cpu;
121803b705cfSriastradh		op->boxes = blt_composite_fill_boxes__cpu;
121903b705cfSriastradh		op->thread_boxes = blt_composite_fill_boxes__cpu;
122003b705cfSriastradh		op->done = nop_done;
122103b705cfSriastradh		return true;
122203b705cfSriastradh	}
122303b705cfSriastradh
122403b705cfSriastradh	op->blt = blt_composite_fill;
122503b705cfSriastradh	if (op->dst.x|op->dst.y) {
122603b705cfSriastradh		op->box   = blt_composite_fill_box;
122703b705cfSriastradh		op->boxes = blt_composite_fill_boxes;
122803b705cfSriastradh		op->thread_boxes = blt_composite_fill_boxes__thread;
122903b705cfSriastradh	} else {
123003b705cfSriastradh		op->box   = blt_composite_fill_box_no_offset;
123103b705cfSriastradh		op->boxes = blt_composite_fill_boxes_no_offset;
123203b705cfSriastradh		op->thread_boxes = blt_composite_fill_boxes_no_offset__thread;
123303b705cfSriastradh	}
123403b705cfSriastradh	op->done = nop_done;
123503b705cfSriastradh
123603b705cfSriastradh	if (!sna_blt_fill_init(sna, &op->u.blt, op->dst.bo,
123703b705cfSriastradh			       op->dst.pixmap->drawable.bitsPerPixel,
123803b705cfSriastradh			       GXcopy, pixel))
123903b705cfSriastradh		return false;
124003b705cfSriastradh
124103b705cfSriastradh	return begin_blt(sna, op);
124203b705cfSriastradh}
124303b705cfSriastradh
124403b705cfSriastradhfastcall static void
124503b705cfSriastradhblt_composite_copy(struct sna *sna,
124603b705cfSriastradh		   const struct sna_composite_op *op,
124703b705cfSriastradh		   const struct sna_composite_rectangles *r)
124803b705cfSriastradh{
124903b705cfSriastradh	int x1, x2, y1, y2;
125003b705cfSriastradh	int src_x, src_y;
125103b705cfSriastradh
125203b705cfSriastradh	DBG(("%s: src=(%d, %d), dst=(%d, %d), size=(%d, %d)\n",
125303b705cfSriastradh	     __FUNCTION__,
125403b705cfSriastradh	     r->src.x, r->src.y,
125503b705cfSriastradh	     r->dst.x, r->dst.y,
125603b705cfSriastradh	     r->width, r->height));
125703b705cfSriastradh
125803b705cfSriastradh	/* XXX higher layer should have clipped? */
125903b705cfSriastradh
126003b705cfSriastradh	x1 = r->dst.x + op->dst.x;
126103b705cfSriastradh	y1 = r->dst.y + op->dst.y;
126203b705cfSriastradh	x2 = x1 + r->width;
126303b705cfSriastradh	y2 = y1 + r->height;
126403b705cfSriastradh
126503b705cfSriastradh	src_x = r->src.x - x1;
126603b705cfSriastradh	src_y = r->src.y - y1;
126703b705cfSriastradh
126803b705cfSriastradh	/* clip against dst */
126903b705cfSriastradh	if (x1 < 0)
127003b705cfSriastradh		x1 = 0;
127103b705cfSriastradh	if (y1 < 0)
127203b705cfSriastradh		y1 = 0;
127303b705cfSriastradh
127403b705cfSriastradh	if (x2 > op->dst.width)
127503b705cfSriastradh		x2 = op->dst.width;
127603b705cfSriastradh
127703b705cfSriastradh	if (y2 > op->dst.height)
127803b705cfSriastradh		y2 = op->dst.height;
127903b705cfSriastradh
128003b705cfSriastradh	DBG(("%s: box=(%d, %d), (%d, %d)\n", __FUNCTION__, x1, y1, x2, y2));
128103b705cfSriastradh
128203b705cfSriastradh	if (x2 <= x1 || y2 <= y1)
128303b705cfSriastradh		return;
128403b705cfSriastradh
128503b705cfSriastradh	sna_blt_copy_one(sna, &op->u.blt,
128603b705cfSriastradh			 x1 + src_x, y1 + src_y,
128703b705cfSriastradh			 x2 - x1, y2 - y1,
128803b705cfSriastradh			 x1, y1);
128903b705cfSriastradh}
129003b705cfSriastradh
129103b705cfSriastradhfastcall static void blt_composite_copy_box(struct sna *sna,
129203b705cfSriastradh					    const struct sna_composite_op *op,
129303b705cfSriastradh					    const BoxRec *box)
129403b705cfSriastradh{
129503b705cfSriastradh	DBG(("%s: box (%d, %d), (%d, %d)\n",
129603b705cfSriastradh	     __FUNCTION__, box->x1, box->y1, box->x2, box->y2));
129703b705cfSriastradh	sna_blt_copy_one(sna, &op->u.blt,
129803b705cfSriastradh			 box->x1 + op->u.blt.sx,
129903b705cfSriastradh			 box->y1 + op->u.blt.sy,
130003b705cfSriastradh			 box->x2 - box->x1,
130103b705cfSriastradh			 box->y2 - box->y1,
130203b705cfSriastradh			 box->x1 + op->dst.x,
130303b705cfSriastradh			 box->y1 + op->dst.y);
130403b705cfSriastradh}
130503b705cfSriastradh
130603b705cfSriastradhstatic void blt_composite_copy_boxes(struct sna *sna,
130703b705cfSriastradh				     const struct sna_composite_op *op,
130803b705cfSriastradh				     const BoxRec *box, int nbox)
130903b705cfSriastradh{
131003b705cfSriastradh	DBG(("%s: nbox=%d\n", __FUNCTION__, nbox));
131103b705cfSriastradh	do {
131203b705cfSriastradh		DBG(("%s: box (%d, %d), (%d, %d)\n",
131303b705cfSriastradh		     __FUNCTION__, box->x1, box->y1, box->x2, box->y2));
131403b705cfSriastradh		sna_blt_copy_one(sna, &op->u.blt,
131503b705cfSriastradh				 box->x1 + op->u.blt.sx, box->y1 + op->u.blt.sy,
131603b705cfSriastradh				 box->x2 - box->x1, box->y2 - box->y1,
131703b705cfSriastradh				 box->x1 + op->dst.x, box->y1 + op->dst.y);
131803b705cfSriastradh		box++;
131903b705cfSriastradh	} while(--nbox);
132003b705cfSriastradh}
132103b705cfSriastradh
132203b705cfSriastradhstatic inline uint32_t add2(uint32_t v, int16_t x, int16_t y)
132303b705cfSriastradh{
132403b705cfSriastradh	x += v & 0xffff;
132503b705cfSriastradh	y += v >> 16;
132603b705cfSriastradh	return (uint16_t)y << 16 | x;
132703b705cfSriastradh}
132803b705cfSriastradh
132903b705cfSriastradhstatic void blt_composite_copy_boxes__thread(struct sna *sna,
133003b705cfSriastradh					     const struct sna_composite_op *op,
133103b705cfSriastradh					     const BoxRec *box, int nbox)
133203b705cfSriastradh{
133303b705cfSriastradh	struct kgem *kgem = &sna->kgem;
133403b705cfSriastradh	int dst_dx = op->dst.x;
133503b705cfSriastradh	int dst_dy = op->dst.y;
133603b705cfSriastradh	int src_dx = op->src.offset[0];
133703b705cfSriastradh	int src_dy = op->src.offset[1];
133803b705cfSriastradh	uint32_t cmd = op->u.blt.cmd;
133903b705cfSriastradh	uint32_t br13 = op->u.blt.br13;
134003b705cfSriastradh	struct kgem_bo *src_bo = op->u.blt.bo[0];
134103b705cfSriastradh	struct kgem_bo *dst_bo = op->u.blt.bo[1];
134203b705cfSriastradh	int src_pitch = op->u.blt.pitch[0];
134303b705cfSriastradh
134403b705cfSriastradh	DBG(("%s: nbox=%d\n", __FUNCTION__, nbox));
134503b705cfSriastradh
134603b705cfSriastradh	sna_vertex_lock(&sna->render);
134703b705cfSriastradh
134803b705cfSriastradh	if ((dst_dx | dst_dy) == 0) {
134903b705cfSriastradh		uint64_t hdr = (uint64_t)br13 << 32 | cmd;
135003b705cfSriastradh		do {
135103b705cfSriastradh			int nbox_this_time;
135203b705cfSriastradh
135303b705cfSriastradh			nbox_this_time = nbox;
135403b705cfSriastradh			if (8*nbox_this_time > kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED)
135503b705cfSriastradh				nbox_this_time = (kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) / 8;
135603b705cfSriastradh			if (2*nbox_this_time > KGEM_RELOC_SIZE(kgem) - kgem->nreloc)
135703b705cfSriastradh				nbox_this_time = (KGEM_RELOC_SIZE(kgem) - kgem->nreloc)/2;
135803b705cfSriastradh			assert(nbox_this_time);
135903b705cfSriastradh			nbox -= nbox_this_time;
136003b705cfSriastradh
136103b705cfSriastradh			do {
136203b705cfSriastradh				uint32_t *b = kgem->batch + kgem->nbatch;
136303b705cfSriastradh
136403b705cfSriastradh				DBG(("  %s: box=(%d, %d)x(%d, %d)\n",
136503b705cfSriastradh				     __FUNCTION__,
136603b705cfSriastradh				     box->x1, box->y1,
136703b705cfSriastradh				     box->x2 - box->x1, box->y2 - box->y1));
136803b705cfSriastradh
136903b705cfSriastradh				assert(box->x1 + src_dx >= 0);
137003b705cfSriastradh				assert(box->y1 + src_dy >= 0);
137103b705cfSriastradh				assert(box->x1 + src_dx <= INT16_MAX);
137203b705cfSriastradh				assert(box->y1 + src_dy <= INT16_MAX);
137303b705cfSriastradh
137403b705cfSriastradh				assert(box->x1 >= 0);
137503b705cfSriastradh				assert(box->y1 >= 0);
137603b705cfSriastradh
137703b705cfSriastradh				*(uint64_t *)&b[0] = hdr;
137803b705cfSriastradh				*(uint64_t *)&b[2] = *(const uint64_t *)box;
137903b705cfSriastradh				b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4, dst_bo,
138003b705cfSriastradh						      I915_GEM_DOMAIN_RENDER << 16 |
138103b705cfSriastradh						      I915_GEM_DOMAIN_RENDER |
138203b705cfSriastradh						      KGEM_RELOC_FENCED,
138303b705cfSriastradh						      0);
138403b705cfSriastradh				b[5] = add2(b[2], src_dx, src_dy);
138503b705cfSriastradh				b[6] = src_pitch;
138603b705cfSriastradh				b[7] = kgem_add_reloc(kgem, kgem->nbatch + 7, src_bo,
138703b705cfSriastradh						      I915_GEM_DOMAIN_RENDER << 16 |
138803b705cfSriastradh						      KGEM_RELOC_FENCED,
138903b705cfSriastradh						      0);
139003b705cfSriastradh				kgem->nbatch += 8;
139103b705cfSriastradh				assert(kgem->nbatch < kgem->surface);
139203b705cfSriastradh				box++;
139303b705cfSriastradh			} while (--nbox_this_time);
139403b705cfSriastradh
139503b705cfSriastradh			if (!nbox)
139603b705cfSriastradh				break;
139703b705cfSriastradh
139803b705cfSriastradh			_kgem_submit(kgem);
139903b705cfSriastradh			_kgem_set_mode(kgem, KGEM_BLT);
140003b705cfSriastradh		} while (1);
140103b705cfSriastradh	} else {
140203b705cfSriastradh		do {
140303b705cfSriastradh			int nbox_this_time;
140403b705cfSriastradh
140503b705cfSriastradh			nbox_this_time = nbox;
140603b705cfSriastradh			if (8*nbox_this_time > kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED)
140703b705cfSriastradh				nbox_this_time = (kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) / 8;
140803b705cfSriastradh			if (2*nbox_this_time > KGEM_RELOC_SIZE(kgem) - kgem->nreloc)
140903b705cfSriastradh				nbox_this_time = (KGEM_RELOC_SIZE(kgem) - kgem->nreloc)/2;
141003b705cfSriastradh			assert(nbox_this_time);
141103b705cfSriastradh			nbox -= nbox_this_time;
141203b705cfSriastradh
141303b705cfSriastradh			do {
141403b705cfSriastradh				uint32_t *b = kgem->batch + kgem->nbatch;
141503b705cfSriastradh
141603b705cfSriastradh				DBG(("  %s: box=(%d, %d)x(%d, %d)\n",
141703b705cfSriastradh				     __FUNCTION__,
141803b705cfSriastradh				     box->x1, box->y1,
141903b705cfSriastradh				     box->x2 - box->x1, box->y2 - box->y1));
142003b705cfSriastradh
142103b705cfSriastradh				assert(box->x1 + src_dx >= 0);
142203b705cfSriastradh				assert(box->y1 + src_dy >= 0);
142303b705cfSriastradh
142403b705cfSriastradh				assert(box->x1 + dst_dx >= 0);
142503b705cfSriastradh				assert(box->y1 + dst_dy >= 0);
142603b705cfSriastradh
142703b705cfSriastradh				b[0] = cmd;
142803b705cfSriastradh				b[1] = br13;
142903b705cfSriastradh				b[2] = ((box->y1 + dst_dy) << 16) | (box->x1 + dst_dx);
143003b705cfSriastradh				b[3] = ((box->y2 + dst_dy) << 16) | (box->x2 + dst_dx);
143103b705cfSriastradh				b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4, dst_bo,
143203b705cfSriastradh						      I915_GEM_DOMAIN_RENDER << 16 |
143303b705cfSriastradh						      I915_GEM_DOMAIN_RENDER |
143403b705cfSriastradh						      KGEM_RELOC_FENCED,
143503b705cfSriastradh						      0);
143603b705cfSriastradh				b[5] = ((box->y1 + src_dy) << 16) | (box->x1 + src_dx);
143703b705cfSriastradh				b[6] = src_pitch;
143803b705cfSriastradh				b[7] = kgem_add_reloc(kgem, kgem->nbatch + 7, src_bo,
143903b705cfSriastradh						      I915_GEM_DOMAIN_RENDER << 16 |
144003b705cfSriastradh						      KGEM_RELOC_FENCED,
144103b705cfSriastradh						      0);
144203b705cfSriastradh				kgem->nbatch += 8;
144303b705cfSriastradh				assert(kgem->nbatch < kgem->surface);
144403b705cfSriastradh				box++;
144503b705cfSriastradh			} while (--nbox_this_time);
144603b705cfSriastradh
144703b705cfSriastradh			if (!nbox)
144803b705cfSriastradh				break;
144903b705cfSriastradh
145003b705cfSriastradh			_kgem_submit(kgem);
145103b705cfSriastradh			_kgem_set_mode(kgem, KGEM_BLT);
145203b705cfSriastradh		} while (1);
145303b705cfSriastradh	}
145403b705cfSriastradh	sna_vertex_unlock(&sna->render);
145503b705cfSriastradh}
145603b705cfSriastradh
145703b705cfSriastradhfastcall static void
145803b705cfSriastradhblt_composite_copy_with_alpha(struct sna *sna,
145903b705cfSriastradh			      const struct sna_composite_op *op,
146003b705cfSriastradh			      const struct sna_composite_rectangles *r)
146103b705cfSriastradh{
146203b705cfSriastradh	int x1, x2, y1, y2;
146303b705cfSriastradh	int src_x, src_y;
146403b705cfSriastradh
146503b705cfSriastradh	DBG(("%s: src=(%d, %d), dst=(%d, %d), size=(%d, %d)\n",
146603b705cfSriastradh	     __FUNCTION__,
146703b705cfSriastradh	     r->src.x, r->src.y,
146803b705cfSriastradh	     r->dst.x, r->dst.y,
146903b705cfSriastradh	     r->width, r->height));
147003b705cfSriastradh
147103b705cfSriastradh	/* XXX higher layer should have clipped? */
147203b705cfSriastradh
147303b705cfSriastradh	x1 = r->dst.x + op->dst.x;
147403b705cfSriastradh	y1 = r->dst.y + op->dst.y;
147503b705cfSriastradh	x2 = x1 + r->width;
147603b705cfSriastradh	y2 = y1 + r->height;
147703b705cfSriastradh
147803b705cfSriastradh	src_x = r->src.x - x1;
147903b705cfSriastradh	src_y = r->src.y - y1;
148003b705cfSriastradh
148103b705cfSriastradh	/* clip against dst */
148203b705cfSriastradh	if (x1 < 0)
148303b705cfSriastradh		x1 = 0;
148403b705cfSriastradh	if (y1 < 0)
148503b705cfSriastradh		y1 = 0;
148603b705cfSriastradh
148703b705cfSriastradh	if (x2 > op->dst.width)
148803b705cfSriastradh		x2 = op->dst.width;
148903b705cfSriastradh
149003b705cfSriastradh	if (y2 > op->dst.height)
149103b705cfSriastradh		y2 = op->dst.height;
149203b705cfSriastradh
149303b705cfSriastradh	DBG(("%s: box=(%d, %d), (%d, %d)\n", __FUNCTION__, x1, y1, x2, y2));
149403b705cfSriastradh
149503b705cfSriastradh	if (x2 <= x1 || y2 <= y1)
149603b705cfSriastradh		return;
149703b705cfSriastradh
149803b705cfSriastradh	sna_blt_alpha_fixup_one(sna, &op->u.blt,
149903b705cfSriastradh				x1 + src_x, y1 + src_y,
150003b705cfSriastradh				x2 - x1, y2 - y1,
150103b705cfSriastradh				x1, y1);
150203b705cfSriastradh}
150303b705cfSriastradh
150403b705cfSriastradhfastcall static void
150503b705cfSriastradhblt_composite_copy_box_with_alpha(struct sna *sna,
150603b705cfSriastradh				  const struct sna_composite_op *op,
150703b705cfSriastradh				  const BoxRec *box)
150803b705cfSriastradh{
150903b705cfSriastradh	DBG(("%s: box (%d, %d), (%d, %d)\n",
151003b705cfSriastradh	     __FUNCTION__, box->x1, box->y1, box->x2, box->y2));
151103b705cfSriastradh	sna_blt_alpha_fixup_one(sna, &op->u.blt,
151203b705cfSriastradh				box->x1 + op->u.blt.sx,
151303b705cfSriastradh				box->y1 + op->u.blt.sy,
151403b705cfSriastradh				box->x2 - box->x1,
151503b705cfSriastradh				box->y2 - box->y1,
151603b705cfSriastradh				box->x1 + op->dst.x,
151703b705cfSriastradh				box->y1 + op->dst.y);
151803b705cfSriastradh}
151903b705cfSriastradh
152003b705cfSriastradhstatic void
152103b705cfSriastradhblt_composite_copy_boxes_with_alpha(struct sna *sna,
152203b705cfSriastradh				    const struct sna_composite_op *op,
152303b705cfSriastradh				    const BoxRec *box, int nbox)
152403b705cfSriastradh{
152503b705cfSriastradh	DBG(("%s: nbox=%d\n", __FUNCTION__, nbox));
152603b705cfSriastradh	do {
152703b705cfSriastradh		DBG(("%s: box (%d, %d), (%d, %d)\n",
152803b705cfSriastradh		     __FUNCTION__, box->x1, box->y1, box->x2, box->y2));
152903b705cfSriastradh		sna_blt_alpha_fixup_one(sna, &op->u.blt,
153003b705cfSriastradh					box->x1 + op->u.blt.sx, box->y1 + op->u.blt.sy,
153103b705cfSriastradh					box->x2 - box->x1, box->y2 - box->y1,
153203b705cfSriastradh					box->x1 + op->dst.x, box->y1 + op->dst.y);
153303b705cfSriastradh		box++;
153403b705cfSriastradh	} while(--nbox);
153503b705cfSriastradh}
153603b705cfSriastradh
153703b705cfSriastradhstatic bool
153803b705cfSriastradhprepare_blt_copy(struct sna *sna,
153903b705cfSriastradh		 struct sna_composite_op *op,
154003b705cfSriastradh		 struct kgem_bo *bo,
154103b705cfSriastradh		 uint32_t alpha_fixup)
154203b705cfSriastradh{
154303b705cfSriastradh	PixmapPtr src = op->u.blt.src_pixmap;
154403b705cfSriastradh
154503b705cfSriastradh	assert(op->dst.bo);
154603b705cfSriastradh	assert(kgem_bo_can_blt(&sna->kgem, op->dst.bo));
154703b705cfSriastradh	assert(kgem_bo_can_blt(&sna->kgem, bo));
154803b705cfSriastradh
154903b705cfSriastradh	if (!kgem_check_many_bo_fenced(&sna->kgem, op->dst.bo, bo, NULL)) {
155003b705cfSriastradh		kgem_submit(&sna->kgem);
155103b705cfSriastradh		if (!kgem_check_many_bo_fenced(&sna->kgem,
155203b705cfSriastradh					       op->dst.bo, bo, NULL)) {
155303b705cfSriastradh			DBG(("%s: fallback -- no room in aperture\n", __FUNCTION__));
155403b705cfSriastradh			return false;
155503b705cfSriastradh		}
155603b705cfSriastradh		_kgem_set_mode(&sna->kgem, KGEM_BLT);
155703b705cfSriastradh	}
155803b705cfSriastradh
155903b705cfSriastradh	DBG(("%s\n", __FUNCTION__));
156003b705cfSriastradh
156103b705cfSriastradh	if (sna->kgem.gen >= 060 && op->dst.bo == bo)
156203b705cfSriastradh		op->done = gen6_blt_copy_done;
156303b705cfSriastradh	else
156403b705cfSriastradh		op->done = nop_done;
156503b705cfSriastradh
156603b705cfSriastradh	if (alpha_fixup) {
156703b705cfSriastradh		op->blt   = blt_composite_copy_with_alpha;
156803b705cfSriastradh		op->box   = blt_composite_copy_box_with_alpha;
156903b705cfSriastradh		op->boxes = blt_composite_copy_boxes_with_alpha;
157003b705cfSriastradh
157103b705cfSriastradh		if (!sna_blt_alpha_fixup_init(sna, &op->u.blt, bo, op->dst.bo,
157203b705cfSriastradh					      src->drawable.bitsPerPixel,
157303b705cfSriastradh					      alpha_fixup))
157403b705cfSriastradh			return false;
157503b705cfSriastradh	} else {
157603b705cfSriastradh		op->blt   = blt_composite_copy;
157703b705cfSriastradh		op->box   = blt_composite_copy_box;
157803b705cfSriastradh		op->boxes = blt_composite_copy_boxes;
157903b705cfSriastradh		op->thread_boxes = blt_composite_copy_boxes__thread;
158003b705cfSriastradh
158103b705cfSriastradh		if (!sna_blt_copy_init(sna, &op->u.blt, bo, op->dst.bo,
158203b705cfSriastradh				       src->drawable.bitsPerPixel,
158303b705cfSriastradh				       GXcopy))
158403b705cfSriastradh			return false;
158503b705cfSriastradh	}
158603b705cfSriastradh
158703b705cfSriastradh	return true;
158803b705cfSriastradh}
158903b705cfSriastradh
159003b705cfSriastradhfastcall static void
159103b705cfSriastradhblt_put_composite__cpu(struct sna *sna,
159203b705cfSriastradh		       const struct sna_composite_op *op,
159303b705cfSriastradh		       const struct sna_composite_rectangles *r)
159403b705cfSriastradh{
159503b705cfSriastradh	PixmapPtr dst = op->dst.pixmap;
159603b705cfSriastradh	PixmapPtr src = op->u.blt.src_pixmap;
159703b705cfSriastradh	memcpy_blt(src->devPrivate.ptr, dst->devPrivate.ptr,
159803b705cfSriastradh		   src->drawable.bitsPerPixel, src->devKind, dst->devKind,
159903b705cfSriastradh		   r->src.x + op->u.blt.sx, r->src.y + op->u.blt.sy,
160003b705cfSriastradh		   r->dst.x + op->dst.x, r->dst.y + op->dst.y,
160103b705cfSriastradh		   r->width, r->height);
160203b705cfSriastradh}
160303b705cfSriastradh
160403b705cfSriastradhfastcall static void
160503b705cfSriastradhblt_put_composite_box__cpu(struct sna *sna,
160603b705cfSriastradh			   const struct sna_composite_op *op,
160703b705cfSriastradh			   const BoxRec *box)
160803b705cfSriastradh{
160903b705cfSriastradh	PixmapPtr dst = op->dst.pixmap;
161003b705cfSriastradh	PixmapPtr src = op->u.blt.src_pixmap;
161103b705cfSriastradh	memcpy_blt(src->devPrivate.ptr, dst->devPrivate.ptr,
161203b705cfSriastradh		   src->drawable.bitsPerPixel, src->devKind, dst->devKind,
161303b705cfSriastradh		   box->x1 + op->u.blt.sx, box->y1 + op->u.blt.sy,
161403b705cfSriastradh		   box->x1 + op->dst.x, box->y1 + op->dst.y,
161503b705cfSriastradh		   box->x2-box->x1, box->y2-box->y1);
161603b705cfSriastradh}
161703b705cfSriastradh
161803b705cfSriastradhstatic void
161903b705cfSriastradhblt_put_composite_boxes__cpu(struct sna *sna,
162003b705cfSriastradh			     const struct sna_composite_op *op,
162103b705cfSriastradh			     const BoxRec *box, int n)
162203b705cfSriastradh{
162303b705cfSriastradh	PixmapPtr dst = op->dst.pixmap;
162403b705cfSriastradh	PixmapPtr src = op->u.blt.src_pixmap;
162503b705cfSriastradh	do {
162603b705cfSriastradh		memcpy_blt(src->devPrivate.ptr, dst->devPrivate.ptr,
162703b705cfSriastradh			   src->drawable.bitsPerPixel, src->devKind, dst->devKind,
162803b705cfSriastradh			   box->x1 + op->u.blt.sx, box->y1 + op->u.blt.sy,
162903b705cfSriastradh			   box->x1 + op->dst.x, box->y1 + op->dst.y,
163003b705cfSriastradh			   box->x2-box->x1, box->y2-box->y1);
163103b705cfSriastradh		box++;
163203b705cfSriastradh	} while (--n);
163303b705cfSriastradh}
163403b705cfSriastradh
163503b705cfSriastradhfastcall static void
163603b705cfSriastradhblt_put_composite_with_alpha__cpu(struct sna *sna,
163703b705cfSriastradh				  const struct sna_composite_op *op,
163803b705cfSriastradh				  const struct sna_composite_rectangles *r)
163903b705cfSriastradh{
164003b705cfSriastradh	PixmapPtr dst = op->dst.pixmap;
164103b705cfSriastradh	PixmapPtr src = op->u.blt.src_pixmap;
164203b705cfSriastradh	memcpy_xor(src->devPrivate.ptr, dst->devPrivate.ptr,
164303b705cfSriastradh		   src->drawable.bitsPerPixel, src->devKind, dst->devKind,
164403b705cfSriastradh		   r->src.x + op->u.blt.sx, r->src.y + op->u.blt.sy,
164503b705cfSriastradh		   r->dst.x + op->dst.x, r->dst.y + op->dst.y,
164603b705cfSriastradh		   r->width, r->height,
164703b705cfSriastradh		   0xffffffff, op->u.blt.pixel);
164803b705cfSriastradh
164903b705cfSriastradh}
165003b705cfSriastradh
165103b705cfSriastradhfastcall static void
165203b705cfSriastradhblt_put_composite_box_with_alpha__cpu(struct sna *sna,
165303b705cfSriastradh				      const struct sna_composite_op *op,
165403b705cfSriastradh				      const BoxRec *box)
165503b705cfSriastradh{
165603b705cfSriastradh	PixmapPtr dst = op->dst.pixmap;
165703b705cfSriastradh	PixmapPtr src = op->u.blt.src_pixmap;
165803b705cfSriastradh	memcpy_xor(src->devPrivate.ptr, dst->devPrivate.ptr,
165903b705cfSriastradh		   src->drawable.bitsPerPixel, src->devKind, dst->devKind,
166003b705cfSriastradh		   box->x1 + op->u.blt.sx, box->y1 + op->u.blt.sy,
166103b705cfSriastradh		   box->x1 + op->dst.x, box->y1 + op->dst.y,
166203b705cfSriastradh		   box->x2-box->x1, box->y2-box->y1,
166303b705cfSriastradh		   0xffffffff, op->u.blt.pixel);
166403b705cfSriastradh}
166503b705cfSriastradh
166603b705cfSriastradhstatic void
166703b705cfSriastradhblt_put_composite_boxes_with_alpha__cpu(struct sna *sna,
166803b705cfSriastradh					const struct sna_composite_op *op,
166903b705cfSriastradh					const BoxRec *box, int n)
167003b705cfSriastradh{
167103b705cfSriastradh	PixmapPtr dst = op->dst.pixmap;
167203b705cfSriastradh	PixmapPtr src = op->u.blt.src_pixmap;
167303b705cfSriastradh	do {
167403b705cfSriastradh		memcpy_xor(src->devPrivate.ptr, dst->devPrivate.ptr,
167503b705cfSriastradh			   src->drawable.bitsPerPixel, src->devKind, dst->devKind,
167603b705cfSriastradh			   box->x1 + op->u.blt.sx, box->y1 + op->u.blt.sy,
167703b705cfSriastradh			   box->x1 + op->dst.x, box->y1 + op->dst.y,
167803b705cfSriastradh			   box->x2-box->x1, box->y2-box->y1,
167903b705cfSriastradh			   0xffffffff, op->u.blt.pixel);
168003b705cfSriastradh		box++;
168103b705cfSriastradh	} while (--n);
168203b705cfSriastradh}
168303b705cfSriastradh
168403b705cfSriastradhfastcall static void
168503b705cfSriastradhblt_put_composite(struct sna *sna,
168603b705cfSriastradh		  const struct sna_composite_op *op,
168703b705cfSriastradh		  const struct sna_composite_rectangles *r)
168803b705cfSriastradh{
168903b705cfSriastradh	PixmapPtr dst = op->dst.pixmap;
169003b705cfSriastradh	PixmapPtr src = op->u.blt.src_pixmap;
169103b705cfSriastradh	struct sna_pixmap *dst_priv = sna_pixmap(dst);
169203b705cfSriastradh	int pitch = src->devKind;
169303b705cfSriastradh	char *data = src->devPrivate.ptr;
169403b705cfSriastradh	int bpp = src->drawable.bitsPerPixel;
169503b705cfSriastradh
169603b705cfSriastradh	int16_t dst_x = r->dst.x + op->dst.x;
169703b705cfSriastradh	int16_t dst_y = r->dst.y + op->dst.y;
169803b705cfSriastradh	int16_t src_x = r->src.x + op->u.blt.sx;
169903b705cfSriastradh	int16_t src_y = r->src.y + op->u.blt.sy;
170003b705cfSriastradh
170103b705cfSriastradh	if (!dst_priv->pinned &&
170203b705cfSriastradh	    dst_x <= 0 && dst_y <= 0 &&
170303b705cfSriastradh	    dst_x + r->width >= op->dst.width &&
170403b705cfSriastradh	    dst_y + r->height >= op->dst.height) {
170503b705cfSriastradh		data += (src_x - dst_x) * bpp / 8;
170603b705cfSriastradh		data += (src_y - dst_y) * pitch;
170703b705cfSriastradh
170803b705cfSriastradh		sna_replace(sna, op->dst.pixmap, &dst_priv->gpu_bo,
170903b705cfSriastradh			    data, pitch);
171003b705cfSriastradh	} else {
171103b705cfSriastradh		BoxRec box;
171203b705cfSriastradh		bool ok;
171303b705cfSriastradh
171403b705cfSriastradh		box.x1 = dst_x;
171503b705cfSriastradh		box.y1 = dst_y;
171603b705cfSriastradh		box.x2 = dst_x + r->width;
171703b705cfSriastradh		box.y2 = dst_y + r->height;
171803b705cfSriastradh
171903b705cfSriastradh		ok = sna_write_boxes(sna, dst,
172003b705cfSriastradh				     dst_priv->gpu_bo, 0, 0,
172103b705cfSriastradh				     data, pitch, src_x, src_y,
172203b705cfSriastradh				     &box, 1);
172303b705cfSriastradh		assert(ok);
172403b705cfSriastradh		(void)ok;
172503b705cfSriastradh	}
172603b705cfSriastradh}
172703b705cfSriastradh
172803b705cfSriastradhfastcall static void blt_put_composite_box(struct sna *sna,
172903b705cfSriastradh					   const struct sna_composite_op *op,
173003b705cfSriastradh					   const BoxRec *box)
173103b705cfSriastradh{
173203b705cfSriastradh	PixmapPtr src = op->u.blt.src_pixmap;
173303b705cfSriastradh	struct sna_pixmap *dst_priv = sna_pixmap(op->dst.pixmap);
173403b705cfSriastradh
173503b705cfSriastradh	DBG(("%s: src=(%d, %d), dst=(%d, %d)\n", __FUNCTION__,
173603b705cfSriastradh	     op->u.blt.sx, op->u.blt.sy,
173703b705cfSriastradh	     op->dst.x, op->dst.y));
173803b705cfSriastradh
173903b705cfSriastradh	if (!dst_priv->pinned &&
174003b705cfSriastradh	    box->x2 - box->x1 == op->dst.width &&
174103b705cfSriastradh	    box->y2 - box->y1 == op->dst.height) {
174203b705cfSriastradh		int pitch = src->devKind;
174303b705cfSriastradh		int bpp = src->drawable.bitsPerPixel / 8;
174403b705cfSriastradh		char *data = src->devPrivate.ptr;
174503b705cfSriastradh
174603b705cfSriastradh		data += (box->y1 + op->u.blt.sy) * pitch;
174703b705cfSriastradh		data += (box->x1 + op->u.blt.sx) * bpp;
174803b705cfSriastradh
174903b705cfSriastradh		sna_replace(sna, op->dst.pixmap, &dst_priv->gpu_bo,
175003b705cfSriastradh			    data, pitch);
175103b705cfSriastradh	} else {
175203b705cfSriastradh		bool ok;
175303b705cfSriastradh
175403b705cfSriastradh		ok = sna_write_boxes(sna, op->dst.pixmap,
175503b705cfSriastradh				     op->dst.bo, op->dst.x, op->dst.y,
175603b705cfSriastradh				     src->devPrivate.ptr,
175703b705cfSriastradh				     src->devKind,
175803b705cfSriastradh				     op->u.blt.sx, op->u.blt.sy,
175903b705cfSriastradh				     box, 1);
176003b705cfSriastradh		assert(ok);
176103b705cfSriastradh		(void)ok;
176203b705cfSriastradh	}
176303b705cfSriastradh}
176403b705cfSriastradh
176503b705cfSriastradhstatic void blt_put_composite_boxes(struct sna *sna,
176603b705cfSriastradh				    const struct sna_composite_op *op,
176703b705cfSriastradh				    const BoxRec *box, int n)
176803b705cfSriastradh{
176903b705cfSriastradh	PixmapPtr src = op->u.blt.src_pixmap;
177003b705cfSriastradh	struct sna_pixmap *dst_priv = sna_pixmap(op->dst.pixmap);
177103b705cfSriastradh
177203b705cfSriastradh	DBG(("%s: src=(%d, %d), dst=(%d, %d), [(%d, %d), (%d, %d) x %d]\n", __FUNCTION__,
177303b705cfSriastradh	     op->u.blt.sx, op->u.blt.sy,
177403b705cfSriastradh	     op->dst.x, op->dst.y,
177503b705cfSriastradh	     box->x1, box->y1, box->x2, box->y2, n));
177603b705cfSriastradh
177703b705cfSriastradh	if (n == 1 && !dst_priv->pinned &&
177803b705cfSriastradh	    box->x2 - box->x1 == op->dst.width &&
177903b705cfSriastradh	    box->y2 - box->y1 == op->dst.height) {
178003b705cfSriastradh		int pitch = src->devKind;
178103b705cfSriastradh		int bpp = src->drawable.bitsPerPixel / 8;
178203b705cfSriastradh		char *data = src->devPrivate.ptr;
178303b705cfSriastradh
178403b705cfSriastradh		data += (box->y1 + op->u.blt.sy) * pitch;
178503b705cfSriastradh		data += (box->x1 + op->u.blt.sx) * bpp;
178603b705cfSriastradh
178703b705cfSriastradh		sna_replace(sna, op->dst.pixmap, &dst_priv->gpu_bo,
178803b705cfSriastradh			    data, pitch);
178903b705cfSriastradh	} else {
179003b705cfSriastradh		bool ok;
179103b705cfSriastradh
179203b705cfSriastradh		ok = sna_write_boxes(sna, op->dst.pixmap,
179303b705cfSriastradh				     op->dst.bo, op->dst.x, op->dst.y,
179403b705cfSriastradh				     src->devPrivate.ptr,
179503b705cfSriastradh				     src->devKind,
179603b705cfSriastradh				     op->u.blt.sx, op->u.blt.sy,
179703b705cfSriastradh				     box, n);
179803b705cfSriastradh		assert(ok);
179903b705cfSriastradh		(void)ok;
180003b705cfSriastradh	}
180103b705cfSriastradh}
180203b705cfSriastradh
180303b705cfSriastradhfastcall static void
180403b705cfSriastradhblt_put_composite_with_alpha(struct sna *sna,
180503b705cfSriastradh			     const struct sna_composite_op *op,
180603b705cfSriastradh			     const struct sna_composite_rectangles *r)
180703b705cfSriastradh{
180803b705cfSriastradh	PixmapPtr dst = op->dst.pixmap;
180903b705cfSriastradh	PixmapPtr src = op->u.blt.src_pixmap;
181003b705cfSriastradh	struct sna_pixmap *dst_priv = sna_pixmap(dst);
181103b705cfSriastradh	int pitch = src->devKind;
181203b705cfSriastradh	char *data = src->devPrivate.ptr;
181303b705cfSriastradh
181403b705cfSriastradh	int16_t dst_x = r->dst.x + op->dst.x;
181503b705cfSriastradh	int16_t dst_y = r->dst.y + op->dst.y;
181603b705cfSriastradh	int16_t src_x = r->src.x + op->u.blt.sx;
181703b705cfSriastradh	int16_t src_y = r->src.y + op->u.blt.sy;
181803b705cfSriastradh
181903b705cfSriastradh	if (!dst_priv->pinned &&
182003b705cfSriastradh	    dst_x <= 0 && dst_y <= 0 &&
182103b705cfSriastradh	    dst_x + r->width >= op->dst.width &&
182203b705cfSriastradh	    dst_y + r->height >= op->dst.height) {
182303b705cfSriastradh		int bpp = dst->drawable.bitsPerPixel / 8;
182403b705cfSriastradh
182503b705cfSriastradh		data += (src_x - dst_x) * bpp;
182603b705cfSriastradh		data += (src_y - dst_y) * pitch;
182703b705cfSriastradh
182803b705cfSriastradh		dst_priv->gpu_bo =
182903b705cfSriastradh			sna_replace__xor(sna, op->dst.pixmap, dst_priv->gpu_bo,
183003b705cfSriastradh					 data, pitch,
183103b705cfSriastradh					 0xffffffff, op->u.blt.pixel);
183203b705cfSriastradh	} else {
183303b705cfSriastradh		BoxRec box;
183403b705cfSriastradh
183503b705cfSriastradh		box.x1 = dst_x;
183603b705cfSriastradh		box.y1 = dst_y;
183703b705cfSriastradh		box.x2 = dst_x + r->width;
183803b705cfSriastradh		box.y2 = dst_y + r->height;
183903b705cfSriastradh
184003b705cfSriastradh		sna_write_boxes__xor(sna, dst,
184103b705cfSriastradh				     dst_priv->gpu_bo, 0, 0,
184203b705cfSriastradh				     data, pitch, src_x, src_y,
184303b705cfSriastradh				     &box, 1,
184403b705cfSriastradh				     0xffffffff, op->u.blt.pixel);
184503b705cfSriastradh	}
184603b705cfSriastradh}
184703b705cfSriastradh
184803b705cfSriastradhfastcall static void
184903b705cfSriastradhblt_put_composite_box_with_alpha(struct sna *sna,
185003b705cfSriastradh				 const struct sna_composite_op *op,
185103b705cfSriastradh				 const BoxRec *box)
185203b705cfSriastradh{
185303b705cfSriastradh	PixmapPtr src = op->u.blt.src_pixmap;
185403b705cfSriastradh	struct sna_pixmap *dst_priv = sna_pixmap(op->dst.pixmap);
185503b705cfSriastradh
185603b705cfSriastradh	DBG(("%s: src=(%d, %d), dst=(%d, %d)\n", __FUNCTION__,
185703b705cfSriastradh	     op->u.blt.sx, op->u.blt.sy,
185803b705cfSriastradh	     op->dst.x, op->dst.y));
185903b705cfSriastradh
186003b705cfSriastradh	if (!dst_priv->pinned &&
186103b705cfSriastradh	    box->x2 - box->x1 == op->dst.width &&
186203b705cfSriastradh	    box->y2 - box->y1 == op->dst.height) {
186303b705cfSriastradh		int pitch = src->devKind;
186403b705cfSriastradh		int bpp = src->drawable.bitsPerPixel / 8;
186503b705cfSriastradh		char *data = src->devPrivate.ptr;
186603b705cfSriastradh
186703b705cfSriastradh		data += (box->y1 + op->u.blt.sy) * pitch;
186803b705cfSriastradh		data += (box->x1 + op->u.blt.sx) * bpp;
186903b705cfSriastradh
187003b705cfSriastradh		dst_priv->gpu_bo =
187103b705cfSriastradh			sna_replace__xor(sna, op->dst.pixmap, op->dst.bo,
187203b705cfSriastradh					 data, pitch,
187303b705cfSriastradh					 0xffffffff, op->u.blt.pixel);
187403b705cfSriastradh	} else {
187503b705cfSriastradh		sna_write_boxes__xor(sna, op->dst.pixmap,
187603b705cfSriastradh				     op->dst.bo, op->dst.x, op->dst.y,
187703b705cfSriastradh				     src->devPrivate.ptr,
187803b705cfSriastradh				     src->devKind,
187903b705cfSriastradh				     op->u.blt.sx, op->u.blt.sy,
188003b705cfSriastradh				     box, 1,
188103b705cfSriastradh				     0xffffffff, op->u.blt.pixel);
188203b705cfSriastradh	}
188303b705cfSriastradh}
188403b705cfSriastradh
188503b705cfSriastradhstatic void
188603b705cfSriastradhblt_put_composite_boxes_with_alpha(struct sna *sna,
188703b705cfSriastradh				   const struct sna_composite_op *op,
188803b705cfSriastradh				   const BoxRec *box, int n)
188903b705cfSriastradh{
189003b705cfSriastradh	PixmapPtr src = op->u.blt.src_pixmap;
189103b705cfSriastradh	struct sna_pixmap *dst_priv = sna_pixmap(op->dst.pixmap);
189203b705cfSriastradh
189303b705cfSriastradh	DBG(("%s: src=(%d, %d), dst=(%d, %d), [(%d, %d), (%d, %d) x %d]\n", __FUNCTION__,
189403b705cfSriastradh	     op->u.blt.sx, op->u.blt.sy,
189503b705cfSriastradh	     op->dst.x, op->dst.y,
189603b705cfSriastradh	     box->x1, box->y1, box->x2, box->y2, n));
189703b705cfSriastradh
189803b705cfSriastradh	if (n == 1 && !dst_priv->pinned &&
189903b705cfSriastradh	    box->x2 - box->x1 == op->dst.width &&
190003b705cfSriastradh	    box->y2 - box->y1 == op->dst.height) {
190103b705cfSriastradh		int pitch = src->devKind;
190203b705cfSriastradh		int bpp = src->drawable.bitsPerPixel / 8;
190303b705cfSriastradh		char *data = src->devPrivate.ptr;
190403b705cfSriastradh
190503b705cfSriastradh		data += (box->y1 + op->u.blt.sy) * pitch;
190603b705cfSriastradh		data += (box->x1 + op->u.blt.sx) * bpp;
190703b705cfSriastradh
190803b705cfSriastradh		dst_priv->gpu_bo =
190903b705cfSriastradh			sna_replace__xor(sna, op->dst.pixmap, op->dst.bo,
191003b705cfSriastradh					 data, pitch,
191103b705cfSriastradh					 0xffffffff, op->u.blt.pixel);
191203b705cfSriastradh	} else {
191303b705cfSriastradh		sna_write_boxes__xor(sna, op->dst.pixmap,
191403b705cfSriastradh				     op->dst.bo, op->dst.x, op->dst.y,
191503b705cfSriastradh				     src->devPrivate.ptr,
191603b705cfSriastradh				     src->devKind,
191703b705cfSriastradh				     op->u.blt.sx, op->u.blt.sy,
191803b705cfSriastradh				     box, n,
191903b705cfSriastradh				     0xffffffff, op->u.blt.pixel);
192003b705cfSriastradh	}
192103b705cfSriastradh}
192203b705cfSriastradh
192303b705cfSriastradhstatic bool
192403b705cfSriastradhprepare_blt_put(struct sna *sna,
192503b705cfSriastradh		struct sna_composite_op *op,
192603b705cfSriastradh		uint32_t alpha_fixup)
192703b705cfSriastradh{
192803b705cfSriastradh	DBG(("%s\n", __FUNCTION__));
192903b705cfSriastradh
193003b705cfSriastradh	if (op->dst.bo) {
193103b705cfSriastradh		assert(op->dst.bo == sna_pixmap(op->dst.pixmap)->gpu_bo);
193203b705cfSriastradh		if (alpha_fixup) {
193303b705cfSriastradh			op->u.blt.pixel = alpha_fixup;
193403b705cfSriastradh			op->blt   = blt_put_composite_with_alpha;
193503b705cfSriastradh			op->box   = blt_put_composite_box_with_alpha;
193603b705cfSriastradh			op->boxes = blt_put_composite_boxes_with_alpha;
193703b705cfSriastradh		} else {
193803b705cfSriastradh			op->blt   = blt_put_composite;
193903b705cfSriastradh			op->box   = blt_put_composite_box;
194003b705cfSriastradh			op->boxes = blt_put_composite_boxes;
194103b705cfSriastradh		}
194203b705cfSriastradh	} else {
194303b705cfSriastradh		if (alpha_fixup) {
194403b705cfSriastradh			op->u.blt.pixel = alpha_fixup;
194503b705cfSriastradh			op->blt   = blt_put_composite_with_alpha__cpu;
194603b705cfSriastradh			op->box   = blt_put_composite_box_with_alpha__cpu;
194703b705cfSriastradh			op->boxes = blt_put_composite_boxes_with_alpha__cpu;
194803b705cfSriastradh		} else {
194903b705cfSriastradh			op->blt   = blt_put_composite__cpu;
195003b705cfSriastradh			op->box   = blt_put_composite_box__cpu;
195103b705cfSriastradh			op->boxes = blt_put_composite_boxes__cpu;
195203b705cfSriastradh		}
195303b705cfSriastradh	}
195403b705cfSriastradh	op->done = nop_done;
195503b705cfSriastradh
195603b705cfSriastradh	return true;
195703b705cfSriastradh}
195803b705cfSriastradh
195903b705cfSriastradhstatic bool
196003b705cfSriastradhis_clear(PixmapPtr pixmap)
196103b705cfSriastradh{
196203b705cfSriastradh	struct sna_pixmap *priv = sna_pixmap(pixmap);
196303b705cfSriastradh	return priv && priv->clear;
196403b705cfSriastradh}
196503b705cfSriastradh
196603b705cfSriastradhbool
196703b705cfSriastradhsna_blt_composite(struct sna *sna,
196803b705cfSriastradh		  uint32_t op,
196903b705cfSriastradh		  PicturePtr src,
197003b705cfSriastradh		  PicturePtr dst,
197103b705cfSriastradh		  int16_t x, int16_t y,
197203b705cfSriastradh		  int16_t dst_x, int16_t dst_y,
197303b705cfSriastradh		  int16_t width, int16_t height,
197403b705cfSriastradh		  struct sna_composite_op *tmp,
197503b705cfSriastradh		  bool fallback)
197603b705cfSriastradh{
197703b705cfSriastradh	PictFormat src_format = src->format;
197803b705cfSriastradh	PixmapPtr src_pixmap;
197903b705cfSriastradh	struct kgem_bo *bo;
198003b705cfSriastradh	int16_t tx, ty;
198103b705cfSriastradh	BoxRec dst_box, src_box;
198203b705cfSriastradh	uint32_t alpha_fixup;
198303b705cfSriastradh	uint32_t color, hint;
198403b705cfSriastradh	bool was_clear;
198503b705cfSriastradh	bool ret;
198603b705cfSriastradh
198703b705cfSriastradh#if DEBUG_NO_BLT || NO_BLT_COMPOSITE
198803b705cfSriastradh	return false;
198903b705cfSriastradh#endif
199003b705cfSriastradh
199103b705cfSriastradh	DBG(("%s (%d, %d), (%d, %d), %dx%d\n",
199203b705cfSriastradh	     __FUNCTION__, x, y, dst_x, dst_y, width, height));
199303b705cfSriastradh
199403b705cfSriastradh	switch (dst->pDrawable->bitsPerPixel) {
199503b705cfSriastradh	case 8:
199603b705cfSriastradh	case 16:
199703b705cfSriastradh	case 32:
199803b705cfSriastradh		break;
199903b705cfSriastradh	default:
200003b705cfSriastradh		DBG(("%s: unhandled bpp: %d\n", __FUNCTION__,
200103b705cfSriastradh		     dst->pDrawable->bitsPerPixel));
200203b705cfSriastradh		return false;
200303b705cfSriastradh	}
200403b705cfSriastradh
200503b705cfSriastradh	was_clear = sna_drawable_is_clear(dst->pDrawable);
200603b705cfSriastradh	tmp->dst.pixmap = get_drawable_pixmap(dst->pDrawable);
200703b705cfSriastradh
200803b705cfSriastradh	if (width | height) {
200903b705cfSriastradh		dst_box.x1 = dst_x;
201003b705cfSriastradh		dst_box.x2 = bound(dst_x, width);
201103b705cfSriastradh		dst_box.y1 = dst_y;
201203b705cfSriastradh		dst_box.y2 = bound(dst_y, height);
201303b705cfSriastradh	} else
201403b705cfSriastradh		sna_render_picture_extents(dst, &dst_box);
201503b705cfSriastradh
201603b705cfSriastradh	tmp->dst.format = dst->format;
201703b705cfSriastradh	tmp->dst.width = tmp->dst.pixmap->drawable.width;
201803b705cfSriastradh	tmp->dst.height = tmp->dst.pixmap->drawable.height;
201903b705cfSriastradh	get_drawable_deltas(dst->pDrawable, tmp->dst.pixmap,
202003b705cfSriastradh			    &tmp->dst.x, &tmp->dst.y);
202103b705cfSriastradh
202203b705cfSriastradh	if (op == PictOpClear) {
202303b705cfSriastradhclear:
202403b705cfSriastradh		if (was_clear)
202503b705cfSriastradh			return prepare_blt_nop(sna, tmp);
202603b705cfSriastradh
202703b705cfSriastradh		hint = 0;
202803b705cfSriastradh		if (can_render(sna)) {
202903b705cfSriastradh			hint |= PREFER_GPU;
203003b705cfSriastradh			if (dst->pCompositeClip->data == NULL && (width | height)) {
203103b705cfSriastradh				hint |= IGNORE_CPU;
203203b705cfSriastradh				if (width == tmp->dst.pixmap->drawable.width &&
203303b705cfSriastradh				    height == tmp->dst.pixmap->drawable.height)
203403b705cfSriastradh					hint |= REPLACES;
203503b705cfSriastradh			}
203603b705cfSriastradh		}
203703b705cfSriastradh		tmp->dst.bo = sna_drawable_use_bo(dst->pDrawable, hint,
203803b705cfSriastradh						  &dst_box, &tmp->damage);
203903b705cfSriastradh		if (tmp->dst.bo && !kgem_bo_can_blt(&sna->kgem, tmp->dst.bo)) {
204003b705cfSriastradh			DBG(("%s: can not blit to dst, tiling? %d, pitch? %d\n",
204103b705cfSriastradh			     __FUNCTION__, tmp->dst.bo->tiling, tmp->dst.bo->pitch));
204203b705cfSriastradh			return false;
204303b705cfSriastradh		}
204403b705cfSriastradh
204503b705cfSriastradh		if (!tmp->dst.bo) {
204603b705cfSriastradh			RegionRec region;
204703b705cfSriastradh
204803b705cfSriastradh			region.extents = dst_box;
204903b705cfSriastradh			region.data = NULL;
205003b705cfSriastradh
205103b705cfSriastradh			if (!sna_drawable_move_region_to_cpu(dst->pDrawable, &region,
205203b705cfSriastradh							     MOVE_INPLACE_HINT | MOVE_WRITE))
205303b705cfSriastradh				return false;
205403b705cfSriastradh		} else if (hint & REPLACES)
205503b705cfSriastradh			kgem_bo_undo(&sna->kgem, tmp->dst.bo);
205603b705cfSriastradh
205703b705cfSriastradh		return prepare_blt_clear(sna, tmp);
205803b705cfSriastradh	}
205903b705cfSriastradh
206003b705cfSriastradh	if (is_solid(src)) {
206103b705cfSriastradh		if (op == PictOpOver && is_opaque_solid(src))
206203b705cfSriastradh			op = PictOpSrc;
206303b705cfSriastradh		if (op == PictOpAdd && is_white(src))
206403b705cfSriastradh			op = PictOpSrc;
206503b705cfSriastradh		if (was_clear && (op == PictOpAdd || op == PictOpOver))
206603b705cfSriastradh			op = PictOpSrc;
206703b705cfSriastradh		if (op == PictOpOutReverse && is_opaque_solid(src))
206803b705cfSriastradh			goto clear;
206903b705cfSriastradh
207003b705cfSriastradh		if (op != PictOpSrc) {
207103b705cfSriastradh			DBG(("%s: unsupported op [%d] for blitting\n",
207203b705cfSriastradh			     __FUNCTION__, op));
207303b705cfSriastradh			return false;
207403b705cfSriastradh		}
207503b705cfSriastradh
207603b705cfSriastradh		color = get_solid_color(src, tmp->dst.format);
207703b705cfSriastradhfill:
207803b705cfSriastradh		if (color == 0)
207903b705cfSriastradh			goto clear;
208003b705cfSriastradh
208103b705cfSriastradh		hint = 0;
208203b705cfSriastradh		if (can_render(sna)) {
208303b705cfSriastradh			hint |= PREFER_GPU;
208403b705cfSriastradh			if (dst->pCompositeClip->data == NULL && (width | height))
208503b705cfSriastradh				hint |= IGNORE_CPU;
208603b705cfSriastradh				if (width == tmp->dst.pixmap->drawable.width &&
208703b705cfSriastradh				    height == tmp->dst.pixmap->drawable.height)
208803b705cfSriastradh					hint |= REPLACES;
208903b705cfSriastradh		}
209003b705cfSriastradh		tmp->dst.bo = sna_drawable_use_bo(dst->pDrawable, hint,
209103b705cfSriastradh						  &dst_box, &tmp->damage);
209203b705cfSriastradh		if (tmp->dst.bo && !kgem_bo_can_blt(&sna->kgem, tmp->dst.bo)) {
209303b705cfSriastradh			DBG(("%s: can not blit to dst, tiling? %d, pitch? %d\n",
209403b705cfSriastradh			     __FUNCTION__, tmp->dst.bo->tiling, tmp->dst.bo->pitch));
209503b705cfSriastradh			return false;
209603b705cfSriastradh		}
209703b705cfSriastradh
209803b705cfSriastradh		if (!tmp->dst.bo) {
209903b705cfSriastradh			RegionRec region;
210003b705cfSriastradh
210103b705cfSriastradh			region.extents = dst_box;
210203b705cfSriastradh			region.data = NULL;
210303b705cfSriastradh
210403b705cfSriastradh			if (!sna_drawable_move_region_to_cpu(dst->pDrawable, &region,
210503b705cfSriastradh							MOVE_INPLACE_HINT | MOVE_WRITE))
210603b705cfSriastradh				return false;
210703b705cfSriastradh		} else if (hint & REPLACES)
210803b705cfSriastradh			kgem_bo_undo(&sna->kgem, tmp->dst.bo);
210903b705cfSriastradh
211003b705cfSriastradh		return prepare_blt_fill(sna, tmp, color);
211103b705cfSriastradh	}
211203b705cfSriastradh
211303b705cfSriastradh	if (!src->pDrawable) {
211403b705cfSriastradh		DBG(("%s: unsupported procedural source\n",
211503b705cfSriastradh		     __FUNCTION__));
211603b705cfSriastradh		return false;
211703b705cfSriastradh	}
211803b705cfSriastradh
211903b705cfSriastradh	if (src->filter == PictFilterConvolution) {
212003b705cfSriastradh		DBG(("%s: convolutions filters not handled\n",
212103b705cfSriastradh		     __FUNCTION__));
212203b705cfSriastradh		return false;
212303b705cfSriastradh	}
212403b705cfSriastradh
212503b705cfSriastradh	if (op == PictOpOver && PICT_FORMAT_A(src_format) == 0)
212603b705cfSriastradh		op = PictOpSrc;
212703b705cfSriastradh
212803b705cfSriastradh	if (op != PictOpSrc) {
212903b705cfSriastradh		DBG(("%s: unsupported op [%d] for blitting\n",
213003b705cfSriastradh		     __FUNCTION__, op));
213103b705cfSriastradh		return false;
213203b705cfSriastradh	}
213303b705cfSriastradh
213403b705cfSriastradh	if (!sna_transform_is_integer_translation(src->transform, &tx, &ty)) {
213503b705cfSriastradh		DBG(("%s: source transform is not an integer translation\n",
213603b705cfSriastradh		     __FUNCTION__));
213703b705cfSriastradh		return false;
213803b705cfSriastradh	}
213903b705cfSriastradh	x += tx;
214003b705cfSriastradh	y += ty;
214103b705cfSriastradh
214203b705cfSriastradh	if ((x >= src->pDrawable->width ||
214303b705cfSriastradh	     y >= src->pDrawable->height ||
214403b705cfSriastradh	     x + width  <= 0 ||
214503b705cfSriastradh	     y + height <= 0) &&
214603b705cfSriastradh	    (!src->repeat || src->repeatType == RepeatNone)) {
214703b705cfSriastradh		DBG(("%s: source is outside of valid area, converting to clear\n",
214803b705cfSriastradh		     __FUNCTION__));
214903b705cfSriastradh		goto clear;
215003b705cfSriastradh	}
215103b705cfSriastradh
215203b705cfSriastradh	src_pixmap = get_drawable_pixmap(src->pDrawable);
215303b705cfSriastradh	if (is_clear(src_pixmap)) {
215403b705cfSriastradh		color = color_convert(sna_pixmap(src_pixmap)->clear_color,
215503b705cfSriastradh				      src->format, tmp->dst.format);
215603b705cfSriastradh		goto fill;
215703b705cfSriastradh	}
215803b705cfSriastradh
215903b705cfSriastradh	alpha_fixup = 0;
216003b705cfSriastradh	if (!(dst->format == src_format ||
216103b705cfSriastradh	      dst->format == alphaless(src_format) ||
216203b705cfSriastradh	      (alphaless(dst->format) == alphaless(src_format) &&
216303b705cfSriastradh	       sna_get_pixel_from_rgba(&alpha_fixup,
216403b705cfSriastradh				       0, 0, 0, 0xffff,
216503b705cfSriastradh				       dst->format)))) {
216603b705cfSriastradh		DBG(("%s: incompatible src/dst formats src=%08x, dst=%08x\n",
216703b705cfSriastradh		     __FUNCTION__, (unsigned)src_format, dst->format));
216803b705cfSriastradh		return false;
216903b705cfSriastradh	}
217003b705cfSriastradh
217103b705cfSriastradh	/* XXX tiling? fixup extend none? */
217203b705cfSriastradh	if (x < 0 || y < 0 ||
217303b705cfSriastradh	    x + width  > src->pDrawable->width ||
217403b705cfSriastradh	    y + height > src->pDrawable->height) {
217503b705cfSriastradh		DBG(("%s: source extends outside (%d, %d), (%d, %d) of valid drawable %dx%d, repeat=%d\n",
217603b705cfSriastradh		     __FUNCTION__,
217703b705cfSriastradh		     x, y, x+width, y+width, src->pDrawable->width, src->pDrawable->height, src->repeatType));
217803b705cfSriastradh		if (src->repeat && src->repeatType == RepeatNormal) {
217903b705cfSriastradh			x = x % src->pDrawable->width;
218003b705cfSriastradh			y = y % src->pDrawable->height;
218103b705cfSriastradh			if (x < 0)
218203b705cfSriastradh				x += src->pDrawable->width;
218303b705cfSriastradh			if (y < 0)
218403b705cfSriastradh				y += src->pDrawable->height;
218503b705cfSriastradh			if (x + width  > src->pDrawable->width ||
218603b705cfSriastradh			    y + height > src->pDrawable->height)
218703b705cfSriastradh				return false;
218803b705cfSriastradh		} else
218903b705cfSriastradh			return false;
219003b705cfSriastradh	}
219103b705cfSriastradh
219203b705cfSriastradh	get_drawable_deltas(src->pDrawable, src_pixmap, &tx, &ty);
219303b705cfSriastradh	x += tx + src->pDrawable->x;
219403b705cfSriastradh	y += ty + src->pDrawable->y;
219503b705cfSriastradh	if (x < 0 || y < 0 ||
219603b705cfSriastradh	    x + width  > src_pixmap->drawable.width ||
219703b705cfSriastradh	    y + height > src_pixmap->drawable.height) {
219803b705cfSriastradh		DBG(("%s: source extends outside (%d, %d), (%d, %d) of valid pixmap %dx%d\n",
219903b705cfSriastradh		     __FUNCTION__,
220003b705cfSriastradh		     x, y, x+width, y+width, src_pixmap->drawable.width, src_pixmap->drawable.height));
220103b705cfSriastradh		return false;
220203b705cfSriastradh	}
220303b705cfSriastradh
220403b705cfSriastradh	tmp->u.blt.src_pixmap = src_pixmap;
220503b705cfSriastradh	tmp->u.blt.sx = x - dst_x;
220603b705cfSriastradh	tmp->u.blt.sy = y - dst_y;
220703b705cfSriastradh	DBG(("%s: blt dst offset (%d, %d), source offset (%d, %d), with alpha fixup? %x\n",
220803b705cfSriastradh	     __FUNCTION__,
220903b705cfSriastradh	     tmp->dst.x, tmp->dst.y, tmp->u.blt.sx, tmp->u.blt.sy, alpha_fixup));
221003b705cfSriastradh
221103b705cfSriastradh	src_box.x1 = x;
221203b705cfSriastradh	src_box.y1 = y;
221303b705cfSriastradh	src_box.x2 = x + width;
221403b705cfSriastradh	src_box.y2 = y + height;
221503b705cfSriastradh	bo = __sna_render_pixmap_bo(sna, src_pixmap, &src_box, true);
221603b705cfSriastradh	if (bo && !kgem_bo_can_blt(&sna->kgem, bo)) {
221703b705cfSriastradh		DBG(("%s: can not blit from src size=%dx%d, tiling? %d, pitch? %d\n",
221803b705cfSriastradh		     __FUNCTION__,
221903b705cfSriastradh		     src_pixmap->drawable.width  < sna->render.max_3d_size,
222003b705cfSriastradh		     src_pixmap->drawable.height < sna->render.max_3d_size,
222103b705cfSriastradh		     bo->tiling, bo->pitch));
222203b705cfSriastradh
222303b705cfSriastradh		if (src_pixmap->drawable.width  <= sna->render.max_3d_size &&
222403b705cfSriastradh		    src_pixmap->drawable.height <= sna->render.max_3d_size &&
222503b705cfSriastradh		    bo->pitch <= sna->render.max_3d_pitch &&
222603b705cfSriastradh		    !fallback)
222703b705cfSriastradh		{
222803b705cfSriastradh			return false;
222903b705cfSriastradh		}
223003b705cfSriastradh
223103b705cfSriastradh		bo = NULL;
223203b705cfSriastradh	}
223303b705cfSriastradh
223403b705cfSriastradh	hint = 0;
223503b705cfSriastradh	if (bo || can_render(sna)) {
223603b705cfSriastradh		hint |= PREFER_GPU;
223703b705cfSriastradh		if (dst->pCompositeClip->data == NULL && (width | height)) {
223803b705cfSriastradh			hint |= IGNORE_CPU;
223903b705cfSriastradh			if (width == tmp->dst.pixmap->drawable.width &&
224003b705cfSriastradh			    height == tmp->dst.pixmap->drawable.height)
224103b705cfSriastradh				hint |= REPLACES;
224203b705cfSriastradh		}
224303b705cfSriastradh		if (bo)
224403b705cfSriastradh			hint |= FORCE_GPU;
224503b705cfSriastradh	}
224603b705cfSriastradh	tmp->dst.bo = sna_drawable_use_bo(dst->pDrawable, hint,
224703b705cfSriastradh					  &dst_box, &tmp->damage);
224803b705cfSriastradh
224903b705cfSriastradh	if (hint & REPLACES)
225003b705cfSriastradh		kgem_bo_undo(&sna->kgem, tmp->dst.bo);
225103b705cfSriastradh
225203b705cfSriastradh	ret = false;
225303b705cfSriastradh	if (bo) {
225403b705cfSriastradh		if (!tmp->dst.bo) {
225503b705cfSriastradh			DBG(("%s: fallback -- unaccelerated read back\n",
225603b705cfSriastradh			     __FUNCTION__));
225703b705cfSriastradh			if (fallback || !kgem_bo_is_busy(bo))
225803b705cfSriastradh				goto put;
225903b705cfSriastradh		} else if (bo->snoop && tmp->dst.bo->snoop) {
226003b705cfSriastradh			DBG(("%s: fallback -- can not copy between snooped bo\n",
226103b705cfSriastradh			     __FUNCTION__));
226203b705cfSriastradh			goto put;
226303b705cfSriastradh		} else if (!kgem_bo_can_blt(&sna->kgem, tmp->dst.bo)) {
226403b705cfSriastradh			DBG(("%s: fallback -- unaccelerated upload\n",
226503b705cfSriastradh			     __FUNCTION__));
226603b705cfSriastradh			if (fallback || !kgem_bo_is_busy(bo))
226703b705cfSriastradh				goto put;
226803b705cfSriastradh		} else {
226903b705cfSriastradh			ret = prepare_blt_copy(sna, tmp, bo, alpha_fixup);
227003b705cfSriastradh			if (fallback && !ret)
227103b705cfSriastradh				goto put;
227203b705cfSriastradh		}
227303b705cfSriastradh	} else {
227403b705cfSriastradh		RegionRec region;
227503b705cfSriastradh
227603b705cfSriastradhput:
227703b705cfSriastradh		if (tmp->dst.bo == sna_pixmap(tmp->dst.pixmap)->cpu_bo) {
227803b705cfSriastradh			tmp->dst.bo = NULL;
227903b705cfSriastradh			tmp->damage = NULL;
228003b705cfSriastradh		}
228103b705cfSriastradh
228203b705cfSriastradh		if (tmp->dst.bo == NULL) {
228303b705cfSriastradh			hint = MOVE_INPLACE_HINT | MOVE_WRITE;
228403b705cfSriastradh			if (dst->pCompositeClip->data)
228503b705cfSriastradh				hint |= MOVE_READ;
228603b705cfSriastradh
228703b705cfSriastradh			region.extents = dst_box;
228803b705cfSriastradh			region.data = NULL;
228903b705cfSriastradh			if (!sna_drawable_move_region_to_cpu(dst->pDrawable,
229003b705cfSriastradh							     &region, hint))
229103b705cfSriastradh				return false;
229203b705cfSriastradh
229303b705cfSriastradh			assert(tmp->damage == NULL);
229403b705cfSriastradh		}
229503b705cfSriastradh
229603b705cfSriastradh		region.extents = src_box;
229703b705cfSriastradh		region.data = NULL;
229803b705cfSriastradh		if (!sna_drawable_move_region_to_cpu(&src_pixmap->drawable,
229903b705cfSriastradh						     &region, MOVE_READ))
230003b705cfSriastradh			return false;
230103b705cfSriastradh
230203b705cfSriastradh		ret = prepare_blt_put(sna, tmp, alpha_fixup);
230303b705cfSriastradh	}
230403b705cfSriastradh
230503b705cfSriastradh	return ret;
230603b705cfSriastradh}
230703b705cfSriastradh
230803b705cfSriastradhstatic void convert_done(struct sna *sna, const struct sna_composite_op *op)
230903b705cfSriastradh{
231003b705cfSriastradh	struct kgem *kgem = &sna->kgem;
231103b705cfSriastradh
231203b705cfSriastradh	assert(kgem->nbatch <= KGEM_BATCH_SIZE(kgem));
231303b705cfSriastradh	if (kgem->nexec > 1 && __kgem_ring_empty(kgem))
231403b705cfSriastradh		_kgem_submit(kgem);
231503b705cfSriastradh
231603b705cfSriastradh	kgem_bo_destroy(kgem, op->src.bo);
231703b705cfSriastradh	sna_render_composite_redirect_done(sna, op);
231803b705cfSriastradh}
231903b705cfSriastradh
232003b705cfSriastradhstatic void gen6_convert_done(struct sna *sna, const struct sna_composite_op *op)
232103b705cfSriastradh{
232203b705cfSriastradh	struct kgem *kgem = &sna->kgem;
232303b705cfSriastradh
232403b705cfSriastradh	if (kgem_check_batch(kgem, 3)) {
232503b705cfSriastradh		uint32_t *b = kgem->batch + kgem->nbatch;
232603b705cfSriastradh		b[0] = XY_SETUP_CLIP;
232703b705cfSriastradh		b[1] = b[2] = 0;
232803b705cfSriastradh		kgem->nbatch += 3;
232903b705cfSriastradh		assert(kgem->nbatch < kgem->surface);
233003b705cfSriastradh	}
233103b705cfSriastradh
233203b705cfSriastradh	convert_done(sna, op);
233303b705cfSriastradh}
233403b705cfSriastradh
233503b705cfSriastradhbool
233603b705cfSriastradhsna_blt_composite__convert(struct sna *sna,
233703b705cfSriastradh			   int x, int y,
233803b705cfSriastradh			   int width, int height,
233903b705cfSriastradh			   struct sna_composite_op *tmp)
234003b705cfSriastradh{
234103b705cfSriastradh	uint32_t alpha_fixup;
234203b705cfSriastradh	int sx, sy;
234303b705cfSriastradh	uint8_t op;
234403b705cfSriastradh
234503b705cfSriastradh#if DEBUG_NO_BLT || NO_BLT_COMPOSITE
234603b705cfSriastradh	return false;
234703b705cfSriastradh#endif
234803b705cfSriastradh
234903b705cfSriastradh	DBG(("%s src=%d, dst=%d (redirect? %d)\n", __FUNCTION__,
235003b705cfSriastradh	     tmp->src.bo->handle, tmp->dst.bo->handle,
235103b705cfSriastradh	     tmp->redirect.real_bo ? tmp->redirect.real_bo->handle : 0));
235203b705cfSriastradh
235303b705cfSriastradh	if (!kgem_bo_can_blt(&sna->kgem, tmp->dst.bo) ||
235403b705cfSriastradh	    !kgem_bo_can_blt(&sna->kgem, tmp->src.bo)) {
235503b705cfSriastradh		DBG(("%s: cannot blt from src or to dst\n", __FUNCTION__));
235603b705cfSriastradh		return false;
235703b705cfSriastradh	}
235803b705cfSriastradh
235903b705cfSriastradh	if (tmp->src.transform) {
236003b705cfSriastradh		DBG(("%s: transforms not handled by the BLT\n", __FUNCTION__));
236103b705cfSriastradh		return false;
236203b705cfSriastradh	}
236303b705cfSriastradh
236403b705cfSriastradh	if (tmp->src.filter == PictFilterConvolution) {
236503b705cfSriastradh		DBG(("%s: convolutions filters not handled\n",
236603b705cfSriastradh		     __FUNCTION__));
236703b705cfSriastradh		return false;
236803b705cfSriastradh	}
236903b705cfSriastradh
237003b705cfSriastradh	op = tmp->op;
237103b705cfSriastradh	if (op == PictOpOver && PICT_FORMAT_A(tmp->src.pict_format) == 0)
237203b705cfSriastradh		op = PictOpSrc;
237303b705cfSriastradh	if (op != PictOpSrc) {
237403b705cfSriastradh		DBG(("%s: unsupported op [%d] for blitting\n",
237503b705cfSriastradh		     __FUNCTION__, op));
237603b705cfSriastradh		return false;
237703b705cfSriastradh	}
237803b705cfSriastradh
237903b705cfSriastradh	alpha_fixup = 0;
238003b705cfSriastradh	if (!(tmp->dst.format == tmp->src.pict_format ||
238103b705cfSriastradh	      tmp->dst.format == alphaless(tmp->src.pict_format) ||
238203b705cfSriastradh	      (alphaless(tmp->dst.format) == alphaless(tmp->src.pict_format) &&
238303b705cfSriastradh	       sna_get_pixel_from_rgba(&alpha_fixup,
238403b705cfSriastradh				       0, 0, 0, 0xffff,
238503b705cfSriastradh				       tmp->dst.format)))) {
238603b705cfSriastradh		DBG(("%s: incompatible src/dst formats src=%08x, dst=%08x\n",
238703b705cfSriastradh		     __FUNCTION__,
238803b705cfSriastradh		     (unsigned)tmp->src.pict_format,
238903b705cfSriastradh		     (unsigned)tmp->dst.format));
239003b705cfSriastradh		return false;
239103b705cfSriastradh	}
239203b705cfSriastradh
239303b705cfSriastradh	sx = tmp->src.offset[0];
239403b705cfSriastradh	sy = tmp->src.offset[1];
239503b705cfSriastradh
239603b705cfSriastradh	x += sx;
239703b705cfSriastradh	y += sy;
239803b705cfSriastradh	if (x < 0 || y < 0 ||
239903b705cfSriastradh	    x + width  > tmp->src.width ||
240003b705cfSriastradh	    y + height > tmp->src.height) {
240103b705cfSriastradh		DBG(("%s: source extends outside (%d, %d), (%d, %d) of valid drawable %dx%d\n",
240203b705cfSriastradh		     __FUNCTION__,
240303b705cfSriastradh		     x, y, x+width, y+width, tmp->src.width, tmp->src.height));
240403b705cfSriastradh		if (tmp->src.repeat == RepeatNormal) {
240503b705cfSriastradh			int xx = x % tmp->src.width;
240603b705cfSriastradh			int yy = y % tmp->src.height;
240703b705cfSriastradh			if (xx < 0)
240803b705cfSriastradh				xx += tmp->src.width;
240903b705cfSriastradh			if (yy < 0)
241003b705cfSriastradh				yy += tmp->src.height;
241103b705cfSriastradh			if (xx + width  > tmp->src.width ||
241203b705cfSriastradh			    yy + height > tmp->src.height)
241303b705cfSriastradh				return false;
241403b705cfSriastradh
241503b705cfSriastradh			sx += xx - x;
241603b705cfSriastradh			sy += yy - y;
241703b705cfSriastradh		} else
241803b705cfSriastradh			return false;
241903b705cfSriastradh	}
242003b705cfSriastradh
242103b705cfSriastradh	if (!kgem_check_many_bo_fenced(&sna->kgem, tmp->dst.bo, tmp->src.bo, NULL)) {
242203b705cfSriastradh		kgem_submit(&sna->kgem);
242303b705cfSriastradh		if (!kgem_check_many_bo_fenced(&sna->kgem,
242403b705cfSriastradh					       tmp->dst.bo, tmp->src.bo, NULL)) {
242503b705cfSriastradh			DBG(("%s: fallback -- no room in aperture\n", __FUNCTION__));
242603b705cfSriastradh			return false;
242703b705cfSriastradh		}
242803b705cfSriastradh		_kgem_set_mode(&sna->kgem, KGEM_BLT);
242903b705cfSriastradh	}
243003b705cfSriastradh
243103b705cfSriastradh	DBG(("%s: blt dst offset (%d, %d), source offset (%d, %d), with alpha fixup? %x\n",
243203b705cfSriastradh	     __FUNCTION__,
243303b705cfSriastradh	     tmp->dst.x, tmp->dst.y, tmp->u.blt.sx, tmp->u.blt.sy, alpha_fixup));
243403b705cfSriastradh
243503b705cfSriastradh	tmp->u.blt.src_pixmap = NULL;
243603b705cfSriastradh	tmp->u.blt.sx = sx;
243703b705cfSriastradh	tmp->u.blt.sy = sy;
243803b705cfSriastradh
243903b705cfSriastradh	if (alpha_fixup) {
244003b705cfSriastradh		tmp->blt   = blt_composite_copy_with_alpha;
244103b705cfSriastradh		tmp->box   = blt_composite_copy_box_with_alpha;
244203b705cfSriastradh		tmp->boxes = blt_composite_copy_boxes_with_alpha;
244303b705cfSriastradh
244403b705cfSriastradh		if (!sna_blt_alpha_fixup_init(sna, &tmp->u.blt,
244503b705cfSriastradh					      tmp->src.bo, tmp->dst.bo,
244603b705cfSriastradh					      PICT_FORMAT_BPP(tmp->src.pict_format),
244703b705cfSriastradh					      alpha_fixup))
244803b705cfSriastradh			return false;
244903b705cfSriastradh	} else {
245003b705cfSriastradh		tmp->blt   = blt_composite_copy;
245103b705cfSriastradh		tmp->box   = blt_composite_copy_box;
245203b705cfSriastradh		tmp->boxes = blt_composite_copy_boxes;
245303b705cfSriastradh		tmp->thread_boxes = blt_composite_copy_boxes__thread;
245403b705cfSriastradh
245503b705cfSriastradh		if (!sna_blt_copy_init(sna, &tmp->u.blt,
245603b705cfSriastradh				       tmp->src.bo, tmp->dst.bo,
245703b705cfSriastradh				       PICT_FORMAT_BPP(tmp->src.pict_format),
245803b705cfSriastradh				       GXcopy))
245903b705cfSriastradh			return false;
246003b705cfSriastradh	}
246103b705cfSriastradh
246203b705cfSriastradh	tmp->done = convert_done;
246303b705cfSriastradh	if (sna->kgem.gen >= 060 && tmp->src.bo == tmp->dst.bo)
246403b705cfSriastradh		tmp->done = gen6_convert_done;
246503b705cfSriastradh
246603b705cfSriastradh	return true;
246703b705cfSriastradh}
246803b705cfSriastradh
246903b705cfSriastradhstatic void sna_blt_fill_op_blt(struct sna *sna,
247003b705cfSriastradh				const struct sna_fill_op *op,
247103b705cfSriastradh				int16_t x, int16_t y,
247203b705cfSriastradh				int16_t width, int16_t height)
247303b705cfSriastradh{
247403b705cfSriastradh	sna_blt_fill_one(sna, &op->base.u.blt, x, y, width, height);
247503b705cfSriastradh}
247603b705cfSriastradh
247703b705cfSriastradhfastcall static void sna_blt_fill_op_box(struct sna *sna,
247803b705cfSriastradh					 const struct sna_fill_op *op,
247903b705cfSriastradh					 const BoxRec *box)
248003b705cfSriastradh{
248103b705cfSriastradh	_sna_blt_fill_box(sna, &op->base.u.blt, box);
248203b705cfSriastradh}
248303b705cfSriastradh
248403b705cfSriastradhfastcall static void sna_blt_fill_op_boxes(struct sna *sna,
248503b705cfSriastradh					   const struct sna_fill_op *op,
248603b705cfSriastradh					   const BoxRec *box,
248703b705cfSriastradh					   int nbox)
248803b705cfSriastradh{
248903b705cfSriastradh	_sna_blt_fill_boxes(sna, &op->base.u.blt, box, nbox);
249003b705cfSriastradh}
249103b705cfSriastradh
249203b705cfSriastradhbool sna_blt_fill(struct sna *sna, uint8_t alu,
249303b705cfSriastradh		  struct kgem_bo *bo, int bpp,
249403b705cfSriastradh		  uint32_t pixel,
249503b705cfSriastradh		  struct sna_fill_op *fill)
249603b705cfSriastradh{
249703b705cfSriastradh#if DEBUG_NO_BLT || NO_BLT_FILL
249803b705cfSriastradh	return false;
249903b705cfSriastradh#endif
250003b705cfSriastradh
250103b705cfSriastradh	DBG(("%s(alu=%d, pixel=%x, bpp=%d)\n", __FUNCTION__, alu, pixel, bpp));
250203b705cfSriastradh
250303b705cfSriastradh	if (!kgem_bo_can_blt(&sna->kgem, bo)) {
250403b705cfSriastradh		DBG(("%s: rejected due to incompatible Y-tiling\n",
250503b705cfSriastradh		     __FUNCTION__));
250603b705cfSriastradh		return false;
250703b705cfSriastradh	}
250803b705cfSriastradh
250903b705cfSriastradh	if (!sna_blt_fill_init(sna, &fill->base.u.blt,
251003b705cfSriastradh			       bo, bpp, alu, pixel))
251103b705cfSriastradh		return false;
251203b705cfSriastradh
251303b705cfSriastradh	fill->blt   = sna_blt_fill_op_blt;
251403b705cfSriastradh	fill->box   = sna_blt_fill_op_box;
251503b705cfSriastradh	fill->boxes = sna_blt_fill_op_boxes;
251603b705cfSriastradh	fill->done  =
251703b705cfSriastradh		(void (*)(struct sna *, const struct sna_fill_op *))nop_done;
251803b705cfSriastradh	return true;
251903b705cfSriastradh}
252003b705cfSriastradh
252103b705cfSriastradhstatic void sna_blt_copy_op_blt(struct sna *sna,
252203b705cfSriastradh				const struct sna_copy_op *op,
252303b705cfSriastradh				int16_t src_x, int16_t src_y,
252403b705cfSriastradh				int16_t width, int16_t height,
252503b705cfSriastradh				int16_t dst_x, int16_t dst_y)
252603b705cfSriastradh{
252703b705cfSriastradh	sna_blt_copy_one(sna, &op->base.u.blt,
252803b705cfSriastradh			 src_x, src_y,
252903b705cfSriastradh			 width, height,
253003b705cfSriastradh			 dst_x, dst_y);
253103b705cfSriastradh}
253203b705cfSriastradh
253303b705cfSriastradhbool sna_blt_copy(struct sna *sna, uint8_t alu,
253403b705cfSriastradh		  struct kgem_bo *src,
253503b705cfSriastradh		  struct kgem_bo *dst,
253603b705cfSriastradh		  int bpp,
253703b705cfSriastradh		  struct sna_copy_op *op)
253803b705cfSriastradh{
253903b705cfSriastradh#if DEBUG_NO_BLT || NO_BLT_COPY
254003b705cfSriastradh	return false;
254103b705cfSriastradh#endif
254203b705cfSriastradh
254303b705cfSriastradh	if (!kgem_bo_can_blt(&sna->kgem, src))
254403b705cfSriastradh		return false;
254503b705cfSriastradh
254603b705cfSriastradh	if (!kgem_bo_can_blt(&sna->kgem, dst))
254703b705cfSriastradh		return false;
254803b705cfSriastradh
254903b705cfSriastradh	if (!sna_blt_copy_init(sna, &op->base.u.blt,
255003b705cfSriastradh			       src, dst,
255103b705cfSriastradh			       bpp, alu))
255203b705cfSriastradh		return false;
255303b705cfSriastradh
255403b705cfSriastradh	op->blt  = sna_blt_copy_op_blt;
255503b705cfSriastradh	if (sna->kgem.gen >= 060 && src == dst)
255603b705cfSriastradh		op->done = (void (*)(struct sna *, const struct sna_copy_op *))
255703b705cfSriastradh			    gen6_blt_copy_done;
255803b705cfSriastradh	else
255903b705cfSriastradh		op->done = (void (*)(struct sna *, const struct sna_copy_op *))
256003b705cfSriastradh			    nop_done;
256103b705cfSriastradh	return true;
256203b705cfSriastradh}
256303b705cfSriastradh
256403b705cfSriastradhstatic bool sna_blt_fill_box(struct sna *sna, uint8_t alu,
256503b705cfSriastradh			     struct kgem_bo *bo, int bpp,
256603b705cfSriastradh			     uint32_t color,
256703b705cfSriastradh			     const BoxRec *box)
256803b705cfSriastradh{
256903b705cfSriastradh	struct kgem *kgem = &sna->kgem;
257003b705cfSriastradh	uint32_t br13, cmd, *b;
257103b705cfSriastradh	bool overwrites;
257203b705cfSriastradh
257303b705cfSriastradh	assert(kgem_bo_can_blt (kgem, bo));
257403b705cfSriastradh
257503b705cfSriastradh	DBG(("%s: box=((%d, %d), (%d, %d))\n", __FUNCTION__,
257603b705cfSriastradh	     box->x1, box->y1, box->x2, box->y2));
257703b705cfSriastradh
257803b705cfSriastradh	assert(box->x1 >= 0);
257903b705cfSriastradh	assert(box->y1 >= 0);
258003b705cfSriastradh
258103b705cfSriastradh	cmd = XY_COLOR_BLT;
258203b705cfSriastradh	br13 = bo->pitch;
258303b705cfSriastradh	if (kgem->gen >= 040 && bo->tiling) {
258403b705cfSriastradh		cmd |= BLT_DST_TILED;
258503b705cfSriastradh		br13 >>= 2;
258603b705cfSriastradh	}
258703b705cfSriastradh	assert(br13 <= MAXSHORT);
258803b705cfSriastradh
258903b705cfSriastradh	br13 |= fill_ROP[alu] << 16;
259003b705cfSriastradh	switch (bpp) {
259103b705cfSriastradh	default: assert(0);
259203b705cfSriastradh	case 32: cmd |= BLT_WRITE_ALPHA | BLT_WRITE_RGB;
259303b705cfSriastradh		 br13 |= 1 << 25; /* RGB8888 */
259403b705cfSriastradh	case 16: br13 |= 1 << 24; /* RGB565 */
259503b705cfSriastradh	case 8: break;
259603b705cfSriastradh	}
259703b705cfSriastradh
259803b705cfSriastradh	/* All too frequently one blt completely overwrites the previous */
259903b705cfSriastradh	overwrites = alu == GXcopy || alu == GXclear || alu == GXset;
260003b705cfSriastradh	if (overwrites && kgem->nbatch >= 6 &&
260103b705cfSriastradh	    kgem->batch[kgem->nbatch-6] == cmd &&
260203b705cfSriastradh	    *(uint64_t *)&kgem->batch[kgem->nbatch-4] == *(const uint64_t *)box &&
260303b705cfSriastradh	    kgem->reloc[kgem->nreloc-1].target_handle == bo->target_handle) {
260403b705cfSriastradh		DBG(("%s: replacing last fill\n", __FUNCTION__));
260503b705cfSriastradh		kgem->batch[kgem->nbatch-5] = br13;
260603b705cfSriastradh		kgem->batch[kgem->nbatch-1] = color;
260703b705cfSriastradh		return true;
260803b705cfSriastradh	}
260903b705cfSriastradh	if (overwrites && kgem->nbatch >= 8 &&
261003b705cfSriastradh	    (kgem->batch[kgem->nbatch-8] & 0xffc0000f) == XY_SRC_COPY_BLT_CMD &&
261103b705cfSriastradh	    *(uint64_t *)&kgem->batch[kgem->nbatch-6] == *(const uint64_t *)box &&
261203b705cfSriastradh	    kgem->reloc[kgem->nreloc-2].target_handle == bo->target_handle) {
261303b705cfSriastradh		DBG(("%s: replacing last copy\n", __FUNCTION__));
261403b705cfSriastradh		kgem->batch[kgem->nbatch-8] = cmd;
261503b705cfSriastradh		kgem->batch[kgem->nbatch-7] = br13;
261603b705cfSriastradh		kgem->batch[kgem->nbatch-3] = color;
261703b705cfSriastradh		/* Keep the src bo as part of the execlist, just remove
261803b705cfSriastradh		 * its relocation entry.
261903b705cfSriastradh		 */
262003b705cfSriastradh		kgem->nreloc--;
262103b705cfSriastradh		kgem->nbatch -= 2;
262203b705cfSriastradh		return true;
262303b705cfSriastradh	}
262403b705cfSriastradh
262503b705cfSriastradh	/* If we are currently emitting SCANLINES, keep doing so */
262603b705cfSriastradh	if (sna->blt_state.fill_bo == bo->unique_id &&
262703b705cfSriastradh	    sna->blt_state.fill_pixel == color &&
262803b705cfSriastradh	    (sna->blt_state.fill_alu == alu ||
262903b705cfSriastradh	     sna->blt_state.fill_alu == ~alu)) {
263003b705cfSriastradh		DBG(("%s: matching last fill, converting to scanlines\n",
263103b705cfSriastradh		     __FUNCTION__));
263203b705cfSriastradh		return false;
263303b705cfSriastradh	}
263403b705cfSriastradh
263503b705cfSriastradh	kgem_set_mode(kgem, KGEM_BLT, bo);
263603b705cfSriastradh	if (!kgem_check_batch(kgem, 6) ||
263703b705cfSriastradh	    !kgem_check_reloc(kgem, 1) ||
263803b705cfSriastradh	    !kgem_check_bo_fenced(kgem, bo)) {
263903b705cfSriastradh		kgem_submit(kgem);
264003b705cfSriastradh		assert(kgem_check_bo_fenced(&sna->kgem, bo));
264103b705cfSriastradh		_kgem_set_mode(kgem, KGEM_BLT);
264203b705cfSriastradh	}
264303b705cfSriastradh
264403b705cfSriastradh	b = kgem->batch + kgem->nbatch;
264503b705cfSriastradh	b[0] = cmd;
264603b705cfSriastradh	b[1] = br13;
264703b705cfSriastradh	*(uint64_t *)(b+2) = *(const uint64_t *)box;
264803b705cfSriastradh	b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4, bo,
264903b705cfSriastradh			      I915_GEM_DOMAIN_RENDER << 16 |
265003b705cfSriastradh			      I915_GEM_DOMAIN_RENDER |
265103b705cfSriastradh			      KGEM_RELOC_FENCED,
265203b705cfSriastradh			      0);
265303b705cfSriastradh	b[5] = color;
265403b705cfSriastradh	kgem->nbatch += 6;
265503b705cfSriastradh	assert(kgem->nbatch < kgem->surface);
265603b705cfSriastradh
265703b705cfSriastradh	sna->blt_state.fill_bo = bo->unique_id;
265803b705cfSriastradh	sna->blt_state.fill_pixel = color;
265903b705cfSriastradh	sna->blt_state.fill_alu = ~alu;
266003b705cfSriastradh	return true;
266103b705cfSriastradh}
266203b705cfSriastradh
266303b705cfSriastradhbool sna_blt_fill_boxes(struct sna *sna, uint8_t alu,
266403b705cfSriastradh			struct kgem_bo *bo, int bpp,
266503b705cfSriastradh			uint32_t pixel,
266603b705cfSriastradh			const BoxRec *box, int nbox)
266703b705cfSriastradh{
266803b705cfSriastradh	struct kgem *kgem = &sna->kgem;
266903b705cfSriastradh	uint32_t br13, cmd;
267003b705cfSriastradh
267103b705cfSriastradh#if DEBUG_NO_BLT || NO_BLT_FILL_BOXES
267203b705cfSriastradh	return false;
267303b705cfSriastradh#endif
267403b705cfSriastradh
267503b705cfSriastradh	DBG(("%s (%d, %08x, %d) x %d\n",
267603b705cfSriastradh	     __FUNCTION__, bpp, pixel, alu, nbox));
267703b705cfSriastradh
267803b705cfSriastradh	if (!kgem_bo_can_blt(kgem, bo)) {
267903b705cfSriastradh		DBG(("%s: fallback -- cannot blt to dst\n", __FUNCTION__));
268003b705cfSriastradh		return false;
268103b705cfSriastradh	}
268203b705cfSriastradh
268303b705cfSriastradh	if (alu == GXclear)
268403b705cfSriastradh		pixel = 0;
268503b705cfSriastradh	else if (alu == GXcopy) {
268603b705cfSriastradh		if (pixel == 0)
268703b705cfSriastradh			alu = GXclear;
268803b705cfSriastradh		else if (pixel == -1)
268903b705cfSriastradh			alu = GXset;
269003b705cfSriastradh	}
269103b705cfSriastradh
269203b705cfSriastradh	if (nbox == 1 && sna_blt_fill_box(sna, alu, bo, bpp, pixel, box))
269303b705cfSriastradh		return true;
269403b705cfSriastradh
269503b705cfSriastradh	br13 = bo->pitch;
269603b705cfSriastradh	cmd = XY_SCANLINE_BLT;
269703b705cfSriastradh	if (kgem->gen >= 040 && bo->tiling) {
269803b705cfSriastradh		cmd |= 1 << 11;
269903b705cfSriastradh		br13 >>= 2;
270003b705cfSriastradh	}
270103b705cfSriastradh	assert(br13 <= MAXSHORT);
270203b705cfSriastradh
270303b705cfSriastradh	br13 |= 1<<31 | fill_ROP[alu] << 16;
270403b705cfSriastradh	switch (bpp) {
270503b705cfSriastradh	default: assert(0);
270603b705cfSriastradh	case 32: br13 |= 1 << 25; /* RGB8888 */
270703b705cfSriastradh	case 16: br13 |= 1 << 24; /* RGB565 */
270803b705cfSriastradh	case 8: break;
270903b705cfSriastradh	}
271003b705cfSriastradh
271103b705cfSriastradh	kgem_set_mode(kgem, KGEM_BLT, bo);
271203b705cfSriastradh	if (!kgem_check_batch(kgem, 12) ||
271303b705cfSriastradh	    !kgem_check_bo_fenced(kgem, bo)) {
271403b705cfSriastradh		kgem_submit(kgem);
271503b705cfSriastradh		if (!kgem_check_bo_fenced(&sna->kgem, bo))
271603b705cfSriastradh			return false;
271703b705cfSriastradh		_kgem_set_mode(kgem, KGEM_BLT);
271803b705cfSriastradh	}
271903b705cfSriastradh
272003b705cfSriastradh	if (sna->blt_state.fill_bo != bo->unique_id ||
272103b705cfSriastradh	    sna->blt_state.fill_pixel != pixel ||
272203b705cfSriastradh	    sna->blt_state.fill_alu != alu)
272303b705cfSriastradh	{
272403b705cfSriastradh		uint32_t *b;
272503b705cfSriastradh
272603b705cfSriastradh		if (!kgem_check_reloc(kgem, 1)) {
272703b705cfSriastradh			_kgem_submit(kgem);
272803b705cfSriastradh			_kgem_set_mode(kgem, KGEM_BLT);
272903b705cfSriastradh		}
273003b705cfSriastradh
273103b705cfSriastradh		b = kgem->batch + kgem->nbatch;
273203b705cfSriastradh		b[0] = XY_SETUP_MONO_PATTERN_SL_BLT;
273303b705cfSriastradh		if (bpp == 32)
273403b705cfSriastradh			b[0] |= BLT_WRITE_ALPHA | BLT_WRITE_RGB;
273503b705cfSriastradh		b[1] = br13;
273603b705cfSriastradh		b[2] = 0;
273703b705cfSriastradh		b[3] = 0;
273803b705cfSriastradh		b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4, bo,
273903b705cfSriastradh				      I915_GEM_DOMAIN_RENDER << 16 |
274003b705cfSriastradh				      I915_GEM_DOMAIN_RENDER |
274103b705cfSriastradh				      KGEM_RELOC_FENCED,
274203b705cfSriastradh				      0);
274303b705cfSriastradh		b[5] = pixel;
274403b705cfSriastradh		b[6] = pixel;
274503b705cfSriastradh		b[7] = 0;
274603b705cfSriastradh		b[8] = 0;
274703b705cfSriastradh		kgem->nbatch += 9;
274803b705cfSriastradh		assert(kgem->nbatch < kgem->surface);
274903b705cfSriastradh
275003b705cfSriastradh		sna->blt_state.fill_bo = bo->unique_id;
275103b705cfSriastradh		sna->blt_state.fill_pixel = pixel;
275203b705cfSriastradh		sna->blt_state.fill_alu = alu;
275303b705cfSriastradh	}
275403b705cfSriastradh
275503b705cfSriastradh	do {
275603b705cfSriastradh		int nbox_this_time;
275703b705cfSriastradh
275803b705cfSriastradh		nbox_this_time = nbox;
275903b705cfSriastradh		if (3*nbox_this_time > kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED)
276003b705cfSriastradh			nbox_this_time = (kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) / 3;
276103b705cfSriastradh		assert(nbox_this_time);
276203b705cfSriastradh		nbox -= nbox_this_time;
276303b705cfSriastradh
276403b705cfSriastradh		do {
276503b705cfSriastradh			uint32_t *b;
276603b705cfSriastradh
276703b705cfSriastradh			DBG(("%s: (%d, %d), (%d, %d): %08x\n",
276803b705cfSriastradh			     __FUNCTION__,
276903b705cfSriastradh			     box->x1, box->y1,
277003b705cfSriastradh			     box->x2, box->y2,
277103b705cfSriastradh			     pixel));
277203b705cfSriastradh
277303b705cfSriastradh			assert(box->x1 >= 0);
277403b705cfSriastradh			assert(box->y1 >= 0);
277503b705cfSriastradh			assert(box->y2 * bo->pitch <= kgem_bo_size(bo));
277603b705cfSriastradh
277703b705cfSriastradh			b = kgem->batch + kgem->nbatch;
277803b705cfSriastradh			kgem->nbatch += 3;
277903b705cfSriastradh			assert(kgem->nbatch < kgem->surface);
278003b705cfSriastradh			b[0] = cmd;
278103b705cfSriastradh			*(uint64_t *)(b+1) = *(const uint64_t *)box;
278203b705cfSriastradh			box++;
278303b705cfSriastradh		} while (--nbox_this_time);
278403b705cfSriastradh
278503b705cfSriastradh		if (nbox) {
278603b705cfSriastradh			uint32_t *b;
278703b705cfSriastradh
278803b705cfSriastradh			_kgem_submit(kgem);
278903b705cfSriastradh			_kgem_set_mode(kgem, KGEM_BLT);
279003b705cfSriastradh
279103b705cfSriastradh			b = kgem->batch + kgem->nbatch;
279203b705cfSriastradh			b[0] = XY_SETUP_MONO_PATTERN_SL_BLT;
279303b705cfSriastradh			if (bpp == 32)
279403b705cfSriastradh				b[0] |= BLT_WRITE_ALPHA | BLT_WRITE_RGB;
279503b705cfSriastradh			b[1] = br13;
279603b705cfSriastradh			b[2] = 0;
279703b705cfSriastradh			b[3] = 0;
279803b705cfSriastradh			b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4, bo,
279903b705cfSriastradh					      I915_GEM_DOMAIN_RENDER << 16 |
280003b705cfSriastradh					      I915_GEM_DOMAIN_RENDER |
280103b705cfSriastradh					      KGEM_RELOC_FENCED,
280203b705cfSriastradh					      0);
280303b705cfSriastradh			b[5] = pixel;
280403b705cfSriastradh			b[6] = pixel;
280503b705cfSriastradh			b[7] = 0;
280603b705cfSriastradh			b[8] = 0;
280703b705cfSriastradh			kgem->nbatch += 9;
280803b705cfSriastradh			assert(kgem->nbatch < kgem->surface);
280903b705cfSriastradh		}
281003b705cfSriastradh	} while (nbox);
281103b705cfSriastradh
281203b705cfSriastradh	if (kgem->nexec > 1 && __kgem_ring_empty(kgem))
281303b705cfSriastradh		_kgem_submit(kgem);
281403b705cfSriastradh
281503b705cfSriastradh	return true;
281603b705cfSriastradh}
281703b705cfSriastradh
281803b705cfSriastradhbool sna_blt_copy_boxes(struct sna *sna, uint8_t alu,
281903b705cfSriastradh			struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy,
282003b705cfSriastradh			struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy,
282103b705cfSriastradh			int bpp, const BoxRec *box, int nbox)
282203b705cfSriastradh{
282303b705cfSriastradh	struct kgem *kgem = &sna->kgem;
282403b705cfSriastradh	unsigned src_pitch, br13, cmd;
282503b705cfSriastradh
282603b705cfSriastradh#if DEBUG_NO_BLT || NO_BLT_COPY_BOXES
282703b705cfSriastradh	return false;
282803b705cfSriastradh#endif
282903b705cfSriastradh
283003b705cfSriastradh	DBG(("%s src=(%d, %d) -> (%d, %d) x %d, tiling=(%d, %d), pitch=(%d, %d)\n",
283103b705cfSriastradh	     __FUNCTION__, src_dx, src_dy, dst_dx, dst_dy, nbox,
283203b705cfSriastradh	    src_bo->tiling, dst_bo->tiling,
283303b705cfSriastradh	    src_bo->pitch, dst_bo->pitch));
283403b705cfSriastradh
283503b705cfSriastradh	if (!kgem_bo_can_blt(kgem, src_bo) || !kgem_bo_can_blt(kgem, dst_bo)) {
283603b705cfSriastradh		DBG(("%s: cannot blt to src? %d or dst? %d\n",
283703b705cfSriastradh		     __FUNCTION__,
283803b705cfSriastradh		     kgem_bo_can_blt(kgem, src_bo),
283903b705cfSriastradh		     kgem_bo_can_blt(kgem, dst_bo)));
284003b705cfSriastradh		return false;
284103b705cfSriastradh	}
284203b705cfSriastradh
284303b705cfSriastradh	cmd = XY_SRC_COPY_BLT_CMD;
284403b705cfSriastradh	if (bpp == 32)
284503b705cfSriastradh		cmd |= BLT_WRITE_ALPHA | BLT_WRITE_RGB;
284603b705cfSriastradh
284703b705cfSriastradh	src_pitch = src_bo->pitch;
284803b705cfSriastradh	if (kgem->gen >= 040 && src_bo->tiling) {
284903b705cfSriastradh		cmd |= BLT_SRC_TILED;
285003b705cfSriastradh		src_pitch >>= 2;
285103b705cfSriastradh	}
285203b705cfSriastradh	assert(src_pitch <= MAXSHORT);
285303b705cfSriastradh
285403b705cfSriastradh	br13 = dst_bo->pitch;
285503b705cfSriastradh	if (kgem->gen >= 040 && dst_bo->tiling) {
285603b705cfSriastradh		cmd |= BLT_DST_TILED;
285703b705cfSriastradh		br13 >>= 2;
285803b705cfSriastradh	}
285903b705cfSriastradh	assert(br13 <= MAXSHORT);
286003b705cfSriastradh
286103b705cfSriastradh	br13 |= copy_ROP[alu] << 16;
286203b705cfSriastradh	switch (bpp) {
286303b705cfSriastradh	default: assert(0);
286403b705cfSriastradh	case 32: br13 |= 1 << 25; /* RGB8888 */
286503b705cfSriastradh	case 16: br13 |= 1 << 24; /* RGB565 */
286603b705cfSriastradh	case 8: break;
286703b705cfSriastradh	}
286803b705cfSriastradh
286903b705cfSriastradh	/* Compare first box against a previous fill */
287003b705cfSriastradh	if (kgem->nbatch >= 6 &&
287103b705cfSriastradh	    (alu == GXcopy || alu == GXclear || alu == GXset) &&
287203b705cfSriastradh	    kgem->reloc[kgem->nreloc-1].target_handle == dst_bo->target_handle &&
287303b705cfSriastradh	    kgem->batch[kgem->nbatch-6] == ((cmd & ~XY_SRC_COPY_BLT_CMD) | XY_COLOR_BLT) &&
287403b705cfSriastradh	    kgem->batch[kgem->nbatch-4] == ((uint32_t)(box->y1 + dst_dy) << 16 | (uint16_t)(box->x1 + dst_dx)) &&
287503b705cfSriastradh	    kgem->batch[kgem->nbatch-3] == ((uint32_t)(box->y2 + dst_dy) << 16 | (uint16_t)(box->x2 + dst_dx))) {
287603b705cfSriastradh		DBG(("%s: deleting last fill\n", __FUNCTION__));
287703b705cfSriastradh		kgem->nbatch -= 6;
287803b705cfSriastradh		kgem->nreloc--;
287903b705cfSriastradh	}
288003b705cfSriastradh
288103b705cfSriastradh	kgem_set_mode(kgem, KGEM_BLT, dst_bo);
288203b705cfSriastradh	if (!kgem_check_batch(kgem, 8) ||
288303b705cfSriastradh	    !kgem_check_reloc(kgem, 2) ||
288403b705cfSriastradh	    !kgem_check_many_bo_fenced(kgem, dst_bo, src_bo, NULL)) {
288503b705cfSriastradh		kgem_submit(kgem);
288603b705cfSriastradh		if (!kgem_check_many_bo_fenced(kgem, dst_bo, src_bo, NULL))
288703b705cfSriastradh			return sna_tiling_blt_copy_boxes(sna, alu,
288803b705cfSriastradh							 src_bo, src_dx, src_dy,
288903b705cfSriastradh							 dst_bo, dst_dx, dst_dy,
289003b705cfSriastradh							 bpp, box, nbox);
289103b705cfSriastradh		_kgem_set_mode(kgem, KGEM_BLT);
289203b705cfSriastradh	}
289303b705cfSriastradh
289403b705cfSriastradh	if ((dst_dx | dst_dy) == 0) {
289503b705cfSriastradh		uint64_t hdr = (uint64_t)br13 << 32 | cmd;
289603b705cfSriastradh		do {
289703b705cfSriastradh			int nbox_this_time;
289803b705cfSriastradh
289903b705cfSriastradh			nbox_this_time = nbox;
290003b705cfSriastradh			if (8*nbox_this_time > kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED)
290103b705cfSriastradh				nbox_this_time = (kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) / 8;
290203b705cfSriastradh			if (2*nbox_this_time > KGEM_RELOC_SIZE(kgem) - kgem->nreloc)
290303b705cfSriastradh				nbox_this_time = (KGEM_RELOC_SIZE(kgem) - kgem->nreloc)/2;
290403b705cfSriastradh			assert(nbox_this_time);
290503b705cfSriastradh			nbox -= nbox_this_time;
290603b705cfSriastradh
290703b705cfSriastradh			do {
290803b705cfSriastradh				uint32_t *b = kgem->batch + kgem->nbatch;
290903b705cfSriastradh
291003b705cfSriastradh				DBG(("  %s: box=(%d, %d)x(%d, %d)\n",
291103b705cfSriastradh				     __FUNCTION__,
291203b705cfSriastradh				     box->x1, box->y1,
291303b705cfSriastradh				     box->x2 - box->x1, box->y2 - box->y1));
291403b705cfSriastradh
291503b705cfSriastradh				assert(box->x1 + src_dx >= 0);
291603b705cfSriastradh				assert(box->y1 + src_dy >= 0);
291703b705cfSriastradh				assert(box->x1 + src_dx <= INT16_MAX);
291803b705cfSriastradh				assert(box->y1 + src_dy <= INT16_MAX);
291903b705cfSriastradh
292003b705cfSriastradh				assert(box->x1 >= 0);
292103b705cfSriastradh				assert(box->y1 >= 0);
292203b705cfSriastradh
292303b705cfSriastradh				*(uint64_t *)&b[0] = hdr;
292403b705cfSriastradh				*(uint64_t *)&b[2] = *(const uint64_t *)box;
292503b705cfSriastradh				b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4, dst_bo,
292603b705cfSriastradh						      I915_GEM_DOMAIN_RENDER << 16 |
292703b705cfSriastradh						      I915_GEM_DOMAIN_RENDER |
292803b705cfSriastradh						      KGEM_RELOC_FENCED,
292903b705cfSriastradh						      0);
293003b705cfSriastradh				b[5] = add2(b[2], src_dx, src_dy);
293103b705cfSriastradh				b[6] = src_pitch;
293203b705cfSriastradh				b[7] = kgem_add_reloc(kgem, kgem->nbatch + 7, src_bo,
293303b705cfSriastradh						      I915_GEM_DOMAIN_RENDER << 16 |
293403b705cfSriastradh						      KGEM_RELOC_FENCED,
293503b705cfSriastradh						      0);
293603b705cfSriastradh				kgem->nbatch += 8;
293703b705cfSriastradh				assert(kgem->nbatch < kgem->surface);
293803b705cfSriastradh				box++;
293903b705cfSriastradh			} while (--nbox_this_time);
294003b705cfSriastradh
294103b705cfSriastradh			if (!nbox)
294203b705cfSriastradh				break;
294303b705cfSriastradh
294403b705cfSriastradh			_kgem_submit(kgem);
294503b705cfSriastradh			_kgem_set_mode(kgem, KGEM_BLT);
294603b705cfSriastradh		} while (1);
294703b705cfSriastradh	} else {
294803b705cfSriastradh		do {
294903b705cfSriastradh			int nbox_this_time;
295003b705cfSriastradh
295103b705cfSriastradh			nbox_this_time = nbox;
295203b705cfSriastradh			if (8*nbox_this_time > kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED)
295303b705cfSriastradh				nbox_this_time = (kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) / 8;
295403b705cfSriastradh			if (2*nbox_this_time > KGEM_RELOC_SIZE(kgem) - kgem->nreloc)
295503b705cfSriastradh				nbox_this_time = (KGEM_RELOC_SIZE(kgem) - kgem->nreloc)/2;
295603b705cfSriastradh			assert(nbox_this_time);
295703b705cfSriastradh			nbox -= nbox_this_time;
295803b705cfSriastradh
295903b705cfSriastradh			do {
296003b705cfSriastradh				uint32_t *b = kgem->batch + kgem->nbatch;
296103b705cfSriastradh
296203b705cfSriastradh				DBG(("  %s: box=(%d, %d)x(%d, %d)\n",
296303b705cfSriastradh				     __FUNCTION__,
296403b705cfSriastradh				     box->x1, box->y1,
296503b705cfSriastradh				     box->x2 - box->x1, box->y2 - box->y1));
296603b705cfSriastradh
296703b705cfSriastradh				assert(box->x1 + src_dx >= 0);
296803b705cfSriastradh				assert(box->y1 + src_dy >= 0);
296903b705cfSriastradh
297003b705cfSriastradh				assert(box->x1 + dst_dx >= 0);
297103b705cfSriastradh				assert(box->y1 + dst_dy >= 0);
297203b705cfSriastradh
297303b705cfSriastradh				b[0] = cmd;
297403b705cfSriastradh				b[1] = br13;
297503b705cfSriastradh				b[2] = ((box->y1 + dst_dy) << 16) | (box->x1 + dst_dx);
297603b705cfSriastradh				b[3] = ((box->y2 + dst_dy) << 16) | (box->x2 + dst_dx);
297703b705cfSriastradh				b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4, dst_bo,
297803b705cfSriastradh						      I915_GEM_DOMAIN_RENDER << 16 |
297903b705cfSriastradh						      I915_GEM_DOMAIN_RENDER |
298003b705cfSriastradh						      KGEM_RELOC_FENCED,
298103b705cfSriastradh						      0);
298203b705cfSriastradh				b[5] = ((box->y1 + src_dy) << 16) | (box->x1 + src_dx);
298303b705cfSriastradh				b[6] = src_pitch;
298403b705cfSriastradh				b[7] = kgem_add_reloc(kgem, kgem->nbatch + 7, src_bo,
298503b705cfSriastradh						      I915_GEM_DOMAIN_RENDER << 16 |
298603b705cfSriastradh						      KGEM_RELOC_FENCED,
298703b705cfSriastradh						      0);
298803b705cfSriastradh				kgem->nbatch += 8;
298903b705cfSriastradh				assert(kgem->nbatch < kgem->surface);
299003b705cfSriastradh				box++;
299103b705cfSriastradh			} while (--nbox_this_time);
299203b705cfSriastradh
299303b705cfSriastradh			if (!nbox)
299403b705cfSriastradh				break;
299503b705cfSriastradh
299603b705cfSriastradh			_kgem_submit(kgem);
299703b705cfSriastradh			_kgem_set_mode(kgem, KGEM_BLT);
299803b705cfSriastradh		} while (1);
299903b705cfSriastradh	}
300003b705cfSriastradh
300103b705cfSriastradh	if (kgem->nexec > 1 && __kgem_ring_empty(kgem)) {
300203b705cfSriastradh		_kgem_submit(kgem);
300303b705cfSriastradh	} else if (kgem->gen >= 060 && kgem_check_batch(kgem, 3)) {
300403b705cfSriastradh		uint32_t *b = kgem->batch + kgem->nbatch;
300503b705cfSriastradh		b[0] = XY_SETUP_CLIP;
300603b705cfSriastradh		b[1] = b[2] = 0;
300703b705cfSriastradh		kgem->nbatch += 3;
300803b705cfSriastradh		assert(kgem->nbatch < kgem->surface);
300903b705cfSriastradh	}
301003b705cfSriastradh
301103b705cfSriastradh	sna->blt_state.fill_bo = 0;
301203b705cfSriastradh	return true;
301303b705cfSriastradh}
301403b705cfSriastradh
301503b705cfSriastradhstatic void box_extents(const BoxRec *box, int n, BoxRec *extents)
301603b705cfSriastradh{
301703b705cfSriastradh	*extents = *box;
301803b705cfSriastradh	while (--n) {
301903b705cfSriastradh		box++;
302003b705cfSriastradh		if (box->x1 < extents->x1)
302103b705cfSriastradh			extents->x1 = box->x1;
302203b705cfSriastradh		if (box->y1 < extents->y1)
302303b705cfSriastradh			extents->y1 = box->y1;
302403b705cfSriastradh
302503b705cfSriastradh		if (box->x2 > extents->x2)
302603b705cfSriastradh			extents->x2 = box->x2;
302703b705cfSriastradh		if (box->y2 > extents->y2)
302803b705cfSriastradh			extents->y2 = box->y2;
302903b705cfSriastradh	}
303003b705cfSriastradh}
303103b705cfSriastradh
303203b705cfSriastradhbool sna_blt_copy_boxes_fallback(struct sna *sna, uint8_t alu,
303303b705cfSriastradh				 PixmapPtr src, struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy,
303403b705cfSriastradh				 PixmapPtr dst, struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy,
303503b705cfSriastradh				 const BoxRec *box, int nbox)
303603b705cfSriastradh{
303703b705cfSriastradh	struct kgem_bo *free_bo = NULL;
303803b705cfSriastradh	bool ret;
303903b705cfSriastradh
304003b705cfSriastradh	DBG(("%s: alu=%d, n=%d\n", __FUNCTION__, alu, nbox));
304103b705cfSriastradh
304203b705cfSriastradh	if (!sna_blt_compare_depth(&src->drawable, &dst->drawable)) {
304303b705cfSriastradh		DBG(("%s: mismatching depths %d -> %d\n",
304403b705cfSriastradh		     __FUNCTION__, src->drawable.depth, dst->drawable.depth));
304503b705cfSriastradh		return false;
304603b705cfSriastradh	}
304703b705cfSriastradh
304803b705cfSriastradh	if (src_bo == dst_bo) {
304903b705cfSriastradh		DBG(("%s: dst == src\n", __FUNCTION__));
305003b705cfSriastradh
305103b705cfSriastradh		if (src_bo->tiling == I915_TILING_Y &&
305203b705cfSriastradh		    kgem_bo_blt_pitch_is_ok(&sna->kgem, src_bo)) {
305303b705cfSriastradh			struct kgem_bo *bo;
305403b705cfSriastradh
305503b705cfSriastradh			DBG(("%s: src is Y-tiled\n", __FUNCTION__));
305603b705cfSriastradh
305703b705cfSriastradh			assert(src_bo == sna_pixmap(src)->gpu_bo);
305803b705cfSriastradh			bo = sna_pixmap_change_tiling(src, I915_TILING_X);
305903b705cfSriastradh			if (bo == NULL) {
306003b705cfSriastradh				BoxRec extents;
306103b705cfSriastradh
306203b705cfSriastradh				DBG(("%s: y-tiling conversion failed\n",
306303b705cfSriastradh				     __FUNCTION__));
306403b705cfSriastradh
306503b705cfSriastradh				box_extents(box, nbox, &extents);
306603b705cfSriastradh				free_bo = kgem_create_2d(&sna->kgem,
306703b705cfSriastradh							 extents.x2 - extents.x1,
306803b705cfSriastradh							 extents.y2 - extents.y1,
306903b705cfSriastradh							 src->drawable.bitsPerPixel,
307003b705cfSriastradh							 I915_TILING_X, 0);
307103b705cfSriastradh				if (free_bo == NULL) {
307203b705cfSriastradh					DBG(("%s: fallback -- temp allocation failed\n",
307303b705cfSriastradh					     __FUNCTION__));
307403b705cfSriastradh					return false;
307503b705cfSriastradh				}
307603b705cfSriastradh
307703b705cfSriastradh				if (!sna_blt_copy_boxes(sna, GXcopy,
307803b705cfSriastradh							src_bo, src_dx, src_dy,
307903b705cfSriastradh							free_bo, -extents.x1, -extents.y1,
308003b705cfSriastradh							src->drawable.bitsPerPixel,
308103b705cfSriastradh							box, nbox)) {
308203b705cfSriastradh					DBG(("%s: fallback -- temp copy failed\n",
308303b705cfSriastradh					     __FUNCTION__));
308403b705cfSriastradh					kgem_bo_destroy(&sna->kgem, free_bo);
308503b705cfSriastradh					return false;
308603b705cfSriastradh				}
308703b705cfSriastradh
308803b705cfSriastradh				src_dx = -extents.x1;
308903b705cfSriastradh				src_dy = -extents.y1;
309003b705cfSriastradh				src_bo = free_bo;
309103b705cfSriastradh			} else
309203b705cfSriastradh				dst_bo = src_bo = bo;
309303b705cfSriastradh		}
309403b705cfSriastradh	} else {
309503b705cfSriastradh		if (src_bo->tiling == I915_TILING_Y &&
309603b705cfSriastradh		    kgem_bo_blt_pitch_is_ok(&sna->kgem, src_bo)) {
309703b705cfSriastradh			DBG(("%s: src is y-tiled\n", __FUNCTION__));
309803b705cfSriastradh			assert(src_bo == sna_pixmap(src)->gpu_bo);
309903b705cfSriastradh			src_bo = sna_pixmap_change_tiling(src, I915_TILING_X);
310003b705cfSriastradh			if (src_bo == NULL) {
310103b705cfSriastradh				DBG(("%s: fallback -- src y-tiling conversion failed\n",
310203b705cfSriastradh				     __FUNCTION__));
310303b705cfSriastradh				return false;
310403b705cfSriastradh			}
310503b705cfSriastradh		}
310603b705cfSriastradh
310703b705cfSriastradh		if (dst_bo->tiling == I915_TILING_Y &&
310803b705cfSriastradh		    kgem_bo_blt_pitch_is_ok(&sna->kgem, dst_bo)) {
310903b705cfSriastradh			DBG(("%s: dst is y-tiled\n", __FUNCTION__));
311003b705cfSriastradh			assert(dst_bo == sna_pixmap(dst)->gpu_bo);
311103b705cfSriastradh			dst_bo = sna_pixmap_change_tiling(dst, I915_TILING_X);
311203b705cfSriastradh			if (dst_bo == NULL) {
311303b705cfSriastradh				DBG(("%s: fallback -- dst y-tiling conversion failed\n",
311403b705cfSriastradh				     __FUNCTION__));
311503b705cfSriastradh				return false;
311603b705cfSriastradh			}
311703b705cfSriastradh		}
311803b705cfSriastradh	}
311903b705cfSriastradh
312003b705cfSriastradh	ret =  sna_blt_copy_boxes(sna, alu,
312103b705cfSriastradh				  src_bo, src_dx, src_dy,
312203b705cfSriastradh				  dst_bo, dst_dx, dst_dy,
312303b705cfSriastradh				  dst->drawable.bitsPerPixel,
312403b705cfSriastradh				  box, nbox);
312503b705cfSriastradh
312603b705cfSriastradh	if (free_bo)
312703b705cfSriastradh		kgem_bo_destroy(&sna->kgem, free_bo);
312803b705cfSriastradh
312903b705cfSriastradh	return ret;
313003b705cfSriastradh}
3131