1/*
2 * Copyright © 2011 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *
23 * Authors:
24 *    Chris Wilson <chris@chris-wilson.co.uk>
25 *
26 */
27
28#ifdef HAVE_CONFIG_H
29#include "config.h"
30#endif
31
32#include "sna.h"
33#include "sna_render.h"
34#include "sna_render_inline.h"
35#include "fb/fbpict.h"
36
37#define NO_REDIRECT 0
38#define NO_CONVERT 0
39#define NO_FIXUP 0
40#define NO_EXTRACT 0
41
42#define DBG_FORCE_UPLOAD 0
43#define DBG_NO_CPU_BO 0
44
45#define alphaless(format) PICT_FORMAT(PICT_FORMAT_BPP(format),		\
46				      PICT_FORMAT_TYPE(format),		\
47				      0,				\
48				      PICT_FORMAT_R(format),		\
49				      PICT_FORMAT_G(format),		\
50				      PICT_FORMAT_B(format))
51
52CARD32
53sna_format_for_depth(int depth)
54{
55	switch (depth) {
56	case 1: return PICT_a1;
57	case 4: return PICT_x4a4;
58	case 8: return PICT_a8;
59	case 15: return PICT_x1r5g5b5;
60	case 16: return PICT_r5g6b5;
61	default: assert(0);
62	case 24: return PICT_x8r8g8b8;
63#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,6,99,900,0)
64	case 30: return PICT_x2r10g10b10;
65#endif
66	case 32: return PICT_a8r8g8b8;
67	}
68}
69
70CARD32
71sna_render_format_for_depth(int depth)
72{
73	switch (depth) {
74	case 1: return PIXMAN_a1;
75	case 4: return PIXMAN_a4;
76	case 8: return PIXMAN_a8;
77	case 15: return PIXMAN_a1r5g5b5;
78	case 16: return PIXMAN_r5g6b5;
79	case 30: return PIXMAN_a2r10g10b10;
80	default: assert(0);
81	case 24:
82	case 32: return PIXMAN_a8r8g8b8;
83	}
84}
85
86static bool
87no_render_composite(struct sna *sna,
88		    uint8_t op,
89		    PicturePtr src,
90		    PicturePtr mask,
91		    PicturePtr dst,
92		    int16_t src_x, int16_t src_y,
93		    int16_t mask_x, int16_t mask_y,
94		    int16_t dst_x, int16_t dst_y,
95		    int16_t width, int16_t height,
96		    unsigned flags,
97		    struct sna_composite_op *tmp)
98{
99	DBG(("%s (op=%d, mask? %d)\n", __FUNCTION__, op, mask != NULL));
100
101	if (mask)
102		return false;
103
104	if (!is_gpu(sna, dst->pDrawable, PREFER_GPU_BLT) &&
105	    (src->pDrawable == NULL || !is_gpu(sna, src->pDrawable, PREFER_GPU_BLT)))
106		return false;
107
108	return sna_blt_composite(sna,
109				 op, src, dst,
110				 src_x, src_y,
111				 dst_x, dst_y,
112				 width, height,
113				 flags | COMPOSITE_FALLBACK, tmp);
114	(void)mask_x;
115	(void)mask_y;
116}
117
118static bool
119no_render_check_composite_spans(struct sna *sna,
120				uint8_t op, PicturePtr src, PicturePtr dst,
121				int16_t width,  int16_t height, unsigned flags)
122{
123	return false;
124}
125
126static bool
127no_render_copy_boxes(struct sna *sna, uint8_t alu,
128		     const DrawableRec *src, struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy,
129		     const DrawableRec *dst, struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy,
130		     const BoxRec *box, int n, unsigned flags)
131{
132	DBG(("%s (n=%d)\n", __FUNCTION__, n));
133
134	if (!sna_blt_compare_depth(src, dst))
135		return false;
136
137	return sna_blt_copy_boxes(sna, alu,
138				  src_bo, src_dx, src_dy,
139				  dst_bo, dst_dx, dst_dy,
140				  dst->bitsPerPixel,
141				  box, n);
142}
143
144static bool
145no_render_copy(struct sna *sna, uint8_t alu,
146		 PixmapPtr src, struct kgem_bo *src_bo,
147		 PixmapPtr dst, struct kgem_bo *dst_bo,
148		 struct sna_copy_op *tmp)
149{
150	DBG(("%s ()\n", __FUNCTION__));
151
152	if (sna_blt_compare_depth(&src->drawable, &dst->drawable) &&
153	    sna_blt_copy(sna, alu,
154			 src_bo, dst_bo, dst->drawable.bitsPerPixel,
155			 tmp))
156		return true;
157
158	return false;
159}
160
161static bool
162no_render_fill_boxes(struct sna *sna,
163		     CARD8 op,
164		     PictFormat format,
165		     const xRenderColor *color,
166		     const DrawableRec *dst, struct kgem_bo *dst_bo,
167		     const BoxRec *box, int n)
168{
169	uint8_t alu = GXcopy;
170	uint32_t pixel;
171
172	DBG(("%s (op=%d, color=(%04x,%04x,%04x, %04x))\n",
173	     __FUNCTION__, op,
174	     color->red, color->green, color->blue, color->alpha));
175
176	if (op == PictOpClear) {
177		pixel = 0;
178		alu = GXclear;
179		op = PictOpSrc;
180	}
181
182	if (op == PictOpOver) {
183		if ((color->alpha >= 0xff00))
184			op = PictOpSrc;
185	}
186
187	if (op != PictOpSrc)
188		return false;
189
190	if (alu == GXcopy &&
191	    !sna_get_pixel_from_rgba(&pixel,
192				     color->red,
193				     color->green,
194				     color->blue,
195				     color->alpha,
196				     format))
197		return false;
198
199	return sna_blt_fill_boxes(sna, alu,
200				  dst_bo, dst->bitsPerPixel,
201				  pixel, box, n);
202}
203
204static bool
205no_render_fill(struct sna *sna, uint8_t alu,
206	       PixmapPtr dst, struct kgem_bo *dst_bo,
207	       uint32_t color, unsigned flags,
208	       struct sna_fill_op *tmp)
209{
210	DBG(("%s (alu=%d, color=%08x)\n", __FUNCTION__, alu, color));
211	return sna_blt_fill(sna, alu,
212			    dst_bo, dst->drawable.bitsPerPixel,
213			    color,
214			    tmp);
215}
216
217static bool
218no_render_fill_one(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo,
219		   uint32_t color,
220		   int16_t x1, int16_t y1, int16_t x2, int16_t y2,
221		   uint8_t alu)
222{
223	BoxRec box;
224
225	box.x1 = x1;
226	box.y1 = y1;
227	box.x2 = x2;
228	box.y2 = y2;
229
230	DBG(("%s (alu=%d, color=%08x) (%d,%d), (%d, %d)\n",
231	     __FUNCTION__, alu, color, x1, y1, x2, y2));
232	return sna_blt_fill_boxes(sna, alu,
233				  bo, dst->drawable.bitsPerPixel,
234				  color, &box, 1);
235}
236
237static bool
238no_render_clear(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo)
239{
240	DBG(("%s: pixmap=%ld %dx%d\n", __FUNCTION__,
241	     dst->drawable.serialNumber,
242	     dst->drawable.width,
243	     dst->drawable.height));
244	return sna->render.fill_one(sna, dst, bo, 0,
245				    0, 0, dst->drawable.width, dst->drawable.height,
246				    GXclear);
247}
248
249static void no_render_reset(struct sna *sna)
250{
251	(void)sna;
252}
253
254static void no_render_flush(struct sna *sna)
255{
256	(void)sna;
257}
258
259static void
260no_render_context_switch(struct kgem *kgem,
261			 int new_mode)
262{
263	if (!kgem->nbatch)
264		return;
265
266	if (kgem_ring_is_idle(kgem, kgem->ring)) {
267		DBG(("%s: GPU idle, flushing\n", __FUNCTION__));
268		_kgem_submit(kgem);
269	}
270
271	(void)new_mode;
272}
273
274static void
275no_render_fini(struct sna *sna)
276{
277	(void)sna;
278}
279
280const char *no_render_init(struct sna *sna)
281{
282	struct sna_render *render = &sna->render;
283
284	memset (render, 0, sizeof (*render));
285
286	render->prefer_gpu = PREFER_GPU_BLT;
287
288	render->vertices = render->vertex_data;
289	render->vertex_size = ARRAY_SIZE(render->vertex_data);
290
291	render->composite = no_render_composite;
292	render->check_composite_spans = no_render_check_composite_spans;
293
294	render->copy_boxes = no_render_copy_boxes;
295	render->copy = no_render_copy;
296
297	render->fill_boxes = no_render_fill_boxes;
298	render->fill = no_render_fill;
299	render->fill_one = no_render_fill_one;
300	render->clear = no_render_clear;
301
302	render->reset = no_render_reset;
303	render->flush = no_render_flush;
304	render->fini = no_render_fini;
305
306	sna->kgem.context_switch = no_render_context_switch;
307	if (sna->kgem.has_blt)
308		sna->kgem.ring = KGEM_BLT;
309
310	sna_vertex_init(sna);
311	return "generic";
312}
313
314static struct kgem_bo *
315use_cpu_bo(struct sna *sna, PixmapPtr pixmap, const BoxRec *box, bool blt)
316{
317	struct sna_pixmap *priv;
318
319	if (DBG_NO_CPU_BO)
320		return NULL;
321
322	priv = sna_pixmap(pixmap);
323	if (priv == NULL || priv->cpu_bo == NULL) {
324		DBG(("%s: no cpu bo\n", __FUNCTION__));
325		return NULL;
326	}
327
328	if (!blt && priv->cpu_bo->snoop && priv->source_count > SOURCE_BIAS) {
329		DBG(("%s: promoting snooped CPU bo due to reuse\n",
330		     __FUNCTION__));
331		return NULL;
332	}
333
334	if (priv->gpu_bo) {
335		switch (sna_damage_contains_box(&priv->cpu_damage, box)) {
336		case PIXMAN_REGION_OUT:
337			DBG(("%s: has GPU bo and no damage to upload\n",
338			     __FUNCTION__));
339			return NULL;
340
341		case PIXMAN_REGION_IN:
342			DBG(("%s: has GPU bo but box is completely on CPU\n",
343			     __FUNCTION__));
344			break;
345		default:
346			if (kgem_bo_is_busy(priv->gpu_bo)){
347				DBG(("%s: box is partially damaged on the CPU, and the GPU is busy\n",
348				     __FUNCTION__));
349				return NULL;
350			}
351			if (sna_damage_contains_box(&priv->gpu_damage,
352						    box) != PIXMAN_REGION_OUT) {
353				DBG(("%s: box is damaged on the GPU\n",
354				     __FUNCTION__));
355				return NULL;
356			}
357			break;
358		}
359	}
360
361	if (!blt) {
362		int w = box->x2 - box->x1;
363		int h = box->y2 - box->y1;
364
365		if (w < pixmap->drawable.width ||
366		    h < pixmap->drawable.height ||
367		    priv->source_count != SOURCE_BIAS) {
368			bool want_tiling;
369
370			if (priv->cpu_bo->pitch >= 4096) {
371				DBG(("%s: size=%dx%d, promoting reused (%d) CPU bo due to TLB miss (%dx%d, pitch=%d)\n",
372				     __FUNCTION__, w, h, priv->source_count,
373				     pixmap->drawable.width,
374				     pixmap->drawable.height,
375				     priv->cpu_bo->pitch));
376				return NULL;
377			}
378
379			if (priv->gpu_bo)
380				want_tiling = priv->gpu_bo->tiling != I915_TILING_NONE;
381			else
382				want_tiling = kgem_choose_tiling(&sna->kgem,
383								 I915_TILING_Y,
384								 pixmap->drawable.width,
385								 pixmap->drawable.height,
386								 pixmap->drawable.bitsPerPixel) != I915_TILING_NONE;
387			if (want_tiling &&
388			    priv->source_count*w*h >= (int)pixmap->drawable.width * pixmap->drawable.height) {
389				DBG(("%s: pitch (%d) requires tiling\n",
390				     __FUNCTION__, priv->cpu_bo->pitch));
391				return NULL;
392			}
393		}
394	}
395
396	add_shm_flush(sna, priv);
397
398	DBG(("%s for box=(%d, %d), (%d, %d)\n",
399	     __FUNCTION__, box->x1, box->y1, box->x2, box->y2));
400	++priv->source_count;
401	return priv->cpu_bo;
402}
403
404static struct kgem_bo *
405move_to_gpu(PixmapPtr pixmap, const BoxRec *box, bool blt)
406{
407	struct sna_pixmap *priv;
408	int count, w, h;
409	bool migrate = false;
410
411	if (DBG_FORCE_UPLOAD > 0)
412		return NULL;
413
414	priv = sna_pixmap(pixmap);
415	if (priv == NULL) {
416		DBG(("%s: not migrating unattached pixmap=%ld\n",
417		     __FUNCTION__, pixmap->drawable.serialNumber));
418		return NULL;
419	}
420
421	if (priv->shm)
422		blt = true;
423
424	if (priv->gpu_bo) {
425		if (priv->cpu_damage &&
426		    sna_damage_contains_box(&priv->cpu_damage,
427					    box) != PIXMAN_REGION_OUT)
428			goto upload;
429
430		return priv->gpu_bo;
431	}
432
433	if (priv->cpu_damage == NULL) {
434		DBG(("%s: not migrating uninitialised pixmap=%ld\n",
435		     __FUNCTION__, pixmap->drawable.serialNumber));
436		return NULL;
437	}
438
439	if (pixmap->usage_hint) {
440		DBG(("%s: not migrating pixmap=%ld due to usage_hint=%d\n",
441		     __FUNCTION__,
442		     pixmap->drawable.serialNumber,
443		     pixmap->usage_hint));
444		return NULL;
445	}
446
447	if (DBG_FORCE_UPLOAD < 0) {
448		if (!sna_pixmap_force_to_gpu(pixmap,
449					     blt ? MOVE_READ : MOVE_SOURCE_HINT | MOVE_ASYNC_HINT | MOVE_READ))
450			return NULL;
451
452		return priv->gpu_bo;
453	}
454
455	w = box->x2 - box->x1;
456	h = box->y2 - box->y1;
457	if (priv->cpu_bo && !priv->cpu_bo->flush) {
458		migrate = true;
459	} else if (w == pixmap->drawable.width && h == pixmap->drawable.height) {
460		migrate = priv->source_count++ > SOURCE_BIAS;
461
462		DBG(("%s: migrating whole pixmap (%dx%d) for source (%d,%d),(%d,%d), count %d? %d\n",
463		     __FUNCTION__,
464		     pixmap->drawable.width, pixmap->drawable.height,
465		     box->x1, box->y1, box->x2, box->y2, priv->source_count,
466		     migrate));
467	} else if (kgem_choose_tiling(&to_sna_from_pixmap(pixmap)->kgem,
468				      blt ? I915_TILING_X : I915_TILING_Y, w, h,
469				      pixmap->drawable.bitsPerPixel) != I915_TILING_NONE) {
470		count = priv->source_count++;
471		if ((priv->create & KGEM_CAN_CREATE_GPU) == 0)
472			count -= SOURCE_BIAS;
473
474		DBG(("%s: migrate box (%d, %d), (%d, %d)? source count=%d, fraction=%d/%d [%d]\n",
475		     __FUNCTION__,
476		     box->x1, box->y1, box->x2, box->y2,
477		     count, w*h,
478		     pixmap->drawable.width * pixmap->drawable.height,
479		     pixmap->drawable.width * pixmap->drawable.height / (w*h)));
480
481		migrate = count*w*h > pixmap->drawable.width * pixmap->drawable.height;
482	}
483
484	if (!migrate)
485		return NULL;
486
487upload:
488	if (blt) {
489		if (!sna_pixmap_move_area_to_gpu(pixmap, box,
490						 __MOVE_FORCE | MOVE_READ))
491			return NULL;
492	} else {
493		if (!sna_pixmap_move_to_gpu(pixmap,
494					    __MOVE_FORCE | MOVE_ASYNC_HINT | MOVE_SOURCE_HINT | MOVE_READ))
495			return NULL;
496	}
497
498	return priv->gpu_bo;
499}
500
501static struct kgem_bo *upload(struct sna *sna,
502			      struct sna_composite_channel *channel,
503			      PixmapPtr pixmap,
504			      const BoxRec *box)
505{
506	struct sna_pixmap *priv;
507	struct kgem_bo *bo;
508
509	DBG(("%s: box=(%d, %d), (%d, %d), pixmap=%dx%d\n",
510	     __FUNCTION__, box->x1, box->y1, box->x2, box->y2, pixmap->drawable.width, pixmap->drawable.height));
511	assert(box->x1 >= 0);
512	assert(box->y1 >= 0);
513	assert(box->x2 <= pixmap->drawable.width);
514	assert(box->y2 <= pixmap->drawable.height);
515
516	priv = sna_pixmap(pixmap);
517	if (priv) {
518		RegionRec region;
519
520		if (priv->cpu_damage == NULL)
521			return NULL; /* uninitialised */
522
523		region.extents = *box;
524		region.data = NULL;
525		if (!sna_drawable_move_region_to_cpu(&pixmap->drawable,
526						     &region, MOVE_READ))
527			return NULL;
528
529		assert(!priv->mapped);
530		if (pixmap->devPrivate.ptr == NULL)
531			return NULL; /* uninitialised */
532	}
533
534	bo = kgem_upload_source_image(&sna->kgem,
535				      pixmap->devPrivate.ptr, box,
536				      pixmap->devKind,
537				      pixmap->drawable.bitsPerPixel);
538	if (channel && bo) {
539		channel->width  = box->x2 - box->x1;
540		channel->height = box->y2 - box->y1;
541		channel->offset[0] -= box->x1;
542		channel->offset[1] -= box->y1;
543
544		if (priv &&
545		    pixmap->usage_hint == 0 &&
546		    channel->width  == pixmap->drawable.width &&
547		    channel->height == pixmap->drawable.height) {
548			DBG(("%s: adding upload cache to pixmap=%ld\n",
549			     __FUNCTION__, pixmap->drawable.serialNumber));
550			assert(priv->gpu_damage == NULL);
551			assert(priv->gpu_bo == NULL);
552			assert(bo->proxy != NULL);
553			sna_damage_all(&priv->cpu_damage, pixmap);
554			kgem_proxy_bo_attach(bo, &priv->gpu_bo);
555		}
556	}
557
558	return bo;
559}
560
561struct kgem_bo *
562__sna_render_pixmap_bo(struct sna *sna,
563		       PixmapPtr pixmap,
564		       const BoxRec *box,
565		       bool blt)
566{
567	struct kgem_bo *bo;
568
569	bo = use_cpu_bo(sna, pixmap, box, blt);
570	if (bo == NULL) {
571		bo = move_to_gpu(pixmap, box, blt);
572		if (bo == NULL)
573			return NULL;
574	}
575
576	return bo;
577}
578
579int
580sna_render_pixmap_bo(struct sna *sna,
581		     struct sna_composite_channel *channel,
582		     PixmapPtr pixmap,
583		     int16_t x, int16_t y,
584		     int16_t w, int16_t h,
585		     int16_t dst_x, int16_t dst_y)
586{
587	struct sna_pixmap *priv;
588	BoxRec box;
589
590	DBG(("%s pixmap=%ld, (%d, %d)x(%d, %d)/(%d, %d)\n",
591	     __FUNCTION__, pixmap->drawable.serialNumber,
592	     x, y, w,h, pixmap->drawable.width, pixmap->drawable.height));
593
594	channel->width  = pixmap->drawable.width;
595	channel->height = pixmap->drawable.height;
596	channel->offset[0] = x - dst_x;
597	channel->offset[1] = y - dst_y;
598
599	priv = sna_pixmap(pixmap);
600	if (priv) {
601		if (priv->gpu_bo &&
602		    (DAMAGE_IS_ALL(priv->gpu_damage) || !priv->cpu_damage ||
603		     priv->gpu_bo->proxy)) {
604			DBG(("%s: GPU all damaged\n", __FUNCTION__));
605			channel->bo = priv->gpu_bo;
606			goto done;
607		}
608
609		if (priv->cpu_bo &&
610		    (DAMAGE_IS_ALL(priv->cpu_damage) || !priv->gpu_damage) &&
611		    !priv->cpu_bo->snoop && priv->cpu_bo->pitch < 4096) {
612			DBG(("%s: CPU all damaged\n", __FUNCTION__));
613			channel->bo = priv->cpu_bo;
614			add_shm_flush(sna, priv);
615			goto done;
616		}
617	}
618
619	/* XXX handle transformed repeat */
620	if (w == 0 || h == 0 || channel->transform) {
621		box.x1 = box.y1 = 0;
622		box.x2 = pixmap->drawable.width;
623		box.y2 = pixmap->drawable.height;
624	} else {
625		box.x1 = x;
626		box.y1 = y;
627		box.x2 = bound(x, w);
628		box.y2 = bound(y, h);
629
630		if (channel->repeat == RepeatNone || channel->repeat == RepeatPad) {
631			if (box.x1 < 0)
632				box.x1 = 0;
633			if (box.y1 < 0)
634				box.y1 = 0;
635			if (box.x2 > pixmap->drawable.width)
636				box.x2 = pixmap->drawable.width;
637			if (box.y2 > pixmap->drawable.height)
638				box.y2 = pixmap->drawable.height;
639		} else {
640			if (box.x1 < 0 || box.x2 > pixmap->drawable.width)
641				box.x1 = 0, box.x2 = pixmap->drawable.width;
642			if (box.y1 < 0 || box.y2 > pixmap->drawable.height)
643				box.y1 = 0, box.y2 = pixmap->drawable.height;
644		}
645	}
646
647	w = box.x2 - box.x1;
648	h = box.y2 - box.y1;
649	DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d)\n", __FUNCTION__,
650	     box.x1, box.y1, box.x2, box.y2, w, h,
651	     pixmap->drawable.width, pixmap->drawable.height));
652	if (w <= 0 || h <= 0) {
653		DBG(("%s: sample extents outside of texture -> clear\n",
654		     __FUNCTION__));
655		return 0;
656	}
657
658	DBG(("%s: offset=(%d, %d), size=(%d, %d)\n",
659	     __FUNCTION__,
660	     channel->offset[0], channel->offset[1],
661	     pixmap->drawable.width, pixmap->drawable.height));
662
663	channel->bo = __sna_render_pixmap_bo(sna, pixmap, &box, false);
664	if (channel->bo == NULL) {
665		DBG(("%s: uploading CPU box (%d, %d), (%d, %d)\n",
666		     __FUNCTION__, box.x1, box.y1, box.x2, box.y2));
667		channel->bo = upload(sna, channel, pixmap, &box);
668		if (channel->bo == NULL)
669			return 0;
670	} else {
671done:
672		kgem_bo_reference(channel->bo);
673	}
674
675	channel->scale[0] = 1.f / channel->width;
676	channel->scale[1] = 1.f / channel->height;
677	return 1;
678}
679
680static int sna_render_picture_downsample(struct sna *sna,
681					 PicturePtr picture,
682					 struct sna_composite_channel *channel,
683					 const int16_t x, const int16_t y,
684					 const int16_t w, const int16_t h,
685					 const int16_t dst_x, const int16_t dst_y)
686{
687	PixmapPtr pixmap = get_drawable_pixmap(picture->pDrawable);
688	ScreenPtr screen = pixmap->drawable.pScreen;
689	PicturePtr tmp_src, tmp_dst;
690	PictFormatPtr format;
691	struct sna_pixmap *priv;
692	pixman_transform_t t;
693	PixmapPtr tmp;
694	int width, height, size, max_size;
695	int sx, sy, sw, sh;
696	int error, ret = 0;
697	BoxRec box, b;
698
699	box.x1 = x;
700	box.y1 = y;
701	box.x2 = bound(x, w);
702	box.y2 = bound(y, h);
703	if (channel->transform) {
704		pixman_vector_t v;
705
706		pixman_transform_bounds(channel->transform, &box);
707
708		v.vector[0] = x << 16;
709		v.vector[1] = y << 16;
710		v.vector[2] = 1 << 16;
711		pixman_transform_point(channel->transform, &v);
712	}
713
714	if (channel->repeat == RepeatNone || channel->repeat == RepeatPad) {
715		if (box.x1 < 0)
716			box.x1 = 0;
717		if (box.y1 < 0)
718			box.y1 = 0;
719		if (box.x2 > pixmap->drawable.width)
720			box.x2 = pixmap->drawable.width;
721		if (box.y2 > pixmap->drawable.height)
722			box.y2 = pixmap->drawable.height;
723	} else {
724		/* XXX tiled repeats? */
725		if (box.x1 < 0 || box.x2 > pixmap->drawable.width)
726			box.x1 = 0, box.x2 = pixmap->drawable.width;
727		if (box.y1 < 0 || box.y2 > pixmap->drawable.height)
728			box.y1 = 0, box.y2 = pixmap->drawable.height;
729
730	}
731
732	sw = box.x2 - box.x1;
733	sh = box.y2 - box.y1;
734
735	DBG(("%s: sample (%d, %d), (%d, %d)\n",
736	     __FUNCTION__, box.x1, box.y1, box.x2, box.y2));
737
738	sx = (sw + sna->render.max_3d_size - 1) / sna->render.max_3d_size;
739	sy = (sh + sna->render.max_3d_size - 1) / sna->render.max_3d_size;
740
741	DBG(("%s: scaling (%d, %d) down by %dx%d\n",
742	     __FUNCTION__, sw, sh, sx, sy));
743
744	width  = sw / sx;
745	height = sh / sy;
746
747	DBG(("%s: creating temporary GPU bo %dx%d\n",
748	     __FUNCTION__, width, height));
749
750	tmp = screen->CreatePixmap(screen,
751				   width, height,
752				   pixmap->drawable.depth,
753				   SNA_CREATE_SCRATCH);
754	if (tmp == NULL)
755		goto fixup;
756
757	priv = sna_pixmap(tmp);
758	assert(priv && priv->gpu_bo);
759
760	if (!sna_pixmap_move_to_gpu(pixmap, MOVE_ASYNC_HINT | MOVE_SOURCE_HINT | MOVE_READ)) {
761fixup:
762		DBG(("%s: unable to create GPU bo for target or temporary pixmaps\n",
763		     __FUNCTION__));
764		return sna_render_picture_fixup(sna, picture, channel,
765						x, y, w, h,
766						dst_x, dst_y);
767	}
768
769	format = PictureMatchFormat(screen,
770				    pixmap->drawable.depth,
771				    picture->format);
772	if (format == NULL) {
773		DBG(("%s: invalid depth=%d, format=%08x\n",
774		     __FUNCTION__, pixmap->drawable.depth, picture->format));
775		goto fixup;
776	}
777
778	tmp_dst = CreatePicture(0, &tmp->drawable, format, 0, NULL,
779				serverClient, &error);
780	if (!tmp_dst)
781		goto cleanup_tmp;
782
783	tmp_src = CreatePicture(0, &pixmap->drawable, format, 0, NULL,
784				serverClient, &error);
785	if (!tmp_src)
786		goto cleanup_dst;
787
788	tmp_src->repeat = 1;
789	tmp_src->repeatType = RepeatPad;
790	/* Prefer to use nearest as it helps reduce artefacts from
791	 * interpolating and filtering twice.
792	 */
793	tmp_src->filter = PictFilterNearest;
794	memset(&t, 0, sizeof(t));
795	t.matrix[0][0] = (sw << 16) / width;
796	t.matrix[0][2] = box.x1 << 16;
797	t.matrix[1][1] = (sh << 16) / height;
798	t.matrix[1][2] = box.y1 << 16;
799	t.matrix[2][2] = 1 << 16;
800	tmp_src->transform = &t;
801
802	ValidatePicture(tmp_dst);
803	ValidatePicture(tmp_src);
804
805	/* Use a small size to accommodate enlargement through tile alignment */
806	max_size = sna_max_tile_copy_size(sna, sna_pixmap(pixmap)->gpu_bo, priv->gpu_bo);
807	if (max_size == 0)
808		goto cleanup_dst;
809
810	size = sna->render.max_3d_size - 4096 / pixmap->drawable.bitsPerPixel;
811	while (size * size * 4 > max_size)
812		size /= 2;
813	DBG(("%s: size=%d (max=%d), scale %dx%d\n",
814	     __FUNCTION__, size, max_size, sx, sy));
815
816	sw = size / sx - 2 * sx;
817	if (sw < 1)
818		sw = 1;
819	sh = size / sy - 2 * sy;
820	if (sh < 1)
821		sh = 1;
822	DBG(("%s %d:%d downsampling using %dx%d GPU tiles\n",
823	     __FUNCTION__, (width + sw-1)/sw, (height + sh-1)/sh, sw, sh));
824
825	for (b.y1 = 0; b.y1 < height; b.y1 = b.y2) {
826		b.y2 = b.y1 + sh;
827		if (b.y2 > height)
828			b.y2 = height;
829
830		for (b.x1 = 0; b.x1 < width; b.x1 = b.x2) {
831			struct sna_composite_op op;
832
833			b.x2 = b.x1 + sw;
834			if (b.x2 > width)
835				b.x2 = width;
836
837			DBG(("%s: tile (%d, %d), (%d, %d)\n",
838			     __FUNCTION__, b.x1, b.y1, b.x2, b.y2));
839
840			memset(&op, 0, sizeof(op));
841			if (!sna->render.composite(sna,
842						   PictOpSrc,
843						   tmp_src, NULL, tmp_dst,
844						   b.x1, b.y1,
845						   0, 0,
846						   b.x1, b.y1,
847						   b.x2 - b.x1, b.y2 - b.y1,
848						   0, &op))
849				goto cleanup_src;
850
851			op.box(sna, &op, &b);
852			op.done(sna, &op);
853		}
854	}
855
856	pixman_transform_invert(&channel->embedded_transform, &t);
857	if (channel->transform)
858		pixman_transform_multiply(&channel->embedded_transform,
859					  &channel->embedded_transform,
860					  channel->transform);
861	channel->transform = &channel->embedded_transform;
862
863	channel->offset[0] = x - dst_x;
864	channel->offset[1] = y - dst_y;
865	channel->scale[0] = 1.f/width;
866	channel->scale[1] = 1.f/height;
867	channel->width  = width;
868	channel->height = height;
869	channel->bo = kgem_bo_reference(priv->gpu_bo);
870
871	ret = 1;
872cleanup_src:
873	tmp_src->transform = NULL;
874	FreePicture(tmp_src, 0);
875cleanup_dst:
876	FreePicture(tmp_dst, 0);
877cleanup_tmp:
878	screen->DestroyPixmap(tmp);
879	return ret;
880}
881
882bool
883sna_render_pixmap_partial(struct sna *sna,
884			  const DrawableRec *draw,
885			  struct kgem_bo *bo,
886			  struct sna_composite_channel *channel,
887			  int16_t x, int16_t y,
888			  int16_t w, int16_t h)
889{
890	BoxRec box;
891	int offset;
892
893	DBG(("%s (%d, %d)x(%d, %d), pitch %d, max %d\n",
894	     __FUNCTION__, x, y, w, h, bo->pitch, sna->render.max_3d_pitch));
895
896	if (bo->pitch > sna->render.max_3d_pitch) {
897		DBG(("%s: pitch too great %d > %d\n", __FUNCTION__, bo->pitch, sna->render.max_3d_pitch));
898		return false;
899	}
900
901	box.x1 = x;
902	box.y1 = y;
903	box.x2 = bound(x, w);
904	box.y2 = bound(y, h);
905	DBG(("%s: unaligned box (%d, %d), (%d, %d)\n",
906	     __FUNCTION__, box.x1, box.y1, box.x2, box.y2));
907
908	if (box.x1 < 0)
909		box.x1 = 0;
910	if (box.y1 < 0)
911		box.y1 = 0;
912
913	if (bo->tiling) {
914		int tile_width, tile_height, tile_size;
915
916		kgem_get_tile_size(&sna->kgem, bo->tiling, bo->pitch,
917				   &tile_width, &tile_height, &tile_size);
918		DBG(("%s: tile size for tiling %d: %dx%d, size=%d\n",
919		     __FUNCTION__, bo->tiling, tile_width, tile_height, tile_size));
920
921		/* Ensure we align to an even tile row */
922		box.y1 = box.y1 & ~(2*tile_height - 1);
923		box.y2 = ALIGN(box.y2, 2*tile_height);
924
925		assert(tile_width * 8 >= draw->bitsPerPixel);
926		box.x1 = box.x1 & ~(tile_width * 8 / draw->bitsPerPixel - 1);
927		box.x2 = ALIGN(box.x2, tile_width * 8 / draw->bitsPerPixel);
928
929		offset = box.x1 * draw->bitsPerPixel / 8 / tile_width * tile_size;
930	} else {
931		box.y1 = box.y1 & ~1;
932		box.y2 = ALIGN(box.y2, 2);
933
934		box.x1 = box.x1 & ~1;
935		box.x2 = ALIGN(box.x2, 2);
936
937		offset = box.x1 * draw->bitsPerPixel / 8;
938	}
939
940	if (box.x2 > draw->width)
941		box.x2 = draw->width;
942	if (box.y2 > draw->height)
943		box.y2 = draw->height;
944
945	w = box.x2 - box.x1;
946	h = box.y2 - box.y1;
947	DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d)\n", __FUNCTION__,
948	     box.x1, box.y1, box.x2, box.y2, w, h,
949	     draw->width, draw->height));
950	if (w <= 0 || h <= 0 ||
951	    w > sna->render.max_3d_size ||
952	    h > sna->render.max_3d_size) {
953		DBG(("%s: box too large (%dx%d) for 3D pipeline (max %d)\n",
954		    __FUNCTION__, w, h, sna->render.max_3d_size));
955		return false;
956	}
957
958	/* How many tiles across are we? */
959	channel->bo = kgem_create_proxy(&sna->kgem, bo,
960					box.y1 * bo->pitch + offset,
961					h * bo->pitch);
962	if (channel->bo == NULL) {
963		DBG(("%s: failed to create proxy for partial (offset=%d, size=%d)\n",
964		     __FUNCTION__, box.y1 * bo->pitch + offset, h * bo->pitch));
965		return false;
966	}
967
968	channel->bo->pitch = bo->pitch;
969
970	channel->offset[0] = -box.x1;
971	channel->offset[1] = -box.y1;
972	channel->scale[0] = 1.f/w;
973	channel->scale[1] = 1.f/h;
974	channel->width  = w;
975	channel->height = h;
976	return true;
977}
978
979static bool
980sna_render_picture_partial(struct sna *sna,
981			   PicturePtr picture,
982			   struct sna_composite_channel *channel,
983			   int16_t x, int16_t y,
984			   int16_t w, int16_t h,
985			   int16_t dst_x, int16_t dst_y)
986{
987	struct kgem_bo *bo = NULL;
988	PixmapPtr pixmap = get_drawable_pixmap(picture->pDrawable);
989	BoxRec box;
990	int offset;
991
992	DBG(("%s (%d, %d)x(%d, %d) [dst=(%d, %d)]\n",
993	     __FUNCTION__, x, y, w, h, dst_x, dst_y));
994
995	box.x1 = x;
996	box.y1 = y;
997	box.x2 = bound(x, w);
998	box.y2 = bound(y, h);
999	if (channel->transform)
1000		pixman_transform_bounds(channel->transform, &box);
1001
1002	DBG(("%s sample=(%d, %d), (%d, %d): (%d, %d)/(%d, %d), repeat=%d\n", __FUNCTION__,
1003	     box.x1, box.y1, box.x2, box.y2, w, h,
1004	     pixmap->drawable.width, pixmap->drawable.height,
1005	     channel->repeat));
1006
1007	if (channel->repeat == RepeatNone || channel->repeat == RepeatPad) {
1008		if (box.x1 < 0)
1009			box.x1 = 0;
1010		if (box.y1 < 0)
1011			box.y1 = 0;
1012		if (box.x2 > pixmap->drawable.width)
1013			box.x2 = pixmap->drawable.width;
1014		if (box.y2 > pixmap->drawable.height)
1015			box.y2 = pixmap->drawable.height;
1016	} else {
1017		if (box.x1 < 0 || box.x2 > pixmap->drawable.width)
1018			box.x1 = 0, box.x2 = pixmap->drawable.width;
1019		if (box.y1 < 0 || box.y2 > pixmap->drawable.height)
1020			box.y1 = 0, box.y2 = pixmap->drawable.height;
1021	}
1022
1023	if (use_cpu_bo(sna, pixmap, &box, false)) {
1024		bo = sna_pixmap(pixmap)->cpu_bo;
1025	} else {
1026		struct sna_pixmap *priv;
1027
1028		priv = sna_pixmap_force_to_gpu(pixmap,
1029					       MOVE_READ | MOVE_ASYNC_HINT | MOVE_SOURCE_HINT);
1030		if (priv == NULL)
1031			return false;
1032
1033		bo = priv->gpu_bo;
1034	}
1035
1036	if (bo->pitch > sna->render.max_3d_pitch) {
1037		DBG(("%s: pitch too great %d > %d\n", __FUNCTION__, bo->pitch, sna->render.max_3d_pitch));
1038		return false;
1039	}
1040
1041	if (bo->tiling) {
1042		int tile_width, tile_height, tile_size;
1043
1044		kgem_get_tile_size(&sna->kgem, bo->tiling, bo->pitch,
1045				   &tile_width, &tile_height, &tile_size);
1046
1047		DBG(("%s: tiling=%d, size=%dx%d, chunk=%d\n",
1048		     __FUNCTION__, bo->tiling,
1049		     tile_width, tile_height, tile_size));
1050
1051		/* Ensure we align to an even tile row */
1052		box.y1 = box.y1 & ~(2*tile_height - 1);
1053		box.y2 = ALIGN(box.y2, 2*tile_height);
1054		if (box.y2 > pixmap->drawable.height)
1055			box.y2 = pixmap->drawable.height;
1056
1057		box.x1 = box.x1 & ~(tile_width * 8 / pixmap->drawable.bitsPerPixel - 1);
1058		box.x2 = ALIGN(box.x2, tile_width * 8 / pixmap->drawable.bitsPerPixel);
1059		if (box.x2 > pixmap->drawable.width)
1060			box.x2 = pixmap->drawable.width;
1061
1062		offset = box.x1 * pixmap->drawable.bitsPerPixel / 8 / tile_width * tile_size;
1063	} else
1064		offset = box.x1 * pixmap->drawable.bitsPerPixel / 8;
1065
1066	w = box.x2 - box.x1;
1067	h = box.y2 - box.y1;
1068	DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d)\n", __FUNCTION__,
1069	     box.x1, box.y1, box.x2, box.y2, w, h,
1070	     pixmap->drawable.width, pixmap->drawable.height));
1071	if (w <= 0 || h <= 0 ||
1072	    w > sna->render.max_3d_size ||
1073	    h > sna->render.max_3d_size)
1074		return false;
1075
1076	/* How many tiles across are we? */
1077	channel->bo = kgem_create_proxy(&sna->kgem, bo,
1078					box.y1 * bo->pitch + offset,
1079					h * bo->pitch);
1080	if (channel->bo == NULL)
1081		return false;
1082
1083	if (channel->transform) {
1084		memset(&channel->embedded_transform,
1085		       0,
1086		       sizeof(channel->embedded_transform));
1087		channel->embedded_transform.matrix[0][0] = 1 << 16;
1088		channel->embedded_transform.matrix[0][2] = -box.x1 << 16;
1089		channel->embedded_transform.matrix[1][1] = 1 << 16;
1090		channel->embedded_transform.matrix[1][2] = -box.y1 << 16;
1091		channel->embedded_transform.matrix[2][2] = 1 << 16;
1092		pixman_transform_multiply(&channel->embedded_transform,
1093					  &channel->embedded_transform,
1094					  channel->transform);
1095		channel->transform = &channel->embedded_transform;
1096	} else {
1097		x -= box.x1;
1098		y -= box.y1;
1099	}
1100
1101	channel->offset[0] = x - dst_x;
1102	channel->offset[1] = y - dst_y;
1103	channel->scale[0] = 1.f/w;
1104	channel->scale[1] = 1.f/h;
1105	channel->width  = w;
1106	channel->height = h;
1107	return true;
1108}
1109
1110int
1111sna_render_picture_extract(struct sna *sna,
1112			   PicturePtr picture,
1113			   struct sna_composite_channel *channel,
1114			   int16_t x, int16_t y,
1115			   int16_t w, int16_t h,
1116			   int16_t dst_x, int16_t dst_y)
1117{
1118	struct kgem_bo *bo = NULL, *src_bo;
1119	PixmapPtr pixmap = get_drawable_pixmap(picture->pDrawable);
1120	int16_t ox, oy, ow, oh;
1121	BoxRec box;
1122
1123#if NO_EXTRACT
1124	return -1;
1125#endif
1126
1127	DBG(("%s (%d, %d)x(%d, %d) [dst=(%d, %d)]\n",
1128	     __FUNCTION__, x, y, w, h, dst_x, dst_y));
1129
1130	if (w == 0 || h == 0) {
1131		DBG(("%s: fallback -- unknown bounds\n", __FUNCTION__));
1132		return -1;
1133	}
1134
1135	if (sna_render_picture_partial(sna, picture, channel,
1136				       x, y, w, h,
1137				       dst_x, dst_y))
1138		return 1;
1139
1140	ow = w;
1141	oh = h;
1142
1143	ox = box.x1 = x;
1144	oy = box.y1 = y;
1145	box.x2 = bound(x, w);
1146	box.y2 = bound(y, h);
1147	if (channel->transform) {
1148		pixman_vector_t v;
1149
1150		pixman_transform_bounds(channel->transform, &box);
1151
1152		v.vector[0] = ox << 16;
1153		v.vector[1] = oy << 16;
1154		v.vector[2] =  1 << 16;
1155		pixman_transform_point(channel->transform, &v);
1156		ox = v.vector[0] / v.vector[2];
1157		oy = v.vector[1] / v.vector[2];
1158	}
1159
1160	DBG(("%s sample=(%d, %d), (%d, %d): (%d, %d)/(%d, %d), repeat=%d\n", __FUNCTION__,
1161	     box.x1, box.y1, box.x2, box.y2, w, h,
1162	     pixmap->drawable.width, pixmap->drawable.height,
1163	     channel->repeat));
1164
1165	if (channel->repeat == RepeatNone || channel->repeat == RepeatPad) {
1166		if (box.x1 < 0)
1167			box.x1 = 0;
1168		if (box.y1 < 0)
1169			box.y1 = 0;
1170		if (box.x2 > pixmap->drawable.width)
1171			box.x2 = pixmap->drawable.width;
1172		if (box.y2 > pixmap->drawable.height)
1173			box.y2 = pixmap->drawable.height;
1174	} else {
1175		/* XXX tiled repeats? */
1176		if (box.x1 < 0 || box.x2 > pixmap->drawable.width)
1177			box.x1 = 0, box.x2 = pixmap->drawable.width;
1178		if (box.y1 < 0 || box.y2 > pixmap->drawable.height)
1179			box.y1 = 0, box.y2 = pixmap->drawable.height;
1180	}
1181
1182	w = box.x2 - box.x1;
1183	h = box.y2 - box.y1;
1184	DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d)\n", __FUNCTION__,
1185	     box.x1, box.y1, box.x2, box.y2, w, h,
1186	     pixmap->drawable.width, pixmap->drawable.height));
1187	if (w <= 0 || h <= 0) {
1188		DBG(("%s: sample extents outside of texture -> clear\n",
1189		     __FUNCTION__));
1190		return 0;
1191	}
1192
1193	if (w > sna->render.max_3d_size || h > sna->render.max_3d_size) {
1194		DBG(("%s: fallback -- sample too large for texture (%d, %d)x(%d, %d)\n",
1195		     __FUNCTION__, box.x1, box.y1, w, h));
1196		return sna_render_picture_downsample(sna, picture, channel,
1197						     x, y, ow, oh,
1198						     dst_x, dst_y);
1199	}
1200
1201	src_bo = use_cpu_bo(sna, pixmap, &box, true);
1202	if (src_bo == NULL)
1203		src_bo = move_to_gpu(pixmap, &box, false);
1204	if (src_bo) {
1205		bo = kgem_create_2d(&sna->kgem, w, h,
1206				    pixmap->drawable.bitsPerPixel,
1207				    kgem_choose_tiling(&sna->kgem,
1208						       I915_TILING_X, w, h,
1209						       pixmap->drawable.bitsPerPixel),
1210				    CREATE_TEMPORARY);
1211		if (bo) {
1212			DrawableRec tmp;
1213
1214			tmp.width  = w;
1215			tmp.height = h;
1216			tmp.depth  = pixmap->drawable.depth;
1217			tmp.bitsPerPixel = pixmap->drawable.bitsPerPixel;
1218
1219			assert(tmp.width);
1220			assert(tmp.height);
1221
1222			if (!sna->render.copy_boxes(sna, GXcopy,
1223						    &pixmap->drawable, src_bo, 0, 0,
1224						    &tmp, bo, -box.x1, -box.y1,
1225						    &box, 1, 0)) {
1226				kgem_bo_destroy(&sna->kgem, bo);
1227				bo = NULL;
1228			}
1229		}
1230	} else {
1231		struct sna_pixmap *priv = sna_pixmap(pixmap);
1232		if (priv) {
1233			RegionRec region;
1234
1235			region.extents = box;
1236			region.data = NULL;
1237			if (!sna_drawable_move_region_to_cpu(&pixmap->drawable,
1238							     &region, MOVE_READ))
1239				return 0;
1240
1241			assert(!priv->mapped);
1242			if (pixmap->devPrivate.ptr == NULL)
1243				return 0; /* uninitialised */
1244		}
1245
1246		bo = kgem_upload_source_image(&sna->kgem,
1247					      pixmap->devPrivate.ptr,
1248					      &box,
1249					      pixmap->devKind,
1250					      pixmap->drawable.bitsPerPixel);
1251		if (priv != NULL && bo != NULL &&
1252		    box.x2 - box.x1 == pixmap->drawable.width &&
1253		    box.y2 - box.y1 == pixmap->drawable.height) {
1254			DBG(("%s: adding upload cache to pixmap=%ld\n",
1255			     __FUNCTION__, pixmap->drawable.serialNumber));
1256			assert(priv->gpu_damage == NULL);
1257			assert(priv->gpu_bo == NULL);
1258			assert(bo->proxy != NULL);
1259			sna_damage_all(&priv->cpu_damage, pixmap);
1260			kgem_proxy_bo_attach(bo, &priv->gpu_bo);
1261		}
1262	}
1263
1264	if (bo == NULL) {
1265		DBG(("%s: falback -- pixmap is not on the GPU\n",
1266		     __FUNCTION__));
1267		return sna_render_picture_fixup(sna, picture, channel,
1268						x, y, ow, oh, dst_x, dst_y);
1269	}
1270
1271	if (ox == x && oy == y) {
1272		x = y = 0;
1273	} else if (channel->transform) {
1274		pixman_vector_t v;
1275		pixman_transform_t m;
1276
1277		v.vector[0] = (ox - box.x1) << 16;
1278		v.vector[1] = (oy - box.y1) << 16;
1279		v.vector[2] = 1 << 16;
1280		pixman_transform_invert(&m, channel->transform);
1281		pixman_transform_point(&m, &v);
1282		x = v.vector[0] / v.vector[2];
1283		y = v.vector[1] / v.vector[2];
1284	} else {
1285		x = ox - box.x1;
1286		y = oy - box.y1;
1287	}
1288
1289	channel->offset[0] = x - dst_x;
1290	channel->offset[1] = y - dst_y;
1291	channel->scale[0] = 1.f/w;
1292	channel->scale[1] = 1.f/h;
1293	channel->width  = w;
1294	channel->height = h;
1295	channel->bo = bo;
1296	return 1;
1297}
1298
1299static int
1300sna_render_picture_convolve(struct sna *sna,
1301			    PicturePtr picture,
1302			    struct sna_composite_channel *channel,
1303			    int16_t x, int16_t y,
1304			    int16_t w, int16_t h,
1305			    int16_t dst_x, int16_t dst_y)
1306{
1307	ScreenPtr screen = picture->pDrawable->pScreen;
1308	PixmapPtr pixmap;
1309	PicturePtr tmp;
1310	pixman_fixed_t *params = picture->filter_params;
1311	int x_off = -pixman_fixed_to_int((params[0] - pixman_fixed_1) >> 1);
1312	int y_off = -pixman_fixed_to_int((params[1] - pixman_fixed_1) >> 1);
1313	int cw = pixman_fixed_to_int(params[0]);
1314	int ch = pixman_fixed_to_int(params[1]);
1315	int i, j, error, depth;
1316	struct kgem_bo *bo;
1317
1318	/* Lame multi-pass accumulation implementation of a general convolution
1319	 * that works everywhere.
1320	 */
1321	DBG(("%s: origin=(%d,%d) kernel=%dx%d, size=%dx%d\n",
1322	     __FUNCTION__, x_off, y_off, cw, ch, w, h));
1323	if (cw*ch > 32) /* too much loss of precision from quantization! */
1324		return -1;
1325
1326	assert(picture->pDrawable);
1327	assert(picture->filter == PictFilterConvolution);
1328	assert(w <= sna->render.max_3d_size && h <= sna->render.max_3d_size);
1329
1330	if (PICT_FORMAT_RGB(picture->format) == 0) {
1331		channel->pict_format = PIXMAN_a8;
1332		depth = 8;
1333	} else {
1334		channel->pict_format = PIXMAN_a8r8g8b8;
1335		depth = 32;
1336	}
1337
1338	pixmap = screen->CreatePixmap(screen, w, h, depth, SNA_CREATE_SCRATCH);
1339	if (pixmap == NullPixmap) {
1340		DBG(("%s: pixmap allocation failed\n", __FUNCTION__));
1341		return -1;
1342	}
1343
1344	tmp = NULL;
1345	bo = __sna_pixmap_get_bo(pixmap);
1346	assert(bo);
1347	if (sna->render.clear(sna, pixmap, bo))
1348		tmp = CreatePicture(0, &pixmap->drawable,
1349				PictureMatchFormat(screen, depth, channel->pict_format),
1350				0, NULL, serverClient, &error);
1351	screen->DestroyPixmap(pixmap);
1352	if (tmp == NULL)
1353		return -1;
1354
1355	ValidatePicture(tmp);
1356
1357	picture->filter = PictFilterBilinear;
1358	params += 2;
1359	for (j = 0; j < ch; j++) {
1360		for (i = 0; i < cw; i++) {
1361			xRenderColor color;
1362			PicturePtr alpha;
1363
1364			color.alpha = *params++;
1365			color.red = color.green = color.blue = 0;
1366			DBG(("%s: (%d, %d), alpha=%x\n",
1367			     __FUNCTION__, i,j, color.alpha));
1368
1369			if (color.alpha <= 0x00ff)
1370				continue;
1371
1372			alpha = CreateSolidPicture(0, &color, &error);
1373			if (alpha) {
1374				sna_composite(PictOpAdd, picture, alpha, tmp,
1375					      x-(x_off+i), y-(y_off+j),
1376					      0, 0,
1377					      0, 0,
1378					      w, h);
1379				FreePicture(alpha, 0);
1380			}
1381		}
1382	}
1383	picture->filter = PictFilterConvolution;
1384
1385	channel->height = h;
1386	channel->width  = w;
1387	channel->filter = PictFilterNearest;
1388	channel->repeat = RepeatNone;
1389	channel->is_affine = true;
1390	channel->transform = NULL;
1391	channel->scale[0] = 1.f / w;
1392	channel->scale[1] = 1.f / h;
1393	channel->offset[0] = -dst_x;
1394	channel->offset[1] = -dst_y;
1395	channel->bo = kgem_bo_reference(bo); /* transfer ownership */
1396	FreePicture(tmp, 0);
1397
1398	return 1;
1399}
1400
1401static bool
1402sna_render_picture_flatten(struct sna *sna,
1403			   PicturePtr picture,
1404			   struct sna_composite_channel *channel,
1405			   int16_t x, int16_t y,
1406			   int16_t w, int16_t h,
1407			   int16_t dst_x, int16_t dst_y)
1408{
1409	ScreenPtr screen = picture->pDrawable->pScreen;
1410	PixmapPtr pixmap;
1411	PicturePtr tmp, alpha;
1412	int old_format, error;
1413
1414	assert(picture->pDrawable);
1415	assert(picture->alphaMap);
1416	assert(w <= sna->render.max_3d_size && h <= sna->render.max_3d_size);
1417
1418	/* XXX shortcut a8? */
1419	DBG(("%s: %dx%d\n", __FUNCTION__, w, h));
1420
1421	pixmap = screen->CreatePixmap(screen, w, h, 32, SNA_CREATE_SCRATCH);
1422	if (pixmap == NullPixmap) {
1423		DBG(("%s: pixmap allocation failed\n", __FUNCTION__));
1424		return false;
1425	}
1426
1427	assert(__sna_pixmap_get_bo(pixmap));
1428
1429	tmp = CreatePicture(0, &pixmap->drawable,
1430			    PictureMatchFormat(screen, 32, PICT_a8r8g8b8),
1431			    0, NULL, serverClient, &error);
1432	screen->DestroyPixmap(pixmap);
1433	if (tmp == NULL)
1434		return false;
1435
1436	ValidatePicture(tmp);
1437
1438	old_format = picture->format;
1439	picture->format = PICT_FORMAT(PICT_FORMAT_BPP(picture->format),
1440				      PICT_FORMAT_TYPE(picture->format),
1441				      0,
1442				      PICT_FORMAT_R(picture->format),
1443				      PICT_FORMAT_G(picture->format),
1444				      PICT_FORMAT_B(picture->format));
1445
1446	alpha = picture->alphaMap;
1447	picture->alphaMap = NULL;
1448
1449	sna_composite(PictOpSrc, picture, alpha, tmp,
1450		      x, y,
1451		      x + picture->alphaOrigin.x, y + picture->alphaOrigin.y,
1452		      0, 0,
1453		      w, h);
1454
1455	picture->format = old_format;
1456	picture->alphaMap = alpha;
1457
1458	channel->height = h;
1459	channel->width  = w;
1460	channel->filter = PictFilterNearest;
1461	channel->repeat = RepeatNone;
1462	channel->pict_format = PIXMAN_a8r8g8b8;
1463	channel->is_affine = true;
1464	channel->transform = NULL;
1465	channel->scale[0] = 1.f / w;
1466	channel->scale[1] = 1.f / h;
1467	channel->offset[0] = -dst_x;
1468	channel->offset[1] = -dst_y;
1469	channel->bo = kgem_bo_reference(__sna_pixmap_get_bo(pixmap));
1470	FreePicture(tmp, 0);
1471
1472	return true;
1473}
1474
1475int
1476sna_render_picture_approximate_gradient(struct sna *sna,
1477					PicturePtr picture,
1478					struct sna_composite_channel *channel,
1479					int16_t x, int16_t y,
1480					int16_t w, int16_t h,
1481					int16_t dst_x, int16_t dst_y)
1482{
1483	pixman_image_t *dst, *src;
1484	pixman_transform_t t;
1485	int w2 = w/2, h2 = h/2;
1486	int dx, dy;
1487	void *ptr;
1488
1489#if NO_FIXUP
1490	return -1;
1491#endif
1492
1493	DBG(("%s: (%d, %d)x(%d, %d), dst=(%d, %d)\n",
1494	     __FUNCTION__, x, y, w, h, dst_x, dst_y));
1495
1496	if (w2 == 0 || h2 == 0) {
1497		DBG(("%s: fallback - unknown bounds\n", __FUNCTION__));
1498		return -1;
1499	}
1500	if (w2 > sna->render.max_3d_size || h2 > sna->render.max_3d_size) {
1501		DBG(("%s: fallback - too large (%dx%d)\n", __FUNCTION__, w, h));
1502		return -1;
1503	}
1504
1505	channel->is_opaque = sna_gradient_is_opaque((PictGradient*)picture->pSourcePict);
1506	channel->pict_format =
1507		channel->is_opaque ? PIXMAN_x8r8g8b8 : PIXMAN_a8r8g8b8;
1508	DBG(("%s: gradient is opaque? %d, selecting format %08x\n",
1509	     __FUNCTION__, channel->is_opaque, channel->pict_format));
1510	assert(channel->card_format == -1);
1511
1512	channel->bo = kgem_create_buffer_2d(&sna->kgem,
1513					    w2, h2, 32,
1514					    KGEM_BUFFER_WRITE_INPLACE,
1515					    &ptr);
1516	if (!channel->bo) {
1517		DBG(("%s: failed to create upload buffer, using clear\n",
1518		     __FUNCTION__));
1519		return 0;
1520	}
1521
1522	dst = pixman_image_create_bits(channel->pict_format,
1523				       w2, h2, ptr, channel->bo->pitch);
1524	if (!dst) {
1525		kgem_bo_destroy(&sna->kgem, channel->bo);
1526		channel->bo = NULL;
1527		return 0;
1528	}
1529
1530	src = image_from_pict(picture, false, &dx, &dy);
1531	if (src == NULL) {
1532		pixman_image_unref(dst);
1533		kgem_bo_destroy(&sna->kgem, channel->bo);
1534		channel->bo = NULL;
1535		return 0;
1536	}
1537	DBG(("%s: source offset (%d, %d)\n", __FUNCTION__, dx, dy));
1538
1539	memset(&t, 0, sizeof(t));
1540	t.matrix[0][0] = (w << 16) / w2;
1541	t.matrix[0][2] = (x + dx) << 16;
1542	t.matrix[1][1] = (h << 16) / h2;
1543	t.matrix[1][2] = (y + dy) << 16;
1544	t.matrix[2][2] = 1 << 16;
1545	if (picture->transform)
1546		pixman_transform_multiply(&t, picture->transform, &t);
1547	DBG(("%s: applying transform [(%f, %f, %f), (%f, %f, %f), (%f, %f, %f)]\n",
1548	     __FUNCTION__,
1549	     pixman_fixed_to_double(t.matrix[0][0]),
1550	     pixman_fixed_to_double(t.matrix[0][1]),
1551	     pixman_fixed_to_double(t.matrix[0][2]),
1552	     pixman_fixed_to_double(t.matrix[1][0]),
1553	     pixman_fixed_to_double(t.matrix[1][1]),
1554	     pixman_fixed_to_double(t.matrix[1][2]),
1555	     pixman_fixed_to_double(t.matrix[2][0]),
1556	     pixman_fixed_to_double(t.matrix[2][1]),
1557	     pixman_fixed_to_double(t.matrix[2][2])));
1558	pixman_image_set_transform(src, &t);
1559
1560	sna_image_composite(PictOpSrc, src, NULL, dst,
1561			    0, 0,
1562			    0, 0,
1563			    0, 0,
1564			    w2, h2);
1565	free_pixman_pict(picture, src);
1566	pixman_image_unref(dst);
1567
1568	channel->width  = w2;
1569	channel->height = h2;
1570
1571	channel->filter = PictFilterNearest;
1572	channel->repeat = RepeatNone;
1573	channel->is_affine = true;
1574
1575	channel->scale[0] = 1.f/w;
1576	channel->scale[1] = 1.f/h;
1577	channel->offset[0] = -dst_x;
1578	channel->offset[1] = -dst_y;
1579	channel->transform = NULL;
1580
1581	return 1;
1582}
1583
1584int
1585sna_render_picture_fixup(struct sna *sna,
1586			 PicturePtr picture,
1587			 struct sna_composite_channel *channel,
1588			 int16_t x, int16_t y,
1589			 int16_t w, int16_t h,
1590			 int16_t dst_x, int16_t dst_y)
1591{
1592	pixman_image_t *dst, *src;
1593	int dx, dy;
1594	void *ptr;
1595
1596#if NO_FIXUP
1597	return -1;
1598#endif
1599
1600	DBG(("%s: (%d, %d)x(%d, %d)\n", __FUNCTION__, x, y, w, h));
1601
1602	if (w == 0 || h == 0) {
1603		DBG(("%s: fallback - unknown bounds\n", __FUNCTION__));
1604		return -1;
1605	}
1606	if (w > sna->render.max_3d_size || h > sna->render.max_3d_size) {
1607		DBG(("%s: fallback - too large (%dx%d)\n", __FUNCTION__, w, h));
1608		return -1;
1609	}
1610
1611	if (picture->alphaMap) {
1612		DBG(("%s: alphamap\n", __FUNCTION__));
1613		if (is_gpu(sna, picture->pDrawable, PREFER_GPU_RENDER) ||
1614		    is_gpu(sna, picture->alphaMap->pDrawable, PREFER_GPU_RENDER)) {
1615			if (sna_render_picture_flatten(sna, picture, channel,
1616							  x, y, w, h, dst_x, dst_y))
1617				return 1;
1618		}
1619
1620		goto do_fixup;
1621	}
1622
1623	if (picture->filter == PictFilterConvolution) {
1624		DBG(("%s: convolution\n", __FUNCTION__));
1625		if (is_gpu(sna, picture->pDrawable, PREFER_GPU_RENDER)) {
1626			return sna_render_picture_convolve(sna, picture, channel,
1627							   x, y, w, h, dst_x, dst_y);
1628		}
1629
1630		goto do_fixup;
1631	}
1632
1633do_fixup:
1634	if (PICT_FORMAT_RGB(picture->format) == 0)
1635		channel->pict_format = PIXMAN_a8;
1636	else
1637		channel->pict_format = PIXMAN_a8r8g8b8;
1638
1639	if (picture->pDrawable &&
1640	    !sna_drawable_move_to_cpu(picture->pDrawable, MOVE_READ))
1641		return 0;
1642
1643	channel->bo = kgem_create_buffer_2d(&sna->kgem,
1644					    w, h, PIXMAN_FORMAT_BPP(channel->pict_format),
1645					    KGEM_BUFFER_WRITE_INPLACE,
1646					    &ptr);
1647	if (!channel->bo) {
1648		DBG(("%s: failed to create upload buffer, using clear\n",
1649		     __FUNCTION__));
1650		return 0;
1651	}
1652
1653	/* Composite in the original format to preserve idiosyncracies */
1654	if (!kgem_buffer_is_inplace(channel->bo) &&
1655	    (picture->pDrawable == NULL ||
1656	     alphaless(picture->format) == alphaless(channel->pict_format)))
1657		dst = pixman_image_create_bits(channel->pict_format,
1658					       w, h, ptr, channel->bo->pitch);
1659	else
1660		dst = pixman_image_create_bits((pixman_format_code_t)picture->format,
1661					       w, h, NULL, 0);
1662	if (!dst) {
1663		kgem_bo_destroy(&sna->kgem, channel->bo);
1664		return 0;
1665	}
1666
1667	src = image_from_pict(picture, false, &dx, &dy);
1668	if (src == NULL) {
1669		pixman_image_unref(dst);
1670		kgem_bo_destroy(&sna->kgem, channel->bo);
1671		return 0;
1672	}
1673
1674	DBG(("%s: compositing tmp=(%d+%d, %d+%d)x(%d, %d)\n",
1675	     __FUNCTION__, x, dx, y, dy, w, h));
1676	sna_image_composite(PictOpSrc, src, NULL, dst,
1677			    x + dx, y + dy,
1678			    0, 0,
1679			    0, 0,
1680			    w, h);
1681	free_pixman_pict(picture, src);
1682
1683	/* Then convert to card format */
1684	if (pixman_image_get_data(dst) != ptr) {
1685		DBG(("%s: performing post-conversion %08x->%08x (%d, %d)\n",
1686		     __FUNCTION__,
1687		     picture->format, channel->pict_format,
1688		     w, h));
1689
1690		src = dst;
1691		dst = pixman_image_create_bits(channel->pict_format,
1692					       w, h, ptr, channel->bo->pitch);
1693		if (dst) {
1694			sna_image_composite(PictOpSrc, src, NULL, dst,
1695					    0, 0,
1696					    0, 0,
1697					    0, 0,
1698					    w, h);
1699			pixman_image_unref(src);
1700		} else {
1701			memset(ptr, 0, __kgem_buffer_size(channel->bo));
1702			dst = src;
1703		}
1704	}
1705	pixman_image_unref(dst);
1706
1707	channel->width  = w;
1708	channel->height = h;
1709
1710	channel->filter = PictFilterNearest;
1711	channel->repeat = RepeatNone;
1712	channel->is_affine = true;
1713
1714	channel->scale[0] = 1.f/w;
1715	channel->scale[1] = 1.f/h;
1716	channel->offset[0] = -dst_x;
1717	channel->offset[1] = -dst_y;
1718	channel->transform = NULL;
1719
1720	return 1;
1721}
1722
1723int
1724sna_render_picture_convert(struct sna *sna,
1725			   PicturePtr picture,
1726			   struct sna_composite_channel *channel,
1727			   PixmapPtr pixmap,
1728			   int16_t x, int16_t y,
1729			   int16_t w, int16_t h,
1730			   int16_t dst_x, int16_t dst_y,
1731			   bool fixup_alpha)
1732{
1733	BoxRec box;
1734
1735#if NO_CONVERT
1736	return -1;
1737#endif
1738
1739	if (w != 0 && h != 0) {
1740		box.x1 = x;
1741		box.y1 = y;
1742		box.x2 = bound(x, w);
1743		box.y2 = bound(y, h);
1744
1745		if (channel->transform) {
1746			DBG(("%s: has transform, converting whole surface\n",
1747			     __FUNCTION__));
1748			box.x1 = box.y1 = 0;
1749			box.x2 = pixmap->drawable.width;
1750			box.y2 = pixmap->drawable.height;
1751		}
1752
1753		if (box.x1 < 0)
1754			box.x1 = 0;
1755		if (box.y1 < 0)
1756			box.y1 = 0;
1757		if (box.x2 > pixmap->drawable.width)
1758			box.x2 = pixmap->drawable.width;
1759		if (box.y2 > pixmap->drawable.height)
1760			box.y2 = pixmap->drawable.height;
1761	} else {
1762		DBG(("%s: op no bounds, converting whole surface\n",
1763		     __FUNCTION__));
1764		box.x1 = box.y1 = 0;
1765		box.x2 = pixmap->drawable.width;
1766		box.y2 = pixmap->drawable.height;
1767	}
1768
1769	w = box.x2 - box.x1;
1770	h = box.y2 - box.y1;
1771
1772	DBG(("%s: convert (%d, %d)x(%d, %d), source size %dx%d\n",
1773	     __FUNCTION__, box.x1, box.y1, w, h,
1774	     pixmap->drawable.width,
1775	     pixmap->drawable.height));
1776
1777	if (w <= 0 || h <= 0) {
1778		DBG(("%s: sample extents lie outside of source, using clear\n",
1779		     __FUNCTION__));
1780		return 0;
1781	}
1782
1783	if (fixup_alpha && is_gpu(sna, &pixmap->drawable, PREFER_GPU_RENDER)) {
1784		ScreenPtr screen = pixmap->drawable.pScreen;
1785		PixmapPtr tmp;
1786		PicturePtr src, dst;
1787		int error;
1788
1789		assert(PICT_FORMAT_BPP(picture->format) == pixmap->drawable.bitsPerPixel);
1790		channel->pict_format = PICT_FORMAT(PICT_FORMAT_BPP(picture->format),
1791						   PICT_FORMAT_TYPE(picture->format),
1792						   PICT_FORMAT_BPP(picture->format) - PIXMAN_FORMAT_DEPTH(picture->format),
1793						   PICT_FORMAT_R(picture->format),
1794						   PICT_FORMAT_G(picture->format),
1795						   PICT_FORMAT_B(picture->format));
1796
1797		DBG(("%s: converting to %08x from %08x using composite alpha-fixup\n",
1798		     __FUNCTION__,
1799		     (unsigned)channel->pict_format,
1800		     (unsigned)picture->format));
1801
1802		tmp = screen->CreatePixmap(screen, w, h, pixmap->drawable.bitsPerPixel, SNA_CREATE_SCRATCH);
1803		if (tmp == NULL)
1804			return -1;
1805
1806		assert(__sna_pixmap_get_bo(tmp));
1807
1808		dst = CreatePicture(0, &tmp->drawable,
1809				    PictureMatchFormat(screen,
1810						       pixmap->drawable.bitsPerPixel,
1811						       channel->pict_format),
1812				    0, NULL, serverClient, &error);
1813		if (dst == NULL) {
1814			screen->DestroyPixmap(tmp);
1815			return 0;
1816		}
1817
1818		src = CreatePicture(0, &pixmap->drawable,
1819				    PictureMatchFormat(screen,
1820						       pixmap->drawable.depth,
1821						       picture->format),
1822				    0, NULL, serverClient, &error);
1823		if (src == NULL) {
1824			FreePicture(dst, 0);
1825			screen->DestroyPixmap(tmp);
1826			return 0;
1827		}
1828
1829		ValidatePicture(src);
1830		ValidatePicture(dst);
1831
1832		sna_composite(PictOpSrc, src, NULL, dst,
1833			      box.x1, box.y1,
1834			      0, 0,
1835			      0, 0,
1836			      w, h);
1837		FreePicture(dst, 0);
1838		FreePicture(src, 0);
1839
1840		channel->bo = __sna_pixmap_get_bo(tmp);
1841		kgem_bo_reference(channel->bo);
1842		screen->DestroyPixmap(tmp);
1843	} else {
1844		pixman_image_t *src, *dst;
1845		void *ptr;
1846
1847		if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ))
1848			return 0;
1849
1850		src = pixman_image_create_bits((pixman_format_code_t)picture->format,
1851					       pixmap->drawable.width,
1852					       pixmap->drawable.height,
1853					       pixmap->devPrivate.ptr,
1854					       pixmap->devKind);
1855		if (!src)
1856			return 0;
1857
1858		if (PICT_FORMAT_RGB(picture->format) == 0) {
1859			channel->pict_format = PIXMAN_a8;
1860			DBG(("%s: converting to a8 from %08x\n",
1861			     __FUNCTION__, picture->format));
1862		} else {
1863			channel->pict_format = PIXMAN_a8r8g8b8;
1864			DBG(("%s: converting to a8r8g8b8 from %08x\n",
1865			     __FUNCTION__, picture->format));
1866		}
1867
1868		channel->bo = kgem_create_buffer_2d(&sna->kgem,
1869						    w, h, PIXMAN_FORMAT_BPP(channel->pict_format),
1870						    KGEM_BUFFER_WRITE_INPLACE,
1871						    &ptr);
1872		if (!channel->bo) {
1873			pixman_image_unref(src);
1874			return 0;
1875		}
1876
1877		dst = pixman_image_create_bits(channel->pict_format,
1878					       w, h, ptr, channel->bo->pitch);
1879		if (!dst) {
1880			kgem_bo_destroy(&sna->kgem, channel->bo);
1881			pixman_image_unref(src);
1882			return 0;
1883		}
1884
1885		if (sigtrap_get() == 0) {
1886			sna_image_composite(PictOpSrc, src, NULL, dst,
1887					    box.x1, box.y1,
1888					    0, 0,
1889					    0, 0,
1890					    w, h);
1891			sigtrap_put();
1892		}
1893		pixman_image_unref(dst);
1894		pixman_image_unref(src);
1895	}
1896
1897	channel->width  = w;
1898	channel->height = h;
1899
1900	channel->scale[0] = 1.f/w;
1901	channel->scale[1] = 1.f/h;
1902	channel->offset[0] = x - dst_x - box.x1;
1903	channel->offset[1] = y - dst_y - box.y1;
1904
1905	DBG(("%s: offset=(%d, %d), size=(%d, %d)\n",
1906	     __FUNCTION__,
1907	     channel->offset[0], channel->offset[1],
1908	     channel->width, channel->height));
1909	return 1;
1910}
1911
1912bool
1913sna_render_composite_redirect(struct sna *sna,
1914			      struct sna_composite_op *op,
1915			      int x, int y, int width, int height,
1916			      bool partial)
1917{
1918	struct sna_composite_redirect *t = &op->redirect;
1919	int bpp = op->dst.pixmap->drawable.bitsPerPixel;
1920	struct kgem_bo *bo;
1921
1922	assert(t->real_bo == NULL);
1923
1924#if NO_REDIRECT
1925	return false;
1926#endif
1927
1928	DBG(("%s: target too large (%dx%d), copying to temporary %dx%d, max %d / %d\n",
1929	     __FUNCTION__,
1930	     op->dst.width, op->dst.height,
1931	     width, height,
1932	     sna->render.max_3d_size,
1933	     sna->render.max_3d_pitch));
1934
1935	if (!width || !height)
1936		return false;
1937
1938	if (width  > sna->render.max_3d_size ||
1939	    height > sna->render.max_3d_size)
1940		return false;
1941
1942	if (op->dst.bo->pitch <= sna->render.max_3d_pitch) {
1943		BoxRec box;
1944		int w, h, offset;
1945
1946		DBG(("%s: dst pitch (%d) fits within render pipeline (%d)\n",
1947		     __FUNCTION__, op->dst.bo->pitch, sna->render.max_3d_pitch));
1948
1949		box.x1 = x + op->dst.x;
1950		box.x2 = bound(box.x1, width);
1951		box.y1 = y + op->dst.y;
1952		box.y2 = bound(box.y1, height);
1953
1954		if (box.x1 < 0)
1955			box.x1 = 0;
1956		if (box.y1 < 0)
1957			box.y1 = 0;
1958
1959		/* Ensure we align to an even tile row */
1960		if (op->dst.bo->tiling) {
1961			int tile_width, tile_height, tile_size;
1962
1963			kgem_get_tile_size(&sna->kgem, op->dst.bo->tiling, op->dst.bo->pitch,
1964					   &tile_width, &tile_height, &tile_size);
1965
1966			box.y1 = box.y1 & ~(2*tile_height - 1);
1967			box.y2 = ALIGN(box.y2, 2*tile_height);
1968
1969			box.x1 = box.x1 & ~(tile_width * 8 / op->dst.pixmap->drawable.bitsPerPixel - 1);
1970			box.x2 = ALIGN(box.x2, tile_width * 8 / op->dst.pixmap->drawable.bitsPerPixel);
1971
1972			if (box.x1 > sna->render.max_3d_size &&
1973			    box.x2 <= 2*sna->render.max_3d_size)
1974				box.x1 = sna->render.max_3d_size;
1975
1976			if (box.y1 > sna->render.max_3d_size &&
1977			    box.y2 <= 2*sna->render.max_3d_size)
1978				box.y1 = sna->render.max_3d_size;
1979
1980			offset = box.x1 * op->dst.pixmap->drawable.bitsPerPixel / 8 / tile_width * tile_size;
1981		} else {
1982			if (sna->kgem.gen < 040) {
1983				box.y1 = box.y1 & ~3;
1984				box.y2 = ALIGN(box.y2, 4);
1985
1986				box.x1 = box.x1 & ~3;
1987				box.x2 = ALIGN(box.x2, 4);
1988			} else {
1989				box.y1 = box.y1 & ~1;
1990				box.y2 = ALIGN(box.y2, 2);
1991
1992				box.x1 = box.x1 & ~1;
1993				box.x2 = ALIGN(box.x2, 2);
1994			}
1995
1996			if (box.x1 > sna->render.max_3d_size &&
1997			    box.x2 <= 2*sna->render.max_3d_size)
1998				box.x1 = sna->render.max_3d_size;
1999
2000			if (box.y1 > sna->render.max_3d_size &&
2001			    box.y2 <= 2*sna->render.max_3d_size)
2002				box.y1 = sna->render.max_3d_size;
2003
2004			offset = box.x1 * op->dst.pixmap->drawable.bitsPerPixel / 8;
2005		}
2006
2007		if (box.y2 > op->dst.pixmap->drawable.height)
2008			box.y2 = op->dst.pixmap->drawable.height;
2009
2010		if (box.x2 > op->dst.pixmap->drawable.width)
2011			box.x2 = op->dst.pixmap->drawable.width;
2012
2013		w = box.x2 - box.x1;
2014		h = box.y2 - box.y1;
2015		DBG(("%s box=(%d, %d), (%d, %d): (%d, %d)/(%d, %d), max %d\n", __FUNCTION__,
2016		     box.x1, box.y1, box.x2, box.y2, w, h,
2017		     op->dst.pixmap->drawable.width,
2018		     op->dst.pixmap->drawable.height,
2019		     sna->render.max_3d_size));
2020		if (w <= sna->render.max_3d_size &&
2021		    h <= sna->render.max_3d_size) {
2022			t->box.x2 = t->box.x1 = op->dst.x;
2023			t->box.y2 = t->box.y1 = op->dst.y;
2024			t->real_bo = op->dst.bo;
2025			t->real_damage = op->damage;
2026			if (op->damage) {
2027				assert(!DAMAGE_IS_ALL(op->damage));
2028				t->damage = sna_damage_create();
2029				op->damage = &t->damage;
2030			}
2031
2032			/* How many tiles across are we? */
2033			op->dst.bo = kgem_create_proxy(&sna->kgem, op->dst.bo,
2034						       box.y1 * op->dst.bo->pitch + offset,
2035						       h * op->dst.bo->pitch);
2036			if (!op->dst.bo) {
2037				t->real_bo = NULL;
2038				if (t->damage)
2039					__sna_damage_destroy(t->damage);
2040				return false;
2041			}
2042
2043			assert(op->dst.bo != t->real_bo);
2044			op->dst.bo->pitch = t->real_bo->pitch;
2045
2046			op->dst.x -= box.x1;
2047			op->dst.y -= box.y1;
2048			op->dst.width  = w;
2049			op->dst.height = h;
2050			return true;
2051		}
2052	}
2053
2054	/* We can process the operation in a single pass,
2055	 * but the target is too large for the 3D pipeline.
2056	 * Copy into a smaller surface and replace afterwards.
2057	 */
2058	bo = kgem_create_2d(&sna->kgem,
2059			    width, height, bpp,
2060			    kgem_choose_tiling(&sna->kgem, I915_TILING_X,
2061					       width, height, bpp),
2062			    CREATE_TEMPORARY);
2063	if (!bo)
2064		return false;
2065
2066	t->box.x1 = x + op->dst.x;
2067	t->box.y1 = y + op->dst.y;
2068	t->box.x2 = bound(t->box.x1, width);
2069	t->box.y2 = bound(t->box.y1, height);
2070
2071	DBG(("%s: original box (%d, %d), (%d, %d)\n",
2072	     __FUNCTION__, t->box.x1, t->box.y1, t->box.x2, t->box.y2));
2073
2074	if (partial &&
2075	    !sna_blt_copy_boxes(sna, GXcopy,
2076				op->dst.bo, 0, 0,
2077				bo, -t->box.x1, -t->box.y1,
2078				bpp, &t->box, 1)) {
2079		kgem_bo_destroy(&sna->kgem, bo);
2080		return false;
2081	}
2082
2083	t->real_bo = op->dst.bo;
2084	t->real_damage = op->damage;
2085	if (op->damage) {
2086		assert(!DAMAGE_IS_ALL(op->damage));
2087		t->damage = sna_damage_create();
2088		op->damage = &t->damage;
2089	}
2090
2091	op->dst.bo = bo;
2092	op->dst.x = -x;
2093	op->dst.y = -y;
2094	op->dst.width  = width;
2095	op->dst.height = height;
2096	return true;
2097}
2098
2099void
2100sna_render_composite_redirect_done(struct sna *sna,
2101				   const struct sna_composite_op *op)
2102{
2103	const struct sna_composite_redirect *t = &op->redirect;
2104
2105	if (t->real_bo) {
2106		assert(op->dst.bo != t->real_bo);
2107
2108		if (t->box.x2 > t->box.x1) {
2109			bool ok;
2110
2111			DBG(("%s: copying temporary to dst\n", __FUNCTION__));
2112			ok = sna_blt_copy_boxes(sna, GXcopy,
2113						op->dst.bo, -t->box.x1, -t->box.y1,
2114						t->real_bo, 0, 0,
2115						op->dst.pixmap->drawable.bitsPerPixel,
2116						&t->box, 1);
2117			assert(ok);
2118			(void)ok;
2119		}
2120		if (t->damage) {
2121			DBG(("%s: combining damage (all? %d), offset=(%d, %d)\n",
2122			     __FUNCTION__, (int)DAMAGE_IS_ALL(t->damage),
2123			     t->box.x1, t->box.y1));
2124			sna_damage_combine(t->real_damage,
2125					   DAMAGE_PTR(t->damage),
2126					   t->box.x1, t->box.y1);
2127			__sna_damage_destroy(DAMAGE_PTR(t->damage));
2128		}
2129
2130		kgem_bo_destroy(&sna->kgem, op->dst.bo);
2131	}
2132}
2133
2134static bool
2135copy_overlap(struct sna *sna, uint8_t alu,
2136	     const DrawableRec *draw, struct kgem_bo *bo,
2137	     int16_t src_dx, int16_t src_dy,
2138	     int16_t dst_dx, int16_t dst_dy,
2139	     const BoxRec *box, int n, const BoxRec *extents)
2140{
2141	ScreenPtr screen = draw->pScreen;
2142	struct kgem_bo *tmp_bo;
2143	PixmapPtr tmp;
2144	bool ret = false;
2145
2146	if (n == 0)
2147		return true;
2148
2149	DBG(("%s: %d x %dx%d src=(%d, %d), dst=(%d, %d)\n",
2150	     __FUNCTION__, n,
2151	     extents->x2 - extents->x1,
2152	     extents->y2 - extents->y1,
2153	     src_dx, src_dy,
2154	     dst_dx, dst_dy));
2155
2156	tmp = screen->CreatePixmap(screen,
2157				   extents->x2 - extents->x1,
2158				   extents->y2 - extents->y1,
2159				   draw->depth,
2160				   SNA_CREATE_SCRATCH);
2161	if (tmp == NULL)
2162		return false;
2163
2164	tmp_bo = __sna_pixmap_get_bo(tmp);
2165	assert(tmp_bo);
2166
2167	ret = (sna->render.copy_boxes(sna, GXcopy,
2168				      draw, bo, src_dx, src_dy,
2169				      &tmp->drawable, tmp_bo, -extents->x1, -extents->y1,
2170				      box, n, 0) &&
2171	       sna->render.copy_boxes(sna, alu,
2172				      &tmp->drawable, tmp_bo, -extents->x1, -extents->y1,
2173				      draw, bo, dst_dx, dst_dy,
2174				      box, n, 0));
2175
2176	screen->DestroyPixmap(tmp);
2177	return ret;
2178}
2179bool
2180sna_render_copy_boxes__overlap(struct sna *sna, uint8_t alu,
2181			       const DrawableRec *draw, struct kgem_bo *bo,
2182			       int16_t src_dx, int16_t src_dy,
2183			       int16_t dst_dx, int16_t dst_dy,
2184			       const BoxRec *box, int n, const BoxRec *extents)
2185{
2186	bool ret = false;
2187	RegionRec overlap, non_overlap;
2188	pixman_region16_t region;
2189	pixman_box16_t stack_boxes[64], *boxes = stack_boxes;
2190	int num_boxes, i;
2191
2192	DBG(("%s: pixmap=%ld, handle=%d, %d x [(%d, %d), (%d, %d)], dst=(%d, %d), src=(%d, %d)\n",
2193	     __FUNCTION__, draw->serialNumber, bo->handle,
2194	     n, extents->x1, extents->y1, extents->x2, extents->y2,
2195	     src_dx, src_dy, dst_dx, dst_dy));
2196
2197	if ((dst_dx - src_dx < 4 && src_dx - dst_dx < 4) &&
2198	    (dst_dy - src_dy < 4 && src_dy - dst_dy < 4))
2199		return copy_overlap(sna, alu, draw, bo,
2200				    src_dx, src_dy,
2201				    dst_dx, dst_dy,
2202				    box, n, extents);
2203
2204	if (n > ARRAY_SIZE(stack_boxes)) {
2205		boxes = malloc(sizeof(pixman_box16_t) * n);
2206		if (boxes == NULL)
2207			return copy_overlap(sna, alu, draw, bo,
2208					    src_dx, src_dy,
2209					    dst_dx, dst_dy,
2210					    box, n, extents);
2211	}
2212
2213	region.extents.x1 = extents->x1 + dst_dx;
2214	region.extents.x2 = extents->x2 + dst_dx;
2215	region.extents.y1 = extents->y1 + dst_dy;
2216	region.extents.y2 = extents->y2 + dst_dy;
2217
2218	for (i = num_boxes = 0; i < n; i++) {
2219		boxes[num_boxes].x1 = box[i].x1 + dst_dx;
2220		if (boxes[num_boxes].x1 < region.extents.x1)
2221			boxes[num_boxes].x1 = region.extents.x1;
2222
2223		boxes[num_boxes].y1 = box[i].y1 + dst_dy;
2224		if (boxes[num_boxes].y1 < region.extents.y1)
2225			boxes[num_boxes].y1 = region.extents.y1;
2226
2227		boxes[num_boxes].x2 = box[i].x2 + dst_dx;
2228		if (boxes[num_boxes].x2 > region.extents.x2)
2229			boxes[num_boxes].x2 = region.extents.x2;
2230
2231		boxes[num_boxes].y2 = box[i].y2 + dst_dy;
2232		if (boxes[num_boxes].y2 > region.extents.y2)
2233			boxes[num_boxes].y2 = region.extents.y2;
2234
2235		if (boxes[num_boxes].x2 > boxes[num_boxes].x1 &&
2236		    boxes[num_boxes].y2 > boxes[num_boxes].y1)
2237			num_boxes++;
2238	}
2239
2240	if (num_boxes == 0) {
2241		ret = true;
2242		goto cleanup_boxes;
2243	}
2244
2245	if (!pixman_region_init_rects(&region, boxes, num_boxes))
2246		goto cleanup_boxes;
2247
2248	overlap.extents.x1 = extents->x1 + src_dx;
2249	overlap.extents.x2 = extents->x2 + src_dx;
2250	overlap.extents.y1 = extents->y1 + src_dy;
2251	overlap.extents.y2 = extents->y2 + src_dy;
2252	overlap.data = NULL;
2253
2254	RegionIntersect(&overlap, &overlap, &region);
2255	DBG(("%s: overlapping extents: (%d, %d), (%d, %d) x %d\n",
2256	     __FUNCTION__,
2257	     overlap.extents.x1, overlap.extents.y1,
2258	     overlap.extents.x2, overlap.extents.y2,
2259	     region_num_rects(&overlap)));
2260
2261	RegionNull(&non_overlap);
2262	RegionSubtract(&non_overlap, &region, &overlap);
2263	DBG(("%s: non-overlapping extents: (%d, %d), (%d, %d) x %d\n",
2264	     __FUNCTION__,
2265	     non_overlap.extents.x1, non_overlap.extents.y1,
2266	     non_overlap.extents.x2, non_overlap.extents.y2,
2267	     region_num_rects(&non_overlap)));
2268
2269	n = region_num_rects(&non_overlap);
2270	box = region_rects(&non_overlap);
2271	if (n && !sna->render.copy_boxes(sna, alu,
2272					 draw, bo, -dst_dx + src_dx, -dst_dy + src_dy,
2273					 draw, bo, 0, 0,
2274					 box, n , COPY_NO_OVERLAP))
2275		goto cleanup_boxes;
2276
2277	n = region_num_rects(&overlap);
2278	box = region_rects(&overlap);
2279	ret = copy_overlap(sna, alu, draw, bo,
2280			   -dst_dx + src_dx, -dst_dy + src_dy,
2281			   0, 0,
2282			   box, n, &overlap.extents);
2283
2284cleanup_boxes:
2285	if (boxes != stack_boxes)
2286		free(boxes);
2287
2288	return ret;
2289}
2290
2291static bool can_copy_cpu(struct sna *sna,
2292			 struct kgem_bo *src,
2293			 struct kgem_bo *dst)
2294{
2295	DBG(("%s: tiling=%d:%d, pitch=%d:%d, can_map=%d:%d[%d]\n",
2296	     __FUNCTION__,
2297	     src->tiling, dst->tiling,
2298	     src->pitch, dst->pitch,
2299	     kgem_bo_can_map__cpu(&sna->kgem, src, false),
2300	     kgem_bo_can_map__cpu(&sna->kgem, dst, true),
2301	     sna->kgem.has_wc_mmap));
2302
2303	if (src->tiling != dst->tiling)
2304		return false;
2305
2306	if (!kgem_bo_can_map__cpu(&sna->kgem, src, false))
2307		return false;
2308
2309	if (!kgem_bo_can_map__cpu(&sna->kgem, dst, true) &&
2310	    !sna->kgem.has_wc_mmap)
2311		return false;
2312
2313	DBG(("%s -- yes, src handle=%d, dst handle=%d\n", __FUNCTION__, src->handle, dst->handle));
2314	return true;
2315}
2316
2317bool
2318memcpy_copy_boxes(struct sna *sna, uint8_t op,
2319		  const DrawableRec *src_draw, struct kgem_bo *src_bo, int16_t sx, int16_t sy,
2320		  const DrawableRec *dst_draw, struct kgem_bo *dst_bo, int16_t dx, int16_t dy,
2321		  const BoxRec *box, int n, unsigned flags)
2322{
2323	memcpy_box_func detile = NULL;
2324	void *dst, *src;
2325
2326	if (op != GXcopy)
2327		return false;
2328
2329	if (src_draw->depth != dst_draw->depth)
2330		return false;
2331
2332	dst = src = NULL;
2333	if (can_copy_cpu(sna, src_bo, dst_bo)) {
2334		if (src_bo->pitch != dst_bo->pitch ||
2335		    dx != sx || dy != sy || n > 1 ||
2336		    box->x1 + dx > 0 ||
2337		    box->y1 + dy > 0 ||
2338		    box->x2 + dx < dst_draw->width ||
2339		    box->y2 + dy < dst_draw->height) {
2340			if (dx != sx) /* not implemented in memcpy yet */
2341				goto use_gtt;
2342
2343			switch (dst_bo->tiling) {
2344			default:
2345			case I915_TILING_Y:
2346				goto use_gtt;
2347
2348			case I915_TILING_X:
2349				detile = sna->kgem.memcpy_between_tiled_x;
2350				if (detile == NULL)
2351					goto use_gtt;
2352				break;
2353
2354			case I915_TILING_NONE:
2355				break;
2356			}
2357		}
2358
2359		if (kgem_bo_can_map__cpu(&sna->kgem, dst_bo, true))
2360			dst = kgem_bo_map__cpu(&sna->kgem, dst_bo);
2361		else
2362			dst = kgem_bo_map__wc(&sna->kgem, dst_bo);
2363		src = kgem_bo_map__cpu(&sna->kgem, src_bo);
2364	}
2365
2366	if (dst == NULL || src == NULL) {
2367use_gtt:
2368		dst = kgem_bo_map__gtt(&sna->kgem, dst_bo);
2369		src = kgem_bo_map__gtt(&sna->kgem, src_bo);
2370		if (dst == NULL || src == NULL)
2371			return false;
2372
2373		kgem_bo_sync__gtt(&sna->kgem, dst_bo);
2374		kgem_bo_sync__gtt(&sna->kgem, src_bo);
2375
2376		detile = NULL;
2377	} else {
2378		if (dst == dst_bo->map__wc)
2379			kgem_bo_sync__gtt(&sna->kgem, dst_bo);
2380		else
2381			kgem_bo_sync__cpu_full(&sna->kgem, dst_bo, true);
2382		kgem_bo_sync__cpu_full(&sna->kgem, src_bo, false);
2383	}
2384
2385	DBG(("%s: src(%d, %d), dst(%d, %d) x %d\n",
2386	     __FUNCTION__, sx, sy, dx, dy, n));
2387
2388	if (sigtrap_get() == 0) {
2389		if (detile) {
2390			do {
2391				detile(src, dst, dst_draw->bitsPerPixel,
2392				       src_bo->pitch, dst_bo->pitch,
2393				       box->x1 + sx, box->y1 + sy,
2394				       box->x1 + dx, box->y1 + dy,
2395				       box->x2 - box->x1, box->y2 - box->y1);
2396				box++;
2397			} while (--n);
2398		} else do {
2399			memcpy_blt(src, dst, dst_draw->bitsPerPixel,
2400				   src_bo->pitch, dst_bo->pitch,
2401				   box->x1 + sx, box->y1 + sy,
2402				   box->x1 + dx, box->y1 + dy,
2403				   box->x2 - box->x1, box->y2 - box->y1);
2404			box++;
2405		} while (--n);
2406		sigtrap_put();
2407	}
2408
2409	return true;
2410}
2411
2412void
2413sna_render_mark_wedged(struct sna *sna)
2414{
2415	sna->render.copy_boxes = memcpy_copy_boxes;
2416	sna->render.prefer_gpu = 0;
2417}
2418