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 ®ion, 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 ®ion, 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(®ion, 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, ®ion);
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, ®ion, &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