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