1428d7b3dSmrg/*
2428d7b3dSmrg * Copyright © 2011 Intel Corporation
3428d7b3dSmrg *
4428d7b3dSmrg * Permission is hereby granted, free of charge, to any person obtaining a
5428d7b3dSmrg * copy of this software and associated documentation files (the "Software"),
6428d7b3dSmrg * to deal in the Software without restriction, including without limitation
7428d7b3dSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8428d7b3dSmrg * and/or sell copies of the Software, and to permit persons to whom the
9428d7b3dSmrg * Software is furnished to do so, subject to the following conditions:
10428d7b3dSmrg *
11428d7b3dSmrg * The above copyright notice and this permission notice (including the next
12428d7b3dSmrg * paragraph) shall be included in all copies or substantial portions of the
13428d7b3dSmrg * Software.
14428d7b3dSmrg *
15428d7b3dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16428d7b3dSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17428d7b3dSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18428d7b3dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19428d7b3dSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20428d7b3dSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21428d7b3dSmrg * SOFTWARE.
22428d7b3dSmrg *
23428d7b3dSmrg * Authors:
24428d7b3dSmrg *    Chris Wilson <chris@chris-wilson.co.uk>
25428d7b3dSmrg *
26428d7b3dSmrg */
27428d7b3dSmrg
28428d7b3dSmrg#ifdef HAVE_CONFIG_H
29428d7b3dSmrg#include "config.h"
30428d7b3dSmrg#endif
31428d7b3dSmrg
32428d7b3dSmrg#include "sna.h"
33428d7b3dSmrg#include "sna_render.h"
34428d7b3dSmrg#include "sna_render_inline.h"
35428d7b3dSmrg#include "fb/fbpict.h"
36428d7b3dSmrg
37428d7b3dSmrg#define NO_REDIRECT 0
38428d7b3dSmrg#define NO_CONVERT 0
39428d7b3dSmrg#define NO_FIXUP 0
40428d7b3dSmrg#define NO_EXTRACT 0
41428d7b3dSmrg
42428d7b3dSmrg#define DBG_FORCE_UPLOAD 0
43428d7b3dSmrg#define DBG_NO_CPU_BO 0
44428d7b3dSmrg
45428d7b3dSmrg#define alphaless(format) PICT_FORMAT(PICT_FORMAT_BPP(format),		\
46428d7b3dSmrg				      PICT_FORMAT_TYPE(format),		\
47428d7b3dSmrg				      0,				\
48428d7b3dSmrg				      PICT_FORMAT_R(format),		\
49428d7b3dSmrg				      PICT_FORMAT_G(format),		\
50428d7b3dSmrg				      PICT_FORMAT_B(format))
51428d7b3dSmrg
52428d7b3dSmrgCARD32
53428d7b3dSmrgsna_format_for_depth(int depth)
54428d7b3dSmrg{
55428d7b3dSmrg	switch (depth) {
56428d7b3dSmrg	case 1: return PICT_a1;
57428d7b3dSmrg	case 4: return PICT_a4;
58428d7b3dSmrg	case 8: return PICT_a8;
59428d7b3dSmrg	case 15: return PICT_x1r5g5b5;
60428d7b3dSmrg	case 16: return PICT_r5g6b5;
61428d7b3dSmrg	default: assert(0);
62428d7b3dSmrg	case 24: return PICT_x8r8g8b8;
63428d7b3dSmrg#ifdef PICT_x2r10g10b10
64428d7b3dSmrg	case 30: return PICT_x2r10g10b10;
65428d7b3dSmrg#endif
66428d7b3dSmrg	case 32: return PICT_a8r8g8b8;
67428d7b3dSmrg	}
68428d7b3dSmrg}
69428d7b3dSmrg
70428d7b3dSmrgCARD32
71428d7b3dSmrgsna_render_format_for_depth(int depth)
72428d7b3dSmrg{
73428d7b3dSmrg	switch (depth) {
74428d7b3dSmrg	case 1: return PIXMAN_a1;
75428d7b3dSmrg	case 4: return PIXMAN_a4;
76428d7b3dSmrg	case 8: return PIXMAN_a8;
77428d7b3dSmrg	case 15: return PIXMAN_a1r5g5b5;
78428d7b3dSmrg	case 16: return PIXMAN_r5g6b5;
79428d7b3dSmrg	case 30: return PIXMAN_a2r10g10b10;
80428d7b3dSmrg	default: assert(0);
81428d7b3dSmrg	case 24:
82428d7b3dSmrg	case 32: return PIXMAN_a8r8g8b8;
83428d7b3dSmrg	}
84428d7b3dSmrg}
85428d7b3dSmrg
86428d7b3dSmrgstatic bool
87428d7b3dSmrgno_render_composite(struct sna *sna,
88428d7b3dSmrg		    uint8_t op,
89428d7b3dSmrg		    PicturePtr src,
90428d7b3dSmrg		    PicturePtr mask,
91428d7b3dSmrg		    PicturePtr dst,
92428d7b3dSmrg		    int16_t src_x, int16_t src_y,
93428d7b3dSmrg		    int16_t mask_x, int16_t mask_y,
94428d7b3dSmrg		    int16_t dst_x, int16_t dst_y,
95428d7b3dSmrg		    int16_t width, int16_t height,
96428d7b3dSmrg		    unsigned flags,
97428d7b3dSmrg		    struct sna_composite_op *tmp)
98428d7b3dSmrg{
99428d7b3dSmrg	DBG(("%s (op=%d, mask? %d)\n", __FUNCTION__, op, mask != NULL));
100428d7b3dSmrg
101428d7b3dSmrg	if (mask)
102428d7b3dSmrg		return false;
103428d7b3dSmrg
104428d7b3dSmrg	if (!is_gpu(sna, dst->pDrawable, PREFER_GPU_BLT) &&
105428d7b3dSmrg	    (src->pDrawable == NULL || !is_gpu(sna, src->pDrawable, PREFER_GPU_BLT)))
106428d7b3dSmrg		return false;
107428d7b3dSmrg
108428d7b3dSmrg	return sna_blt_composite(sna,
109428d7b3dSmrg				 op, src, dst,
110428d7b3dSmrg				 src_x, src_y,
111428d7b3dSmrg				 dst_x, dst_y,
112428d7b3dSmrg				 width, height,
113428d7b3dSmrg				 flags | COMPOSITE_FALLBACK, tmp);
114428d7b3dSmrg	(void)mask_x;
115428d7b3dSmrg	(void)mask_y;
116428d7b3dSmrg}
117428d7b3dSmrg
118428d7b3dSmrgstatic bool
119428d7b3dSmrgno_render_check_composite_spans(struct sna *sna,
120428d7b3dSmrg				uint8_t op, PicturePtr src, PicturePtr dst,
121428d7b3dSmrg				int16_t width,  int16_t height, unsigned flags)
122428d7b3dSmrg{
123428d7b3dSmrg	return false;
124428d7b3dSmrg}
125428d7b3dSmrg
126428d7b3dSmrgstatic bool
127428d7b3dSmrgno_render_copy_boxes(struct sna *sna, uint8_t alu,
128428d7b3dSmrg		     const DrawableRec *src, struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy,
129428d7b3dSmrg		     const DrawableRec *dst, struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy,
130428d7b3dSmrg		     const BoxRec *box, int n, unsigned flags)
131428d7b3dSmrg{
132428d7b3dSmrg	DBG(("%s (n=%d)\n", __FUNCTION__, n));
133428d7b3dSmrg
134428d7b3dSmrg	if (!sna_blt_compare_depth(src, dst))
135428d7b3dSmrg		return false;
136428d7b3dSmrg
137428d7b3dSmrg	return sna_blt_copy_boxes(sna, alu,
138428d7b3dSmrg				  src_bo, src_dx, src_dy,
139428d7b3dSmrg				  dst_bo, dst_dx, dst_dy,
140428d7b3dSmrg				  dst->bitsPerPixel,
141428d7b3dSmrg				  box, n);
142428d7b3dSmrg}
143428d7b3dSmrg
144428d7b3dSmrgstatic bool
145428d7b3dSmrgno_render_copy(struct sna *sna, uint8_t alu,
146428d7b3dSmrg		 PixmapPtr src, struct kgem_bo *src_bo,
147428d7b3dSmrg		 PixmapPtr dst, struct kgem_bo *dst_bo,
148428d7b3dSmrg		 struct sna_copy_op *tmp)
149428d7b3dSmrg{
150428d7b3dSmrg	DBG(("%s ()\n", __FUNCTION__));
151428d7b3dSmrg
152428d7b3dSmrg	if (sna_blt_compare_depth(&src->drawable, &dst->drawable) &&
153428d7b3dSmrg	    sna_blt_copy(sna, alu,
154428d7b3dSmrg			 src_bo, dst_bo, dst->drawable.bitsPerPixel,
155428d7b3dSmrg			 tmp))
156428d7b3dSmrg		return true;
157428d7b3dSmrg
158428d7b3dSmrg	return false;
159428d7b3dSmrg}
160428d7b3dSmrg
161428d7b3dSmrgstatic bool
162428d7b3dSmrgno_render_fill_boxes(struct sna *sna,
163428d7b3dSmrg		     CARD8 op,
164428d7b3dSmrg		     PictFormat format,
165428d7b3dSmrg		     const xRenderColor *color,
166428d7b3dSmrg		     const DrawableRec *dst, struct kgem_bo *dst_bo,
167428d7b3dSmrg		     const BoxRec *box, int n)
168428d7b3dSmrg{
169428d7b3dSmrg	uint8_t alu = GXcopy;
170428d7b3dSmrg	uint32_t pixel;
171428d7b3dSmrg
172428d7b3dSmrg	DBG(("%s (op=%d, color=(%04x,%04x,%04x, %04x))\n",
173428d7b3dSmrg	     __FUNCTION__, op,
174428d7b3dSmrg	     color->red, color->green, color->blue, color->alpha));
175428d7b3dSmrg
176428d7b3dSmrg	if (op == PictOpClear) {
177428d7b3dSmrg		pixel = 0;
178428d7b3dSmrg		alu = GXclear;
179428d7b3dSmrg		op = PictOpSrc;
180428d7b3dSmrg	}
181428d7b3dSmrg
182428d7b3dSmrg	if (op == PictOpOver) {
183428d7b3dSmrg		if ((color->alpha >= 0xff00))
184428d7b3dSmrg			op = PictOpSrc;
185428d7b3dSmrg	}
186428d7b3dSmrg
187428d7b3dSmrg	if (op != PictOpSrc)
188428d7b3dSmrg		return false;
189428d7b3dSmrg
190428d7b3dSmrg	if (alu == GXcopy &&
191428d7b3dSmrg	    !sna_get_pixel_from_rgba(&pixel,
192428d7b3dSmrg				     color->red,
193428d7b3dSmrg				     color->green,
194428d7b3dSmrg				     color->blue,
195428d7b3dSmrg				     color->alpha,
196428d7b3dSmrg				     format))
197428d7b3dSmrg		return false;
198428d7b3dSmrg
199428d7b3dSmrg	return sna_blt_fill_boxes(sna, alu,
200428d7b3dSmrg				  dst_bo, dst->bitsPerPixel,
201428d7b3dSmrg				  pixel, box, n);
202428d7b3dSmrg}
203428d7b3dSmrg
204428d7b3dSmrgstatic bool
205428d7b3dSmrgno_render_fill(struct sna *sna, uint8_t alu,
206428d7b3dSmrg	       PixmapPtr dst, struct kgem_bo *dst_bo,
207428d7b3dSmrg	       uint32_t color, unsigned flags,
208428d7b3dSmrg	       struct sna_fill_op *tmp)
209428d7b3dSmrg{
210428d7b3dSmrg	DBG(("%s (alu=%d, color=%08x)\n", __FUNCTION__, alu, color));
211428d7b3dSmrg	return sna_blt_fill(sna, alu,
212428d7b3dSmrg			    dst_bo, dst->drawable.bitsPerPixel,
213428d7b3dSmrg			    color,
214428d7b3dSmrg			    tmp);
215428d7b3dSmrg}
216428d7b3dSmrg
217428d7b3dSmrgstatic bool
218428d7b3dSmrgno_render_fill_one(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo,
219428d7b3dSmrg		   uint32_t color,
220428d7b3dSmrg		   int16_t x1, int16_t y1, int16_t x2, int16_t y2,
221428d7b3dSmrg		   uint8_t alu)
222428d7b3dSmrg{
223428d7b3dSmrg	BoxRec box;
224428d7b3dSmrg
225428d7b3dSmrg	box.x1 = x1;
226428d7b3dSmrg	box.y1 = y1;
227428d7b3dSmrg	box.x2 = x2;
228428d7b3dSmrg	box.y2 = y2;
229428d7b3dSmrg
230428d7b3dSmrg	DBG(("%s (alu=%d, color=%08x) (%d,%d), (%d, %d)\n",
231428d7b3dSmrg	     __FUNCTION__, alu, color, x1, y1, x2, y2));
232428d7b3dSmrg	return sna_blt_fill_boxes(sna, alu,
233428d7b3dSmrg				  bo, dst->drawable.bitsPerPixel,
234428d7b3dSmrg				  color, &box, 1);
235428d7b3dSmrg}
236428d7b3dSmrg
237428d7b3dSmrgstatic bool
238428d7b3dSmrgno_render_clear(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo)
239428d7b3dSmrg{
240428d7b3dSmrg	DBG(("%s: pixmap=%ld %dx%d\n", __FUNCTION__,
241428d7b3dSmrg	     dst->drawable.serialNumber,
242428d7b3dSmrg	     dst->drawable.width,
243428d7b3dSmrg	     dst->drawable.height));
244428d7b3dSmrg	return sna->render.fill_one(sna, dst, bo, 0,
245428d7b3dSmrg				    0, 0, dst->drawable.width, dst->drawable.height,
246428d7b3dSmrg				    GXclear);
247428d7b3dSmrg}
248428d7b3dSmrg
249428d7b3dSmrgstatic void no_render_reset(struct sna *sna)
250428d7b3dSmrg{
251428d7b3dSmrg	(void)sna;
252428d7b3dSmrg}
253428d7b3dSmrg
254428d7b3dSmrgstatic void no_render_flush(struct sna *sna)
255428d7b3dSmrg{
256428d7b3dSmrg	(void)sna;
257428d7b3dSmrg}
258428d7b3dSmrg
259428d7b3dSmrgstatic void
260428d7b3dSmrgno_render_context_switch(struct kgem *kgem,
261428d7b3dSmrg			 int new_mode)
262428d7b3dSmrg{
263428d7b3dSmrg	if (!kgem->nbatch)
264428d7b3dSmrg		return;
265428d7b3dSmrg
266428d7b3dSmrg	if (kgem_ring_is_idle(kgem, kgem->ring)) {
267428d7b3dSmrg		DBG(("%s: GPU idle, flushing\n", __FUNCTION__));
268428d7b3dSmrg		_kgem_submit(kgem);
269428d7b3dSmrg	}
270428d7b3dSmrg
271428d7b3dSmrg	(void)new_mode;
272428d7b3dSmrg}
273428d7b3dSmrg
274428d7b3dSmrgstatic void
275428d7b3dSmrgno_render_retire(struct kgem *kgem)
276428d7b3dSmrg{
277428d7b3dSmrg	(void)kgem;
278428d7b3dSmrg}
279428d7b3dSmrg
280428d7b3dSmrgstatic void
281428d7b3dSmrgno_render_expire(struct kgem *kgem)
282428d7b3dSmrg{
283428d7b3dSmrg	(void)kgem;
284428d7b3dSmrg}
285428d7b3dSmrg
286428d7b3dSmrgstatic void
287428d7b3dSmrgno_render_fini(struct sna *sna)
288428d7b3dSmrg{
289428d7b3dSmrg	(void)sna;
290428d7b3dSmrg}
291428d7b3dSmrg
292428d7b3dSmrgconst char *no_render_init(struct sna *sna)
293428d7b3dSmrg{
294428d7b3dSmrg	struct sna_render *render = &sna->render;
295428d7b3dSmrg
296428d7b3dSmrg	memset (render, 0, sizeof (*render));
297428d7b3dSmrg
298428d7b3dSmrg	render->prefer_gpu = PREFER_GPU_BLT;
299428d7b3dSmrg
300428d7b3dSmrg	render->vertices = render->vertex_data;
301428d7b3dSmrg	render->vertex_size = ARRAY_SIZE(render->vertex_data);
302428d7b3dSmrg
303428d7b3dSmrg	render->composite = no_render_composite;
304428d7b3dSmrg	render->check_composite_spans = no_render_check_composite_spans;
305428d7b3dSmrg
306428d7b3dSmrg	render->copy_boxes = no_render_copy_boxes;
307428d7b3dSmrg	render->copy = no_render_copy;
308428d7b3dSmrg
309428d7b3dSmrg	render->fill_boxes = no_render_fill_boxes;
310428d7b3dSmrg	render->fill = no_render_fill;
311428d7b3dSmrg	render->fill_one = no_render_fill_one;
312428d7b3dSmrg	render->clear = no_render_clear;
313428d7b3dSmrg
314428d7b3dSmrg	render->reset = no_render_reset;
315428d7b3dSmrg	render->flush = no_render_flush;
316428d7b3dSmrg	render->fini = no_render_fini;
317428d7b3dSmrg
318428d7b3dSmrg	sna->kgem.context_switch = no_render_context_switch;
319428d7b3dSmrg	sna->kgem.retire = no_render_retire;
320428d7b3dSmrg	sna->kgem.expire = no_render_expire;
321428d7b3dSmrg	if (sna->kgem.has_blt)
322428d7b3dSmrg		sna->kgem.ring = KGEM_BLT;
323428d7b3dSmrg
324428d7b3dSmrg	sna_vertex_init(sna);
325428d7b3dSmrg	return "generic";
326428d7b3dSmrg}
327428d7b3dSmrg
328428d7b3dSmrgstatic struct kgem_bo *
329428d7b3dSmrguse_cpu_bo(struct sna *sna, PixmapPtr pixmap, const BoxRec *box, bool blt)
330428d7b3dSmrg{
331428d7b3dSmrg	struct sna_pixmap *priv;
332428d7b3dSmrg
333428d7b3dSmrg	if (DBG_NO_CPU_BO)
334428d7b3dSmrg		return NULL;
335428d7b3dSmrg
336428d7b3dSmrg	priv = sna_pixmap(pixmap);
337428d7b3dSmrg	if (priv == NULL || priv->cpu_bo == NULL) {
338428d7b3dSmrg		DBG(("%s: no cpu bo\n", __FUNCTION__));
339428d7b3dSmrg		return NULL;
340428d7b3dSmrg	}
341428d7b3dSmrg
342428d7b3dSmrg	if (!blt && priv->cpu_bo->snoop && priv->source_count > SOURCE_BIAS) {
343428d7b3dSmrg		DBG(("%s: promoting snooped CPU bo due to reuse\n",
344428d7b3dSmrg		     __FUNCTION__));
345428d7b3dSmrg		return NULL;
346428d7b3dSmrg	}
347428d7b3dSmrg
348428d7b3dSmrg	if (priv->gpu_bo) {
349428d7b3dSmrg		switch (sna_damage_contains_box(&priv->cpu_damage, box)) {
350428d7b3dSmrg		case PIXMAN_REGION_OUT:
351428d7b3dSmrg			DBG(("%s: has GPU bo and no damage to upload\n",
352428d7b3dSmrg			     __FUNCTION__));
353428d7b3dSmrg			return NULL;
354428d7b3dSmrg
355428d7b3dSmrg		case PIXMAN_REGION_IN:
356428d7b3dSmrg			DBG(("%s: has GPU bo but box is completely on CPU\n",
357428d7b3dSmrg			     __FUNCTION__));
358428d7b3dSmrg			break;
359428d7b3dSmrg		default:
360428d7b3dSmrg			if (kgem_bo_is_busy(priv->gpu_bo)){
361428d7b3dSmrg				DBG(("%s: box is partially damaged on the CPU, and the GPU is busy\n",
362428d7b3dSmrg				     __FUNCTION__));
363428d7b3dSmrg				return NULL;
364428d7b3dSmrg			}
365428d7b3dSmrg			if (sna_damage_contains_box(&priv->gpu_damage,
366428d7b3dSmrg						    box) != PIXMAN_REGION_OUT) {
367428d7b3dSmrg				DBG(("%s: box is damaged on the GPU\n",
368428d7b3dSmrg				     __FUNCTION__));
369428d7b3dSmrg				return NULL;
370428d7b3dSmrg			}
371428d7b3dSmrg			break;
372428d7b3dSmrg		}
373428d7b3dSmrg	}
374428d7b3dSmrg
375428d7b3dSmrg	if (!blt) {
376428d7b3dSmrg		int w = box->x2 - box->x1;
377428d7b3dSmrg		int h = box->y2 - box->y1;
378428d7b3dSmrg
379428d7b3dSmrg		if (w < pixmap->drawable.width ||
380428d7b3dSmrg		    h < pixmap->drawable.height ||
381428d7b3dSmrg		    priv->source_count != SOURCE_BIAS) {
382428d7b3dSmrg			bool want_tiling;
383428d7b3dSmrg
384428d7b3dSmrg			if (priv->cpu_bo->pitch >= 4096) {
385428d7b3dSmrg				DBG(("%s: size=%dx%d, promoting reused (%d) CPU bo due to TLB miss (%dx%d, pitch=%d)\n",
386428d7b3dSmrg				     __FUNCTION__, w, h, priv->source_count,
387428d7b3dSmrg				     pixmap->drawable.width,
388428d7b3dSmrg				     pixmap->drawable.height,
389428d7b3dSmrg				     priv->cpu_bo->pitch));
390428d7b3dSmrg				return NULL;
391428d7b3dSmrg			}
392428d7b3dSmrg
393428d7b3dSmrg			if (priv->gpu_bo)
394428d7b3dSmrg				want_tiling = priv->gpu_bo->tiling != I915_TILING_NONE;
395428d7b3dSmrg			else
396428d7b3dSmrg				want_tiling = kgem_choose_tiling(&sna->kgem,
397428d7b3dSmrg								 I915_TILING_Y,
398428d7b3dSmrg								 pixmap->drawable.width,
399428d7b3dSmrg								 pixmap->drawable.height,
400428d7b3dSmrg								 pixmap->drawable.bitsPerPixel) != I915_TILING_NONE;
401428d7b3dSmrg			if (want_tiling &&
402428d7b3dSmrg			    priv->source_count*w*h >= (int)pixmap->drawable.width * pixmap->drawable.height) {
403428d7b3dSmrg				DBG(("%s: pitch (%d) requires tiling\n",
404428d7b3dSmrg				     __FUNCTION__, priv->cpu_bo->pitch));
405428d7b3dSmrg				return NULL;
406428d7b3dSmrg			}
407428d7b3dSmrg		}
408428d7b3dSmrg	}
409428d7b3dSmrg
410428d7b3dSmrg	if (priv->shm) {
411428d7b3dSmrg		assert(!priv->flush);
412428d7b3dSmrg		sna_add_flush_pixmap(sna, priv, priv->cpu_bo);
413428d7b3dSmrg	}
414428d7b3dSmrg
415428d7b3dSmrg	DBG(("%s for box=(%d, %d), (%d, %d)\n",
416428d7b3dSmrg	     __FUNCTION__, box->x1, box->y1, box->x2, box->y2));
417428d7b3dSmrg	++priv->source_count;
418428d7b3dSmrg	return priv->cpu_bo;
419428d7b3dSmrg}
420428d7b3dSmrg
421428d7b3dSmrgstatic struct kgem_bo *
422428d7b3dSmrgmove_to_gpu(PixmapPtr pixmap, const BoxRec *box, bool blt)
423428d7b3dSmrg{
424428d7b3dSmrg	struct sna_pixmap *priv;
425428d7b3dSmrg	int count, w, h;
426428d7b3dSmrg	bool migrate = false;
427428d7b3dSmrg
428428d7b3dSmrg	if (DBG_FORCE_UPLOAD > 0)
429428d7b3dSmrg		return NULL;
430428d7b3dSmrg
431428d7b3dSmrg	priv = sna_pixmap(pixmap);
432428d7b3dSmrg	if (priv == NULL) {
433428d7b3dSmrg		DBG(("%s: not migrating unattached pixmap=%ld\n",
434428d7b3dSmrg		     __FUNCTION__, pixmap->drawable.serialNumber));
435428d7b3dSmrg		return NULL;
436428d7b3dSmrg	}
437428d7b3dSmrg
438428d7b3dSmrg	if (priv->shm)
439428d7b3dSmrg		blt = true;
440428d7b3dSmrg
441428d7b3dSmrg	if (priv->gpu_bo) {
442428d7b3dSmrg		if (priv->cpu_damage &&
443428d7b3dSmrg		    sna_damage_contains_box(&priv->cpu_damage,
444428d7b3dSmrg					    box) != PIXMAN_REGION_OUT)
445428d7b3dSmrg			goto upload;
446428d7b3dSmrg
447428d7b3dSmrg		return priv->gpu_bo;
448428d7b3dSmrg	}
449428d7b3dSmrg
450428d7b3dSmrg	if (priv->cpu_damage == NULL) {
451428d7b3dSmrg		DBG(("%s: not migrating uninitialised pixmap=%ld\n",
452428d7b3dSmrg		     __FUNCTION__, pixmap->drawable.serialNumber));
453428d7b3dSmrg		return NULL;
454428d7b3dSmrg	}
455428d7b3dSmrg
456428d7b3dSmrg	if (pixmap->usage_hint) {
457428d7b3dSmrg		DBG(("%s: not migrating pixmap=%ld due to usage_hint=%d\n",
458428d7b3dSmrg		     __FUNCTION__,
459428d7b3dSmrg		     pixmap->drawable.serialNumber,
460428d7b3dSmrg		     pixmap->usage_hint));
461428d7b3dSmrg		return NULL;
462428d7b3dSmrg	}
463428d7b3dSmrg
464428d7b3dSmrg	if (DBG_FORCE_UPLOAD < 0) {
465428d7b3dSmrg		if (!sna_pixmap_force_to_gpu(pixmap,
466428d7b3dSmrg					     blt ? MOVE_READ : MOVE_SOURCE_HINT | MOVE_ASYNC_HINT | MOVE_READ))
467428d7b3dSmrg			return NULL;
468428d7b3dSmrg
469428d7b3dSmrg		return priv->gpu_bo;
470428d7b3dSmrg	}
471428d7b3dSmrg
472428d7b3dSmrg	w = box->x2 - box->x1;
473428d7b3dSmrg	h = box->y2 - box->y1;
474428d7b3dSmrg	if (priv->cpu_bo && !priv->cpu_bo->flush) {
475428d7b3dSmrg		migrate = true;
476428d7b3dSmrg	} else if (w == pixmap->drawable.width && h == pixmap->drawable.height) {
477428d7b3dSmrg		migrate = priv->source_count++ > SOURCE_BIAS;
478428d7b3dSmrg
479428d7b3dSmrg		DBG(("%s: migrating whole pixmap (%dx%d) for source (%d,%d),(%d,%d), count %d? %d\n",
480428d7b3dSmrg		     __FUNCTION__,
481428d7b3dSmrg		     pixmap->drawable.width, pixmap->drawable.height,
482428d7b3dSmrg		     box->x1, box->y1, box->x2, box->y2, priv->source_count,
483428d7b3dSmrg		     migrate));
484428d7b3dSmrg	} else if (kgem_choose_tiling(&to_sna_from_pixmap(pixmap)->kgem,
485428d7b3dSmrg				      blt ? I915_TILING_X : I915_TILING_Y, w, h,
486428d7b3dSmrg				      pixmap->drawable.bitsPerPixel) != I915_TILING_NONE) {
487428d7b3dSmrg		count = priv->source_count++;
488428d7b3dSmrg		if ((priv->create & KGEM_CAN_CREATE_GPU) == 0)
489428d7b3dSmrg			count -= SOURCE_BIAS;
490428d7b3dSmrg
491428d7b3dSmrg		DBG(("%s: migrate box (%d, %d), (%d, %d)? source count=%d, fraction=%d/%d [%d]\n",
492428d7b3dSmrg		     __FUNCTION__,
493428d7b3dSmrg		     box->x1, box->y1, box->x2, box->y2,
494428d7b3dSmrg		     count, w*h,
495428d7b3dSmrg		     pixmap->drawable.width * pixmap->drawable.height,
496428d7b3dSmrg		     pixmap->drawable.width * pixmap->drawable.height / (w*h)));
497428d7b3dSmrg
498428d7b3dSmrg		migrate = count*w*h > pixmap->drawable.width * pixmap->drawable.height;
499428d7b3dSmrg	}
500428d7b3dSmrg
501428d7b3dSmrg	if (!migrate)
502428d7b3dSmrg		return NULL;
503428d7b3dSmrg
504428d7b3dSmrgupload:
505428d7b3dSmrg	if (blt) {
506428d7b3dSmrg		if (!sna_pixmap_move_area_to_gpu(pixmap, box,
507428d7b3dSmrg						 __MOVE_FORCE | MOVE_READ))
508428d7b3dSmrg			return NULL;
509428d7b3dSmrg	} else {
510428d7b3dSmrg		if (!sna_pixmap_move_to_gpu(pixmap,
511428d7b3dSmrg					    __MOVE_FORCE | MOVE_ASYNC_HINT | MOVE_SOURCE_HINT | MOVE_READ))
512428d7b3dSmrg			return NULL;
513428d7b3dSmrg	}
514428d7b3dSmrg
515428d7b3dSmrg	return priv->gpu_bo;
516428d7b3dSmrg}
517428d7b3dSmrg
518428d7b3dSmrgstatic struct kgem_bo *upload(struct sna *sna,
519428d7b3dSmrg			      struct sna_composite_channel *channel,
520428d7b3dSmrg			      PixmapPtr pixmap,
521428d7b3dSmrg			      const BoxRec *box)
522428d7b3dSmrg{
523428d7b3dSmrg	struct sna_pixmap *priv;
524428d7b3dSmrg	struct kgem_bo *bo;
525428d7b3dSmrg
526428d7b3dSmrg	DBG(("%s: box=(%d, %d), (%d, %d), pixmap=%dx%d\n",
527428d7b3dSmrg	     __FUNCTION__, box->x1, box->y1, box->x2, box->y2, pixmap->drawable.width, pixmap->drawable.height));
528428d7b3dSmrg	assert(box->x1 >= 0);
529428d7b3dSmrg	assert(box->y1 >= 0);
530428d7b3dSmrg	assert(box->x2 <= pixmap->drawable.width);
531428d7b3dSmrg	assert(box->y2 <= pixmap->drawable.height);
532428d7b3dSmrg
533428d7b3dSmrg	priv = sna_pixmap(pixmap);
534428d7b3dSmrg	if (priv) {
535428d7b3dSmrg		RegionRec region;
536428d7b3dSmrg
537428d7b3dSmrg		if (priv->cpu_damage == NULL)
538428d7b3dSmrg			return NULL; /* uninitialised */
539428d7b3dSmrg
540428d7b3dSmrg		region.extents = *box;
541428d7b3dSmrg		region.data = NULL;
542428d7b3dSmrg		if (!sna_drawable_move_region_to_cpu(&pixmap->drawable,
543428d7b3dSmrg						     &region, MOVE_READ))
544428d7b3dSmrg			return NULL;
545428d7b3dSmrg
546428d7b3dSmrg		assert(!priv->mapped);
547428d7b3dSmrg		if (pixmap->devPrivate.ptr == NULL)
548428d7b3dSmrg			return NULL; /* uninitialised */
549428d7b3dSmrg	}
550428d7b3dSmrg
551428d7b3dSmrg	bo = kgem_upload_source_image(&sna->kgem,
552428d7b3dSmrg				      pixmap->devPrivate.ptr, box,
553428d7b3dSmrg				      pixmap->devKind,
554428d7b3dSmrg				      pixmap->drawable.bitsPerPixel);
555428d7b3dSmrg	if (channel && bo) {
556428d7b3dSmrg		channel->width  = box->x2 - box->x1;
557428d7b3dSmrg		channel->height = box->y2 - box->y1;
558428d7b3dSmrg		channel->offset[0] -= box->x1;
559428d7b3dSmrg		channel->offset[1] -= box->y1;
560428d7b3dSmrg
561428d7b3dSmrg		if (priv &&
562428d7b3dSmrg		    pixmap->usage_hint == 0 &&
563428d7b3dSmrg		    channel->width  == pixmap->drawable.width &&
564428d7b3dSmrg		    channel->height == pixmap->drawable.height) {
565428d7b3dSmrg			DBG(("%s: adding upload cache to pixmap=%ld\n",
566428d7b3dSmrg			     __FUNCTION__, pixmap->drawable.serialNumber));
567428d7b3dSmrg			assert(priv->gpu_damage == NULL);
568428d7b3dSmrg			assert(priv->gpu_bo == NULL);
569428d7b3dSmrg			assert(bo->proxy != NULL);
570428d7b3dSmrg			kgem_proxy_bo_attach(bo, &priv->gpu_bo);
571428d7b3dSmrg		}
572428d7b3dSmrg	}
573428d7b3dSmrg
574428d7b3dSmrg	return bo;
575428d7b3dSmrg}
576428d7b3dSmrg
577428d7b3dSmrgstruct kgem_bo *
578428d7b3dSmrg__sna_render_pixmap_bo(struct sna *sna,
579428d7b3dSmrg		       PixmapPtr pixmap,
580428d7b3dSmrg		       const BoxRec *box,
581428d7b3dSmrg		       bool blt)
582428d7b3dSmrg{
583428d7b3dSmrg	struct kgem_bo *bo;
584428d7b3dSmrg
585428d7b3dSmrg	bo = use_cpu_bo(sna, pixmap, box, blt);
586428d7b3dSmrg	if (bo == NULL) {
587428d7b3dSmrg		bo = move_to_gpu(pixmap, box, blt);
588428d7b3dSmrg		if (bo == NULL)
589428d7b3dSmrg			return NULL;
590428d7b3dSmrg	}
591428d7b3dSmrg
592428d7b3dSmrg	return bo;
593428d7b3dSmrg}
594428d7b3dSmrg
595428d7b3dSmrgint
596428d7b3dSmrgsna_render_pixmap_bo(struct sna *sna,
597428d7b3dSmrg		     struct sna_composite_channel *channel,
598428d7b3dSmrg		     PixmapPtr pixmap,
599428d7b3dSmrg		     int16_t x, int16_t y,
600428d7b3dSmrg		     int16_t w, int16_t h,
601428d7b3dSmrg		     int16_t dst_x, int16_t dst_y)
602428d7b3dSmrg{
603428d7b3dSmrg	struct sna_pixmap *priv;
604428d7b3dSmrg	BoxRec box;
605428d7b3dSmrg
606428d7b3dSmrg	DBG(("%s pixmap=%ld, (%d, %d)x(%d, %d)/(%d, %d)\n",
607428d7b3dSmrg	     __FUNCTION__, pixmap->drawable.serialNumber,
608428d7b3dSmrg	     x, y, w,h, pixmap->drawable.width, pixmap->drawable.height));
609428d7b3dSmrg
610428d7b3dSmrg	channel->width  = pixmap->drawable.width;
611428d7b3dSmrg	channel->height = pixmap->drawable.height;
612428d7b3dSmrg	channel->offset[0] = x - dst_x;
613428d7b3dSmrg	channel->offset[1] = y - dst_y;
614428d7b3dSmrg
615428d7b3dSmrg	priv = sna_pixmap(pixmap);
616428d7b3dSmrg	if (priv) {
617428d7b3dSmrg		if (priv->gpu_bo &&
618428d7b3dSmrg		    (DAMAGE_IS_ALL(priv->gpu_damage) || !priv->cpu_damage ||
619428d7b3dSmrg		     priv->gpu_bo->proxy)) {
620428d7b3dSmrg			DBG(("%s: GPU all damaged\n", __FUNCTION__));
621428d7b3dSmrg			channel->bo = priv->gpu_bo;
622428d7b3dSmrg			goto done;
623428d7b3dSmrg		}
624428d7b3dSmrg
625428d7b3dSmrg		if (priv->cpu_bo &&
626428d7b3dSmrg		    (DAMAGE_IS_ALL(priv->cpu_damage) || !priv->gpu_damage) &&
627428d7b3dSmrg		    !priv->cpu_bo->snoop && priv->cpu_bo->pitch < 4096) {
628428d7b3dSmrg			DBG(("%s: CPU all damaged\n", __FUNCTION__));
629428d7b3dSmrg			channel->bo = priv->cpu_bo;
630428d7b3dSmrg			if (priv->shm) {
631428d7b3dSmrg				assert(!priv->flush);
632428d7b3dSmrg				sna_add_flush_pixmap(sna, priv, priv->cpu_bo);
633428d7b3dSmrg			}
634428d7b3dSmrg			goto done;
635428d7b3dSmrg		}
636428d7b3dSmrg	}
637428d7b3dSmrg
638428d7b3dSmrg	/* XXX handle transformed repeat */
639428d7b3dSmrg	if (w == 0 || h == 0 || channel->transform) {
640428d7b3dSmrg		box.x1 = box.y1 = 0;
641428d7b3dSmrg		box.x2 = pixmap->drawable.width;
642428d7b3dSmrg		box.y2 = pixmap->drawable.height;
643428d7b3dSmrg	} else {
644428d7b3dSmrg		box.x1 = x;
645428d7b3dSmrg		box.y1 = y;
646428d7b3dSmrg		box.x2 = bound(x, w);
647428d7b3dSmrg		box.y2 = bound(y, h);
648428d7b3dSmrg
649428d7b3dSmrg		if (channel->repeat == RepeatNone || channel->repeat == RepeatPad) {
650428d7b3dSmrg			if (box.x1 < 0)
651428d7b3dSmrg				box.x1 = 0;
652428d7b3dSmrg			if (box.y1 < 0)
653428d7b3dSmrg				box.y1 = 0;
654428d7b3dSmrg			if (box.x2 > pixmap->drawable.width)
655428d7b3dSmrg				box.x2 = pixmap->drawable.width;
656428d7b3dSmrg			if (box.y2 > pixmap->drawable.height)
657428d7b3dSmrg				box.y2 = pixmap->drawable.height;
658428d7b3dSmrg		} else {
659428d7b3dSmrg			if (box.x1 < 0 || box.x2 > pixmap->drawable.width)
660428d7b3dSmrg				box.x1 = 0, box.x2 = pixmap->drawable.width;
661428d7b3dSmrg			if (box.y1 < 0 || box.y2 > pixmap->drawable.height)
662428d7b3dSmrg				box.y1 = 0, box.y2 = pixmap->drawable.height;
663428d7b3dSmrg		}
664428d7b3dSmrg	}
665428d7b3dSmrg
666428d7b3dSmrg	w = box.x2 - box.x1;
667428d7b3dSmrg	h = box.y2 - box.y1;
668428d7b3dSmrg	DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d)\n", __FUNCTION__,
669428d7b3dSmrg	     box.x1, box.y1, box.x2, box.y2, w, h,
670428d7b3dSmrg	     pixmap->drawable.width, pixmap->drawable.height));
671428d7b3dSmrg	if (w <= 0 || h <= 0) {
672428d7b3dSmrg		DBG(("%s: sample extents outside of texture -> clear\n",
673428d7b3dSmrg		     __FUNCTION__));
674428d7b3dSmrg		return 0;
675428d7b3dSmrg	}
676428d7b3dSmrg
677428d7b3dSmrg	DBG(("%s: offset=(%d, %d), size=(%d, %d)\n",
678428d7b3dSmrg	     __FUNCTION__,
679428d7b3dSmrg	     channel->offset[0], channel->offset[1],
680428d7b3dSmrg	     pixmap->drawable.width, pixmap->drawable.height));
681428d7b3dSmrg
682428d7b3dSmrg	channel->bo = __sna_render_pixmap_bo(sna, pixmap, &box, false);
683428d7b3dSmrg	if (channel->bo == NULL) {
684428d7b3dSmrg		DBG(("%s: uploading CPU box (%d, %d), (%d, %d)\n",
685428d7b3dSmrg		     __FUNCTION__, box.x1, box.y1, box.x2, box.y2));
686428d7b3dSmrg		channel->bo = upload(sna, channel, pixmap, &box);
687428d7b3dSmrg		if (channel->bo == NULL)
688428d7b3dSmrg			return 0;
689428d7b3dSmrg	} else {
690428d7b3dSmrgdone:
691428d7b3dSmrg		kgem_bo_reference(channel->bo);
692428d7b3dSmrg	}
693428d7b3dSmrg
694428d7b3dSmrg	channel->scale[0] = 1.f / channel->width;
695428d7b3dSmrg	channel->scale[1] = 1.f / channel->height;
696428d7b3dSmrg	return 1;
697428d7b3dSmrg}
698428d7b3dSmrg
699428d7b3dSmrgstatic int sna_render_picture_downsample(struct sna *sna,
700428d7b3dSmrg					 PicturePtr picture,
701428d7b3dSmrg					 struct sna_composite_channel *channel,
702428d7b3dSmrg					 const int16_t x, const int16_t y,
703428d7b3dSmrg					 const int16_t w, const int16_t h,
704428d7b3dSmrg					 const int16_t dst_x, const int16_t dst_y)
705428d7b3dSmrg{
706428d7b3dSmrg	PixmapPtr pixmap = get_drawable_pixmap(picture->pDrawable);
707428d7b3dSmrg	ScreenPtr screen = pixmap->drawable.pScreen;
708428d7b3dSmrg	PicturePtr tmp_src, tmp_dst;
709428d7b3dSmrg	PictFormatPtr format;
710428d7b3dSmrg	struct sna_pixmap *priv;
711428d7b3dSmrg	pixman_transform_t t;
712428d7b3dSmrg	PixmapPtr tmp;
713428d7b3dSmrg	int width, height, size, max_size;
714428d7b3dSmrg	int sx, sy, sw, sh;
715428d7b3dSmrg	int error, ret = 0;
716428d7b3dSmrg	BoxRec box, b;
717428d7b3dSmrg
718428d7b3dSmrg	box.x1 = x;
719428d7b3dSmrg	box.y1 = y;
720428d7b3dSmrg	box.x2 = bound(x, w);
721428d7b3dSmrg	box.y2 = bound(y, h);
722428d7b3dSmrg	if (channel->transform) {
723428d7b3dSmrg		pixman_vector_t v;
724428d7b3dSmrg
725428d7b3dSmrg		pixman_transform_bounds(channel->transform, &box);
726428d7b3dSmrg
727428d7b3dSmrg		v.vector[0] = x << 16;
728428d7b3dSmrg		v.vector[1] = y << 16;
729428d7b3dSmrg		v.vector[2] = 1 << 16;
730428d7b3dSmrg		pixman_transform_point(channel->transform, &v);
731428d7b3dSmrg	}
732428d7b3dSmrg
733428d7b3dSmrg	if (channel->repeat == RepeatNone || channel->repeat == RepeatPad) {
734428d7b3dSmrg		if (box.x1 < 0)
735428d7b3dSmrg			box.x1 = 0;
736428d7b3dSmrg		if (box.y1 < 0)
737428d7b3dSmrg			box.y1 = 0;
738428d7b3dSmrg		if (box.x2 > pixmap->drawable.width)
739428d7b3dSmrg			box.x2 = pixmap->drawable.width;
740428d7b3dSmrg		if (box.y2 > pixmap->drawable.height)
741428d7b3dSmrg			box.y2 = pixmap->drawable.height;
742428d7b3dSmrg	} else {
743428d7b3dSmrg		/* XXX tiled repeats? */
744428d7b3dSmrg		if (box.x1 < 0 || box.x2 > pixmap->drawable.width)
745428d7b3dSmrg			box.x1 = 0, box.x2 = pixmap->drawable.width;
746428d7b3dSmrg		if (box.y1 < 0 || box.y2 > pixmap->drawable.height)
747428d7b3dSmrg			box.y1 = 0, box.y2 = pixmap->drawable.height;
748428d7b3dSmrg
749428d7b3dSmrg	}
750428d7b3dSmrg
751428d7b3dSmrg	sw = box.x2 - box.x1;
752428d7b3dSmrg	sh = box.y2 - box.y1;
753428d7b3dSmrg
754428d7b3dSmrg	DBG(("%s: sample (%d, %d), (%d, %d)\n",
755428d7b3dSmrg	     __FUNCTION__, box.x1, box.y1, box.x2, box.y2));
756428d7b3dSmrg
757428d7b3dSmrg	sx = (sw + sna->render.max_3d_size - 1) / sna->render.max_3d_size;
758428d7b3dSmrg	sy = (sh + sna->render.max_3d_size - 1) / sna->render.max_3d_size;
759428d7b3dSmrg
760428d7b3dSmrg	DBG(("%s: scaling (%d, %d) down by %dx%d\n",
761428d7b3dSmrg	     __FUNCTION__, sw, sh, sx, sy));
762428d7b3dSmrg
763428d7b3dSmrg	width  = sw / sx;
764428d7b3dSmrg	height = sh / sy;
765428d7b3dSmrg
766428d7b3dSmrg	DBG(("%s: creating temporary GPU bo %dx%d\n",
767428d7b3dSmrg	     __FUNCTION__, width, height));
768428d7b3dSmrg
769428d7b3dSmrg	tmp = screen->CreatePixmap(screen,
770428d7b3dSmrg				   width, height,
771428d7b3dSmrg				   pixmap->drawable.depth,
772428d7b3dSmrg				   SNA_CREATE_SCRATCH);
773428d7b3dSmrg	if (tmp == NULL)
774428d7b3dSmrg		goto fixup;
775428d7b3dSmrg
776428d7b3dSmrg	priv = sna_pixmap(tmp);
777428d7b3dSmrg	assert(priv && priv->gpu_bo);
778428d7b3dSmrg
779428d7b3dSmrg	if (!sna_pixmap_move_to_gpu(pixmap, MOVE_ASYNC_HINT | MOVE_SOURCE_HINT | MOVE_READ)) {
780428d7b3dSmrgfixup:
781428d7b3dSmrg		DBG(("%s: unable to create GPU bo for target or temporary pixmaps\n",
782428d7b3dSmrg		     __FUNCTION__));
783428d7b3dSmrg		return sna_render_picture_fixup(sna, picture, channel,
784428d7b3dSmrg						x, y, w, h,
785428d7b3dSmrg						dst_x, dst_y);
786428d7b3dSmrg	}
787428d7b3dSmrg
788428d7b3dSmrg	format = PictureMatchFormat(screen,
789428d7b3dSmrg				    pixmap->drawable.depth,
790428d7b3dSmrg				    picture->format);
791428d7b3dSmrg	if (format == NULL) {
792428d7b3dSmrg		DBG(("%s: invalid depth=%d, format=%08x\n",
793428d7b3dSmrg		     __FUNCTION__, pixmap->drawable.depth, picture->format));
794428d7b3dSmrg		goto fixup;
795428d7b3dSmrg	}
796428d7b3dSmrg
797428d7b3dSmrg	tmp_dst = CreatePicture(0, &tmp->drawable, format, 0, NULL,
798428d7b3dSmrg				serverClient, &error);
799428d7b3dSmrg	if (!tmp_dst)
800428d7b3dSmrg		goto cleanup_tmp;
801428d7b3dSmrg
802428d7b3dSmrg	tmp_src = CreatePicture(0, &pixmap->drawable, format, 0, NULL,
803428d7b3dSmrg				serverClient, &error);
804428d7b3dSmrg	if (!tmp_src)
805428d7b3dSmrg		goto cleanup_dst;
806428d7b3dSmrg
807428d7b3dSmrg	tmp_src->repeat = 1;
808428d7b3dSmrg	tmp_src->repeatType = RepeatPad;
809428d7b3dSmrg	/* Prefer to use nearest as it helps reduce artefacts from
810428d7b3dSmrg	 * interpolating and filtering twice.
811428d7b3dSmrg	 */
812428d7b3dSmrg	tmp_src->filter = PictFilterNearest;
813428d7b3dSmrg	memset(&t, 0, sizeof(t));
814428d7b3dSmrg	t.matrix[0][0] = (sw << 16) / width;
815428d7b3dSmrg	t.matrix[0][2] = box.x1 << 16;
816428d7b3dSmrg	t.matrix[1][1] = (sh << 16) / height;
817428d7b3dSmrg	t.matrix[1][2] = box.y1 << 16;
818428d7b3dSmrg	t.matrix[2][2] = 1 << 16;
819428d7b3dSmrg	tmp_src->transform = &t;
820428d7b3dSmrg
821428d7b3dSmrg	ValidatePicture(tmp_dst);
822428d7b3dSmrg	ValidatePicture(tmp_src);
823428d7b3dSmrg
824428d7b3dSmrg	/* Use a small size to accommodate enlargement through tile alignment */
825428d7b3dSmrg	max_size = sna_max_tile_copy_size(sna, sna_pixmap(pixmap)->gpu_bo, priv->gpu_bo);
826428d7b3dSmrg	if (max_size == 0)
827428d7b3dSmrg		goto cleanup_dst;
828428d7b3dSmrg
829428d7b3dSmrg	size = sna->render.max_3d_size - 4096 / pixmap->drawable.bitsPerPixel;
830428d7b3dSmrg	while (size * size * 4 > max_size)
831428d7b3dSmrg		size /= 2;
832428d7b3dSmrg	DBG(("%s: size=%d (max=%d), scale %dx%d\n",
833428d7b3dSmrg	     __FUNCTION__, size, max_size, sx, sy));
834428d7b3dSmrg
835428d7b3dSmrg	sw = size / sx - 2 * sx;
836428d7b3dSmrg	if (sw < 1)
837428d7b3dSmrg		sw = 1;
838428d7b3dSmrg	sh = size / sy - 2 * sy;
839428d7b3dSmrg	if (sh < 1)
840428d7b3dSmrg		sh = 1;
841428d7b3dSmrg	DBG(("%s %d:%d downsampling using %dx%d GPU tiles\n",
842428d7b3dSmrg	     __FUNCTION__, (width + sw-1)/sw, (height + sh-1)/sh, sw, sh));
843428d7b3dSmrg
844428d7b3dSmrg	for (b.y1 = 0; b.y1 < height; b.y1 = b.y2) {
845428d7b3dSmrg		b.y2 = b.y1 + sh;
846428d7b3dSmrg		if (b.y2 > height)
847428d7b3dSmrg			b.y2 = height;
848428d7b3dSmrg
849428d7b3dSmrg		for (b.x1 = 0; b.x1 < width; b.x1 = b.x2) {
850428d7b3dSmrg			struct sna_composite_op op;
851428d7b3dSmrg
852428d7b3dSmrg			b.x2 = b.x1 + sw;
853428d7b3dSmrg			if (b.x2 > width)
854428d7b3dSmrg				b.x2 = width;
855428d7b3dSmrg
856428d7b3dSmrg			DBG(("%s: tile (%d, %d), (%d, %d)\n",
857428d7b3dSmrg			     __FUNCTION__, b.x1, b.y1, b.x2, b.y2));
858428d7b3dSmrg
859428d7b3dSmrg			memset(&op, 0, sizeof(op));
860428d7b3dSmrg			if (!sna->render.composite(sna,
861428d7b3dSmrg						   PictOpSrc,
862428d7b3dSmrg						   tmp_src, NULL, tmp_dst,
863428d7b3dSmrg						   b.x1, b.y1,
864428d7b3dSmrg						   0, 0,
865428d7b3dSmrg						   b.x1, b.y1,
866428d7b3dSmrg						   b.x2 - b.x1, b.y2 - b.y1,
867428d7b3dSmrg						   0, &op))
868428d7b3dSmrg				goto cleanup_src;
869428d7b3dSmrg
870428d7b3dSmrg			op.box(sna, &op, &b);
871428d7b3dSmrg			op.done(sna, &op);
872428d7b3dSmrg		}
873428d7b3dSmrg	}
874428d7b3dSmrg
875428d7b3dSmrg	pixman_transform_invert(&channel->embedded_transform, &t);
876428d7b3dSmrg	if (channel->transform)
877428d7b3dSmrg		pixman_transform_multiply(&channel->embedded_transform,
878428d7b3dSmrg					  &channel->embedded_transform,
879428d7b3dSmrg					  channel->transform);
880428d7b3dSmrg	channel->transform = &channel->embedded_transform;
881428d7b3dSmrg
882428d7b3dSmrg	channel->offset[0] = x - dst_x;
883428d7b3dSmrg	channel->offset[1] = y - dst_y;
884428d7b3dSmrg	channel->scale[0] = 1.f/width;
885428d7b3dSmrg	channel->scale[1] = 1.f/height;
886428d7b3dSmrg	channel->width  = width;
887428d7b3dSmrg	channel->height = height;
888428d7b3dSmrg	channel->bo = kgem_bo_reference(priv->gpu_bo);
889428d7b3dSmrg
890428d7b3dSmrg	ret = 1;
891428d7b3dSmrgcleanup_src:
892428d7b3dSmrg	tmp_src->transform = NULL;
893428d7b3dSmrg	FreePicture(tmp_src, 0);
894428d7b3dSmrgcleanup_dst:
895428d7b3dSmrg	FreePicture(tmp_dst, 0);
896428d7b3dSmrgcleanup_tmp:
897428d7b3dSmrg	screen->DestroyPixmap(tmp);
898428d7b3dSmrg	return ret;
899428d7b3dSmrg}
900428d7b3dSmrg
901428d7b3dSmrgbool
902428d7b3dSmrgsna_render_pixmap_partial(struct sna *sna,
903428d7b3dSmrg			  const DrawableRec *draw,
904428d7b3dSmrg			  struct kgem_bo *bo,
905428d7b3dSmrg			  struct sna_composite_channel *channel,
906428d7b3dSmrg			  int16_t x, int16_t y,
907428d7b3dSmrg			  int16_t w, int16_t h)
908428d7b3dSmrg{
909428d7b3dSmrg	BoxRec box;
910428d7b3dSmrg	int offset;
911428d7b3dSmrg
912428d7b3dSmrg	DBG(("%s (%d, %d)x(%d, %d), pitch %d, max %d\n",
913428d7b3dSmrg	     __FUNCTION__, x, y, w, h, bo->pitch, sna->render.max_3d_pitch));
914428d7b3dSmrg
915428d7b3dSmrg	if (bo->pitch > sna->render.max_3d_pitch) {
916428d7b3dSmrg		DBG(("%s: pitch too great %d > %d\n", __FUNCTION__, bo->pitch, sna->render.max_3d_pitch));
917428d7b3dSmrg		return false;
918428d7b3dSmrg	}
919428d7b3dSmrg
920428d7b3dSmrg	box.x1 = x;
921428d7b3dSmrg	box.y1 = y;
922428d7b3dSmrg	box.x2 = bound(x, w);
923428d7b3dSmrg	box.y2 = bound(y, h);
924428d7b3dSmrg	DBG(("%s: unaligned box (%d, %d), (%d, %d)\n",
925428d7b3dSmrg	     __FUNCTION__, box.x1, box.y1, box.x2, box.y2));
926428d7b3dSmrg
927428d7b3dSmrg	if (box.x1 < 0)
928428d7b3dSmrg		box.x1 = 0;
929428d7b3dSmrg	if (box.y1 < 0)
930428d7b3dSmrg		box.y1 = 0;
931428d7b3dSmrg
932428d7b3dSmrg	if (bo->tiling) {
933428d7b3dSmrg		int tile_width, tile_height, tile_size;
934428d7b3dSmrg
935428d7b3dSmrg		kgem_get_tile_size(&sna->kgem, bo->tiling, bo->pitch,
936428d7b3dSmrg				   &tile_width, &tile_height, &tile_size);
937428d7b3dSmrg		DBG(("%s: tile size for tiling %d: %dx%d, size=%d\n",
938428d7b3dSmrg		     __FUNCTION__, bo->tiling, tile_width, tile_height, tile_size));
939428d7b3dSmrg
940428d7b3dSmrg		/* Ensure we align to an even tile row */
941428d7b3dSmrg		box.y1 = box.y1 & ~(2*tile_height - 1);
942428d7b3dSmrg		box.y2 = ALIGN(box.y2, 2*tile_height);
943428d7b3dSmrg
944428d7b3dSmrg		assert(tile_width * 8 >= draw->bitsPerPixel);
945428d7b3dSmrg		box.x1 = box.x1 & ~(tile_width * 8 / draw->bitsPerPixel - 1);
946428d7b3dSmrg		box.x2 = ALIGN(box.x2, tile_width * 8 / draw->bitsPerPixel);
947428d7b3dSmrg
948428d7b3dSmrg		offset = box.x1 * draw->bitsPerPixel / 8 / tile_width * tile_size;
949428d7b3dSmrg	} else {
950428d7b3dSmrg		box.y1 = box.y1 & ~1;
951428d7b3dSmrg		box.y2 = ALIGN(box.y2, 2);
952428d7b3dSmrg
953428d7b3dSmrg		box.x1 = box.x1 & ~1;
954428d7b3dSmrg		box.x2 = ALIGN(box.x2, 2);
955428d7b3dSmrg
956428d7b3dSmrg		offset = box.x1 * draw->bitsPerPixel / 8;
957428d7b3dSmrg	}
958428d7b3dSmrg
959428d7b3dSmrg	if (box.x2 > draw->width)
960428d7b3dSmrg		box.x2 = draw->width;
961428d7b3dSmrg	if (box.y2 > draw->height)
962428d7b3dSmrg		box.y2 = draw->height;
963428d7b3dSmrg
964428d7b3dSmrg	w = box.x2 - box.x1;
965428d7b3dSmrg	h = box.y2 - box.y1;
966428d7b3dSmrg	DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d)\n", __FUNCTION__,
967428d7b3dSmrg	     box.x1, box.y1, box.x2, box.y2, w, h,
968428d7b3dSmrg	     draw->width, draw->height));
969428d7b3dSmrg	if (w <= 0 || h <= 0 ||
970428d7b3dSmrg	    w > sna->render.max_3d_size ||
971428d7b3dSmrg	    h > sna->render.max_3d_size) {
972428d7b3dSmrg		DBG(("%s: box too large (%dx%d) for 3D pipeline (max %d)\n",
973428d7b3dSmrg		    __FUNCTION__, w, h, sna->render.max_3d_size));
974428d7b3dSmrg		return false;
975428d7b3dSmrg	}
976428d7b3dSmrg
977428d7b3dSmrg	/* How many tiles across are we? */
978428d7b3dSmrg	channel->bo = kgem_create_proxy(&sna->kgem, bo,
979428d7b3dSmrg					box.y1 * bo->pitch + offset,
980428d7b3dSmrg					h * bo->pitch);
981428d7b3dSmrg	if (channel->bo == NULL) {
982428d7b3dSmrg		DBG(("%s: failed to create proxy for partial (offset=%d, size=%d)\n",
983428d7b3dSmrg		     __FUNCTION__, box.y1 * bo->pitch + offset, h * bo->pitch));
984428d7b3dSmrg		return false;
985428d7b3dSmrg	}
986428d7b3dSmrg
987428d7b3dSmrg	channel->bo->pitch = bo->pitch;
988428d7b3dSmrg
989428d7b3dSmrg	channel->offset[0] = -box.x1;
990428d7b3dSmrg	channel->offset[1] = -box.y1;
991428d7b3dSmrg	channel->scale[0] = 1.f/w;
992428d7b3dSmrg	channel->scale[1] = 1.f/h;
993428d7b3dSmrg	channel->width  = w;
994428d7b3dSmrg	channel->height = h;
995428d7b3dSmrg	return true;
996428d7b3dSmrg}
997428d7b3dSmrg
998428d7b3dSmrgstatic bool
999428d7b3dSmrgsna_render_picture_partial(struct sna *sna,
1000428d7b3dSmrg			   PicturePtr picture,
1001428d7b3dSmrg			   struct sna_composite_channel *channel,
1002428d7b3dSmrg			   int16_t x, int16_t y,
1003428d7b3dSmrg			   int16_t w, int16_t h,
1004428d7b3dSmrg			   int16_t dst_x, int16_t dst_y)
1005428d7b3dSmrg{
1006428d7b3dSmrg	struct kgem_bo *bo = NULL;
1007428d7b3dSmrg	PixmapPtr pixmap = get_drawable_pixmap(picture->pDrawable);
1008428d7b3dSmrg	BoxRec box;
1009428d7b3dSmrg	int offset;
1010428d7b3dSmrg
1011428d7b3dSmrg	DBG(("%s (%d, %d)x(%d, %d) [dst=(%d, %d)]\n",
1012428d7b3dSmrg	     __FUNCTION__, x, y, w, h, dst_x, dst_y));
1013428d7b3dSmrg
1014428d7b3dSmrg	box.x1 = x;
1015428d7b3dSmrg	box.y1 = y;
1016428d7b3dSmrg	box.x2 = bound(x, w);
1017428d7b3dSmrg	box.y2 = bound(y, h);
1018428d7b3dSmrg	if (channel->transform)
1019428d7b3dSmrg		pixman_transform_bounds(channel->transform, &box);
1020428d7b3dSmrg
1021428d7b3dSmrg	DBG(("%s sample=(%d, %d), (%d, %d): (%d, %d)/(%d, %d), repeat=%d\n", __FUNCTION__,
1022428d7b3dSmrg	     box.x1, box.y1, box.x2, box.y2, w, h,
1023428d7b3dSmrg	     pixmap->drawable.width, pixmap->drawable.height,
1024428d7b3dSmrg	     channel->repeat));
1025428d7b3dSmrg
1026428d7b3dSmrg	if (channel->repeat == RepeatNone || channel->repeat == RepeatPad) {
1027428d7b3dSmrg		if (box.x1 < 0)
1028428d7b3dSmrg			box.x1 = 0;
1029428d7b3dSmrg		if (box.y1 < 0)
1030428d7b3dSmrg			box.y1 = 0;
1031428d7b3dSmrg		if (box.x2 > pixmap->drawable.width)
1032428d7b3dSmrg			box.x2 = pixmap->drawable.width;
1033428d7b3dSmrg		if (box.y2 > pixmap->drawable.height)
1034428d7b3dSmrg			box.y2 = pixmap->drawable.height;
1035428d7b3dSmrg	} else {
1036428d7b3dSmrg		if (box.x1 < 0 || box.x2 > pixmap->drawable.width)
1037428d7b3dSmrg			box.x1 = 0, box.x2 = pixmap->drawable.width;
1038428d7b3dSmrg		if (box.y1 < 0 || box.y2 > pixmap->drawable.height)
1039428d7b3dSmrg			box.y1 = 0, box.y2 = pixmap->drawable.height;
1040428d7b3dSmrg	}
1041428d7b3dSmrg
1042428d7b3dSmrg	if (use_cpu_bo(sna, pixmap, &box, false)) {
1043428d7b3dSmrg		bo = sna_pixmap(pixmap)->cpu_bo;
1044428d7b3dSmrg	} else {
1045428d7b3dSmrg		struct sna_pixmap *priv;
1046428d7b3dSmrg
1047428d7b3dSmrg		priv = sna_pixmap_force_to_gpu(pixmap,
1048428d7b3dSmrg					       MOVE_READ | MOVE_ASYNC_HINT | MOVE_SOURCE_HINT);
1049428d7b3dSmrg		if (priv == NULL)
1050428d7b3dSmrg			return false;
1051428d7b3dSmrg
1052428d7b3dSmrg		bo = priv->gpu_bo;
1053428d7b3dSmrg	}
1054428d7b3dSmrg
1055428d7b3dSmrg	if (bo->pitch > sna->render.max_3d_pitch) {
1056428d7b3dSmrg		DBG(("%s: pitch too great %d > %d\n", __FUNCTION__, bo->pitch, sna->render.max_3d_pitch));
1057428d7b3dSmrg		return false;
1058428d7b3dSmrg	}
1059428d7b3dSmrg
1060428d7b3dSmrg	if (bo->tiling) {
1061428d7b3dSmrg		int tile_width, tile_height, tile_size;
1062428d7b3dSmrg
1063428d7b3dSmrg		kgem_get_tile_size(&sna->kgem, bo->tiling, bo->pitch,
1064428d7b3dSmrg				   &tile_width, &tile_height, &tile_size);
1065428d7b3dSmrg
1066428d7b3dSmrg		DBG(("%s: tiling=%d, size=%dx%d, chunk=%d\n",
1067428d7b3dSmrg		     __FUNCTION__, bo->tiling,
1068428d7b3dSmrg		     tile_width, tile_height, tile_size));
1069428d7b3dSmrg
1070428d7b3dSmrg		/* Ensure we align to an even tile row */
1071428d7b3dSmrg		box.y1 = box.y1 & ~(2*tile_height - 1);
1072428d7b3dSmrg		box.y2 = ALIGN(box.y2, 2*tile_height);
1073428d7b3dSmrg		if (box.y2 > pixmap->drawable.height)
1074428d7b3dSmrg			box.y2 = pixmap->drawable.height;
1075428d7b3dSmrg
1076428d7b3dSmrg		box.x1 = box.x1 & ~(tile_width * 8 / pixmap->drawable.bitsPerPixel - 1);
1077428d7b3dSmrg		box.x2 = ALIGN(box.x2, tile_width * 8 / pixmap->drawable.bitsPerPixel);
1078428d7b3dSmrg		if (box.x2 > pixmap->drawable.width)
1079428d7b3dSmrg			box.x2 = pixmap->drawable.width;
1080428d7b3dSmrg
1081428d7b3dSmrg		offset = box.x1 * pixmap->drawable.bitsPerPixel / 8 / tile_width * tile_size;
1082428d7b3dSmrg	} else
1083428d7b3dSmrg		offset = box.x1 * pixmap->drawable.bitsPerPixel / 8;
1084428d7b3dSmrg
1085428d7b3dSmrg	w = box.x2 - box.x1;
1086428d7b3dSmrg	h = box.y2 - box.y1;
1087428d7b3dSmrg	DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d)\n", __FUNCTION__,
1088428d7b3dSmrg	     box.x1, box.y1, box.x2, box.y2, w, h,
1089428d7b3dSmrg	     pixmap->drawable.width, pixmap->drawable.height));
1090428d7b3dSmrg	if (w <= 0 || h <= 0 ||
1091428d7b3dSmrg	    w > sna->render.max_3d_size ||
1092428d7b3dSmrg	    h > sna->render.max_3d_size)
1093428d7b3dSmrg		return false;
1094428d7b3dSmrg
1095428d7b3dSmrg	/* How many tiles across are we? */
1096428d7b3dSmrg	channel->bo = kgem_create_proxy(&sna->kgem, bo,
1097428d7b3dSmrg					box.y1 * bo->pitch + offset,
1098428d7b3dSmrg					h * bo->pitch);
1099428d7b3dSmrg	if (channel->bo == NULL)
1100428d7b3dSmrg		return false;
1101428d7b3dSmrg
1102428d7b3dSmrg	if (channel->transform) {
1103428d7b3dSmrg		memset(&channel->embedded_transform,
1104428d7b3dSmrg		       0,
1105428d7b3dSmrg		       sizeof(channel->embedded_transform));
1106428d7b3dSmrg		channel->embedded_transform.matrix[0][0] = 1 << 16;
1107428d7b3dSmrg		channel->embedded_transform.matrix[0][2] = -box.x1 << 16;
1108428d7b3dSmrg		channel->embedded_transform.matrix[1][1] = 1 << 16;
1109428d7b3dSmrg		channel->embedded_transform.matrix[1][2] = -box.y1 << 16;
1110428d7b3dSmrg		channel->embedded_transform.matrix[2][2] = 1 << 16;
1111428d7b3dSmrg		pixman_transform_multiply(&channel->embedded_transform,
1112428d7b3dSmrg					  &channel->embedded_transform,
1113428d7b3dSmrg					  channel->transform);
1114428d7b3dSmrg		channel->transform = &channel->embedded_transform;
1115428d7b3dSmrg	} else {
1116428d7b3dSmrg		x -= box.x1;
1117428d7b3dSmrg		y -= box.y1;
1118428d7b3dSmrg	}
1119428d7b3dSmrg
1120428d7b3dSmrg	channel->offset[0] = x - dst_x;
1121428d7b3dSmrg	channel->offset[1] = y - dst_y;
1122428d7b3dSmrg	channel->scale[0] = 1.f/w;
1123428d7b3dSmrg	channel->scale[1] = 1.f/h;
1124428d7b3dSmrg	channel->width  = w;
1125428d7b3dSmrg	channel->height = h;
1126428d7b3dSmrg	return true;
1127428d7b3dSmrg}
1128428d7b3dSmrg
1129428d7b3dSmrgint
1130428d7b3dSmrgsna_render_picture_extract(struct sna *sna,
1131428d7b3dSmrg			   PicturePtr picture,
1132428d7b3dSmrg			   struct sna_composite_channel *channel,
1133428d7b3dSmrg			   int16_t x, int16_t y,
1134428d7b3dSmrg			   int16_t w, int16_t h,
1135428d7b3dSmrg			   int16_t dst_x, int16_t dst_y)
1136428d7b3dSmrg{
1137428d7b3dSmrg	struct kgem_bo *bo = NULL, *src_bo;
1138428d7b3dSmrg	PixmapPtr pixmap = get_drawable_pixmap(picture->pDrawable);
1139428d7b3dSmrg	int16_t ox, oy, ow, oh;
1140428d7b3dSmrg	BoxRec box;
1141428d7b3dSmrg
1142428d7b3dSmrg#if NO_EXTRACT
1143428d7b3dSmrg	return -1;
1144428d7b3dSmrg#endif
1145428d7b3dSmrg
1146428d7b3dSmrg	DBG(("%s (%d, %d)x(%d, %d) [dst=(%d, %d)]\n",
1147428d7b3dSmrg	     __FUNCTION__, x, y, w, h, dst_x, dst_y));
1148428d7b3dSmrg
1149428d7b3dSmrg	if (w == 0 || h == 0) {
1150428d7b3dSmrg		DBG(("%s: fallback -- unknown bounds\n", __FUNCTION__));
1151428d7b3dSmrg		return -1;
1152428d7b3dSmrg	}
1153428d7b3dSmrg
1154428d7b3dSmrg	if (sna_render_picture_partial(sna, picture, channel,
1155428d7b3dSmrg				       x, y, w, h,
1156428d7b3dSmrg				       dst_x, dst_y))
1157428d7b3dSmrg		return 1;
1158428d7b3dSmrg
1159428d7b3dSmrg	ow = w;
1160428d7b3dSmrg	oh = h;
1161428d7b3dSmrg
1162428d7b3dSmrg	ox = box.x1 = x;
1163428d7b3dSmrg	oy = box.y1 = y;
1164428d7b3dSmrg	box.x2 = bound(x, w);
1165428d7b3dSmrg	box.y2 = bound(y, h);
1166428d7b3dSmrg	if (channel->transform) {
1167428d7b3dSmrg		pixman_vector_t v;
1168428d7b3dSmrg
1169428d7b3dSmrg		pixman_transform_bounds(channel->transform, &box);
1170428d7b3dSmrg
1171428d7b3dSmrg		v.vector[0] = ox << 16;
1172428d7b3dSmrg		v.vector[1] = oy << 16;
1173428d7b3dSmrg		v.vector[2] =  1 << 16;
1174428d7b3dSmrg		pixman_transform_point(channel->transform, &v);
1175428d7b3dSmrg		ox = v.vector[0] / v.vector[2];
1176428d7b3dSmrg		oy = v.vector[1] / v.vector[2];
1177428d7b3dSmrg	}
1178428d7b3dSmrg
1179428d7b3dSmrg	DBG(("%s sample=(%d, %d), (%d, %d): (%d, %d)/(%d, %d), repeat=%d\n", __FUNCTION__,
1180428d7b3dSmrg	     box.x1, box.y1, box.x2, box.y2, w, h,
1181428d7b3dSmrg	     pixmap->drawable.width, pixmap->drawable.height,
1182428d7b3dSmrg	     channel->repeat));
1183428d7b3dSmrg
1184428d7b3dSmrg	if (channel->repeat == RepeatNone || channel->repeat == RepeatPad) {
1185428d7b3dSmrg		if (box.x1 < 0)
1186428d7b3dSmrg			box.x1 = 0;
1187428d7b3dSmrg		if (box.y1 < 0)
1188428d7b3dSmrg			box.y1 = 0;
1189428d7b3dSmrg		if (box.x2 > pixmap->drawable.width)
1190428d7b3dSmrg			box.x2 = pixmap->drawable.width;
1191428d7b3dSmrg		if (box.y2 > pixmap->drawable.height)
1192428d7b3dSmrg			box.y2 = pixmap->drawable.height;
1193428d7b3dSmrg	} else {
1194428d7b3dSmrg		/* XXX tiled repeats? */
1195428d7b3dSmrg		if (box.x1 < 0 || box.x2 > pixmap->drawable.width)
1196428d7b3dSmrg			box.x1 = 0, box.x2 = pixmap->drawable.width;
1197428d7b3dSmrg		if (box.y1 < 0 || box.y2 > pixmap->drawable.height)
1198428d7b3dSmrg			box.y1 = 0, box.y2 = pixmap->drawable.height;
1199428d7b3dSmrg	}
1200428d7b3dSmrg
1201428d7b3dSmrg	w = box.x2 - box.x1;
1202428d7b3dSmrg	h = box.y2 - box.y1;
1203428d7b3dSmrg	DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d)\n", __FUNCTION__,
1204428d7b3dSmrg	     box.x1, box.y1, box.x2, box.y2, w, h,
1205428d7b3dSmrg	     pixmap->drawable.width, pixmap->drawable.height));
1206428d7b3dSmrg	if (w <= 0 || h <= 0) {
1207428d7b3dSmrg		DBG(("%s: sample extents outside of texture -> clear\n",
1208428d7b3dSmrg		     __FUNCTION__));
1209428d7b3dSmrg		return 0;
1210428d7b3dSmrg	}
1211428d7b3dSmrg
1212428d7b3dSmrg	if (w > sna->render.max_3d_size || h > sna->render.max_3d_size) {
1213428d7b3dSmrg		DBG(("%s: fallback -- sample too large for texture (%d, %d)x(%d, %d)\n",
1214428d7b3dSmrg		     __FUNCTION__, box.x1, box.y1, w, h));
1215428d7b3dSmrg		return sna_render_picture_downsample(sna, picture, channel,
1216428d7b3dSmrg						     x, y, ow, oh,
1217428d7b3dSmrg						     dst_x, dst_y);
1218428d7b3dSmrg	}
1219428d7b3dSmrg
1220428d7b3dSmrg	src_bo = use_cpu_bo(sna, pixmap, &box, true);
1221428d7b3dSmrg	if (src_bo == NULL)
1222428d7b3dSmrg		src_bo = move_to_gpu(pixmap, &box, false);
1223428d7b3dSmrg	if (src_bo) {
1224428d7b3dSmrg		bo = kgem_create_2d(&sna->kgem, w, h,
1225428d7b3dSmrg				    pixmap->drawable.bitsPerPixel,
1226428d7b3dSmrg				    kgem_choose_tiling(&sna->kgem,
1227428d7b3dSmrg						       I915_TILING_X, w, h,
1228428d7b3dSmrg						       pixmap->drawable.bitsPerPixel),
1229428d7b3dSmrg				    CREATE_TEMPORARY);
1230428d7b3dSmrg		if (bo) {
1231428d7b3dSmrg			DrawableRec tmp;
1232428d7b3dSmrg
1233428d7b3dSmrg			tmp.width  = w;
1234428d7b3dSmrg			tmp.height = h;
1235428d7b3dSmrg			tmp.depth  = pixmap->drawable.depth;
1236428d7b3dSmrg			tmp.bitsPerPixel = pixmap->drawable.bitsPerPixel;
1237428d7b3dSmrg
1238428d7b3dSmrg			assert(tmp.width);
1239428d7b3dSmrg			assert(tmp.height);
1240428d7b3dSmrg
1241428d7b3dSmrg			if (!sna->render.copy_boxes(sna, GXcopy,
1242428d7b3dSmrg						    &pixmap->drawable, src_bo, 0, 0,
1243428d7b3dSmrg						    &tmp, bo, -box.x1, -box.y1,
1244428d7b3dSmrg						    &box, 1, 0)) {
1245428d7b3dSmrg				kgem_bo_destroy(&sna->kgem, bo);
1246428d7b3dSmrg				bo = NULL;
1247428d7b3dSmrg			}
1248428d7b3dSmrg		}
1249428d7b3dSmrg	} else {
1250428d7b3dSmrg		struct sna_pixmap *priv = sna_pixmap(pixmap);
1251428d7b3dSmrg		if (priv) {
1252428d7b3dSmrg			RegionRec region;
1253428d7b3dSmrg
1254428d7b3dSmrg			region.extents = box;
1255428d7b3dSmrg			region.data = NULL;
1256428d7b3dSmrg			if (!sna_drawable_move_region_to_cpu(&pixmap->drawable,
1257428d7b3dSmrg							     &region, MOVE_READ))
1258428d7b3dSmrg				return 0;
1259428d7b3dSmrg
1260428d7b3dSmrg			assert(!priv->mapped);
1261428d7b3dSmrg			if (pixmap->devPrivate.ptr == NULL)
1262428d7b3dSmrg				return 0; /* uninitialised */
1263428d7b3dSmrg		}
1264428d7b3dSmrg
1265428d7b3dSmrg		bo = kgem_upload_source_image(&sna->kgem,
1266428d7b3dSmrg					      pixmap->devPrivate.ptr,
1267428d7b3dSmrg					      &box,
1268428d7b3dSmrg					      pixmap->devKind,
1269428d7b3dSmrg					      pixmap->drawable.bitsPerPixel);
1270428d7b3dSmrg		if (priv != NULL && bo != NULL &&
1271428d7b3dSmrg		    box.x2 - box.x1 == pixmap->drawable.width &&
1272428d7b3dSmrg		    box.y2 - box.y1 == pixmap->drawable.height) {
1273428d7b3dSmrg			DBG(("%s: adding upload cache to pixmap=%ld\n",
1274428d7b3dSmrg			     __FUNCTION__, pixmap->drawable.serialNumber));
1275428d7b3dSmrg			assert(priv->gpu_damage == NULL);
1276428d7b3dSmrg			assert(priv->gpu_bo == NULL);
1277428d7b3dSmrg			assert(bo->proxy != NULL);
1278428d7b3dSmrg			kgem_proxy_bo_attach(bo, &priv->gpu_bo);
1279428d7b3dSmrg		}
1280428d7b3dSmrg	}
1281428d7b3dSmrg
1282428d7b3dSmrg	if (bo == NULL) {
1283428d7b3dSmrg		DBG(("%s: falback -- pixmap is not on the GPU\n",
1284428d7b3dSmrg		     __FUNCTION__));
1285428d7b3dSmrg		return sna_render_picture_fixup(sna, picture, channel,
1286428d7b3dSmrg						x, y, ow, oh, dst_x, dst_y);
1287428d7b3dSmrg	}
1288428d7b3dSmrg
1289428d7b3dSmrg	if (ox == x && oy == y) {
1290428d7b3dSmrg		x = y = 0;
1291428d7b3dSmrg	} else if (channel->transform) {
1292428d7b3dSmrg		pixman_vector_t v;
1293428d7b3dSmrg		pixman_transform_t m;
1294428d7b3dSmrg
1295428d7b3dSmrg		v.vector[0] = (ox - box.x1) << 16;
1296428d7b3dSmrg		v.vector[1] = (oy - box.y1) << 16;
1297428d7b3dSmrg		v.vector[2] = 1 << 16;
1298428d7b3dSmrg		pixman_transform_invert(&m, channel->transform);
1299428d7b3dSmrg		pixman_transform_point(&m, &v);
1300428d7b3dSmrg		x = v.vector[0] / v.vector[2];
1301428d7b3dSmrg		y = v.vector[1] / v.vector[2];
1302428d7b3dSmrg	} else {
1303428d7b3dSmrg		x = ox - box.x1;
1304428d7b3dSmrg		y = oy - box.y1;
1305428d7b3dSmrg	}
1306428d7b3dSmrg
1307428d7b3dSmrg	channel->offset[0] = x - dst_x;
1308428d7b3dSmrg	channel->offset[1] = y - dst_y;
1309428d7b3dSmrg	channel->scale[0] = 1.f/w;
1310428d7b3dSmrg	channel->scale[1] = 1.f/h;
1311428d7b3dSmrg	channel->width  = w;
1312428d7b3dSmrg	channel->height = h;
1313428d7b3dSmrg	channel->bo = bo;
1314428d7b3dSmrg	return 1;
1315428d7b3dSmrg}
1316428d7b3dSmrg
1317428d7b3dSmrgstatic int
1318428d7b3dSmrgsna_render_picture_convolve(struct sna *sna,
1319428d7b3dSmrg			    PicturePtr picture,
1320428d7b3dSmrg			    struct sna_composite_channel *channel,
1321428d7b3dSmrg			    int16_t x, int16_t y,
1322428d7b3dSmrg			    int16_t w, int16_t h,
1323428d7b3dSmrg			    int16_t dst_x, int16_t dst_y)
1324428d7b3dSmrg{
1325428d7b3dSmrg	ScreenPtr screen = picture->pDrawable->pScreen;
1326428d7b3dSmrg	PixmapPtr pixmap;
1327428d7b3dSmrg	PicturePtr tmp;
1328428d7b3dSmrg	pixman_fixed_t *params = picture->filter_params;
1329428d7b3dSmrg	int x_off = -pixman_fixed_to_int((params[0] - pixman_fixed_1) >> 1);
1330428d7b3dSmrg	int y_off = -pixman_fixed_to_int((params[1] - pixman_fixed_1) >> 1);
1331428d7b3dSmrg	int cw = pixman_fixed_to_int(params[0]);
1332428d7b3dSmrg	int ch = pixman_fixed_to_int(params[1]);
1333428d7b3dSmrg	int i, j, error, depth;
1334428d7b3dSmrg	struct kgem_bo *bo;
1335428d7b3dSmrg
1336428d7b3dSmrg	/* Lame multi-pass accumulation implementation of a general convolution
1337428d7b3dSmrg	 * that works everywhere.
1338428d7b3dSmrg	 */
1339428d7b3dSmrg	DBG(("%s: origin=(%d,%d) kernel=%dx%d, size=%dx%d\n",
1340428d7b3dSmrg	     __FUNCTION__, x_off, y_off, cw, ch, w, h));
1341428d7b3dSmrg
1342428d7b3dSmrg	assert(picture->pDrawable);
1343428d7b3dSmrg	assert(picture->filter == PictFilterConvolution);
1344428d7b3dSmrg	assert(w <= sna->render.max_3d_size && h <= sna->render.max_3d_size);
1345428d7b3dSmrg
1346428d7b3dSmrg	if (PICT_FORMAT_RGB(picture->format) == 0) {
1347428d7b3dSmrg		channel->pict_format = PIXMAN_a8;
1348428d7b3dSmrg		depth = 8;
1349428d7b3dSmrg	} else {
1350428d7b3dSmrg		channel->pict_format = PIXMAN_a8r8g8b8;
1351428d7b3dSmrg		depth = 32;
1352428d7b3dSmrg	}
1353428d7b3dSmrg
1354428d7b3dSmrg	pixmap = screen->CreatePixmap(screen, w, h, depth, SNA_CREATE_SCRATCH);
1355428d7b3dSmrg	if (pixmap == NullPixmap) {
1356428d7b3dSmrg		DBG(("%s: pixmap allocation failed\n", __FUNCTION__));
1357428d7b3dSmrg		return -1;
1358428d7b3dSmrg	}
1359428d7b3dSmrg
1360428d7b3dSmrg	tmp = NULL;
1361428d7b3dSmrg	bo = __sna_pixmap_get_bo(pixmap);
1362428d7b3dSmrg	assert(bo);
1363428d7b3dSmrg	if (sna->render.clear(sna, pixmap, bo))
1364428d7b3dSmrg		tmp = CreatePicture(0, &pixmap->drawable,
1365428d7b3dSmrg				PictureMatchFormat(screen, depth, channel->pict_format),
1366428d7b3dSmrg				0, NULL, serverClient, &error);
1367428d7b3dSmrg	screen->DestroyPixmap(pixmap);
1368428d7b3dSmrg	if (tmp == NULL)
1369428d7b3dSmrg		return -1;
1370428d7b3dSmrg
1371428d7b3dSmrg	ValidatePicture(tmp);
1372428d7b3dSmrg
1373428d7b3dSmrg	picture->filter = PictFilterBilinear;
1374428d7b3dSmrg	params += 2;
1375428d7b3dSmrg	for (j = 0; j < ch; j++) {
1376428d7b3dSmrg		for (i = 0; i < cw; i++) {
1377428d7b3dSmrg			xRenderColor color;
1378428d7b3dSmrg			PicturePtr alpha;
1379428d7b3dSmrg
1380428d7b3dSmrg			color.alpha = *params++;
1381428d7b3dSmrg			color.red = color.green = color.blue = 0;
1382428d7b3dSmrg			DBG(("%s: (%d, %d), alpha=%x\n",
1383428d7b3dSmrg			     __FUNCTION__, i,j, color.alpha));
1384428d7b3dSmrg
1385428d7b3dSmrg			if (color.alpha <= 0x00ff)
1386428d7b3dSmrg				continue;
1387428d7b3dSmrg
1388428d7b3dSmrg			alpha = CreateSolidPicture(0, &color, &error);
1389428d7b3dSmrg			if (alpha) {
1390428d7b3dSmrg				sna_composite(PictOpAdd, picture, alpha, tmp,
1391428d7b3dSmrg					      x, y,
1392428d7b3dSmrg					      0, 0,
1393428d7b3dSmrg					      x_off+i, y_off+j,
1394428d7b3dSmrg					      w, h);
1395428d7b3dSmrg				FreePicture(alpha, 0);
1396428d7b3dSmrg			}
1397428d7b3dSmrg		}
1398428d7b3dSmrg	}
1399428d7b3dSmrg	picture->filter = PictFilterConvolution;
1400428d7b3dSmrg
1401428d7b3dSmrg	channel->height = h;
1402428d7b3dSmrg	channel->width  = w;
1403428d7b3dSmrg	channel->filter = PictFilterNearest;
1404428d7b3dSmrg	channel->repeat = RepeatNone;
1405428d7b3dSmrg	channel->is_affine = true;
1406428d7b3dSmrg	channel->transform = NULL;
1407428d7b3dSmrg	channel->scale[0] = 1.f / w;
1408428d7b3dSmrg	channel->scale[1] = 1.f / h;
1409428d7b3dSmrg	channel->offset[0] = -dst_x;
1410428d7b3dSmrg	channel->offset[1] = -dst_y;
1411428d7b3dSmrg	channel->bo = kgem_bo_reference(bo); /* transfer ownership */
1412428d7b3dSmrg	FreePicture(tmp, 0);
1413428d7b3dSmrg
1414428d7b3dSmrg	return 1;
1415428d7b3dSmrg}
1416428d7b3dSmrg
1417428d7b3dSmrgstatic bool
1418428d7b3dSmrgsna_render_picture_flatten(struct sna *sna,
1419428d7b3dSmrg			   PicturePtr picture,
1420428d7b3dSmrg			   struct sna_composite_channel *channel,
1421428d7b3dSmrg			   int16_t x, int16_t y,
1422428d7b3dSmrg			   int16_t w, int16_t h,
1423428d7b3dSmrg			   int16_t dst_x, int16_t dst_y)
1424428d7b3dSmrg{
1425428d7b3dSmrg	ScreenPtr screen = picture->pDrawable->pScreen;
1426428d7b3dSmrg	PixmapPtr pixmap;
1427428d7b3dSmrg	PicturePtr tmp, alpha;
1428428d7b3dSmrg	int old_format, error;
1429428d7b3dSmrg
1430428d7b3dSmrg	assert(picture->pDrawable);
1431428d7b3dSmrg	assert(picture->alphaMap);
1432428d7b3dSmrg	assert(w <= sna->render.max_3d_size && h <= sna->render.max_3d_size);
1433428d7b3dSmrg
1434428d7b3dSmrg	/* XXX shortcut a8? */
1435428d7b3dSmrg	DBG(("%s: %dx%d\n", __FUNCTION__, w, h));
1436428d7b3dSmrg
1437428d7b3dSmrg	pixmap = screen->CreatePixmap(screen, w, h, 32, SNA_CREATE_SCRATCH);
1438428d7b3dSmrg	if (pixmap == NullPixmap) {
1439428d7b3dSmrg		DBG(("%s: pixmap allocation failed\n", __FUNCTION__));
1440428d7b3dSmrg		return false;
1441428d7b3dSmrg	}
1442428d7b3dSmrg
1443428d7b3dSmrg	assert(__sna_pixmap_get_bo(pixmap));
1444428d7b3dSmrg
1445428d7b3dSmrg	tmp = CreatePicture(0, &pixmap->drawable,
1446428d7b3dSmrg			    PictureMatchFormat(screen, 32, PICT_a8r8g8b8),
1447428d7b3dSmrg			    0, NULL, serverClient, &error);
1448428d7b3dSmrg	screen->DestroyPixmap(pixmap);
1449428d7b3dSmrg	if (tmp == NULL)
1450428d7b3dSmrg		return false;
1451428d7b3dSmrg
1452428d7b3dSmrg	ValidatePicture(tmp);
1453428d7b3dSmrg
1454428d7b3dSmrg	old_format = picture->format;
1455428d7b3dSmrg	picture->format = PICT_FORMAT(PICT_FORMAT_BPP(picture->format),
1456428d7b3dSmrg				      PICT_FORMAT_TYPE(picture->format),
1457428d7b3dSmrg				      0,
1458428d7b3dSmrg				      PICT_FORMAT_R(picture->format),
1459428d7b3dSmrg				      PICT_FORMAT_G(picture->format),
1460428d7b3dSmrg				      PICT_FORMAT_B(picture->format));
1461428d7b3dSmrg
1462428d7b3dSmrg	alpha = picture->alphaMap;
1463428d7b3dSmrg	picture->alphaMap = NULL;
1464428d7b3dSmrg
1465428d7b3dSmrg	sna_composite(PictOpSrc, picture, alpha, tmp,
1466428d7b3dSmrg		      x, y,
1467428d7b3dSmrg		      x + picture->alphaOrigin.x, y + picture->alphaOrigin.y,
1468428d7b3dSmrg		      0, 0,
1469428d7b3dSmrg		      w, h);
1470428d7b3dSmrg
1471428d7b3dSmrg	picture->format = old_format;
1472428d7b3dSmrg	picture->alphaMap = alpha;
1473428d7b3dSmrg
1474428d7b3dSmrg	channel->height = h;
1475428d7b3dSmrg	channel->width  = w;
1476428d7b3dSmrg	channel->filter = PictFilterNearest;
1477428d7b3dSmrg	channel->repeat = RepeatNone;
1478428d7b3dSmrg	channel->pict_format = PIXMAN_a8r8g8b8;
1479428d7b3dSmrg	channel->is_affine = true;
1480428d7b3dSmrg	channel->transform = NULL;
1481428d7b3dSmrg	channel->scale[0] = 1.f / w;
1482428d7b3dSmrg	channel->scale[1] = 1.f / h;
1483428d7b3dSmrg	channel->offset[0] = -dst_x;
1484428d7b3dSmrg	channel->offset[1] = -dst_y;
1485428d7b3dSmrg	channel->bo = kgem_bo_reference(__sna_pixmap_get_bo(pixmap));
1486428d7b3dSmrg	FreePicture(tmp, 0);
1487428d7b3dSmrg
1488428d7b3dSmrg	return true;
1489428d7b3dSmrg}
1490428d7b3dSmrg
1491428d7b3dSmrgint
1492428d7b3dSmrgsna_render_picture_approximate_gradient(struct sna *sna,
1493428d7b3dSmrg					PicturePtr picture,
1494428d7b3dSmrg					struct sna_composite_channel *channel,
1495428d7b3dSmrg					int16_t x, int16_t y,
1496428d7b3dSmrg					int16_t w, int16_t h,
1497428d7b3dSmrg					int16_t dst_x, int16_t dst_y)
1498428d7b3dSmrg{
1499428d7b3dSmrg	pixman_image_t *dst, *src;
1500428d7b3dSmrg	pixman_transform_t t;
1501428d7b3dSmrg	int w2 = w/2, h2 = h/2;
1502428d7b3dSmrg	int dx, dy;
1503428d7b3dSmrg	void *ptr;
1504428d7b3dSmrg
1505428d7b3dSmrg#if NO_FIXUP
1506428d7b3dSmrg	return -1;
1507428d7b3dSmrg#endif
1508428d7b3dSmrg
1509428d7b3dSmrg	DBG(("%s: (%d, %d)x(%d, %d), dst=(%d, %d)\n",
1510428d7b3dSmrg	     __FUNCTION__, x, y, w, h, dst_x, dst_y));
1511428d7b3dSmrg
1512428d7b3dSmrg	if (w2 == 0 || h2 == 0) {
1513428d7b3dSmrg		DBG(("%s: fallback - unknown bounds\n", __FUNCTION__));
1514428d7b3dSmrg		return -1;
1515428d7b3dSmrg	}
1516428d7b3dSmrg	if (w2 > sna->render.max_3d_size || h2 > sna->render.max_3d_size) {
1517428d7b3dSmrg		DBG(("%s: fallback - too large (%dx%d)\n", __FUNCTION__, w, h));
1518428d7b3dSmrg		return -1;
1519428d7b3dSmrg	}
1520428d7b3dSmrg
1521428d7b3dSmrg	channel->is_opaque = sna_gradient_is_opaque((PictGradient*)picture->pSourcePict);
1522428d7b3dSmrg	channel->pict_format =
1523428d7b3dSmrg		channel->is_opaque ? PIXMAN_x8r8g8b8 : PIXMAN_a8r8g8b8;
1524428d7b3dSmrg	DBG(("%s: gradient is opaque? %d, selecting format %08x\n",
1525428d7b3dSmrg	     __FUNCTION__, channel->is_opaque, channel->pict_format));
1526428d7b3dSmrg	assert(channel->card_format == -1);
1527428d7b3dSmrg
1528428d7b3dSmrg	channel->bo = kgem_create_buffer_2d(&sna->kgem,
1529428d7b3dSmrg					    w2, h2, 32,
1530428d7b3dSmrg					    KGEM_BUFFER_WRITE_INPLACE,
1531428d7b3dSmrg					    &ptr);
1532428d7b3dSmrg	if (!channel->bo) {
1533428d7b3dSmrg		DBG(("%s: failed to create upload buffer, using clear\n",
1534428d7b3dSmrg		     __FUNCTION__));
1535428d7b3dSmrg		return 0;
1536428d7b3dSmrg	}
1537428d7b3dSmrg
1538428d7b3dSmrg	dst = pixman_image_create_bits(channel->pict_format,
1539428d7b3dSmrg				       w2, h2, ptr, channel->bo->pitch);
1540428d7b3dSmrg	if (!dst) {
1541428d7b3dSmrg		kgem_bo_destroy(&sna->kgem, channel->bo);
1542428d7b3dSmrg		channel->bo = NULL;
1543428d7b3dSmrg		return 0;
1544428d7b3dSmrg	}
1545428d7b3dSmrg
1546428d7b3dSmrg	src = image_from_pict(picture, false, &dx, &dy);
1547428d7b3dSmrg	if (src == NULL) {
1548428d7b3dSmrg		pixman_image_unref(dst);
1549428d7b3dSmrg		kgem_bo_destroy(&sna->kgem, channel->bo);
1550428d7b3dSmrg		channel->bo = NULL;
1551428d7b3dSmrg		return 0;
1552428d7b3dSmrg	}
1553428d7b3dSmrg	DBG(("%s: source offset (%d, %d)\n", __FUNCTION__, dx, dy));
1554428d7b3dSmrg
1555428d7b3dSmrg	memset(&t, 0, sizeof(t));
1556428d7b3dSmrg	t.matrix[0][0] = (w << 16) / w2;
1557428d7b3dSmrg	t.matrix[0][2] = (x + dx) << 16;
1558428d7b3dSmrg	t.matrix[1][1] = (h << 16) / h2;
1559428d7b3dSmrg	t.matrix[1][2] = (y + dy) << 16;
1560428d7b3dSmrg	t.matrix[2][2] = 1 << 16;
1561428d7b3dSmrg	if (picture->transform)
1562428d7b3dSmrg		pixman_transform_multiply(&t, picture->transform, &t);
1563428d7b3dSmrg	DBG(("%s: applying transform [(%f, %f, %f), (%f, %f, %f), (%f, %f, %f)]\n",
1564428d7b3dSmrg	     __FUNCTION__,
1565428d7b3dSmrg	     pixman_fixed_to_double(t.matrix[0][0]),
1566428d7b3dSmrg	     pixman_fixed_to_double(t.matrix[0][1]),
1567428d7b3dSmrg	     pixman_fixed_to_double(t.matrix[0][2]),
1568428d7b3dSmrg	     pixman_fixed_to_double(t.matrix[1][0]),
1569428d7b3dSmrg	     pixman_fixed_to_double(t.matrix[1][1]),
1570428d7b3dSmrg	     pixman_fixed_to_double(t.matrix[1][2]),
1571428d7b3dSmrg	     pixman_fixed_to_double(t.matrix[2][0]),
1572428d7b3dSmrg	     pixman_fixed_to_double(t.matrix[2][1]),
1573428d7b3dSmrg	     pixman_fixed_to_double(t.matrix[2][2])));
1574428d7b3dSmrg	pixman_image_set_transform(src, &t);
1575428d7b3dSmrg
1576428d7b3dSmrg	sna_image_composite(PictOpSrc, src, NULL, dst,
1577428d7b3dSmrg			    0, 0,
1578428d7b3dSmrg			    0, 0,
1579428d7b3dSmrg			    0, 0,
1580428d7b3dSmrg			    w2, h2);
1581428d7b3dSmrg	free_pixman_pict(picture, src);
1582428d7b3dSmrg	pixman_image_unref(dst);
1583428d7b3dSmrg
1584428d7b3dSmrg	channel->width  = w2;
1585428d7b3dSmrg	channel->height = h2;
1586428d7b3dSmrg
1587428d7b3dSmrg	channel->filter = PictFilterNearest;
1588428d7b3dSmrg	channel->repeat = RepeatNone;
1589428d7b3dSmrg	channel->is_affine = true;
1590428d7b3dSmrg
1591428d7b3dSmrg	channel->scale[0] = 1.f/w;
1592428d7b3dSmrg	channel->scale[1] = 1.f/h;
1593428d7b3dSmrg	channel->offset[0] = -dst_x;
1594428d7b3dSmrg	channel->offset[1] = -dst_y;
1595428d7b3dSmrg	channel->transform = NULL;
1596428d7b3dSmrg
1597428d7b3dSmrg	return 1;
1598428d7b3dSmrg}
1599428d7b3dSmrg
1600428d7b3dSmrgint
1601428d7b3dSmrgsna_render_picture_fixup(struct sna *sna,
1602428d7b3dSmrg			 PicturePtr picture,
1603428d7b3dSmrg			 struct sna_composite_channel *channel,
1604428d7b3dSmrg			 int16_t x, int16_t y,
1605428d7b3dSmrg			 int16_t w, int16_t h,
1606428d7b3dSmrg			 int16_t dst_x, int16_t dst_y)
1607428d7b3dSmrg{
1608428d7b3dSmrg	pixman_image_t *dst, *src;
1609428d7b3dSmrg	int dx, dy;
1610428d7b3dSmrg	void *ptr;
1611428d7b3dSmrg
1612428d7b3dSmrg#if NO_FIXUP
1613428d7b3dSmrg	return -1;
1614428d7b3dSmrg#endif
1615428d7b3dSmrg
1616428d7b3dSmrg	DBG(("%s: (%d, %d)x(%d, %d)\n", __FUNCTION__, x, y, w, h));
1617428d7b3dSmrg
1618428d7b3dSmrg	if (w == 0 || h == 0) {
1619428d7b3dSmrg		DBG(("%s: fallback - unknown bounds\n", __FUNCTION__));
1620428d7b3dSmrg		return -1;
1621428d7b3dSmrg	}
1622428d7b3dSmrg	if (w > sna->render.max_3d_size || h > sna->render.max_3d_size) {
1623428d7b3dSmrg		DBG(("%s: fallback - too large (%dx%d)\n", __FUNCTION__, w, h));
1624428d7b3dSmrg		return -1;
1625428d7b3dSmrg	}
1626428d7b3dSmrg
1627428d7b3dSmrg	if (picture->alphaMap) {
1628428d7b3dSmrg		DBG(("%s: alphamap\n", __FUNCTION__));
1629428d7b3dSmrg		if (is_gpu(sna, picture->pDrawable, PREFER_GPU_RENDER) ||
1630428d7b3dSmrg		    is_gpu(sna, picture->alphaMap->pDrawable, PREFER_GPU_RENDER)) {
1631428d7b3dSmrg			if (sna_render_picture_flatten(sna, picture, channel,
1632428d7b3dSmrg							  x, y, w, h, dst_x, dst_y))
1633428d7b3dSmrg				return 1;
1634428d7b3dSmrg		}
1635428d7b3dSmrg
1636428d7b3dSmrg		goto do_fixup;
1637428d7b3dSmrg	}
1638428d7b3dSmrg
1639428d7b3dSmrg	if (picture->filter == PictFilterConvolution) {
1640428d7b3dSmrg		DBG(("%s: convolution\n", __FUNCTION__));
1641428d7b3dSmrg		if (is_gpu(sna, picture->pDrawable, PREFER_GPU_RENDER)) {
1642428d7b3dSmrg			return sna_render_picture_convolve(sna, picture, channel,
1643428d7b3dSmrg							   x, y, w, h, dst_x, dst_y);
1644428d7b3dSmrg		}
1645428d7b3dSmrg
1646428d7b3dSmrg		goto do_fixup;
1647428d7b3dSmrg	}
1648428d7b3dSmrg
1649428d7b3dSmrgdo_fixup:
1650428d7b3dSmrg	if (PICT_FORMAT_RGB(picture->format) == 0)
1651428d7b3dSmrg		channel->pict_format = PIXMAN_a8;
1652428d7b3dSmrg	else
1653428d7b3dSmrg		channel->pict_format = PIXMAN_a8r8g8b8;
1654428d7b3dSmrg
1655428d7b3dSmrg	if (picture->pDrawable &&
1656428d7b3dSmrg	    !sna_drawable_move_to_cpu(picture->pDrawable, MOVE_READ))
1657428d7b3dSmrg		return 0;
1658428d7b3dSmrg
1659428d7b3dSmrg	channel->bo = kgem_create_buffer_2d(&sna->kgem,
1660428d7b3dSmrg					    w, h, PIXMAN_FORMAT_BPP(channel->pict_format),
1661428d7b3dSmrg					    KGEM_BUFFER_WRITE_INPLACE,
1662428d7b3dSmrg					    &ptr);
1663428d7b3dSmrg	if (!channel->bo) {
1664428d7b3dSmrg		DBG(("%s: failed to create upload buffer, using clear\n",
1665428d7b3dSmrg		     __FUNCTION__));
1666428d7b3dSmrg		return 0;
1667428d7b3dSmrg	}
1668428d7b3dSmrg
1669428d7b3dSmrg	/* Composite in the original format to preserve idiosyncracies */
1670428d7b3dSmrg	if (!kgem_buffer_is_inplace(channel->bo) &&
1671428d7b3dSmrg	    (picture->pDrawable == NULL ||
1672428d7b3dSmrg	     alphaless(picture->format) == alphaless(channel->pict_format)))
1673428d7b3dSmrg		dst = pixman_image_create_bits(channel->pict_format,
1674428d7b3dSmrg					       w, h, ptr, channel->bo->pitch);
1675428d7b3dSmrg	else
1676428d7b3dSmrg		dst = pixman_image_create_bits((pixman_format_code_t)picture->format,
1677428d7b3dSmrg					       w, h, NULL, 0);
1678428d7b3dSmrg	if (!dst) {
1679428d7b3dSmrg		kgem_bo_destroy(&sna->kgem, channel->bo);
1680428d7b3dSmrg		return 0;
1681428d7b3dSmrg	}
1682428d7b3dSmrg
1683428d7b3dSmrg	src = image_from_pict(picture, false, &dx, &dy);
1684428d7b3dSmrg	if (src == NULL) {
1685428d7b3dSmrg		pixman_image_unref(dst);
1686428d7b3dSmrg		kgem_bo_destroy(&sna->kgem, channel->bo);
1687428d7b3dSmrg		return 0;
1688428d7b3dSmrg	}
1689428d7b3dSmrg
1690428d7b3dSmrg	DBG(("%s: compositing tmp=(%d+%d, %d+%d)x(%d, %d)\n",
1691428d7b3dSmrg	     __FUNCTION__, x, dx, y, dy, w, h));
1692428d7b3dSmrg	sna_image_composite(PictOpSrc, src, NULL, dst,
1693428d7b3dSmrg			    x + dx, y + dy,
1694428d7b3dSmrg			    0, 0,
1695428d7b3dSmrg			    0, 0,
1696428d7b3dSmrg			    w, h);
1697428d7b3dSmrg	free_pixman_pict(picture, src);
1698428d7b3dSmrg
1699428d7b3dSmrg	/* Then convert to card format */
1700428d7b3dSmrg	if (pixman_image_get_data(dst) != ptr) {
1701428d7b3dSmrg		DBG(("%s: performing post-conversion %08x->%08x (%d, %d)\n",
1702428d7b3dSmrg		     __FUNCTION__,
1703428d7b3dSmrg		     picture->format, channel->pict_format,
1704428d7b3dSmrg		     w, h));
1705428d7b3dSmrg
1706428d7b3dSmrg		src = dst;
1707428d7b3dSmrg		dst = pixman_image_create_bits(channel->pict_format,
1708428d7b3dSmrg					       w, h, ptr, channel->bo->pitch);
1709428d7b3dSmrg		if (dst) {
1710428d7b3dSmrg			sna_image_composite(PictOpSrc, src, NULL, dst,
1711428d7b3dSmrg					    0, 0,
1712428d7b3dSmrg					    0, 0,
1713428d7b3dSmrg					    0, 0,
1714428d7b3dSmrg					    w, h);
1715428d7b3dSmrg			pixman_image_unref(src);
1716428d7b3dSmrg		} else {
1717428d7b3dSmrg			memset(ptr, 0, __kgem_buffer_size(channel->bo));
1718428d7b3dSmrg			dst = src;
1719428d7b3dSmrg		}
1720428d7b3dSmrg	}
1721428d7b3dSmrg	pixman_image_unref(dst);
1722428d7b3dSmrg
1723428d7b3dSmrg	channel->width  = w;
1724428d7b3dSmrg	channel->height = h;
1725428d7b3dSmrg
1726428d7b3dSmrg	channel->filter = PictFilterNearest;
1727428d7b3dSmrg	channel->repeat = RepeatNone;
1728428d7b3dSmrg	channel->is_affine = true;
1729428d7b3dSmrg
1730428d7b3dSmrg	channel->scale[0] = 1.f/w;
1731428d7b3dSmrg	channel->scale[1] = 1.f/h;
1732428d7b3dSmrg	channel->offset[0] = -dst_x;
1733428d7b3dSmrg	channel->offset[1] = -dst_y;
1734428d7b3dSmrg	channel->transform = NULL;
1735428d7b3dSmrg
1736428d7b3dSmrg	return 1;
1737428d7b3dSmrg}
1738428d7b3dSmrg
1739428d7b3dSmrgint
1740428d7b3dSmrgsna_render_picture_convert(struct sna *sna,
1741428d7b3dSmrg			   PicturePtr picture,
1742428d7b3dSmrg			   struct sna_composite_channel *channel,
1743428d7b3dSmrg			   PixmapPtr pixmap,
1744428d7b3dSmrg			   int16_t x, int16_t y,
1745428d7b3dSmrg			   int16_t w, int16_t h,
1746428d7b3dSmrg			   int16_t dst_x, int16_t dst_y,
1747428d7b3dSmrg			   bool fixup_alpha)
1748428d7b3dSmrg{
1749428d7b3dSmrg	BoxRec box;
1750428d7b3dSmrg
1751428d7b3dSmrg#if NO_CONVERT
1752428d7b3dSmrg	return -1;
1753428d7b3dSmrg#endif
1754428d7b3dSmrg
1755428d7b3dSmrg	if (w != 0 && h != 0) {
1756428d7b3dSmrg		box.x1 = x;
1757428d7b3dSmrg		box.y1 = y;
1758428d7b3dSmrg		box.x2 = bound(x, w);
1759428d7b3dSmrg		box.y2 = bound(y, h);
1760428d7b3dSmrg
1761428d7b3dSmrg		if (channel->transform) {
1762428d7b3dSmrg			DBG(("%s: has transform, converting whole surface\n",
1763428d7b3dSmrg			     __FUNCTION__));
1764428d7b3dSmrg			box.x1 = box.y1 = 0;
1765428d7b3dSmrg			box.x2 = pixmap->drawable.width;
1766428d7b3dSmrg			box.y2 = pixmap->drawable.height;
1767428d7b3dSmrg		}
1768428d7b3dSmrg
1769428d7b3dSmrg		if (box.x1 < 0)
1770428d7b3dSmrg			box.x1 = 0;
1771428d7b3dSmrg		if (box.y1 < 0)
1772428d7b3dSmrg			box.y1 = 0;
1773428d7b3dSmrg		if (box.x2 > pixmap->drawable.width)
1774428d7b3dSmrg			box.x2 = pixmap->drawable.width;
1775428d7b3dSmrg		if (box.y2 > pixmap->drawable.height)
1776428d7b3dSmrg			box.y2 = pixmap->drawable.height;
1777428d7b3dSmrg	} else {
1778428d7b3dSmrg		DBG(("%s: op no bounds, converting whole surface\n",
1779428d7b3dSmrg		     __FUNCTION__));
1780428d7b3dSmrg		box.x1 = box.y1 = 0;
1781428d7b3dSmrg		box.x2 = pixmap->drawable.width;
1782428d7b3dSmrg		box.y2 = pixmap->drawable.height;
1783428d7b3dSmrg	}
1784428d7b3dSmrg
1785428d7b3dSmrg	w = box.x2 - box.x1;
1786428d7b3dSmrg	h = box.y2 - box.y1;
1787428d7b3dSmrg
1788428d7b3dSmrg	DBG(("%s: convert (%d, %d)x(%d, %d), source size %dx%d\n",
1789428d7b3dSmrg	     __FUNCTION__, box.x1, box.y1, w, h,
1790428d7b3dSmrg	     pixmap->drawable.width,
1791428d7b3dSmrg	     pixmap->drawable.height));
1792428d7b3dSmrg
1793428d7b3dSmrg	if (w <= 0 || h <= 0) {
1794428d7b3dSmrg		DBG(("%s: sample extents lie outside of source, using clear\n",
1795428d7b3dSmrg		     __FUNCTION__));
1796428d7b3dSmrg		return 0;
1797428d7b3dSmrg	}
1798428d7b3dSmrg
1799428d7b3dSmrg	if (fixup_alpha && is_gpu(sna, &pixmap->drawable, PREFER_GPU_RENDER)) {
1800428d7b3dSmrg		ScreenPtr screen = pixmap->drawable.pScreen;
1801428d7b3dSmrg		PixmapPtr tmp;
1802428d7b3dSmrg		PicturePtr src, dst;
1803428d7b3dSmrg		int error;
1804428d7b3dSmrg
1805428d7b3dSmrg		assert(PICT_FORMAT_BPP(picture->format) == pixmap->drawable.bitsPerPixel);
1806428d7b3dSmrg		channel->pict_format = PICT_FORMAT(PICT_FORMAT_BPP(picture->format),
1807428d7b3dSmrg						   PICT_FORMAT_TYPE(picture->format),
1808428d7b3dSmrg						   PICT_FORMAT_BPP(picture->format) - PIXMAN_FORMAT_DEPTH(picture->format),
1809428d7b3dSmrg						   PICT_FORMAT_R(picture->format),
1810428d7b3dSmrg						   PICT_FORMAT_G(picture->format),
1811428d7b3dSmrg						   PICT_FORMAT_B(picture->format));
1812428d7b3dSmrg
1813428d7b3dSmrg		DBG(("%s: converting to %08x from %08x using composite alpha-fixup\n",
1814428d7b3dSmrg		     __FUNCTION__,
1815428d7b3dSmrg		     (unsigned)channel->pict_format,
1816428d7b3dSmrg		     (unsigned)picture->format));
1817428d7b3dSmrg
1818428d7b3dSmrg		tmp = screen->CreatePixmap(screen, w, h, pixmap->drawable.bitsPerPixel, SNA_CREATE_SCRATCH);
1819428d7b3dSmrg		if (tmp == NULL)
1820428d7b3dSmrg			return -1;
1821428d7b3dSmrg
1822428d7b3dSmrg		assert(__sna_pixmap_get_bo(tmp));
1823428d7b3dSmrg
1824428d7b3dSmrg		dst = CreatePicture(0, &tmp->drawable,
1825428d7b3dSmrg				    PictureMatchFormat(screen,
1826428d7b3dSmrg						       pixmap->drawable.bitsPerPixel,
1827428d7b3dSmrg						       channel->pict_format),
1828428d7b3dSmrg				    0, NULL, serverClient, &error);
1829428d7b3dSmrg		if (dst == NULL) {
1830428d7b3dSmrg			screen->DestroyPixmap(tmp);
1831428d7b3dSmrg			return 0;
1832428d7b3dSmrg		}
1833428d7b3dSmrg
1834428d7b3dSmrg		src = CreatePicture(0, &pixmap->drawable,
1835428d7b3dSmrg				    PictureMatchFormat(screen,
1836428d7b3dSmrg						       pixmap->drawable.depth,
1837428d7b3dSmrg						       picture->format),
1838428d7b3dSmrg				    0, NULL, serverClient, &error);
1839428d7b3dSmrg		if (src == NULL) {
1840428d7b3dSmrg			FreePicture(dst, 0);
1841428d7b3dSmrg			screen->DestroyPixmap(tmp);
1842428d7b3dSmrg			return 0;
1843428d7b3dSmrg		}
1844428d7b3dSmrg
1845428d7b3dSmrg		ValidatePicture(src);
1846428d7b3dSmrg		ValidatePicture(dst);
1847428d7b3dSmrg
1848428d7b3dSmrg		sna_composite(PictOpSrc, src, NULL, dst,
1849428d7b3dSmrg			      box.x1, box.y1,
1850428d7b3dSmrg			      0, 0,
1851428d7b3dSmrg			      0, 0,
1852428d7b3dSmrg			      w, h);
1853428d7b3dSmrg		FreePicture(dst, 0);
1854428d7b3dSmrg		FreePicture(src, 0);
1855428d7b3dSmrg
1856428d7b3dSmrg		channel->bo = __sna_pixmap_get_bo(tmp);
1857428d7b3dSmrg		kgem_bo_reference(channel->bo);
1858428d7b3dSmrg		screen->DestroyPixmap(tmp);
1859428d7b3dSmrg	} else {
1860428d7b3dSmrg		pixman_image_t *src, *dst;
1861428d7b3dSmrg		void *ptr;
1862428d7b3dSmrg
1863428d7b3dSmrg		if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ))
1864428d7b3dSmrg			return 0;
1865428d7b3dSmrg
1866428d7b3dSmrg		src = pixman_image_create_bits((pixman_format_code_t)picture->format,
1867428d7b3dSmrg					       pixmap->drawable.width,
1868428d7b3dSmrg					       pixmap->drawable.height,
1869428d7b3dSmrg					       pixmap->devPrivate.ptr,
1870428d7b3dSmrg					       pixmap->devKind);
1871428d7b3dSmrg		if (!src)
1872428d7b3dSmrg			return 0;
1873428d7b3dSmrg
1874428d7b3dSmrg		if (PICT_FORMAT_RGB(picture->format) == 0) {
1875428d7b3dSmrg			channel->pict_format = PIXMAN_a8;
1876428d7b3dSmrg			DBG(("%s: converting to a8 from %08x\n",
1877428d7b3dSmrg			     __FUNCTION__, picture->format));
1878428d7b3dSmrg		} else {
1879428d7b3dSmrg			channel->pict_format = PIXMAN_a8r8g8b8;
1880428d7b3dSmrg			DBG(("%s: converting to a8r8g8b8 from %08x\n",
1881428d7b3dSmrg			     __FUNCTION__, picture->format));
1882428d7b3dSmrg		}
1883428d7b3dSmrg
1884428d7b3dSmrg		channel->bo = kgem_create_buffer_2d(&sna->kgem,
1885428d7b3dSmrg						    w, h, PIXMAN_FORMAT_BPP(channel->pict_format),
1886428d7b3dSmrg						    KGEM_BUFFER_WRITE_INPLACE,
1887428d7b3dSmrg						    &ptr);
1888428d7b3dSmrg		if (!channel->bo) {
1889428d7b3dSmrg			pixman_image_unref(src);
1890428d7b3dSmrg			return 0;
1891428d7b3dSmrg		}
1892428d7b3dSmrg
1893428d7b3dSmrg		dst = pixman_image_create_bits(channel->pict_format,
1894428d7b3dSmrg					       w, h, ptr, channel->bo->pitch);
1895428d7b3dSmrg		if (!dst) {
1896428d7b3dSmrg			kgem_bo_destroy(&sna->kgem, channel->bo);
1897428d7b3dSmrg			pixman_image_unref(src);
1898428d7b3dSmrg			return 0;
1899428d7b3dSmrg		}
1900428d7b3dSmrg
1901428d7b3dSmrg		if (sigtrap_get() == 0) {
1902428d7b3dSmrg			sna_image_composite(PictOpSrc, src, NULL, dst,
1903428d7b3dSmrg					    box.x1, box.y1,
1904428d7b3dSmrg					    0, 0,
1905428d7b3dSmrg					    0, 0,
1906428d7b3dSmrg					    w, h);
1907428d7b3dSmrg			sigtrap_put();
1908428d7b3dSmrg		}
1909428d7b3dSmrg		pixman_image_unref(dst);
1910428d7b3dSmrg		pixman_image_unref(src);
1911428d7b3dSmrg	}
1912428d7b3dSmrg
1913428d7b3dSmrg	channel->width  = w;
1914428d7b3dSmrg	channel->height = h;
1915428d7b3dSmrg
1916428d7b3dSmrg	channel->scale[0] = 1.f/w;
1917428d7b3dSmrg	channel->scale[1] = 1.f/h;
1918428d7b3dSmrg	channel->offset[0] = x - dst_x - box.x1;
1919428d7b3dSmrg	channel->offset[1] = y - dst_y - box.y1;
1920428d7b3dSmrg
1921428d7b3dSmrg	DBG(("%s: offset=(%d, %d), size=(%d, %d)\n",
1922428d7b3dSmrg	     __FUNCTION__,
1923428d7b3dSmrg	     channel->offset[0], channel->offset[1],
1924428d7b3dSmrg	     channel->width, channel->height));
1925428d7b3dSmrg	return 1;
1926428d7b3dSmrg}
1927428d7b3dSmrg
1928428d7b3dSmrgbool
1929428d7b3dSmrgsna_render_composite_redirect(struct sna *sna,
1930428d7b3dSmrg			      struct sna_composite_op *op,
1931428d7b3dSmrg			      int x, int y, int width, int height,
1932428d7b3dSmrg			      bool partial)
1933428d7b3dSmrg{
1934428d7b3dSmrg	struct sna_composite_redirect *t = &op->redirect;
1935428d7b3dSmrg	int bpp = op->dst.pixmap->drawable.bitsPerPixel;
1936428d7b3dSmrg	struct kgem_bo *bo;
1937428d7b3dSmrg
1938428d7b3dSmrg	assert(t->real_bo == NULL);
1939428d7b3dSmrg
1940428d7b3dSmrg#if NO_REDIRECT
1941428d7b3dSmrg	return false;
1942428d7b3dSmrg#endif
1943428d7b3dSmrg
1944428d7b3dSmrg	DBG(("%s: target too large (%dx%d), copying to temporary %dx%d, max %d / %d\n",
1945428d7b3dSmrg	     __FUNCTION__,
1946428d7b3dSmrg	     op->dst.width, op->dst.height,
1947428d7b3dSmrg	     width, height,
1948428d7b3dSmrg	     sna->render.max_3d_size,
1949428d7b3dSmrg	     sna->render.max_3d_pitch));
1950428d7b3dSmrg
1951428d7b3dSmrg	if (!width || !height)
1952428d7b3dSmrg		return false;
1953428d7b3dSmrg
1954428d7b3dSmrg	if (width  > sna->render.max_3d_size ||
1955428d7b3dSmrg	    height > sna->render.max_3d_size)
1956428d7b3dSmrg		return false;
1957428d7b3dSmrg
1958428d7b3dSmrg	if (op->dst.bo->pitch <= sna->render.max_3d_pitch) {
1959428d7b3dSmrg		BoxRec box;
1960428d7b3dSmrg		int w, h, offset;
1961428d7b3dSmrg
1962428d7b3dSmrg		DBG(("%s: dst pitch (%d) fits within render pipeline (%d)\n",
1963428d7b3dSmrg		     __FUNCTION__, op->dst.bo->pitch, sna->render.max_3d_pitch));
1964428d7b3dSmrg
1965428d7b3dSmrg		box.x1 = x + op->dst.x;
1966428d7b3dSmrg		box.x2 = bound(box.x1, width);
1967428d7b3dSmrg		box.y1 = y + op->dst.y;
1968428d7b3dSmrg		box.y2 = bound(box.y1, height);
1969428d7b3dSmrg
1970428d7b3dSmrg		if (box.x1 < 0)
1971428d7b3dSmrg			box.x1 = 0;
1972428d7b3dSmrg		if (box.y1 < 0)
1973428d7b3dSmrg			box.y1 = 0;
1974428d7b3dSmrg
1975428d7b3dSmrg		/* Ensure we align to an even tile row */
1976428d7b3dSmrg		if (op->dst.bo->tiling) {
1977428d7b3dSmrg			int tile_width, tile_height, tile_size;
1978428d7b3dSmrg
1979428d7b3dSmrg			kgem_get_tile_size(&sna->kgem, op->dst.bo->tiling, op->dst.bo->pitch,
1980428d7b3dSmrg					   &tile_width, &tile_height, &tile_size);
1981428d7b3dSmrg
1982428d7b3dSmrg			box.y1 = box.y1 & ~(2*tile_height - 1);
1983428d7b3dSmrg			box.y2 = ALIGN(box.y2, 2*tile_height);
1984428d7b3dSmrg
1985428d7b3dSmrg			box.x1 = box.x1 & ~(tile_width * 8 / op->dst.pixmap->drawable.bitsPerPixel - 1);
1986428d7b3dSmrg			box.x2 = ALIGN(box.x2, tile_width * 8 / op->dst.pixmap->drawable.bitsPerPixel);
1987428d7b3dSmrg
1988428d7b3dSmrg			if (box.x1 > sna->render.max_3d_size &&
1989428d7b3dSmrg			    box.x2 <= 2*sna->render.max_3d_size)
1990428d7b3dSmrg				box.x1 = sna->render.max_3d_size;
1991428d7b3dSmrg
1992428d7b3dSmrg			if (box.y1 > sna->render.max_3d_size &&
1993428d7b3dSmrg			    box.y2 <= 2*sna->render.max_3d_size)
1994428d7b3dSmrg				box.y1 = sna->render.max_3d_size;
1995428d7b3dSmrg
1996428d7b3dSmrg			offset = box.x1 * op->dst.pixmap->drawable.bitsPerPixel / 8 / tile_width * tile_size;
1997428d7b3dSmrg		} else {
1998428d7b3dSmrg			if (sna->kgem.gen < 040) {
1999428d7b3dSmrg				box.y1 = box.y1 & ~3;
2000428d7b3dSmrg				box.y2 = ALIGN(box.y2, 4);
2001428d7b3dSmrg
2002428d7b3dSmrg				box.x1 = box.x1 & ~3;
2003428d7b3dSmrg				box.x2 = ALIGN(box.x2, 4);
2004428d7b3dSmrg			} else {
2005428d7b3dSmrg				box.y1 = box.y1 & ~1;
2006428d7b3dSmrg				box.y2 = ALIGN(box.y2, 2);
2007428d7b3dSmrg
2008428d7b3dSmrg				box.x1 = box.x1 & ~1;
2009428d7b3dSmrg				box.x2 = ALIGN(box.x2, 2);
2010428d7b3dSmrg			}
2011428d7b3dSmrg
2012428d7b3dSmrg			if (box.x1 > sna->render.max_3d_size &&
2013428d7b3dSmrg			    box.x2 <= 2*sna->render.max_3d_size)
2014428d7b3dSmrg				box.x1 = sna->render.max_3d_size;
2015428d7b3dSmrg
2016428d7b3dSmrg			if (box.y1 > sna->render.max_3d_size &&
2017428d7b3dSmrg			    box.y2 <= 2*sna->render.max_3d_size)
2018428d7b3dSmrg				box.y1 = sna->render.max_3d_size;
2019428d7b3dSmrg
2020428d7b3dSmrg			offset = box.x1 * op->dst.pixmap->drawable.bitsPerPixel / 8;
2021428d7b3dSmrg		}
2022428d7b3dSmrg
2023428d7b3dSmrg		if (box.y2 > op->dst.pixmap->drawable.height)
2024428d7b3dSmrg			box.y2 = op->dst.pixmap->drawable.height;
2025428d7b3dSmrg
2026428d7b3dSmrg		if (box.x2 > op->dst.pixmap->drawable.width)
2027428d7b3dSmrg			box.x2 = op->dst.pixmap->drawable.width;
2028428d7b3dSmrg
2029428d7b3dSmrg		w = box.x2 - box.x1;
2030428d7b3dSmrg		h = box.y2 - box.y1;
2031428d7b3dSmrg		DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d), max %d\n", __FUNCTION__,
2032428d7b3dSmrg		     box.x1, box.y1, box.x2, box.y2, w, h,
2033428d7b3dSmrg		     op->dst.pixmap->drawable.width,
2034428d7b3dSmrg		     op->dst.pixmap->drawable.height,
2035428d7b3dSmrg		     sna->render.max_3d_size));
2036428d7b3dSmrg		if (w <= sna->render.max_3d_size &&
2037428d7b3dSmrg		    h <= sna->render.max_3d_size) {
2038428d7b3dSmrg			t->box.x2 = t->box.x1 = op->dst.x;
2039428d7b3dSmrg			t->box.y2 = t->box.y1 = op->dst.y;
2040428d7b3dSmrg			t->real_bo = op->dst.bo;
2041428d7b3dSmrg			t->real_damage = op->damage;
2042428d7b3dSmrg			if (op->damage) {
2043428d7b3dSmrg				assert(!DAMAGE_IS_ALL(op->damage));
2044428d7b3dSmrg				t->damage = sna_damage_create();
2045428d7b3dSmrg				op->damage = &t->damage;
2046428d7b3dSmrg			}
2047428d7b3dSmrg
2048428d7b3dSmrg			/* How many tiles across are we? */
2049428d7b3dSmrg			op->dst.bo = kgem_create_proxy(&sna->kgem, op->dst.bo,
2050428d7b3dSmrg						       box.y1 * op->dst.bo->pitch + offset,
2051428d7b3dSmrg						       h * op->dst.bo->pitch);
2052428d7b3dSmrg			if (!op->dst.bo) {
2053428d7b3dSmrg				t->real_bo = NULL;
2054428d7b3dSmrg				if (t->damage)
2055428d7b3dSmrg					__sna_damage_destroy(t->damage);
2056428d7b3dSmrg				return false;
2057428d7b3dSmrg			}
2058428d7b3dSmrg
2059428d7b3dSmrg			assert(op->dst.bo != t->real_bo);
2060428d7b3dSmrg			op->dst.bo->pitch = t->real_bo->pitch;
2061428d7b3dSmrg
2062428d7b3dSmrg			op->dst.x -= box.x1;
2063428d7b3dSmrg			op->dst.y -= box.y1;
2064428d7b3dSmrg			op->dst.width  = w;
2065428d7b3dSmrg			op->dst.height = h;
2066428d7b3dSmrg			return true;
2067428d7b3dSmrg		}
2068428d7b3dSmrg	}
2069428d7b3dSmrg
2070428d7b3dSmrg	/* We can process the operation in a single pass,
2071428d7b3dSmrg	 * but the target is too large for the 3D pipeline.
2072428d7b3dSmrg	 * Copy into a smaller surface and replace afterwards.
2073428d7b3dSmrg	 */
2074428d7b3dSmrg	bo = kgem_create_2d(&sna->kgem,
2075428d7b3dSmrg			    width, height, bpp,
2076428d7b3dSmrg			    kgem_choose_tiling(&sna->kgem, I915_TILING_X,
2077428d7b3dSmrg					       width, height, bpp),
2078428d7b3dSmrg			    CREATE_TEMPORARY);
2079428d7b3dSmrg	if (!bo)
2080428d7b3dSmrg		return false;
2081428d7b3dSmrg
2082428d7b3dSmrg	t->box.x1 = x + op->dst.x;
2083428d7b3dSmrg	t->box.y1 = y + op->dst.y;
2084428d7b3dSmrg	t->box.x2 = bound(t->box.x1, width);
2085428d7b3dSmrg	t->box.y2 = bound(t->box.y1, height);
2086428d7b3dSmrg
2087428d7b3dSmrg	DBG(("%s: original box (%d, %d), (%d, %d)\n",
2088428d7b3dSmrg	     __FUNCTION__, t->box.x1, t->box.y1, t->box.x2, t->box.y2));
2089428d7b3dSmrg
2090428d7b3dSmrg	if (partial &&
2091428d7b3dSmrg	    !sna_blt_copy_boxes(sna, GXcopy,
2092428d7b3dSmrg				op->dst.bo, 0, 0,
2093428d7b3dSmrg				bo, -t->box.x1, -t->box.y1,
2094428d7b3dSmrg				bpp, &t->box, 1)) {
2095428d7b3dSmrg		kgem_bo_destroy(&sna->kgem, bo);
2096428d7b3dSmrg		return false;
2097428d7b3dSmrg	}
2098428d7b3dSmrg
2099428d7b3dSmrg	t->real_bo = op->dst.bo;
2100428d7b3dSmrg	t->real_damage = op->damage;
2101428d7b3dSmrg	if (op->damage) {
2102428d7b3dSmrg		assert(!DAMAGE_IS_ALL(op->damage));
2103428d7b3dSmrg		t->damage = sna_damage_create();
2104428d7b3dSmrg		op->damage = &t->damage;
2105428d7b3dSmrg	}
2106428d7b3dSmrg
2107428d7b3dSmrg	op->dst.bo = bo;
2108428d7b3dSmrg	op->dst.x = -x;
2109428d7b3dSmrg	op->dst.y = -y;
2110428d7b3dSmrg	op->dst.width  = width;
2111428d7b3dSmrg	op->dst.height = height;
2112428d7b3dSmrg	return true;
2113428d7b3dSmrg}
2114428d7b3dSmrg
2115428d7b3dSmrgvoid
2116428d7b3dSmrgsna_render_composite_redirect_done(struct sna *sna,
2117428d7b3dSmrg				   const struct sna_composite_op *op)
2118428d7b3dSmrg{
2119428d7b3dSmrg	const struct sna_composite_redirect *t = &op->redirect;
2120428d7b3dSmrg
2121428d7b3dSmrg	if (t->real_bo) {
2122428d7b3dSmrg		assert(op->dst.bo != t->real_bo);
2123428d7b3dSmrg
2124428d7b3dSmrg		if (t->box.x2 > t->box.x1) {
2125428d7b3dSmrg			bool ok;
2126428d7b3dSmrg
2127428d7b3dSmrg			DBG(("%s: copying temporary to dst\n", __FUNCTION__));
2128428d7b3dSmrg			ok = sna_blt_copy_boxes(sna, GXcopy,
2129428d7b3dSmrg						op->dst.bo, -t->box.x1, -t->box.y1,
2130428d7b3dSmrg						t->real_bo, 0, 0,
2131428d7b3dSmrg						op->dst.pixmap->drawable.bitsPerPixel,
2132428d7b3dSmrg						&t->box, 1);
2133428d7b3dSmrg			assert(ok);
2134428d7b3dSmrg			(void)ok;
2135428d7b3dSmrg		}
2136428d7b3dSmrg		if (t->damage) {
2137428d7b3dSmrg			DBG(("%s: combining damage (all? %d), offset=(%d, %d)\n",
2138428d7b3dSmrg			     __FUNCTION__, (int)DAMAGE_IS_ALL(t->damage),
2139428d7b3dSmrg			     t->box.x1, t->box.y1));
2140428d7b3dSmrg			sna_damage_combine(t->real_damage,
2141428d7b3dSmrg					   DAMAGE_PTR(t->damage),
2142428d7b3dSmrg					   t->box.x1, t->box.y1);
2143428d7b3dSmrg			__sna_damage_destroy(DAMAGE_PTR(t->damage));
2144428d7b3dSmrg		}
2145428d7b3dSmrg
2146428d7b3dSmrg		kgem_bo_destroy(&sna->kgem, op->dst.bo);
2147428d7b3dSmrg	}
2148428d7b3dSmrg}
2149428d7b3dSmrg
2150428d7b3dSmrgstatic bool
2151428d7b3dSmrgcopy_overlap(struct sna *sna, uint8_t alu,
2152428d7b3dSmrg	     const DrawableRec *draw, struct kgem_bo *bo,
2153428d7b3dSmrg	     int16_t src_dx, int16_t src_dy,
2154428d7b3dSmrg	     int16_t dst_dx, int16_t dst_dy,
2155428d7b3dSmrg	     const BoxRec *box, int n, const BoxRec *extents)
2156428d7b3dSmrg{
2157428d7b3dSmrg	ScreenPtr screen = draw->pScreen;
2158428d7b3dSmrg	struct kgem_bo *tmp_bo;
2159428d7b3dSmrg	PixmapPtr tmp;
2160428d7b3dSmrg	bool ret = false;
2161428d7b3dSmrg
2162428d7b3dSmrg	if (n == 0)
2163428d7b3dSmrg		return true;
2164428d7b3dSmrg
2165428d7b3dSmrg	DBG(("%s: %d x %dx%d src=(%d, %d), dst=(%d, %d)\n",
2166428d7b3dSmrg	     __FUNCTION__, n,
2167428d7b3dSmrg	     extents->x2 - extents->x1,
2168428d7b3dSmrg	     extents->y2 - extents->y1,
2169428d7b3dSmrg	     src_dx, src_dy,
2170428d7b3dSmrg	     dst_dx, dst_dy));
2171428d7b3dSmrg
2172428d7b3dSmrg	tmp = screen->CreatePixmap(screen,
2173428d7b3dSmrg				   extents->x2 - extents->x1,
2174428d7b3dSmrg				   extents->y2 - extents->y1,
2175428d7b3dSmrg				   draw->depth,
2176428d7b3dSmrg				   SNA_CREATE_SCRATCH);
2177428d7b3dSmrg	if (tmp == NULL)
2178428d7b3dSmrg		return false;
2179428d7b3dSmrg
2180428d7b3dSmrg	tmp_bo = __sna_pixmap_get_bo(tmp);
2181428d7b3dSmrg	assert(tmp_bo);
2182428d7b3dSmrg
2183428d7b3dSmrg	ret = (sna->render.copy_boxes(sna, GXcopy,
2184428d7b3dSmrg				      draw, bo, src_dx, src_dy,
2185428d7b3dSmrg				      &tmp->drawable, tmp_bo, -extents->x1, -extents->y1,
2186428d7b3dSmrg				      box, n , 0) &&
2187428d7b3dSmrg	       sna->render.copy_boxes(sna, alu,
2188428d7b3dSmrg				      &tmp->drawable, tmp_bo, -extents->x1, -extents->y1,
2189428d7b3dSmrg				      draw, bo, dst_dx, dst_dy,
2190428d7b3dSmrg				      box, n , 0));
2191428d7b3dSmrg
2192428d7b3dSmrg	screen->DestroyPixmap(tmp);
2193428d7b3dSmrg	return ret;
2194428d7b3dSmrg}
2195428d7b3dSmrgbool
2196428d7b3dSmrgsna_render_copy_boxes__overlap(struct sna *sna, uint8_t alu,
2197428d7b3dSmrg			       const DrawableRec *draw, struct kgem_bo *bo,
2198428d7b3dSmrg			       int16_t src_dx, int16_t src_dy,
2199428d7b3dSmrg			       int16_t dst_dx, int16_t dst_dy,
2200428d7b3dSmrg			       const BoxRec *box, int n, const BoxRec *extents)
2201428d7b3dSmrg{
2202428d7b3dSmrg	bool ret = false;
2203428d7b3dSmrg	RegionRec overlap, non_overlap;
2204428d7b3dSmrg	pixman_region16_t region;
2205428d7b3dSmrg	pixman_box16_t stack_boxes[64], *boxes = stack_boxes;
2206428d7b3dSmrg	int num_boxes, i;
2207428d7b3dSmrg
2208428d7b3dSmrg	DBG(("%s: pixmap=%ld, handle=%d, %d x [(%d, %d), (%d, %d)], dst=(%d, %d), src=(%d, %d)\n",
2209428d7b3dSmrg	     __FUNCTION__, draw->serialNumber, bo->handle,
2210428d7b3dSmrg	     n, extents->x1, extents->y1, extents->x2, extents->y2,
2211428d7b3dSmrg	     src_dx, src_dy, dst_dx, dst_dy));
2212428d7b3dSmrg
2213428d7b3dSmrg	if ((dst_dx - src_dx < 4 && src_dx - dst_dx < 4) &&
2214428d7b3dSmrg	    (dst_dy - src_dy < 4 && src_dy - dst_dy < 4))
2215428d7b3dSmrg		return copy_overlap(sna, alu, draw, bo,
2216428d7b3dSmrg				    src_dx, src_dy,
2217428d7b3dSmrg				    dst_dx, dst_dy,
2218428d7b3dSmrg				    box, n, extents);
2219428d7b3dSmrg
2220428d7b3dSmrg	if (n > ARRAY_SIZE(stack_boxes)) {
2221428d7b3dSmrg		boxes = malloc(sizeof(pixman_box16_t) * n);
2222428d7b3dSmrg		if (boxes == NULL)
2223428d7b3dSmrg			return copy_overlap(sna, alu, draw, bo,
2224428d7b3dSmrg					    src_dx, src_dy,
2225428d7b3dSmrg					    dst_dx, dst_dy,
2226428d7b3dSmrg					    box, n, extents);
2227428d7b3dSmrg	}
2228428d7b3dSmrg
2229428d7b3dSmrg	region.extents.x1 = extents->x1 + dst_dx;
2230428d7b3dSmrg	region.extents.x2 = extents->x2 + dst_dx;
2231428d7b3dSmrg	region.extents.y1 = extents->y1 + dst_dy;
2232428d7b3dSmrg	region.extents.y2 = extents->y2 + dst_dy;
2233428d7b3dSmrg
2234428d7b3dSmrg	for (i = num_boxes = 0; i < n; i++) {
2235428d7b3dSmrg		boxes[num_boxes].x1 = box[i].x1 + dst_dx;
2236428d7b3dSmrg		if (boxes[num_boxes].x1 < region.extents.x1)
2237428d7b3dSmrg			boxes[num_boxes].x1 = region.extents.x1;
2238428d7b3dSmrg
2239428d7b3dSmrg		boxes[num_boxes].y1 = box[i].y1 + dst_dy;
2240428d7b3dSmrg		if (boxes[num_boxes].y1 < region.extents.y1)
2241428d7b3dSmrg			boxes[num_boxes].y1 = region.extents.y1;
2242428d7b3dSmrg
2243428d7b3dSmrg		boxes[num_boxes].x2 = box[i].x2 + dst_dx;
2244428d7b3dSmrg		if (boxes[num_boxes].x2 > region.extents.x2)
2245428d7b3dSmrg			boxes[num_boxes].x2 = region.extents.x2;
2246428d7b3dSmrg
2247428d7b3dSmrg		boxes[num_boxes].y2 = box[i].y2 + dst_dy;
2248428d7b3dSmrg		if (boxes[num_boxes].y2 > region.extents.y2)
2249428d7b3dSmrg			boxes[num_boxes].y2 = region.extents.y2;
2250428d7b3dSmrg
2251428d7b3dSmrg		if (boxes[num_boxes].x2 > boxes[num_boxes].x1 &&
2252428d7b3dSmrg		    boxes[num_boxes].y2 > boxes[num_boxes].y1)
2253428d7b3dSmrg			num_boxes++;
2254428d7b3dSmrg	}
2255428d7b3dSmrg
2256428d7b3dSmrg	if (num_boxes == 0) {
2257428d7b3dSmrg		ret = true;
2258428d7b3dSmrg		goto cleanup_boxes;
2259428d7b3dSmrg	}
2260428d7b3dSmrg
2261428d7b3dSmrg	if (!pixman_region_init_rects(&region, boxes, num_boxes))
2262428d7b3dSmrg		goto cleanup_boxes;
2263428d7b3dSmrg
2264428d7b3dSmrg	overlap.extents.x1 = extents->x1 + src_dx;
2265428d7b3dSmrg	overlap.extents.x2 = extents->x2 + src_dx;
2266428d7b3dSmrg	overlap.extents.y1 = extents->y1 + src_dy;
2267428d7b3dSmrg	overlap.extents.y2 = extents->y2 + src_dy;
2268428d7b3dSmrg	overlap.data = NULL;
2269428d7b3dSmrg
2270428d7b3dSmrg	RegionIntersect(&overlap, &overlap, &region);
2271428d7b3dSmrg	DBG(("%s: overlapping extents: (%d, %d), (%d, %d) x %d\n",
2272428d7b3dSmrg	     __FUNCTION__,
2273428d7b3dSmrg	     overlap.extents.x1, overlap.extents.y1,
2274428d7b3dSmrg	     overlap.extents.x2, overlap.extents.y2,
2275428d7b3dSmrg	     region_num_rects(&overlap)));
2276428d7b3dSmrg
2277428d7b3dSmrg	RegionNull(&non_overlap);
2278428d7b3dSmrg	RegionSubtract(&non_overlap, &region, &overlap);
2279428d7b3dSmrg	DBG(("%s: non-overlapping extents: (%d, %d), (%d, %d) x %d\n",
2280428d7b3dSmrg	     __FUNCTION__,
2281428d7b3dSmrg	     non_overlap.extents.x1, non_overlap.extents.y1,
2282428d7b3dSmrg	     non_overlap.extents.x2, non_overlap.extents.y2,
2283428d7b3dSmrg	     region_num_rects(&non_overlap)));
2284428d7b3dSmrg
2285428d7b3dSmrg	n = region_num_rects(&non_overlap);
2286428d7b3dSmrg	box = region_rects(&non_overlap);
2287428d7b3dSmrg	if (n && !sna->render.copy_boxes(sna, alu,
2288428d7b3dSmrg					 draw, bo, -dst_dx + src_dx, -dst_dy + src_dy,
2289428d7b3dSmrg					 draw, bo, 0, 0,
2290428d7b3dSmrg					 box, n , COPY_NO_OVERLAP))
2291428d7b3dSmrg		goto cleanup_boxes;
2292428d7b3dSmrg
2293428d7b3dSmrg	n = region_num_rects(&overlap);
2294428d7b3dSmrg	box = region_rects(&overlap);
2295428d7b3dSmrg	ret = copy_overlap(sna, alu, draw, bo,
2296428d7b3dSmrg			   -dst_dx + src_dx, -dst_dy + src_dy,
2297428d7b3dSmrg			   0, 0,
2298428d7b3dSmrg			   box, n, &overlap.extents);
2299428d7b3dSmrg
2300428d7b3dSmrgcleanup_boxes:
2301428d7b3dSmrg	if (boxes != stack_boxes)
2302428d7b3dSmrg		free(boxes);
2303428d7b3dSmrg
2304428d7b3dSmrg	return ret;
2305428d7b3dSmrg}
2306428d7b3dSmrg
2307428d7b3dSmrgstatic bool can_copy_cpu(struct sna *sna,
2308428d7b3dSmrg			 struct kgem_bo *src,
2309428d7b3dSmrg			 struct kgem_bo *dst)
2310428d7b3dSmrg{
2311428d7b3dSmrg	if (src->tiling != dst->tiling)
2312428d7b3dSmrg		return false;
2313428d7b3dSmrg
2314428d7b3dSmrg	if (src->pitch != dst->pitch)
2315428d7b3dSmrg		return false;
2316428d7b3dSmrg
2317428d7b3dSmrg	if (!kgem_bo_can_map__cpu(&sna->kgem, src, false))
2318428d7b3dSmrg		return false;
2319428d7b3dSmrg
2320428d7b3dSmrg	if (!kgem_bo_can_map__cpu(&sna->kgem, dst, true))
2321428d7b3dSmrg		return false;
2322428d7b3dSmrg
2323428d7b3dSmrg	DBG(("%s -- yes, src handle=%d, dst handle=%d\n", __FUNCTION__, src->handle, dst->handle));
2324428d7b3dSmrg	return true;
2325428d7b3dSmrg}
2326428d7b3dSmrg
2327428d7b3dSmrgbool
2328428d7b3dSmrgmemcpy_copy_boxes(struct sna *sna, uint8_t op,
2329428d7b3dSmrg		  const DrawableRec *src_draw, struct kgem_bo *src_bo, int16_t sx, int16_t sy,
2330428d7b3dSmrg		  const DrawableRec *dst_draw, struct kgem_bo *dst_bo, int16_t dx, int16_t dy,
2331428d7b3dSmrg		  const BoxRec *box, int n, unsigned flags)
2332428d7b3dSmrg{
2333428d7b3dSmrg	void *dst, *src;
2334428d7b3dSmrg	bool clipped;
2335428d7b3dSmrg
2336428d7b3dSmrg	if (op != GXcopy)
2337428d7b3dSmrg		return false;
2338428d7b3dSmrg
2339428d7b3dSmrg	clipped = (n > 1 ||
2340428d7b3dSmrg		   box->x1 + dx > 0 ||
2341428d7b3dSmrg		   box->y1 + dy > 0 ||
2342428d7b3dSmrg		   box->x2 + dx < dst_draw->width ||
2343428d7b3dSmrg		   box->y2 + dy < dst_draw->height);
2344428d7b3dSmrg
2345428d7b3dSmrg	dst = src = NULL;
2346428d7b3dSmrg	if (!clipped && can_copy_cpu(sna, src_bo, dst_bo)) {
2347428d7b3dSmrg		dst = kgem_bo_map__cpu(&sna->kgem, dst_bo);
2348428d7b3dSmrg		src = kgem_bo_map__cpu(&sna->kgem, src_bo);
2349428d7b3dSmrg	}
2350428d7b3dSmrg
2351428d7b3dSmrg	if (dst == NULL || src == NULL) {
2352428d7b3dSmrg		dst = kgem_bo_map__gtt(&sna->kgem, dst_bo);
2353428d7b3dSmrg		src = kgem_bo_map__gtt(&sna->kgem, src_bo);
2354428d7b3dSmrg		if (dst == NULL || src == NULL)
2355428d7b3dSmrg			return false;
2356428d7b3dSmrg	} else {
2357428d7b3dSmrg		kgem_bo_sync__cpu_full(&sna->kgem, dst_bo, true);
2358428d7b3dSmrg		kgem_bo_sync__cpu_full(&sna->kgem, src_bo, false);
2359428d7b3dSmrg	}
2360428d7b3dSmrg
2361428d7b3dSmrg	DBG(("%s: src(%d, %d), dst(%d, %d) x %d\n",
2362428d7b3dSmrg	     __FUNCTION__, sx, sy, dx, dy, n));
2363428d7b3dSmrg
2364428d7b3dSmrg	if (sigtrap_get() == 0) {
2365428d7b3dSmrg		do {
2366428d7b3dSmrg			memcpy_blt(src, dst, dst_draw->bitsPerPixel,
2367428d7b3dSmrg				   src_bo->pitch, dst_bo->pitch,
2368428d7b3dSmrg				   box->x1 + sx, box->y1 + sy,
2369428d7b3dSmrg				   box->x1 + dx, box->y1 + dy,
2370428d7b3dSmrg				   box->x2 - box->x1, box->y2 - box->y1);
2371428d7b3dSmrg			box++;
2372428d7b3dSmrg		} while (--n);
2373428d7b3dSmrg		sigtrap_put();
2374428d7b3dSmrg	}
2375428d7b3dSmrg
2376428d7b3dSmrg	return true;
2377428d7b3dSmrg}
2378428d7b3dSmrg
2379428d7b3dSmrgvoid
2380428d7b3dSmrgsna_render_mark_wedged(struct sna *sna)
2381428d7b3dSmrg{
2382428d7b3dSmrg	sna->render.copy_boxes = memcpy_copy_boxes;
2383428d7b3dSmrg}
2384