Imported Upstream version 1.15.1
[deb_xorg-server.git] / exa / exa_render.c
CommitLineData
a09e091a
JB
1/*
2 * Copyright © 2001 Keith Packard
3 *
4 * Partly based on code that is Copyright © The XFree86 Project Inc.
5 *
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of Keith Packard not be used in
11 * advertising or publicity pertaining to distribution of the software without
12 * specific, written prior permission. Keith Packard makes no
13 * representations about the suitability of this software for any purpose. It
14 * is provided "as is" without express or implied warranty.
15 *
16 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22 * PERFORMANCE OF THIS SOFTWARE.
23 */
24
25#ifdef HAVE_DIX_CONFIG_H
26#include <dix-config.h>
27#endif
28
29#include <stdlib.h>
30
31#include "exa_priv.h"
32
33#include "mipict.h"
34
35#if DEBUG_TRACE_FALL
36static void
37exaCompositeFallbackPictDesc(PicturePtr pict, char *string, int n)
38{
39 char format[20];
40 char size[20];
41 char loc;
42 int temp;
43
44 if (!pict) {
45 snprintf(string, n, "None");
46 return;
47 }
48
49 switch (pict->format) {
50 case PICT_a8r8g8b8:
51 snprintf(format, 20, "ARGB8888");
52 break;
53 case PICT_x8r8g8b8:
54 snprintf(format, 20, "XRGB8888");
55 break;
56 case PICT_b8g8r8a8:
57 snprintf(format, 20, "BGRA8888");
58 break;
59 case PICT_b8g8r8x8:
60 snprintf(format, 20, "BGRX8888");
61 break;
62 case PICT_r5g6b5:
63 snprintf(format, 20, "RGB565 ");
64 break;
65 case PICT_x1r5g5b5:
66 snprintf(format, 20, "RGB555 ");
67 break;
68 case PICT_a8:
69 snprintf(format, 20, "A8 ");
70 break;
71 case PICT_a1:
72 snprintf(format, 20, "A1 ");
73 break;
74 default:
75 snprintf(format, 20, "0x%x", (int) pict->format);
76 break;
77 }
78
79 if (pict->pDrawable) {
80 loc = exaGetOffscreenPixmap(pict->pDrawable, &temp, &temp) ? 's' : 'm';
81
82 snprintf(size, 20, "%dx%d%s", pict->pDrawable->width,
83 pict->pDrawable->height, pict->repeat ? " R" : "");
84 }
85 else {
86 loc = '-';
87
88 snprintf(size, 20, "%s", pict->repeat ? " R" : "");
89 }
90
91 snprintf(string, n, "%p:%c fmt %s (%s)", pict->pDrawable, loc, format,
92 size);
93}
94
95static void
96exaPrintCompositeFallback(CARD8 op,
97 PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst)
98{
99 char sop[20];
100 char srcdesc[40], maskdesc[40], dstdesc[40];
101
102 switch (op) {
103 case PictOpSrc:
104 snprintf(sop, sizeof(sop), "Src");
105 break;
106 case PictOpOver:
107 snprintf(sop, sizeof(sop), "Over");
108 break;
109 default:
110 snprintf(sop, sizeof(sop), "0x%x", (int) op);
111 break;
112 }
113
114 exaCompositeFallbackPictDesc(pSrc, srcdesc, 40);
115 exaCompositeFallbackPictDesc(pMask, maskdesc, 40);
116 exaCompositeFallbackPictDesc(pDst, dstdesc, 40);
117
118 ErrorF("Composite fallback: op %s, \n"
119 " src %s, \n"
120 " mask %s, \n"
121 " dst %s, \n", sop, srcdesc, maskdesc, dstdesc);
122}
123#endif /* DEBUG_TRACE_FALL */
124
125Bool
126exaOpReadsDestination(CARD8 op)
127{
128 /* FALSE (does not read destination) is the list of ops in the protocol
129 * document with "0" in the "Fb" column and no "Ab" in the "Fa" column.
130 * That's just Clear and Src. ReduceCompositeOp() will already have
131 * converted con/disjoint clear/src to Clear or Src.
132 */
133 switch (op) {
134 case PictOpClear:
135 case PictOpSrc:
136 return FALSE;
137 default:
138 return TRUE;
139 }
140}
141
142static Bool
143exaGetPixelFromRGBA(CARD32 *pixel,
144 CARD16 red,
145 CARD16 green,
146 CARD16 blue, CARD16 alpha, PictFormatPtr pFormat)
147{
148 int rbits, bbits, gbits, abits;
149 int rshift, bshift, gshift, ashift;
150
151 *pixel = 0;
152
153 if (!PICT_FORMAT_COLOR(pFormat->format) &&
154 PICT_FORMAT_TYPE(pFormat->format) != PICT_TYPE_A)
155 return FALSE;
156
157 rbits = PICT_FORMAT_R(pFormat->format);
158 gbits = PICT_FORMAT_G(pFormat->format);
159 bbits = PICT_FORMAT_B(pFormat->format);
160 abits = PICT_FORMAT_A(pFormat->format);
161
162 rshift = pFormat->direct.red;
163 gshift = pFormat->direct.green;
164 bshift = pFormat->direct.blue;
165 ashift = pFormat->direct.alpha;
166
167 *pixel |= (blue >> (16 - bbits)) << bshift;
168 *pixel |= (red >> (16 - rbits)) << rshift;
169 *pixel |= (green >> (16 - gbits)) << gshift;
170 *pixel |= (alpha >> (16 - abits)) << ashift;
171
172 return TRUE;
173}
174
175static Bool
176exaGetRGBAFromPixel(CARD32 pixel,
177 CARD16 *red,
178 CARD16 *green,
179 CARD16 *blue,
180 CARD16 *alpha,
181 PictFormatPtr pFormat, PictFormatShort format)
182{
183 int rbits, bbits, gbits, abits;
184 int rshift, bshift, gshift, ashift;
185
186 if (!PICT_FORMAT_COLOR(format) && PICT_FORMAT_TYPE(format) != PICT_TYPE_A)
187 return FALSE;
188
189 rbits = PICT_FORMAT_R(format);
190 gbits = PICT_FORMAT_G(format);
191 bbits = PICT_FORMAT_B(format);
192 abits = PICT_FORMAT_A(format);
193
194 if (pFormat) {
195 rshift = pFormat->direct.red;
196 gshift = pFormat->direct.green;
197 bshift = pFormat->direct.blue;
198 ashift = pFormat->direct.alpha;
199 }
200 else if (format == PICT_a8r8g8b8) {
201 rshift = 16;
202 gshift = 8;
203 bshift = 0;
204 ashift = 24;
205 }
206 else
207 FatalError("EXA bug: exaGetRGBAFromPixel() doesn't match "
208 "createSourcePicture()\n");
209
210 if (rbits) {
211 *red = ((pixel >> rshift) & ((1 << rbits) - 1)) << (16 - rbits);
212 while (rbits < 16) {
213 *red |= *red >> rbits;
214 rbits <<= 1;
215 }
216
217 *green = ((pixel >> gshift) & ((1 << gbits) - 1)) << (16 - gbits);
218 while (gbits < 16) {
219 *green |= *green >> gbits;
220 gbits <<= 1;
221 }
222
223 *blue = ((pixel >> bshift) & ((1 << bbits) - 1)) << (16 - bbits);
224 while (bbits < 16) {
225 *blue |= *blue >> bbits;
226 bbits <<= 1;
227 }
228 }
229 else {
230 *red = 0x0000;
231 *green = 0x0000;
232 *blue = 0x0000;
233 }
234
235 if (abits) {
236 *alpha = ((pixel >> ashift) & ((1 << abits) - 1)) << (16 - abits);
237 while (abits < 16) {
238 *alpha |= *alpha >> abits;
239 abits <<= 1;
240 }
241 }
242 else
243 *alpha = 0xffff;
244
245 return TRUE;
246}
247
248static int
249exaTryDriverSolidFill(PicturePtr pSrc,
250 PicturePtr pDst,
251 INT16 xSrc,
252 INT16 ySrc,
253 INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
254{
255 ExaScreenPriv(pDst->pDrawable->pScreen);
256 RegionRec region;
257 BoxPtr pbox;
258 int nbox;
259 int dst_off_x, dst_off_y;
260 PixmapPtr pSrcPix, pDstPix;
261 ExaPixmapPrivPtr pDstExaPix;
262 CARD32 pixel;
263 CARD16 red, green, blue, alpha;
264
265 pDstPix = exaGetDrawablePixmap(pDst->pDrawable);
266 pDstExaPix = ExaGetPixmapPriv(pDstPix);
267
268 /* Check whether the accelerator can use the destination pixmap.
269 */
270 if (pDstExaPix->accel_blocked) {
271 return -1;
272 }
273
274 xDst += pDst->pDrawable->x;
275 yDst += pDst->pDrawable->y;
276 if (pSrc->pDrawable) {
277 xSrc += pSrc->pDrawable->x;
278 ySrc += pSrc->pDrawable->y;
279 }
280
281 if (!miComputeCompositeRegion(&region, pSrc, NULL, pDst,
282 xSrc, ySrc, 0, 0, xDst, yDst, width, height))
283 return 1;
284
285 exaGetDrawableDeltas(pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y);
286
287 RegionTranslate(&region, dst_off_x, dst_off_y);
288
289 if (pSrc->pDrawable) {
290 pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable);
291 pixel = exaGetPixmapFirstPixel(pSrcPix);
292 }
293 else
294 pixel = pSrc->pSourcePict->solidFill.color;
295
296 if (!exaGetRGBAFromPixel(pixel, &red, &green, &blue, &alpha,
297 pSrc->pFormat, pSrc->format) ||
298 !exaGetPixelFromRGBA(&pixel, red, green, blue, alpha, pDst->pFormat)) {
299 RegionUninit(&region);
300 return -1;
301 }
302
303 if (pExaScr->do_migration) {
304 ExaMigrationRec pixmaps[1];
305
306 pixmaps[0].as_dst = TRUE;
307 pixmaps[0].as_src = FALSE;
308 pixmaps[0].pPix = pDstPix;
309 pixmaps[0].pReg = &region;
310 exaDoMigration(pixmaps, 1, TRUE);
311 }
312
313 if (!exaPixmapHasGpuCopy(pDstPix)) {
314 RegionUninit(&region);
315 return 0;
316 }
317
318 if (!(*pExaScr->info->PrepareSolid) (pDstPix, GXcopy, 0xffffffff, pixel)) {
319 RegionUninit(&region);
320 return -1;
321 }
322
323 nbox = RegionNumRects(&region);
324 pbox = RegionRects(&region);
325
326 while (nbox--) {
327 (*pExaScr->info->Solid) (pDstPix, pbox->x1, pbox->y1, pbox->x2,
328 pbox->y2);
329 pbox++;
330 }
331
332 (*pExaScr->info->DoneSolid) (pDstPix);
333 exaMarkSync(pDst->pDrawable->pScreen);
334
335 RegionUninit(&region);
336 return 1;
337}
338
339static int
340exaTryDriverCompositeRects(CARD8 op,
341 PicturePtr pSrc,
342 PicturePtr pMask,
343 PicturePtr pDst,
344 int nrect, ExaCompositeRectPtr rects)
345{
346 ExaScreenPriv(pDst->pDrawable->pScreen);
347 int src_off_x = 0, src_off_y = 0, mask_off_x = 0, mask_off_y = 0;
348 int dst_off_x, dst_off_y;
349 PixmapPtr pSrcPix = NULL, pMaskPix = NULL, pDstPix;
350 ExaPixmapPrivPtr pSrcExaPix = NULL, pMaskExaPix = NULL, pDstExaPix;
351
352 if (!pExaScr->info->PrepareComposite)
353 return -1;
354
355 if (pSrc->pDrawable) {
356 pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable);
357 pSrcExaPix = ExaGetPixmapPriv(pSrcPix);
358 }
359
360 if (pMask && pMask->pDrawable) {
361 pMaskPix = exaGetDrawablePixmap(pMask->pDrawable);
362 pMaskExaPix = ExaGetPixmapPriv(pMaskPix);
363 }
364
365 pDstPix = exaGetDrawablePixmap(pDst->pDrawable);
366 pDstExaPix = ExaGetPixmapPriv(pDstPix);
367
368 /* Check whether the accelerator can use these pixmaps.
369 * FIXME: If it cannot, use temporary pixmaps so that the drawing
370 * happens within limits.
371 */
372 if (pDstExaPix->accel_blocked ||
373 (pSrcExaPix && pSrcExaPix->accel_blocked) ||
374 (pMaskExaPix && pMaskExaPix->accel_blocked)) {
375 return -1;
376 }
377
378 if (pExaScr->info->CheckComposite &&
379 !(*pExaScr->info->CheckComposite) (op, pSrc, pMask, pDst)) {
380 return -1;
381 }
382
383 if (pExaScr->do_migration) {
384 ExaMigrationRec pixmaps[3];
385 int i = 0;
386
387 pixmaps[i].as_dst = TRUE;
388 pixmaps[i].as_src = exaOpReadsDestination(op);
389 pixmaps[i].pPix = pDstPix;
390 pixmaps[i].pReg = NULL;
391 i++;
392
393 if (pSrcPix) {
394 pixmaps[i].as_dst = FALSE;
395 pixmaps[i].as_src = TRUE;
396 pixmaps[i].pPix = pSrcPix;
397 pixmaps[i].pReg = NULL;
398 i++;
399 }
400
401 if (pMaskPix) {
402 pixmaps[i].as_dst = FALSE;
403 pixmaps[i].as_src = TRUE;
404 pixmaps[i].pPix = pMaskPix;
405 pixmaps[i].pReg = NULL;
406 i++;
407 }
408
409 exaDoMigration(pixmaps, i, TRUE);
410 }
411
412 pDstPix = exaGetOffscreenPixmap(pDst->pDrawable, &dst_off_x, &dst_off_y);
413 if (!pDstPix)
414 return 0;
415
416 if (pSrcPix) {
417 pSrcPix =
418 exaGetOffscreenPixmap(pSrc->pDrawable, &src_off_x, &src_off_y);
419 if (!pSrcPix)
420 return 0;
421 }
422
423 if (pMaskPix) {
424 pMaskPix =
425 exaGetOffscreenPixmap(pMask->pDrawable, &mask_off_x, &mask_off_y);
426 if (!pMaskPix)
427 return 0;
428 }
429
430 if (!(*pExaScr->info->PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix,
431 pMaskPix, pDstPix))
432 return -1;
433
434 while (nrect--) {
435 INT16 xDst = rects->xDst + pDst->pDrawable->x;
436 INT16 yDst = rects->yDst + pDst->pDrawable->y;
437 INT16 xMask = rects->xMask;
438 INT16 yMask = rects->yMask;
439 INT16 xSrc = rects->xSrc;
440 INT16 ySrc = rects->ySrc;
441 RegionRec region;
442 BoxPtr pbox;
443 int nbox;
444
445 if (pMaskPix) {
446 xMask += pMask->pDrawable->x;
447 yMask += pMask->pDrawable->y;
448 }
449
450 if (pSrcPix) {
451 xSrc += pSrc->pDrawable->x;
452 ySrc += pSrc->pDrawable->y;
453 }
454
455 if (!miComputeCompositeRegion(&region, pSrc, pMask, pDst,
456 xSrc, ySrc, xMask, yMask, xDst, yDst,
457 rects->width, rects->height))
458 goto next_rect;
459
460 RegionTranslate(&region, dst_off_x, dst_off_y);
461
462 nbox = RegionNumRects(&region);
463 pbox = RegionRects(&region);
464
465 xMask = xMask + mask_off_x - xDst - dst_off_x;
466 yMask = yMask + mask_off_y - yDst - dst_off_y;
467 xSrc = xSrc + src_off_x - xDst - dst_off_x;
468 ySrc = ySrc + src_off_y - yDst - dst_off_y;
469
470 while (nbox--) {
471 (*pExaScr->info->Composite) (pDstPix,
472 pbox->x1 + xSrc,
473 pbox->y1 + ySrc,
474 pbox->x1 + xMask,
475 pbox->y1 + yMask,
476 pbox->x1,
477 pbox->y1,
478 pbox->x2 - pbox->x1,
479 pbox->y2 - pbox->y1);
480 pbox++;
481 }
482
483 next_rect:
484 RegionUninit(&region);
485
486 rects++;
487 }
488
489 (*pExaScr->info->DoneComposite) (pDstPix);
490 exaMarkSync(pDst->pDrawable->pScreen);
491
492 return 1;
493}
494
495/**
496 * Copy a number of rectangles from source to destination in a single
497 * operation. This is specialized for glyph rendering: we don't have the
498 * special-case fallbacks found in exaComposite() - if the driver can support
499 * it, we use the driver functionality, otherwise we fall back straight to
500 * software.
501 */
502void
503exaCompositeRects(CARD8 op,
504 PicturePtr pSrc,
505 PicturePtr pMask,
506 PicturePtr pDst, int nrect, ExaCompositeRectPtr rects)
507{
508 ExaScreenPriv(pDst->pDrawable->pScreen);
509 int n;
510 ExaCompositeRectPtr r;
511 int ret;
512
513 /* If we get a mask, that means we're rendering to the exaGlyphs
514 * destination directly, so the damage layer takes care of this.
515 */
516 if (!pMask) {
517 RegionRec region;
518 int x1 = MAXSHORT;
519 int y1 = MAXSHORT;
520 int x2 = MINSHORT;
521 int y2 = MINSHORT;
522 BoxRec box;
523
524 /* We have to manage the damage ourselves, since CompositeRects isn't
525 * something in the screen that can be managed by the damage extension,
526 * and EXA depends on damage to track what needs to be migrated between
527 * the gpu and the cpu.
528 */
529
530 /* Compute the overall extents of the composited region - we're making
531 * the assumption here that we are compositing a bunch of glyphs that
532 * cluster closely together and damaging each glyph individually would
533 * be a loss compared to damaging the bounding box.
534 */
535 n = nrect;
536 r = rects;
537 while (n--) {
538 int rect_x2 = r->xDst + r->width;
539 int rect_y2 = r->yDst + r->height;
540
541 if (r->xDst < x1)
542 x1 = r->xDst;
543 if (r->yDst < y1)
544 y1 = r->yDst;
545 if (rect_x2 > x2)
546 x2 = rect_x2;
547 if (rect_y2 > y2)
548 y2 = rect_y2;
549
550 r++;
551 }
552
553 if (x2 <= x1 || y2 <= y1)
554 return;
555
556 box.x1 = x1;
557 box.x2 = x2 < MAXSHORT ? x2 : MAXSHORT;
558 box.y1 = y1;
559 box.y2 = y2 < MAXSHORT ? y2 : MAXSHORT;
560
561 /* The pixmap migration code relies on pendingDamage indicating
562 * the bounds of the current rendering, so we need to force
563 * the actual damage into that region before we do anything, and
564 * (see use of DamagePendingRegion in exaCopyDirty)
565 */
566
567 RegionInit(&region, &box, 1);
568
569 DamageRegionAppend(pDst->pDrawable, &region);
570
571 RegionUninit(&region);
572 }
573
574 /************************************************************/
575
576 ValidatePicture(pSrc);
577 if (pMask)
578 ValidatePicture(pMask);
579 ValidatePicture(pDst);
580
581 ret = exaTryDriverCompositeRects(op, pSrc, pMask, pDst, nrect, rects);
582
583 if (ret != 1) {
584 if (ret == -1 && op == PictOpOver && pMask && pMask->componentAlpha &&
585 (!pExaScr->info->CheckComposite ||
586 ((*pExaScr->info->CheckComposite) (PictOpOutReverse, pSrc, pMask,
587 pDst) &&
588 (*pExaScr->info->CheckComposite) (PictOpAdd, pSrc, pMask,
589 pDst)))) {
590 ret =
591 exaTryDriverCompositeRects(PictOpOutReverse, pSrc, pMask, pDst,
592 nrect, rects);
593 if (ret == 1) {
594 op = PictOpAdd;
595 ret = exaTryDriverCompositeRects(op, pSrc, pMask, pDst, nrect,
596 rects);
597 }
598 }
599
600 if (ret != 1) {
601 n = nrect;
602 r = rects;
603 while (n--) {
604 ExaCheckComposite(op, pSrc, pMask, pDst,
605 r->xSrc, r->ySrc,
606 r->xMask, r->yMask,
607 r->xDst, r->yDst, r->width, r->height);
608 r++;
609 }
610 }
611 }
612
613 /************************************************************/
614
615 if (!pMask) {
616 /* Now we have to flush the damage out from pendingDamage => damage
617 * Calling DamageRegionProcessPending has that effect.
618 */
619
620 DamageRegionProcessPending(pDst->pDrawable);
621 }
622}
623
624static int
625exaTryDriverComposite(CARD8 op,
626 PicturePtr pSrc,
627 PicturePtr pMask,
628 PicturePtr pDst,
629 INT16 xSrc,
630 INT16 ySrc,
631 INT16 xMask,
632 INT16 yMask,
633 INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
634{
635 ExaScreenPriv(pDst->pDrawable->pScreen);
636 RegionRec region;
637 BoxPtr pbox;
638 int nbox;
639 int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y;
640 PixmapPtr pSrcPix = NULL, pMaskPix = NULL, pDstPix;
641 ExaPixmapPrivPtr pSrcExaPix = NULL, pMaskExaPix = NULL, pDstExaPix;
642
643 if (pSrc->pDrawable) {
644 pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable);
645 pSrcExaPix = ExaGetPixmapPriv(pSrcPix);
646 }
647
648 pDstPix = exaGetDrawablePixmap(pDst->pDrawable);
649 pDstExaPix = ExaGetPixmapPriv(pDstPix);
650
651 if (pMask && pMask->pDrawable) {
652 pMaskPix = exaGetDrawablePixmap(pMask->pDrawable);
653 pMaskExaPix = ExaGetPixmapPriv(pMaskPix);
654 }
655
656 /* Check whether the accelerator can use these pixmaps.
657 * FIXME: If it cannot, use temporary pixmaps so that the drawing
658 * happens within limits.
659 */
660 if (pDstExaPix->accel_blocked ||
661 (pSrcExaPix && pSrcExaPix->accel_blocked) ||
662 (pMaskExaPix && (pMaskExaPix->accel_blocked))) {
663 return -1;
664 }
665
666 xDst += pDst->pDrawable->x;
667 yDst += pDst->pDrawable->y;
668
669 if (pMaskPix) {
670 xMask += pMask->pDrawable->x;
671 yMask += pMask->pDrawable->y;
672 }
673
674 if (pSrcPix) {
675 xSrc += pSrc->pDrawable->x;
676 ySrc += pSrc->pDrawable->y;
677 }
678
679 if (pExaScr->info->CheckComposite &&
680 !(*pExaScr->info->CheckComposite) (op, pSrc, pMask, pDst)) {
681 return -1;
682 }
683
684 if (!miComputeCompositeRegion(&region, pSrc, pMask, pDst,
685 xSrc, ySrc, xMask, yMask, xDst, yDst,
686 width, height))
687 return 1;
688
689 exaGetDrawableDeltas(pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y);
690
691 RegionTranslate(&region, dst_off_x, dst_off_y);
692
693 if (pExaScr->do_migration) {
694 ExaMigrationRec pixmaps[3];
695 int i = 0;
696
697 pixmaps[i].as_dst = TRUE;
698 pixmaps[i].as_src = exaOpReadsDestination(op);
699 pixmaps[i].pPix = pDstPix;
700 pixmaps[i].pReg = pixmaps[0].as_src ? NULL : &region;
701 i++;
702
703 if (pSrcPix) {
704 pixmaps[i].as_dst = FALSE;
705 pixmaps[i].as_src = TRUE;
706 pixmaps[i].pPix = pSrcPix;
707 pixmaps[i].pReg = NULL;
708 i++;
709 }
710
711 if (pMaskPix) {
712 pixmaps[i].as_dst = FALSE;
713 pixmaps[i].as_src = TRUE;
714 pixmaps[i].pPix = pMaskPix;
715 pixmaps[i].pReg = NULL;
716 i++;
717 }
718
719 exaDoMigration(pixmaps, i, TRUE);
720 }
721
722 if (pSrcPix) {
723 pSrcPix =
724 exaGetOffscreenPixmap(pSrc->pDrawable, &src_off_x, &src_off_y);
725 if (!pSrcPix) {
726 RegionUninit(&region);
727 return 0;
728 }
729 }
730
731 if (pMaskPix) {
732 pMaskPix = exaGetOffscreenPixmap(pMask->pDrawable, &mask_off_x,
733 &mask_off_y);
734 if (!pMaskPix) {
735 RegionUninit(&region);
736 return 0;
737 }
738 }
739
740 if (!exaPixmapHasGpuCopy(pDstPix)) {
741 RegionUninit(&region);
742 return 0;
743 }
744
745 if (!(*pExaScr->info->PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix,
746 pMaskPix, pDstPix)) {
747 RegionUninit(&region);
748 return -1;
749 }
750
751 nbox = RegionNumRects(&region);
752 pbox = RegionRects(&region);
753
754 xMask = xMask + mask_off_x - xDst - dst_off_x;
755 yMask = yMask + mask_off_y - yDst - dst_off_y;
756
757 xSrc = xSrc + src_off_x - xDst - dst_off_x;
758 ySrc = ySrc + src_off_y - yDst - dst_off_y;
759
760 while (nbox--) {
761 (*pExaScr->info->Composite) (pDstPix,
762 pbox->x1 + xSrc,
763 pbox->y1 + ySrc,
764 pbox->x1 + xMask,
765 pbox->y1 + yMask,
766 pbox->x1,
767 pbox->y1,
768 pbox->x2 - pbox->x1, pbox->y2 - pbox->y1);
769 pbox++;
770 }
771 (*pExaScr->info->DoneComposite) (pDstPix);
772 exaMarkSync(pDst->pDrawable->pScreen);
773
774 RegionUninit(&region);
775 return 1;
776}
777
778/**
779 * exaTryMagicTwoPassCompositeHelper implements PictOpOver using two passes of
780 * simpler operations PictOpOutReverse and PictOpAdd. Mainly used for component
781 * alpha and limited 1-tmu cards.
782 *
783 * From http://anholt.livejournal.com/32058.html:
784 *
785 * The trouble is that component-alpha rendering requires two different sources
786 * for blending: one for the source value to the blender, which is the
787 * per-channel multiplication of source and mask, and one for the source alpha
788 * for multiplying with the destination channels, which is the multiplication
789 * of the source channels by the mask alpha. So the equation for Over is:
790 *
791 * dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A
792 * dst.R = src.R * mask.R + (1 - (src.A * mask.R)) * dst.R
793 * dst.G = src.G * mask.G + (1 - (src.A * mask.G)) * dst.G
794 * dst.B = src.B * mask.B + (1 - (src.A * mask.B)) * dst.B
795 *
796 * But we can do some simpler operations, right? How about PictOpOutReverse,
797 * which has a source factor of 0 and dest factor of (1 - source alpha). We
798 * can get the source alpha value (srca.X = src.A * mask.X) out of the texture
799 * blenders pretty easily. So we can do a component-alpha OutReverse, which
800 * gets us:
801 *
802 * dst.A = 0 + (1 - (src.A * mask.A)) * dst.A
803 * dst.R = 0 + (1 - (src.A * mask.R)) * dst.R
804 * dst.G = 0 + (1 - (src.A * mask.G)) * dst.G
805 * dst.B = 0 + (1 - (src.A * mask.B)) * dst.B
806 *
807 * OK. And if an op doesn't use the source alpha value for the destination
808 * factor, then we can do the channel multiplication in the texture blenders
809 * to get the source value, and ignore the source alpha that we wouldn't use.
810 * We've supported this in the Radeon driver for a long time. An example would
811 * be PictOpAdd, which does:
812 *
813 * dst.A = src.A * mask.A + dst.A
814 * dst.R = src.R * mask.R + dst.R
815 * dst.G = src.G * mask.G + dst.G
816 * dst.B = src.B * mask.B + dst.B
817 *
818 * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right
819 * after it, we get:
820 *
821 * dst.A = src.A * mask.A + ((1 - (src.A * mask.A)) * dst.A)
822 * dst.R = src.R * mask.R + ((1 - (src.A * mask.R)) * dst.R)
823 * dst.G = src.G * mask.G + ((1 - (src.A * mask.G)) * dst.G)
824 * dst.B = src.B * mask.B + ((1 - (src.A * mask.B)) * dst.B)
825 */
826
827static int
828exaTryMagicTwoPassCompositeHelper(CARD8 op,
829 PicturePtr pSrc,
830 PicturePtr pMask,
831 PicturePtr pDst,
832 INT16 xSrc,
833 INT16 ySrc,
834 INT16 xMask,
835 INT16 yMask,
836 INT16 xDst,
837 INT16 yDst, CARD16 width, CARD16 height)
838{
839 ExaScreenPriv(pDst->pDrawable->pScreen);
840
841 assert(op == PictOpOver);
842
843 if (pExaScr->info->CheckComposite &&
844 (!(*pExaScr->info->CheckComposite) (PictOpOutReverse, pSrc, pMask,
845 pDst) ||
846 !(*pExaScr->info->CheckComposite) (PictOpAdd, pSrc, pMask, pDst))) {
847 return -1;
848 }
849
850 /* Now, we think we should be able to accelerate this operation. First,
851 * composite the destination to be the destination times the source alpha
852 * factors.
853 */
854 exaComposite(PictOpOutReverse, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask,
855 xDst, yDst, width, height);
856
857 /* Then, add in the source value times the destination alpha factors (1.0).
858 */
859 exaComposite(PictOpAdd, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask,
860 xDst, yDst, width, height);
861
862 return 1;
863}
864
865void
866exaComposite(CARD8 op,
867 PicturePtr pSrc,
868 PicturePtr pMask,
869 PicturePtr pDst,
870 INT16 xSrc,
871 INT16 ySrc,
872 INT16 xMask,
873 INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
874{
875 ExaScreenPriv(pDst->pDrawable->pScreen);
876 int ret = -1;
877 Bool saveSrcRepeat = pSrc->repeat;
878 Bool saveMaskRepeat = pMask ? pMask->repeat : 0;
879 RegionRec region;
880
881 if (pExaScr->swappedOut)
882 goto fallback;
883
884 /* Remove repeat in source if useless */
885 if (pSrc->pDrawable && pSrc->repeat && !pSrc->transform && xSrc >= 0 &&
886 (xSrc + width) <= pSrc->pDrawable->width && ySrc >= 0 &&
887 (ySrc + height) <= pSrc->pDrawable->height)
888 pSrc->repeat = 0;
889
890 if (!pMask && !pSrc->alphaMap && !pDst->alphaMap &&
891 (op == PictOpSrc || (op == PictOpOver && !PICT_FORMAT_A(pSrc->format))))
892 {
893 if (pSrc->pDrawable ?
894 (pSrc->pDrawable->width == 1 && pSrc->pDrawable->height == 1 &&
895 pSrc->repeat) :
896 (pSrc->pSourcePict->type == SourcePictTypeSolidFill)) {
897 ret = exaTryDriverSolidFill(pSrc, pDst, xSrc, ySrc, xDst, yDst,
898 width, height);
899 if (ret == 1)
900 goto done;
901 }
902 else if (pSrc->pDrawable && !pSrc->transform &&
903 ((op == PictOpSrc &&
904 (pSrc->format == pDst->format ||
905 (PICT_FORMAT_COLOR(pDst->format) &&
906 PICT_FORMAT_COLOR(pSrc->format) &&
907 pDst->format == PICT_FORMAT(PICT_FORMAT_BPP(pSrc->format),
908 PICT_FORMAT_TYPE(pSrc->format),
909 0,
910 PICT_FORMAT_R(pSrc->format),
911 PICT_FORMAT_G(pSrc->format),
912 PICT_FORMAT_B(pSrc->format)))))
913 || (op == PictOpOver && pSrc->format == pDst->format &&
914 !PICT_FORMAT_A(pSrc->format)))) {
915 if (!pSrc->repeat && xSrc >= 0 && ySrc >= 0 &&
916 (xSrc + width <= pSrc->pDrawable->width) &&
917 (ySrc + height <= pSrc->pDrawable->height)) {
918 Bool ret;
919
920 xDst += pDst->pDrawable->x;
921 yDst += pDst->pDrawable->y;
922 xSrc += pSrc->pDrawable->x;
923 ySrc += pSrc->pDrawable->y;
924
925 if (!miComputeCompositeRegion(&region, pSrc, pMask, pDst,
926 xSrc, ySrc, xMask, yMask, xDst,
927 yDst, width, height))
928 goto done;
929
930 ret = exaHWCopyNtoN(pSrc->pDrawable, pDst->pDrawable, NULL,
931 RegionRects(&region),
932 RegionNumRects(&region), xSrc - xDst,
933 ySrc - yDst, FALSE, FALSE);
934 RegionUninit(&region);
935
936 /* Reset values to their original values. */
937 xDst -= pDst->pDrawable->x;
938 yDst -= pDst->pDrawable->y;
939 xSrc -= pSrc->pDrawable->x;
940 ySrc -= pSrc->pDrawable->y;
941
942 if (!ret)
943 goto fallback;
944
945 goto done;
946 }
947
948 if (pSrc->repeat && pSrc->repeatType == RepeatNormal &&
949 pSrc->pDrawable->type == DRAWABLE_PIXMAP) {
950 DDXPointRec patOrg;
951
952 /* Let's see if the driver can do the repeat in one go */
953 if (pExaScr->info->PrepareComposite && !pSrc->alphaMap &&
954 !pDst->alphaMap) {
955 ret = exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc,
956 ySrc, xMask, yMask, xDst, yDst,
957 width, height);
958 if (ret == 1)
959 goto done;
960 }
961
962 /* Now see if we can use exaFillRegionTiled() */
963 xDst += pDst->pDrawable->x;
964 yDst += pDst->pDrawable->y;
965 xSrc += pSrc->pDrawable->x;
966 ySrc += pSrc->pDrawable->y;
967
968 if (!miComputeCompositeRegion(&region, pSrc, pMask, pDst, xSrc,
969 ySrc, xMask, yMask, xDst, yDst,
970 width, height))
971 goto done;
972
973 /* pattern origin is the point in the destination drawable
974 * corresponding to (0,0) in the source */
975 patOrg.x = xDst - xSrc;
976 patOrg.y = yDst - ySrc;
977
978 ret = exaFillRegionTiled(pDst->pDrawable, &region,
979 (PixmapPtr) pSrc->pDrawable,
980 &patOrg, FB_ALLONES, GXcopy, CT_NONE);
981
982 RegionUninit(&region);
983
984 if (ret)
985 goto done;
986
987 /* Let's be correct and restore the variables to their original state. */
988 xDst -= pDst->pDrawable->x;
989 yDst -= pDst->pDrawable->y;
990 xSrc -= pSrc->pDrawable->x;
991 ySrc -= pSrc->pDrawable->y;
992 }
993 }
994 }
995
996 /* Remove repeat in mask if useless */
997 if (pMask && pMask->pDrawable && pMask->repeat && !pMask->transform &&
998 xMask >= 0 && (xMask + width) <= pMask->pDrawable->width &&
999 yMask >= 0 && (yMask + height) <= pMask->pDrawable->height)
1000 pMask->repeat = 0;
1001
1002 if (pExaScr->info->PrepareComposite &&
1003 !pSrc->alphaMap && (!pMask || !pMask->alphaMap) && !pDst->alphaMap) {
1004 Bool isSrcSolid;
1005
1006 ret = exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask,
1007 yMask, xDst, yDst, width, height);
1008 if (ret == 1)
1009 goto done;
1010
1011 /* For generic masks and solid src pictures, mach64 can do Over in two
1012 * passes, similar to the component-alpha case.
1013 */
1014 isSrcSolid = pSrc->pDrawable ?
1015 (pSrc->pDrawable->width == 1 && pSrc->pDrawable->height == 1 &&
1016 pSrc->repeat) :
1017 (pSrc->pSourcePict->type == SourcePictTypeSolidFill);
1018
1019 /* If we couldn't do the Composite in a single pass, and it was a
1020 * component-alpha Over, see if we can do it in two passes with
1021 * an OutReverse and then an Add.
1022 */
1023 if (ret == -1 && op == PictOpOver && pMask &&
1024 (pMask->componentAlpha || isSrcSolid)) {
1025 ret = exaTryMagicTwoPassCompositeHelper(op, pSrc, pMask, pDst,
1026 xSrc, ySrc,
1027 xMask, yMask, xDst, yDst,
1028 width, height);
1029 if (ret == 1)
1030 goto done;
1031 }
1032 }
1033
1034 fallback:
1035#if DEBUG_TRACE_FALL
1036 exaPrintCompositeFallback(op, pSrc, pMask, pDst);
1037#endif
1038
1039 ExaCheckComposite(op, pSrc, pMask, pDst, xSrc, ySrc,
1040 xMask, yMask, xDst, yDst, width, height);
1041
1042 done:
1043 pSrc->repeat = saveSrcRepeat;
1044 if (pMask)
1045 pMask->repeat = saveMaskRepeat;
1046}
1047
1048/**
1049 * Same as miCreateAlphaPicture, except it uses ExaCheckPolyFillRect instead
1050 * of PolyFillRect to initialize the pixmap after creating it, to prevent
1051 * the pixmap from being migrated.
1052 *
1053 * See the comments about exaTrapezoids and exaTriangles.
1054 */
1055static PicturePtr
1056exaCreateAlphaPicture(ScreenPtr pScreen,
1057 PicturePtr pDst,
1058 PictFormatPtr pPictFormat, CARD16 width, CARD16 height)
1059{
1060 PixmapPtr pPixmap;
1061 PicturePtr pPicture;
1062 GCPtr pGC;
1063 int error;
1064 xRectangle rect;
1065
1066 if (width > 32767 || height > 32767)
1067 return 0;
1068
1069 if (!pPictFormat) {
1070 if (pDst->polyEdge == PolyEdgeSharp)
1071 pPictFormat = PictureMatchFormat(pScreen, 1, PICT_a1);
1072 else
1073 pPictFormat = PictureMatchFormat(pScreen, 8, PICT_a8);
1074 if (!pPictFormat)
1075 return 0;
1076 }
1077
1078 pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
1079 pPictFormat->depth, 0);
1080 if (!pPixmap)
1081 return 0;
1082 pGC = GetScratchGC(pPixmap->drawable.depth, pScreen);
1083 if (!pGC) {
1084 (*pScreen->DestroyPixmap) (pPixmap);
1085 return 0;
1086 }
1087 ValidateGC(&pPixmap->drawable, pGC);
1088 rect.x = 0;
1089 rect.y = 0;
1090 rect.width = width;
1091 rect.height = height;
1092 ExaCheckPolyFillRect(&pPixmap->drawable, pGC, 1, &rect);
1093 exaPixmapDirty(pPixmap, 0, 0, width, height);
1094 FreeScratchGC(pGC);
1095 pPicture = CreatePicture(0, &pPixmap->drawable, pPictFormat,
1096 0, 0, serverClient, &error);
1097 (*pScreen->DestroyPixmap) (pPixmap);
1098 return pPicture;
1099}
1100
1101/**
1102 * exaTrapezoids is essentially a copy of miTrapezoids that uses
1103 * exaCreateAlphaPicture instead of miCreateAlphaPicture.
1104 *
1105 * The problem with miCreateAlphaPicture is that it calls PolyFillRect
1106 * to initialize the contents after creating the pixmap, which
1107 * causes the pixmap to be moved in for acceleration. The subsequent
1108 * call to RasterizeTrapezoid won't be accelerated however, which
1109 * forces the pixmap to be moved out again.
1110 *
1111 * exaCreateAlphaPicture avoids this roundtrip by using ExaCheckPolyFillRect
1112 * to initialize the contents.
1113 */
1114void
1115exaTrapezoids(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
1116 PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
1117 int ntrap, xTrapezoid * traps)
1118{
1119 ScreenPtr pScreen = pDst->pDrawable->pScreen;
1120 PictureScreenPtr ps = GetPictureScreen(pScreen);
1121 BoxRec bounds;
1122
1123 if (maskFormat) {
1124 PicturePtr pPicture;
1125 INT16 xDst, yDst;
1126 INT16 xRel, yRel;
1127
1128 miTrapezoidBounds(ntrap, traps, &bounds);
1129
1130 if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
1131 return;
1132
1133 xDst = traps[0].left.p1.x >> 16;
1134 yDst = traps[0].left.p1.y >> 16;
1135
1136 pPicture = exaCreateAlphaPicture(pScreen, pDst, maskFormat,
1137 bounds.x2 - bounds.x1,
1138 bounds.y2 - bounds.y1);
1139 if (!pPicture)
1140 return;
1141
1142 exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
1143 for (; ntrap; ntrap--, traps++)
1144 (*ps->RasterizeTrapezoid) (pPicture, traps, -bounds.x1, -bounds.y1);
1145 exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
1146
1147 xRel = bounds.x1 + xSrc - xDst;
1148 yRel = bounds.y1 + ySrc - yDst;
1149 CompositePicture(op, pSrc, pPicture, pDst,
1150 xRel, yRel, 0, 0, bounds.x1, bounds.y1,
1151 bounds.x2 - bounds.x1, bounds.y2 - bounds.y1);
1152 FreePicture(pPicture, 0);
1153 }
1154 else {
1155 if (pDst->polyEdge == PolyEdgeSharp)
1156 maskFormat = PictureMatchFormat(pScreen, 1, PICT_a1);
1157 else
1158 maskFormat = PictureMatchFormat(pScreen, 8, PICT_a8);
1159 for (; ntrap; ntrap--, traps++)
1160 exaTrapezoids(op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, traps);
1161 }
1162}
1163
1164/**
1165 * exaTriangles is essentially a copy of miTriangles that uses
1166 * exaCreateAlphaPicture instead of miCreateAlphaPicture.
1167 *
1168 * The problem with miCreateAlphaPicture is that it calls PolyFillRect
1169 * to initialize the contents after creating the pixmap, which
1170 * causes the pixmap to be moved in for acceleration. The subsequent
1171 * call to AddTriangles won't be accelerated however, which forces the pixmap
1172 * to be moved out again.
1173 *
1174 * exaCreateAlphaPicture avoids this roundtrip by using ExaCheckPolyFillRect
1175 * to initialize the contents.
1176 */
1177void
1178exaTriangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
1179 PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
1180 int ntri, xTriangle * tris)
1181{
1182 ScreenPtr pScreen = pDst->pDrawable->pScreen;
1183 PictureScreenPtr ps = GetPictureScreen(pScreen);
1184 BoxRec bounds;
1185
1186 if (maskFormat) {
1187 PicturePtr pPicture;
1188 INT16 xDst, yDst;
1189 INT16 xRel, yRel;
1190
1191 miTriangleBounds(ntri, tris, &bounds);
1192
1193 if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
1194 return;
1195
1196 xDst = tris[0].p1.x >> 16;
1197 yDst = tris[0].p1.y >> 16;
1198
1199 pPicture = exaCreateAlphaPicture(pScreen, pDst, maskFormat,
1200 bounds.x2 - bounds.x1,
1201 bounds.y2 - bounds.y1);
1202 if (!pPicture)
1203 return;
1204
1205 exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
1206 (*ps->AddTriangles) (pPicture, -bounds.x1, -bounds.y1, ntri, tris);
1207 exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
1208
1209 xRel = bounds.x1 + xSrc - xDst;
1210 yRel = bounds.y1 + ySrc - yDst;
1211 CompositePicture(op, pSrc, pPicture, pDst,
1212 xRel, yRel, 0, 0, bounds.x1, bounds.y1,
1213 bounds.x2 - bounds.x1, bounds.y2 - bounds.y1);
1214 FreePicture(pPicture, 0);
1215 }
1216 else {
1217 if (pDst->polyEdge == PolyEdgeSharp)
1218 maskFormat = PictureMatchFormat(pScreen, 1, PICT_a1);
1219 else
1220 maskFormat = PictureMatchFormat(pScreen, 8, PICT_a8);
1221
1222 for (; ntri; ntri--, tris++)
1223 exaTriangles(op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, tris);
1224 }
1225}