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