sna_render.c revision 03b705cf
103b705cfSriastradh/*
203b705cfSriastradh * Copyright © 2011 Intel Corporation
303b705cfSriastradh *
403b705cfSriastradh * Permission is hereby granted, free of charge, to any person obtaining a
503b705cfSriastradh * copy of this software and associated documentation files (the "Software"),
603b705cfSriastradh * to deal in the Software without restriction, including without limitation
703b705cfSriastradh * the rights to use, copy, modify, merge, publish, distribute, sublicense,
803b705cfSriastradh * and/or sell copies of the Software, and to permit persons to whom the
903b705cfSriastradh * Software is furnished to do so, subject to the following conditions:
1003b705cfSriastradh *
1103b705cfSriastradh * The above copyright notice and this permission notice (including the next
1203b705cfSriastradh * paragraph) shall be included in all copies or substantial portions of the
1303b705cfSriastradh * Software.
1403b705cfSriastradh *
1503b705cfSriastradh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1603b705cfSriastradh * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1703b705cfSriastradh * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1803b705cfSriastradh * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1903b705cfSriastradh * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2003b705cfSriastradh * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2103b705cfSriastradh * SOFTWARE.
2203b705cfSriastradh *
2303b705cfSriastradh * Authors:
2403b705cfSriastradh *    Chris Wilson <chris@chris-wilson.co.uk>
2503b705cfSriastradh *
2603b705cfSriastradh */
2703b705cfSriastradh
2803b705cfSriastradh#include "sna.h"
2903b705cfSriastradh#include "sna_render.h"
3003b705cfSriastradh#include "sna_render_inline.h"
3103b705cfSriastradh#include "fb/fbpict.h"
3203b705cfSriastradh
3303b705cfSriastradh#define NO_REDIRECT 0
3403b705cfSriastradh#define NO_CONVERT 0
3503b705cfSriastradh#define NO_FIXUP 0
3603b705cfSriastradh#define NO_EXTRACT 0
3703b705cfSriastradh
3803b705cfSriastradh#define DBG_FORCE_UPLOAD 0
3903b705cfSriastradh#define DBG_NO_CPU_BO 0
4003b705cfSriastradh
4103b705cfSriastradh#define alphaless(format) PICT_FORMAT(PICT_FORMAT_BPP(format),		\
4203b705cfSriastradh				      PICT_FORMAT_TYPE(format),		\
4303b705cfSriastradh				      0,				\
4403b705cfSriastradh				      PICT_FORMAT_R(format),		\
4503b705cfSriastradh				      PICT_FORMAT_G(format),		\
4603b705cfSriastradh				      PICT_FORMAT_B(format))
4703b705cfSriastradh
4803b705cfSriastradhCARD32
4903b705cfSriastradhsna_format_for_depth(int depth)
5003b705cfSriastradh{
5103b705cfSriastradh	switch (depth) {
5203b705cfSriastradh	case 1: return PICT_a1;
5303b705cfSriastradh	case 4: return PICT_a4;
5403b705cfSriastradh	case 8: return PICT_a8;
5503b705cfSriastradh	case 15: return PICT_x1r5g5b5;
5603b705cfSriastradh	case 16: return PICT_r5g6b5;
5703b705cfSriastradh	default: assert(0);
5803b705cfSriastradh	case 24: return PICT_x8r8g8b8;
5903b705cfSriastradh	case 30: return PICT_x2r10g10b10;
6003b705cfSriastradh	case 32: return PICT_a8r8g8b8;
6103b705cfSriastradh	}
6203b705cfSriastradh}
6303b705cfSriastradh
6403b705cfSriastradhCARD32
6503b705cfSriastradhsna_render_format_for_depth(int depth)
6603b705cfSriastradh{
6703b705cfSriastradh	switch (depth) {
6803b705cfSriastradh	case 1: return PIXMAN_a1;
6903b705cfSriastradh	case 4: return PIXMAN_a4;
7003b705cfSriastradh	case 8: return PIXMAN_a8;
7103b705cfSriastradh	case 15: return PIXMAN_a1r5g5b5;
7203b705cfSriastradh	case 16: return PIXMAN_r5g6b5;
7303b705cfSriastradh	case 30: return PIXMAN_a2r10g10b10;
7403b705cfSriastradh	default: assert(0);
7503b705cfSriastradh	case 24:
7603b705cfSriastradh	case 32: return PIXMAN_a8r8g8b8;
7703b705cfSriastradh	}
7803b705cfSriastradh}
7903b705cfSriastradh
8003b705cfSriastradhstatic bool
8103b705cfSriastradhno_render_composite(struct sna *sna,
8203b705cfSriastradh		    uint8_t op,
8303b705cfSriastradh		    PicturePtr src,
8403b705cfSriastradh		    PicturePtr mask,
8503b705cfSriastradh		    PicturePtr dst,
8603b705cfSriastradh		    int16_t src_x, int16_t src_y,
8703b705cfSriastradh		    int16_t mask_x, int16_t mask_y,
8803b705cfSriastradh		    int16_t dst_x, int16_t dst_y,
8903b705cfSriastradh		    int16_t width, int16_t height,
9003b705cfSriastradh		    struct sna_composite_op *tmp)
9103b705cfSriastradh{
9203b705cfSriastradh	DBG(("%s (op=%d, mask? %d)\n", __FUNCTION__, op, mask != NULL));
9303b705cfSriastradh
9403b705cfSriastradh	if (mask)
9503b705cfSriastradh		return false;
9603b705cfSriastradh
9703b705cfSriastradh	if (!is_gpu(sna, dst->pDrawable, PREFER_GPU_BLT) &&
9803b705cfSriastradh	    (src->pDrawable == NULL || !is_gpu(sna, src->pDrawable, PREFER_GPU_BLT)))
9903b705cfSriastradh		return false;
10003b705cfSriastradh
10103b705cfSriastradh	return sna_blt_composite(sna,
10203b705cfSriastradh				 op, src, dst,
10303b705cfSriastradh				 src_x, src_y,
10403b705cfSriastradh				 dst_x, dst_y,
10503b705cfSriastradh				 width, height,
10603b705cfSriastradh				 tmp, true);
10703b705cfSriastradh	(void)mask_x;
10803b705cfSriastradh	(void)mask_y;
10903b705cfSriastradh}
11003b705cfSriastradh
11103b705cfSriastradhstatic bool
11203b705cfSriastradhno_render_check_composite_spans(struct sna *sna,
11303b705cfSriastradh				uint8_t op, PicturePtr src, PicturePtr dst,
11403b705cfSriastradh				int16_t width,  int16_t height, unsigned flags)
11503b705cfSriastradh{
11603b705cfSriastradh	return false;
11703b705cfSriastradh}
11803b705cfSriastradh
11903b705cfSriastradhstatic bool
12003b705cfSriastradhno_render_copy_boxes(struct sna *sna, uint8_t alu,
12103b705cfSriastradh		     PixmapPtr src, struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy,
12203b705cfSriastradh		     PixmapPtr dst, struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy,
12303b705cfSriastradh		     const BoxRec *box, int n, unsigned flags)
12403b705cfSriastradh{
12503b705cfSriastradh	DBG(("%s (n=%d)\n", __FUNCTION__, n));
12603b705cfSriastradh
12703b705cfSriastradh	if (!sna_blt_compare_depth(&src->drawable, &dst->drawable))
12803b705cfSriastradh		return false;
12903b705cfSriastradh
13003b705cfSriastradh	return sna_blt_copy_boxes(sna, alu,
13103b705cfSriastradh				  src_bo, src_dx, src_dy,
13203b705cfSriastradh				  dst_bo, dst_dx, dst_dy,
13303b705cfSriastradh				  dst->drawable.bitsPerPixel,
13403b705cfSriastradh				  box, n);
13503b705cfSriastradh}
13603b705cfSriastradh
13703b705cfSriastradhstatic bool
13803b705cfSriastradhno_render_copy(struct sna *sna, uint8_t alu,
13903b705cfSriastradh		 PixmapPtr src, struct kgem_bo *src_bo,
14003b705cfSriastradh		 PixmapPtr dst, struct kgem_bo *dst_bo,
14103b705cfSriastradh		 struct sna_copy_op *tmp)
14203b705cfSriastradh{
14303b705cfSriastradh	DBG(("%s ()\n", __FUNCTION__));
14403b705cfSriastradh
14503b705cfSriastradh	if (sna_blt_compare_depth(&src->drawable, &dst->drawable) &&
14603b705cfSriastradh	    sna_blt_copy(sna, alu,
14703b705cfSriastradh			 src_bo, dst_bo, dst->drawable.bitsPerPixel,
14803b705cfSriastradh			 tmp))
14903b705cfSriastradh		return true;
15003b705cfSriastradh
15103b705cfSriastradh	return false;
15203b705cfSriastradh}
15303b705cfSriastradh
15403b705cfSriastradhstatic bool
15503b705cfSriastradhno_render_fill_boxes(struct sna *sna,
15603b705cfSriastradh		     CARD8 op,
15703b705cfSriastradh		     PictFormat format,
15803b705cfSriastradh		     const xRenderColor *color,
15903b705cfSriastradh		     PixmapPtr dst, struct kgem_bo *dst_bo,
16003b705cfSriastradh		     const BoxRec *box, int n)
16103b705cfSriastradh{
16203b705cfSriastradh	uint8_t alu = GXcopy;
16303b705cfSriastradh	uint32_t pixel;
16403b705cfSriastradh
16503b705cfSriastradh	DBG(("%s (op=%d, color=(%04x,%04x,%04x, %04x))\n",
16603b705cfSriastradh	     __FUNCTION__, op,
16703b705cfSriastradh	     color->red, color->green, color->blue, color->alpha));
16803b705cfSriastradh
16903b705cfSriastradh	if (op == PictOpClear) {
17003b705cfSriastradh		pixel = 0;
17103b705cfSriastradh		alu = GXclear;
17203b705cfSriastradh		op = PictOpSrc;
17303b705cfSriastradh	}
17403b705cfSriastradh
17503b705cfSriastradh	if (op == PictOpOver) {
17603b705cfSriastradh		if ((color->alpha >= 0xff00))
17703b705cfSriastradh			op = PictOpSrc;
17803b705cfSriastradh	}
17903b705cfSriastradh
18003b705cfSriastradh	if (op != PictOpSrc)
18103b705cfSriastradh		return false;
18203b705cfSriastradh
18303b705cfSriastradh	if (alu == GXcopy &&
18403b705cfSriastradh	    !sna_get_pixel_from_rgba(&pixel,
18503b705cfSriastradh				     color->red,
18603b705cfSriastradh				     color->green,
18703b705cfSriastradh				     color->blue,
18803b705cfSriastradh				     color->alpha,
18903b705cfSriastradh				     format))
19003b705cfSriastradh		return false;
19103b705cfSriastradh
19203b705cfSriastradh	return sna_blt_fill_boxes(sna, alu,
19303b705cfSriastradh				  dst_bo, dst->drawable.bitsPerPixel,
19403b705cfSriastradh				  pixel, box, n);
19503b705cfSriastradh}
19603b705cfSriastradh
19703b705cfSriastradhstatic bool
19803b705cfSriastradhno_render_fill(struct sna *sna, uint8_t alu,
19903b705cfSriastradh	       PixmapPtr dst, struct kgem_bo *dst_bo,
20003b705cfSriastradh	       uint32_t color,
20103b705cfSriastradh	       struct sna_fill_op *tmp)
20203b705cfSriastradh{
20303b705cfSriastradh	DBG(("%s (alu=%d, color=%08x)\n", __FUNCTION__, alu, color));
20403b705cfSriastradh	return sna_blt_fill(sna, alu,
20503b705cfSriastradh			    dst_bo, dst->drawable.bitsPerPixel,
20603b705cfSriastradh			    color,
20703b705cfSriastradh			    tmp);
20803b705cfSriastradh}
20903b705cfSriastradh
21003b705cfSriastradhstatic bool
21103b705cfSriastradhno_render_fill_one(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo,
21203b705cfSriastradh		   uint32_t color,
21303b705cfSriastradh		   int16_t x1, int16_t y1, int16_t x2, int16_t y2,
21403b705cfSriastradh		   uint8_t alu)
21503b705cfSriastradh{
21603b705cfSriastradh	BoxRec box;
21703b705cfSriastradh
21803b705cfSriastradh	box.x1 = x1;
21903b705cfSriastradh	box.y1 = y1;
22003b705cfSriastradh	box.x2 = x2;
22103b705cfSriastradh	box.y2 = y2;
22203b705cfSriastradh
22303b705cfSriastradh	DBG(("%s (alu=%d, color=%08x) (%d,%d), (%d, %d)\n",
22403b705cfSriastradh	     __FUNCTION__, alu, color, x1, y1, x2, y2));
22503b705cfSriastradh	return sna_blt_fill_boxes(sna, alu,
22603b705cfSriastradh				  bo, dst->drawable.bitsPerPixel,
22703b705cfSriastradh				  color, &box, 1);
22803b705cfSriastradh}
22903b705cfSriastradh
23003b705cfSriastradhstatic bool
23103b705cfSriastradhno_render_clear(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo)
23203b705cfSriastradh{
23303b705cfSriastradh	DBG(("%s: pixmap=%ld %dx%d\n", __FUNCTION__,
23403b705cfSriastradh	     dst->drawable.serialNumber,
23503b705cfSriastradh	     dst->drawable.width,
23603b705cfSriastradh	     dst->drawable.height));
23703b705cfSriastradh	return sna->render.fill_one(sna, dst, bo, 0,
23803b705cfSriastradh				    0, 0, dst->drawable.width, dst->drawable.height,
23903b705cfSriastradh				    GXclear);
24003b705cfSriastradh}
24103b705cfSriastradh
24203b705cfSriastradhstatic void no_render_reset(struct sna *sna)
24303b705cfSriastradh{
24403b705cfSriastradh	(void)sna;
24503b705cfSriastradh}
24603b705cfSriastradh
24703b705cfSriastradhstatic void no_render_flush(struct sna *sna)
24803b705cfSriastradh{
24903b705cfSriastradh	(void)sna;
25003b705cfSriastradh}
25103b705cfSriastradh
25203b705cfSriastradhstatic void
25303b705cfSriastradhno_render_context_switch(struct kgem *kgem,
25403b705cfSriastradh			 int new_mode)
25503b705cfSriastradh{
25603b705cfSriastradh	if (!kgem->nbatch)
25703b705cfSriastradh		return;
25803b705cfSriastradh
25903b705cfSriastradh	if (kgem_ring_is_idle(kgem, kgem->ring)) {
26003b705cfSriastradh		DBG(("%s: GPU idle, flushing\n", __FUNCTION__));
26103b705cfSriastradh		_kgem_submit(kgem);
26203b705cfSriastradh	}
26303b705cfSriastradh
26403b705cfSriastradh	(void)new_mode;
26503b705cfSriastradh}
26603b705cfSriastradh
26703b705cfSriastradhstatic void
26803b705cfSriastradhno_render_retire(struct kgem *kgem)
26903b705cfSriastradh{
27003b705cfSriastradh	(void)kgem;
27103b705cfSriastradh}
27203b705cfSriastradh
27303b705cfSriastradhstatic void
27403b705cfSriastradhno_render_expire(struct kgem *kgem)
27503b705cfSriastradh{
27603b705cfSriastradh	(void)kgem;
27703b705cfSriastradh}
27803b705cfSriastradh
27903b705cfSriastradhstatic void
28003b705cfSriastradhno_render_fini(struct sna *sna)
28103b705cfSriastradh{
28203b705cfSriastradh	(void)sna;
28303b705cfSriastradh}
28403b705cfSriastradh
28503b705cfSriastradhconst char *no_render_init(struct sna *sna)
28603b705cfSriastradh{
28703b705cfSriastradh	struct sna_render *render = &sna->render;
28803b705cfSriastradh
28903b705cfSriastradh	memset (render, 0, sizeof (*render));
29003b705cfSriastradh
29103b705cfSriastradh	render->prefer_gpu = PREFER_GPU_BLT;
29203b705cfSriastradh
29303b705cfSriastradh	render->vertices = render->vertex_data;
29403b705cfSriastradh	render->vertex_size = ARRAY_SIZE(render->vertex_data);
29503b705cfSriastradh
29603b705cfSriastradh	render->composite = no_render_composite;
29703b705cfSriastradh	render->check_composite_spans = no_render_check_composite_spans;
29803b705cfSriastradh
29903b705cfSriastradh	render->copy_boxes = no_render_copy_boxes;
30003b705cfSriastradh	render->copy = no_render_copy;
30103b705cfSriastradh
30203b705cfSriastradh	render->fill_boxes = no_render_fill_boxes;
30303b705cfSriastradh	render->fill = no_render_fill;
30403b705cfSriastradh	render->fill_one = no_render_fill_one;
30503b705cfSriastradh	render->clear = no_render_clear;
30603b705cfSriastradh
30703b705cfSriastradh	render->reset = no_render_reset;
30803b705cfSriastradh	render->flush = no_render_flush;
30903b705cfSriastradh	render->fini = no_render_fini;
31003b705cfSriastradh
31103b705cfSriastradh	sna->kgem.context_switch = no_render_context_switch;
31203b705cfSriastradh	sna->kgem.retire = no_render_retire;
31303b705cfSriastradh	sna->kgem.expire = no_render_expire;
31403b705cfSriastradh	if (sna->kgem.has_blt)
31503b705cfSriastradh		sna->kgem.ring = KGEM_BLT;
31603b705cfSriastradh
31703b705cfSriastradh	sna_vertex_init(sna);
31803b705cfSriastradh	return "generic";
31903b705cfSriastradh}
32003b705cfSriastradh
32103b705cfSriastradhstatic struct kgem_bo *
32203b705cfSriastradhuse_cpu_bo(struct sna *sna, PixmapPtr pixmap, const BoxRec *box, bool blt)
32303b705cfSriastradh{
32403b705cfSriastradh	struct sna_pixmap *priv;
32503b705cfSriastradh
32603b705cfSriastradh	if (DBG_NO_CPU_BO)
32703b705cfSriastradh		return NULL;
32803b705cfSriastradh
32903b705cfSriastradh	priv = sna_pixmap(pixmap);
33003b705cfSriastradh	if (priv == NULL || priv->cpu_bo == NULL) {
33103b705cfSriastradh		DBG(("%s: no cpu bo\n", __FUNCTION__));
33203b705cfSriastradh		return NULL;
33303b705cfSriastradh	}
33403b705cfSriastradh
33503b705cfSriastradh	if (!blt && priv->cpu_bo->snoop && priv->source_count > SOURCE_BIAS) {
33603b705cfSriastradh		DBG(("%s: promoting snooped CPU bo due to reuse\n",
33703b705cfSriastradh		     __FUNCTION__));
33803b705cfSriastradh		return NULL;
33903b705cfSriastradh	}
34003b705cfSriastradh
34103b705cfSriastradh	if (priv->gpu_bo) {
34203b705cfSriastradh		switch (sna_damage_contains_box(priv->cpu_damage, box)) {
34303b705cfSriastradh		case PIXMAN_REGION_OUT:
34403b705cfSriastradh			DBG(("%s: has GPU bo and no damage to upload\n",
34503b705cfSriastradh			     __FUNCTION__));
34603b705cfSriastradh			return NULL;
34703b705cfSriastradh
34803b705cfSriastradh		case PIXMAN_REGION_IN:
34903b705cfSriastradh			DBG(("%s: has GPU bo but box is completely on CPU\n",
35003b705cfSriastradh			     __FUNCTION__));
35103b705cfSriastradh			break;
35203b705cfSriastradh		default:
35303b705cfSriastradh			if (kgem_bo_is_busy(priv->gpu_bo)){
35403b705cfSriastradh				DBG(("%s: box is partially damaged on the CPU, and the GPU is busy\n",
35503b705cfSriastradh				     __FUNCTION__));
35603b705cfSriastradh				return NULL;
35703b705cfSriastradh			}
35803b705cfSriastradh			if (sna_damage_contains_box(priv->gpu_damage,
35903b705cfSriastradh						    box) != PIXMAN_REGION_OUT) {
36003b705cfSriastradh				DBG(("%s: box is damaged on the GPU\n",
36103b705cfSriastradh				     __FUNCTION__));
36203b705cfSriastradh				return NULL;
36303b705cfSriastradh			}
36403b705cfSriastradh			break;
36503b705cfSriastradh		}
36603b705cfSriastradh	}
36703b705cfSriastradh
36803b705cfSriastradh	if (!blt) {
36903b705cfSriastradh		int w = box->x2 - box->x1;
37003b705cfSriastradh		int h = box->y2 - box->y1;
37103b705cfSriastradh
37203b705cfSriastradh		if (w < pixmap->drawable.width ||
37303b705cfSriastradh		    h < pixmap->drawable.height ||
37403b705cfSriastradh		    priv->source_count != SOURCE_BIAS) {
37503b705cfSriastradh			bool want_tiling;
37603b705cfSriastradh
37703b705cfSriastradh			if (priv->cpu_bo->pitch >= 4096) {
37803b705cfSriastradh				DBG(("%s: size=%dx%d, promoting reused (%d) CPU bo due to TLB miss (%dx%d, pitch=%d)\n",
37903b705cfSriastradh				     __FUNCTION__, w, h, priv->source_count,
38003b705cfSriastradh				     pixmap->drawable.width,
38103b705cfSriastradh				     pixmap->drawable.height,
38203b705cfSriastradh				     priv->cpu_bo->pitch));
38303b705cfSriastradh				return NULL;
38403b705cfSriastradh			}
38503b705cfSriastradh
38603b705cfSriastradh			if (priv->gpu_bo)
38703b705cfSriastradh				want_tiling = priv->gpu_bo->tiling != I915_TILING_NONE;
38803b705cfSriastradh			else
38903b705cfSriastradh				want_tiling = kgem_choose_tiling(&sna->kgem,
39003b705cfSriastradh								 I915_TILING_Y,
39103b705cfSriastradh								 pixmap->drawable.width,
39203b705cfSriastradh								 pixmap->drawable.height,
39303b705cfSriastradh								 pixmap->drawable.bitsPerPixel) != I915_TILING_NONE;
39403b705cfSriastradh			if (want_tiling &&
39503b705cfSriastradh			    priv->source_count*w*h >= (int)pixmap->drawable.width * pixmap->drawable.height) {
39603b705cfSriastradh				DBG(("%s: pitch (%d) requires tiling\n",
39703b705cfSriastradh				     __FUNCTION__, priv->cpu_bo->pitch));
39803b705cfSriastradh				return NULL;
39903b705cfSriastradh			}
40003b705cfSriastradh		}
40103b705cfSriastradh	}
40203b705cfSriastradh
40303b705cfSriastradh	if (priv->shm) {
40403b705cfSriastradh		assert(!priv->flush);
40503b705cfSriastradh		sna_add_flush_pixmap(sna, priv, priv->cpu_bo);
40603b705cfSriastradh	}
40703b705cfSriastradh
40803b705cfSriastradh	DBG(("%s for box=(%d, %d), (%d, %d)\n",
40903b705cfSriastradh	     __FUNCTION__, box->x1, box->y1, box->x2, box->y2));
41003b705cfSriastradh	++priv->source_count;
41103b705cfSriastradh	return priv->cpu_bo;
41203b705cfSriastradh}
41303b705cfSriastradh
41403b705cfSriastradhstatic struct kgem_bo *
41503b705cfSriastradhmove_to_gpu(PixmapPtr pixmap, const BoxRec *box, bool blt)
41603b705cfSriastradh{
41703b705cfSriastradh	struct sna_pixmap *priv;
41803b705cfSriastradh	int count, w, h;
41903b705cfSriastradh	bool migrate = false;
42003b705cfSriastradh
42103b705cfSriastradh	if (DBG_FORCE_UPLOAD > 0)
42203b705cfSriastradh		return NULL;
42303b705cfSriastradh
42403b705cfSriastradh	priv = sna_pixmap(pixmap);
42503b705cfSriastradh	if (priv == NULL) {
42603b705cfSriastradh		DBG(("%s: not migrating unattached pixmap\n",
42703b705cfSriastradh		     __FUNCTION__));
42803b705cfSriastradh		return NULL;
42903b705cfSriastradh	}
43003b705cfSriastradh
43103b705cfSriastradh	if (priv->shm)
43203b705cfSriastradh		blt = true;
43303b705cfSriastradh
43403b705cfSriastradh	if (priv->gpu_bo) {
43503b705cfSriastradh		if (priv->cpu_damage &&
43603b705cfSriastradh		    sna_damage_contains_box(priv->cpu_damage,
43703b705cfSriastradh					    box) != PIXMAN_REGION_OUT)
43803b705cfSriastradh			goto upload;
43903b705cfSriastradh
44003b705cfSriastradh		return priv->gpu_bo;
44103b705cfSriastradh	}
44203b705cfSriastradh
44303b705cfSriastradh	if (priv->cpu_damage == NULL) {
44403b705cfSriastradh		DBG(("%s: not migrating uninitialised pixmap\n",
44503b705cfSriastradh		     __FUNCTION__));
44603b705cfSriastradh		return NULL;
44703b705cfSriastradh	}
44803b705cfSriastradh
44903b705cfSriastradh	if (pixmap->usage_hint) {
45003b705cfSriastradh		DBG(("%s: not migrating pixmap due to usage_hint=%d\n",
45103b705cfSriastradh		     __FUNCTION__, pixmap->usage_hint));
45203b705cfSriastradh		return NULL;
45303b705cfSriastradh	}
45403b705cfSriastradh
45503b705cfSriastradh	if (DBG_FORCE_UPLOAD < 0) {
45603b705cfSriastradh		if (!sna_pixmap_force_to_gpu(pixmap,
45703b705cfSriastradh					     blt ? MOVE_READ : MOVE_SOURCE_HINT | MOVE_READ))
45803b705cfSriastradh			return NULL;
45903b705cfSriastradh
46003b705cfSriastradh		return priv->gpu_bo;
46103b705cfSriastradh	}
46203b705cfSriastradh
46303b705cfSriastradh	w = box->x2 - box->x1;
46403b705cfSriastradh	h = box->y2 - box->y1;
46503b705cfSriastradh	if (priv->cpu_bo && !priv->cpu_bo->flush) {
46603b705cfSriastradh		migrate = true;
46703b705cfSriastradh	} else if (w == pixmap->drawable.width && h == pixmap->drawable.height) {
46803b705cfSriastradh		migrate = priv->source_count++ > SOURCE_BIAS;
46903b705cfSriastradh
47003b705cfSriastradh		DBG(("%s: migrating whole pixmap (%dx%d) for source (%d,%d),(%d,%d), count %d? %d\n",
47103b705cfSriastradh		     __FUNCTION__,
47203b705cfSriastradh		     pixmap->drawable.width, pixmap->drawable.height,
47303b705cfSriastradh		     box->x1, box->y1, box->x2, box->y2, priv->source_count,
47403b705cfSriastradh		     migrate));
47503b705cfSriastradh	} else if (kgem_choose_tiling(&to_sna_from_pixmap(pixmap)->kgem,
47603b705cfSriastradh				      blt ? I915_TILING_X : I915_TILING_Y, w, h,
47703b705cfSriastradh				      pixmap->drawable.bitsPerPixel) != I915_TILING_NONE) {
47803b705cfSriastradh		count = priv->source_count++;
47903b705cfSriastradh		if ((priv->create & KGEM_CAN_CREATE_GPU) == 0)
48003b705cfSriastradh			count -= SOURCE_BIAS;
48103b705cfSriastradh
48203b705cfSriastradh		DBG(("%s: migrate box (%d, %d), (%d, %d)? source count=%d, fraction=%d/%d [%d]\n",
48303b705cfSriastradh		     __FUNCTION__,
48403b705cfSriastradh		     box->x1, box->y1, box->x2, box->y2,
48503b705cfSriastradh		     count, w*h,
48603b705cfSriastradh		     pixmap->drawable.width * pixmap->drawable.height,
48703b705cfSriastradh		     pixmap->drawable.width * pixmap->drawable.height / (w*h)));
48803b705cfSriastradh
48903b705cfSriastradh		migrate = count*w*h > pixmap->drawable.width * pixmap->drawable.height;
49003b705cfSriastradh	}
49103b705cfSriastradh
49203b705cfSriastradh	if (!migrate)
49303b705cfSriastradh		return NULL;
49403b705cfSriastradh
49503b705cfSriastradhupload:
49603b705cfSriastradh	if (blt) {
49703b705cfSriastradh		if (!sna_pixmap_move_area_to_gpu(pixmap, box,
49803b705cfSriastradh						 __MOVE_FORCE | MOVE_READ))
49903b705cfSriastradh			return NULL;
50003b705cfSriastradh	} else {
50103b705cfSriastradh		if (!sna_pixmap_move_to_gpu(pixmap,
50203b705cfSriastradh					    __MOVE_FORCE | MOVE_SOURCE_HINT | MOVE_READ))
50303b705cfSriastradh			return NULL;
50403b705cfSriastradh	}
50503b705cfSriastradh
50603b705cfSriastradh	return priv->gpu_bo;
50703b705cfSriastradh}
50803b705cfSriastradh
50903b705cfSriastradhstatic struct kgem_bo *upload(struct sna *sna,
51003b705cfSriastradh			      struct sna_composite_channel *channel,
51103b705cfSriastradh			      PixmapPtr pixmap,
51203b705cfSriastradh			      const BoxRec *box)
51303b705cfSriastradh{
51403b705cfSriastradh	struct sna_pixmap *priv;
51503b705cfSriastradh	struct kgem_bo *bo;
51603b705cfSriastradh
51703b705cfSriastradh	DBG(("%s: box=(%d, %d), (%d, %d), pixmap=%dx%d\n",
51803b705cfSriastradh	     __FUNCTION__, box->x1, box->y1, box->x2, box->y2, pixmap->drawable.width, pixmap->drawable.height));
51903b705cfSriastradh	assert(box->x1 >= 0);
52003b705cfSriastradh	assert(box->y1 >= 0);
52103b705cfSriastradh	assert(box->x2 <= pixmap->drawable.width);
52203b705cfSriastradh	assert(box->y2 <= pixmap->drawable.height);
52303b705cfSriastradh
52403b705cfSriastradh	priv = sna_pixmap(pixmap);
52503b705cfSriastradh	if (priv) {
52603b705cfSriastradh		RegionRec region;
52703b705cfSriastradh
52803b705cfSriastradh		if (priv->cpu_damage == NULL)
52903b705cfSriastradh			return NULL; /* uninitialised */
53003b705cfSriastradh
53103b705cfSriastradh		region.extents = *box;
53203b705cfSriastradh		region.data = NULL;
53303b705cfSriastradh		if (!sna_drawable_move_region_to_cpu(&pixmap->drawable,
53403b705cfSriastradh						     &region, MOVE_READ))
53503b705cfSriastradh			return NULL;
53603b705cfSriastradh
53703b705cfSriastradh		assert(!priv->mapped);
53803b705cfSriastradh		if (pixmap->devPrivate.ptr == NULL)
53903b705cfSriastradh			return NULL; /* uninitialised */
54003b705cfSriastradh	}
54103b705cfSriastradh
54203b705cfSriastradh	bo = kgem_upload_source_image(&sna->kgem,
54303b705cfSriastradh				      pixmap->devPrivate.ptr, box,
54403b705cfSriastradh				      pixmap->devKind,
54503b705cfSriastradh				      pixmap->drawable.bitsPerPixel);
54603b705cfSriastradh	if (channel && bo) {
54703b705cfSriastradh		channel->width  = box->x2 - box->x1;
54803b705cfSriastradh		channel->height = box->y2 - box->y1;
54903b705cfSriastradh		channel->offset[0] -= box->x1;
55003b705cfSriastradh		channel->offset[1] -= box->y1;
55103b705cfSriastradh
55203b705cfSriastradh		if (priv &&
55303b705cfSriastradh		    pixmap->usage_hint == 0 &&
55403b705cfSriastradh		    channel->width  == pixmap->drawable.width &&
55503b705cfSriastradh		    channel->height == pixmap->drawable.height) {
55603b705cfSriastradh			DBG(("%s: adding upload cache to pixmap=%ld\n",
55703b705cfSriastradh			     __FUNCTION__, pixmap->drawable.serialNumber));
55803b705cfSriastradh			assert(priv->gpu_damage == NULL);
55903b705cfSriastradh			assert(priv->gpu_bo == NULL);
56003b705cfSriastradh			assert(bo->proxy != NULL);
56103b705cfSriastradh			kgem_proxy_bo_attach(bo, &priv->gpu_bo);
56203b705cfSriastradh		}
56303b705cfSriastradh	}
56403b705cfSriastradh
56503b705cfSriastradh	return bo;
56603b705cfSriastradh}
56703b705cfSriastradh
56803b705cfSriastradhstruct kgem_bo *
56903b705cfSriastradh__sna_render_pixmap_bo(struct sna *sna,
57003b705cfSriastradh		       PixmapPtr pixmap,
57103b705cfSriastradh		       const BoxRec *box,
57203b705cfSriastradh		       bool blt)
57303b705cfSriastradh{
57403b705cfSriastradh	struct kgem_bo *bo;
57503b705cfSriastradh
57603b705cfSriastradh	bo = use_cpu_bo(sna, pixmap, box, blt);
57703b705cfSriastradh	if (bo == NULL) {
57803b705cfSriastradh		bo = move_to_gpu(pixmap, box, blt);
57903b705cfSriastradh		if (bo == NULL)
58003b705cfSriastradh			return NULL;
58103b705cfSriastradh	}
58203b705cfSriastradh
58303b705cfSriastradh	return bo;
58403b705cfSriastradh}
58503b705cfSriastradh
58603b705cfSriastradhint
58703b705cfSriastradhsna_render_pixmap_bo(struct sna *sna,
58803b705cfSriastradh		     struct sna_composite_channel *channel,
58903b705cfSriastradh		     PixmapPtr pixmap,
59003b705cfSriastradh		     int16_t x, int16_t y,
59103b705cfSriastradh		     int16_t w, int16_t h,
59203b705cfSriastradh		     int16_t dst_x, int16_t dst_y)
59303b705cfSriastradh{
59403b705cfSriastradh	struct sna_pixmap *priv;
59503b705cfSriastradh	BoxRec box;
59603b705cfSriastradh
59703b705cfSriastradh	DBG(("%s pixmap=%ld, (%d, %d)x(%d, %d)/(%d, %d)\n",
59803b705cfSriastradh	     __FUNCTION__, pixmap->drawable.serialNumber,
59903b705cfSriastradh	     x, y, w,h, pixmap->drawable.width, pixmap->drawable.height));
60003b705cfSriastradh
60103b705cfSriastradh	channel->width  = pixmap->drawable.width;
60203b705cfSriastradh	channel->height = pixmap->drawable.height;
60303b705cfSriastradh	channel->offset[0] = x - dst_x;
60403b705cfSriastradh	channel->offset[1] = y - dst_y;
60503b705cfSriastradh
60603b705cfSriastradh	priv = sna_pixmap(pixmap);
60703b705cfSriastradh	if (priv) {
60803b705cfSriastradh		if (priv->gpu_bo &&
60903b705cfSriastradh		    (DAMAGE_IS_ALL(priv->gpu_damage) || !priv->cpu_damage ||
61003b705cfSriastradh		     priv->gpu_bo->proxy)) {
61103b705cfSriastradh			DBG(("%s: GPU all damaged\n", __FUNCTION__));
61203b705cfSriastradh			channel->bo = priv->gpu_bo;
61303b705cfSriastradh			goto done;
61403b705cfSriastradh		}
61503b705cfSriastradh
61603b705cfSriastradh		if (priv->cpu_bo &&
61703b705cfSriastradh		    (DAMAGE_IS_ALL(priv->cpu_damage) || !priv->gpu_damage) &&
61803b705cfSriastradh		    !priv->cpu_bo->snoop && priv->cpu_bo->pitch < 4096) {
61903b705cfSriastradh			DBG(("%s: CPU all damaged\n", __FUNCTION__));
62003b705cfSriastradh			channel->bo = priv->cpu_bo;
62103b705cfSriastradh			if (priv->shm) {
62203b705cfSriastradh				assert(!priv->flush);
62303b705cfSriastradh				sna_add_flush_pixmap(sna, priv, priv->cpu_bo);
62403b705cfSriastradh			}
62503b705cfSriastradh			goto done;
62603b705cfSriastradh		}
62703b705cfSriastradh	}
62803b705cfSriastradh
62903b705cfSriastradh	/* XXX handle transformed repeat */
63003b705cfSriastradh	if (w == 0 || h == 0 || channel->transform) {
63103b705cfSriastradh		box.x1 = box.y1 = 0;
63203b705cfSriastradh		box.x2 = pixmap->drawable.width;
63303b705cfSriastradh		box.y2 = pixmap->drawable.height;
63403b705cfSriastradh	} else {
63503b705cfSriastradh		box.x1 = x;
63603b705cfSriastradh		box.y1 = y;
63703b705cfSriastradh		box.x2 = bound(x, w);
63803b705cfSriastradh		box.y2 = bound(y, h);
63903b705cfSriastradh
64003b705cfSriastradh		if (channel->repeat == RepeatNone || channel->repeat == RepeatPad) {
64103b705cfSriastradh			if (box.x1 < 0)
64203b705cfSriastradh				box.x1 = 0;
64303b705cfSriastradh			if (box.y1 < 0)
64403b705cfSriastradh				box.y1 = 0;
64503b705cfSriastradh			if (box.x2 > pixmap->drawable.width)
64603b705cfSriastradh				box.x2 = pixmap->drawable.width;
64703b705cfSriastradh			if (box.y2 > pixmap->drawable.height)
64803b705cfSriastradh				box.y2 = pixmap->drawable.height;
64903b705cfSriastradh		} else {
65003b705cfSriastradh			if (box.x1 < 0 || box.x2 > pixmap->drawable.width)
65103b705cfSriastradh				box.x1 = 0, box.x2 = pixmap->drawable.width;
65203b705cfSriastradh			if (box.y1 < 0 || box.y2 > pixmap->drawable.height)
65303b705cfSriastradh				box.y1 = 0, box.y2 = pixmap->drawable.height;
65403b705cfSriastradh		}
65503b705cfSriastradh	}
65603b705cfSriastradh
65703b705cfSriastradh	w = box.x2 - box.x1;
65803b705cfSriastradh	h = box.y2 - box.y1;
65903b705cfSriastradh	DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d)\n", __FUNCTION__,
66003b705cfSriastradh	     box.x1, box.y1, box.x2, box.y2, w, h,
66103b705cfSriastradh	     pixmap->drawable.width, pixmap->drawable.height));
66203b705cfSriastradh	if (w <= 0 || h <= 0) {
66303b705cfSriastradh		DBG(("%s: sample extents outside of texture -> clear\n",
66403b705cfSriastradh		     __FUNCTION__));
66503b705cfSriastradh		return 0;
66603b705cfSriastradh	}
66703b705cfSriastradh
66803b705cfSriastradh	DBG(("%s: offset=(%d, %d), size=(%d, %d)\n",
66903b705cfSriastradh	     __FUNCTION__,
67003b705cfSriastradh	     channel->offset[0], channel->offset[1],
67103b705cfSriastradh	     pixmap->drawable.width, pixmap->drawable.height));
67203b705cfSriastradh
67303b705cfSriastradh	channel->bo = __sna_render_pixmap_bo(sna, pixmap, &box, false);
67403b705cfSriastradh	if (channel->bo == NULL) {
67503b705cfSriastradh		DBG(("%s: uploading CPU box (%d, %d), (%d, %d)\n",
67603b705cfSriastradh		     __FUNCTION__, box.x1, box.y1, box.x2, box.y2));
67703b705cfSriastradh		channel->bo = upload(sna, channel, pixmap, &box);
67803b705cfSriastradh		if (channel->bo == NULL)
67903b705cfSriastradh			return 0;
68003b705cfSriastradh	} else {
68103b705cfSriastradhdone:
68203b705cfSriastradh		kgem_bo_reference(channel->bo);
68303b705cfSriastradh	}
68403b705cfSriastradh
68503b705cfSriastradh	channel->scale[0] = 1.f / channel->width;
68603b705cfSriastradh	channel->scale[1] = 1.f / channel->height;
68703b705cfSriastradh	return 1;
68803b705cfSriastradh}
68903b705cfSriastradh
69003b705cfSriastradhstatic int sna_render_picture_downsample(struct sna *sna,
69103b705cfSriastradh					 PicturePtr picture,
69203b705cfSriastradh					 struct sna_composite_channel *channel,
69303b705cfSriastradh					 const int16_t x, const int16_t y,
69403b705cfSriastradh					 const int16_t w, const int16_t h,
69503b705cfSriastradh					 const int16_t dst_x, const int16_t dst_y)
69603b705cfSriastradh{
69703b705cfSriastradh	PixmapPtr pixmap = get_drawable_pixmap(picture->pDrawable);
69803b705cfSriastradh	ScreenPtr screen = pixmap->drawable.pScreen;
69903b705cfSriastradh	PicturePtr tmp_src, tmp_dst;
70003b705cfSriastradh	PictFormatPtr format;
70103b705cfSriastradh	struct sna_pixmap *priv;
70203b705cfSriastradh	pixman_transform_t t;
70303b705cfSriastradh	PixmapPtr tmp;
70403b705cfSriastradh	int width, height, size;
70503b705cfSriastradh	int sx, sy, sw, sh;
70603b705cfSriastradh	int error, ret = 0;
70703b705cfSriastradh	BoxRec box, b;
70803b705cfSriastradh
70903b705cfSriastradh	box.x1 = x;
71003b705cfSriastradh	box.y1 = y;
71103b705cfSriastradh	box.x2 = bound(x, w);
71203b705cfSriastradh	box.y2 = bound(y, h);
71303b705cfSriastradh	if (channel->transform) {
71403b705cfSriastradh		pixman_vector_t v;
71503b705cfSriastradh
71603b705cfSriastradh		pixman_transform_bounds(channel->transform, &box);
71703b705cfSriastradh
71803b705cfSriastradh		v.vector[0] = x << 16;
71903b705cfSriastradh		v.vector[1] = y << 16;
72003b705cfSriastradh		v.vector[2] = 1 << 16;
72103b705cfSriastradh		pixman_transform_point(channel->transform, &v);
72203b705cfSriastradh	}
72303b705cfSriastradh
72403b705cfSriastradh	if (channel->repeat == RepeatNone || channel->repeat == RepeatPad) {
72503b705cfSriastradh		if (box.x1 < 0)
72603b705cfSriastradh			box.x1 = 0;
72703b705cfSriastradh		if (box.y1 < 0)
72803b705cfSriastradh			box.y1 = 0;
72903b705cfSriastradh		if (box.x2 > pixmap->drawable.width)
73003b705cfSriastradh			box.x2 = pixmap->drawable.width;
73103b705cfSriastradh		if (box.y2 > pixmap->drawable.height)
73203b705cfSriastradh			box.y2 = pixmap->drawable.height;
73303b705cfSriastradh	} else {
73403b705cfSriastradh		/* XXX tiled repeats? */
73503b705cfSriastradh		if (box.x1 < 0 || box.x2 > pixmap->drawable.width)
73603b705cfSriastradh			box.x1 = 0, box.x2 = pixmap->drawable.width;
73703b705cfSriastradh		if (box.y1 < 0 || box.y2 > pixmap->drawable.height)
73803b705cfSriastradh			box.y1 = 0, box.y2 = pixmap->drawable.height;
73903b705cfSriastradh
74003b705cfSriastradh	}
74103b705cfSriastradh
74203b705cfSriastradh	sw = box.x2 - box.x1;
74303b705cfSriastradh	sh = box.y2 - box.y1;
74403b705cfSriastradh
74503b705cfSriastradh	DBG(("%s: sample (%d, %d), (%d, %d)\n",
74603b705cfSriastradh	     __FUNCTION__, box.x1, box.y1, box.x2, box.y2));
74703b705cfSriastradh
74803b705cfSriastradh	sx = (sw + sna->render.max_3d_size - 1) / sna->render.max_3d_size;
74903b705cfSriastradh	sy = (sh + sna->render.max_3d_size - 1) / sna->render.max_3d_size;
75003b705cfSriastradh
75103b705cfSriastradh	DBG(("%s: scaling (%d, %d) down by %dx%d\n",
75203b705cfSriastradh	     __FUNCTION__, sw, sh, sx, sy));
75303b705cfSriastradh
75403b705cfSriastradh	width  = sw / sx;
75503b705cfSriastradh	height = sh / sy;
75603b705cfSriastradh
75703b705cfSriastradh	DBG(("%s: creating temporary GPU bo %dx%d\n",
75803b705cfSriastradh	     __FUNCTION__, width, height));
75903b705cfSriastradh
76003b705cfSriastradh	if (!sna_pixmap_force_to_gpu(pixmap, MOVE_SOURCE_HINT | MOVE_READ))
76103b705cfSriastradh		return sna_render_picture_fixup(sna, picture, channel,
76203b705cfSriastradh						x, y, w, h,
76303b705cfSriastradh						dst_x, dst_y);
76403b705cfSriastradh
76503b705cfSriastradh	tmp = screen->CreatePixmap(screen,
76603b705cfSriastradh				   width, height,
76703b705cfSriastradh				   pixmap->drawable.depth,
76803b705cfSriastradh				   SNA_CREATE_SCRATCH);
76903b705cfSriastradh	if (!tmp)
77003b705cfSriastradh		return 0;
77103b705cfSriastradh
77203b705cfSriastradh	priv = sna_pixmap(tmp);
77303b705cfSriastradh	if (!priv)
77403b705cfSriastradh		goto cleanup_tmp;
77503b705cfSriastradh
77603b705cfSriastradh	format = PictureMatchFormat(screen,
77703b705cfSriastradh				    pixmap->drawable.depth,
77803b705cfSriastradh				    picture->format);
77903b705cfSriastradh
78003b705cfSriastradh	tmp_dst = CreatePicture(0, &tmp->drawable, format, 0, NULL,
78103b705cfSriastradh				serverClient, &error);
78203b705cfSriastradh	if (!tmp_dst)
78303b705cfSriastradh		goto cleanup_tmp;
78403b705cfSriastradh
78503b705cfSriastradh	tmp_src = CreatePicture(0, &pixmap->drawable, format, 0, NULL,
78603b705cfSriastradh				serverClient, &error);
78703b705cfSriastradh	if (!tmp_src)
78803b705cfSriastradh		goto cleanup_dst;
78903b705cfSriastradh
79003b705cfSriastradh	tmp_src->repeat = 1;
79103b705cfSriastradh	tmp_src->repeatType = RepeatPad;
79203b705cfSriastradh	/* Prefer to use nearest as it helps reduce artefacts from
79303b705cfSriastradh	 * interpolating and filtering twice.
79403b705cfSriastradh	 */
79503b705cfSriastradh	tmp_src->filter = PictFilterNearest;
79603b705cfSriastradh	memset(&t, 0, sizeof(t));
79703b705cfSriastradh	t.matrix[0][0] = (sw << 16) / width;
79803b705cfSriastradh	t.matrix[0][2] = box.x1 << 16;
79903b705cfSriastradh	t.matrix[1][1] = (sh << 16) / height;
80003b705cfSriastradh	t.matrix[1][2] = box.y1 << 16;
80103b705cfSriastradh	t.matrix[2][2] = 1 << 16;
80203b705cfSriastradh	tmp_src->transform = &t;
80303b705cfSriastradh
80403b705cfSriastradh	ValidatePicture(tmp_dst);
80503b705cfSriastradh	ValidatePicture(tmp_src);
80603b705cfSriastradh
80703b705cfSriastradh	/* Use a small size to accommodate enlargement through tile alignment */
80803b705cfSriastradh	size = sna->render.max_3d_size - 4096 / pixmap->drawable.bitsPerPixel;
80903b705cfSriastradh	while (size * size * 4 > sna->kgem.max_copy_tile_size)
81003b705cfSriastradh		size /= 2;
81103b705cfSriastradh
81203b705cfSriastradh	sw = size / sx - 2 * sx;
81303b705cfSriastradh	sh = size / sy - 2 * sy;
81403b705cfSriastradh	DBG(("%s %d:%d downsampling using %dx%d GPU tiles\n",
81503b705cfSriastradh	     __FUNCTION__, (width + sw-1)/sw, (height + sh-1)/sh, sw, sh));
81603b705cfSriastradh
81703b705cfSriastradh	for (b.y1 = 0; b.y1 < height; b.y1 = b.y2) {
81803b705cfSriastradh		b.y2 = b.y1 + sh;
81903b705cfSriastradh		if (b.y2 > height)
82003b705cfSriastradh			b.y2 = height;
82103b705cfSriastradh
82203b705cfSriastradh		for (b.x1 = 0; b.x1 < width; b.x1 = b.x2) {
82303b705cfSriastradh			struct sna_composite_op op;
82403b705cfSriastradh
82503b705cfSriastradh			b.x2 = b.x1 + sw;
82603b705cfSriastradh			if (b.x2 > width)
82703b705cfSriastradh				b.x2 = width;
82803b705cfSriastradh
82903b705cfSriastradh			DBG(("%s: tile (%d, %d), (%d, %d)\n",
83003b705cfSriastradh			     __FUNCTION__, b.x1, b.y1, b.x2, b.y2));
83103b705cfSriastradh
83203b705cfSriastradh			memset(&op, 0, sizeof(op));
83303b705cfSriastradh			if (!sna->render.composite(sna,
83403b705cfSriastradh						   PictOpSrc,
83503b705cfSriastradh						   tmp_src, NULL, tmp_dst,
83603b705cfSriastradh						   b.x1, b.y1,
83703b705cfSriastradh						   0, 0,
83803b705cfSriastradh						   b.x1, b.y1,
83903b705cfSriastradh						   b.x2 - b.x1, b.y2 - b.y1,
84003b705cfSriastradh						   &op))
84103b705cfSriastradh				goto cleanup_src;
84203b705cfSriastradh
84303b705cfSriastradh			op.box(sna, &op, &b);
84403b705cfSriastradh			op.done(sna, &op);
84503b705cfSriastradh		}
84603b705cfSriastradh	}
84703b705cfSriastradh
84803b705cfSriastradh	pixman_transform_invert(&channel->embedded_transform, &t);
84903b705cfSriastradh	if (channel->transform)
85003b705cfSriastradh		pixman_transform_multiply(&channel->embedded_transform,
85103b705cfSriastradh					  &channel->embedded_transform,
85203b705cfSriastradh					  channel->transform);
85303b705cfSriastradh	channel->transform = &channel->embedded_transform;
85403b705cfSriastradh
85503b705cfSriastradh	channel->offset[0] = x - dst_x;
85603b705cfSriastradh	channel->offset[1] = y - dst_y;
85703b705cfSriastradh	channel->scale[0] = 1.f/width;
85803b705cfSriastradh	channel->scale[1] = 1.f/height;
85903b705cfSriastradh	channel->width  = width;
86003b705cfSriastradh	channel->height = height;
86103b705cfSriastradh	channel->bo = kgem_bo_reference(priv->gpu_bo);
86203b705cfSriastradh
86303b705cfSriastradh	ret = 1;
86403b705cfSriastradhcleanup_src:
86503b705cfSriastradh	tmp_src->transform = NULL;
86603b705cfSriastradh	FreePicture(tmp_src, 0);
86703b705cfSriastradhcleanup_dst:
86803b705cfSriastradh	FreePicture(tmp_dst, 0);
86903b705cfSriastradhcleanup_tmp:
87003b705cfSriastradh	screen->DestroyPixmap(tmp);
87103b705cfSriastradh	return ret;
87203b705cfSriastradh}
87303b705cfSriastradh
87403b705cfSriastradhbool
87503b705cfSriastradhsna_render_pixmap_partial(struct sna *sna,
87603b705cfSriastradh			  PixmapPtr pixmap,
87703b705cfSriastradh			  struct kgem_bo *bo,
87803b705cfSriastradh			  struct sna_composite_channel *channel,
87903b705cfSriastradh			  int16_t x, int16_t y,
88003b705cfSriastradh			  int16_t w, int16_t h)
88103b705cfSriastradh{
88203b705cfSriastradh	BoxRec box;
88303b705cfSriastradh	int offset;
88403b705cfSriastradh
88503b705cfSriastradh	DBG(("%s (%d, %d)x(%d, %d), pitch %d, max %d\n",
88603b705cfSriastradh	     __FUNCTION__, x, y, w, h, bo->pitch, sna->render.max_3d_pitch));
88703b705cfSriastradh
88803b705cfSriastradh	if (bo->pitch > sna->render.max_3d_pitch)
88903b705cfSriastradh		return false;
89003b705cfSriastradh
89103b705cfSriastradh	box.x1 = x;
89203b705cfSriastradh	box.y1 = y;
89303b705cfSriastradh	box.x2 = bound(x, w);
89403b705cfSriastradh	box.y2 = bound(y, h);
89503b705cfSriastradh	DBG(("%s: unaligned box (%d, %d), (%d, %d)\n",
89603b705cfSriastradh	     __FUNCTION__, box.x1, box.y1, box.x2, box.y2));
89703b705cfSriastradh
89803b705cfSriastradh	if (box.x1 < 0)
89903b705cfSriastradh		box.x1 = 0;
90003b705cfSriastradh	if (box.y1 < 0)
90103b705cfSriastradh		box.y1 = 0;
90203b705cfSriastradh
90303b705cfSriastradh	if (bo->tiling) {
90403b705cfSriastradh		int tile_width, tile_height, tile_size;
90503b705cfSriastradh
90603b705cfSriastradh		kgem_get_tile_size(&sna->kgem, bo->tiling,
90703b705cfSriastradh				   &tile_width, &tile_height, &tile_size);
90803b705cfSriastradh		DBG(("%s: tile size for tiling %d: %dx%d, size=%d\n",
90903b705cfSriastradh		     __FUNCTION__, bo->tiling, tile_width, tile_height, tile_size));
91003b705cfSriastradh
91103b705cfSriastradh		if (sna->kgem.gen < 033)
91203b705cfSriastradh			tile_width = bo->pitch;
91303b705cfSriastradh
91403b705cfSriastradh		/* Ensure we align to an even tile row */
91503b705cfSriastradh		box.y1 = box.y1 & ~(2*tile_height - 1);
91603b705cfSriastradh		box.y2 = ALIGN(box.y2, 2*tile_height);
91703b705cfSriastradh
91803b705cfSriastradh		assert(tile_width * 8 >= pixmap->drawable.bitsPerPixel);
91903b705cfSriastradh		box.x1 = box.x1 & ~(tile_width * 8 / pixmap->drawable.bitsPerPixel - 1);
92003b705cfSriastradh		box.x2 = ALIGN(box.x2, tile_width * 8 / pixmap->drawable.bitsPerPixel);
92103b705cfSriastradh
92203b705cfSriastradh		offset = box.x1 * pixmap->drawable.bitsPerPixel / 8 / tile_width * tile_size;
92303b705cfSriastradh	} else {
92403b705cfSriastradh		box.y1 = box.y1 & ~1;
92503b705cfSriastradh		box.y2 = ALIGN(box.y2, 2);
92603b705cfSriastradh
92703b705cfSriastradh		box.x1 = box.x1 & ~1;
92803b705cfSriastradh		box.x2 = ALIGN(box.x2, 2);
92903b705cfSriastradh
93003b705cfSriastradh		offset = box.x1 * pixmap->drawable.bitsPerPixel / 8;
93103b705cfSriastradh	}
93203b705cfSriastradh
93303b705cfSriastradh	if (box.x2 > pixmap->drawable.width)
93403b705cfSriastradh		box.x2 = pixmap->drawable.width;
93503b705cfSriastradh	if (box.y2 > pixmap->drawable.height)
93603b705cfSriastradh		box.y2 = pixmap->drawable.height;
93703b705cfSriastradh
93803b705cfSriastradh	w = box.x2 - box.x1;
93903b705cfSriastradh	h = box.y2 - box.y1;
94003b705cfSriastradh	DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d)\n", __FUNCTION__,
94103b705cfSriastradh	     box.x1, box.y1, box.x2, box.y2, w, h,
94203b705cfSriastradh	     pixmap->drawable.width, pixmap->drawable.height));
94303b705cfSriastradh	if (w <= 0 || h <= 0 ||
94403b705cfSriastradh	    w > sna->render.max_3d_size ||
94503b705cfSriastradh	    h > sna->render.max_3d_size) {
94603b705cfSriastradh		DBG(("%s: box too large (%dx%d) for 3D pipeline (max %d)\n",
94703b705cfSriastradh		    __FUNCTION__, w, h, sna->render.max_3d_size));
94803b705cfSriastradh		return false;
94903b705cfSriastradh	}
95003b705cfSriastradh
95103b705cfSriastradh	/* How many tiles across are we? */
95203b705cfSriastradh	channel->bo = kgem_create_proxy(&sna->kgem, bo,
95303b705cfSriastradh					box.y1 * bo->pitch + offset,
95403b705cfSriastradh					h * bo->pitch);
95503b705cfSriastradh	if (channel->bo == NULL)
95603b705cfSriastradh		return false;
95703b705cfSriastradh
95803b705cfSriastradh	channel->bo->pitch = bo->pitch;
95903b705cfSriastradh
96003b705cfSriastradh	channel->offset[0] = -box.x1;
96103b705cfSriastradh	channel->offset[1] = -box.y1;
96203b705cfSriastradh	channel->scale[0] = 1.f/w;
96303b705cfSriastradh	channel->scale[1] = 1.f/h;
96403b705cfSriastradh	channel->width  = w;
96503b705cfSriastradh	channel->height = h;
96603b705cfSriastradh	return true;
96703b705cfSriastradh}
96803b705cfSriastradh
96903b705cfSriastradhstatic int
97003b705cfSriastradhsna_render_picture_partial(struct sna *sna,
97103b705cfSriastradh			   PicturePtr picture,
97203b705cfSriastradh			   struct sna_composite_channel *channel,
97303b705cfSriastradh			   int16_t x, int16_t y,
97403b705cfSriastradh			   int16_t w, int16_t h,
97503b705cfSriastradh			   int16_t dst_x, int16_t dst_y)
97603b705cfSriastradh{
97703b705cfSriastradh	struct kgem_bo *bo = NULL;
97803b705cfSriastradh	PixmapPtr pixmap = get_drawable_pixmap(picture->pDrawable);
97903b705cfSriastradh	BoxRec box;
98003b705cfSriastradh	int offset;
98103b705cfSriastradh
98203b705cfSriastradh	DBG(("%s (%d, %d)x(%d, %d) [dst=(%d, %d)]\n",
98303b705cfSriastradh	     __FUNCTION__, x, y, w, h, dst_x, dst_y));
98403b705cfSriastradh
98503b705cfSriastradh	box.x1 = x;
98603b705cfSriastradh	box.y1 = y;
98703b705cfSriastradh	box.x2 = bound(x, w);
98803b705cfSriastradh	box.y2 = bound(y, h);
98903b705cfSriastradh	if (channel->transform)
99003b705cfSriastradh		pixman_transform_bounds(channel->transform, &box);
99103b705cfSriastradh
99203b705cfSriastradh	DBG(("%s sample=(%d, %d), (%d, %d): (%d, %d)/(%d, %d), repeat=%d\n", __FUNCTION__,
99303b705cfSriastradh	     box.x1, box.y1, box.x2, box.y2, w, h,
99403b705cfSriastradh	     pixmap->drawable.width, pixmap->drawable.height,
99503b705cfSriastradh	     channel->repeat));
99603b705cfSriastradh
99703b705cfSriastradh	if (channel->repeat == RepeatNone || channel->repeat == RepeatPad) {
99803b705cfSriastradh		if (box.x1 < 0)
99903b705cfSriastradh			box.x1 = 0;
100003b705cfSriastradh		if (box.y1 < 0)
100103b705cfSriastradh			box.y1 = 0;
100203b705cfSriastradh		if (box.x2 > pixmap->drawable.width)
100303b705cfSriastradh			box.x2 = pixmap->drawable.width;
100403b705cfSriastradh		if (box.y2 > pixmap->drawable.height)
100503b705cfSriastradh			box.y2 = pixmap->drawable.height;
100603b705cfSriastradh	} else {
100703b705cfSriastradh		if (box.x1 < 0 || box.x2 > pixmap->drawable.width)
100803b705cfSriastradh			box.x1 = 0, box.x2 = pixmap->drawable.width;
100903b705cfSriastradh		if (box.y1 < 0 || box.y2 > pixmap->drawable.height)
101003b705cfSriastradh			box.y1 = 0, box.y2 = pixmap->drawable.height;
101103b705cfSriastradh	}
101203b705cfSriastradh
101303b705cfSriastradh	if (use_cpu_bo(sna, pixmap, &box, false)) {
101403b705cfSriastradh		bo = sna_pixmap(pixmap)->cpu_bo;
101503b705cfSriastradh	} else {
101603b705cfSriastradh		struct sna_pixmap *priv;
101703b705cfSriastradh
101803b705cfSriastradh		priv = sna_pixmap_force_to_gpu(pixmap,
101903b705cfSriastradh					       MOVE_READ | MOVE_SOURCE_HINT);
102003b705cfSriastradh		if (priv == NULL)
102103b705cfSriastradh			return 0;
102203b705cfSriastradh
102303b705cfSriastradh		bo = priv->gpu_bo;
102403b705cfSriastradh	}
102503b705cfSriastradh
102603b705cfSriastradh	if (bo->pitch > sna->render.max_3d_pitch)
102703b705cfSriastradh		return 0;
102803b705cfSriastradh
102903b705cfSriastradh	if (bo->tiling) {
103003b705cfSriastradh		int tile_width, tile_height, tile_size;
103103b705cfSriastradh
103203b705cfSriastradh		kgem_get_tile_size(&sna->kgem, bo->tiling,
103303b705cfSriastradh				   &tile_width, &tile_height, &tile_size);
103403b705cfSriastradh
103503b705cfSriastradh		DBG(("%s: tiling=%d, size=%dx%d, chunk=%d\n",
103603b705cfSriastradh		     __FUNCTION__, bo->tiling,
103703b705cfSriastradh		     tile_width, tile_height, tile_size));
103803b705cfSriastradh
103903b705cfSriastradh		/* Ensure we align to an even tile row */
104003b705cfSriastradh		box.y1 = box.y1 & ~(2*tile_height - 1);
104103b705cfSriastradh		box.y2 = ALIGN(box.y2, 2*tile_height);
104203b705cfSriastradh		if (box.y2 > pixmap->drawable.height)
104303b705cfSriastradh			box.y2 = pixmap->drawable.height;
104403b705cfSriastradh
104503b705cfSriastradh		box.x1 = box.x1 & ~(tile_width * 8 / pixmap->drawable.bitsPerPixel - 1);
104603b705cfSriastradh		box.x2 = ALIGN(box.x2, tile_width * 8 / pixmap->drawable.bitsPerPixel);
104703b705cfSriastradh		if (box.x2 > pixmap->drawable.width)
104803b705cfSriastradh			box.x2 = pixmap->drawable.width;
104903b705cfSriastradh
105003b705cfSriastradh		offset = box.x1 * pixmap->drawable.bitsPerPixel / 8 / tile_width * tile_size;
105103b705cfSriastradh	} else
105203b705cfSriastradh		offset = box.x1 * pixmap->drawable.bitsPerPixel / 8;
105303b705cfSriastradh
105403b705cfSriastradh	w = box.x2 - box.x1;
105503b705cfSriastradh	h = box.y2 - box.y1;
105603b705cfSriastradh	DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d)\n", __FUNCTION__,
105703b705cfSriastradh	     box.x1, box.y1, box.x2, box.y2, w, h,
105803b705cfSriastradh	     pixmap->drawable.width, pixmap->drawable.height));
105903b705cfSriastradh	if (w <= 0 || h <= 0 ||
106003b705cfSriastradh	    w > sna->render.max_3d_size ||
106103b705cfSriastradh	    h > sna->render.max_3d_size)
106203b705cfSriastradh		return 0;
106303b705cfSriastradh
106403b705cfSriastradh	/* How many tiles across are we? */
106503b705cfSriastradh	channel->bo = kgem_create_proxy(&sna->kgem, bo,
106603b705cfSriastradh					box.y1 * bo->pitch + offset,
106703b705cfSriastradh					h * bo->pitch);
106803b705cfSriastradh	if (channel->bo == NULL)
106903b705cfSriastradh		return 0;
107003b705cfSriastradh
107103b705cfSriastradh	if (channel->transform) {
107203b705cfSriastradh		memset(&channel->embedded_transform,
107303b705cfSriastradh		       0,
107403b705cfSriastradh		       sizeof(channel->embedded_transform));
107503b705cfSriastradh		channel->embedded_transform.matrix[0][0] = 1 << 16;
107603b705cfSriastradh		channel->embedded_transform.matrix[0][2] = -box.x1 << 16;
107703b705cfSriastradh		channel->embedded_transform.matrix[1][1] = 1 << 16;
107803b705cfSriastradh		channel->embedded_transform.matrix[1][2] = -box.y1 << 16;
107903b705cfSriastradh		channel->embedded_transform.matrix[2][2] = 1 << 16;
108003b705cfSriastradh		pixman_transform_multiply(&channel->embedded_transform,
108103b705cfSriastradh					  &channel->embedded_transform,
108203b705cfSriastradh					  channel->transform);
108303b705cfSriastradh		channel->transform = &channel->embedded_transform;
108403b705cfSriastradh	} else {
108503b705cfSriastradh		x -= box.x1;
108603b705cfSriastradh		y -= box.y1;
108703b705cfSriastradh	}
108803b705cfSriastradh
108903b705cfSriastradh	channel->offset[0] = x - dst_x;
109003b705cfSriastradh	channel->offset[1] = y - dst_y;
109103b705cfSriastradh	channel->scale[0] = 1.f/w;
109203b705cfSriastradh	channel->scale[1] = 1.f/h;
109303b705cfSriastradh	channel->width  = w;
109403b705cfSriastradh	channel->height = h;
109503b705cfSriastradh	return 1;
109603b705cfSriastradh}
109703b705cfSriastradh
109803b705cfSriastradhint
109903b705cfSriastradhsna_render_picture_extract(struct sna *sna,
110003b705cfSriastradh			   PicturePtr picture,
110103b705cfSriastradh			   struct sna_composite_channel *channel,
110203b705cfSriastradh			   int16_t x, int16_t y,
110303b705cfSriastradh			   int16_t w, int16_t h,
110403b705cfSriastradh			   int16_t dst_x, int16_t dst_y)
110503b705cfSriastradh{
110603b705cfSriastradh	struct kgem_bo *bo = NULL, *src_bo;
110703b705cfSriastradh	PixmapPtr pixmap = get_drawable_pixmap(picture->pDrawable);
110803b705cfSriastradh	int16_t ox, oy, ow, oh;
110903b705cfSriastradh	BoxRec box;
111003b705cfSriastradh
111103b705cfSriastradh#if NO_EXTRACT
111203b705cfSriastradh	return -1;
111303b705cfSriastradh#endif
111403b705cfSriastradh
111503b705cfSriastradh	DBG(("%s (%d, %d)x(%d, %d) [dst=(%d, %d)]\n",
111603b705cfSriastradh	     __FUNCTION__, x, y, w, h, dst_x, dst_y));
111703b705cfSriastradh
111803b705cfSriastradh	if (w == 0 || h == 0) {
111903b705cfSriastradh		DBG(("%s: fallback -- unknown bounds\n", __FUNCTION__));
112003b705cfSriastradh		return -1;
112103b705cfSriastradh	}
112203b705cfSriastradh
112303b705cfSriastradh	if (sna_render_picture_partial(sna, picture, channel,
112403b705cfSriastradh				       x, y, w, h,
112503b705cfSriastradh				       dst_x, dst_y))
112603b705cfSriastradh		return 1;
112703b705cfSriastradh
112803b705cfSriastradh	ow = w;
112903b705cfSriastradh	oh = h;
113003b705cfSriastradh
113103b705cfSriastradh	ox = box.x1 = x;
113203b705cfSriastradh	oy = box.y1 = y;
113303b705cfSriastradh	box.x2 = bound(x, w);
113403b705cfSriastradh	box.y2 = bound(y, h);
113503b705cfSriastradh	if (channel->transform) {
113603b705cfSriastradh		pixman_vector_t v;
113703b705cfSriastradh
113803b705cfSriastradh		pixman_transform_bounds(channel->transform, &box);
113903b705cfSriastradh
114003b705cfSriastradh		v.vector[0] = ox << 16;
114103b705cfSriastradh		v.vector[1] = oy << 16;
114203b705cfSriastradh		v.vector[2] =  1 << 16;
114303b705cfSriastradh		pixman_transform_point(channel->transform, &v);
114403b705cfSriastradh		ox = v.vector[0] / v.vector[2];
114503b705cfSriastradh		oy = v.vector[1] / v.vector[2];
114603b705cfSriastradh	}
114703b705cfSriastradh
114803b705cfSriastradh	DBG(("%s sample=(%d, %d), (%d, %d): (%d, %d)/(%d, %d), repeat=%d\n", __FUNCTION__,
114903b705cfSriastradh	     box.x1, box.y1, box.x2, box.y2, w, h,
115003b705cfSriastradh	     pixmap->drawable.width, pixmap->drawable.height,
115103b705cfSriastradh	     channel->repeat));
115203b705cfSriastradh
115303b705cfSriastradh	if (channel->repeat == RepeatNone || channel->repeat == RepeatPad) {
115403b705cfSriastradh		if (box.x1 < 0)
115503b705cfSriastradh			box.x1 = 0;
115603b705cfSriastradh		if (box.y1 < 0)
115703b705cfSriastradh			box.y1 = 0;
115803b705cfSriastradh		if (box.x2 > pixmap->drawable.width)
115903b705cfSriastradh			box.x2 = pixmap->drawable.width;
116003b705cfSriastradh		if (box.y2 > pixmap->drawable.height)
116103b705cfSriastradh			box.y2 = pixmap->drawable.height;
116203b705cfSriastradh	} else {
116303b705cfSriastradh		/* XXX tiled repeats? */
116403b705cfSriastradh		if (box.x1 < 0 || box.x2 > pixmap->drawable.width)
116503b705cfSriastradh			box.x1 = 0, box.x2 = pixmap->drawable.width;
116603b705cfSriastradh		if (box.y1 < 0 || box.y2 > pixmap->drawable.height)
116703b705cfSriastradh			box.y1 = 0, box.y2 = pixmap->drawable.height;
116803b705cfSriastradh	}
116903b705cfSriastradh
117003b705cfSriastradh	w = box.x2 - box.x1;
117103b705cfSriastradh	h = box.y2 - box.y1;
117203b705cfSriastradh	DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d)\n", __FUNCTION__,
117303b705cfSriastradh	     box.x1, box.y1, box.x2, box.y2, w, h,
117403b705cfSriastradh	     pixmap->drawable.width, pixmap->drawable.height));
117503b705cfSriastradh	if (w <= 0 || h <= 0) {
117603b705cfSriastradh		DBG(("%s: sample extents outside of texture -> clear\n",
117703b705cfSriastradh		     __FUNCTION__));
117803b705cfSriastradh		return 0;
117903b705cfSriastradh	}
118003b705cfSriastradh
118103b705cfSriastradh	if (w > sna->render.max_3d_size || h > sna->render.max_3d_size) {
118203b705cfSriastradh		DBG(("%s: fallback -- sample too large for texture (%d, %d)x(%d, %d)\n",
118303b705cfSriastradh		     __FUNCTION__, box.x1, box.y1, w, h));
118403b705cfSriastradh		return sna_render_picture_downsample(sna, picture, channel,
118503b705cfSriastradh						     x, y, ow, oh,
118603b705cfSriastradh						     dst_x, dst_y);
118703b705cfSriastradh	}
118803b705cfSriastradh
118903b705cfSriastradh	src_bo = use_cpu_bo(sna, pixmap, &box, true);
119003b705cfSriastradh	if (src_bo == NULL) {
119103b705cfSriastradh		src_bo = move_to_gpu(pixmap, &box, false);
119203b705cfSriastradh		if (src_bo == NULL) {
119303b705cfSriastradh			struct sna_pixmap *priv = sna_pixmap(pixmap);
119403b705cfSriastradh			if (priv) {
119503b705cfSriastradh				RegionRec region;
119603b705cfSriastradh
119703b705cfSriastradh				region.extents = box;
119803b705cfSriastradh				region.data = NULL;
119903b705cfSriastradh				if (!sna_drawable_move_region_to_cpu(&pixmap->drawable,
120003b705cfSriastradh								     &region, MOVE_READ))
120103b705cfSriastradh					return 0;
120203b705cfSriastradh
120303b705cfSriastradh				assert(!priv->mapped);
120403b705cfSriastradh				if (pixmap->devPrivate.ptr == NULL)
120503b705cfSriastradh					return 0; /* uninitialised */
120603b705cfSriastradh			}
120703b705cfSriastradh
120803b705cfSriastradh			bo = kgem_upload_source_image(&sna->kgem,
120903b705cfSriastradh						      pixmap->devPrivate.ptr,
121003b705cfSriastradh						      &box,
121103b705cfSriastradh						      pixmap->devKind,
121203b705cfSriastradh						      pixmap->drawable.bitsPerPixel);
121303b705cfSriastradh			if (priv != NULL && bo != NULL &&
121403b705cfSriastradh			    box.x2 - box.x1 == pixmap->drawable.width &&
121503b705cfSriastradh			    box.y2 - box.y1 == pixmap->drawable.height) {
121603b705cfSriastradh				DBG(("%s: adding upload cache to pixmap=%ld\n",
121703b705cfSriastradh				     __FUNCTION__, pixmap->drawable.serialNumber));
121803b705cfSriastradh				assert(priv->gpu_damage == NULL);
121903b705cfSriastradh				assert(priv->gpu_bo == NULL);
122003b705cfSriastradh				assert(bo->proxy != NULL);
122103b705cfSriastradh				kgem_proxy_bo_attach(bo, &priv->gpu_bo);
122203b705cfSriastradh			}
122303b705cfSriastradh		}
122403b705cfSriastradh	}
122503b705cfSriastradh	if (src_bo) {
122603b705cfSriastradh		bo = kgem_create_2d(&sna->kgem, w, h,
122703b705cfSriastradh				    pixmap->drawable.bitsPerPixel,
122803b705cfSriastradh				    kgem_choose_tiling(&sna->kgem,
122903b705cfSriastradh						       I915_TILING_X, w, h,
123003b705cfSriastradh						       pixmap->drawable.bitsPerPixel),
123103b705cfSriastradh				    CREATE_TEMPORARY);
123203b705cfSriastradh		if (bo) {
123303b705cfSriastradh			PixmapRec tmp;
123403b705cfSriastradh
123503b705cfSriastradh			tmp.drawable.width  = w;
123603b705cfSriastradh			tmp.drawable.height = h;
123703b705cfSriastradh			tmp.drawable.depth  = pixmap->drawable.depth;
123803b705cfSriastradh			tmp.drawable.bitsPerPixel = pixmap->drawable.bitsPerPixel;
123903b705cfSriastradh			tmp.devPrivate.ptr = NULL;
124003b705cfSriastradh
124103b705cfSriastradh			assert(tmp.drawable.width);
124203b705cfSriastradh			assert(tmp.drawable.height);
124303b705cfSriastradh
124403b705cfSriastradh			if (!sna->render.copy_boxes(sna, GXcopy,
124503b705cfSriastradh						    pixmap, src_bo, 0, 0,
124603b705cfSriastradh						    &tmp, bo, -box.x1, -box.y1,
124703b705cfSriastradh						    &box, 1, 0)) {
124803b705cfSriastradh				kgem_bo_destroy(&sna->kgem, bo);
124903b705cfSriastradh				bo = NULL;
125003b705cfSriastradh			}
125103b705cfSriastradh		}
125203b705cfSriastradh	}
125303b705cfSriastradh
125403b705cfSriastradh	if (bo == NULL) {
125503b705cfSriastradh		DBG(("%s: falback -- pixmap is not on the GPU\n",
125603b705cfSriastradh		     __FUNCTION__));
125703b705cfSriastradh		return sna_render_picture_fixup(sna, picture, channel,
125803b705cfSriastradh						x, y, ow, oh, dst_x, dst_y);
125903b705cfSriastradh	}
126003b705cfSriastradh
126103b705cfSriastradh	if (ox == x && oy == y) {
126203b705cfSriastradh		x = y = 0;
126303b705cfSriastradh	} else if (channel->transform) {
126403b705cfSriastradh		pixman_vector_t v;
126503b705cfSriastradh		pixman_transform_t m;
126603b705cfSriastradh
126703b705cfSriastradh		v.vector[0] = (ox - box.x1) << 16;
126803b705cfSriastradh		v.vector[1] = (oy - box.y1) << 16;
126903b705cfSriastradh		v.vector[2] = 1 << 16;
127003b705cfSriastradh		pixman_transform_invert(&m, channel->transform);
127103b705cfSriastradh		pixman_transform_point(&m, &v);
127203b705cfSriastradh		x = v.vector[0] / v.vector[2];
127303b705cfSriastradh		y = v.vector[1] / v.vector[2];
127403b705cfSriastradh	} else {
127503b705cfSriastradh		x = ox - box.x1;
127603b705cfSriastradh		y = oy - box.y1;
127703b705cfSriastradh	}
127803b705cfSriastradh
127903b705cfSriastradh	channel->offset[0] = x - dst_x;
128003b705cfSriastradh	channel->offset[1] = y - dst_y;
128103b705cfSriastradh	channel->scale[0] = 1.f/w;
128203b705cfSriastradh	channel->scale[1] = 1.f/h;
128303b705cfSriastradh	channel->width  = w;
128403b705cfSriastradh	channel->height = h;
128503b705cfSriastradh	channel->bo = bo;
128603b705cfSriastradh	return 1;
128703b705cfSriastradh}
128803b705cfSriastradh
128903b705cfSriastradhstatic int
129003b705cfSriastradhsna_render_picture_convolve(struct sna *sna,
129103b705cfSriastradh			    PicturePtr picture,
129203b705cfSriastradh			    struct sna_composite_channel *channel,
129303b705cfSriastradh			    int16_t x, int16_t y,
129403b705cfSriastradh			    int16_t w, int16_t h,
129503b705cfSriastradh			    int16_t dst_x, int16_t dst_y)
129603b705cfSriastradh{
129703b705cfSriastradh	ScreenPtr screen = picture->pDrawable->pScreen;
129803b705cfSriastradh	PixmapPtr pixmap;
129903b705cfSriastradh	PicturePtr tmp;
130003b705cfSriastradh	pixman_fixed_t *params = picture->filter_params;
130103b705cfSriastradh	int x_off = -pixman_fixed_to_int((params[0] - pixman_fixed_1) >> 1);
130203b705cfSriastradh	int y_off = -pixman_fixed_to_int((params[1] - pixman_fixed_1) >> 1);
130303b705cfSriastradh	int cw = pixman_fixed_to_int(params[0]);
130403b705cfSriastradh	int ch = pixman_fixed_to_int(params[1]);
130503b705cfSriastradh	int i, j, error, depth;
130603b705cfSriastradh	struct kgem_bo *bo;
130703b705cfSriastradh
130803b705cfSriastradh	/* Lame multi-pass accumulation implementation of a general convolution
130903b705cfSriastradh	 * that works everywhere.
131003b705cfSriastradh	 */
131103b705cfSriastradh	DBG(("%s: origin=(%d,%d) kernel=%dx%d, size=%dx%d\n",
131203b705cfSriastradh	     __FUNCTION__, x_off, y_off, cw, ch, w, h));
131303b705cfSriastradh
131403b705cfSriastradh	assert(picture->pDrawable);
131503b705cfSriastradh	assert(picture->filter == PictFilterConvolution);
131603b705cfSriastradh	assert(w <= sna->render.max_3d_size && h <= sna->render.max_3d_size);
131703b705cfSriastradh
131803b705cfSriastradh	if (PICT_FORMAT_RGB(picture->format) == 0) {
131903b705cfSriastradh		channel->pict_format = PIXMAN_a8;
132003b705cfSriastradh		depth = 8;
132103b705cfSriastradh	} else {
132203b705cfSriastradh		channel->pict_format = PIXMAN_a8r8g8b8;
132303b705cfSriastradh		depth = 32;
132403b705cfSriastradh	}
132503b705cfSriastradh
132603b705cfSriastradh	pixmap = screen->CreatePixmap(screen, w, h, depth, SNA_CREATE_SCRATCH);
132703b705cfSriastradh	if (pixmap == NullPixmap)
132803b705cfSriastradh		return 0;
132903b705cfSriastradh
133003b705cfSriastradh	tmp = CreatePicture(0, &pixmap->drawable,
133103b705cfSriastradh			    PictureMatchFormat(screen, depth, channel->pict_format),
133203b705cfSriastradh			    0, NULL, serverClient, &error);
133303b705cfSriastradh	screen->DestroyPixmap(pixmap);
133403b705cfSriastradh	if (tmp == NULL)
133503b705cfSriastradh		return 0;
133603b705cfSriastradh
133703b705cfSriastradh	ValidatePicture(tmp);
133803b705cfSriastradh
133903b705cfSriastradh	bo = __sna_pixmap_get_bo(pixmap);
134003b705cfSriastradh	if (!sna->render.clear(sna, pixmap, bo)) {
134103b705cfSriastradh		FreePicture(tmp, 0);
134203b705cfSriastradh		return 0;
134303b705cfSriastradh	}
134403b705cfSriastradh
134503b705cfSriastradh	picture->filter = PictFilterBilinear;
134603b705cfSriastradh	params += 2;
134703b705cfSriastradh	for (j = 0; j < ch; j++) {
134803b705cfSriastradh		for (i = 0; i < cw; i++) {
134903b705cfSriastradh			xRenderColor color;
135003b705cfSriastradh			PicturePtr alpha;
135103b705cfSriastradh
135203b705cfSriastradh			color.alpha = *params++;
135303b705cfSriastradh			color.red = color.green = color.blue = 0;
135403b705cfSriastradh			DBG(("%s: (%d, %d), alpha=%x\n",
135503b705cfSriastradh			     __FUNCTION__, i,j, color.alpha));
135603b705cfSriastradh
135703b705cfSriastradh			if (color.alpha <= 0x00ff)
135803b705cfSriastradh				continue;
135903b705cfSriastradh
136003b705cfSriastradh			alpha = CreateSolidPicture(0, &color, &error);
136103b705cfSriastradh			if (alpha) {
136203b705cfSriastradh				sna_composite(PictOpAdd, picture, alpha, tmp,
136303b705cfSriastradh					      x, y,
136403b705cfSriastradh					      0, 0,
136503b705cfSriastradh					      x_off+i, y_off+j,
136603b705cfSriastradh					      w, h);
136703b705cfSriastradh				FreePicture(alpha, 0);
136803b705cfSriastradh			}
136903b705cfSriastradh		}
137003b705cfSriastradh	}
137103b705cfSriastradh	picture->filter = PictFilterConvolution;
137203b705cfSriastradh
137303b705cfSriastradh	channel->height = h;
137403b705cfSriastradh	channel->width  = w;
137503b705cfSriastradh	channel->filter = PictFilterNearest;
137603b705cfSriastradh	channel->repeat = RepeatNone;
137703b705cfSriastradh	channel->is_affine = true;
137803b705cfSriastradh	channel->transform = NULL;
137903b705cfSriastradh	channel->scale[0] = 1.f / w;
138003b705cfSriastradh	channel->scale[1] = 1.f / h;
138103b705cfSriastradh	channel->offset[0] = -dst_x;
138203b705cfSriastradh	channel->offset[1] = -dst_y;
138303b705cfSriastradh	channel->bo = kgem_bo_reference(bo); /* transfer ownership */
138403b705cfSriastradh	FreePicture(tmp, 0);
138503b705cfSriastradh
138603b705cfSriastradh	return 1;
138703b705cfSriastradh}
138803b705cfSriastradh
138903b705cfSriastradhstatic int
139003b705cfSriastradhsna_render_picture_flatten(struct sna *sna,
139103b705cfSriastradh			   PicturePtr picture,
139203b705cfSriastradh			   struct sna_composite_channel *channel,
139303b705cfSriastradh			   int16_t x, int16_t y,
139403b705cfSriastradh			   int16_t w, int16_t h,
139503b705cfSriastradh			   int16_t dst_x, int16_t dst_y)
139603b705cfSriastradh{
139703b705cfSriastradh	ScreenPtr screen = picture->pDrawable->pScreen;
139803b705cfSriastradh	PixmapPtr pixmap;
139903b705cfSriastradh	PicturePtr tmp, alpha;
140003b705cfSriastradh	int old_format, error;
140103b705cfSriastradh
140203b705cfSriastradh	assert(picture->pDrawable);
140303b705cfSriastradh	assert(picture->alphaMap);
140403b705cfSriastradh	assert(w <= sna->render.max_3d_size && h <= sna->render.max_3d_size);
140503b705cfSriastradh
140603b705cfSriastradh	/* XXX shortcut a8? */
140703b705cfSriastradh	DBG(("%s: %dx%d\n", __FUNCTION__, w, h));
140803b705cfSriastradh
140903b705cfSriastradh	pixmap = screen->CreatePixmap(screen, w, h, 32, SNA_CREATE_SCRATCH);
141003b705cfSriastradh	if (pixmap == NullPixmap)
141103b705cfSriastradh		return 0;
141203b705cfSriastradh
141303b705cfSriastradh	tmp = CreatePicture(0, &pixmap->drawable,
141403b705cfSriastradh			    PictureMatchFormat(screen, 32, PICT_a8r8g8b8),
141503b705cfSriastradh			    0, NULL, serverClient, &error);
141603b705cfSriastradh	screen->DestroyPixmap(pixmap);
141703b705cfSriastradh	if (tmp == NULL)
141803b705cfSriastradh		return 0;
141903b705cfSriastradh
142003b705cfSriastradh	ValidatePicture(tmp);
142103b705cfSriastradh
142203b705cfSriastradh	old_format = picture->format;
142303b705cfSriastradh	picture->format = PICT_FORMAT(PICT_FORMAT_BPP(picture->format),
142403b705cfSriastradh				      PICT_FORMAT_TYPE(picture->format),
142503b705cfSriastradh				      0,
142603b705cfSriastradh				      PICT_FORMAT_R(picture->format),
142703b705cfSriastradh				      PICT_FORMAT_G(picture->format),
142803b705cfSriastradh				      PICT_FORMAT_B(picture->format));
142903b705cfSriastradh
143003b705cfSriastradh	alpha = picture->alphaMap;
143103b705cfSriastradh	picture->alphaMap = NULL;
143203b705cfSriastradh
143303b705cfSriastradh	sna_composite(PictOpSrc, picture, alpha, tmp,
143403b705cfSriastradh		      x, y,
143503b705cfSriastradh		      x + picture->alphaOrigin.x, y + picture->alphaOrigin.y,
143603b705cfSriastradh		      0, 0,
143703b705cfSriastradh		      w, h);
143803b705cfSriastradh
143903b705cfSriastradh	picture->format = old_format;
144003b705cfSriastradh	picture->alphaMap = alpha;
144103b705cfSriastradh
144203b705cfSriastradh	channel->height = h;
144303b705cfSriastradh	channel->width  = w;
144403b705cfSriastradh	channel->filter = PictFilterNearest;
144503b705cfSriastradh	channel->repeat = RepeatNone;
144603b705cfSriastradh	channel->pict_format = PIXMAN_a8r8g8b8;
144703b705cfSriastradh	channel->is_affine = true;
144803b705cfSriastradh	channel->transform = NULL;
144903b705cfSriastradh	channel->scale[0] = 1.f / w;
145003b705cfSriastradh	channel->scale[1] = 1.f / h;
145103b705cfSriastradh	channel->offset[0] = -dst_x;
145203b705cfSriastradh	channel->offset[1] = -dst_y;
145303b705cfSriastradh	channel->bo = kgem_bo_reference(__sna_pixmap_get_bo(pixmap));
145403b705cfSriastradh	FreePicture(tmp, 0);
145503b705cfSriastradh
145603b705cfSriastradh	return 1;
145703b705cfSriastradh}
145803b705cfSriastradh
145903b705cfSriastradhint
146003b705cfSriastradhsna_render_picture_approximate_gradient(struct sna *sna,
146103b705cfSriastradh					PicturePtr picture,
146203b705cfSriastradh					struct sna_composite_channel *channel,
146303b705cfSriastradh					int16_t x, int16_t y,
146403b705cfSriastradh					int16_t w, int16_t h,
146503b705cfSriastradh					int16_t dst_x, int16_t dst_y)
146603b705cfSriastradh{
146703b705cfSriastradh	pixman_image_t *dst, *src;
146803b705cfSriastradh	pixman_transform_t t;
146903b705cfSriastradh	int w2 = w/2, h2 = h/2;
147003b705cfSriastradh	int dx, dy;
147103b705cfSriastradh	void *ptr;
147203b705cfSriastradh
147303b705cfSriastradh#if NO_FIXUP
147403b705cfSriastradh	return -1;
147503b705cfSriastradh#endif
147603b705cfSriastradh
147703b705cfSriastradh	DBG(("%s: (%d, %d)x(%d, %d), dst=(%d, %d)\n",
147803b705cfSriastradh	     __FUNCTION__, x, y, w, h, dst_x, dst_y));
147903b705cfSriastradh
148003b705cfSriastradh	if (w2 == 0 || h2 == 0) {
148103b705cfSriastradh		DBG(("%s: fallback - unknown bounds\n", __FUNCTION__));
148203b705cfSriastradh		return -1;
148303b705cfSriastradh	}
148403b705cfSriastradh	if (w2 > sna->render.max_3d_size || h2 > sna->render.max_3d_size) {
148503b705cfSriastradh		DBG(("%s: fallback - too large (%dx%d)\n", __FUNCTION__, w, h));
148603b705cfSriastradh		return -1;
148703b705cfSriastradh	}
148803b705cfSriastradh
148903b705cfSriastradh	channel->is_opaque = sna_gradient_is_opaque((PictGradient*)picture->pSourcePict);
149003b705cfSriastradh	channel->pict_format =
149103b705cfSriastradh		channel->is_opaque ? PIXMAN_x8r8g8b8 : PIXMAN_a8r8g8b8;
149203b705cfSriastradh	DBG(("%s: gradient is opaque? %d, selecting format %08x\n",
149303b705cfSriastradh	     __FUNCTION__, channel->is_opaque, channel->pict_format));
149403b705cfSriastradh	assert(channel->card_format == -1);
149503b705cfSriastradh
149603b705cfSriastradh	channel->bo = kgem_create_buffer_2d(&sna->kgem,
149703b705cfSriastradh					    w2, h2, 32,
149803b705cfSriastradh					    KGEM_BUFFER_WRITE_INPLACE,
149903b705cfSriastradh					    &ptr);
150003b705cfSriastradh	if (!channel->bo) {
150103b705cfSriastradh		DBG(("%s: failed to create upload buffer, using clear\n",
150203b705cfSriastradh		     __FUNCTION__));
150303b705cfSriastradh		return 0;
150403b705cfSriastradh	}
150503b705cfSriastradh
150603b705cfSriastradh	dst = pixman_image_create_bits(channel->pict_format,
150703b705cfSriastradh				       w2, h2, ptr, channel->bo->pitch);
150803b705cfSriastradh	if (!dst) {
150903b705cfSriastradh		kgem_bo_destroy(&sna->kgem, channel->bo);
151003b705cfSriastradh		channel->bo = NULL;
151103b705cfSriastradh		return 0;
151203b705cfSriastradh	}
151303b705cfSriastradh
151403b705cfSriastradh	src = image_from_pict(picture, false, &dx, &dy);
151503b705cfSriastradh	if (src == NULL) {
151603b705cfSriastradh		pixman_image_unref(dst);
151703b705cfSriastradh		kgem_bo_destroy(&sna->kgem, channel->bo);
151803b705cfSriastradh		channel->bo = NULL;
151903b705cfSriastradh		return 0;
152003b705cfSriastradh	}
152103b705cfSriastradh	DBG(("%s: source offset (%d, %d)\n", __FUNCTION__, dx, dy));
152203b705cfSriastradh
152303b705cfSriastradh	memset(&t, 0, sizeof(t));
152403b705cfSriastradh	t.matrix[0][0] = (w << 16) / w2;
152503b705cfSriastradh	t.matrix[0][2] = (x + dx) << 16;
152603b705cfSriastradh	t.matrix[1][1] = (h << 16) / h2;
152703b705cfSriastradh	t.matrix[1][2] = (y + dy) << 16;
152803b705cfSriastradh	t.matrix[2][2] = 1 << 16;
152903b705cfSriastradh	if (picture->transform)
153003b705cfSriastradh		pixman_transform_multiply(&t, picture->transform, &t);
153103b705cfSriastradh	DBG(("%s: applying transform [(%f, %f, %f), (%f, %f, %f), (%f, %f, %f)]\n",
153203b705cfSriastradh	     __FUNCTION__,
153303b705cfSriastradh	     pixman_fixed_to_double(t.matrix[0][0]),
153403b705cfSriastradh	     pixman_fixed_to_double(t.matrix[0][1]),
153503b705cfSriastradh	     pixman_fixed_to_double(t.matrix[0][2]),
153603b705cfSriastradh	     pixman_fixed_to_double(t.matrix[1][0]),
153703b705cfSriastradh	     pixman_fixed_to_double(t.matrix[1][1]),
153803b705cfSriastradh	     pixman_fixed_to_double(t.matrix[1][2]),
153903b705cfSriastradh	     pixman_fixed_to_double(t.matrix[2][0]),
154003b705cfSriastradh	     pixman_fixed_to_double(t.matrix[2][1]),
154103b705cfSriastradh	     pixman_fixed_to_double(t.matrix[2][2])));
154203b705cfSriastradh	pixman_image_set_transform(src, &t);
154303b705cfSriastradh
154403b705cfSriastradh	sna_image_composite(PictOpSrc, src, NULL, dst,
154503b705cfSriastradh			    0, 0,
154603b705cfSriastradh			    0, 0,
154703b705cfSriastradh			    0, 0,
154803b705cfSriastradh			    w2, h2);
154903b705cfSriastradh	free_pixman_pict(picture, src);
155003b705cfSriastradh	pixman_image_unref(dst);
155103b705cfSriastradh
155203b705cfSriastradh	channel->width  = w2;
155303b705cfSriastradh	channel->height = h2;
155403b705cfSriastradh
155503b705cfSriastradh	channel->filter = PictFilterNearest;
155603b705cfSriastradh	channel->repeat = RepeatNone;
155703b705cfSriastradh	channel->is_affine = true;
155803b705cfSriastradh
155903b705cfSriastradh	channel->scale[0] = 1.f/w;
156003b705cfSriastradh	channel->scale[1] = 1.f/h;
156103b705cfSriastradh	channel->offset[0] = -dst_x;
156203b705cfSriastradh	channel->offset[1] = -dst_y;
156303b705cfSriastradh	channel->transform = NULL;
156403b705cfSriastradh
156503b705cfSriastradh	return 1;
156603b705cfSriastradh}
156703b705cfSriastradh
156803b705cfSriastradhint
156903b705cfSriastradhsna_render_picture_fixup(struct sna *sna,
157003b705cfSriastradh			 PicturePtr picture,
157103b705cfSriastradh			 struct sna_composite_channel *channel,
157203b705cfSriastradh			 int16_t x, int16_t y,
157303b705cfSriastradh			 int16_t w, int16_t h,
157403b705cfSriastradh			 int16_t dst_x, int16_t dst_y)
157503b705cfSriastradh{
157603b705cfSriastradh	pixman_image_t *dst, *src;
157703b705cfSriastradh	int dx, dy;
157803b705cfSriastradh	void *ptr;
157903b705cfSriastradh
158003b705cfSriastradh#if NO_FIXUP
158103b705cfSriastradh	return -1;
158203b705cfSriastradh#endif
158303b705cfSriastradh
158403b705cfSriastradh	DBG(("%s: (%d, %d)x(%d, %d)\n", __FUNCTION__, x, y, w, h));
158503b705cfSriastradh
158603b705cfSriastradh	if (w == 0 || h == 0) {
158703b705cfSriastradh		DBG(("%s: fallback - unknown bounds\n", __FUNCTION__));
158803b705cfSriastradh		return -1;
158903b705cfSriastradh	}
159003b705cfSriastradh	if (w > sna->render.max_3d_size || h > sna->render.max_3d_size) {
159103b705cfSriastradh		DBG(("%s: fallback - too large (%dx%d)\n", __FUNCTION__, w, h));
159203b705cfSriastradh		return -1;
159303b705cfSriastradh	}
159403b705cfSriastradh
159503b705cfSriastradh	if (picture->alphaMap) {
159603b705cfSriastradh		DBG(("%s: alphamap\n", __FUNCTION__));
159703b705cfSriastradh		if (is_gpu(sna, picture->pDrawable, PREFER_GPU_RENDER) ||
159803b705cfSriastradh		    is_gpu(sna, picture->alphaMap->pDrawable, PREFER_GPU_RENDER)) {
159903b705cfSriastradh			return sna_render_picture_flatten(sna, picture, channel,
160003b705cfSriastradh							  x, y, w, h, dst_x, dst_y);
160103b705cfSriastradh		}
160203b705cfSriastradh
160303b705cfSriastradh		goto do_fixup;
160403b705cfSriastradh	}
160503b705cfSriastradh
160603b705cfSriastradh	if (picture->filter == PictFilterConvolution) {
160703b705cfSriastradh		DBG(("%s: convolution\n", __FUNCTION__));
160803b705cfSriastradh		if (is_gpu(sna, picture->pDrawable, PREFER_GPU_RENDER)) {
160903b705cfSriastradh			return sna_render_picture_convolve(sna, picture, channel,
161003b705cfSriastradh							   x, y, w, h, dst_x, dst_y);
161103b705cfSriastradh		}
161203b705cfSriastradh
161303b705cfSriastradh		goto do_fixup;
161403b705cfSriastradh	}
161503b705cfSriastradh
161603b705cfSriastradhdo_fixup:
161703b705cfSriastradh	if (PICT_FORMAT_RGB(picture->format) == 0)
161803b705cfSriastradh		channel->pict_format = PIXMAN_a8;
161903b705cfSriastradh	else
162003b705cfSriastradh		channel->pict_format = PIXMAN_a8r8g8b8;
162103b705cfSriastradh
162203b705cfSriastradh	if (picture->pDrawable &&
162303b705cfSriastradh	    !sna_drawable_move_to_cpu(picture->pDrawable, MOVE_READ))
162403b705cfSriastradh		return 0;
162503b705cfSriastradh
162603b705cfSriastradh	channel->bo = kgem_create_buffer_2d(&sna->kgem,
162703b705cfSriastradh					    w, h, PIXMAN_FORMAT_BPP(channel->pict_format),
162803b705cfSriastradh					    KGEM_BUFFER_WRITE_INPLACE,
162903b705cfSriastradh					    &ptr);
163003b705cfSriastradh	if (!channel->bo) {
163103b705cfSriastradh		DBG(("%s: failed to create upload buffer, using clear\n",
163203b705cfSriastradh		     __FUNCTION__));
163303b705cfSriastradh		return 0;
163403b705cfSriastradh	}
163503b705cfSriastradh
163603b705cfSriastradh	/* Composite in the original format to preserve idiosyncracies */
163703b705cfSriastradh	if (!kgem_buffer_is_inplace(channel->bo) &&
163803b705cfSriastradh	    (picture->pDrawable == NULL ||
163903b705cfSriastradh	     alphaless(picture->format) == alphaless(channel->pict_format)))
164003b705cfSriastradh		dst = pixman_image_create_bits(channel->pict_format,
164103b705cfSriastradh					       w, h, ptr, channel->bo->pitch);
164203b705cfSriastradh	else
164303b705cfSriastradh		dst = pixman_image_create_bits(picture->format, w, h, NULL, 0);
164403b705cfSriastradh	if (!dst) {
164503b705cfSriastradh		kgem_bo_destroy(&sna->kgem, channel->bo);
164603b705cfSriastradh		return 0;
164703b705cfSriastradh	}
164803b705cfSriastradh
164903b705cfSriastradh	src = image_from_pict(picture, false, &dx, &dy);
165003b705cfSriastradh	if (src == NULL) {
165103b705cfSriastradh		pixman_image_unref(dst);
165203b705cfSriastradh		kgem_bo_destroy(&sna->kgem, channel->bo);
165303b705cfSriastradh		return 0;
165403b705cfSriastradh	}
165503b705cfSriastradh
165603b705cfSriastradh	DBG(("%s: compositing tmp=(%d+%d, %d+%d)x(%d, %d)\n",
165703b705cfSriastradh	     __FUNCTION__, x, dx, y, dy, w, h));
165803b705cfSriastradh	sna_image_composite(PictOpSrc, src, NULL, dst,
165903b705cfSriastradh			    x + dx, y + dy,
166003b705cfSriastradh			    0, 0,
166103b705cfSriastradh			    0, 0,
166203b705cfSriastradh			    w, h);
166303b705cfSriastradh	free_pixman_pict(picture, src);
166403b705cfSriastradh
166503b705cfSriastradh	/* Then convert to card format */
166603b705cfSriastradh	if (pixman_image_get_data(dst) != ptr) {
166703b705cfSriastradh		DBG(("%s: performing post-conversion %08x->%08x (%d, %d)\n",
166803b705cfSriastradh		     __FUNCTION__,
166903b705cfSriastradh		     picture->format, channel->pict_format,
167003b705cfSriastradh		     w, h));
167103b705cfSriastradh
167203b705cfSriastradh		src = dst;
167303b705cfSriastradh		dst = pixman_image_create_bits(channel->pict_format,
167403b705cfSriastradh					       w, h, ptr, channel->bo->pitch);
167503b705cfSriastradh		if (dst) {
167603b705cfSriastradh			pixman_image_composite(PictOpSrc, src, NULL, dst,
167703b705cfSriastradh					       0, 0,
167803b705cfSriastradh					       0, 0,
167903b705cfSriastradh					       0, 0,
168003b705cfSriastradh					       w, h);
168103b705cfSriastradh			pixman_image_unref(src);
168203b705cfSriastradh		} else {
168303b705cfSriastradh			memset(ptr, 0, __kgem_buffer_size(channel->bo));
168403b705cfSriastradh			dst = src;
168503b705cfSriastradh		}
168603b705cfSriastradh	}
168703b705cfSriastradh	pixman_image_unref(dst);
168803b705cfSriastradh
168903b705cfSriastradh	channel->width  = w;
169003b705cfSriastradh	channel->height = h;
169103b705cfSriastradh
169203b705cfSriastradh	channel->filter = PictFilterNearest;
169303b705cfSriastradh	channel->repeat = RepeatNone;
169403b705cfSriastradh	channel->is_affine = true;
169503b705cfSriastradh
169603b705cfSriastradh	channel->scale[0] = 1.f/w;
169703b705cfSriastradh	channel->scale[1] = 1.f/h;
169803b705cfSriastradh	channel->offset[0] = -dst_x;
169903b705cfSriastradh	channel->offset[1] = -dst_y;
170003b705cfSriastradh	channel->transform = NULL;
170103b705cfSriastradh
170203b705cfSriastradh	return 1;
170303b705cfSriastradh}
170403b705cfSriastradh
170503b705cfSriastradhint
170603b705cfSriastradhsna_render_picture_convert(struct sna *sna,
170703b705cfSriastradh			   PicturePtr picture,
170803b705cfSriastradh			   struct sna_composite_channel *channel,
170903b705cfSriastradh			   PixmapPtr pixmap,
171003b705cfSriastradh			   int16_t x, int16_t y,
171103b705cfSriastradh			   int16_t w, int16_t h,
171203b705cfSriastradh			   int16_t dst_x, int16_t dst_y,
171303b705cfSriastradh			   bool fixup_alpha)
171403b705cfSriastradh{
171503b705cfSriastradh	BoxRec box;
171603b705cfSriastradh
171703b705cfSriastradh#if NO_CONVERT
171803b705cfSriastradh	return -1;
171903b705cfSriastradh#endif
172003b705cfSriastradh
172103b705cfSriastradh	if (w != 0 && h != 0) {
172203b705cfSriastradh		box.x1 = x;
172303b705cfSriastradh		box.y1 = y;
172403b705cfSriastradh		box.x2 = bound(x, w);
172503b705cfSriastradh		box.y2 = bound(y, h);
172603b705cfSriastradh
172703b705cfSriastradh		if (channel->transform) {
172803b705cfSriastradh			DBG(("%s: has transform, converting whole surface\n",
172903b705cfSriastradh			     __FUNCTION__));
173003b705cfSriastradh			box.x1 = box.y1 = 0;
173103b705cfSriastradh			box.x2 = pixmap->drawable.width;
173203b705cfSriastradh			box.y2 = pixmap->drawable.height;
173303b705cfSriastradh		}
173403b705cfSriastradh
173503b705cfSriastradh		if (box.x1 < 0)
173603b705cfSriastradh			box.x1 = 0;
173703b705cfSriastradh		if (box.y1 < 0)
173803b705cfSriastradh			box.y1 = 0;
173903b705cfSriastradh		if (box.x2 > pixmap->drawable.width)
174003b705cfSriastradh			box.x2 = pixmap->drawable.width;
174103b705cfSriastradh		if (box.y2 > pixmap->drawable.height)
174203b705cfSriastradh			box.y2 = pixmap->drawable.height;
174303b705cfSriastradh	} else {
174403b705cfSriastradh		DBG(("%s: op no bounds, converting whole surface\n",
174503b705cfSriastradh		     __FUNCTION__));
174603b705cfSriastradh		box.x1 = box.y1 = 0;
174703b705cfSriastradh		box.x2 = pixmap->drawable.width;
174803b705cfSriastradh		box.y2 = pixmap->drawable.height;
174903b705cfSriastradh	}
175003b705cfSriastradh
175103b705cfSriastradh	w = box.x2 - box.x1;
175203b705cfSriastradh	h = box.y2 - box.y1;
175303b705cfSriastradh
175403b705cfSriastradh	DBG(("%s: convert (%d, %d)x(%d, %d), source size %dx%d\n",
175503b705cfSriastradh	     __FUNCTION__, box.x1, box.y1, w, h,
175603b705cfSriastradh	     pixmap->drawable.width,
175703b705cfSriastradh	     pixmap->drawable.height));
175803b705cfSriastradh
175903b705cfSriastradh	if (w <= 0 || h <= 0) {
176003b705cfSriastradh		DBG(("%s: sample extents lie outside of source, using clear\n",
176103b705cfSriastradh		     __FUNCTION__));
176203b705cfSriastradh		return 0;
176303b705cfSriastradh	}
176403b705cfSriastradh
176503b705cfSriastradh	if (fixup_alpha && is_gpu(sna, &pixmap->drawable, PREFER_GPU_RENDER)) {
176603b705cfSriastradh		ScreenPtr screen = pixmap->drawable.pScreen;
176703b705cfSriastradh		PixmapPtr tmp;
176803b705cfSriastradh		PicturePtr src, dst;
176903b705cfSriastradh		int error;
177003b705cfSriastradh
177103b705cfSriastradh		assert(PICT_FORMAT_BPP(picture->format) == pixmap->drawable.bitsPerPixel);
177203b705cfSriastradh		channel->pict_format = PICT_FORMAT(PICT_FORMAT_BPP(picture->format),
177303b705cfSriastradh						   PICT_FORMAT_TYPE(picture->format),
177403b705cfSriastradh						   PICT_FORMAT_BPP(picture->format) - PIXMAN_FORMAT_DEPTH(picture->format),
177503b705cfSriastradh						   PICT_FORMAT_R(picture->format),
177603b705cfSriastradh						   PICT_FORMAT_G(picture->format),
177703b705cfSriastradh						   PICT_FORMAT_B(picture->format));
177803b705cfSriastradh
177903b705cfSriastradh		DBG(("%s: converting to %08x from %08x using composite alpha-fixup\n",
178003b705cfSriastradh		     __FUNCTION__,
178103b705cfSriastradh		     (unsigned)channel->pict_format,
178203b705cfSriastradh		     (unsigned)picture->format));
178303b705cfSriastradh
178403b705cfSriastradh		tmp = screen->CreatePixmap(screen, w, h, pixmap->drawable.bitsPerPixel, 0);
178503b705cfSriastradh		if (tmp == NULL)
178603b705cfSriastradh			return 0;
178703b705cfSriastradh
178803b705cfSriastradh		dst = CreatePicture(0, &tmp->drawable,
178903b705cfSriastradh				    PictureMatchFormat(screen,
179003b705cfSriastradh						       pixmap->drawable.bitsPerPixel,
179103b705cfSriastradh						       channel->pict_format),
179203b705cfSriastradh				    0, NULL, serverClient, &error);
179303b705cfSriastradh		if (dst == NULL) {
179403b705cfSriastradh			screen->DestroyPixmap(tmp);
179503b705cfSriastradh			return 0;
179603b705cfSriastradh		}
179703b705cfSriastradh
179803b705cfSriastradh		src = CreatePicture(0, &pixmap->drawable,
179903b705cfSriastradh				    PictureMatchFormat(screen,
180003b705cfSriastradh						       pixmap->drawable.depth,
180103b705cfSriastradh						       picture->format),
180203b705cfSriastradh				    0, NULL, serverClient, &error);
180303b705cfSriastradh		if (src == NULL) {
180403b705cfSriastradh			FreePicture(dst, 0);
180503b705cfSriastradh			screen->DestroyPixmap(tmp);
180603b705cfSriastradh			return 0;
180703b705cfSriastradh		}
180803b705cfSriastradh
180903b705cfSriastradh		ValidatePicture(src);
181003b705cfSriastradh		ValidatePicture(dst);
181103b705cfSriastradh
181203b705cfSriastradh		sna_composite(PictOpSrc, src, NULL, dst,
181303b705cfSriastradh			      box.x1, box.y1,
181403b705cfSriastradh			      0, 0,
181503b705cfSriastradh			      0, 0,
181603b705cfSriastradh			      w, h);
181703b705cfSriastradh		FreePicture(dst, 0);
181803b705cfSriastradh		FreePicture(src, 0);
181903b705cfSriastradh
182003b705cfSriastradh		channel->bo = __sna_pixmap_get_bo(tmp);
182103b705cfSriastradh		kgem_bo_reference(channel->bo);
182203b705cfSriastradh		screen->DestroyPixmap(tmp);
182303b705cfSriastradh	} else {
182403b705cfSriastradh		pixman_image_t *src, *dst;
182503b705cfSriastradh		void *ptr;
182603b705cfSriastradh
182703b705cfSriastradh		if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ))
182803b705cfSriastradh			return 0;
182903b705cfSriastradh
183003b705cfSriastradh		src = pixman_image_create_bits(picture->format,
183103b705cfSriastradh					       pixmap->drawable.width,
183203b705cfSriastradh					       pixmap->drawable.height,
183303b705cfSriastradh					       pixmap->devPrivate.ptr,
183403b705cfSriastradh					       pixmap->devKind);
183503b705cfSriastradh		if (!src)
183603b705cfSriastradh			return 0;
183703b705cfSriastradh
183803b705cfSriastradh		if (PICT_FORMAT_RGB(picture->format) == 0) {
183903b705cfSriastradh			channel->pict_format = PIXMAN_a8;
184003b705cfSriastradh			DBG(("%s: converting to a8 from %08x\n",
184103b705cfSriastradh			     __FUNCTION__, picture->format));
184203b705cfSriastradh		} else {
184303b705cfSriastradh			channel->pict_format = PIXMAN_a8r8g8b8;
184403b705cfSriastradh			DBG(("%s: converting to a8r8g8b8 from %08x\n",
184503b705cfSriastradh			     __FUNCTION__, picture->format));
184603b705cfSriastradh		}
184703b705cfSriastradh
184803b705cfSriastradh		channel->bo = kgem_create_buffer_2d(&sna->kgem,
184903b705cfSriastradh						    w, h, PIXMAN_FORMAT_BPP(channel->pict_format),
185003b705cfSriastradh						    KGEM_BUFFER_WRITE_INPLACE,
185103b705cfSriastradh						    &ptr);
185203b705cfSriastradh		if (!channel->bo) {
185303b705cfSriastradh			pixman_image_unref(src);
185403b705cfSriastradh			return 0;
185503b705cfSriastradh		}
185603b705cfSriastradh
185703b705cfSriastradh		dst = pixman_image_create_bits(channel->pict_format,
185803b705cfSriastradh					       w, h, ptr, channel->bo->pitch);
185903b705cfSriastradh		if (!dst) {
186003b705cfSriastradh			kgem_bo_destroy(&sna->kgem, channel->bo);
186103b705cfSriastradh			pixman_image_unref(src);
186203b705cfSriastradh			return 0;
186303b705cfSriastradh		}
186403b705cfSriastradh
186503b705cfSriastradh		pixman_image_composite(PictOpSrc, src, NULL, dst,
186603b705cfSriastradh				       box.x1, box.y1,
186703b705cfSriastradh				       0, 0,
186803b705cfSriastradh				       0, 0,
186903b705cfSriastradh				       w, h);
187003b705cfSriastradh		pixman_image_unref(dst);
187103b705cfSriastradh		pixman_image_unref(src);
187203b705cfSriastradh	}
187303b705cfSriastradh
187403b705cfSriastradh	channel->width  = w;
187503b705cfSriastradh	channel->height = h;
187603b705cfSriastradh
187703b705cfSriastradh	channel->scale[0] = 1.f/w;
187803b705cfSriastradh	channel->scale[1] = 1.f/h;
187903b705cfSriastradh	channel->offset[0] = x - dst_x - box.x1;
188003b705cfSriastradh	channel->offset[1] = y - dst_y - box.y1;
188103b705cfSriastradh
188203b705cfSriastradh	DBG(("%s: offset=(%d, %d), size=(%d, %d)\n",
188303b705cfSriastradh	     __FUNCTION__,
188403b705cfSriastradh	     channel->offset[0], channel->offset[1],
188503b705cfSriastradh	     channel->width, channel->height));
188603b705cfSriastradh	return 1;
188703b705cfSriastradh}
188803b705cfSriastradh
188903b705cfSriastradhbool
189003b705cfSriastradhsna_render_composite_redirect(struct sna *sna,
189103b705cfSriastradh			      struct sna_composite_op *op,
189203b705cfSriastradh			      int x, int y, int width, int height,
189303b705cfSriastradh			      bool partial)
189403b705cfSriastradh{
189503b705cfSriastradh	struct sna_composite_redirect *t = &op->redirect;
189603b705cfSriastradh	int bpp = op->dst.pixmap->drawable.bitsPerPixel;
189703b705cfSriastradh	struct kgem_bo *bo;
189803b705cfSriastradh
189903b705cfSriastradh	assert(t->real_bo == NULL);
190003b705cfSriastradh
190103b705cfSriastradh#if NO_REDIRECT
190203b705cfSriastradh	return false;
190303b705cfSriastradh#endif
190403b705cfSriastradh
190503b705cfSriastradh	DBG(("%s: target too large (%dx%d), copying to temporary %dx%d, max %d / %d\n",
190603b705cfSriastradh	     __FUNCTION__,
190703b705cfSriastradh	     op->dst.width, op->dst.height,
190803b705cfSriastradh	     width, height,
190903b705cfSriastradh	     sna->render.max_3d_size,
191003b705cfSriastradh	     sna->render.max_3d_pitch));
191103b705cfSriastradh
191203b705cfSriastradh	if (!width || !height)
191303b705cfSriastradh		return false;
191403b705cfSriastradh
191503b705cfSriastradh	if (width  > sna->render.max_3d_size ||
191603b705cfSriastradh	    height > sna->render.max_3d_size)
191703b705cfSriastradh		return false;
191803b705cfSriastradh
191903b705cfSriastradh	if (op->dst.bo->pitch <= sna->render.max_3d_pitch) {
192003b705cfSriastradh		BoxRec box;
192103b705cfSriastradh		int w, h, offset;
192203b705cfSriastradh
192303b705cfSriastradh		DBG(("%s: dst pitch (%d) fits within render pipeline (%d)\n",
192403b705cfSriastradh		     __FUNCTION__, op->dst.bo->pitch, sna->render.max_3d_pitch));
192503b705cfSriastradh
192603b705cfSriastradh		box.x1 = x + op->dst.x;
192703b705cfSriastradh		box.x2 = bound(box.x1, width);
192803b705cfSriastradh		box.y1 = y + op->dst.y;
192903b705cfSriastradh		box.y2 = bound(box.y1, height);
193003b705cfSriastradh
193103b705cfSriastradh		if (box.x1 < 0)
193203b705cfSriastradh			box.x1 = 0;
193303b705cfSriastradh		if (box.y1 < 0)
193403b705cfSriastradh			box.y1 = 0;
193503b705cfSriastradh
193603b705cfSriastradh		/* Ensure we align to an even tile row */
193703b705cfSriastradh		if (op->dst.bo->tiling) {
193803b705cfSriastradh			int tile_width, tile_height, tile_size;
193903b705cfSriastradh
194003b705cfSriastradh			kgem_get_tile_size(&sna->kgem, op->dst.bo->tiling,
194103b705cfSriastradh					   &tile_width, &tile_height, &tile_size);
194203b705cfSriastradh
194303b705cfSriastradh			box.y1 = box.y1 & ~(2*tile_height - 1);
194403b705cfSriastradh			box.y2 = ALIGN(box.y2, 2*tile_height);
194503b705cfSriastradh
194603b705cfSriastradh			box.x1 = box.x1 & ~(tile_width * 8 / op->dst.pixmap->drawable.bitsPerPixel - 1);
194703b705cfSriastradh			box.x2 = ALIGN(box.x2, tile_width * 8 / op->dst.pixmap->drawable.bitsPerPixel);
194803b705cfSriastradh
194903b705cfSriastradh			offset = box.x1 * op->dst.pixmap->drawable.bitsPerPixel / 8 / tile_width * tile_size;
195003b705cfSriastradh		} else {
195103b705cfSriastradh			if (sna->kgem.gen < 040) {
195203b705cfSriastradh				box.y1 = box.y1 & ~3;
195303b705cfSriastradh				box.y2 = ALIGN(box.y2, 4);
195403b705cfSriastradh
195503b705cfSriastradh				box.x1 = box.x1 & ~3;
195603b705cfSriastradh				box.x2 = ALIGN(box.x2, 4);
195703b705cfSriastradh			} else {
195803b705cfSriastradh				box.y1 = box.y1 & ~1;
195903b705cfSriastradh				box.y2 = ALIGN(box.y2, 2);
196003b705cfSriastradh
196103b705cfSriastradh				box.x1 = box.x1 & ~1;
196203b705cfSriastradh				box.x2 = ALIGN(box.x2, 2);
196303b705cfSriastradh			}
196403b705cfSriastradh
196503b705cfSriastradh			offset = box.x1 * op->dst.pixmap->drawable.bitsPerPixel / 8;
196603b705cfSriastradh		}
196703b705cfSriastradh
196803b705cfSriastradh		if (box.y2 > op->dst.pixmap->drawable.height)
196903b705cfSriastradh			box.y2 = op->dst.pixmap->drawable.height;
197003b705cfSriastradh
197103b705cfSriastradh		if (box.x2 > op->dst.pixmap->drawable.width)
197203b705cfSriastradh			box.x2 = op->dst.pixmap->drawable.width;
197303b705cfSriastradh
197403b705cfSriastradh		w = box.x2 - box.x1;
197503b705cfSriastradh		h = box.y2 - box.y1;
197603b705cfSriastradh		DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d), max %d\n", __FUNCTION__,
197703b705cfSriastradh		     box.x1, box.y1, box.x2, box.y2, w, h,
197803b705cfSriastradh		     op->dst.pixmap->drawable.width,
197903b705cfSriastradh		     op->dst.pixmap->drawable.height,
198003b705cfSriastradh		     sna->render.max_3d_size));
198103b705cfSriastradh		if (w <= sna->render.max_3d_size &&
198203b705cfSriastradh		    h <= sna->render.max_3d_size) {
198303b705cfSriastradh			t->box.x2 = t->box.x1 = op->dst.x;
198403b705cfSriastradh			t->box.y2 = t->box.y1 = op->dst.y;
198503b705cfSriastradh			t->real_bo = op->dst.bo;
198603b705cfSriastradh			t->real_damage = op->damage;
198703b705cfSriastradh			if (op->damage) {
198803b705cfSriastradh				assert(!DAMAGE_IS_ALL(op->damage));
198903b705cfSriastradh				t->damage = sna_damage_create();
199003b705cfSriastradh				op->damage = &t->damage;
199103b705cfSriastradh			}
199203b705cfSriastradh
199303b705cfSriastradh			/* How many tiles across are we? */
199403b705cfSriastradh			op->dst.bo = kgem_create_proxy(&sna->kgem, op->dst.bo,
199503b705cfSriastradh						       box.y1 * op->dst.bo->pitch + offset,
199603b705cfSriastradh						       h * op->dst.bo->pitch);
199703b705cfSriastradh			if (!op->dst.bo) {
199803b705cfSriastradh				t->real_bo = NULL;
199903b705cfSriastradh				if (t->damage)
200003b705cfSriastradh					__sna_damage_destroy(t->damage);
200103b705cfSriastradh				return false;
200203b705cfSriastradh			}
200303b705cfSriastradh
200403b705cfSriastradh			assert(op->dst.bo != t->real_bo);
200503b705cfSriastradh			op->dst.bo->unique_id = kgem_get_unique_id(&sna->kgem);
200603b705cfSriastradh			op->dst.bo->pitch = t->real_bo->pitch;
200703b705cfSriastradh
200803b705cfSriastradh			op->dst.x -= box.x1;
200903b705cfSriastradh			op->dst.y -= box.y1;
201003b705cfSriastradh			op->dst.width  = w;
201103b705cfSriastradh			op->dst.height = h;
201203b705cfSriastradh			return true;
201303b705cfSriastradh		}
201403b705cfSriastradh	}
201503b705cfSriastradh
201603b705cfSriastradh	/* We can process the operation in a single pass,
201703b705cfSriastradh	 * but the target is too large for the 3D pipeline.
201803b705cfSriastradh	 * Copy into a smaller surface and replace afterwards.
201903b705cfSriastradh	 */
202003b705cfSriastradh	bo = kgem_create_2d(&sna->kgem,
202103b705cfSriastradh			    width, height, bpp,
202203b705cfSriastradh			    kgem_choose_tiling(&sna->kgem, I915_TILING_X,
202303b705cfSriastradh					       width, height, bpp),
202403b705cfSriastradh			    CREATE_TEMPORARY);
202503b705cfSriastradh	if (!bo)
202603b705cfSriastradh		return false;
202703b705cfSriastradh
202803b705cfSriastradh	t->box.x1 = x + op->dst.x;
202903b705cfSriastradh	t->box.y1 = y + op->dst.y;
203003b705cfSriastradh	t->box.x2 = bound(t->box.x1, width);
203103b705cfSriastradh	t->box.y2 = bound(t->box.y1, height);
203203b705cfSriastradh
203303b705cfSriastradh	DBG(("%s: original box (%d, %d), (%d, %d)\n",
203403b705cfSriastradh	     __FUNCTION__, t->box.x1, t->box.y1, t->box.x2, t->box.y2));
203503b705cfSriastradh
203603b705cfSriastradh	if (partial &&
203703b705cfSriastradh	    !sna_blt_copy_boxes(sna, GXcopy,
203803b705cfSriastradh				op->dst.bo, 0, 0,
203903b705cfSriastradh				bo, -t->box.x1, -t->box.y1,
204003b705cfSriastradh				bpp, &t->box, 1)) {
204103b705cfSriastradh		kgem_bo_destroy(&sna->kgem, bo);
204203b705cfSriastradh		return false;
204303b705cfSriastradh	}
204403b705cfSriastradh
204503b705cfSriastradh	t->real_bo = op->dst.bo;
204603b705cfSriastradh	t->real_damage = op->damage;
204703b705cfSriastradh	if (op->damage) {
204803b705cfSriastradh		assert(!DAMAGE_IS_ALL(op->damage));
204903b705cfSriastradh		t->damage = sna_damage_create();
205003b705cfSriastradh		op->damage = &t->damage;
205103b705cfSriastradh	}
205203b705cfSriastradh
205303b705cfSriastradh	op->dst.bo = bo;
205403b705cfSriastradh	op->dst.x = -x;
205503b705cfSriastradh	op->dst.y = -y;
205603b705cfSriastradh	op->dst.width  = width;
205703b705cfSriastradh	op->dst.height = height;
205803b705cfSriastradh	return true;
205903b705cfSriastradh}
206003b705cfSriastradh
206103b705cfSriastradhvoid
206203b705cfSriastradhsna_render_composite_redirect_done(struct sna *sna,
206303b705cfSriastradh				   const struct sna_composite_op *op)
206403b705cfSriastradh{
206503b705cfSriastradh	const struct sna_composite_redirect *t = &op->redirect;
206603b705cfSriastradh
206703b705cfSriastradh	if (t->real_bo) {
206803b705cfSriastradh		assert(op->dst.bo != t->real_bo);
206903b705cfSriastradh
207003b705cfSriastradh		if (t->box.x2 > t->box.x1) {
207103b705cfSriastradh			bool ok;
207203b705cfSriastradh
207303b705cfSriastradh			DBG(("%s: copying temporary to dst\n", __FUNCTION__));
207403b705cfSriastradh			ok = sna_blt_copy_boxes(sna, GXcopy,
207503b705cfSriastradh						op->dst.bo, -t->box.x1, -t->box.y1,
207603b705cfSriastradh						t->real_bo, 0, 0,
207703b705cfSriastradh						op->dst.pixmap->drawable.bitsPerPixel,
207803b705cfSriastradh						&t->box, 1);
207903b705cfSriastradh			assert(ok);
208003b705cfSriastradh			(void)ok;
208103b705cfSriastradh		}
208203b705cfSriastradh		if (t->damage) {
208303b705cfSriastradh			DBG(("%s: combining damage (all? %d), offset=(%d, %d)\n",
208403b705cfSriastradh			     __FUNCTION__, (int)DAMAGE_IS_ALL(t->damage),
208503b705cfSriastradh			     t->box.x1, t->box.y1));
208603b705cfSriastradh			sna_damage_combine(t->real_damage,
208703b705cfSriastradh					   DAMAGE_PTR(t->damage),
208803b705cfSriastradh					   t->box.x1, t->box.y1);
208903b705cfSriastradh			__sna_damage_destroy(DAMAGE_PTR(t->damage));
209003b705cfSriastradh		}
209103b705cfSriastradh
209203b705cfSriastradh		kgem_bo_destroy(&sna->kgem, op->dst.bo);
209303b705cfSriastradh	}
209403b705cfSriastradh}
209503b705cfSriastradh
209603b705cfSriastradhbool
209703b705cfSriastradhsna_render_copy_boxes__overlap(struct sna *sna, uint8_t alu,
209803b705cfSriastradh			       PixmapPtr src, struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy,
209903b705cfSriastradh			       PixmapPtr dst, struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy,
210003b705cfSriastradh			       const BoxRec *box, int n, const BoxRec *extents)
210103b705cfSriastradh{
210203b705cfSriastradh	ScreenPtr screen = dst->drawable.pScreen;
210303b705cfSriastradh	struct kgem_bo *bo;
210403b705cfSriastradh	PixmapPtr tmp;
210503b705cfSriastradh	bool ret = false;
210603b705cfSriastradh
210703b705cfSriastradh	tmp = screen->CreatePixmap(screen,
210803b705cfSriastradh				   extents->x2 - extents->x1,
210903b705cfSriastradh				   extents->y2 - extents->y1,
211003b705cfSriastradh				   dst->drawable.depth,
211103b705cfSriastradh				   SNA_CREATE_SCRATCH);
211203b705cfSriastradh	if (tmp == NULL)
211303b705cfSriastradh		return false;
211403b705cfSriastradh
211503b705cfSriastradh	bo = __sna_pixmap_get_bo(tmp);
211603b705cfSriastradh	if (bo == NULL)
211703b705cfSriastradh		goto out;
211803b705cfSriastradh
211903b705cfSriastradh	ret = (sna->render.copy_boxes(sna, alu,
212003b705cfSriastradh				      src, src_bo, src_dx, src_dy,
212103b705cfSriastradh				      tmp, bo, -extents->x1, -extents->y1,
212203b705cfSriastradh				      box, n , 0) &&
212303b705cfSriastradh	       sna->render.copy_boxes(sna, alu,
212403b705cfSriastradh				      tmp, bo, -extents->x1, -extents->y1,
212503b705cfSriastradh				      dst, dst_bo, dst_dx, dst_dy,
212603b705cfSriastradh				      box, n , 0));
212703b705cfSriastradh
212803b705cfSriastradhout:
212903b705cfSriastradh	screen->DestroyPixmap(tmp);
213003b705cfSriastradh	return ret;
213103b705cfSriastradh}
2132