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