1 /*
2 * Copyright © 2010 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 "fb/fbpict.h"
35
36 struct sna_tile_span {
37 BoxRec box;
38 float opacity;
39 };
40
41 struct sna_tile_state {
42 int op;
43 PicturePtr src, mask, dst;
44 PixmapPtr dst_pixmap;
45 uint32_t dst_format;
46 int16_t src_x, src_y;
47 int16_t mask_x, mask_y;
48 int16_t dst_x, dst_y;
49 int16_t width, height;
50 unsigned flags;
51
52 int rect_count;
53 int rect_size;
54 struct sna_composite_rectangles rects_embedded[16], *rects;
55 };
56
57 static void
sna_tiling_composite_add_rect(struct sna_tile_state * tile,const struct sna_composite_rectangles * r)58 sna_tiling_composite_add_rect(struct sna_tile_state *tile,
59 const struct sna_composite_rectangles *r)
60 {
61 if (tile->rect_count == tile->rect_size) {
62 struct sna_composite_rectangles *a;
63 int newsize = tile->rect_size * 2;
64
65 if (tile->rects == tile->rects_embedded) {
66 a = malloc (sizeof(struct sna_composite_rectangles) * newsize);
67 if (a == NULL)
68 return;
69
70 memcpy(a,
71 tile->rects_embedded,
72 sizeof(struct sna_composite_rectangles) * tile->rect_count);
73 } else {
74 a = realloc(tile->rects,
75 sizeof(struct sna_composite_rectangles) * newsize);
76 if (a == NULL)
77 return;
78 }
79
80 tile->rects = a;
81 tile->rect_size = newsize;
82 }
83
84 tile->rects[tile->rect_count++] = *r;
85 }
86
87 fastcall static void
sna_tiling_composite_blt(struct sna * sna,const struct sna_composite_op * op,const struct sna_composite_rectangles * r)88 sna_tiling_composite_blt(struct sna *sna,
89 const struct sna_composite_op *op,
90 const struct sna_composite_rectangles *r)
91 {
92 sna_tiling_composite_add_rect(op->priv, r);
93 (void)sna;
94 }
95
96 fastcall static void
sna_tiling_composite_box(struct sna * sna,const struct sna_composite_op * op,const BoxRec * box)97 sna_tiling_composite_box(struct sna *sna,
98 const struct sna_composite_op *op,
99 const BoxRec *box)
100 {
101 struct sna_composite_rectangles r;
102
103 r.dst.x = box->x1;
104 r.dst.y = box->y1;
105 r.mask = r.src = r.dst;
106
107 r.width = box->x2 - box->x1;
108 r.height = box->y2 - box->y1;
109
110 sna_tiling_composite_add_rect(op->priv, &r);
111 (void)sna;
112 }
113
114 static void
sna_tiling_composite_boxes(struct sna * sna,const struct sna_composite_op * op,const BoxRec * box,int nbox)115 sna_tiling_composite_boxes(struct sna *sna,
116 const struct sna_composite_op *op,
117 const BoxRec *box, int nbox)
118 {
119 while (nbox--) {
120 struct sna_composite_rectangles r;
121
122 r.dst.x = box->x1;
123 r.dst.y = box->y1;
124 r.mask = r.src = r.dst;
125
126 r.width = box->x2 - box->x1;
127 r.height = box->y2 - box->y1;
128
129 sna_tiling_composite_add_rect(op->priv, &r);
130 box++;
131 }
132 (void)sna;
133 }
134
135 static void
sna_tiling_composite_done(struct sna * sna,const struct sna_composite_op * op)136 sna_tiling_composite_done(struct sna *sna,
137 const struct sna_composite_op *op)
138 {
139 struct sna_tile_state *tile = op->priv;
140 struct sna_composite_op tmp;
141 int x, y, n, step, max_size;
142
143 /* Use a small step to accommodate enlargement through tile alignment */
144 step = sna->render.max_3d_size;
145 if (tile->dst_x & (8*512 / tile->dst->pDrawable->bitsPerPixel - 1) ||
146 tile->dst_y & 63)
147 step /= 2;
148
149 max_size = sna_max_tile_copy_size(sna, op->dst.bo, op->dst.bo);
150 if (max_size == 0)
151 goto done;
152
153 while (step * step * 4 > max_size)
154 step /= 2;
155
156 DBG(("%s -- %dx%d, count=%d, step size=%d\n", __FUNCTION__,
157 tile->width, tile->height, tile->rect_count, step));
158
159 if (tile->rect_count == 0)
160 goto done;
161
162 for (y = 0; y < tile->height; y += step) {
163 int height = step;
164 if (y + height > tile->height)
165 height = tile->height - y;
166 for (x = 0; x < tile->width; x += step) {
167 int width = step;
168 if (x + width > tile->width)
169 width = tile->width - x;
170 if (sna->render.composite(sna, tile->op,
171 tile->src, tile->mask, tile->dst,
172 tile->src_x + x, tile->src_y + y,
173 tile->mask_x + x, tile->mask_y + y,
174 tile->dst_x + x, tile->dst_y + y,
175 width, height,
176 COMPOSITE_PARTIAL, memset(&tmp, 0, sizeof(tmp)))) {
177 for (n = 0; n < tile->rect_count; n++) {
178 const struct sna_composite_rectangles *r = &tile->rects[n];
179 int x1, x2, dx, y1, y2, dy;
180
181 x1 = r->dst.x - tile->dst_x, dx = 0;
182 if (x1 < x)
183 dx = x - x1, x1 = x;
184 y1 = r->dst.y - tile->dst_y, dy = 0;
185 if (y1 < y)
186 dy = y - y1, y1 = y;
187
188 x2 = r->dst.x + r->width - tile->dst_x;
189 if (x2 > x + width)
190 x2 = x + width;
191 y2 = r->dst.y + r->height - tile->dst_y;
192 if (y2 > y + height)
193 y2 = y + height;
194
195 DBG(("%s: rect[%d] = (%d, %d)x(%d,%d), tile=(%d,%d)x(%d, %d), blt=(%d,%d),(%d,%d), delta=(%d,%d)\n",
196 __FUNCTION__, n,
197 r->dst.x, r->dst.y,
198 r->width, r->height,
199 x, y, width, height,
200 x1, y1, x2, y2,
201 dx, dy));
202
203 if (y2 > y1 && x2 > x1) {
204 struct sna_composite_rectangles rr;
205 rr.src.x = dx + r->src.x;
206 rr.src.y = dy + r->src.y;
207
208 rr.mask.x = dx + r->mask.x;
209 rr.mask.y = dy + r->mask.y;
210
211 rr.dst.x = dx + r->dst.x;
212 rr.dst.y = dy + r->dst.y;
213
214 rr.width = x2 - x1;
215 rr.height = y2 - y1;
216
217 tmp.blt(sna, &tmp, &rr);
218 }
219 }
220 tmp.done(sna, &tmp);
221 } else {
222 unsigned int flags;
223 DBG(("%s -- falback\n", __FUNCTION__));
224
225 if (tile->op <= PictOpSrc)
226 flags = MOVE_WRITE;
227 else
228 flags = MOVE_WRITE | MOVE_READ;
229 if (!sna_drawable_move_to_cpu(tile->dst->pDrawable,
230 flags))
231 goto done;
232 if (tile->dst->alphaMap &&
233 !sna_drawable_move_to_cpu(tile->dst->alphaMap->pDrawable,
234 flags))
235 goto done;
236
237 if (tile->src->pDrawable &&
238 !sna_drawable_move_to_cpu(tile->src->pDrawable,
239 MOVE_READ))
240 goto done;
241 if (tile->src->alphaMap &&
242 !sna_drawable_move_to_cpu(tile->src->alphaMap->pDrawable,
243 MOVE_READ))
244 goto done;
245
246 if (tile->mask && tile->mask->pDrawable &&
247 !sna_drawable_move_to_cpu(tile->mask->pDrawable,
248 MOVE_READ))
249 goto done;
250
251 if (tile->mask && tile->mask->alphaMap &&
252 !sna_drawable_move_to_cpu(tile->mask->alphaMap->pDrawable,
253 MOVE_READ))
254 goto done;
255
256 if (sigtrap_get() == 0) {
257 fbComposite(tile->op,
258 tile->src, tile->mask, tile->dst,
259 tile->src_x + x, tile->src_y + y,
260 tile->mask_x + x, tile->mask_y + y,
261 tile->dst_x + x, tile->dst_y + y,
262 width, height);
263 sigtrap_put();
264 }
265 }
266 }
267 }
268
269 done:
270 if (tile->rects != tile->rects_embedded)
271 free(tile->rects);
272 free(tile);
273 }
274
275 bool
sna_tiling_composite(uint32_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,struct sna_composite_op * tmp)276 sna_tiling_composite(uint32_t op,
277 PicturePtr src,
278 PicturePtr mask,
279 PicturePtr dst,
280 int16_t src_x, int16_t src_y,
281 int16_t mask_x, int16_t mask_y,
282 int16_t dst_x, int16_t dst_y,
283 int16_t width, int16_t height,
284 struct sna_composite_op *tmp)
285 {
286 struct sna_tile_state *tile;
287 struct sna_pixmap *priv;
288
289 DBG(("%s size=(%d, %d), tile=%d\n",
290 __FUNCTION__, width, height,
291 to_sna_from_drawable(dst->pDrawable)->render.max_3d_size));
292
293 priv = sna_pixmap(get_drawable_pixmap(dst->pDrawable));
294 if (priv == NULL || priv->gpu_bo == NULL)
295 return false;
296
297 tile = malloc(sizeof(*tile));
298 if (!tile)
299 return false;
300
301 tile->op = op;
302
303 tile->src = src;
304 tile->mask = mask;
305 tile->dst = dst;
306
307 tile->src_x = src_x;
308 tile->src_y = src_y;
309 tile->mask_x = mask_x;
310 tile->mask_y = mask_y;
311 tile->dst_x = dst_x;
312 tile->dst_y = dst_y;
313 tile->width = width;
314 tile->height = height;
315 tile->rects = tile->rects_embedded;
316 tile->rect_count = 0;
317 tile->rect_size = ARRAY_SIZE(tile->rects_embedded);
318
319 tmp->blt = sna_tiling_composite_blt;
320 tmp->box = sna_tiling_composite_box;
321 tmp->boxes = sna_tiling_composite_boxes;
322 tmp->done = sna_tiling_composite_done;
323
324 tmp->priv = tile;
325 tmp->dst.bo = priv->gpu_bo;
326 return true;
327 }
328
329 fastcall static void
sna_tiling_composite_spans_box(struct sna * sna,const struct sna_composite_spans_op * op,const BoxRec * box,float opacity)330 sna_tiling_composite_spans_box(struct sna *sna,
331 const struct sna_composite_spans_op *op,
332 const BoxRec *box, float opacity)
333 {
334 struct sna_tile_state *tile = op->base.priv;
335 struct sna_tile_span *a;
336
337 if (tile->rect_count == tile->rect_size) {
338 int newsize = tile->rect_size * 2;
339
340 if (tile->rects == tile->rects_embedded) {
341 a = malloc (sizeof(struct sna_tile_span) * newsize);
342 if (a == NULL)
343 return;
344
345 memcpy(a,
346 tile->rects_embedded,
347 sizeof(struct sna_tile_span) * tile->rect_count);
348 } else {
349 a = realloc(tile->rects,
350 sizeof(struct sna_tile_span) * newsize);
351 if (a == NULL)
352 return;
353 }
354
355 tile->rects = (void *)a;
356 tile->rect_size = newsize;
357 } else
358 a = (void *)tile->rects;
359
360 a[tile->rect_count].box = *box;
361 a[tile->rect_count].opacity = opacity;
362 tile->rect_count++;
363 (void)sna;
364 }
365
366 static void
sna_tiling_composite_spans_boxes(struct sna * sna,const struct sna_composite_spans_op * op,const BoxRec * box,int nbox,float opacity)367 sna_tiling_composite_spans_boxes(struct sna *sna,
368 const struct sna_composite_spans_op *op,
369 const BoxRec *box, int nbox, float opacity)
370 {
371 while (nbox--)
372 sna_tiling_composite_spans_box(sna, op, box++, opacity);
373 }
374
375 fastcall static void
sna_tiling_composite_spans_done(struct sna * sna,const struct sna_composite_spans_op * op)376 sna_tiling_composite_spans_done(struct sna *sna,
377 const struct sna_composite_spans_op *op)
378 {
379 struct sna_tile_state *tile = op->base.priv;
380 struct sna_composite_spans_op tmp;
381 int x, y, n, step, max_size;
382 bool force_fallback = false;
383
384 /* Use a small step to accommodate enlargement through tile alignment */
385 step = sna->render.max_3d_size;
386 if (tile->dst_x & (8*512 / tile->dst->pDrawable->bitsPerPixel - 1) ||
387 tile->dst_y & 63)
388 step /= 2;
389
390 max_size = sna_max_tile_copy_size(sna, op->base.dst.bo, op->base.dst.bo);
391 if (max_size == 0)
392 goto done;
393
394 while (step * step * 4 > max_size)
395 step /= 2;
396
397 DBG(("%s -- %dx%d, count=%d, step size=%d\n", __FUNCTION__,
398 tile->width, tile->height, tile->rect_count, step));
399
400 if (tile->rect_count == 0)
401 goto done;
402
403 for (y = 0; y < tile->height; y += step) {
404 int height = step;
405 if (y + height > tile->height)
406 height = tile->height - y;
407 for (x = 0; x < tile->width; x += step) {
408 const struct sna_tile_span *r = (void *)tile->rects;
409 int width = step;
410 if (x + width > tile->width)
411 width = tile->width - x;
412 if (!force_fallback &&
413 sna->render.composite_spans(sna, tile->op,
414 tile->src, tile->dst,
415 tile->src_x + x, tile->src_y + y,
416 tile->dst_x + x, tile->dst_y + y,
417 width, height, tile->flags,
418 memset(&tmp, 0, sizeof(tmp)))) {
419 for (n = 0; n < tile->rect_count; n++) {
420 BoxRec b;
421
422 b.x1 = r->box.x1 - tile->dst_x;
423 if (b.x1 < x)
424 b.x1 = x;
425
426 b.y1 = r->box.y1 - tile->dst_y;
427 if (b.y1 < y)
428 b.y1 = y;
429
430 b.x2 = r->box.x2 - tile->dst_x;
431 if (b.x2 > x + width)
432 b.x2 = x + width;
433
434 b.y2 = r->box.y2 - tile->dst_y;
435 if (b.y2 > y + height)
436 b.y2 = y + height;
437
438 DBG(("%s: rect[%d] = (%d, %d)x(%d,%d), tile=(%d,%d)x(%d, %d), blt=(%d,%d),(%d,%d)\n",
439 __FUNCTION__, n,
440 r->box.x1, r->box.y1,
441 r->box.x2-r->box.x1, r->box.y2-r->box.y1,
442 x, y, width, height,
443 b.x1, b.y1, b.x2, b.y2));
444
445 if (b.y2 > b.y1 && b.x2 > b.x1)
446 tmp.box(sna, &tmp, &b, r->opacity);
447 r++;
448 }
449 tmp.done(sna, &tmp);
450 } else {
451 unsigned int flags;
452
453 DBG(("%s -- falback\n", __FUNCTION__));
454
455 if (tile->op <= PictOpSrc)
456 flags = MOVE_WRITE;
457 else
458 flags = MOVE_WRITE | MOVE_READ;
459 if (!sna_drawable_move_to_cpu(tile->dst->pDrawable,
460 flags))
461 goto done;
462 if (tile->dst->alphaMap &&
463 !sna_drawable_move_to_cpu(tile->dst->alphaMap->pDrawable,
464 flags))
465 goto done;
466
467 if (tile->src->pDrawable &&
468 !sna_drawable_move_to_cpu(tile->src->pDrawable,
469 MOVE_READ))
470 goto done;
471 if (tile->src->alphaMap &&
472 !sna_drawable_move_to_cpu(tile->src->alphaMap->pDrawable,
473 MOVE_READ))
474 goto done;
475
476 for (n = 0; n < tile->rect_count; n++) {
477 BoxRec b;
478
479 b.x1 = r->box.x1 - tile->dst_x;
480 if (b.x1 < x)
481 b.x1 = x;
482
483 b.y1 = r->box.y1 - tile->dst_y;
484 if (b.y1 < y)
485 b.y1 = y;
486
487 b.x2 = r->box.x2 - tile->dst_x;
488 if (b.x2 > x + width)
489 b.x2 = x + width;
490
491 b.y2 = r->box.y2 - tile->dst_y;
492 if (b.y2 > y + height)
493 b.y2 = y + height;
494
495 DBG(("%s: rect[%d] = (%d, %d)x(%d,%d), tile=(%d,%d)x(%d, %d), blt=(%d,%d),(%d,%d)\n",
496 __FUNCTION__, n,
497 r->box.x1, r->box.y1,
498 r->box.x2-r->box.x1, r->box.y2-r->box.y1,
499 x, y, width, height,
500 b.x1, b.y1, b.x2, b.y2));
501
502 if (b.y2 > b.y1 && b.x2 > b.x1) {
503 xRenderColor alpha;
504 PicturePtr mask;
505 int error;
506
507 alpha.red = alpha.green = alpha.blue = 0;
508 alpha.alpha = r->opacity * 0xffff;
509
510 mask = CreateSolidPicture(0, &alpha, &error);
511 if (!mask)
512 goto done;
513
514 if (sigtrap_get() == 0) {
515 fbComposite(tile->op,
516 tile->src, mask, tile->dst,
517 tile->src_x + x, tile->src_y + y,
518 0, 0,
519 tile->dst_x + x, tile->dst_y + y,
520 width, height);
521 sigtrap_put();
522 }
523
524 FreePicture(mask, 0);
525 }
526 r++;
527 }
528
529 force_fallback = true;
530 }
531 }
532 }
533
534 done:
535 if (tile->rects != tile->rects_embedded)
536 free(tile->rects);
537 free(tile);
538 }
539
540 bool
sna_tiling_composite_spans(uint32_t op,PicturePtr src,PicturePtr dst,int16_t src_x,int16_t src_y,int16_t dst_x,int16_t dst_y,int16_t width,int16_t height,unsigned flags,struct sna_composite_spans_op * tmp)541 sna_tiling_composite_spans(uint32_t op,
542 PicturePtr src,
543 PicturePtr dst,
544 int16_t src_x, int16_t src_y,
545 int16_t dst_x, int16_t dst_y,
546 int16_t width, int16_t height,
547 unsigned flags,
548 struct sna_composite_spans_op *tmp)
549 {
550 struct sna_tile_state *tile;
551 struct sna_pixmap *priv;
552
553 DBG(("%s size=(%d, %d), tile=%d\n",
554 __FUNCTION__, width, height,
555 to_sna_from_drawable(dst->pDrawable)->render.max_3d_size));
556
557 priv = sna_pixmap(get_drawable_pixmap(dst->pDrawable));
558 if (priv == NULL || priv->gpu_bo == NULL)
559 return false;
560
561 tile = malloc(sizeof(*tile));
562 if (!tile)
563 return false;
564
565 tile->op = op;
566 tile->flags = flags;
567
568 tile->src = src;
569 tile->mask = NULL;
570 tile->dst = dst;
571
572 tile->src_x = src_x;
573 tile->src_y = src_y;
574 tile->mask_x = 0;
575 tile->mask_y = 0;
576 tile->dst_x = dst_x;
577 tile->dst_y = dst_y;
578 tile->width = width;
579 tile->height = height;
580 tile->rects = tile->rects_embedded;
581 tile->rect_count = 0;
582 tile->rect_size = ARRAY_SIZE(tile->rects_embedded);
583 COMPILE_TIME_ASSERT(sizeof(tile->rects_embedded[0]) >= sizeof(struct sna_tile_span));
584
585 tmp->box = sna_tiling_composite_spans_box;
586 tmp->boxes = sna_tiling_composite_spans_boxes;
587 tmp->done = sna_tiling_composite_spans_done;
588
589 tmp->base.priv = tile;
590 tmp->base.dst.bo = priv->gpu_bo;
591 return true;
592 }
593
594 bool
sna_tiling_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)595 sna_tiling_fill_boxes(struct sna *sna,
596 CARD8 op,
597 PictFormat format,
598 const xRenderColor *color,
599 const DrawableRec *dst, struct kgem_bo *dst_bo,
600 const BoxRec *box, int n)
601 {
602 RegionRec region, tile, this;
603 struct kgem_bo *bo;
604 int step, max_size;
605 bool ret = false;
606
607 pixman_region_init_rects(®ion, box, n);
608
609 /* Use a small step to accommodate enlargement through tile alignment */
610 step = sna->render.max_3d_size;
611 if (region.extents.x1 & (8*512 / dst->bitsPerPixel - 1) ||
612 region.extents.y1 & 63)
613 step /= 2;
614
615 max_size = sna_max_tile_copy_size(sna, dst_bo, dst_bo);
616 if (max_size == 0)
617 goto done;
618
619 while (step * step * 4 > max_size)
620 step /= 2;
621
622 DBG(("%s (op=%d, format=%x, color=(%04x,%04x,%04x, %04x), tile.size=%d, box=%dx[(%d, %d), (%d, %d)])\n",
623 __FUNCTION__, op, (int)format,
624 color->red, color->green, color->blue, color->alpha,
625 step, n,
626 region.extents.x1, region.extents.y1,
627 region.extents.x2, region.extents.y2));
628
629 for (tile.extents.y1 = tile.extents.y2 = region.extents.y1;
630 tile.extents.y2 < region.extents.y2;
631 tile.extents.y1 = tile.extents.y2) {
632 int y2 = tile.extents.y1 + step;
633 if (y2 > region.extents.y2)
634 y2 = region.extents.y2;
635 tile.extents.y2 = y2;
636
637 for (tile.extents.x1 = tile.extents.x2 = region.extents.x1;
638 tile.extents.x2 < region.extents.x2;
639 tile.extents.x1 = tile.extents.x2) {
640 DrawableRec tmp;
641 int x2 = tile.extents.x1 + step;
642 if (x2 > region.extents.x2)
643 x2 = region.extents.x2;
644 tile.extents.x2 = x2;
645
646 tile.data = NULL;
647
648 RegionNull(&this);
649 RegionIntersect(&this, ®ion, &tile);
650 if (RegionNil(&this))
651 continue;
652
653 tmp.width = this.extents.x2 - this.extents.x1;
654 tmp.height = this.extents.y2 - this.extents.y1;
655 tmp.depth = dst->depth;
656 tmp.bitsPerPixel = dst->bitsPerPixel;
657
658 bo = kgem_create_2d(&sna->kgem,
659 tmp.width,
660 tmp.height,
661 dst->bitsPerPixel,
662 kgem_choose_tiling(&sna->kgem,
663 I915_TILING_X,
664 tmp.width,
665 tmp.height,
666 dst->bitsPerPixel),
667 CREATE_TEMPORARY);
668 if (bo) {
669 int16_t dx = this.extents.x1;
670 int16_t dy = this.extents.y1;
671
672 assert(kgem_bo_can_blt(&sna->kgem, bo));
673
674 if (op > PictOpSrc &&
675 !sna->render.copy_boxes(sna, GXcopy,
676 dst, dst_bo, 0, 0,
677 &tmp, bo, -dx, -dy,
678 region_rects(&this), region_num_rects(&this), 0))
679 goto err;
680
681 RegionTranslate(&this, -dx, -dy);
682 if (!sna->render.fill_boxes(sna, op, format, color, &tmp, bo,
683 region_rects(&this), region_num_rects(&this)))
684 goto err;
685
686 if (!sna->render.copy_boxes(sna, GXcopy,
687 &tmp, bo, 0, 0,
688 dst, dst_bo, dx, dy,
689 region_rects(&this), region_num_rects(&this), 0))
690 goto err;
691
692 kgem_bo_destroy(&sna->kgem, bo);
693 }
694 RegionUninit(&this);
695 }
696 }
697
698 ret = true;
699 goto done;
700 err:
701 kgem_bo_destroy(&sna->kgem, bo);
702 RegionUninit(&this);
703 done:
704 pixman_region_fini(®ion);
705 return ret;
706 }
707
708 fastcall static void
tiling_blt(struct sna * sna,const struct sna_composite_op * op,const struct sna_composite_rectangles * r)709 tiling_blt(struct sna *sna,
710 const struct sna_composite_op *op,
711 const struct sna_composite_rectangles *r)
712 {
713 int x1, x2, y1, y2;
714 int src_x, src_y;
715 BoxRec box;
716
717 DBG(("%s: src=(%d, %d), dst=(%d, %d), size=(%d, %d)\n",
718 __FUNCTION__,
719 r->src.x, r->src.y,
720 r->dst.x, r->dst.y,
721 r->width, r->height));
722
723 /* XXX higher layer should have clipped? */
724
725 x1 = r->dst.x + op->dst.x;
726 y1 = r->dst.y + op->dst.y;
727 x2 = x1 + r->width;
728 y2 = y1 + r->height;
729
730 src_x = r->src.x - x1 + op->u.blt.sx;
731 src_y = r->src.y - y1 + op->u.blt.sy;
732
733 /* clip against dst */
734 if (x1 < 0)
735 x1 = 0;
736 if (y1 < 0)
737 y1 = 0;
738
739 if (x2 > op->dst.width)
740 x2 = op->dst.width;
741
742 if (y2 > op->dst.height)
743 y2 = op->dst.height;
744
745 DBG(("%s: box=(%d, %d), (%d, %d)\n", __FUNCTION__, x1, y1, x2, y2));
746
747 if (x2 <= x1 || y2 <= y1)
748 return;
749
750 box.x1 = x1; box.y1 = y1;
751 box.x2 = x2; box.y2 = y2;
752 sna_tiling_blt_copy_boxes(sna, GXcopy,
753 op->src.bo, src_x, src_y,
754 op->dst.bo, 0, 0,
755 op->u.blt.bpp,
756 &box, 1);
757 }
758
759 fastcall static void
tiling_blt_box(struct sna * sna,const struct sna_composite_op * op,const BoxRec * box)760 tiling_blt_box(struct sna *sna,
761 const struct sna_composite_op *op,
762 const BoxRec *box)
763 {
764 DBG(("%s: box (%d, %d), (%d, %d)\n",
765 __FUNCTION__, box->x1, box->y1, box->x2, box->y2));
766 sna_tiling_blt_copy_boxes(sna, GXcopy,
767 op->src.bo, op->u.blt.sx, op->u.blt.sy,
768 op->dst.bo, op->dst.x, op->dst.y,
769 op->u.blt.bpp,
770 box, 1);
771 }
772
773 static void
tiling_blt_boxes(struct sna * sna,const struct sna_composite_op * op,const BoxRec * box,int nbox)774 tiling_blt_boxes(struct sna *sna,
775 const struct sna_composite_op *op,
776 const BoxRec *box, int nbox)
777 {
778 DBG(("%s: nbox=%d\n", __FUNCTION__, nbox));
779 sna_tiling_blt_copy_boxes(sna, GXcopy,
780 op->src.bo, op->u.blt.sx, op->u.blt.sy,
781 op->dst.bo, op->dst.x, op->dst.y,
782 op->u.blt.bpp,
783 box, nbox);
784 }
785
786 static bool
sna_tiling_blt_copy_boxes__with_alpha(struct sna * sna,uint8_t alu,struct kgem_bo * src_bo,int16_t src_dx,int16_t src_dy,struct kgem_bo * dst_bo,int16_t dst_dx,int16_t dst_dy,int bpp,int alpha_fixup,const BoxRec * box,int nbox)787 sna_tiling_blt_copy_boxes__with_alpha(struct sna *sna, uint8_t alu,
788 struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy,
789 struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy,
790 int bpp, int alpha_fixup,
791 const BoxRec *box, int nbox)
792 {
793 RegionRec region, tile, this;
794 struct kgem_bo *bo;
795 int max_size, step;
796 bool ret = false;
797
798 if (wedged(sna) ||
799 !kgem_bo_can_blt(&sna->kgem, src_bo) ||
800 !kgem_bo_can_blt(&sna->kgem, dst_bo)) {
801 /* XXX */
802 DBG(("%s: tiling blt fail: src?=%d, dst?=%d\n",
803 __FUNCTION__,
804 kgem_bo_can_blt(&sna->kgem, src_bo),
805 kgem_bo_can_blt(&sna->kgem, dst_bo)));
806 return false;
807 }
808
809 max_size = sna_max_tile_copy_size(sna, src_bo, dst_bo);
810 if (max_size == 0)
811 return false;
812
813 pixman_region_init_rects(®ion, box, nbox);
814
815 /* Use a small step to accommodate enlargement through tile alignment */
816 step = sna->render.max_3d_size;
817 if (region.extents.x1 & (8*512 / bpp - 1) || region.extents.y1 & 63)
818 step /= 2;
819 while (step * step * 4 > max_size)
820 step /= 2;
821 if (sna->kgem.gen < 033)
822 step /= 2; /* accommodate severe fence restrictions */
823 if (step == 0) {
824 DBG(("%s: tiles cannot fit into aperture\n", __FUNCTION__));
825 return false;
826 }
827
828 DBG(("%s (alu=%d), tile.size=%d, box=%dx[(%d, %d), (%d, %d)])\n",
829 __FUNCTION__, alu, step, nbox,
830 region.extents.x1, region.extents.y1,
831 region.extents.x2, region.extents.y2));
832
833 for (tile.extents.y1 = tile.extents.y2 = region.extents.y1;
834 tile.extents.y2 < region.extents.y2;
835 tile.extents.y1 = tile.extents.y2) {
836 int y2 = tile.extents.y1 + step;
837 if (y2 > region.extents.y2)
838 y2 = region.extents.y2;
839 tile.extents.y2 = y2;
840
841 for (tile.extents.x1 = tile.extents.x2 = region.extents.x1;
842 tile.extents.x2 < region.extents.x2;
843 tile.extents.x1 = tile.extents.x2) {
844 int w, h;
845 int x2 = tile.extents.x1 + step;
846 if (x2 > region.extents.x2)
847 x2 = region.extents.x2;
848 tile.extents.x2 = x2;
849
850 tile.data = NULL;
851
852 RegionNull(&this);
853 RegionIntersect(&this, ®ion, &tile);
854 if (RegionNil(&this))
855 continue;
856
857 w = this.extents.x2 - this.extents.x1;
858 h = this.extents.y2 - this.extents.y1;
859 bo = kgem_create_2d(&sna->kgem, w, h, bpp,
860 kgem_choose_tiling(&sna->kgem,
861 I915_TILING_X,
862 w, h, bpp),
863 CREATE_TEMPORARY);
864 if (bo) {
865 int16_t dx = this.extents.x1;
866 int16_t dy = this.extents.y1;
867
868 assert(kgem_bo_can_blt(&sna->kgem, bo));
869
870 if (!sna_blt_copy_boxes(sna, GXcopy,
871 src_bo, src_dx, src_dy,
872 bo, -dx, -dy,
873 bpp, region_rects(&this), region_num_rects(&this)))
874 goto err;
875
876 if (!sna_blt_copy_boxes__with_alpha(sna, alu,
877 bo, -dx, -dy,
878 dst_bo, dst_dx, dst_dy,
879 bpp, alpha_fixup,
880 region_rects(&this), region_num_rects(&this)))
881 goto err;
882
883 kgem_bo_destroy(&sna->kgem, bo);
884 }
885 RegionUninit(&this);
886 }
887 }
888
889 ret = true;
890 goto done;
891 err:
892 kgem_bo_destroy(&sna->kgem, bo);
893 RegionUninit(&this);
894 done:
895 pixman_region_fini(®ion);
896 return ret;
897 }
898
899 fastcall static void
tiling_blt__with_alpha(struct sna * sna,const struct sna_composite_op * op,const struct sna_composite_rectangles * r)900 tiling_blt__with_alpha(struct sna *sna,
901 const struct sna_composite_op *op,
902 const struct sna_composite_rectangles *r)
903 {
904 int x1, x2, y1, y2;
905 int src_x, src_y;
906 BoxRec box;
907
908 DBG(("%s: src=(%d, %d), dst=(%d, %d), size=(%d, %d)\n",
909 __FUNCTION__,
910 r->src.x, r->src.y,
911 r->dst.x, r->dst.y,
912 r->width, r->height));
913
914 /* XXX higher layer should have clipped? */
915
916 x1 = r->dst.x + op->dst.x;
917 y1 = r->dst.y + op->dst.y;
918 x2 = x1 + r->width;
919 y2 = y1 + r->height;
920
921 src_x = r->src.x - x1 + op->u.blt.sx;
922 src_y = r->src.y - y1 + op->u.blt.sy;
923
924 /* clip against dst */
925 if (x1 < 0)
926 x1 = 0;
927 if (y1 < 0)
928 y1 = 0;
929
930 if (x2 > op->dst.width)
931 x2 = op->dst.width;
932
933 if (y2 > op->dst.height)
934 y2 = op->dst.height;
935
936 DBG(("%s: box=(%d, %d), (%d, %d)\n", __FUNCTION__, x1, y1, x2, y2));
937
938 if (x2 <= x1 || y2 <= y1)
939 return;
940
941 box.x1 = x1; box.y1 = y1;
942 box.x2 = x2; box.y2 = y2;
943 sna_tiling_blt_copy_boxes__with_alpha(sna, GXcopy,
944 op->src.bo, src_x, src_y,
945 op->dst.bo, 0, 0,
946 op->u.blt.bpp, op->u.blt.pixel,
947 &box, 1);
948 }
949
950 fastcall static void
tiling_blt_box__with_alpha(struct sna * sna,const struct sna_composite_op * op,const BoxRec * box)951 tiling_blt_box__with_alpha(struct sna *sna,
952 const struct sna_composite_op *op,
953 const BoxRec *box)
954 {
955 DBG(("%s: box (%d, %d), (%d, %d)\n",
956 __FUNCTION__, box->x1, box->y1, box->x2, box->y2));
957 sna_tiling_blt_copy_boxes__with_alpha(sna, GXcopy,
958 op->src.bo, op->u.blt.sx, op->u.blt.sy,
959 op->dst.bo, op->dst.x, op->dst.y,
960 op->u.blt.bpp, op->u.blt.pixel,
961 box, 1);
962 }
963
964 static void
tiling_blt_boxes__with_alpha(struct sna * sna,const struct sna_composite_op * op,const BoxRec * box,int nbox)965 tiling_blt_boxes__with_alpha(struct sna *sna,
966 const struct sna_composite_op *op,
967 const BoxRec *box, int nbox)
968 {
969 DBG(("%s: nbox=%d\n", __FUNCTION__, nbox));
970 sna_tiling_blt_copy_boxes__with_alpha(sna, GXcopy,
971 op->src.bo, op->u.blt.sx, op->u.blt.sy,
972 op->dst.bo, op->dst.x, op->dst.y,
973 op->u.blt.bpp, op->u.blt.pixel,
974 box, nbox);
975 }
976
nop_done(struct sna * sna,const struct sna_composite_op * op)977 static void nop_done(struct sna *sna, const struct sna_composite_op *op)
978 {
979 assert(sna->kgem.nbatch <= KGEM_BATCH_SIZE(&sna->kgem));
980 (void)op;
981 }
982
983 bool
sna_tiling_blt_composite(struct sna * sna,struct sna_composite_op * op,struct kgem_bo * bo,int bpp,uint32_t alpha_fixup)984 sna_tiling_blt_composite(struct sna *sna,
985 struct sna_composite_op *op,
986 struct kgem_bo *bo,
987 int bpp,
988 uint32_t alpha_fixup)
989 {
990 assert(op->dst.bo);
991 assert(kgem_bo_can_blt(&sna->kgem, op->dst.bo));
992 assert(kgem_bo_can_blt(&sna->kgem, bo));
993
994 op->src.bo = bo;
995 op->u.blt.bpp = bpp;
996 op->u.blt.pixel = alpha_fixup;
997
998 if (alpha_fixup) {
999 op->blt = tiling_blt__with_alpha;
1000 op->box = tiling_blt_box__with_alpha;
1001 op->boxes = tiling_blt_boxes__with_alpha;
1002 } else {
1003 op->blt = tiling_blt;
1004 op->box = tiling_blt_box;
1005 op->boxes = tiling_blt_boxes;
1006 }
1007 op->done = nop_done;
1008
1009 return true;
1010 }
1011
sna_tiling_blt_copy_boxes(struct sna * sna,uint8_t alu,struct kgem_bo * src_bo,int16_t src_dx,int16_t src_dy,struct kgem_bo * dst_bo,int16_t dst_dx,int16_t dst_dy,int bpp,const BoxRec * box,int nbox)1012 bool sna_tiling_blt_copy_boxes(struct sna *sna, uint8_t alu,
1013 struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy,
1014 struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy,
1015 int bpp, const BoxRec *box, int nbox)
1016 {
1017 RegionRec region, tile, this;
1018 struct kgem_bo *bo;
1019 int max_size, step;
1020 bool ret = false;
1021
1022 DBG(("%s: alu=%d, src size=%d, dst size=%d\n", __FUNCTION__,
1023 alu, kgem_bo_size(src_bo), kgem_bo_size(dst_bo)));
1024
1025 if (wedged(sna) ||
1026 !kgem_bo_can_blt(&sna->kgem, src_bo) ||
1027 !kgem_bo_can_blt(&sna->kgem, dst_bo)) {
1028 /* XXX */
1029 DBG(("%s: tiling blt fail: src?=%d, dst?=%d\n",
1030 __FUNCTION__,
1031 kgem_bo_can_blt(&sna->kgem, src_bo),
1032 kgem_bo_can_blt(&sna->kgem, dst_bo)));
1033 return false;
1034 }
1035
1036 max_size = sna_max_tile_copy_size(sna, src_bo, dst_bo);
1037 if (max_size == 0)
1038 return false;
1039
1040 pixman_region_init_rects(®ion, box, nbox);
1041
1042 /* Use a small step to accommodate enlargement through tile alignment */
1043 step = sna->render.max_3d_size;
1044 if (region.extents.x1 & (8*512 / bpp - 1) || region.extents.y1 & 63)
1045 step /= 2;
1046 while (step * step * 4 > max_size)
1047 step /= 2;
1048 if (sna->kgem.gen < 033)
1049 step /= 2; /* accommodate severe fence restrictions */
1050 if (step == 0) {
1051 DBG(("%s: tiles cannot fit into aperture\n", __FUNCTION__));
1052 return false;
1053 }
1054
1055 DBG(("%s (alu=%d), tile.size=%d, box=%dx[(%d, %d), (%d, %d)])\n",
1056 __FUNCTION__, alu, step, nbox,
1057 region.extents.x1, region.extents.y1,
1058 region.extents.x2, region.extents.y2));
1059
1060 for (tile.extents.y1 = tile.extents.y2 = region.extents.y1;
1061 tile.extents.y2 < region.extents.y2;
1062 tile.extents.y1 = tile.extents.y2) {
1063 int y2 = tile.extents.y1 + step;
1064 if (y2 > region.extents.y2)
1065 y2 = region.extents.y2;
1066 tile.extents.y2 = y2;
1067
1068 for (tile.extents.x1 = tile.extents.x2 = region.extents.x1;
1069 tile.extents.x2 < region.extents.x2;
1070 tile.extents.x1 = tile.extents.x2) {
1071 int w, h;
1072 int x2 = tile.extents.x1 + step;
1073 if (x2 > region.extents.x2)
1074 x2 = region.extents.x2;
1075 tile.extents.x2 = x2;
1076
1077 tile.data = NULL;
1078
1079 RegionNull(&this);
1080 RegionIntersect(&this, ®ion, &tile);
1081 if (RegionNil(&this))
1082 continue;
1083
1084 w = this.extents.x2 - this.extents.x1;
1085 h = this.extents.y2 - this.extents.y1;
1086 bo = kgem_create_2d(&sna->kgem, w, h, bpp,
1087 kgem_choose_tiling(&sna->kgem,
1088 I915_TILING_X,
1089 w, h, bpp),
1090 CREATE_TEMPORARY);
1091 if (bo) {
1092 int16_t dx = this.extents.x1;
1093 int16_t dy = this.extents.y1;
1094
1095 assert(kgem_bo_can_blt(&sna->kgem, bo));
1096
1097 if (!sna_blt_copy_boxes(sna, GXcopy,
1098 src_bo, src_dx, src_dy,
1099 bo, -dx, -dy,
1100 bpp, region_rects(&this), region_num_rects(&this)))
1101 goto err;
1102
1103 if (!sna_blt_copy_boxes(sna, alu,
1104 bo, -dx, -dy,
1105 dst_bo, dst_dx, dst_dy,
1106 bpp, region_rects(&this), region_num_rects(&this)))
1107 goto err;
1108
1109 kgem_bo_destroy(&sna->kgem, bo);
1110 }
1111 RegionUninit(&this);
1112 }
1113 }
1114
1115 ret = true;
1116 goto done;
1117 err:
1118 kgem_bo_destroy(&sna->kgem, bo);
1119 RegionUninit(&this);
1120 done:
1121 pixman_region_fini(®ion);
1122 return ret;
1123 }
1124
1125 bool
sna_tiling_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)1126 sna_tiling_copy_boxes(struct sna *sna, uint8_t alu,
1127 const DrawableRec *src, struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy,
1128 const DrawableRec *dst, struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy,
1129 const BoxRec *box, int n)
1130 {
1131 BoxRec extents, tile, stack[64], *clipped, *c;
1132 DrawableRec p;
1133 int i, step, tiling;
1134 bool create = true;
1135 bool ret = false;
1136
1137 extents = box[0];
1138 for (i = 1; i < n; i++) {
1139 if (box[i].x1 < extents.x1)
1140 extents.x1 = box[i].x1;
1141 if (box[i].y1 < extents.y1)
1142 extents.y1 = box[i].y1;
1143
1144 if (box[i].x2 > extents.x2)
1145 extents.x2 = box[i].x2;
1146 if (box[i].y2 > extents.y2)
1147 extents.y2 = box[i].y2;
1148 }
1149
1150 tiling = I915_TILING_X;
1151 if (!kgem_bo_can_blt(&sna->kgem, src_bo) ||
1152 !kgem_bo_can_blt(&sna->kgem, dst_bo))
1153 tiling = I915_TILING_Y;
1154
1155 create = (src_bo->pitch > sna->render.max_3d_pitch ||
1156 dst_bo->pitch > sna->render.max_3d_pitch);
1157
1158 step = sna->render.max_3d_size / 2;
1159 if (create) {
1160 while (step * step * 4 > sna->kgem.max_upload_tile_size)
1161 step /= 2;
1162 }
1163
1164 DBG(("%s: tiling copy %dx%d, %s %dx%d %c tiles\n", __FUNCTION__,
1165 extents.x2-extents.x1, extents.y2-extents.y1,
1166 create ? "creating" : "using",
1167 step, step, tiling == I915_TILING_X ? 'X' : 'Y'));
1168
1169 if (n > ARRAY_SIZE(stack)) {
1170 clipped = malloc(sizeof(BoxRec) * n);
1171 if (clipped == NULL)
1172 goto tiled_error;
1173 } else
1174 clipped = stack;
1175
1176 p.depth = src->depth;
1177 p.bitsPerPixel = src->bitsPerPixel;
1178
1179 for (tile.y1 = extents.y1; tile.y1 < extents.y2; tile.y1 = tile.y2) {
1180 int y2 = tile.y1 + step;
1181 if (y2 > extents.y2)
1182 y2 = extents.y2;
1183 tile.y2 = y2;
1184
1185 for (tile.x1 = extents.x1; tile.x1 < extents.x2; tile.x1 = tile.x2) {
1186 struct kgem_bo *tmp_bo;
1187 int x2 = tile.x1 + step;
1188 if (x2 > extents.x2)
1189 x2 = extents.x2;
1190 tile.x2 = x2;
1191
1192 c = clipped;
1193 for (i = 0; i < n; i++) {
1194 *c = box[i];
1195 if (!box_intersect(c, &tile))
1196 continue;
1197
1198 DBG(("%s: box(%d, %d), (%d, %d), src=(%d, %d), dst=(%d, %d)\n",
1199 __FUNCTION__,
1200 c->x1, c->y1,
1201 c->x2, c->y2,
1202 src_dx, src_dy,
1203 c->x1 - tile.x1,
1204 c->y1 - tile.y1));
1205 c++;
1206 }
1207 if (c == clipped)
1208 continue;
1209
1210 p.width = tile.x2 - tile.x1;
1211 p.height = tile.y2 - tile.y1;
1212
1213 DBG(("%s: tile (%d, %d), (%d, %d)\n",
1214 __FUNCTION__, tile.x1, tile.y1, tile.x2, tile.y2));
1215
1216 if (create) {
1217 tmp_bo = kgem_create_2d(&sna->kgem,
1218 p.width,
1219 p.height,
1220 p.bitsPerPixel,
1221 tiling, CREATE_TEMPORARY);
1222 if (!tmp_bo)
1223 goto tiled_error;
1224
1225 i = (sna->render.copy_boxes(sna, GXcopy,
1226 src, src_bo, src_dx, src_dy,
1227 &p, tmp_bo, -tile.x1, -tile.y1,
1228 clipped, c - clipped, 0) &&
1229 sna->render.copy_boxes(sna, alu,
1230 &p, tmp_bo, -tile.x1, -tile.y1,
1231 dst, dst_bo, dst_dx, dst_dy,
1232 clipped, c - clipped, 0));
1233
1234 kgem_bo_destroy(&sna->kgem, tmp_bo);
1235 } else {
1236 i = sna->render.copy_boxes(sna, GXcopy,
1237 src, src_bo, src_dx, src_dy,
1238 dst, dst_bo, dst_dx, dst_dy,
1239 clipped, c - clipped, 0);
1240 }
1241
1242 if (!i)
1243 goto tiled_error;
1244 }
1245 }
1246
1247 ret = true;
1248 tiled_error:
1249 if (clipped != stack)
1250 free(clipped);
1251
1252 return ret;
1253 }
1254