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
2842542f5fSchristos#ifdef HAVE_CONFIG_H
2942542f5fSchristos#include "config.h"
3042542f5fSchristos#endif
3142542f5fSchristos
3203b705cfSriastradh#include "sna.h"
3303b705cfSriastradh#include "sna_render.h"
3403b705cfSriastradh#include "sna_render_inline.h"
3503b705cfSriastradh#include "fb/fbpict.h"
3603b705cfSriastradh
3703b705cfSriastradh#define NO_REDIRECT 0
3803b705cfSriastradh#define NO_CONVERT 0
3903b705cfSriastradh#define NO_FIXUP 0
4003b705cfSriastradh#define NO_EXTRACT 0
4103b705cfSriastradh
4203b705cfSriastradh#define DBG_FORCE_UPLOAD 0
4303b705cfSriastradh#define DBG_NO_CPU_BO 0
4403b705cfSriastradh
4503b705cfSriastradh#define alphaless(format) PICT_FORMAT(PICT_FORMAT_BPP(format),		\
4603b705cfSriastradh				      PICT_FORMAT_TYPE(format),		\
4703b705cfSriastradh				      0,				\
4803b705cfSriastradh				      PICT_FORMAT_R(format),		\
4903b705cfSriastradh				      PICT_FORMAT_G(format),		\
5003b705cfSriastradh				      PICT_FORMAT_B(format))
5103b705cfSriastradh
5203b705cfSriastradhCARD32
5303b705cfSriastradhsna_format_for_depth(int depth)
5403b705cfSriastradh{
5503b705cfSriastradh	switch (depth) {
5603b705cfSriastradh	case 1: return PICT_a1;
57fe8aea9eSmrg	case 4: return PICT_x4a4;
5803b705cfSriastradh	case 8: return PICT_a8;
5903b705cfSriastradh	case 15: return PICT_x1r5g5b5;
6003b705cfSriastradh	case 16: return PICT_r5g6b5;
6103b705cfSriastradh	default: assert(0);
6203b705cfSriastradh	case 24: return PICT_x8r8g8b8;
63fe8aea9eSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,6,99,900,0)
6403b705cfSriastradh	case 30: return PICT_x2r10g10b10;
6542542f5fSchristos#endif
6603b705cfSriastradh	case 32: return PICT_a8r8g8b8;
6703b705cfSriastradh	}
6803b705cfSriastradh}
6903b705cfSriastradh
7003b705cfSriastradhCARD32
7103b705cfSriastradhsna_render_format_for_depth(int depth)
7203b705cfSriastradh{
7303b705cfSriastradh	switch (depth) {
7403b705cfSriastradh	case 1: return PIXMAN_a1;
7503b705cfSriastradh	case 4: return PIXMAN_a4;
7603b705cfSriastradh	case 8: return PIXMAN_a8;
7703b705cfSriastradh	case 15: return PIXMAN_a1r5g5b5;
7803b705cfSriastradh	case 16: return PIXMAN_r5g6b5;
7903b705cfSriastradh	case 30: return PIXMAN_a2r10g10b10;
8003b705cfSriastradh	default: assert(0);
8103b705cfSriastradh	case 24:
8203b705cfSriastradh	case 32: return PIXMAN_a8r8g8b8;
8303b705cfSriastradh	}
8403b705cfSriastradh}
8503b705cfSriastradh
8603b705cfSriastradhstatic bool
8703b705cfSriastradhno_render_composite(struct sna *sna,
8803b705cfSriastradh		    uint8_t op,
8903b705cfSriastradh		    PicturePtr src,
9003b705cfSriastradh		    PicturePtr mask,
9103b705cfSriastradh		    PicturePtr dst,
9203b705cfSriastradh		    int16_t src_x, int16_t src_y,
9303b705cfSriastradh		    int16_t mask_x, int16_t mask_y,
9403b705cfSriastradh		    int16_t dst_x, int16_t dst_y,
9503b705cfSriastradh		    int16_t width, int16_t height,
9642542f5fSchristos		    unsigned flags,
9703b705cfSriastradh		    struct sna_composite_op *tmp)
9803b705cfSriastradh{
9903b705cfSriastradh	DBG(("%s (op=%d, mask? %d)\n", __FUNCTION__, op, mask != NULL));
10003b705cfSriastradh
10103b705cfSriastradh	if (mask)
10203b705cfSriastradh		return false;
10303b705cfSriastradh
10403b705cfSriastradh	if (!is_gpu(sna, dst->pDrawable, PREFER_GPU_BLT) &&
10503b705cfSriastradh	    (src->pDrawable == NULL || !is_gpu(sna, src->pDrawable, PREFER_GPU_BLT)))
10603b705cfSriastradh		return false;
10703b705cfSriastradh
10803b705cfSriastradh	return sna_blt_composite(sna,
10903b705cfSriastradh				 op, src, dst,
11003b705cfSriastradh				 src_x, src_y,
11103b705cfSriastradh				 dst_x, dst_y,
11203b705cfSriastradh				 width, height,
11342542f5fSchristos				 flags | COMPOSITE_FALLBACK, tmp);
11403b705cfSriastradh	(void)mask_x;
11503b705cfSriastradh	(void)mask_y;
11603b705cfSriastradh}
11703b705cfSriastradh
11803b705cfSriastradhstatic bool
11903b705cfSriastradhno_render_check_composite_spans(struct sna *sna,
12003b705cfSriastradh				uint8_t op, PicturePtr src, PicturePtr dst,
12103b705cfSriastradh				int16_t width,  int16_t height, unsigned flags)
12203b705cfSriastradh{
12303b705cfSriastradh	return false;
12403b705cfSriastradh}
12503b705cfSriastradh
12603b705cfSriastradhstatic bool
12703b705cfSriastradhno_render_copy_boxes(struct sna *sna, uint8_t alu,
12842542f5fSchristos		     const DrawableRec *src, struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy,
12942542f5fSchristos		     const DrawableRec *dst, struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy,
13003b705cfSriastradh		     const BoxRec *box, int n, unsigned flags)
13103b705cfSriastradh{
13203b705cfSriastradh	DBG(("%s (n=%d)\n", __FUNCTION__, n));
13303b705cfSriastradh
13442542f5fSchristos	if (!sna_blt_compare_depth(src, dst))
13503b705cfSriastradh		return false;
13603b705cfSriastradh
13703b705cfSriastradh	return sna_blt_copy_boxes(sna, alu,
13803b705cfSriastradh				  src_bo, src_dx, src_dy,
13903b705cfSriastradh				  dst_bo, dst_dx, dst_dy,
14042542f5fSchristos				  dst->bitsPerPixel,
14103b705cfSriastradh				  box, n);
14203b705cfSriastradh}
14303b705cfSriastradh
14403b705cfSriastradhstatic bool
14503b705cfSriastradhno_render_copy(struct sna *sna, uint8_t alu,
14603b705cfSriastradh		 PixmapPtr src, struct kgem_bo *src_bo,
14703b705cfSriastradh		 PixmapPtr dst, struct kgem_bo *dst_bo,
14803b705cfSriastradh		 struct sna_copy_op *tmp)
14903b705cfSriastradh{
15003b705cfSriastradh	DBG(("%s ()\n", __FUNCTION__));
15103b705cfSriastradh
15203b705cfSriastradh	if (sna_blt_compare_depth(&src->drawable, &dst->drawable) &&
15303b705cfSriastradh	    sna_blt_copy(sna, alu,
15403b705cfSriastradh			 src_bo, dst_bo, dst->drawable.bitsPerPixel,
15503b705cfSriastradh			 tmp))
15603b705cfSriastradh		return true;
15703b705cfSriastradh
15803b705cfSriastradh	return false;
15903b705cfSriastradh}
16003b705cfSriastradh
16103b705cfSriastradhstatic bool
16203b705cfSriastradhno_render_fill_boxes(struct sna *sna,
16303b705cfSriastradh		     CARD8 op,
16403b705cfSriastradh		     PictFormat format,
16503b705cfSriastradh		     const xRenderColor *color,
16642542f5fSchristos		     const DrawableRec *dst, struct kgem_bo *dst_bo,
16703b705cfSriastradh		     const BoxRec *box, int n)
16803b705cfSriastradh{
16903b705cfSriastradh	uint8_t alu = GXcopy;
17003b705cfSriastradh	uint32_t pixel;
17103b705cfSriastradh
17203b705cfSriastradh	DBG(("%s (op=%d, color=(%04x,%04x,%04x, %04x))\n",
17303b705cfSriastradh	     __FUNCTION__, op,
17403b705cfSriastradh	     color->red, color->green, color->blue, color->alpha));
17503b705cfSriastradh
17603b705cfSriastradh	if (op == PictOpClear) {
17703b705cfSriastradh		pixel = 0;
17803b705cfSriastradh		alu = GXclear;
17903b705cfSriastradh		op = PictOpSrc;
18003b705cfSriastradh	}
18103b705cfSriastradh
18203b705cfSriastradh	if (op == PictOpOver) {
18303b705cfSriastradh		if ((color->alpha >= 0xff00))
18403b705cfSriastradh			op = PictOpSrc;
18503b705cfSriastradh	}
18603b705cfSriastradh
18703b705cfSriastradh	if (op != PictOpSrc)
18803b705cfSriastradh		return false;
18903b705cfSriastradh
19003b705cfSriastradh	if (alu == GXcopy &&
19103b705cfSriastradh	    !sna_get_pixel_from_rgba(&pixel,
19203b705cfSriastradh				     color->red,
19303b705cfSriastradh				     color->green,
19403b705cfSriastradh				     color->blue,
19503b705cfSriastradh				     color->alpha,
19603b705cfSriastradh				     format))
19703b705cfSriastradh		return false;
19803b705cfSriastradh
19903b705cfSriastradh	return sna_blt_fill_boxes(sna, alu,
20042542f5fSchristos				  dst_bo, dst->bitsPerPixel,
20103b705cfSriastradh				  pixel, box, n);
20203b705cfSriastradh}
20303b705cfSriastradh
20403b705cfSriastradhstatic bool
20503b705cfSriastradhno_render_fill(struct sna *sna, uint8_t alu,
20603b705cfSriastradh	       PixmapPtr dst, struct kgem_bo *dst_bo,
20742542f5fSchristos	       uint32_t color, unsigned flags,
20803b705cfSriastradh	       struct sna_fill_op *tmp)
20903b705cfSriastradh{
21003b705cfSriastradh	DBG(("%s (alu=%d, color=%08x)\n", __FUNCTION__, alu, color));
21103b705cfSriastradh	return sna_blt_fill(sna, alu,
21203b705cfSriastradh			    dst_bo, dst->drawable.bitsPerPixel,
21303b705cfSriastradh			    color,
21403b705cfSriastradh			    tmp);
21503b705cfSriastradh}
21603b705cfSriastradh
21703b705cfSriastradhstatic bool
21803b705cfSriastradhno_render_fill_one(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo,
21903b705cfSriastradh		   uint32_t color,
22003b705cfSriastradh		   int16_t x1, int16_t y1, int16_t x2, int16_t y2,
22103b705cfSriastradh		   uint8_t alu)
22203b705cfSriastradh{
22303b705cfSriastradh	BoxRec box;
22403b705cfSriastradh
22503b705cfSriastradh	box.x1 = x1;
22603b705cfSriastradh	box.y1 = y1;
22703b705cfSriastradh	box.x2 = x2;
22803b705cfSriastradh	box.y2 = y2;
22903b705cfSriastradh
23003b705cfSriastradh	DBG(("%s (alu=%d, color=%08x) (%d,%d), (%d, %d)\n",
23103b705cfSriastradh	     __FUNCTION__, alu, color, x1, y1, x2, y2));
23203b705cfSriastradh	return sna_blt_fill_boxes(sna, alu,
23303b705cfSriastradh				  bo, dst->drawable.bitsPerPixel,
23403b705cfSriastradh				  color, &box, 1);
23503b705cfSriastradh}
23603b705cfSriastradh
23703b705cfSriastradhstatic bool
23803b705cfSriastradhno_render_clear(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo)
23903b705cfSriastradh{
24003b705cfSriastradh	DBG(("%s: pixmap=%ld %dx%d\n", __FUNCTION__,
24103b705cfSriastradh	     dst->drawable.serialNumber,
24203b705cfSriastradh	     dst->drawable.width,
24303b705cfSriastradh	     dst->drawable.height));
24403b705cfSriastradh	return sna->render.fill_one(sna, dst, bo, 0,
24503b705cfSriastradh				    0, 0, dst->drawable.width, dst->drawable.height,
24603b705cfSriastradh				    GXclear);
24703b705cfSriastradh}
24803b705cfSriastradh
24903b705cfSriastradhstatic void no_render_reset(struct sna *sna)
25003b705cfSriastradh{
25103b705cfSriastradh	(void)sna;
25203b705cfSriastradh}
25303b705cfSriastradh
25403b705cfSriastradhstatic void no_render_flush(struct sna *sna)
25503b705cfSriastradh{
25603b705cfSriastradh	(void)sna;
25703b705cfSriastradh}
25803b705cfSriastradh
25903b705cfSriastradhstatic void
26003b705cfSriastradhno_render_context_switch(struct kgem *kgem,
26103b705cfSriastradh			 int new_mode)
26203b705cfSriastradh{
26303b705cfSriastradh	if (!kgem->nbatch)
26403b705cfSriastradh		return;
26503b705cfSriastradh
26603b705cfSriastradh	if (kgem_ring_is_idle(kgem, kgem->ring)) {
26703b705cfSriastradh		DBG(("%s: GPU idle, flushing\n", __FUNCTION__));
26803b705cfSriastradh		_kgem_submit(kgem);
26903b705cfSriastradh	}
27003b705cfSriastradh
27103b705cfSriastradh	(void)new_mode;
27203b705cfSriastradh}
27303b705cfSriastradh
27403b705cfSriastradhstatic void
27503b705cfSriastradhno_render_fini(struct sna *sna)
27603b705cfSriastradh{
27703b705cfSriastradh	(void)sna;
27803b705cfSriastradh}
27903b705cfSriastradh
28003b705cfSriastradhconst char *no_render_init(struct sna *sna)
28103b705cfSriastradh{
28203b705cfSriastradh	struct sna_render *render = &sna->render;
28303b705cfSriastradh
28403b705cfSriastradh	memset (render, 0, sizeof (*render));
28503b705cfSriastradh
28603b705cfSriastradh	render->prefer_gpu = PREFER_GPU_BLT;
28703b705cfSriastradh
28803b705cfSriastradh	render->vertices = render->vertex_data;
28903b705cfSriastradh	render->vertex_size = ARRAY_SIZE(render->vertex_data);
29003b705cfSriastradh
29103b705cfSriastradh	render->composite = no_render_composite;
29203b705cfSriastradh	render->check_composite_spans = no_render_check_composite_spans;
29303b705cfSriastradh
29403b705cfSriastradh	render->copy_boxes = no_render_copy_boxes;
29503b705cfSriastradh	render->copy = no_render_copy;
29603b705cfSriastradh
29703b705cfSriastradh	render->fill_boxes = no_render_fill_boxes;
29803b705cfSriastradh	render->fill = no_render_fill;
29903b705cfSriastradh	render->fill_one = no_render_fill_one;
30003b705cfSriastradh	render->clear = no_render_clear;
30103b705cfSriastradh
30203b705cfSriastradh	render->reset = no_render_reset;
30303b705cfSriastradh	render->flush = no_render_flush;
30403b705cfSriastradh	render->fini = no_render_fini;
30503b705cfSriastradh
30603b705cfSriastradh	sna->kgem.context_switch = no_render_context_switch;
30703b705cfSriastradh	if (sna->kgem.has_blt)
30803b705cfSriastradh		sna->kgem.ring = KGEM_BLT;
30903b705cfSriastradh
31003b705cfSriastradh	sna_vertex_init(sna);
31103b705cfSriastradh	return "generic";
31203b705cfSriastradh}
31303b705cfSriastradh
31403b705cfSriastradhstatic struct kgem_bo *
31503b705cfSriastradhuse_cpu_bo(struct sna *sna, PixmapPtr pixmap, const BoxRec *box, bool blt)
31603b705cfSriastradh{
31703b705cfSriastradh	struct sna_pixmap *priv;
31803b705cfSriastradh
31903b705cfSriastradh	if (DBG_NO_CPU_BO)
32003b705cfSriastradh		return NULL;
32103b705cfSriastradh
32203b705cfSriastradh	priv = sna_pixmap(pixmap);
32303b705cfSriastradh	if (priv == NULL || priv->cpu_bo == NULL) {
32403b705cfSriastradh		DBG(("%s: no cpu bo\n", __FUNCTION__));
32503b705cfSriastradh		return NULL;
32603b705cfSriastradh	}
32703b705cfSriastradh
32803b705cfSriastradh	if (!blt && priv->cpu_bo->snoop && priv->source_count > SOURCE_BIAS) {
32903b705cfSriastradh		DBG(("%s: promoting snooped CPU bo due to reuse\n",
33003b705cfSriastradh		     __FUNCTION__));
33103b705cfSriastradh		return NULL;
33203b705cfSriastradh	}
33303b705cfSriastradh
33403b705cfSriastradh	if (priv->gpu_bo) {
33542542f5fSchristos		switch (sna_damage_contains_box(&priv->cpu_damage, box)) {
33603b705cfSriastradh		case PIXMAN_REGION_OUT:
33703b705cfSriastradh			DBG(("%s: has GPU bo and no damage to upload\n",
33803b705cfSriastradh			     __FUNCTION__));
33903b705cfSriastradh			return NULL;
34003b705cfSriastradh
34103b705cfSriastradh		case PIXMAN_REGION_IN:
34203b705cfSriastradh			DBG(("%s: has GPU bo but box is completely on CPU\n",
34303b705cfSriastradh			     __FUNCTION__));
34403b705cfSriastradh			break;
34503b705cfSriastradh		default:
34603b705cfSriastradh			if (kgem_bo_is_busy(priv->gpu_bo)){
34703b705cfSriastradh				DBG(("%s: box is partially damaged on the CPU, and the GPU is busy\n",
34803b705cfSriastradh				     __FUNCTION__));
34903b705cfSriastradh				return NULL;
35003b705cfSriastradh			}
35142542f5fSchristos			if (sna_damage_contains_box(&priv->gpu_damage,
35203b705cfSriastradh						    box) != PIXMAN_REGION_OUT) {
35303b705cfSriastradh				DBG(("%s: box is damaged on the GPU\n",
35403b705cfSriastradh				     __FUNCTION__));
35503b705cfSriastradh				return NULL;
35603b705cfSriastradh			}
35703b705cfSriastradh			break;
35803b705cfSriastradh		}
35903b705cfSriastradh	}
36003b705cfSriastradh
36103b705cfSriastradh	if (!blt) {
36203b705cfSriastradh		int w = box->x2 - box->x1;
36303b705cfSriastradh		int h = box->y2 - box->y1;
36403b705cfSriastradh
36503b705cfSriastradh		if (w < pixmap->drawable.width ||
36603b705cfSriastradh		    h < pixmap->drawable.height ||
36703b705cfSriastradh		    priv->source_count != SOURCE_BIAS) {
36803b705cfSriastradh			bool want_tiling;
36903b705cfSriastradh
37003b705cfSriastradh			if (priv->cpu_bo->pitch >= 4096) {
37103b705cfSriastradh				DBG(("%s: size=%dx%d, promoting reused (%d) CPU bo due to TLB miss (%dx%d, pitch=%d)\n",
37203b705cfSriastradh				     __FUNCTION__, w, h, priv->source_count,
37303b705cfSriastradh				     pixmap->drawable.width,
37403b705cfSriastradh				     pixmap->drawable.height,
37503b705cfSriastradh				     priv->cpu_bo->pitch));
37603b705cfSriastradh				return NULL;
37703b705cfSriastradh			}
37803b705cfSriastradh
37903b705cfSriastradh			if (priv->gpu_bo)
38003b705cfSriastradh				want_tiling = priv->gpu_bo->tiling != I915_TILING_NONE;
38103b705cfSriastradh			else
38203b705cfSriastradh				want_tiling = kgem_choose_tiling(&sna->kgem,
38303b705cfSriastradh								 I915_TILING_Y,
38403b705cfSriastradh								 pixmap->drawable.width,
38503b705cfSriastradh								 pixmap->drawable.height,
38603b705cfSriastradh								 pixmap->drawable.bitsPerPixel) != I915_TILING_NONE;
38703b705cfSriastradh			if (want_tiling &&
38803b705cfSriastradh			    priv->source_count*w*h >= (int)pixmap->drawable.width * pixmap->drawable.height) {
38903b705cfSriastradh				DBG(("%s: pitch (%d) requires tiling\n",
39003b705cfSriastradh				     __FUNCTION__, priv->cpu_bo->pitch));
39103b705cfSriastradh				return NULL;
39203b705cfSriastradh			}
39303b705cfSriastradh		}
39403b705cfSriastradh	}
39503b705cfSriastradh
396fe8aea9eSmrg	add_shm_flush(sna, priv);
39703b705cfSriastradh
39803b705cfSriastradh	DBG(("%s for box=(%d, %d), (%d, %d)\n",
39903b705cfSriastradh	     __FUNCTION__, box->x1, box->y1, box->x2, box->y2));
40003b705cfSriastradh	++priv->source_count;
40103b705cfSriastradh	return priv->cpu_bo;
40203b705cfSriastradh}
40303b705cfSriastradh
40403b705cfSriastradhstatic struct kgem_bo *
40503b705cfSriastradhmove_to_gpu(PixmapPtr pixmap, const BoxRec *box, bool blt)
40603b705cfSriastradh{
40703b705cfSriastradh	struct sna_pixmap *priv;
40803b705cfSriastradh	int count, w, h;
40903b705cfSriastradh	bool migrate = false;
41003b705cfSriastradh
41103b705cfSriastradh	if (DBG_FORCE_UPLOAD > 0)
41203b705cfSriastradh		return NULL;
41303b705cfSriastradh
41403b705cfSriastradh	priv = sna_pixmap(pixmap);
41503b705cfSriastradh	if (priv == NULL) {
41613496ba1Ssnj		DBG(("%s: not migrating unattached pixmap=%ld\n",
41713496ba1Ssnj		     __FUNCTION__, pixmap->drawable.serialNumber));
41803b705cfSriastradh		return NULL;
41903b705cfSriastradh	}
42003b705cfSriastradh
42103b705cfSriastradh	if (priv->shm)
42203b705cfSriastradh		blt = true;
42303b705cfSriastradh
42403b705cfSriastradh	if (priv->gpu_bo) {
42503b705cfSriastradh		if (priv->cpu_damage &&
42642542f5fSchristos		    sna_damage_contains_box(&priv->cpu_damage,
42703b705cfSriastradh					    box) != PIXMAN_REGION_OUT)
42803b705cfSriastradh			goto upload;
42903b705cfSriastradh
43003b705cfSriastradh		return priv->gpu_bo;
43103b705cfSriastradh	}
43203b705cfSriastradh
43303b705cfSriastradh	if (priv->cpu_damage == NULL) {
43413496ba1Ssnj		DBG(("%s: not migrating uninitialised pixmap=%ld\n",
43513496ba1Ssnj		     __FUNCTION__, pixmap->drawable.serialNumber));
43603b705cfSriastradh		return NULL;
43703b705cfSriastradh	}
43803b705cfSriastradh
43903b705cfSriastradh	if (pixmap->usage_hint) {
44013496ba1Ssnj		DBG(("%s: not migrating pixmap=%ld due to usage_hint=%d\n",
44113496ba1Ssnj		     __FUNCTION__,
44213496ba1Ssnj		     pixmap->drawable.serialNumber,
44313496ba1Ssnj		     pixmap->usage_hint));
44403b705cfSriastradh		return NULL;
44503b705cfSriastradh	}
44603b705cfSriastradh
44703b705cfSriastradh	if (DBG_FORCE_UPLOAD < 0) {
44803b705cfSriastradh		if (!sna_pixmap_force_to_gpu(pixmap,
44913496ba1Ssnj					     blt ? MOVE_READ : MOVE_SOURCE_HINT | MOVE_ASYNC_HINT | MOVE_READ))
45003b705cfSriastradh			return NULL;
45103b705cfSriastradh
45203b705cfSriastradh		return priv->gpu_bo;
45303b705cfSriastradh	}
45403b705cfSriastradh
45503b705cfSriastradh	w = box->x2 - box->x1;
45603b705cfSriastradh	h = box->y2 - box->y1;
45703b705cfSriastradh	if (priv->cpu_bo && !priv->cpu_bo->flush) {
45803b705cfSriastradh		migrate = true;
45903b705cfSriastradh	} else if (w == pixmap->drawable.width && h == pixmap->drawable.height) {
46003b705cfSriastradh		migrate = priv->source_count++ > SOURCE_BIAS;
46103b705cfSriastradh
46203b705cfSriastradh		DBG(("%s: migrating whole pixmap (%dx%d) for source (%d,%d),(%d,%d), count %d? %d\n",
46303b705cfSriastradh		     __FUNCTION__,
46403b705cfSriastradh		     pixmap->drawable.width, pixmap->drawable.height,
46503b705cfSriastradh		     box->x1, box->y1, box->x2, box->y2, priv->source_count,
46603b705cfSriastradh		     migrate));
46703b705cfSriastradh	} else if (kgem_choose_tiling(&to_sna_from_pixmap(pixmap)->kgem,
46803b705cfSriastradh				      blt ? I915_TILING_X : I915_TILING_Y, w, h,
46903b705cfSriastradh				      pixmap->drawable.bitsPerPixel) != I915_TILING_NONE) {
47003b705cfSriastradh		count = priv->source_count++;
47103b705cfSriastradh		if ((priv->create & KGEM_CAN_CREATE_GPU) == 0)
47203b705cfSriastradh			count -= SOURCE_BIAS;
47303b705cfSriastradh
47403b705cfSriastradh		DBG(("%s: migrate box (%d, %d), (%d, %d)? source count=%d, fraction=%d/%d [%d]\n",
47503b705cfSriastradh		     __FUNCTION__,
47603b705cfSriastradh		     box->x1, box->y1, box->x2, box->y2,
47703b705cfSriastradh		     count, w*h,
47803b705cfSriastradh		     pixmap->drawable.width * pixmap->drawable.height,
47903b705cfSriastradh		     pixmap->drawable.width * pixmap->drawable.height / (w*h)));
48003b705cfSriastradh
48103b705cfSriastradh		migrate = count*w*h > pixmap->drawable.width * pixmap->drawable.height;
48203b705cfSriastradh	}
48303b705cfSriastradh
48403b705cfSriastradh	if (!migrate)
48503b705cfSriastradh		return NULL;
48603b705cfSriastradh
48703b705cfSriastradhupload:
48803b705cfSriastradh	if (blt) {
48903b705cfSriastradh		if (!sna_pixmap_move_area_to_gpu(pixmap, box,
49003b705cfSriastradh						 __MOVE_FORCE | MOVE_READ))
49103b705cfSriastradh			return NULL;
49203b705cfSriastradh	} else {
49303b705cfSriastradh		if (!sna_pixmap_move_to_gpu(pixmap,
49413496ba1Ssnj					    __MOVE_FORCE | MOVE_ASYNC_HINT | MOVE_SOURCE_HINT | MOVE_READ))
49503b705cfSriastradh			return NULL;
49603b705cfSriastradh	}
49703b705cfSriastradh
49803b705cfSriastradh	return priv->gpu_bo;
49903b705cfSriastradh}
50003b705cfSriastradh
50103b705cfSriastradhstatic struct kgem_bo *upload(struct sna *sna,
50203b705cfSriastradh			      struct sna_composite_channel *channel,
50303b705cfSriastradh			      PixmapPtr pixmap,
50403b705cfSriastradh			      const BoxRec *box)
50503b705cfSriastradh{
50603b705cfSriastradh	struct sna_pixmap *priv;
50703b705cfSriastradh	struct kgem_bo *bo;
50803b705cfSriastradh
50903b705cfSriastradh	DBG(("%s: box=(%d, %d), (%d, %d), pixmap=%dx%d\n",
51003b705cfSriastradh	     __FUNCTION__, box->x1, box->y1, box->x2, box->y2, pixmap->drawable.width, pixmap->drawable.height));
51103b705cfSriastradh	assert(box->x1 >= 0);
51203b705cfSriastradh	assert(box->y1 >= 0);
51303b705cfSriastradh	assert(box->x2 <= pixmap->drawable.width);
51403b705cfSriastradh	assert(box->y2 <= pixmap->drawable.height);
51503b705cfSriastradh
51603b705cfSriastradh	priv = sna_pixmap(pixmap);
51703b705cfSriastradh	if (priv) {
51803b705cfSriastradh		RegionRec region;
51903b705cfSriastradh
52003b705cfSriastradh		if (priv->cpu_damage == NULL)
52103b705cfSriastradh			return NULL; /* uninitialised */
52203b705cfSriastradh
52303b705cfSriastradh		region.extents = *box;
52403b705cfSriastradh		region.data = NULL;
52503b705cfSriastradh		if (!sna_drawable_move_region_to_cpu(&pixmap->drawable,
52603b705cfSriastradh						     &region, MOVE_READ))
52703b705cfSriastradh			return NULL;
52803b705cfSriastradh
52903b705cfSriastradh		assert(!priv->mapped);
53003b705cfSriastradh		if (pixmap->devPrivate.ptr == NULL)
53103b705cfSriastradh			return NULL; /* uninitialised */
53203b705cfSriastradh	}
53303b705cfSriastradh
53403b705cfSriastradh	bo = kgem_upload_source_image(&sna->kgem,
53503b705cfSriastradh				      pixmap->devPrivate.ptr, box,
53603b705cfSriastradh				      pixmap->devKind,
53703b705cfSriastradh				      pixmap->drawable.bitsPerPixel);
53803b705cfSriastradh	if (channel && bo) {
53903b705cfSriastradh		channel->width  = box->x2 - box->x1;
54003b705cfSriastradh		channel->height = box->y2 - box->y1;
54103b705cfSriastradh		channel->offset[0] -= box->x1;
54203b705cfSriastradh		channel->offset[1] -= box->y1;
54303b705cfSriastradh
54403b705cfSriastradh		if (priv &&
54503b705cfSriastradh		    pixmap->usage_hint == 0 &&
54603b705cfSriastradh		    channel->width  == pixmap->drawable.width &&
54703b705cfSriastradh		    channel->height == pixmap->drawable.height) {
54803b705cfSriastradh			DBG(("%s: adding upload cache to pixmap=%ld\n",
54903b705cfSriastradh			     __FUNCTION__, pixmap->drawable.serialNumber));
55003b705cfSriastradh			assert(priv->gpu_damage == NULL);
55103b705cfSriastradh			assert(priv->gpu_bo == NULL);
55203b705cfSriastradh			assert(bo->proxy != NULL);
553fe8aea9eSmrg			sna_damage_all(&priv->cpu_damage, pixmap);
55403b705cfSriastradh			kgem_proxy_bo_attach(bo, &priv->gpu_bo);
55503b705cfSriastradh		}
55603b705cfSriastradh	}
55703b705cfSriastradh
55803b705cfSriastradh	return bo;
55903b705cfSriastradh}
56003b705cfSriastradh
56103b705cfSriastradhstruct kgem_bo *
56203b705cfSriastradh__sna_render_pixmap_bo(struct sna *sna,
56303b705cfSriastradh		       PixmapPtr pixmap,
56403b705cfSriastradh		       const BoxRec *box,
56503b705cfSriastradh		       bool blt)
56603b705cfSriastradh{
56703b705cfSriastradh	struct kgem_bo *bo;
56803b705cfSriastradh
56903b705cfSriastradh	bo = use_cpu_bo(sna, pixmap, box, blt);
57003b705cfSriastradh	if (bo == NULL) {
57103b705cfSriastradh		bo = move_to_gpu(pixmap, box, blt);
57203b705cfSriastradh		if (bo == NULL)
57303b705cfSriastradh			return NULL;
57403b705cfSriastradh	}
57503b705cfSriastradh
57603b705cfSriastradh	return bo;
57703b705cfSriastradh}
57803b705cfSriastradh
57903b705cfSriastradhint
58003b705cfSriastradhsna_render_pixmap_bo(struct sna *sna,
58103b705cfSriastradh		     struct sna_composite_channel *channel,
58203b705cfSriastradh		     PixmapPtr pixmap,
58303b705cfSriastradh		     int16_t x, int16_t y,
58403b705cfSriastradh		     int16_t w, int16_t h,
58503b705cfSriastradh		     int16_t dst_x, int16_t dst_y)
58603b705cfSriastradh{
58703b705cfSriastradh	struct sna_pixmap *priv;
58803b705cfSriastradh	BoxRec box;
58903b705cfSriastradh
59003b705cfSriastradh	DBG(("%s pixmap=%ld, (%d, %d)x(%d, %d)/(%d, %d)\n",
59103b705cfSriastradh	     __FUNCTION__, pixmap->drawable.serialNumber,
59203b705cfSriastradh	     x, y, w,h, pixmap->drawable.width, pixmap->drawable.height));
59303b705cfSriastradh
59403b705cfSriastradh	channel->width  = pixmap->drawable.width;
59503b705cfSriastradh	channel->height = pixmap->drawable.height;
59603b705cfSriastradh	channel->offset[0] = x - dst_x;
59703b705cfSriastradh	channel->offset[1] = y - dst_y;
59803b705cfSriastradh
59903b705cfSriastradh	priv = sna_pixmap(pixmap);
60003b705cfSriastradh	if (priv) {
60103b705cfSriastradh		if (priv->gpu_bo &&
60203b705cfSriastradh		    (DAMAGE_IS_ALL(priv->gpu_damage) || !priv->cpu_damage ||
60303b705cfSriastradh		     priv->gpu_bo->proxy)) {
60403b705cfSriastradh			DBG(("%s: GPU all damaged\n", __FUNCTION__));
60503b705cfSriastradh			channel->bo = priv->gpu_bo;
60603b705cfSriastradh			goto done;
60703b705cfSriastradh		}
60803b705cfSriastradh
60903b705cfSriastradh		if (priv->cpu_bo &&
61003b705cfSriastradh		    (DAMAGE_IS_ALL(priv->cpu_damage) || !priv->gpu_damage) &&
61103b705cfSriastradh		    !priv->cpu_bo->snoop && priv->cpu_bo->pitch < 4096) {
61203b705cfSriastradh			DBG(("%s: CPU all damaged\n", __FUNCTION__));
61303b705cfSriastradh			channel->bo = priv->cpu_bo;
614fe8aea9eSmrg			add_shm_flush(sna, priv);
61503b705cfSriastradh			goto done;
61603b705cfSriastradh		}
61703b705cfSriastradh	}
61803b705cfSriastradh
61903b705cfSriastradh	/* XXX handle transformed repeat */
62003b705cfSriastradh	if (w == 0 || h == 0 || channel->transform) {
62103b705cfSriastradh		box.x1 = box.y1 = 0;
62203b705cfSriastradh		box.x2 = pixmap->drawable.width;
62303b705cfSriastradh		box.y2 = pixmap->drawable.height;
62403b705cfSriastradh	} else {
62503b705cfSriastradh		box.x1 = x;
62603b705cfSriastradh		box.y1 = y;
62703b705cfSriastradh		box.x2 = bound(x, w);
62803b705cfSriastradh		box.y2 = bound(y, h);
62903b705cfSriastradh
63003b705cfSriastradh		if (channel->repeat == RepeatNone || channel->repeat == RepeatPad) {
63103b705cfSriastradh			if (box.x1 < 0)
63203b705cfSriastradh				box.x1 = 0;
63303b705cfSriastradh			if (box.y1 < 0)
63403b705cfSriastradh				box.y1 = 0;
63503b705cfSriastradh			if (box.x2 > pixmap->drawable.width)
63603b705cfSriastradh				box.x2 = pixmap->drawable.width;
63703b705cfSriastradh			if (box.y2 > pixmap->drawable.height)
63803b705cfSriastradh				box.y2 = pixmap->drawable.height;
63903b705cfSriastradh		} else {
64003b705cfSriastradh			if (box.x1 < 0 || box.x2 > pixmap->drawable.width)
64103b705cfSriastradh				box.x1 = 0, box.x2 = pixmap->drawable.width;
64203b705cfSriastradh			if (box.y1 < 0 || box.y2 > pixmap->drawable.height)
64303b705cfSriastradh				box.y1 = 0, box.y2 = pixmap->drawable.height;
64403b705cfSriastradh		}
64503b705cfSriastradh	}
64603b705cfSriastradh
64703b705cfSriastradh	w = box.x2 - box.x1;
64803b705cfSriastradh	h = box.y2 - box.y1;
64903b705cfSriastradh	DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d)\n", __FUNCTION__,
65003b705cfSriastradh	     box.x1, box.y1, box.x2, box.y2, w, h,
65103b705cfSriastradh	     pixmap->drawable.width, pixmap->drawable.height));
65203b705cfSriastradh	if (w <= 0 || h <= 0) {
65303b705cfSriastradh		DBG(("%s: sample extents outside of texture -> clear\n",
65403b705cfSriastradh		     __FUNCTION__));
65503b705cfSriastradh		return 0;
65603b705cfSriastradh	}
65703b705cfSriastradh
65803b705cfSriastradh	DBG(("%s: offset=(%d, %d), size=(%d, %d)\n",
65903b705cfSriastradh	     __FUNCTION__,
66003b705cfSriastradh	     channel->offset[0], channel->offset[1],
66103b705cfSriastradh	     pixmap->drawable.width, pixmap->drawable.height));
66203b705cfSriastradh
66303b705cfSriastradh	channel->bo = __sna_render_pixmap_bo(sna, pixmap, &box, false);
66403b705cfSriastradh	if (channel->bo == NULL) {
66503b705cfSriastradh		DBG(("%s: uploading CPU box (%d, %d), (%d, %d)\n",
66603b705cfSriastradh		     __FUNCTION__, box.x1, box.y1, box.x2, box.y2));
66703b705cfSriastradh		channel->bo = upload(sna, channel, pixmap, &box);
66803b705cfSriastradh		if (channel->bo == NULL)
66903b705cfSriastradh			return 0;
67003b705cfSriastradh	} else {
67103b705cfSriastradhdone:
67203b705cfSriastradh		kgem_bo_reference(channel->bo);
67303b705cfSriastradh	}
67403b705cfSriastradh
67503b705cfSriastradh	channel->scale[0] = 1.f / channel->width;
67603b705cfSriastradh	channel->scale[1] = 1.f / channel->height;
67703b705cfSriastradh	return 1;
67803b705cfSriastradh}
67903b705cfSriastradh
68003b705cfSriastradhstatic int sna_render_picture_downsample(struct sna *sna,
68103b705cfSriastradh					 PicturePtr picture,
68203b705cfSriastradh					 struct sna_composite_channel *channel,
68303b705cfSriastradh					 const int16_t x, const int16_t y,
68403b705cfSriastradh					 const int16_t w, const int16_t h,
68503b705cfSriastradh					 const int16_t dst_x, const int16_t dst_y)
68603b705cfSriastradh{
68703b705cfSriastradh	PixmapPtr pixmap = get_drawable_pixmap(picture->pDrawable);
68803b705cfSriastradh	ScreenPtr screen = pixmap->drawable.pScreen;
68903b705cfSriastradh	PicturePtr tmp_src, tmp_dst;
69003b705cfSriastradh	PictFormatPtr format;
69103b705cfSriastradh	struct sna_pixmap *priv;
69203b705cfSriastradh	pixman_transform_t t;
69303b705cfSriastradh	PixmapPtr tmp;
69442542f5fSchristos	int width, height, size, max_size;
69503b705cfSriastradh	int sx, sy, sw, sh;
69603b705cfSriastradh	int error, ret = 0;
69703b705cfSriastradh	BoxRec box, b;
69803b705cfSriastradh
69903b705cfSriastradh	box.x1 = x;
70003b705cfSriastradh	box.y1 = y;
70103b705cfSriastradh	box.x2 = bound(x, w);
70203b705cfSriastradh	box.y2 = bound(y, h);
70303b705cfSriastradh	if (channel->transform) {
70403b705cfSriastradh		pixman_vector_t v;
70503b705cfSriastradh
70603b705cfSriastradh		pixman_transform_bounds(channel->transform, &box);
70703b705cfSriastradh
70803b705cfSriastradh		v.vector[0] = x << 16;
70903b705cfSriastradh		v.vector[1] = y << 16;
71003b705cfSriastradh		v.vector[2] = 1 << 16;
71103b705cfSriastradh		pixman_transform_point(channel->transform, &v);
71203b705cfSriastradh	}
71303b705cfSriastradh
71403b705cfSriastradh	if (channel->repeat == RepeatNone || channel->repeat == RepeatPad) {
71503b705cfSriastradh		if (box.x1 < 0)
71603b705cfSriastradh			box.x1 = 0;
71703b705cfSriastradh		if (box.y1 < 0)
71803b705cfSriastradh			box.y1 = 0;
71903b705cfSriastradh		if (box.x2 > pixmap->drawable.width)
72003b705cfSriastradh			box.x2 = pixmap->drawable.width;
72103b705cfSriastradh		if (box.y2 > pixmap->drawable.height)
72203b705cfSriastradh			box.y2 = pixmap->drawable.height;
72303b705cfSriastradh	} else {
72403b705cfSriastradh		/* XXX tiled repeats? */
72503b705cfSriastradh		if (box.x1 < 0 || box.x2 > pixmap->drawable.width)
72603b705cfSriastradh			box.x1 = 0, box.x2 = pixmap->drawable.width;
72703b705cfSriastradh		if (box.y1 < 0 || box.y2 > pixmap->drawable.height)
72803b705cfSriastradh			box.y1 = 0, box.y2 = pixmap->drawable.height;
72903b705cfSriastradh
73003b705cfSriastradh	}
73103b705cfSriastradh
73203b705cfSriastradh	sw = box.x2 - box.x1;
73303b705cfSriastradh	sh = box.y2 - box.y1;
73403b705cfSriastradh
73503b705cfSriastradh	DBG(("%s: sample (%d, %d), (%d, %d)\n",
73603b705cfSriastradh	     __FUNCTION__, box.x1, box.y1, box.x2, box.y2));
73703b705cfSriastradh
73803b705cfSriastradh	sx = (sw + sna->render.max_3d_size - 1) / sna->render.max_3d_size;
73903b705cfSriastradh	sy = (sh + sna->render.max_3d_size - 1) / sna->render.max_3d_size;
74003b705cfSriastradh
74103b705cfSriastradh	DBG(("%s: scaling (%d, %d) down by %dx%d\n",
74203b705cfSriastradh	     __FUNCTION__, sw, sh, sx, sy));
74303b705cfSriastradh
74403b705cfSriastradh	width  = sw / sx;
74503b705cfSriastradh	height = sh / sy;
74603b705cfSriastradh
74703b705cfSriastradh	DBG(("%s: creating temporary GPU bo %dx%d\n",
74803b705cfSriastradh	     __FUNCTION__, width, height));
74903b705cfSriastradh
75003b705cfSriastradh	tmp = screen->CreatePixmap(screen,
75103b705cfSriastradh				   width, height,
75203b705cfSriastradh				   pixmap->drawable.depth,
75303b705cfSriastradh				   SNA_CREATE_SCRATCH);
75442542f5fSchristos	if (tmp == NULL)
75542542f5fSchristos		goto fixup;
75603b705cfSriastradh
75703b705cfSriastradh	priv = sna_pixmap(tmp);
75842542f5fSchristos	assert(priv && priv->gpu_bo);
75942542f5fSchristos
76013496ba1Ssnj	if (!sna_pixmap_move_to_gpu(pixmap, MOVE_ASYNC_HINT | MOVE_SOURCE_HINT | MOVE_READ)) {
76142542f5fSchristosfixup:
76242542f5fSchristos		DBG(("%s: unable to create GPU bo for target or temporary pixmaps\n",
76342542f5fSchristos		     __FUNCTION__));
76442542f5fSchristos		return sna_render_picture_fixup(sna, picture, channel,
76542542f5fSchristos						x, y, w, h,
76642542f5fSchristos						dst_x, dst_y);
76742542f5fSchristos	}
76803b705cfSriastradh
76903b705cfSriastradh	format = PictureMatchFormat(screen,
77003b705cfSriastradh				    pixmap->drawable.depth,
77103b705cfSriastradh				    picture->format);
77242542f5fSchristos	if (format == NULL) {
77342542f5fSchristos		DBG(("%s: invalid depth=%d, format=%08x\n",
77442542f5fSchristos		     __FUNCTION__, pixmap->drawable.depth, picture->format));
77542542f5fSchristos		goto fixup;
77642542f5fSchristos	}
77703b705cfSriastradh
77803b705cfSriastradh	tmp_dst = CreatePicture(0, &tmp->drawable, format, 0, NULL,
77903b705cfSriastradh				serverClient, &error);
78003b705cfSriastradh	if (!tmp_dst)
78103b705cfSriastradh		goto cleanup_tmp;
78203b705cfSriastradh
78303b705cfSriastradh	tmp_src = CreatePicture(0, &pixmap->drawable, format, 0, NULL,
78403b705cfSriastradh				serverClient, &error);
78503b705cfSriastradh	if (!tmp_src)
78603b705cfSriastradh		goto cleanup_dst;
78703b705cfSriastradh
78803b705cfSriastradh	tmp_src->repeat = 1;
78903b705cfSriastradh	tmp_src->repeatType = RepeatPad;
79003b705cfSriastradh	/* Prefer to use nearest as it helps reduce artefacts from
79103b705cfSriastradh	 * interpolating and filtering twice.
79203b705cfSriastradh	 */
79303b705cfSriastradh	tmp_src->filter = PictFilterNearest;
79403b705cfSriastradh	memset(&t, 0, sizeof(t));
79503b705cfSriastradh	t.matrix[0][0] = (sw << 16) / width;
79603b705cfSriastradh	t.matrix[0][2] = box.x1 << 16;
79703b705cfSriastradh	t.matrix[1][1] = (sh << 16) / height;
79803b705cfSriastradh	t.matrix[1][2] = box.y1 << 16;
79903b705cfSriastradh	t.matrix[2][2] = 1 << 16;
80003b705cfSriastradh	tmp_src->transform = &t;
80103b705cfSriastradh
80203b705cfSriastradh	ValidatePicture(tmp_dst);
80303b705cfSriastradh	ValidatePicture(tmp_src);
80403b705cfSriastradh
80503b705cfSriastradh	/* Use a small size to accommodate enlargement through tile alignment */
80642542f5fSchristos	max_size = sna_max_tile_copy_size(sna, sna_pixmap(pixmap)->gpu_bo, priv->gpu_bo);
80742542f5fSchristos	if (max_size == 0)
80842542f5fSchristos		goto cleanup_dst;
80942542f5fSchristos
81003b705cfSriastradh	size = sna->render.max_3d_size - 4096 / pixmap->drawable.bitsPerPixel;
81142542f5fSchristos	while (size * size * 4 > max_size)
81203b705cfSriastradh		size /= 2;
81313496ba1Ssnj	DBG(("%s: size=%d (max=%d), scale %dx%d\n",
81413496ba1Ssnj	     __FUNCTION__, size, max_size, sx, sy));
81503b705cfSriastradh
81603b705cfSriastradh	sw = size / sx - 2 * sx;
81713496ba1Ssnj	if (sw < 1)
81813496ba1Ssnj		sw = 1;
81903b705cfSriastradh	sh = size / sy - 2 * sy;
82013496ba1Ssnj	if (sh < 1)
82113496ba1Ssnj		sh = 1;
82203b705cfSriastradh	DBG(("%s %d:%d downsampling using %dx%d GPU tiles\n",
82303b705cfSriastradh	     __FUNCTION__, (width + sw-1)/sw, (height + sh-1)/sh, sw, sh));
82403b705cfSriastradh
82503b705cfSriastradh	for (b.y1 = 0; b.y1 < height; b.y1 = b.y2) {
82603b705cfSriastradh		b.y2 = b.y1 + sh;
82703b705cfSriastradh		if (b.y2 > height)
82803b705cfSriastradh			b.y2 = height;
82903b705cfSriastradh
83003b705cfSriastradh		for (b.x1 = 0; b.x1 < width; b.x1 = b.x2) {
83103b705cfSriastradh			struct sna_composite_op op;
83203b705cfSriastradh
83303b705cfSriastradh			b.x2 = b.x1 + sw;
83403b705cfSriastradh			if (b.x2 > width)
83503b705cfSriastradh				b.x2 = width;
83603b705cfSriastradh
83703b705cfSriastradh			DBG(("%s: tile (%d, %d), (%d, %d)\n",
83803b705cfSriastradh			     __FUNCTION__, b.x1, b.y1, b.x2, b.y2));
83903b705cfSriastradh
84003b705cfSriastradh			memset(&op, 0, sizeof(op));
84103b705cfSriastradh			if (!sna->render.composite(sna,
84203b705cfSriastradh						   PictOpSrc,
84303b705cfSriastradh						   tmp_src, NULL, tmp_dst,
84403b705cfSriastradh						   b.x1, b.y1,
84503b705cfSriastradh						   0, 0,
84603b705cfSriastradh						   b.x1, b.y1,
84703b705cfSriastradh						   b.x2 - b.x1, b.y2 - b.y1,
84842542f5fSchristos						   0, &op))
84903b705cfSriastradh				goto cleanup_src;
85003b705cfSriastradh
85103b705cfSriastradh			op.box(sna, &op, &b);
85203b705cfSriastradh			op.done(sna, &op);
85303b705cfSriastradh		}
85403b705cfSriastradh	}
85503b705cfSriastradh
85603b705cfSriastradh	pixman_transform_invert(&channel->embedded_transform, &t);
85703b705cfSriastradh	if (channel->transform)
85803b705cfSriastradh		pixman_transform_multiply(&channel->embedded_transform,
85903b705cfSriastradh					  &channel->embedded_transform,
86003b705cfSriastradh					  channel->transform);
86103b705cfSriastradh	channel->transform = &channel->embedded_transform;
86203b705cfSriastradh
86303b705cfSriastradh	channel->offset[0] = x - dst_x;
86403b705cfSriastradh	channel->offset[1] = y - dst_y;
86503b705cfSriastradh	channel->scale[0] = 1.f/width;
86603b705cfSriastradh	channel->scale[1] = 1.f/height;
86703b705cfSriastradh	channel->width  = width;
86803b705cfSriastradh	channel->height = height;
86903b705cfSriastradh	channel->bo = kgem_bo_reference(priv->gpu_bo);
87003b705cfSriastradh
87103b705cfSriastradh	ret = 1;
87203b705cfSriastradhcleanup_src:
87303b705cfSriastradh	tmp_src->transform = NULL;
87403b705cfSriastradh	FreePicture(tmp_src, 0);
87503b705cfSriastradhcleanup_dst:
87603b705cfSriastradh	FreePicture(tmp_dst, 0);
87703b705cfSriastradhcleanup_tmp:
87803b705cfSriastradh	screen->DestroyPixmap(tmp);
87903b705cfSriastradh	return ret;
88003b705cfSriastradh}
88103b705cfSriastradh
88203b705cfSriastradhbool
88303b705cfSriastradhsna_render_pixmap_partial(struct sna *sna,
88442542f5fSchristos			  const DrawableRec *draw,
88503b705cfSriastradh			  struct kgem_bo *bo,
88603b705cfSriastradh			  struct sna_composite_channel *channel,
88703b705cfSriastradh			  int16_t x, int16_t y,
88803b705cfSriastradh			  int16_t w, int16_t h)
88903b705cfSriastradh{
89003b705cfSriastradh	BoxRec box;
89103b705cfSriastradh	int offset;
89203b705cfSriastradh
89303b705cfSriastradh	DBG(("%s (%d, %d)x(%d, %d), pitch %d, max %d\n",
89403b705cfSriastradh	     __FUNCTION__, x, y, w, h, bo->pitch, sna->render.max_3d_pitch));
89503b705cfSriastradh
89642542f5fSchristos	if (bo->pitch > sna->render.max_3d_pitch) {
89742542f5fSchristos		DBG(("%s: pitch too great %d > %d\n", __FUNCTION__, bo->pitch, sna->render.max_3d_pitch));
89803b705cfSriastradh		return false;
89942542f5fSchristos	}
90003b705cfSriastradh
90103b705cfSriastradh	box.x1 = x;
90203b705cfSriastradh	box.y1 = y;
90303b705cfSriastradh	box.x2 = bound(x, w);
90403b705cfSriastradh	box.y2 = bound(y, h);
90503b705cfSriastradh	DBG(("%s: unaligned box (%d, %d), (%d, %d)\n",
90603b705cfSriastradh	     __FUNCTION__, box.x1, box.y1, box.x2, box.y2));
90703b705cfSriastradh
90803b705cfSriastradh	if (box.x1 < 0)
90903b705cfSriastradh		box.x1 = 0;
91003b705cfSriastradh	if (box.y1 < 0)
91103b705cfSriastradh		box.y1 = 0;
91203b705cfSriastradh
91303b705cfSriastradh	if (bo->tiling) {
91403b705cfSriastradh		int tile_width, tile_height, tile_size;
91503b705cfSriastradh
91642542f5fSchristos		kgem_get_tile_size(&sna->kgem, bo->tiling, bo->pitch,
91703b705cfSriastradh				   &tile_width, &tile_height, &tile_size);
91803b705cfSriastradh		DBG(("%s: tile size for tiling %d: %dx%d, size=%d\n",
91903b705cfSriastradh		     __FUNCTION__, bo->tiling, tile_width, tile_height, tile_size));
92003b705cfSriastradh
92103b705cfSriastradh		/* Ensure we align to an even tile row */
92203b705cfSriastradh		box.y1 = box.y1 & ~(2*tile_height - 1);
92303b705cfSriastradh		box.y2 = ALIGN(box.y2, 2*tile_height);
92403b705cfSriastradh
92542542f5fSchristos		assert(tile_width * 8 >= draw->bitsPerPixel);
92642542f5fSchristos		box.x1 = box.x1 & ~(tile_width * 8 / draw->bitsPerPixel - 1);
92742542f5fSchristos		box.x2 = ALIGN(box.x2, tile_width * 8 / draw->bitsPerPixel);
92803b705cfSriastradh
92942542f5fSchristos		offset = box.x1 * draw->bitsPerPixel / 8 / tile_width * tile_size;
93003b705cfSriastradh	} else {
93103b705cfSriastradh		box.y1 = box.y1 & ~1;
93203b705cfSriastradh		box.y2 = ALIGN(box.y2, 2);
93303b705cfSriastradh
93403b705cfSriastradh		box.x1 = box.x1 & ~1;
93503b705cfSriastradh		box.x2 = ALIGN(box.x2, 2);
93603b705cfSriastradh
93742542f5fSchristos		offset = box.x1 * draw->bitsPerPixel / 8;
93803b705cfSriastradh	}
93903b705cfSriastradh
94042542f5fSchristos	if (box.x2 > draw->width)
94142542f5fSchristos		box.x2 = draw->width;
94242542f5fSchristos	if (box.y2 > draw->height)
94342542f5fSchristos		box.y2 = draw->height;
94403b705cfSriastradh
94503b705cfSriastradh	w = box.x2 - box.x1;
94603b705cfSriastradh	h = box.y2 - box.y1;
94703b705cfSriastradh	DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d)\n", __FUNCTION__,
94803b705cfSriastradh	     box.x1, box.y1, box.x2, box.y2, w, h,
94942542f5fSchristos	     draw->width, draw->height));
95003b705cfSriastradh	if (w <= 0 || h <= 0 ||
95103b705cfSriastradh	    w > sna->render.max_3d_size ||
95203b705cfSriastradh	    h > sna->render.max_3d_size) {
95303b705cfSriastradh		DBG(("%s: box too large (%dx%d) for 3D pipeline (max %d)\n",
95403b705cfSriastradh		    __FUNCTION__, w, h, sna->render.max_3d_size));
95503b705cfSriastradh		return false;
95603b705cfSriastradh	}
95703b705cfSriastradh
95803b705cfSriastradh	/* How many tiles across are we? */
95903b705cfSriastradh	channel->bo = kgem_create_proxy(&sna->kgem, bo,
96003b705cfSriastradh					box.y1 * bo->pitch + offset,
96103b705cfSriastradh					h * bo->pitch);
96242542f5fSchristos	if (channel->bo == NULL) {
96342542f5fSchristos		DBG(("%s: failed to create proxy for partial (offset=%d, size=%d)\n",
96442542f5fSchristos		     __FUNCTION__, box.y1 * bo->pitch + offset, h * bo->pitch));
96503b705cfSriastradh		return false;
96642542f5fSchristos	}
96703b705cfSriastradh
96803b705cfSriastradh	channel->bo->pitch = bo->pitch;
96903b705cfSriastradh
97003b705cfSriastradh	channel->offset[0] = -box.x1;
97103b705cfSriastradh	channel->offset[1] = -box.y1;
97203b705cfSriastradh	channel->scale[0] = 1.f/w;
97303b705cfSriastradh	channel->scale[1] = 1.f/h;
97403b705cfSriastradh	channel->width  = w;
97503b705cfSriastradh	channel->height = h;
97603b705cfSriastradh	return true;
97703b705cfSriastradh}
97803b705cfSriastradh
97942542f5fSchristosstatic bool
98003b705cfSriastradhsna_render_picture_partial(struct sna *sna,
98103b705cfSriastradh			   PicturePtr picture,
98203b705cfSriastradh			   struct sna_composite_channel *channel,
98303b705cfSriastradh			   int16_t x, int16_t y,
98403b705cfSriastradh			   int16_t w, int16_t h,
98503b705cfSriastradh			   int16_t dst_x, int16_t dst_y)
98603b705cfSriastradh{
98703b705cfSriastradh	struct kgem_bo *bo = NULL;
98803b705cfSriastradh	PixmapPtr pixmap = get_drawable_pixmap(picture->pDrawable);
98903b705cfSriastradh	BoxRec box;
99003b705cfSriastradh	int offset;
99103b705cfSriastradh
99203b705cfSriastradh	DBG(("%s (%d, %d)x(%d, %d) [dst=(%d, %d)]\n",
99303b705cfSriastradh	     __FUNCTION__, x, y, w, h, dst_x, dst_y));
99403b705cfSriastradh
99503b705cfSriastradh	box.x1 = x;
99603b705cfSriastradh	box.y1 = y;
99703b705cfSriastradh	box.x2 = bound(x, w);
99803b705cfSriastradh	box.y2 = bound(y, h);
99903b705cfSriastradh	if (channel->transform)
100003b705cfSriastradh		pixman_transform_bounds(channel->transform, &box);
100103b705cfSriastradh
100203b705cfSriastradh	DBG(("%s sample=(%d, %d), (%d, %d): (%d, %d)/(%d, %d), repeat=%d\n", __FUNCTION__,
100303b705cfSriastradh	     box.x1, box.y1, box.x2, box.y2, w, h,
100403b705cfSriastradh	     pixmap->drawable.width, pixmap->drawable.height,
100503b705cfSriastradh	     channel->repeat));
100603b705cfSriastradh
100703b705cfSriastradh	if (channel->repeat == RepeatNone || channel->repeat == RepeatPad) {
100803b705cfSriastradh		if (box.x1 < 0)
100903b705cfSriastradh			box.x1 = 0;
101003b705cfSriastradh		if (box.y1 < 0)
101103b705cfSriastradh			box.y1 = 0;
101203b705cfSriastradh		if (box.x2 > pixmap->drawable.width)
101303b705cfSriastradh			box.x2 = pixmap->drawable.width;
101403b705cfSriastradh		if (box.y2 > pixmap->drawable.height)
101503b705cfSriastradh			box.y2 = pixmap->drawable.height;
101603b705cfSriastradh	} else {
101703b705cfSriastradh		if (box.x1 < 0 || box.x2 > pixmap->drawable.width)
101803b705cfSriastradh			box.x1 = 0, box.x2 = pixmap->drawable.width;
101903b705cfSriastradh		if (box.y1 < 0 || box.y2 > pixmap->drawable.height)
102003b705cfSriastradh			box.y1 = 0, box.y2 = pixmap->drawable.height;
102103b705cfSriastradh	}
102203b705cfSriastradh
102303b705cfSriastradh	if (use_cpu_bo(sna, pixmap, &box, false)) {
102403b705cfSriastradh		bo = sna_pixmap(pixmap)->cpu_bo;
102503b705cfSriastradh	} else {
102603b705cfSriastradh		struct sna_pixmap *priv;
102703b705cfSriastradh
102803b705cfSriastradh		priv = sna_pixmap_force_to_gpu(pixmap,
102913496ba1Ssnj					       MOVE_READ | MOVE_ASYNC_HINT | MOVE_SOURCE_HINT);
103003b705cfSriastradh		if (priv == NULL)
103142542f5fSchristos			return false;
103203b705cfSriastradh
103303b705cfSriastradh		bo = priv->gpu_bo;
103403b705cfSriastradh	}
103503b705cfSriastradh
103642542f5fSchristos	if (bo->pitch > sna->render.max_3d_pitch) {
103742542f5fSchristos		DBG(("%s: pitch too great %d > %d\n", __FUNCTION__, bo->pitch, sna->render.max_3d_pitch));
103842542f5fSchristos		return false;
103942542f5fSchristos	}
104003b705cfSriastradh
104103b705cfSriastradh	if (bo->tiling) {
104203b705cfSriastradh		int tile_width, tile_height, tile_size;
104303b705cfSriastradh
104442542f5fSchristos		kgem_get_tile_size(&sna->kgem, bo->tiling, bo->pitch,
104503b705cfSriastradh				   &tile_width, &tile_height, &tile_size);
104603b705cfSriastradh
104703b705cfSriastradh		DBG(("%s: tiling=%d, size=%dx%d, chunk=%d\n",
104803b705cfSriastradh		     __FUNCTION__, bo->tiling,
104903b705cfSriastradh		     tile_width, tile_height, tile_size));
105003b705cfSriastradh
105103b705cfSriastradh		/* Ensure we align to an even tile row */
105203b705cfSriastradh		box.y1 = box.y1 & ~(2*tile_height - 1);
105303b705cfSriastradh		box.y2 = ALIGN(box.y2, 2*tile_height);
105403b705cfSriastradh		if (box.y2 > pixmap->drawable.height)
105503b705cfSriastradh			box.y2 = pixmap->drawable.height;
105603b705cfSriastradh
105703b705cfSriastradh		box.x1 = box.x1 & ~(tile_width * 8 / pixmap->drawable.bitsPerPixel - 1);
105803b705cfSriastradh		box.x2 = ALIGN(box.x2, tile_width * 8 / pixmap->drawable.bitsPerPixel);
105903b705cfSriastradh		if (box.x2 > pixmap->drawable.width)
106003b705cfSriastradh			box.x2 = pixmap->drawable.width;
106103b705cfSriastradh
106203b705cfSriastradh		offset = box.x1 * pixmap->drawable.bitsPerPixel / 8 / tile_width * tile_size;
106303b705cfSriastradh	} else
106403b705cfSriastradh		offset = box.x1 * pixmap->drawable.bitsPerPixel / 8;
106503b705cfSriastradh
106603b705cfSriastradh	w = box.x2 - box.x1;
106703b705cfSriastradh	h = box.y2 - box.y1;
106803b705cfSriastradh	DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d)\n", __FUNCTION__,
106903b705cfSriastradh	     box.x1, box.y1, box.x2, box.y2, w, h,
107003b705cfSriastradh	     pixmap->drawable.width, pixmap->drawable.height));
107103b705cfSriastradh	if (w <= 0 || h <= 0 ||
107203b705cfSriastradh	    w > sna->render.max_3d_size ||
107303b705cfSriastradh	    h > sna->render.max_3d_size)
107442542f5fSchristos		return false;
107503b705cfSriastradh
107603b705cfSriastradh	/* How many tiles across are we? */
107703b705cfSriastradh	channel->bo = kgem_create_proxy(&sna->kgem, bo,
107803b705cfSriastradh					box.y1 * bo->pitch + offset,
107903b705cfSriastradh					h * bo->pitch);
108003b705cfSriastradh	if (channel->bo == NULL)
108142542f5fSchristos		return false;
108203b705cfSriastradh
108303b705cfSriastradh	if (channel->transform) {
108403b705cfSriastradh		memset(&channel->embedded_transform,
108503b705cfSriastradh		       0,
108603b705cfSriastradh		       sizeof(channel->embedded_transform));
108703b705cfSriastradh		channel->embedded_transform.matrix[0][0] = 1 << 16;
108803b705cfSriastradh		channel->embedded_transform.matrix[0][2] = -box.x1 << 16;
108903b705cfSriastradh		channel->embedded_transform.matrix[1][1] = 1 << 16;
109003b705cfSriastradh		channel->embedded_transform.matrix[1][2] = -box.y1 << 16;
109103b705cfSriastradh		channel->embedded_transform.matrix[2][2] = 1 << 16;
109203b705cfSriastradh		pixman_transform_multiply(&channel->embedded_transform,
109303b705cfSriastradh					  &channel->embedded_transform,
109403b705cfSriastradh					  channel->transform);
109503b705cfSriastradh		channel->transform = &channel->embedded_transform;
109603b705cfSriastradh	} else {
109703b705cfSriastradh		x -= box.x1;
109803b705cfSriastradh		y -= box.y1;
109903b705cfSriastradh	}
110003b705cfSriastradh
110103b705cfSriastradh	channel->offset[0] = x - dst_x;
110203b705cfSriastradh	channel->offset[1] = y - dst_y;
110303b705cfSriastradh	channel->scale[0] = 1.f/w;
110403b705cfSriastradh	channel->scale[1] = 1.f/h;
110503b705cfSriastradh	channel->width  = w;
110603b705cfSriastradh	channel->height = h;
110742542f5fSchristos	return true;
110803b705cfSriastradh}
110903b705cfSriastradh
111003b705cfSriastradhint
111103b705cfSriastradhsna_render_picture_extract(struct sna *sna,
111203b705cfSriastradh			   PicturePtr picture,
111303b705cfSriastradh			   struct sna_composite_channel *channel,
111403b705cfSriastradh			   int16_t x, int16_t y,
111503b705cfSriastradh			   int16_t w, int16_t h,
111603b705cfSriastradh			   int16_t dst_x, int16_t dst_y)
111703b705cfSriastradh{
111803b705cfSriastradh	struct kgem_bo *bo = NULL, *src_bo;
111903b705cfSriastradh	PixmapPtr pixmap = get_drawable_pixmap(picture->pDrawable);
112003b705cfSriastradh	int16_t ox, oy, ow, oh;
112103b705cfSriastradh	BoxRec box;
112203b705cfSriastradh
112303b705cfSriastradh#if NO_EXTRACT
112403b705cfSriastradh	return -1;
112503b705cfSriastradh#endif
112603b705cfSriastradh
112703b705cfSriastradh	DBG(("%s (%d, %d)x(%d, %d) [dst=(%d, %d)]\n",
112803b705cfSriastradh	     __FUNCTION__, x, y, w, h, dst_x, dst_y));
112903b705cfSriastradh
113003b705cfSriastradh	if (w == 0 || h == 0) {
113103b705cfSriastradh		DBG(("%s: fallback -- unknown bounds\n", __FUNCTION__));
113203b705cfSriastradh		return -1;
113303b705cfSriastradh	}
113403b705cfSriastradh
113503b705cfSriastradh	if (sna_render_picture_partial(sna, picture, channel,
113603b705cfSriastradh				       x, y, w, h,
113703b705cfSriastradh				       dst_x, dst_y))
113803b705cfSriastradh		return 1;
113903b705cfSriastradh
114003b705cfSriastradh	ow = w;
114103b705cfSriastradh	oh = h;
114203b705cfSriastradh
114303b705cfSriastradh	ox = box.x1 = x;
114403b705cfSriastradh	oy = box.y1 = y;
114503b705cfSriastradh	box.x2 = bound(x, w);
114603b705cfSriastradh	box.y2 = bound(y, h);
114703b705cfSriastradh	if (channel->transform) {
114803b705cfSriastradh		pixman_vector_t v;
114903b705cfSriastradh
115003b705cfSriastradh		pixman_transform_bounds(channel->transform, &box);
115103b705cfSriastradh
115203b705cfSriastradh		v.vector[0] = ox << 16;
115303b705cfSriastradh		v.vector[1] = oy << 16;
115403b705cfSriastradh		v.vector[2] =  1 << 16;
115503b705cfSriastradh		pixman_transform_point(channel->transform, &v);
115603b705cfSriastradh		ox = v.vector[0] / v.vector[2];
115703b705cfSriastradh		oy = v.vector[1] / v.vector[2];
115803b705cfSriastradh	}
115903b705cfSriastradh
116003b705cfSriastradh	DBG(("%s sample=(%d, %d), (%d, %d): (%d, %d)/(%d, %d), repeat=%d\n", __FUNCTION__,
116103b705cfSriastradh	     box.x1, box.y1, box.x2, box.y2, w, h,
116203b705cfSriastradh	     pixmap->drawable.width, pixmap->drawable.height,
116303b705cfSriastradh	     channel->repeat));
116403b705cfSriastradh
116503b705cfSriastradh	if (channel->repeat == RepeatNone || channel->repeat == RepeatPad) {
116603b705cfSriastradh		if (box.x1 < 0)
116703b705cfSriastradh			box.x1 = 0;
116803b705cfSriastradh		if (box.y1 < 0)
116903b705cfSriastradh			box.y1 = 0;
117003b705cfSriastradh		if (box.x2 > pixmap->drawable.width)
117103b705cfSriastradh			box.x2 = pixmap->drawable.width;
117203b705cfSriastradh		if (box.y2 > pixmap->drawable.height)
117303b705cfSriastradh			box.y2 = pixmap->drawable.height;
117403b705cfSriastradh	} else {
117503b705cfSriastradh		/* XXX tiled repeats? */
117603b705cfSriastradh		if (box.x1 < 0 || box.x2 > pixmap->drawable.width)
117703b705cfSriastradh			box.x1 = 0, box.x2 = pixmap->drawable.width;
117803b705cfSriastradh		if (box.y1 < 0 || box.y2 > pixmap->drawable.height)
117903b705cfSriastradh			box.y1 = 0, box.y2 = pixmap->drawable.height;
118003b705cfSriastradh	}
118103b705cfSriastradh
118203b705cfSriastradh	w = box.x2 - box.x1;
118303b705cfSriastradh	h = box.y2 - box.y1;
118403b705cfSriastradh	DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d)\n", __FUNCTION__,
118503b705cfSriastradh	     box.x1, box.y1, box.x2, box.y2, w, h,
118603b705cfSriastradh	     pixmap->drawable.width, pixmap->drawable.height));
118703b705cfSriastradh	if (w <= 0 || h <= 0) {
118803b705cfSriastradh		DBG(("%s: sample extents outside of texture -> clear\n",
118903b705cfSriastradh		     __FUNCTION__));
119003b705cfSriastradh		return 0;
119103b705cfSriastradh	}
119203b705cfSriastradh
119303b705cfSriastradh	if (w > sna->render.max_3d_size || h > sna->render.max_3d_size) {
119403b705cfSriastradh		DBG(("%s: fallback -- sample too large for texture (%d, %d)x(%d, %d)\n",
119503b705cfSriastradh		     __FUNCTION__, box.x1, box.y1, w, h));
119603b705cfSriastradh		return sna_render_picture_downsample(sna, picture, channel,
119703b705cfSriastradh						     x, y, ow, oh,
119803b705cfSriastradh						     dst_x, dst_y);
119903b705cfSriastradh	}
120003b705cfSriastradh
120103b705cfSriastradh	src_bo = use_cpu_bo(sna, pixmap, &box, true);
120242542f5fSchristos	if (src_bo == NULL)
120303b705cfSriastradh		src_bo = move_to_gpu(pixmap, &box, false);
120403b705cfSriastradh	if (src_bo) {
120503b705cfSriastradh		bo = kgem_create_2d(&sna->kgem, w, h,
120603b705cfSriastradh				    pixmap->drawable.bitsPerPixel,
120703b705cfSriastradh				    kgem_choose_tiling(&sna->kgem,
120803b705cfSriastradh						       I915_TILING_X, w, h,
120903b705cfSriastradh						       pixmap->drawable.bitsPerPixel),
121003b705cfSriastradh				    CREATE_TEMPORARY);
121103b705cfSriastradh		if (bo) {
121242542f5fSchristos			DrawableRec tmp;
121303b705cfSriastradh
121442542f5fSchristos			tmp.width  = w;
121542542f5fSchristos			tmp.height = h;
121642542f5fSchristos			tmp.depth  = pixmap->drawable.depth;
121742542f5fSchristos			tmp.bitsPerPixel = pixmap->drawable.bitsPerPixel;
121803b705cfSriastradh
121942542f5fSchristos			assert(tmp.width);
122042542f5fSchristos			assert(tmp.height);
122103b705cfSriastradh
122203b705cfSriastradh			if (!sna->render.copy_boxes(sna, GXcopy,
122342542f5fSchristos						    &pixmap->drawable, src_bo, 0, 0,
122403b705cfSriastradh						    &tmp, bo, -box.x1, -box.y1,
122503b705cfSriastradh						    &box, 1, 0)) {
122603b705cfSriastradh				kgem_bo_destroy(&sna->kgem, bo);
122703b705cfSriastradh				bo = NULL;
122803b705cfSriastradh			}
122903b705cfSriastradh		}
123042542f5fSchristos	} else {
123142542f5fSchristos		struct sna_pixmap *priv = sna_pixmap(pixmap);
123242542f5fSchristos		if (priv) {
123342542f5fSchristos			RegionRec region;
123442542f5fSchristos
123542542f5fSchristos			region.extents = box;
123642542f5fSchristos			region.data = NULL;
123742542f5fSchristos			if (!sna_drawable_move_region_to_cpu(&pixmap->drawable,
123842542f5fSchristos							     &region, MOVE_READ))
123942542f5fSchristos				return 0;
124042542f5fSchristos
124142542f5fSchristos			assert(!priv->mapped);
124242542f5fSchristos			if (pixmap->devPrivate.ptr == NULL)
124342542f5fSchristos				return 0; /* uninitialised */
124442542f5fSchristos		}
124542542f5fSchristos
124642542f5fSchristos		bo = kgem_upload_source_image(&sna->kgem,
124742542f5fSchristos					      pixmap->devPrivate.ptr,
124842542f5fSchristos					      &box,
124942542f5fSchristos					      pixmap->devKind,
125042542f5fSchristos					      pixmap->drawable.bitsPerPixel);
125142542f5fSchristos		if (priv != NULL && bo != NULL &&
125242542f5fSchristos		    box.x2 - box.x1 == pixmap->drawable.width &&
125342542f5fSchristos		    box.y2 - box.y1 == pixmap->drawable.height) {
125442542f5fSchristos			DBG(("%s: adding upload cache to pixmap=%ld\n",
125542542f5fSchristos			     __FUNCTION__, pixmap->drawable.serialNumber));
125642542f5fSchristos			assert(priv->gpu_damage == NULL);
125742542f5fSchristos			assert(priv->gpu_bo == NULL);
125842542f5fSchristos			assert(bo->proxy != NULL);
1259fe8aea9eSmrg			sna_damage_all(&priv->cpu_damage, pixmap);
126042542f5fSchristos			kgem_proxy_bo_attach(bo, &priv->gpu_bo);
126142542f5fSchristos		}
126203b705cfSriastradh	}
126303b705cfSriastradh
126403b705cfSriastradh	if (bo == NULL) {
126503b705cfSriastradh		DBG(("%s: falback -- pixmap is not on the GPU\n",
126603b705cfSriastradh		     __FUNCTION__));
126703b705cfSriastradh		return sna_render_picture_fixup(sna, picture, channel,
126803b705cfSriastradh						x, y, ow, oh, dst_x, dst_y);
126903b705cfSriastradh	}
127003b705cfSriastradh
127103b705cfSriastradh	if (ox == x && oy == y) {
127203b705cfSriastradh		x = y = 0;
127303b705cfSriastradh	} else if (channel->transform) {
127403b705cfSriastradh		pixman_vector_t v;
127503b705cfSriastradh		pixman_transform_t m;
127603b705cfSriastradh
127703b705cfSriastradh		v.vector[0] = (ox - box.x1) << 16;
127803b705cfSriastradh		v.vector[1] = (oy - box.y1) << 16;
127903b705cfSriastradh		v.vector[2] = 1 << 16;
128003b705cfSriastradh		pixman_transform_invert(&m, channel->transform);
128103b705cfSriastradh		pixman_transform_point(&m, &v);
128203b705cfSriastradh		x = v.vector[0] / v.vector[2];
128303b705cfSriastradh		y = v.vector[1] / v.vector[2];
128403b705cfSriastradh	} else {
128503b705cfSriastradh		x = ox - box.x1;
128603b705cfSriastradh		y = oy - box.y1;
128703b705cfSriastradh	}
128803b705cfSriastradh
128903b705cfSriastradh	channel->offset[0] = x - dst_x;
129003b705cfSriastradh	channel->offset[1] = y - dst_y;
129103b705cfSriastradh	channel->scale[0] = 1.f/w;
129203b705cfSriastradh	channel->scale[1] = 1.f/h;
129303b705cfSriastradh	channel->width  = w;
129403b705cfSriastradh	channel->height = h;
129503b705cfSriastradh	channel->bo = bo;
129603b705cfSriastradh	return 1;
129703b705cfSriastradh}
129803b705cfSriastradh
129903b705cfSriastradhstatic int
130003b705cfSriastradhsna_render_picture_convolve(struct sna *sna,
130103b705cfSriastradh			    PicturePtr picture,
130203b705cfSriastradh			    struct sna_composite_channel *channel,
130303b705cfSriastradh			    int16_t x, int16_t y,
130403b705cfSriastradh			    int16_t w, int16_t h,
130503b705cfSriastradh			    int16_t dst_x, int16_t dst_y)
130603b705cfSriastradh{
130703b705cfSriastradh	ScreenPtr screen = picture->pDrawable->pScreen;
130803b705cfSriastradh	PixmapPtr pixmap;
130903b705cfSriastradh	PicturePtr tmp;
131003b705cfSriastradh	pixman_fixed_t *params = picture->filter_params;
131103b705cfSriastradh	int x_off = -pixman_fixed_to_int((params[0] - pixman_fixed_1) >> 1);
131203b705cfSriastradh	int y_off = -pixman_fixed_to_int((params[1] - pixman_fixed_1) >> 1);
131303b705cfSriastradh	int cw = pixman_fixed_to_int(params[0]);
131403b705cfSriastradh	int ch = pixman_fixed_to_int(params[1]);
131503b705cfSriastradh	int i, j, error, depth;
131603b705cfSriastradh	struct kgem_bo *bo;
131703b705cfSriastradh
131803b705cfSriastradh	/* Lame multi-pass accumulation implementation of a general convolution
131903b705cfSriastradh	 * that works everywhere.
132003b705cfSriastradh	 */
132103b705cfSriastradh	DBG(("%s: origin=(%d,%d) kernel=%dx%d, size=%dx%d\n",
132203b705cfSriastradh	     __FUNCTION__, x_off, y_off, cw, ch, w, h));
1323fe8aea9eSmrg	if (cw*ch > 32) /* too much loss of precision from quantization! */
1324fe8aea9eSmrg		return -1;
132503b705cfSriastradh
132603b705cfSriastradh	assert(picture->pDrawable);
132703b705cfSriastradh	assert(picture->filter == PictFilterConvolution);
132803b705cfSriastradh	assert(w <= sna->render.max_3d_size && h <= sna->render.max_3d_size);
132903b705cfSriastradh
133003b705cfSriastradh	if (PICT_FORMAT_RGB(picture->format) == 0) {
133103b705cfSriastradh		channel->pict_format = PIXMAN_a8;
133203b705cfSriastradh		depth = 8;
133303b705cfSriastradh	} else {
133403b705cfSriastradh		channel->pict_format = PIXMAN_a8r8g8b8;
133503b705cfSriastradh		depth = 32;
133603b705cfSriastradh	}
133703b705cfSriastradh
133803b705cfSriastradh	pixmap = screen->CreatePixmap(screen, w, h, depth, SNA_CREATE_SCRATCH);
133942542f5fSchristos	if (pixmap == NullPixmap) {
134042542f5fSchristos		DBG(("%s: pixmap allocation failed\n", __FUNCTION__));
134142542f5fSchristos		return -1;
134242542f5fSchristos	}
134303b705cfSriastradh
134442542f5fSchristos	tmp = NULL;
134542542f5fSchristos	bo = __sna_pixmap_get_bo(pixmap);
134642542f5fSchristos	assert(bo);
134742542f5fSchristos	if (sna->render.clear(sna, pixmap, bo))
134842542f5fSchristos		tmp = CreatePicture(0, &pixmap->drawable,
134942542f5fSchristos				PictureMatchFormat(screen, depth, channel->pict_format),
135042542f5fSchristos				0, NULL, serverClient, &error);
135103b705cfSriastradh	screen->DestroyPixmap(pixmap);
135203b705cfSriastradh	if (tmp == NULL)
135342542f5fSchristos		return -1;
135403b705cfSriastradh
135503b705cfSriastradh	ValidatePicture(tmp);
135603b705cfSriastradh
135703b705cfSriastradh	picture->filter = PictFilterBilinear;
135803b705cfSriastradh	params += 2;
135903b705cfSriastradh	for (j = 0; j < ch; j++) {
136003b705cfSriastradh		for (i = 0; i < cw; i++) {
136103b705cfSriastradh			xRenderColor color;
136203b705cfSriastradh			PicturePtr alpha;
136303b705cfSriastradh
136403b705cfSriastradh			color.alpha = *params++;
136503b705cfSriastradh			color.red = color.green = color.blue = 0;
136603b705cfSriastradh			DBG(("%s: (%d, %d), alpha=%x\n",
136703b705cfSriastradh			     __FUNCTION__, i,j, color.alpha));
136803b705cfSriastradh
136903b705cfSriastradh			if (color.alpha <= 0x00ff)
137003b705cfSriastradh				continue;
137103b705cfSriastradh
137203b705cfSriastradh			alpha = CreateSolidPicture(0, &color, &error);
137303b705cfSriastradh			if (alpha) {
137403b705cfSriastradh				sna_composite(PictOpAdd, picture, alpha, tmp,
1375fe8aea9eSmrg					      x-(x_off+i), y-(y_off+j),
1376fe8aea9eSmrg					      0, 0,
137703b705cfSriastradh					      0, 0,
137803b705cfSriastradh					      w, h);
137903b705cfSriastradh				FreePicture(alpha, 0);
138003b705cfSriastradh			}
138103b705cfSriastradh		}
138203b705cfSriastradh	}
138303b705cfSriastradh	picture->filter = PictFilterConvolution;
138403b705cfSriastradh
138503b705cfSriastradh	channel->height = h;
138603b705cfSriastradh	channel->width  = w;
138703b705cfSriastradh	channel->filter = PictFilterNearest;
138803b705cfSriastradh	channel->repeat = RepeatNone;
138903b705cfSriastradh	channel->is_affine = true;
139003b705cfSriastradh	channel->transform = NULL;
139103b705cfSriastradh	channel->scale[0] = 1.f / w;
139203b705cfSriastradh	channel->scale[1] = 1.f / h;
139303b705cfSriastradh	channel->offset[0] = -dst_x;
139403b705cfSriastradh	channel->offset[1] = -dst_y;
139503b705cfSriastradh	channel->bo = kgem_bo_reference(bo); /* transfer ownership */
139603b705cfSriastradh	FreePicture(tmp, 0);
139703b705cfSriastradh
139803b705cfSriastradh	return 1;
139903b705cfSriastradh}
140003b705cfSriastradh
140142542f5fSchristosstatic bool
140203b705cfSriastradhsna_render_picture_flatten(struct sna *sna,
140303b705cfSriastradh			   PicturePtr picture,
140403b705cfSriastradh			   struct sna_composite_channel *channel,
140503b705cfSriastradh			   int16_t x, int16_t y,
140603b705cfSriastradh			   int16_t w, int16_t h,
140703b705cfSriastradh			   int16_t dst_x, int16_t dst_y)
140803b705cfSriastradh{
140903b705cfSriastradh	ScreenPtr screen = picture->pDrawable->pScreen;
141003b705cfSriastradh	PixmapPtr pixmap;
141103b705cfSriastradh	PicturePtr tmp, alpha;
141203b705cfSriastradh	int old_format, error;
141303b705cfSriastradh
141403b705cfSriastradh	assert(picture->pDrawable);
141503b705cfSriastradh	assert(picture->alphaMap);
141603b705cfSriastradh	assert(w <= sna->render.max_3d_size && h <= sna->render.max_3d_size);
141703b705cfSriastradh
141803b705cfSriastradh	/* XXX shortcut a8? */
141903b705cfSriastradh	DBG(("%s: %dx%d\n", __FUNCTION__, w, h));
142003b705cfSriastradh
142103b705cfSriastradh	pixmap = screen->CreatePixmap(screen, w, h, 32, SNA_CREATE_SCRATCH);
142242542f5fSchristos	if (pixmap == NullPixmap) {
142342542f5fSchristos		DBG(("%s: pixmap allocation failed\n", __FUNCTION__));
142442542f5fSchristos		return false;
142542542f5fSchristos	}
142642542f5fSchristos
142742542f5fSchristos	assert(__sna_pixmap_get_bo(pixmap));
142803b705cfSriastradh
142903b705cfSriastradh	tmp = CreatePicture(0, &pixmap->drawable,
143003b705cfSriastradh			    PictureMatchFormat(screen, 32, PICT_a8r8g8b8),
143103b705cfSriastradh			    0, NULL, serverClient, &error);
143203b705cfSriastradh	screen->DestroyPixmap(pixmap);
143303b705cfSriastradh	if (tmp == NULL)
143442542f5fSchristos		return false;
143503b705cfSriastradh
143603b705cfSriastradh	ValidatePicture(tmp);
143703b705cfSriastradh
143803b705cfSriastradh	old_format = picture->format;
143903b705cfSriastradh	picture->format = PICT_FORMAT(PICT_FORMAT_BPP(picture->format),
144003b705cfSriastradh				      PICT_FORMAT_TYPE(picture->format),
144103b705cfSriastradh				      0,
144203b705cfSriastradh				      PICT_FORMAT_R(picture->format),
144303b705cfSriastradh				      PICT_FORMAT_G(picture->format),
144403b705cfSriastradh				      PICT_FORMAT_B(picture->format));
144503b705cfSriastradh
144603b705cfSriastradh	alpha = picture->alphaMap;
144703b705cfSriastradh	picture->alphaMap = NULL;
144803b705cfSriastradh
144903b705cfSriastradh	sna_composite(PictOpSrc, picture, alpha, tmp,
145003b705cfSriastradh		      x, y,
145103b705cfSriastradh		      x + picture->alphaOrigin.x, y + picture->alphaOrigin.y,
145203b705cfSriastradh		      0, 0,
145303b705cfSriastradh		      w, h);
145403b705cfSriastradh
145503b705cfSriastradh	picture->format = old_format;
145603b705cfSriastradh	picture->alphaMap = alpha;
145703b705cfSriastradh
145803b705cfSriastradh	channel->height = h;
145903b705cfSriastradh	channel->width  = w;
146003b705cfSriastradh	channel->filter = PictFilterNearest;
146103b705cfSriastradh	channel->repeat = RepeatNone;
146203b705cfSriastradh	channel->pict_format = PIXMAN_a8r8g8b8;
146303b705cfSriastradh	channel->is_affine = true;
146403b705cfSriastradh	channel->transform = NULL;
146503b705cfSriastradh	channel->scale[0] = 1.f / w;
146603b705cfSriastradh	channel->scale[1] = 1.f / h;
146703b705cfSriastradh	channel->offset[0] = -dst_x;
146803b705cfSriastradh	channel->offset[1] = -dst_y;
146903b705cfSriastradh	channel->bo = kgem_bo_reference(__sna_pixmap_get_bo(pixmap));
147003b705cfSriastradh	FreePicture(tmp, 0);
147103b705cfSriastradh
147242542f5fSchristos	return true;
147303b705cfSriastradh}
147403b705cfSriastradh
147503b705cfSriastradhint
147603b705cfSriastradhsna_render_picture_approximate_gradient(struct sna *sna,
147703b705cfSriastradh					PicturePtr picture,
147803b705cfSriastradh					struct sna_composite_channel *channel,
147903b705cfSriastradh					int16_t x, int16_t y,
148003b705cfSriastradh					int16_t w, int16_t h,
148103b705cfSriastradh					int16_t dst_x, int16_t dst_y)
148203b705cfSriastradh{
148303b705cfSriastradh	pixman_image_t *dst, *src;
148403b705cfSriastradh	pixman_transform_t t;
148503b705cfSriastradh	int w2 = w/2, h2 = h/2;
148603b705cfSriastradh	int dx, dy;
148703b705cfSriastradh	void *ptr;
148803b705cfSriastradh
148903b705cfSriastradh#if NO_FIXUP
149003b705cfSriastradh	return -1;
149103b705cfSriastradh#endif
149203b705cfSriastradh
149303b705cfSriastradh	DBG(("%s: (%d, %d)x(%d, %d), dst=(%d, %d)\n",
149403b705cfSriastradh	     __FUNCTION__, x, y, w, h, dst_x, dst_y));
149503b705cfSriastradh
149603b705cfSriastradh	if (w2 == 0 || h2 == 0) {
149703b705cfSriastradh		DBG(("%s: fallback - unknown bounds\n", __FUNCTION__));
149803b705cfSriastradh		return -1;
149903b705cfSriastradh	}
150003b705cfSriastradh	if (w2 > sna->render.max_3d_size || h2 > sna->render.max_3d_size) {
150103b705cfSriastradh		DBG(("%s: fallback - too large (%dx%d)\n", __FUNCTION__, w, h));
150203b705cfSriastradh		return -1;
150303b705cfSriastradh	}
150403b705cfSriastradh
150503b705cfSriastradh	channel->is_opaque = sna_gradient_is_opaque((PictGradient*)picture->pSourcePict);
150603b705cfSriastradh	channel->pict_format =
150703b705cfSriastradh		channel->is_opaque ? PIXMAN_x8r8g8b8 : PIXMAN_a8r8g8b8;
150803b705cfSriastradh	DBG(("%s: gradient is opaque? %d, selecting format %08x\n",
150903b705cfSriastradh	     __FUNCTION__, channel->is_opaque, channel->pict_format));
151003b705cfSriastradh	assert(channel->card_format == -1);
151103b705cfSriastradh
151203b705cfSriastradh	channel->bo = kgem_create_buffer_2d(&sna->kgem,
151303b705cfSriastradh					    w2, h2, 32,
151403b705cfSriastradh					    KGEM_BUFFER_WRITE_INPLACE,
151503b705cfSriastradh					    &ptr);
151603b705cfSriastradh	if (!channel->bo) {
151703b705cfSriastradh		DBG(("%s: failed to create upload buffer, using clear\n",
151803b705cfSriastradh		     __FUNCTION__));
151903b705cfSriastradh		return 0;
152003b705cfSriastradh	}
152103b705cfSriastradh
152203b705cfSriastradh	dst = pixman_image_create_bits(channel->pict_format,
152303b705cfSriastradh				       w2, h2, ptr, channel->bo->pitch);
152403b705cfSriastradh	if (!dst) {
152503b705cfSriastradh		kgem_bo_destroy(&sna->kgem, channel->bo);
152603b705cfSriastradh		channel->bo = NULL;
152703b705cfSriastradh		return 0;
152803b705cfSriastradh	}
152903b705cfSriastradh
153003b705cfSriastradh	src = image_from_pict(picture, false, &dx, &dy);
153103b705cfSriastradh	if (src == NULL) {
153203b705cfSriastradh		pixman_image_unref(dst);
153303b705cfSriastradh		kgem_bo_destroy(&sna->kgem, channel->bo);
153403b705cfSriastradh		channel->bo = NULL;
153503b705cfSriastradh		return 0;
153603b705cfSriastradh	}
153703b705cfSriastradh	DBG(("%s: source offset (%d, %d)\n", __FUNCTION__, dx, dy));
153803b705cfSriastradh
153903b705cfSriastradh	memset(&t, 0, sizeof(t));
154003b705cfSriastradh	t.matrix[0][0] = (w << 16) / w2;
154103b705cfSriastradh	t.matrix[0][2] = (x + dx) << 16;
154203b705cfSriastradh	t.matrix[1][1] = (h << 16) / h2;
154303b705cfSriastradh	t.matrix[1][2] = (y + dy) << 16;
154403b705cfSriastradh	t.matrix[2][2] = 1 << 16;
154503b705cfSriastradh	if (picture->transform)
154603b705cfSriastradh		pixman_transform_multiply(&t, picture->transform, &t);
154703b705cfSriastradh	DBG(("%s: applying transform [(%f, %f, %f), (%f, %f, %f), (%f, %f, %f)]\n",
154803b705cfSriastradh	     __FUNCTION__,
154903b705cfSriastradh	     pixman_fixed_to_double(t.matrix[0][0]),
155003b705cfSriastradh	     pixman_fixed_to_double(t.matrix[0][1]),
155103b705cfSriastradh	     pixman_fixed_to_double(t.matrix[0][2]),
155203b705cfSriastradh	     pixman_fixed_to_double(t.matrix[1][0]),
155303b705cfSriastradh	     pixman_fixed_to_double(t.matrix[1][1]),
155403b705cfSriastradh	     pixman_fixed_to_double(t.matrix[1][2]),
155503b705cfSriastradh	     pixman_fixed_to_double(t.matrix[2][0]),
155603b705cfSriastradh	     pixman_fixed_to_double(t.matrix[2][1]),
155703b705cfSriastradh	     pixman_fixed_to_double(t.matrix[2][2])));
155803b705cfSriastradh	pixman_image_set_transform(src, &t);
155903b705cfSriastradh
156003b705cfSriastradh	sna_image_composite(PictOpSrc, src, NULL, dst,
156103b705cfSriastradh			    0, 0,
156203b705cfSriastradh			    0, 0,
156303b705cfSriastradh			    0, 0,
156403b705cfSriastradh			    w2, h2);
156503b705cfSriastradh	free_pixman_pict(picture, src);
156603b705cfSriastradh	pixman_image_unref(dst);
156703b705cfSriastradh
156803b705cfSriastradh	channel->width  = w2;
156903b705cfSriastradh	channel->height = h2;
157003b705cfSriastradh
157103b705cfSriastradh	channel->filter = PictFilterNearest;
157203b705cfSriastradh	channel->repeat = RepeatNone;
157303b705cfSriastradh	channel->is_affine = true;
157403b705cfSriastradh
157503b705cfSriastradh	channel->scale[0] = 1.f/w;
157603b705cfSriastradh	channel->scale[1] = 1.f/h;
157703b705cfSriastradh	channel->offset[0] = -dst_x;
157803b705cfSriastradh	channel->offset[1] = -dst_y;
157903b705cfSriastradh	channel->transform = NULL;
158003b705cfSriastradh
158103b705cfSriastradh	return 1;
158203b705cfSriastradh}
158303b705cfSriastradh
158403b705cfSriastradhint
158503b705cfSriastradhsna_render_picture_fixup(struct sna *sna,
158603b705cfSriastradh			 PicturePtr picture,
158703b705cfSriastradh			 struct sna_composite_channel *channel,
158803b705cfSriastradh			 int16_t x, int16_t y,
158903b705cfSriastradh			 int16_t w, int16_t h,
159003b705cfSriastradh			 int16_t dst_x, int16_t dst_y)
159103b705cfSriastradh{
159203b705cfSriastradh	pixman_image_t *dst, *src;
159303b705cfSriastradh	int dx, dy;
159403b705cfSriastradh	void *ptr;
159503b705cfSriastradh
159603b705cfSriastradh#if NO_FIXUP
159703b705cfSriastradh	return -1;
159803b705cfSriastradh#endif
159903b705cfSriastradh
160003b705cfSriastradh	DBG(("%s: (%d, %d)x(%d, %d)\n", __FUNCTION__, x, y, w, h));
160103b705cfSriastradh
160203b705cfSriastradh	if (w == 0 || h == 0) {
160303b705cfSriastradh		DBG(("%s: fallback - unknown bounds\n", __FUNCTION__));
160403b705cfSriastradh		return -1;
160503b705cfSriastradh	}
160603b705cfSriastradh	if (w > sna->render.max_3d_size || h > sna->render.max_3d_size) {
160703b705cfSriastradh		DBG(("%s: fallback - too large (%dx%d)\n", __FUNCTION__, w, h));
160803b705cfSriastradh		return -1;
160903b705cfSriastradh	}
161003b705cfSriastradh
161103b705cfSriastradh	if (picture->alphaMap) {
161203b705cfSriastradh		DBG(("%s: alphamap\n", __FUNCTION__));
161303b705cfSriastradh		if (is_gpu(sna, picture->pDrawable, PREFER_GPU_RENDER) ||
161403b705cfSriastradh		    is_gpu(sna, picture->alphaMap->pDrawable, PREFER_GPU_RENDER)) {
161542542f5fSchristos			if (sna_render_picture_flatten(sna, picture, channel,
161642542f5fSchristos							  x, y, w, h, dst_x, dst_y))
161742542f5fSchristos				return 1;
161803b705cfSriastradh		}
161903b705cfSriastradh
162003b705cfSriastradh		goto do_fixup;
162103b705cfSriastradh	}
162203b705cfSriastradh
162303b705cfSriastradh	if (picture->filter == PictFilterConvolution) {
162403b705cfSriastradh		DBG(("%s: convolution\n", __FUNCTION__));
162503b705cfSriastradh		if (is_gpu(sna, picture->pDrawable, PREFER_GPU_RENDER)) {
162603b705cfSriastradh			return sna_render_picture_convolve(sna, picture, channel,
162703b705cfSriastradh							   x, y, w, h, dst_x, dst_y);
162803b705cfSriastradh		}
162903b705cfSriastradh
163003b705cfSriastradh		goto do_fixup;
163103b705cfSriastradh	}
163203b705cfSriastradh
163303b705cfSriastradhdo_fixup:
163403b705cfSriastradh	if (PICT_FORMAT_RGB(picture->format) == 0)
163503b705cfSriastradh		channel->pict_format = PIXMAN_a8;
163603b705cfSriastradh	else
163703b705cfSriastradh		channel->pict_format = PIXMAN_a8r8g8b8;
163803b705cfSriastradh
163903b705cfSriastradh	if (picture->pDrawable &&
164003b705cfSriastradh	    !sna_drawable_move_to_cpu(picture->pDrawable, MOVE_READ))
164103b705cfSriastradh		return 0;
164203b705cfSriastradh
164303b705cfSriastradh	channel->bo = kgem_create_buffer_2d(&sna->kgem,
164403b705cfSriastradh					    w, h, PIXMAN_FORMAT_BPP(channel->pict_format),
164503b705cfSriastradh					    KGEM_BUFFER_WRITE_INPLACE,
164603b705cfSriastradh					    &ptr);
164703b705cfSriastradh	if (!channel->bo) {
164803b705cfSriastradh		DBG(("%s: failed to create upload buffer, using clear\n",
164903b705cfSriastradh		     __FUNCTION__));
165003b705cfSriastradh		return 0;
165103b705cfSriastradh	}
165203b705cfSriastradh
165303b705cfSriastradh	/* Composite in the original format to preserve idiosyncracies */
165403b705cfSriastradh	if (!kgem_buffer_is_inplace(channel->bo) &&
165503b705cfSriastradh	    (picture->pDrawable == NULL ||
165603b705cfSriastradh	     alphaless(picture->format) == alphaless(channel->pict_format)))
165703b705cfSriastradh		dst = pixman_image_create_bits(channel->pict_format,
165803b705cfSriastradh					       w, h, ptr, channel->bo->pitch);
165903b705cfSriastradh	else
166042542f5fSchristos		dst = pixman_image_create_bits((pixman_format_code_t)picture->format,
166142542f5fSchristos					       w, h, NULL, 0);
166203b705cfSriastradh	if (!dst) {
166303b705cfSriastradh		kgem_bo_destroy(&sna->kgem, channel->bo);
166403b705cfSriastradh		return 0;
166503b705cfSriastradh	}
166603b705cfSriastradh
166703b705cfSriastradh	src = image_from_pict(picture, false, &dx, &dy);
166803b705cfSriastradh	if (src == NULL) {
166903b705cfSriastradh		pixman_image_unref(dst);
167003b705cfSriastradh		kgem_bo_destroy(&sna->kgem, channel->bo);
167103b705cfSriastradh		return 0;
167203b705cfSriastradh	}
167303b705cfSriastradh
167403b705cfSriastradh	DBG(("%s: compositing tmp=(%d+%d, %d+%d)x(%d, %d)\n",
167503b705cfSriastradh	     __FUNCTION__, x, dx, y, dy, w, h));
167603b705cfSriastradh	sna_image_composite(PictOpSrc, src, NULL, dst,
167703b705cfSriastradh			    x + dx, y + dy,
167803b705cfSriastradh			    0, 0,
167903b705cfSriastradh			    0, 0,
168003b705cfSriastradh			    w, h);
168103b705cfSriastradh	free_pixman_pict(picture, src);
168203b705cfSriastradh
168303b705cfSriastradh	/* Then convert to card format */
168403b705cfSriastradh	if (pixman_image_get_data(dst) != ptr) {
168503b705cfSriastradh		DBG(("%s: performing post-conversion %08x->%08x (%d, %d)\n",
168603b705cfSriastradh		     __FUNCTION__,
168703b705cfSriastradh		     picture->format, channel->pict_format,
168803b705cfSriastradh		     w, h));
168903b705cfSriastradh
169003b705cfSriastradh		src = dst;
169103b705cfSriastradh		dst = pixman_image_create_bits(channel->pict_format,
169203b705cfSriastradh					       w, h, ptr, channel->bo->pitch);
169303b705cfSriastradh		if (dst) {
169442542f5fSchristos			sna_image_composite(PictOpSrc, src, NULL, dst,
169542542f5fSchristos					    0, 0,
169642542f5fSchristos					    0, 0,
169742542f5fSchristos					    0, 0,
169842542f5fSchristos					    w, h);
169903b705cfSriastradh			pixman_image_unref(src);
170003b705cfSriastradh		} else {
170103b705cfSriastradh			memset(ptr, 0, __kgem_buffer_size(channel->bo));
170203b705cfSriastradh			dst = src;
170303b705cfSriastradh		}
170403b705cfSriastradh	}
170503b705cfSriastradh	pixman_image_unref(dst);
170603b705cfSriastradh
170703b705cfSriastradh	channel->width  = w;
170803b705cfSriastradh	channel->height = h;
170903b705cfSriastradh
171003b705cfSriastradh	channel->filter = PictFilterNearest;
171103b705cfSriastradh	channel->repeat = RepeatNone;
171203b705cfSriastradh	channel->is_affine = true;
171303b705cfSriastradh
171403b705cfSriastradh	channel->scale[0] = 1.f/w;
171503b705cfSriastradh	channel->scale[1] = 1.f/h;
171603b705cfSriastradh	channel->offset[0] = -dst_x;
171703b705cfSriastradh	channel->offset[1] = -dst_y;
171803b705cfSriastradh	channel->transform = NULL;
171903b705cfSriastradh
172003b705cfSriastradh	return 1;
172103b705cfSriastradh}
172203b705cfSriastradh
172303b705cfSriastradhint
172403b705cfSriastradhsna_render_picture_convert(struct sna *sna,
172503b705cfSriastradh			   PicturePtr picture,
172603b705cfSriastradh			   struct sna_composite_channel *channel,
172703b705cfSriastradh			   PixmapPtr pixmap,
172803b705cfSriastradh			   int16_t x, int16_t y,
172903b705cfSriastradh			   int16_t w, int16_t h,
173003b705cfSriastradh			   int16_t dst_x, int16_t dst_y,
173103b705cfSriastradh			   bool fixup_alpha)
173203b705cfSriastradh{
173303b705cfSriastradh	BoxRec box;
173403b705cfSriastradh
173503b705cfSriastradh#if NO_CONVERT
173603b705cfSriastradh	return -1;
173703b705cfSriastradh#endif
173803b705cfSriastradh
173903b705cfSriastradh	if (w != 0 && h != 0) {
174003b705cfSriastradh		box.x1 = x;
174103b705cfSriastradh		box.y1 = y;
174203b705cfSriastradh		box.x2 = bound(x, w);
174303b705cfSriastradh		box.y2 = bound(y, h);
174403b705cfSriastradh
174503b705cfSriastradh		if (channel->transform) {
174603b705cfSriastradh			DBG(("%s: has transform, converting whole surface\n",
174703b705cfSriastradh			     __FUNCTION__));
174803b705cfSriastradh			box.x1 = box.y1 = 0;
174903b705cfSriastradh			box.x2 = pixmap->drawable.width;
175003b705cfSriastradh			box.y2 = pixmap->drawable.height;
175103b705cfSriastradh		}
175203b705cfSriastradh
175303b705cfSriastradh		if (box.x1 < 0)
175403b705cfSriastradh			box.x1 = 0;
175503b705cfSriastradh		if (box.y1 < 0)
175603b705cfSriastradh			box.y1 = 0;
175703b705cfSriastradh		if (box.x2 > pixmap->drawable.width)
175803b705cfSriastradh			box.x2 = pixmap->drawable.width;
175903b705cfSriastradh		if (box.y2 > pixmap->drawable.height)
176003b705cfSriastradh			box.y2 = pixmap->drawable.height;
176103b705cfSriastradh	} else {
176203b705cfSriastradh		DBG(("%s: op no bounds, converting whole surface\n",
176303b705cfSriastradh		     __FUNCTION__));
176403b705cfSriastradh		box.x1 = box.y1 = 0;
176503b705cfSriastradh		box.x2 = pixmap->drawable.width;
176603b705cfSriastradh		box.y2 = pixmap->drawable.height;
176703b705cfSriastradh	}
176803b705cfSriastradh
176903b705cfSriastradh	w = box.x2 - box.x1;
177003b705cfSriastradh	h = box.y2 - box.y1;
177103b705cfSriastradh
177203b705cfSriastradh	DBG(("%s: convert (%d, %d)x(%d, %d), source size %dx%d\n",
177303b705cfSriastradh	     __FUNCTION__, box.x1, box.y1, w, h,
177403b705cfSriastradh	     pixmap->drawable.width,
177503b705cfSriastradh	     pixmap->drawable.height));
177603b705cfSriastradh
177703b705cfSriastradh	if (w <= 0 || h <= 0) {
177803b705cfSriastradh		DBG(("%s: sample extents lie outside of source, using clear\n",
177903b705cfSriastradh		     __FUNCTION__));
178003b705cfSriastradh		return 0;
178103b705cfSriastradh	}
178203b705cfSriastradh
178303b705cfSriastradh	if (fixup_alpha && is_gpu(sna, &pixmap->drawable, PREFER_GPU_RENDER)) {
178403b705cfSriastradh		ScreenPtr screen = pixmap->drawable.pScreen;
178503b705cfSriastradh		PixmapPtr tmp;
178603b705cfSriastradh		PicturePtr src, dst;
178703b705cfSriastradh		int error;
178803b705cfSriastradh
178903b705cfSriastradh		assert(PICT_FORMAT_BPP(picture->format) == pixmap->drawable.bitsPerPixel);
179003b705cfSriastradh		channel->pict_format = PICT_FORMAT(PICT_FORMAT_BPP(picture->format),
179103b705cfSriastradh						   PICT_FORMAT_TYPE(picture->format),
179203b705cfSriastradh						   PICT_FORMAT_BPP(picture->format) - PIXMAN_FORMAT_DEPTH(picture->format),
179303b705cfSriastradh						   PICT_FORMAT_R(picture->format),
179403b705cfSriastradh						   PICT_FORMAT_G(picture->format),
179503b705cfSriastradh						   PICT_FORMAT_B(picture->format));
179603b705cfSriastradh
179703b705cfSriastradh		DBG(("%s: converting to %08x from %08x using composite alpha-fixup\n",
179803b705cfSriastradh		     __FUNCTION__,
179903b705cfSriastradh		     (unsigned)channel->pict_format,
180003b705cfSriastradh		     (unsigned)picture->format));
180103b705cfSriastradh
180242542f5fSchristos		tmp = screen->CreatePixmap(screen, w, h, pixmap->drawable.bitsPerPixel, SNA_CREATE_SCRATCH);
180303b705cfSriastradh		if (tmp == NULL)
180442542f5fSchristos			return -1;
180542542f5fSchristos
180642542f5fSchristos		assert(__sna_pixmap_get_bo(tmp));
180703b705cfSriastradh
180803b705cfSriastradh		dst = CreatePicture(0, &tmp->drawable,
180903b705cfSriastradh				    PictureMatchFormat(screen,
181003b705cfSriastradh						       pixmap->drawable.bitsPerPixel,
181103b705cfSriastradh						       channel->pict_format),
181203b705cfSriastradh				    0, NULL, serverClient, &error);
181303b705cfSriastradh		if (dst == NULL) {
181403b705cfSriastradh			screen->DestroyPixmap(tmp);
181503b705cfSriastradh			return 0;
181603b705cfSriastradh		}
181703b705cfSriastradh
181803b705cfSriastradh		src = CreatePicture(0, &pixmap->drawable,
181903b705cfSriastradh				    PictureMatchFormat(screen,
182003b705cfSriastradh						       pixmap->drawable.depth,
182103b705cfSriastradh						       picture->format),
182203b705cfSriastradh				    0, NULL, serverClient, &error);
182303b705cfSriastradh		if (src == NULL) {
182403b705cfSriastradh			FreePicture(dst, 0);
182503b705cfSriastradh			screen->DestroyPixmap(tmp);
182603b705cfSriastradh			return 0;
182703b705cfSriastradh		}
182803b705cfSriastradh
182903b705cfSriastradh		ValidatePicture(src);
183003b705cfSriastradh		ValidatePicture(dst);
183103b705cfSriastradh
183203b705cfSriastradh		sna_composite(PictOpSrc, src, NULL, dst,
183303b705cfSriastradh			      box.x1, box.y1,
183403b705cfSriastradh			      0, 0,
183503b705cfSriastradh			      0, 0,
183603b705cfSriastradh			      w, h);
183703b705cfSriastradh		FreePicture(dst, 0);
183803b705cfSriastradh		FreePicture(src, 0);
183903b705cfSriastradh
184003b705cfSriastradh		channel->bo = __sna_pixmap_get_bo(tmp);
184103b705cfSriastradh		kgem_bo_reference(channel->bo);
184203b705cfSriastradh		screen->DestroyPixmap(tmp);
184303b705cfSriastradh	} else {
184403b705cfSriastradh		pixman_image_t *src, *dst;
184503b705cfSriastradh		void *ptr;
184603b705cfSriastradh
184703b705cfSriastradh		if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ))
184803b705cfSriastradh			return 0;
184903b705cfSriastradh
185042542f5fSchristos		src = pixman_image_create_bits((pixman_format_code_t)picture->format,
185103b705cfSriastradh					       pixmap->drawable.width,
185203b705cfSriastradh					       pixmap->drawable.height,
185303b705cfSriastradh					       pixmap->devPrivate.ptr,
185403b705cfSriastradh					       pixmap->devKind);
185503b705cfSriastradh		if (!src)
185603b705cfSriastradh			return 0;
185703b705cfSriastradh
185803b705cfSriastradh		if (PICT_FORMAT_RGB(picture->format) == 0) {
185903b705cfSriastradh			channel->pict_format = PIXMAN_a8;
186003b705cfSriastradh			DBG(("%s: converting to a8 from %08x\n",
186103b705cfSriastradh			     __FUNCTION__, picture->format));
186203b705cfSriastradh		} else {
186303b705cfSriastradh			channel->pict_format = PIXMAN_a8r8g8b8;
186403b705cfSriastradh			DBG(("%s: converting to a8r8g8b8 from %08x\n",
186503b705cfSriastradh			     __FUNCTION__, picture->format));
186603b705cfSriastradh		}
186703b705cfSriastradh
186803b705cfSriastradh		channel->bo = kgem_create_buffer_2d(&sna->kgem,
186903b705cfSriastradh						    w, h, PIXMAN_FORMAT_BPP(channel->pict_format),
187003b705cfSriastradh						    KGEM_BUFFER_WRITE_INPLACE,
187103b705cfSriastradh						    &ptr);
187203b705cfSriastradh		if (!channel->bo) {
187303b705cfSriastradh			pixman_image_unref(src);
187403b705cfSriastradh			return 0;
187503b705cfSriastradh		}
187603b705cfSriastradh
187703b705cfSriastradh		dst = pixman_image_create_bits(channel->pict_format,
187803b705cfSriastradh					       w, h, ptr, channel->bo->pitch);
187903b705cfSriastradh		if (!dst) {
188003b705cfSriastradh			kgem_bo_destroy(&sna->kgem, channel->bo);
188103b705cfSriastradh			pixman_image_unref(src);
188203b705cfSriastradh			return 0;
188303b705cfSriastradh		}
188403b705cfSriastradh
188542542f5fSchristos		if (sigtrap_get() == 0) {
188642542f5fSchristos			sna_image_composite(PictOpSrc, src, NULL, dst,
188742542f5fSchristos					    box.x1, box.y1,
188842542f5fSchristos					    0, 0,
188942542f5fSchristos					    0, 0,
189042542f5fSchristos					    w, h);
189142542f5fSchristos			sigtrap_put();
189242542f5fSchristos		}
189303b705cfSriastradh		pixman_image_unref(dst);
189403b705cfSriastradh		pixman_image_unref(src);
189503b705cfSriastradh	}
189603b705cfSriastradh
189703b705cfSriastradh	channel->width  = w;
189803b705cfSriastradh	channel->height = h;
189903b705cfSriastradh
190003b705cfSriastradh	channel->scale[0] = 1.f/w;
190103b705cfSriastradh	channel->scale[1] = 1.f/h;
190203b705cfSriastradh	channel->offset[0] = x - dst_x - box.x1;
190303b705cfSriastradh	channel->offset[1] = y - dst_y - box.y1;
190403b705cfSriastradh
190503b705cfSriastradh	DBG(("%s: offset=(%d, %d), size=(%d, %d)\n",
190603b705cfSriastradh	     __FUNCTION__,
190703b705cfSriastradh	     channel->offset[0], channel->offset[1],
190803b705cfSriastradh	     channel->width, channel->height));
190903b705cfSriastradh	return 1;
191003b705cfSriastradh}
191103b705cfSriastradh
191203b705cfSriastradhbool
191303b705cfSriastradhsna_render_composite_redirect(struct sna *sna,
191403b705cfSriastradh			      struct sna_composite_op *op,
191503b705cfSriastradh			      int x, int y, int width, int height,
191603b705cfSriastradh			      bool partial)
191703b705cfSriastradh{
191803b705cfSriastradh	struct sna_composite_redirect *t = &op->redirect;
191903b705cfSriastradh	int bpp = op->dst.pixmap->drawable.bitsPerPixel;
192003b705cfSriastradh	struct kgem_bo *bo;
192103b705cfSriastradh
192203b705cfSriastradh	assert(t->real_bo == NULL);
192303b705cfSriastradh
192403b705cfSriastradh#if NO_REDIRECT
192503b705cfSriastradh	return false;
192603b705cfSriastradh#endif
192703b705cfSriastradh
192803b705cfSriastradh	DBG(("%s: target too large (%dx%d), copying to temporary %dx%d, max %d / %d\n",
192903b705cfSriastradh	     __FUNCTION__,
193003b705cfSriastradh	     op->dst.width, op->dst.height,
193103b705cfSriastradh	     width, height,
193203b705cfSriastradh	     sna->render.max_3d_size,
193303b705cfSriastradh	     sna->render.max_3d_pitch));
193403b705cfSriastradh
193503b705cfSriastradh	if (!width || !height)
193603b705cfSriastradh		return false;
193703b705cfSriastradh
193803b705cfSriastradh	if (width  > sna->render.max_3d_size ||
193903b705cfSriastradh	    height > sna->render.max_3d_size)
194003b705cfSriastradh		return false;
194103b705cfSriastradh
194203b705cfSriastradh	if (op->dst.bo->pitch <= sna->render.max_3d_pitch) {
194303b705cfSriastradh		BoxRec box;
194403b705cfSriastradh		int w, h, offset;
194503b705cfSriastradh
194603b705cfSriastradh		DBG(("%s: dst pitch (%d) fits within render pipeline (%d)\n",
194703b705cfSriastradh		     __FUNCTION__, op->dst.bo->pitch, sna->render.max_3d_pitch));
194803b705cfSriastradh
194903b705cfSriastradh		box.x1 = x + op->dst.x;
195003b705cfSriastradh		box.x2 = bound(box.x1, width);
195103b705cfSriastradh		box.y1 = y + op->dst.y;
195203b705cfSriastradh		box.y2 = bound(box.y1, height);
195303b705cfSriastradh
195403b705cfSriastradh		if (box.x1 < 0)
195503b705cfSriastradh			box.x1 = 0;
195603b705cfSriastradh		if (box.y1 < 0)
195703b705cfSriastradh			box.y1 = 0;
195803b705cfSriastradh
195903b705cfSriastradh		/* Ensure we align to an even tile row */
196003b705cfSriastradh		if (op->dst.bo->tiling) {
196103b705cfSriastradh			int tile_width, tile_height, tile_size;
196203b705cfSriastradh
196342542f5fSchristos			kgem_get_tile_size(&sna->kgem, op->dst.bo->tiling, op->dst.bo->pitch,
196403b705cfSriastradh					   &tile_width, &tile_height, &tile_size);
196503b705cfSriastradh
196603b705cfSriastradh			box.y1 = box.y1 & ~(2*tile_height - 1);
196703b705cfSriastradh			box.y2 = ALIGN(box.y2, 2*tile_height);
196803b705cfSriastradh
196903b705cfSriastradh			box.x1 = box.x1 & ~(tile_width * 8 / op->dst.pixmap->drawable.bitsPerPixel - 1);
197003b705cfSriastradh			box.x2 = ALIGN(box.x2, tile_width * 8 / op->dst.pixmap->drawable.bitsPerPixel);
197103b705cfSriastradh
197213496ba1Ssnj			if (box.x1 > sna->render.max_3d_size &&
197313496ba1Ssnj			    box.x2 <= 2*sna->render.max_3d_size)
197413496ba1Ssnj				box.x1 = sna->render.max_3d_size;
197513496ba1Ssnj
197613496ba1Ssnj			if (box.y1 > sna->render.max_3d_size &&
197713496ba1Ssnj			    box.y2 <= 2*sna->render.max_3d_size)
197813496ba1Ssnj				box.y1 = sna->render.max_3d_size;
197913496ba1Ssnj
198003b705cfSriastradh			offset = box.x1 * op->dst.pixmap->drawable.bitsPerPixel / 8 / tile_width * tile_size;
198103b705cfSriastradh		} else {
198203b705cfSriastradh			if (sna->kgem.gen < 040) {
198303b705cfSriastradh				box.y1 = box.y1 & ~3;
198403b705cfSriastradh				box.y2 = ALIGN(box.y2, 4);
198503b705cfSriastradh
198603b705cfSriastradh				box.x1 = box.x1 & ~3;
198703b705cfSriastradh				box.x2 = ALIGN(box.x2, 4);
198803b705cfSriastradh			} else {
198903b705cfSriastradh				box.y1 = box.y1 & ~1;
199003b705cfSriastradh				box.y2 = ALIGN(box.y2, 2);
199103b705cfSriastradh
199203b705cfSriastradh				box.x1 = box.x1 & ~1;
199303b705cfSriastradh				box.x2 = ALIGN(box.x2, 2);
199403b705cfSriastradh			}
199503b705cfSriastradh
199613496ba1Ssnj			if (box.x1 > sna->render.max_3d_size &&
199713496ba1Ssnj			    box.x2 <= 2*sna->render.max_3d_size)
199813496ba1Ssnj				box.x1 = sna->render.max_3d_size;
199913496ba1Ssnj
200013496ba1Ssnj			if (box.y1 > sna->render.max_3d_size &&
200113496ba1Ssnj			    box.y2 <= 2*sna->render.max_3d_size)
200213496ba1Ssnj				box.y1 = sna->render.max_3d_size;
200313496ba1Ssnj
200403b705cfSriastradh			offset = box.x1 * op->dst.pixmap->drawable.bitsPerPixel / 8;
200503b705cfSriastradh		}
200603b705cfSriastradh
200703b705cfSriastradh		if (box.y2 > op->dst.pixmap->drawable.height)
200803b705cfSriastradh			box.y2 = op->dst.pixmap->drawable.height;
200903b705cfSriastradh
201003b705cfSriastradh		if (box.x2 > op->dst.pixmap->drawable.width)
201103b705cfSriastradh			box.x2 = op->dst.pixmap->drawable.width;
201203b705cfSriastradh
201303b705cfSriastradh		w = box.x2 - box.x1;
201403b705cfSriastradh		h = box.y2 - box.y1;
201503b705cfSriastradh		DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d), max %d\n", __FUNCTION__,
201603b705cfSriastradh		     box.x1, box.y1, box.x2, box.y2, w, h,
201703b705cfSriastradh		     op->dst.pixmap->drawable.width,
201803b705cfSriastradh		     op->dst.pixmap->drawable.height,
201903b705cfSriastradh		     sna->render.max_3d_size));
202003b705cfSriastradh		if (w <= sna->render.max_3d_size &&
202103b705cfSriastradh		    h <= sna->render.max_3d_size) {
202203b705cfSriastradh			t->box.x2 = t->box.x1 = op->dst.x;
202303b705cfSriastradh			t->box.y2 = t->box.y1 = op->dst.y;
202403b705cfSriastradh			t->real_bo = op->dst.bo;
202503b705cfSriastradh			t->real_damage = op->damage;
202603b705cfSriastradh			if (op->damage) {
202703b705cfSriastradh				assert(!DAMAGE_IS_ALL(op->damage));
202803b705cfSriastradh				t->damage = sna_damage_create();
202903b705cfSriastradh				op->damage = &t->damage;
203003b705cfSriastradh			}
203103b705cfSriastradh
203203b705cfSriastradh			/* How many tiles across are we? */
203303b705cfSriastradh			op->dst.bo = kgem_create_proxy(&sna->kgem, op->dst.bo,
203403b705cfSriastradh						       box.y1 * op->dst.bo->pitch + offset,
203503b705cfSriastradh						       h * op->dst.bo->pitch);
203603b705cfSriastradh			if (!op->dst.bo) {
203703b705cfSriastradh				t->real_bo = NULL;
203803b705cfSriastradh				if (t->damage)
203903b705cfSriastradh					__sna_damage_destroy(t->damage);
204003b705cfSriastradh				return false;
204103b705cfSriastradh			}
204203b705cfSriastradh
204303b705cfSriastradh			assert(op->dst.bo != t->real_bo);
204403b705cfSriastradh			op->dst.bo->pitch = t->real_bo->pitch;
204503b705cfSriastradh
204603b705cfSriastradh			op->dst.x -= box.x1;
204703b705cfSriastradh			op->dst.y -= box.y1;
204803b705cfSriastradh			op->dst.width  = w;
204903b705cfSriastradh			op->dst.height = h;
205003b705cfSriastradh			return true;
205103b705cfSriastradh		}
205203b705cfSriastradh	}
205303b705cfSriastradh
205403b705cfSriastradh	/* We can process the operation in a single pass,
205503b705cfSriastradh	 * but the target is too large for the 3D pipeline.
205603b705cfSriastradh	 * Copy into a smaller surface and replace afterwards.
205703b705cfSriastradh	 */
205803b705cfSriastradh	bo = kgem_create_2d(&sna->kgem,
205903b705cfSriastradh			    width, height, bpp,
206003b705cfSriastradh			    kgem_choose_tiling(&sna->kgem, I915_TILING_X,
206103b705cfSriastradh					       width, height, bpp),
206203b705cfSriastradh			    CREATE_TEMPORARY);
206303b705cfSriastradh	if (!bo)
206403b705cfSriastradh		return false;
206503b705cfSriastradh
206603b705cfSriastradh	t->box.x1 = x + op->dst.x;
206703b705cfSriastradh	t->box.y1 = y + op->dst.y;
206803b705cfSriastradh	t->box.x2 = bound(t->box.x1, width);
206903b705cfSriastradh	t->box.y2 = bound(t->box.y1, height);
207003b705cfSriastradh
207103b705cfSriastradh	DBG(("%s: original box (%d, %d), (%d, %d)\n",
207203b705cfSriastradh	     __FUNCTION__, t->box.x1, t->box.y1, t->box.x2, t->box.y2));
207303b705cfSriastradh
207403b705cfSriastradh	if (partial &&
207503b705cfSriastradh	    !sna_blt_copy_boxes(sna, GXcopy,
207603b705cfSriastradh				op->dst.bo, 0, 0,
207703b705cfSriastradh				bo, -t->box.x1, -t->box.y1,
207803b705cfSriastradh				bpp, &t->box, 1)) {
207903b705cfSriastradh		kgem_bo_destroy(&sna->kgem, bo);
208003b705cfSriastradh		return false;
208103b705cfSriastradh	}
208203b705cfSriastradh
208303b705cfSriastradh	t->real_bo = op->dst.bo;
208403b705cfSriastradh	t->real_damage = op->damage;
208503b705cfSriastradh	if (op->damage) {
208603b705cfSriastradh		assert(!DAMAGE_IS_ALL(op->damage));
208703b705cfSriastradh		t->damage = sna_damage_create();
208803b705cfSriastradh		op->damage = &t->damage;
208903b705cfSriastradh	}
209003b705cfSriastradh
209103b705cfSriastradh	op->dst.bo = bo;
209203b705cfSriastradh	op->dst.x = -x;
209303b705cfSriastradh	op->dst.y = -y;
209403b705cfSriastradh	op->dst.width  = width;
209503b705cfSriastradh	op->dst.height = height;
209603b705cfSriastradh	return true;
209703b705cfSriastradh}
209803b705cfSriastradh
209903b705cfSriastradhvoid
210003b705cfSriastradhsna_render_composite_redirect_done(struct sna *sna,
210103b705cfSriastradh				   const struct sna_composite_op *op)
210203b705cfSriastradh{
210303b705cfSriastradh	const struct sna_composite_redirect *t = &op->redirect;
210403b705cfSriastradh
210503b705cfSriastradh	if (t->real_bo) {
210603b705cfSriastradh		assert(op->dst.bo != t->real_bo);
210703b705cfSriastradh
210803b705cfSriastradh		if (t->box.x2 > t->box.x1) {
210903b705cfSriastradh			bool ok;
211003b705cfSriastradh
211103b705cfSriastradh			DBG(("%s: copying temporary to dst\n", __FUNCTION__));
211203b705cfSriastradh			ok = sna_blt_copy_boxes(sna, GXcopy,
211303b705cfSriastradh						op->dst.bo, -t->box.x1, -t->box.y1,
211403b705cfSriastradh						t->real_bo, 0, 0,
211503b705cfSriastradh						op->dst.pixmap->drawable.bitsPerPixel,
211603b705cfSriastradh						&t->box, 1);
211703b705cfSriastradh			assert(ok);
211803b705cfSriastradh			(void)ok;
211903b705cfSriastradh		}
212003b705cfSriastradh		if (t->damage) {
212103b705cfSriastradh			DBG(("%s: combining damage (all? %d), offset=(%d, %d)\n",
212203b705cfSriastradh			     __FUNCTION__, (int)DAMAGE_IS_ALL(t->damage),
212303b705cfSriastradh			     t->box.x1, t->box.y1));
212403b705cfSriastradh			sna_damage_combine(t->real_damage,
212503b705cfSriastradh					   DAMAGE_PTR(t->damage),
212603b705cfSriastradh					   t->box.x1, t->box.y1);
212703b705cfSriastradh			__sna_damage_destroy(DAMAGE_PTR(t->damage));
212803b705cfSriastradh		}
212903b705cfSriastradh
213003b705cfSriastradh		kgem_bo_destroy(&sna->kgem, op->dst.bo);
213103b705cfSriastradh	}
213203b705cfSriastradh}
213303b705cfSriastradh
213442542f5fSchristosstatic bool
213542542f5fSchristoscopy_overlap(struct sna *sna, uint8_t alu,
213642542f5fSchristos	     const DrawableRec *draw, struct kgem_bo *bo,
213742542f5fSchristos	     int16_t src_dx, int16_t src_dy,
213842542f5fSchristos	     int16_t dst_dx, int16_t dst_dy,
213942542f5fSchristos	     const BoxRec *box, int n, const BoxRec *extents)
214003b705cfSriastradh{
214142542f5fSchristos	ScreenPtr screen = draw->pScreen;
214242542f5fSchristos	struct kgem_bo *tmp_bo;
214303b705cfSriastradh	PixmapPtr tmp;
214403b705cfSriastradh	bool ret = false;
214503b705cfSriastradh
214642542f5fSchristos	if (n == 0)
214742542f5fSchristos		return true;
214842542f5fSchristos
214942542f5fSchristos	DBG(("%s: %d x %dx%d src=(%d, %d), dst=(%d, %d)\n",
215042542f5fSchristos	     __FUNCTION__, n,
215142542f5fSchristos	     extents->x2 - extents->x1,
215242542f5fSchristos	     extents->y2 - extents->y1,
215342542f5fSchristos	     src_dx, src_dy,
215442542f5fSchristos	     dst_dx, dst_dy));
215542542f5fSchristos
215603b705cfSriastradh	tmp = screen->CreatePixmap(screen,
215703b705cfSriastradh				   extents->x2 - extents->x1,
215803b705cfSriastradh				   extents->y2 - extents->y1,
215942542f5fSchristos				   draw->depth,
216003b705cfSriastradh				   SNA_CREATE_SCRATCH);
216103b705cfSriastradh	if (tmp == NULL)
216203b705cfSriastradh		return false;
216303b705cfSriastradh
216442542f5fSchristos	tmp_bo = __sna_pixmap_get_bo(tmp);
216542542f5fSchristos	assert(tmp_bo);
216603b705cfSriastradh
216742542f5fSchristos	ret = (sna->render.copy_boxes(sna, GXcopy,
216842542f5fSchristos				      draw, bo, src_dx, src_dy,
216942542f5fSchristos				      &tmp->drawable, tmp_bo, -extents->x1, -extents->y1,
2170fe8aea9eSmrg				      box, n, 0) &&
217103b705cfSriastradh	       sna->render.copy_boxes(sna, alu,
217242542f5fSchristos				      &tmp->drawable, tmp_bo, -extents->x1, -extents->y1,
217342542f5fSchristos				      draw, bo, dst_dx, dst_dy,
2174fe8aea9eSmrg				      box, n, 0));
217503b705cfSriastradh
217603b705cfSriastradh	screen->DestroyPixmap(tmp);
217703b705cfSriastradh	return ret;
217803b705cfSriastradh}
217942542f5fSchristosbool
218042542f5fSchristossna_render_copy_boxes__overlap(struct sna *sna, uint8_t alu,
218142542f5fSchristos			       const DrawableRec *draw, struct kgem_bo *bo,
218242542f5fSchristos			       int16_t src_dx, int16_t src_dy,
218342542f5fSchristos			       int16_t dst_dx, int16_t dst_dy,
218442542f5fSchristos			       const BoxRec *box, int n, const BoxRec *extents)
218542542f5fSchristos{
218642542f5fSchristos	bool ret = false;
218742542f5fSchristos	RegionRec overlap, non_overlap;
218842542f5fSchristos	pixman_region16_t region;
218942542f5fSchristos	pixman_box16_t stack_boxes[64], *boxes = stack_boxes;
219042542f5fSchristos	int num_boxes, i;
219142542f5fSchristos
219242542f5fSchristos	DBG(("%s: pixmap=%ld, handle=%d, %d x [(%d, %d), (%d, %d)], dst=(%d, %d), src=(%d, %d)\n",
219342542f5fSchristos	     __FUNCTION__, draw->serialNumber, bo->handle,
219442542f5fSchristos	     n, extents->x1, extents->y1, extents->x2, extents->y2,
219542542f5fSchristos	     src_dx, src_dy, dst_dx, dst_dy));
219642542f5fSchristos
219742542f5fSchristos	if ((dst_dx - src_dx < 4 && src_dx - dst_dx < 4) &&
219842542f5fSchristos	    (dst_dy - src_dy < 4 && src_dy - dst_dy < 4))
219942542f5fSchristos		return copy_overlap(sna, alu, draw, bo,
220042542f5fSchristos				    src_dx, src_dy,
220142542f5fSchristos				    dst_dx, dst_dy,
220242542f5fSchristos				    box, n, extents);
220342542f5fSchristos
220442542f5fSchristos	if (n > ARRAY_SIZE(stack_boxes)) {
220542542f5fSchristos		boxes = malloc(sizeof(pixman_box16_t) * n);
220642542f5fSchristos		if (boxes == NULL)
220742542f5fSchristos			return copy_overlap(sna, alu, draw, bo,
220842542f5fSchristos					    src_dx, src_dy,
220942542f5fSchristos					    dst_dx, dst_dy,
221042542f5fSchristos					    box, n, extents);
221142542f5fSchristos	}
221242542f5fSchristos
221342542f5fSchristos	region.extents.x1 = extents->x1 + dst_dx;
221442542f5fSchristos	region.extents.x2 = extents->x2 + dst_dx;
221542542f5fSchristos	region.extents.y1 = extents->y1 + dst_dy;
221642542f5fSchristos	region.extents.y2 = extents->y2 + dst_dy;
221742542f5fSchristos
221842542f5fSchristos	for (i = num_boxes = 0; i < n; i++) {
221942542f5fSchristos		boxes[num_boxes].x1 = box[i].x1 + dst_dx;
222042542f5fSchristos		if (boxes[num_boxes].x1 < region.extents.x1)
222142542f5fSchristos			boxes[num_boxes].x1 = region.extents.x1;
222242542f5fSchristos
222342542f5fSchristos		boxes[num_boxes].y1 = box[i].y1 + dst_dy;
222442542f5fSchristos		if (boxes[num_boxes].y1 < region.extents.y1)
222542542f5fSchristos			boxes[num_boxes].y1 = region.extents.y1;
222642542f5fSchristos
222742542f5fSchristos		boxes[num_boxes].x2 = box[i].x2 + dst_dx;
222842542f5fSchristos		if (boxes[num_boxes].x2 > region.extents.x2)
222942542f5fSchristos			boxes[num_boxes].x2 = region.extents.x2;
223042542f5fSchristos
223142542f5fSchristos		boxes[num_boxes].y2 = box[i].y2 + dst_dy;
223242542f5fSchristos		if (boxes[num_boxes].y2 > region.extents.y2)
223342542f5fSchristos			boxes[num_boxes].y2 = region.extents.y2;
223442542f5fSchristos
223542542f5fSchristos		if (boxes[num_boxes].x2 > boxes[num_boxes].x1 &&
223642542f5fSchristos		    boxes[num_boxes].y2 > boxes[num_boxes].y1)
223742542f5fSchristos			num_boxes++;
223842542f5fSchristos	}
223942542f5fSchristos
224042542f5fSchristos	if (num_boxes == 0) {
224142542f5fSchristos		ret = true;
224242542f5fSchristos		goto cleanup_boxes;
224342542f5fSchristos	}
224442542f5fSchristos
224542542f5fSchristos	if (!pixman_region_init_rects(&region, boxes, num_boxes))
224642542f5fSchristos		goto cleanup_boxes;
224742542f5fSchristos
224842542f5fSchristos	overlap.extents.x1 = extents->x1 + src_dx;
224942542f5fSchristos	overlap.extents.x2 = extents->x2 + src_dx;
225042542f5fSchristos	overlap.extents.y1 = extents->y1 + src_dy;
225142542f5fSchristos	overlap.extents.y2 = extents->y2 + src_dy;
225242542f5fSchristos	overlap.data = NULL;
225342542f5fSchristos
225442542f5fSchristos	RegionIntersect(&overlap, &overlap, &region);
225542542f5fSchristos	DBG(("%s: overlapping extents: (%d, %d), (%d, %d) x %d\n",
225642542f5fSchristos	     __FUNCTION__,
225742542f5fSchristos	     overlap.extents.x1, overlap.extents.y1,
225842542f5fSchristos	     overlap.extents.x2, overlap.extents.y2,
225942542f5fSchristos	     region_num_rects(&overlap)));
226042542f5fSchristos
226142542f5fSchristos	RegionNull(&non_overlap);
226242542f5fSchristos	RegionSubtract(&non_overlap, &region, &overlap);
226342542f5fSchristos	DBG(("%s: non-overlapping extents: (%d, %d), (%d, %d) x %d\n",
226442542f5fSchristos	     __FUNCTION__,
226542542f5fSchristos	     non_overlap.extents.x1, non_overlap.extents.y1,
226642542f5fSchristos	     non_overlap.extents.x2, non_overlap.extents.y2,
226742542f5fSchristos	     region_num_rects(&non_overlap)));
226842542f5fSchristos
226942542f5fSchristos	n = region_num_rects(&non_overlap);
227042542f5fSchristos	box = region_rects(&non_overlap);
227142542f5fSchristos	if (n && !sna->render.copy_boxes(sna, alu,
227242542f5fSchristos					 draw, bo, -dst_dx + src_dx, -dst_dy + src_dy,
227342542f5fSchristos					 draw, bo, 0, 0,
227442542f5fSchristos					 box, n , COPY_NO_OVERLAP))
227542542f5fSchristos		goto cleanup_boxes;
227642542f5fSchristos
227742542f5fSchristos	n = region_num_rects(&overlap);
227842542f5fSchristos	box = region_rects(&overlap);
227942542f5fSchristos	ret = copy_overlap(sna, alu, draw, bo,
228042542f5fSchristos			   -dst_dx + src_dx, -dst_dy + src_dy,
228142542f5fSchristos			   0, 0,
228242542f5fSchristos			   box, n, &overlap.extents);
228342542f5fSchristos
228442542f5fSchristoscleanup_boxes:
228542542f5fSchristos	if (boxes != stack_boxes)
228642542f5fSchristos		free(boxes);
228742542f5fSchristos
228842542f5fSchristos	return ret;
228942542f5fSchristos}
229013496ba1Ssnj
229113496ba1Ssnjstatic bool can_copy_cpu(struct sna *sna,
229213496ba1Ssnj			 struct kgem_bo *src,
229313496ba1Ssnj			 struct kgem_bo *dst)
229413496ba1Ssnj{
2295fe8aea9eSmrg	DBG(("%s: tiling=%d:%d, pitch=%d:%d, can_map=%d:%d[%d]\n",
2296fe8aea9eSmrg	     __FUNCTION__,
2297fe8aea9eSmrg	     src->tiling, dst->tiling,
2298fe8aea9eSmrg	     src->pitch, dst->pitch,
2299fe8aea9eSmrg	     kgem_bo_can_map__cpu(&sna->kgem, src, false),
2300fe8aea9eSmrg	     kgem_bo_can_map__cpu(&sna->kgem, dst, true),
2301fe8aea9eSmrg	     sna->kgem.has_wc_mmap));
230213496ba1Ssnj
2303fe8aea9eSmrg	if (src->tiling != dst->tiling)
230413496ba1Ssnj		return false;
230513496ba1Ssnj
230613496ba1Ssnj	if (!kgem_bo_can_map__cpu(&sna->kgem, src, false))
230713496ba1Ssnj		return false;
230813496ba1Ssnj
2309fe8aea9eSmrg	if (!kgem_bo_can_map__cpu(&sna->kgem, dst, true) &&
2310fe8aea9eSmrg	    !sna->kgem.has_wc_mmap)
231113496ba1Ssnj		return false;
231213496ba1Ssnj
231313496ba1Ssnj	DBG(("%s -- yes, src handle=%d, dst handle=%d\n", __FUNCTION__, src->handle, dst->handle));
231413496ba1Ssnj	return true;
231513496ba1Ssnj}
231613496ba1Ssnj
231713496ba1Ssnjbool
231813496ba1Ssnjmemcpy_copy_boxes(struct sna *sna, uint8_t op,
231913496ba1Ssnj		  const DrawableRec *src_draw, struct kgem_bo *src_bo, int16_t sx, int16_t sy,
232013496ba1Ssnj		  const DrawableRec *dst_draw, struct kgem_bo *dst_bo, int16_t dx, int16_t dy,
232113496ba1Ssnj		  const BoxRec *box, int n, unsigned flags)
232213496ba1Ssnj{
2323fe8aea9eSmrg	memcpy_box_func detile = NULL;
232413496ba1Ssnj	void *dst, *src;
232513496ba1Ssnj
232613496ba1Ssnj	if (op != GXcopy)
232713496ba1Ssnj		return false;
232813496ba1Ssnj
2329fe8aea9eSmrg	if (src_draw->depth != dst_draw->depth)
2330fe8aea9eSmrg		return false;
233113496ba1Ssnj
233213496ba1Ssnj	dst = src = NULL;
2333fe8aea9eSmrg	if (can_copy_cpu(sna, src_bo, dst_bo)) {
2334fe8aea9eSmrg		if (src_bo->pitch != dst_bo->pitch ||
2335fe8aea9eSmrg		    dx != sx || dy != sy || n > 1 ||
2336fe8aea9eSmrg		    box->x1 + dx > 0 ||
2337fe8aea9eSmrg		    box->y1 + dy > 0 ||
2338fe8aea9eSmrg		    box->x2 + dx < dst_draw->width ||
2339fe8aea9eSmrg		    box->y2 + dy < dst_draw->height) {
2340fe8aea9eSmrg			if (dx != sx) /* not implemented in memcpy yet */
2341fe8aea9eSmrg				goto use_gtt;
2342fe8aea9eSmrg
2343fe8aea9eSmrg			switch (dst_bo->tiling) {
2344fe8aea9eSmrg			default:
2345fe8aea9eSmrg			case I915_TILING_Y:
2346fe8aea9eSmrg				goto use_gtt;
2347fe8aea9eSmrg
2348fe8aea9eSmrg			case I915_TILING_X:
2349fe8aea9eSmrg				detile = sna->kgem.memcpy_between_tiled_x;
2350fe8aea9eSmrg				if (detile == NULL)
2351fe8aea9eSmrg					goto use_gtt;
2352fe8aea9eSmrg				break;
2353fe8aea9eSmrg
2354fe8aea9eSmrg			case I915_TILING_NONE:
2355fe8aea9eSmrg				break;
2356fe8aea9eSmrg			}
2357fe8aea9eSmrg		}
2358fe8aea9eSmrg
2359fe8aea9eSmrg		if (kgem_bo_can_map__cpu(&sna->kgem, dst_bo, true))
2360fe8aea9eSmrg			dst = kgem_bo_map__cpu(&sna->kgem, dst_bo);
2361fe8aea9eSmrg		else
2362fe8aea9eSmrg			dst = kgem_bo_map__wc(&sna->kgem, dst_bo);
236313496ba1Ssnj		src = kgem_bo_map__cpu(&sna->kgem, src_bo);
236413496ba1Ssnj	}
236513496ba1Ssnj
236613496ba1Ssnj	if (dst == NULL || src == NULL) {
2367fe8aea9eSmrguse_gtt:
236813496ba1Ssnj		dst = kgem_bo_map__gtt(&sna->kgem, dst_bo);
236913496ba1Ssnj		src = kgem_bo_map__gtt(&sna->kgem, src_bo);
237013496ba1Ssnj		if (dst == NULL || src == NULL)
237113496ba1Ssnj			return false;
2372fe8aea9eSmrg
2373fe8aea9eSmrg		kgem_bo_sync__gtt(&sna->kgem, dst_bo);
2374fe8aea9eSmrg		kgem_bo_sync__gtt(&sna->kgem, src_bo);
2375fe8aea9eSmrg
2376fe8aea9eSmrg		detile = NULL;
237713496ba1Ssnj	} else {
2378fe8aea9eSmrg		if (dst == dst_bo->map__wc)
2379fe8aea9eSmrg			kgem_bo_sync__gtt(&sna->kgem, dst_bo);
2380fe8aea9eSmrg		else
2381fe8aea9eSmrg			kgem_bo_sync__cpu_full(&sna->kgem, dst_bo, true);
238213496ba1Ssnj		kgem_bo_sync__cpu_full(&sna->kgem, src_bo, false);
238313496ba1Ssnj	}
238413496ba1Ssnj
238513496ba1Ssnj	DBG(("%s: src(%d, %d), dst(%d, %d) x %d\n",
238613496ba1Ssnj	     __FUNCTION__, sx, sy, dx, dy, n));
238713496ba1Ssnj
238813496ba1Ssnj	if (sigtrap_get() == 0) {
2389fe8aea9eSmrg		if (detile) {
2390fe8aea9eSmrg			do {
2391fe8aea9eSmrg				detile(src, dst, dst_draw->bitsPerPixel,
2392fe8aea9eSmrg				       src_bo->pitch, dst_bo->pitch,
2393fe8aea9eSmrg				       box->x1 + sx, box->y1 + sy,
2394fe8aea9eSmrg				       box->x1 + dx, box->y1 + dy,
2395fe8aea9eSmrg				       box->x2 - box->x1, box->y2 - box->y1);
2396fe8aea9eSmrg				box++;
2397fe8aea9eSmrg			} while (--n);
2398fe8aea9eSmrg		} else do {
239913496ba1Ssnj			memcpy_blt(src, dst, dst_draw->bitsPerPixel,
240013496ba1Ssnj				   src_bo->pitch, dst_bo->pitch,
240113496ba1Ssnj				   box->x1 + sx, box->y1 + sy,
240213496ba1Ssnj				   box->x1 + dx, box->y1 + dy,
240313496ba1Ssnj				   box->x2 - box->x1, box->y2 - box->y1);
240413496ba1Ssnj			box++;
240513496ba1Ssnj		} while (--n);
240613496ba1Ssnj		sigtrap_put();
240713496ba1Ssnj	}
240813496ba1Ssnj
240913496ba1Ssnj	return true;
241013496ba1Ssnj}
241113496ba1Ssnj
241213496ba1Ssnjvoid
241313496ba1Ssnjsna_render_mark_wedged(struct sna *sna)
241413496ba1Ssnj{
241513496ba1Ssnj	sna->render.copy_boxes = memcpy_copy_boxes;
2416fe8aea9eSmrg	sna->render.prefer_gpu = 0;
241713496ba1Ssnj}
2418