2 * Copyright © 2001 Keith Packard
4 * Partly based on code that is Copyright © The XFree86 Project Inc.
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.
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.
25 #ifdef HAVE_DIX_CONFIG_H
26 #include <dix-config.h>
37 exaCompositeFallbackPictDesc(PicturePtr pict
, char *string
, int n
)
45 snprintf(string
, n
, "None");
49 switch (pict
->format
) {
51 snprintf(format
, 20, "ARGB8888");
54 snprintf(format
, 20, "XRGB8888");
57 snprintf(format
, 20, "BGRA8888");
60 snprintf(format
, 20, "BGRX8888");
63 snprintf(format
, 20, "RGB565 ");
66 snprintf(format
, 20, "RGB555 ");
69 snprintf(format
, 20, "A8 ");
72 snprintf(format
, 20, "A1 ");
75 snprintf(format
, 20, "0x%x", (int) pict
->format
);
79 if (pict
->pDrawable
) {
80 loc
= exaGetOffscreenPixmap(pict
->pDrawable
, &temp
, &temp
) ? 's' : 'm';
82 snprintf(size
, 20, "%dx%d%s", pict
->pDrawable
->width
,
83 pict
->pDrawable
->height
, pict
->repeat
? " R" : "");
88 snprintf(size
, 20, "%s", pict
->repeat
? " R" : "");
91 snprintf(string
, n
, "%p:%c fmt %s (%s)", pict
->pDrawable
, loc
, format
,
96 exaPrintCompositeFallback(CARD8 op
,
97 PicturePtr pSrc
, PicturePtr pMask
, PicturePtr pDst
)
100 char srcdesc
[40], maskdesc
[40], dstdesc
[40];
104 snprintf(sop
, sizeof(sop
), "Src");
107 snprintf(sop
, sizeof(sop
), "Over");
110 snprintf(sop
, sizeof(sop
), "0x%x", (int) op
);
114 exaCompositeFallbackPictDesc(pSrc
, srcdesc
, 40);
115 exaCompositeFallbackPictDesc(pMask
, maskdesc
, 40);
116 exaCompositeFallbackPictDesc(pDst
, dstdesc
, 40);
118 ErrorF("Composite fallback: op %s, \n"
121 " dst %s, \n", sop
, srcdesc
, maskdesc
, dstdesc
);
123 #endif /* DEBUG_TRACE_FALL */
126 exaOpReadsDestination(CARD8 op
)
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.
143 exaGetPixelFromRGBA(CARD32
*pixel
,
146 CARD16 blue
, CARD16 alpha
, PictFormatPtr pFormat
)
148 int rbits
, bbits
, gbits
, abits
;
149 int rshift
, bshift
, gshift
, ashift
;
153 if (!PICT_FORMAT_COLOR(pFormat
->format
) &&
154 PICT_FORMAT_TYPE(pFormat
->format
) != PICT_TYPE_A
)
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
);
162 rshift
= pFormat
->direct
.red
;
163 gshift
= pFormat
->direct
.green
;
164 bshift
= pFormat
->direct
.blue
;
165 ashift
= pFormat
->direct
.alpha
;
167 *pixel
|= (blue
>> (16 - bbits
)) << bshift
;
168 *pixel
|= (red
>> (16 - rbits
)) << rshift
;
169 *pixel
|= (green
>> (16 - gbits
)) << gshift
;
170 *pixel
|= (alpha
>> (16 - abits
)) << ashift
;
176 exaGetRGBAFromPixel(CARD32 pixel
,
181 PictFormatPtr pFormat
, PictFormatShort format
)
183 int rbits
, bbits
, gbits
, abits
;
184 int rshift
, bshift
, gshift
, ashift
;
186 if (!PICT_FORMAT_COLOR(format
) && PICT_FORMAT_TYPE(format
) != PICT_TYPE_A
)
189 rbits
= PICT_FORMAT_R(format
);
190 gbits
= PICT_FORMAT_G(format
);
191 bbits
= PICT_FORMAT_B(format
);
192 abits
= PICT_FORMAT_A(format
);
195 rshift
= pFormat
->direct
.red
;
196 gshift
= pFormat
->direct
.green
;
197 bshift
= pFormat
->direct
.blue
;
198 ashift
= pFormat
->direct
.alpha
;
200 else if (format
== PICT_a8r8g8b8
) {
207 FatalError("EXA bug: exaGetRGBAFromPixel() doesn't match "
208 "createSourcePicture()\n");
211 *red
= ((pixel
>> rshift
) & ((1 << rbits
) - 1)) << (16 - rbits
);
213 *red
|= *red
>> rbits
;
217 *green
= ((pixel
>> gshift
) & ((1 << gbits
) - 1)) << (16 - gbits
);
219 *green
|= *green
>> gbits
;
223 *blue
= ((pixel
>> bshift
) & ((1 << bbits
) - 1)) << (16 - bbits
);
225 *blue
|= *blue
>> bbits
;
236 *alpha
= ((pixel
>> ashift
) & ((1 << abits
) - 1)) << (16 - abits
);
238 *alpha
|= *alpha
>> abits
;
249 exaTryDriverSolidFill(PicturePtr pSrc
,
253 INT16 xDst
, INT16 yDst
, CARD16 width
, CARD16 height
)
255 ExaScreenPriv(pDst
->pDrawable
->pScreen
);
259 int dst_off_x
, dst_off_y
;
260 PixmapPtr pSrcPix
, pDstPix
;
261 ExaPixmapPrivPtr pDstExaPix
;
263 CARD16 red
, green
, blue
, alpha
;
265 pDstPix
= exaGetDrawablePixmap(pDst
->pDrawable
);
266 pDstExaPix
= ExaGetPixmapPriv(pDstPix
);
268 /* Check whether the accelerator can use the destination pixmap.
270 if (pDstExaPix
->accel_blocked
) {
274 xDst
+= pDst
->pDrawable
->x
;
275 yDst
+= pDst
->pDrawable
->y
;
276 if (pSrc
->pDrawable
) {
277 xSrc
+= pSrc
->pDrawable
->x
;
278 ySrc
+= pSrc
->pDrawable
->y
;
281 if (!miComputeCompositeRegion(®ion
, pSrc
, NULL
, pDst
,
282 xSrc
, ySrc
, 0, 0, xDst
, yDst
, width
, height
))
285 exaGetDrawableDeltas(pDst
->pDrawable
, pDstPix
, &dst_off_x
, &dst_off_y
);
287 RegionTranslate(®ion
, dst_off_x
, dst_off_y
);
289 if (pSrc
->pDrawable
) {
290 pSrcPix
= exaGetDrawablePixmap(pSrc
->pDrawable
);
291 pixel
= exaGetPixmapFirstPixel(pSrcPix
);
294 pixel
= pSrc
->pSourcePict
->solidFill
.color
;
296 if (!exaGetRGBAFromPixel(pixel
, &red
, &green
, &blue
, &alpha
,
297 pSrc
->pFormat
, pSrc
->format
) ||
298 !exaGetPixelFromRGBA(&pixel
, red
, green
, blue
, alpha
, pDst
->pFormat
)) {
299 RegionUninit(®ion
);
303 if (pExaScr
->do_migration
) {
304 ExaMigrationRec pixmaps
[1];
306 pixmaps
[0].as_dst
= TRUE
;
307 pixmaps
[0].as_src
= FALSE
;
308 pixmaps
[0].pPix
= pDstPix
;
309 pixmaps
[0].pReg
= ®ion
;
310 exaDoMigration(pixmaps
, 1, TRUE
);
313 if (!exaPixmapHasGpuCopy(pDstPix
)) {
314 RegionUninit(®ion
);
318 if (!(*pExaScr
->info
->PrepareSolid
) (pDstPix
, GXcopy
, 0xffffffff, pixel
)) {
319 RegionUninit(®ion
);
323 nbox
= RegionNumRects(®ion
);
324 pbox
= RegionRects(®ion
);
327 (*pExaScr
->info
->Solid
) (pDstPix
, pbox
->x1
, pbox
->y1
, pbox
->x2
,
332 (*pExaScr
->info
->DoneSolid
) (pDstPix
);
333 exaMarkSync(pDst
->pDrawable
->pScreen
);
335 RegionUninit(®ion
);
340 exaTryDriverCompositeRects(CARD8 op
,
344 int nrect
, ExaCompositeRectPtr rects
)
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
;
352 if (!pExaScr
->info
->PrepareComposite
)
355 if (pSrc
->pDrawable
) {
356 pSrcPix
= exaGetDrawablePixmap(pSrc
->pDrawable
);
357 pSrcExaPix
= ExaGetPixmapPriv(pSrcPix
);
360 if (pMask
&& pMask
->pDrawable
) {
361 pMaskPix
= exaGetDrawablePixmap(pMask
->pDrawable
);
362 pMaskExaPix
= ExaGetPixmapPriv(pMaskPix
);
365 pDstPix
= exaGetDrawablePixmap(pDst
->pDrawable
);
366 pDstExaPix
= ExaGetPixmapPriv(pDstPix
);
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.
372 if (pDstExaPix
->accel_blocked
||
373 (pSrcExaPix
&& pSrcExaPix
->accel_blocked
) ||
374 (pMaskExaPix
&& pMaskExaPix
->accel_blocked
)) {
378 if (pExaScr
->info
->CheckComposite
&&
379 !(*pExaScr
->info
->CheckComposite
) (op
, pSrc
, pMask
, pDst
)) {
383 if (pExaScr
->do_migration
) {
384 ExaMigrationRec pixmaps
[3];
387 pixmaps
[i
].as_dst
= TRUE
;
388 pixmaps
[i
].as_src
= exaOpReadsDestination(op
);
389 pixmaps
[i
].pPix
= pDstPix
;
390 pixmaps
[i
].pReg
= NULL
;
394 pixmaps
[i
].as_dst
= FALSE
;
395 pixmaps
[i
].as_src
= TRUE
;
396 pixmaps
[i
].pPix
= pSrcPix
;
397 pixmaps
[i
].pReg
= NULL
;
402 pixmaps
[i
].as_dst
= FALSE
;
403 pixmaps
[i
].as_src
= TRUE
;
404 pixmaps
[i
].pPix
= pMaskPix
;
405 pixmaps
[i
].pReg
= NULL
;
409 exaDoMigration(pixmaps
, i
, TRUE
);
412 pDstPix
= exaGetOffscreenPixmap(pDst
->pDrawable
, &dst_off_x
, &dst_off_y
);
418 exaGetOffscreenPixmap(pSrc
->pDrawable
, &src_off_x
, &src_off_y
);
425 exaGetOffscreenPixmap(pMask
->pDrawable
, &mask_off_x
, &mask_off_y
);
430 if (!(*pExaScr
->info
->PrepareComposite
) (op
, pSrc
, pMask
, pDst
, pSrcPix
,
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
;
446 xMask
+= pMask
->pDrawable
->x
;
447 yMask
+= pMask
->pDrawable
->y
;
451 xSrc
+= pSrc
->pDrawable
->x
;
452 ySrc
+= pSrc
->pDrawable
->y
;
455 if (!miComputeCompositeRegion(®ion
, pSrc
, pMask
, pDst
,
456 xSrc
, ySrc
, xMask
, yMask
, xDst
, yDst
,
457 rects
->width
, rects
->height
))
460 RegionTranslate(®ion
, dst_off_x
, dst_off_y
);
462 nbox
= RegionNumRects(®ion
);
463 pbox
= RegionRects(®ion
);
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
;
471 (*pExaScr
->info
->Composite
) (pDstPix
,
479 pbox
->y2
- pbox
->y1
);
484 RegionUninit(®ion
);
489 (*pExaScr
->info
->DoneComposite
) (pDstPix
);
490 exaMarkSync(pDst
->pDrawable
->pScreen
);
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
503 exaCompositeRects(CARD8 op
,
506 PicturePtr pDst
, int nrect
, ExaCompositeRectPtr rects
)
508 ExaScreenPriv(pDst
->pDrawable
->pScreen
);
510 ExaCompositeRectPtr r
;
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.
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.
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.
538 int rect_x2
= r
->xDst
+ r
->width
;
539 int rect_y2
= r
->yDst
+ r
->height
;
553 if (x2
<= x1
|| y2
<= y1
)
557 box
.x2
= x2
< MAXSHORT
? x2
: MAXSHORT
;
559 box
.y2
= y2
< MAXSHORT
? y2
: MAXSHORT
;
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)
567 RegionInit(®ion
, &box
, 1);
569 DamageRegionAppend(pDst
->pDrawable
, ®ion
);
571 RegionUninit(®ion
);
574 /************************************************************/
576 ValidatePicture(pSrc
);
578 ValidatePicture(pMask
);
579 ValidatePicture(pDst
);
581 ret
= exaTryDriverCompositeRects(op
, pSrc
, pMask
, pDst
, nrect
, rects
);
584 if (ret
== -1 && op
== PictOpOver
&& pMask
&& pMask
->componentAlpha
&&
585 (!pExaScr
->info
->CheckComposite
||
586 ((*pExaScr
->info
->CheckComposite
) (PictOpOutReverse
, pSrc
, pMask
,
588 (*pExaScr
->info
->CheckComposite
) (PictOpAdd
, pSrc
, pMask
,
591 exaTryDriverCompositeRects(PictOpOutReverse
, pSrc
, pMask
, pDst
,
595 ret
= exaTryDriverCompositeRects(op
, pSrc
, pMask
, pDst
, nrect
,
604 ExaCheckComposite(op
, pSrc
, pMask
, pDst
,
607 r
->xDst
, r
->yDst
, r
->width
, r
->height
);
613 /************************************************************/
616 /* Now we have to flush the damage out from pendingDamage => damage
617 * Calling DamageRegionProcessPending has that effect.
620 DamageRegionProcessPending(pDst
->pDrawable
);
625 exaTryDriverComposite(CARD8 op
,
633 INT16 xDst
, INT16 yDst
, CARD16 width
, CARD16 height
)
635 ExaScreenPriv(pDst
->pDrawable
->pScreen
);
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
;
643 if (pSrc
->pDrawable
) {
644 pSrcPix
= exaGetDrawablePixmap(pSrc
->pDrawable
);
645 pSrcExaPix
= ExaGetPixmapPriv(pSrcPix
);
648 pDstPix
= exaGetDrawablePixmap(pDst
->pDrawable
);
649 pDstExaPix
= ExaGetPixmapPriv(pDstPix
);
651 if (pMask
&& pMask
->pDrawable
) {
652 pMaskPix
= exaGetDrawablePixmap(pMask
->pDrawable
);
653 pMaskExaPix
= ExaGetPixmapPriv(pMaskPix
);
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.
660 if (pDstExaPix
->accel_blocked
||
661 (pSrcExaPix
&& pSrcExaPix
->accel_blocked
) ||
662 (pMaskExaPix
&& (pMaskExaPix
->accel_blocked
))) {
666 xDst
+= pDst
->pDrawable
->x
;
667 yDst
+= pDst
->pDrawable
->y
;
670 xMask
+= pMask
->pDrawable
->x
;
671 yMask
+= pMask
->pDrawable
->y
;
675 xSrc
+= pSrc
->pDrawable
->x
;
676 ySrc
+= pSrc
->pDrawable
->y
;
679 if (pExaScr
->info
->CheckComposite
&&
680 !(*pExaScr
->info
->CheckComposite
) (op
, pSrc
, pMask
, pDst
)) {
684 if (!miComputeCompositeRegion(®ion
, pSrc
, pMask
, pDst
,
685 xSrc
, ySrc
, xMask
, yMask
, xDst
, yDst
,
689 exaGetDrawableDeltas(pDst
->pDrawable
, pDstPix
, &dst_off_x
, &dst_off_y
);
691 RegionTranslate(®ion
, dst_off_x
, dst_off_y
);
693 if (pExaScr
->do_migration
) {
694 ExaMigrationRec pixmaps
[3];
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
: ®ion
;
704 pixmaps
[i
].as_dst
= FALSE
;
705 pixmaps
[i
].as_src
= TRUE
;
706 pixmaps
[i
].pPix
= pSrcPix
;
707 pixmaps
[i
].pReg
= NULL
;
712 pixmaps
[i
].as_dst
= FALSE
;
713 pixmaps
[i
].as_src
= TRUE
;
714 pixmaps
[i
].pPix
= pMaskPix
;
715 pixmaps
[i
].pReg
= NULL
;
719 exaDoMigration(pixmaps
, i
, TRUE
);
724 exaGetOffscreenPixmap(pSrc
->pDrawable
, &src_off_x
, &src_off_y
);
726 RegionUninit(®ion
);
732 pMaskPix
= exaGetOffscreenPixmap(pMask
->pDrawable
, &mask_off_x
,
735 RegionUninit(®ion
);
740 if (!exaPixmapHasGpuCopy(pDstPix
)) {
741 RegionUninit(®ion
);
745 if (!(*pExaScr
->info
->PrepareComposite
) (op
, pSrc
, pMask
, pDst
, pSrcPix
,
746 pMaskPix
, pDstPix
)) {
747 RegionUninit(®ion
);
751 nbox
= RegionNumRects(®ion
);
752 pbox
= RegionRects(®ion
);
754 xMask
= xMask
+ mask_off_x
- xDst
- dst_off_x
;
755 yMask
= yMask
+ mask_off_y
- yDst
- dst_off_y
;
757 xSrc
= xSrc
+ src_off_x
- xDst
- dst_off_x
;
758 ySrc
= ySrc
+ src_off_y
- yDst
- dst_off_y
;
761 (*pExaScr
->info
->Composite
) (pDstPix
,
768 pbox
->x2
- pbox
->x1
, pbox
->y2
- pbox
->y1
);
771 (*pExaScr
->info
->DoneComposite
) (pDstPix
);
772 exaMarkSync(pDst
->pDrawable
->pScreen
);
774 RegionUninit(®ion
);
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.
783 * From http://anholt.livejournal.com/32058.html:
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:
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
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
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
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:
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
818 * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right
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)
828 exaTryMagicTwoPassCompositeHelper(CARD8 op
,
837 INT16 yDst
, CARD16 width
, CARD16 height
)
839 ExaScreenPriv(pDst
->pDrawable
->pScreen
);
841 assert(op
== PictOpOver
);
843 if (pExaScr
->info
->CheckComposite
&&
844 (!(*pExaScr
->info
->CheckComposite
) (PictOpOutReverse
, pSrc
, pMask
,
846 !(*pExaScr
->info
->CheckComposite
) (PictOpAdd
, pSrc
, pMask
, pDst
))) {
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
854 exaComposite(PictOpOutReverse
, pSrc
, pMask
, pDst
, xSrc
, ySrc
, xMask
, yMask
,
855 xDst
, yDst
, width
, height
);
857 /* Then, add in the source value times the destination alpha factors (1.0).
859 exaComposite(PictOpAdd
, pSrc
, pMask
, pDst
, xSrc
, ySrc
, xMask
, yMask
,
860 xDst
, yDst
, width
, height
);
866 exaComposite(CARD8 op
,
873 INT16 yMask
, INT16 xDst
, INT16 yDst
, CARD16 width
, CARD16 height
)
875 ExaScreenPriv(pDst
->pDrawable
->pScreen
);
877 Bool saveSrcRepeat
= pSrc
->repeat
;
878 Bool saveMaskRepeat
= pMask
? pMask
->repeat
: 0;
881 if (pExaScr
->swappedOut
)
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
)
890 if (!pMask
&& !pSrc
->alphaMap
&& !pDst
->alphaMap
&&
891 (op
== PictOpSrc
|| (op
== PictOpOver
&& !PICT_FORMAT_A(pSrc
->format
))))
893 if (pSrc
->pDrawable
?
894 (pSrc
->pDrawable
->width
== 1 && pSrc
->pDrawable
->height
== 1 &&
896 (pSrc
->pSourcePict
->type
== SourcePictTypeSolidFill
)) {
897 ret
= exaTryDriverSolidFill(pSrc
, pDst
, xSrc
, ySrc
, xDst
, yDst
,
902 else if (pSrc
->pDrawable
&& !pSrc
->transform
&&
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
),
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
)) {
920 xDst
+= pDst
->pDrawable
->x
;
921 yDst
+= pDst
->pDrawable
->y
;
922 xSrc
+= pSrc
->pDrawable
->x
;
923 ySrc
+= pSrc
->pDrawable
->y
;
925 if (!miComputeCompositeRegion(®ion
, pSrc
, pMask
, pDst
,
926 xSrc
, ySrc
, xMask
, yMask
, xDst
,
927 yDst
, width
, height
))
930 ret
= exaHWCopyNtoN(pSrc
->pDrawable
, pDst
->pDrawable
, NULL
,
931 RegionRects(®ion
),
932 RegionNumRects(®ion
), xSrc
- xDst
,
933 ySrc
- yDst
, FALSE
, FALSE
);
934 RegionUninit(®ion
);
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
;
948 if (pSrc
->repeat
&& pSrc
->repeatType
== RepeatNormal
&&
949 pSrc
->pDrawable
->type
== DRAWABLE_PIXMAP
) {
952 /* Let's see if the driver can do the repeat in one go */
953 if (pExaScr
->info
->PrepareComposite
&& !pSrc
->alphaMap
&&
955 ret
= exaTryDriverComposite(op
, pSrc
, pMask
, pDst
, xSrc
,
956 ySrc
, xMask
, yMask
, xDst
, yDst
,
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
;
968 if (!miComputeCompositeRegion(®ion
, pSrc
, pMask
, pDst
, xSrc
,
969 ySrc
, xMask
, yMask
, xDst
, yDst
,
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
;
978 ret
= exaFillRegionTiled(pDst
->pDrawable
, ®ion
,
979 (PixmapPtr
) pSrc
->pDrawable
,
980 &patOrg
, FB_ALLONES
, GXcopy
, CT_NONE
);
982 RegionUninit(®ion
);
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
;
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
)
1002 if (pExaScr
->info
->PrepareComposite
&&
1003 !pSrc
->alphaMap
&& (!pMask
|| !pMask
->alphaMap
) && !pDst
->alphaMap
) {
1006 ret
= exaTryDriverComposite(op
, pSrc
, pMask
, pDst
, xSrc
, ySrc
, xMask
,
1007 yMask
, xDst
, yDst
, width
, height
);
1011 /* For generic masks and solid src pictures, mach64 can do Over in two
1012 * passes, similar to the component-alpha case.
1014 isSrcSolid
= pSrc
->pDrawable
?
1015 (pSrc
->pDrawable
->width
== 1 && pSrc
->pDrawable
->height
== 1 &&
1017 (pSrc
->pSourcePict
->type
== SourcePictTypeSolidFill
);
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.
1023 if (ret
== -1 && op
== PictOpOver
&& pMask
&&
1024 (pMask
->componentAlpha
|| isSrcSolid
)) {
1025 ret
= exaTryMagicTwoPassCompositeHelper(op
, pSrc
, pMask
, pDst
,
1027 xMask
, yMask
, xDst
, yDst
,
1035 #if DEBUG_TRACE_FALL
1036 exaPrintCompositeFallback(op
, pSrc
, pMask
, pDst
);
1039 ExaCheckComposite(op
, pSrc
, pMask
, pDst
, xSrc
, ySrc
,
1040 xMask
, yMask
, xDst
, yDst
, width
, height
);
1043 pSrc
->repeat
= saveSrcRepeat
;
1045 pMask
->repeat
= saveMaskRepeat
;
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.
1053 * See the comments about exaTrapezoids and exaTriangles.
1056 exaCreateAlphaPicture(ScreenPtr pScreen
,
1058 PictFormatPtr pPictFormat
, CARD16 width
, CARD16 height
)
1061 PicturePtr pPicture
;
1066 if (width
> 32767 || height
> 32767)
1070 if (pDst
->polyEdge
== PolyEdgeSharp
)
1071 pPictFormat
= PictureMatchFormat(pScreen
, 1, PICT_a1
);
1073 pPictFormat
= PictureMatchFormat(pScreen
, 8, PICT_a8
);
1078 pPixmap
= (*pScreen
->CreatePixmap
) (pScreen
, width
, height
,
1079 pPictFormat
->depth
, 0);
1082 pGC
= GetScratchGC(pPixmap
->drawable
.depth
, pScreen
);
1084 (*pScreen
->DestroyPixmap
) (pPixmap
);
1087 ValidateGC(&pPixmap
->drawable
, pGC
);
1091 rect
.height
= height
;
1092 ExaCheckPolyFillRect(&pPixmap
->drawable
, pGC
, 1, &rect
);
1093 exaPixmapDirty(pPixmap
, 0, 0, width
, height
);
1095 pPicture
= CreatePicture(0, &pPixmap
->drawable
, pPictFormat
,
1096 0, 0, serverClient
, &error
);
1097 (*pScreen
->DestroyPixmap
) (pPixmap
);
1102 * exaTrapezoids is essentially a copy of miTrapezoids that uses
1103 * exaCreateAlphaPicture instead of miCreateAlphaPicture.
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.
1111 * exaCreateAlphaPicture avoids this roundtrip by using ExaCheckPolyFillRect
1112 * to initialize the contents.
1115 exaTrapezoids(CARD8 op
, PicturePtr pSrc
, PicturePtr pDst
,
1116 PictFormatPtr maskFormat
, INT16 xSrc
, INT16 ySrc
,
1117 int ntrap
, xTrapezoid
* traps
)
1119 ScreenPtr pScreen
= pDst
->pDrawable
->pScreen
;
1120 PictureScreenPtr ps
= GetPictureScreen(pScreen
);
1124 PicturePtr pPicture
;
1128 miTrapezoidBounds(ntrap
, traps
, &bounds
);
1130 if (bounds
.y1
>= bounds
.y2
|| bounds
.x1
>= bounds
.x2
)
1133 xDst
= traps
[0].left
.p1
.x
>> 16;
1134 yDst
= traps
[0].left
.p1
.y
>> 16;
1136 pPicture
= exaCreateAlphaPicture(pScreen
, pDst
, maskFormat
,
1137 bounds
.x2
- bounds
.x1
,
1138 bounds
.y2
- bounds
.y1
);
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
);
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);
1155 if (pDst
->polyEdge
== PolyEdgeSharp
)
1156 maskFormat
= PictureMatchFormat(pScreen
, 1, PICT_a1
);
1158 maskFormat
= PictureMatchFormat(pScreen
, 8, PICT_a8
);
1159 for (; ntrap
; ntrap
--, traps
++)
1160 exaTrapezoids(op
, pSrc
, pDst
, maskFormat
, xSrc
, ySrc
, 1, traps
);
1165 * exaTriangles is essentially a copy of miTriangles that uses
1166 * exaCreateAlphaPicture instead of miCreateAlphaPicture.
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.
1174 * exaCreateAlphaPicture avoids this roundtrip by using ExaCheckPolyFillRect
1175 * to initialize the contents.
1178 exaTriangles(CARD8 op
, PicturePtr pSrc
, PicturePtr pDst
,
1179 PictFormatPtr maskFormat
, INT16 xSrc
, INT16 ySrc
,
1180 int ntri
, xTriangle
* tris
)
1182 ScreenPtr pScreen
= pDst
->pDrawable
->pScreen
;
1183 PictureScreenPtr ps
= GetPictureScreen(pScreen
);
1187 PicturePtr pPicture
;
1191 miTriangleBounds(ntri
, tris
, &bounds
);
1193 if (bounds
.y1
>= bounds
.y2
|| bounds
.x1
>= bounds
.x2
)
1196 xDst
= tris
[0].p1
.x
>> 16;
1197 yDst
= tris
[0].p1
.y
>> 16;
1199 pPicture
= exaCreateAlphaPicture(pScreen
, pDst
, maskFormat
,
1200 bounds
.x2
- bounds
.x1
,
1201 bounds
.y2
- bounds
.y1
);
1205 exaPrepareAccess(pPicture
->pDrawable
, EXA_PREPARE_DEST
);
1206 (*ps
->AddTriangles
) (pPicture
, -bounds
.x1
, -bounds
.y1
, ntri
, tris
);
1207 exaFinishAccess(pPicture
->pDrawable
, EXA_PREPARE_DEST
);
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);
1217 if (pDst
->polyEdge
== PolyEdgeSharp
)
1218 maskFormat
= PictureMatchFormat(pScreen
, 1, PICT_a1
);
1220 maskFormat
= PictureMatchFormat(pScreen
, 8, PICT_a8
);
1222 for (; ntri
; ntri
--, tris
++)
1223 exaTriangles(op
, pSrc
, pDst
, maskFormat
, xSrc
, ySrc
, 1, tris
);