#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <stdlib.h>
#include "exa_priv.h"
#include "mipict.h"
#if DEBUG_TRACE_FALL
static void exaCompositeFallbackPictDesc(PicturePtr pict, char *string, int n)
{
char format[20];
char size[20];
char loc;
int temp;
if (!pict) {
snprintf(string, n, "None");
return;
}
switch (pict->format)
{
case PICT_a8r8g8b8:
snprintf(format, 20, "ARGB8888");
break;
case PICT_x8r8g8b8:
snprintf(format, 20, "XRGB8888");
break;
case PICT_b8g8r8a8:
snprintf(format, 20, "BGRA8888");
break;
case PICT_b8g8r8x8:
snprintf(format, 20, "BGRX8888");
break;
case PICT_r5g6b5:
snprintf(format, 20, "RGB565 ");
break;
case PICT_x1r5g5b5:
snprintf(format, 20, "RGB555 ");
break;
case PICT_a8:
snprintf(format, 20, "A8 ");
break;
case PICT_a1:
snprintf(format, 20, "A1 ");
break;
default:
snprintf(format, 20, "0x%x", (int)pict->format);
break;
}
if (pict->pDrawable) {
loc = exaGetOffscreenPixmap(pict->pDrawable, &temp, &temp) ? 's' : 'm';
snprintf(size, 20, "%dx%d%s", pict->pDrawable->width,
pict->pDrawable->height, pict->repeat ?
" R" : "");
} else {
loc = '-';
snprintf(size, 20, "%s", pict->repeat ? " R" : "");
}
snprintf(string, n, "%p:%c fmt %s (%s)", pict->pDrawable, loc, format, size);
}
static void
exaPrintCompositeFallback(CARD8 op,
PicturePtr pSrc,
PicturePtr pMask,
PicturePtr pDst)
{
char sop[20];
char srcdesc[40], maskdesc[40], dstdesc[40];
switch(op)
{
case PictOpSrc:
sprintf(sop, "Src");
break;
case PictOpOver:
sprintf(sop, "Over");
break;
default:
sprintf(sop, "0x%x", (int)op);
break;
}
exaCompositeFallbackPictDesc(pSrc, srcdesc, 40);
exaCompositeFallbackPictDesc(pMask, maskdesc, 40);
exaCompositeFallbackPictDesc(pDst, dstdesc, 40);
ErrorF("Composite fallback: op %s, \n"
" src %s, \n"
" mask %s, \n"
" dst %s, \n",
sop, srcdesc, maskdesc, dstdesc);
}
#endif
Bool
exaOpReadsDestination (CARD8 op)
{
switch (op) {
case PictOpClear:
case PictOpSrc:
return FALSE;
default:
return TRUE;
}
}
static Bool
exaGetPixelFromRGBA(CARD32 *pixel,
CARD16 red,
CARD16 green,
CARD16 blue,
CARD16 alpha,
PictFormatPtr pFormat)
{
int rbits, bbits, gbits, abits;
int rshift, bshift, gshift, ashift;
*pixel = 0;
if (!PICT_FORMAT_COLOR(pFormat->format) &&
PICT_FORMAT_TYPE(pFormat->format) != PICT_TYPE_A)
return FALSE;
rbits = PICT_FORMAT_R(pFormat->format);
gbits = PICT_FORMAT_G(pFormat->format);
bbits = PICT_FORMAT_B(pFormat->format);
abits = PICT_FORMAT_A(pFormat->format);
rshift = pFormat->direct.red;
gshift = pFormat->direct.green;
bshift = pFormat->direct.blue;
ashift = pFormat->direct.alpha;
*pixel |= ( blue >> (16 - bbits)) << bshift;
*pixel |= ( red >> (16 - rbits)) << rshift;
*pixel |= (green >> (16 - gbits)) << gshift;
*pixel |= (alpha >> (16 - abits)) << ashift;
return TRUE;
}
static Bool
exaGetRGBAFromPixel(CARD32 pixel,
CARD16 *red,
CARD16 *green,
CARD16 *blue,
CARD16 *alpha,
PictFormatPtr pFormat,
PictFormatShort format)
{
int rbits, bbits, gbits, abits;
int rshift, bshift, gshift, ashift;
if (!PICT_FORMAT_COLOR(format) && PICT_FORMAT_TYPE(format) != PICT_TYPE_A)
return FALSE;
rbits = PICT_FORMAT_R(format);
gbits = PICT_FORMAT_G(format);
bbits = PICT_FORMAT_B(format);
abits = PICT_FORMAT_A(format);
if (pFormat) {
rshift = pFormat->direct.red;
gshift = pFormat->direct.green;
bshift = pFormat->direct.blue;
ashift = pFormat->direct.alpha;
} else if (format == PICT_a8r8g8b8) {
rshift = 16;
gshift = 8;
bshift = 0;
ashift = 24;
} else
FatalError("EXA bug: exaGetRGBAFromPixel() doesn't match "
"createSourcePicture()\n");
if (rbits) {
*red = ((pixel >> rshift ) & ((1 << rbits) - 1)) << (16 - rbits);
while (rbits < 16) {
*red |= *red >> rbits;
rbits <<= 1;
}
*green = ((pixel >> gshift ) & ((1 << gbits) - 1)) << (16 - gbits);
while (gbits < 16) {
*green |= *green >> gbits;
gbits <<= 1;
}
*blue = ((pixel >> bshift ) & ((1 << bbits) - 1)) << (16 - bbits);
while (bbits < 16) {
*blue |= *blue >> bbits;
bbits <<= 1;
}
} else {
*red = 0x0000;
*green = 0x0000;
*blue = 0x0000;
}
if (abits) {
*alpha = ((pixel >> ashift ) & ((1 << abits) - 1)) << (16 - abits);
while (abits < 16) {
*alpha |= *alpha >> abits;
abits <<= 1;
}
} else
*alpha = 0xffff;
return TRUE;
}
static int
exaTryDriverSolidFill(PicturePtr pSrc,
PicturePtr pDst,
INT16 xSrc,
INT16 ySrc,
INT16 xDst,
INT16 yDst,
CARD16 width,
CARD16 height)
{
ExaScreenPriv (pDst->pDrawable->pScreen);
RegionRec region;
BoxPtr pbox;
int nbox;
int dst_off_x, dst_off_y;
PixmapPtr pSrcPix, pDstPix;
ExaPixmapPrivPtr pDstExaPix;
CARD32 pixel;
CARD16 red, green, blue, alpha;
pDstPix = exaGetDrawablePixmap (pDst->pDrawable);
pDstExaPix = ExaGetPixmapPriv(pDstPix);
if (pDstExaPix->accel_blocked)
{
return -1;
}
xDst += pDst->pDrawable->x;
yDst += pDst->pDrawable->y;
if (pSrc->pDrawable) {
xSrc += pSrc->pDrawable->x;
ySrc += pSrc->pDrawable->y;
}
if (!miComputeCompositeRegion (®ion, pSrc, NULL, pDst,
xSrc, ySrc, 0, 0, xDst, yDst,
width, height))
return 1;
exaGetDrawableDeltas (pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y);
RegionTranslate(®ion, dst_off_x, dst_off_y);
if (pSrc->pDrawable) {
pSrcPix = exaGetDrawablePixmap (pSrc->pDrawable);
pixel = exaGetPixmapFirstPixel (pSrcPix);
} else
pixel = pSrc->pSourcePict->solidFill.color;
if (!exaGetRGBAFromPixel(pixel, &red, &green, &blue, &alpha,
pSrc->pFormat, pSrc->format) ||
!exaGetPixelFromRGBA(&pixel, red, green, blue, alpha,
pDst->pFormat))
{
RegionUninit(®ion);
return -1;
}
if (pExaScr->do_migration) {
ExaMigrationRec pixmaps[1];
pixmaps[0].as_dst = TRUE;
pixmaps[0].as_src = FALSE;
pixmaps[0].pPix = pDstPix;
pixmaps[0].pReg = ®ion;
exaDoMigration(pixmaps, 1, TRUE);
}
if (!exaPixmapHasGpuCopy(pDstPix)) {
RegionUninit(®ion);
return 0;
}
if (!(*pExaScr->info->PrepareSolid) (pDstPix, GXcopy, 0xffffffff, pixel))
{
RegionUninit(®ion);
return -1;
}
nbox = RegionNumRects(®ion);
pbox = RegionRects(®ion);
while (nbox--)
{
(*pExaScr->info->Solid) (pDstPix, pbox->x1, pbox->y1, pbox->x2, pbox->y2);
pbox++;
}
(*pExaScr->info->DoneSolid) (pDstPix);
exaMarkSync(pDst->pDrawable->pScreen);
RegionUninit(®ion);
return 1;
}
static int
exaTryDriverCompositeRects(CARD8 op,
PicturePtr pSrc,
PicturePtr pMask,
PicturePtr pDst,
int nrect,
ExaCompositeRectPtr rects)
{
ExaScreenPriv (pDst->pDrawable->pScreen);
int src_off_x = 0, src_off_y = 0, mask_off_x = 0, mask_off_y = 0;
int dst_off_x, dst_off_y;
PixmapPtr pSrcPix = NULL, pMaskPix = NULL, pDstPix;
ExaPixmapPrivPtr pSrcExaPix = NULL, pMaskExaPix = NULL, pDstExaPix;
if (!pExaScr->info->PrepareComposite)
return -1;
if (pSrc->pDrawable) {
pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable);
pSrcExaPix = ExaGetPixmapPriv(pSrcPix);
}
if (pMask && pMask->pDrawable) {
pMaskPix = exaGetDrawablePixmap(pMask->pDrawable);
pMaskExaPix = ExaGetPixmapPriv(pMaskPix);
}
pDstPix = exaGetDrawablePixmap(pDst->pDrawable);
pDstExaPix = ExaGetPixmapPriv(pDstPix);
if (pDstExaPix->accel_blocked ||
(pSrcExaPix && pSrcExaPix->accel_blocked) ||
(pMaskExaPix && pMaskExaPix->accel_blocked))
{
return -1;
}
if (pExaScr->info->CheckComposite &&
!(*pExaScr->info->CheckComposite) (op, pSrc, pMask, pDst))
{
return -1;
}
if (pExaScr->do_migration) {
ExaMigrationRec pixmaps[3];
int i = 0;
pixmaps[i].as_dst = TRUE;
pixmaps[i].as_src = exaOpReadsDestination(op);
pixmaps[i].pPix = pDstPix;
pixmaps[i].pReg = NULL;
i++;
if (pSrcPix) {
pixmaps[i].as_dst = FALSE;
pixmaps[i].as_src = TRUE;
pixmaps[i].pPix = pSrcPix;
pixmaps[i].pReg = NULL;
i++;
}
if (pMaskPix) {
pixmaps[i].as_dst = FALSE;
pixmaps[i].as_src = TRUE;
pixmaps[i].pPix = pMaskPix;
pixmaps[i].pReg = NULL;
i++;
}
exaDoMigration(pixmaps, i, TRUE);
}
pDstPix = exaGetOffscreenPixmap (pDst->pDrawable, &dst_off_x, &dst_off_y);
if (!pDstPix)
return 0;
if (pSrcPix) {
pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y);
if (!pSrcPix)
return 0;
}
if (pMaskPix) {
pMaskPix = exaGetOffscreenPixmap (pMask->pDrawable, &mask_off_x, &mask_off_y);
if (!pMaskPix)
return 0;
}
if (!(*pExaScr->info->PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix,
pMaskPix, pDstPix))
return -1;
while (nrect--)
{
INT16 xDst = rects->xDst + pDst->pDrawable->x;
INT16 yDst = rects->yDst + pDst->pDrawable->y;
INT16 xMask = rects->xMask;
INT16 yMask = rects->yMask;
INT16 xSrc = rects->xSrc;
INT16 ySrc = rects->ySrc;
RegionRec region;
BoxPtr pbox;
int nbox;
if (pMaskPix) {
xMask += pMask->pDrawable->x;
yMask += pMask->pDrawable->y;
}
if (pSrcPix) {
xSrc += pSrc->pDrawable->x;
ySrc += pSrc->pDrawable->y;
}
if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst,
xSrc, ySrc, xMask, yMask, xDst, yDst,
rects->width, rects->height))
goto next_rect;
RegionTranslate(®ion, dst_off_x, dst_off_y);
nbox = RegionNumRects(®ion);
pbox = RegionRects(®ion);
xMask = xMask + mask_off_x - xDst - dst_off_x;
yMask = yMask + mask_off_y - yDst - dst_off_y;
xSrc = xSrc + src_off_x - xDst - dst_off_x;
ySrc = ySrc + src_off_y - yDst - dst_off_y;
while (nbox--)
{
(*pExaScr->info->Composite) (pDstPix,
pbox->x1 + xSrc,
pbox->y1 + ySrc,
pbox->x1 + xMask,
pbox->y1 + yMask,
pbox->x1,
pbox->y1,
pbox->x2 - pbox->x1,
pbox->y2 - pbox->y1);
pbox++;
}
next_rect:
RegionUninit(®ion);
rects++;
}
(*pExaScr->info->DoneComposite) (pDstPix);
exaMarkSync(pDst->pDrawable->pScreen);
return 1;
}
void
exaCompositeRects(CARD8 op,
PicturePtr pSrc,
PicturePtr pMask,
PicturePtr pDst,
int nrect,
ExaCompositeRectPtr rects)
{
ExaScreenPriv (pDst->pDrawable->pScreen);
int n;
ExaCompositeRectPtr r;
int ret;
if (!pMask) {
RegionRec region;
int x1 = MAXSHORT;
int y1 = MAXSHORT;
int x2 = MINSHORT;
int y2 = MINSHORT;
BoxRec box;
n = nrect;
r = rects;
while (n--) {
int rect_x2 = r->xDst + r->width;
int rect_y2 = r->yDst + r->height;
if (r->xDst < x1) x1 = r->xDst;
if (r->yDst < y1) y1 = r->yDst;
if (rect_x2 > x2) x2 = rect_x2;
if (rect_y2 > y2) y2 = rect_y2;
r++;
}
if (x2 <= x1 || y2 <= y1)
return;
box.x1 = x1;
box.x2 = x2 < MAXSHORT ? x2 : MAXSHORT;
box.y1 = y1;
box.y2 = y2 < MAXSHORT ? y2 : MAXSHORT;
RegionInit(®ion, &box, 1);
DamageRegionAppend(pDst->pDrawable, ®ion);
RegionUninit(®ion);
}
ValidatePicture (pSrc);
if (pMask)
ValidatePicture (pMask);
ValidatePicture (pDst);
ret = exaTryDriverCompositeRects(op, pSrc, pMask, pDst, nrect, rects);
if (ret != 1) {
if (ret == -1 && op == PictOpOver && pMask && pMask->componentAlpha &&
(!pExaScr->info->CheckComposite ||
((*pExaScr->info->CheckComposite)(PictOpOutReverse, pSrc, pMask,
pDst) &&
(*pExaScr->info->CheckComposite)(PictOpAdd, pSrc, pMask, pDst)))) {
ret = exaTryDriverCompositeRects(PictOpOutReverse, pSrc, pMask,
pDst, nrect, rects);
if (ret == 1) {
op = PictOpAdd;
ret = exaTryDriverCompositeRects(op, pSrc, pMask, pDst, nrect,
rects);
}
}
if (ret != 1) {
n = nrect;
r = rects;
while (n--) {
ExaCheckComposite (op, pSrc, pMask, pDst,
r->xSrc, r->ySrc,
r->xMask, r->yMask,
r->xDst, r->yDst,
r->width, r->height);
r++;
}
}
}
if (!pMask) {
DamageRegionProcessPending(pDst->pDrawable);
}
}
static int
exaTryDriverComposite(CARD8 op,
PicturePtr pSrc,
PicturePtr pMask,
PicturePtr pDst,
INT16 xSrc,
INT16 ySrc,
INT16 xMask,
INT16 yMask,
INT16 xDst,
INT16 yDst,
CARD16 width,
CARD16 height)
{
ExaScreenPriv (pDst->pDrawable->pScreen);
RegionRec region;
BoxPtr pbox;
int nbox;
int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y;
PixmapPtr pSrcPix = NULL, pMaskPix = NULL, pDstPix;
ExaPixmapPrivPtr pSrcExaPix = NULL, pMaskExaPix = NULL, pDstExaPix;
if (pSrc->pDrawable) {
pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable);
pSrcExaPix = ExaGetPixmapPriv(pSrcPix);
}
pDstPix = exaGetDrawablePixmap(pDst->pDrawable);
pDstExaPix = ExaGetPixmapPriv(pDstPix);
if (pMask && pMask->pDrawable) {
pMaskPix = exaGetDrawablePixmap(pMask->pDrawable);
pMaskExaPix = ExaGetPixmapPriv(pMaskPix);
}
if (pDstExaPix->accel_blocked ||
(pSrcExaPix && pSrcExaPix->accel_blocked) ||
(pMaskExaPix && (pMaskExaPix->accel_blocked)))
{
return -1;
}
xDst += pDst->pDrawable->x;
yDst += pDst->pDrawable->y;
if (pMaskPix) {
xMask += pMask->pDrawable->x;
yMask += pMask->pDrawable->y;
}
if (pSrcPix) {
xSrc += pSrc->pDrawable->x;
ySrc += pSrc->pDrawable->y;
}
if (pExaScr->info->CheckComposite &&
!(*pExaScr->info->CheckComposite) (op, pSrc, pMask, pDst))
{
return -1;
}
if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst,
xSrc, ySrc, xMask, yMask, xDst, yDst,
width, height))
return 1;
exaGetDrawableDeltas (pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y);
RegionTranslate(®ion, dst_off_x, dst_off_y);
if (pExaScr->do_migration) {
ExaMigrationRec pixmaps[3];
int i = 0;
pixmaps[i].as_dst = TRUE;
pixmaps[i].as_src = exaOpReadsDestination(op);
pixmaps[i].pPix = pDstPix;
pixmaps[i].pReg = pixmaps[0].as_src ? NULL : ®ion;
i++;
if (pSrcPix) {
pixmaps[i].as_dst = FALSE;
pixmaps[i].as_src = TRUE;
pixmaps[i].pPix = pSrcPix;
pixmaps[i].pReg = NULL;
i++;
}
if (pMaskPix) {
pixmaps[i].as_dst = FALSE;
pixmaps[i].as_src = TRUE;
pixmaps[i].pPix = pMaskPix;
pixmaps[i].pReg = NULL;
i++;
}
exaDoMigration(pixmaps, i, TRUE);
}
if (pSrcPix) {
pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y);
if (!pSrcPix) {
RegionUninit(®ion);
return 0;
}
}
if (pMaskPix) {
pMaskPix = exaGetOffscreenPixmap (pMask->pDrawable, &mask_off_x,
&mask_off_y);
if (!pMaskPix) {
RegionUninit(®ion);
return 0;
}
}
if (!exaPixmapHasGpuCopy(pDstPix)) {
RegionUninit(®ion);
return 0;
}
if (!(*pExaScr->info->PrepareComposite) (op, pSrc, pMask, pDst, pSrcPix,
pMaskPix, pDstPix))
{
RegionUninit(®ion);
return -1;
}
nbox = RegionNumRects(®ion);
pbox = RegionRects(®ion);
xMask = xMask + mask_off_x - xDst - dst_off_x;
yMask = yMask + mask_off_y - yDst - dst_off_y;
xSrc = xSrc + src_off_x - xDst - dst_off_x;
ySrc = ySrc + src_off_y - yDst - dst_off_y;
while (nbox--)
{
(*pExaScr->info->Composite) (pDstPix,
pbox->x1 + xSrc,
pbox->y1 + ySrc,
pbox->x1 + xMask,
pbox->y1 + yMask,
pbox->x1,
pbox->y1,
pbox->x2 - pbox->x1,
pbox->y2 - pbox->y1);
pbox++;
}
(*pExaScr->info->DoneComposite) (pDstPix);
exaMarkSync(pDst->pDrawable->pScreen);
RegionUninit(®ion);
return 1;
}
static int
exaTryMagicTwoPassCompositeHelper(CARD8 op,
PicturePtr pSrc,
PicturePtr pMask,
PicturePtr pDst,
INT16 xSrc,
INT16 ySrc,
INT16 xMask,
INT16 yMask,
INT16 xDst,
INT16 yDst,
CARD16 width,
CARD16 height)
{
ExaScreenPriv (pDst->pDrawable->pScreen);
assert(op == PictOpOver);
if (pExaScr->info->CheckComposite &&
(!(*pExaScr->info->CheckComposite)(PictOpOutReverse, pSrc, pMask,
pDst) ||
!(*pExaScr->info->CheckComposite)(PictOpAdd, pSrc, pMask, pDst)))
{
return -1;
}
exaComposite(PictOpOutReverse, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask,
xDst, yDst, width, height);
exaComposite(PictOpAdd, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask,
xDst, yDst, width, height);
return 1;
}
void
exaComposite(CARD8 op,
PicturePtr pSrc,
PicturePtr pMask,
PicturePtr pDst,
INT16 xSrc,
INT16 ySrc,
INT16 xMask,
INT16 yMask,
INT16 xDst,
INT16 yDst,
CARD16 width,
CARD16 height)
{
ExaScreenPriv (pDst->pDrawable->pScreen);
int ret = -1;
Bool saveSrcRepeat = pSrc->repeat;
Bool saveMaskRepeat = pMask ? pMask->repeat : 0;
RegionRec region;
if (pExaScr->swappedOut)
goto fallback;
if (pSrc->pDrawable && pSrc->repeat && !pSrc->transform && xSrc >= 0 &&
(xSrc + width) <= pSrc->pDrawable->width && ySrc >= 0 &&
(ySrc + height) <= pSrc->pDrawable->height)
pSrc->repeat = 0;
if (!pMask && !pSrc->alphaMap && !pDst->alphaMap &&
(op == PictOpSrc || (op == PictOpOver && !PICT_FORMAT_A(pSrc->format))))
{
if (pSrc->pDrawable ?
(pSrc->pDrawable->width == 1 && pSrc->pDrawable->height == 1 &&
pSrc->repeat) :
(pSrc->pSourcePict->type == SourcePictTypeSolidFill))
{
ret = exaTryDriverSolidFill(pSrc, pDst, xSrc, ySrc, xDst, yDst,
width, height);
if (ret == 1)
goto done;
} else if (pSrc->pDrawable && !pSrc->transform &&
((op == PictOpSrc &&
(pSrc->format == pDst->format ||
(PICT_FORMAT_COLOR(pDst->format) &&
PICT_FORMAT_COLOR(pSrc->format) &&
pDst->format == PICT_FORMAT(PICT_FORMAT_BPP(pSrc->format),
PICT_FORMAT_TYPE(pSrc->format),
0,
PICT_FORMAT_R(pSrc->format),
PICT_FORMAT_G(pSrc->format),
PICT_FORMAT_B(pSrc->format))))) ||
(op == PictOpOver && pSrc->format == pDst->format &&
!PICT_FORMAT_A(pSrc->format))))
{
if (!pSrc->repeat && xSrc >= 0 && ySrc >= 0 &&
(xSrc + width <= pSrc->pDrawable->width) &&
(ySrc + height <= pSrc->pDrawable->height))
{
Bool ret;
xDst += pDst->pDrawable->x;
yDst += pDst->pDrawable->y;
xSrc += pSrc->pDrawable->x;
ySrc += pSrc->pDrawable->y;
if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst,
xSrc, ySrc, xMask, yMask, xDst,
yDst, width, height))
goto done;
ret = exaHWCopyNtoN(pSrc->pDrawable, pDst->pDrawable, NULL,
RegionRects(®ion), RegionNumRects(®ion),
xSrc - xDst, ySrc - yDst, FALSE, FALSE);
RegionUninit(®ion);
xDst -= pDst->pDrawable->x;
yDst -= pDst->pDrawable->y;
xSrc -= pSrc->pDrawable->x;
ySrc -= pSrc->pDrawable->y;
if (!ret)
goto fallback;
goto done;
}
if (pSrc->repeat && pSrc->repeatType == RepeatNormal &&
pSrc->pDrawable->type == DRAWABLE_PIXMAP)
{
DDXPointRec patOrg;
if (pExaScr->info->PrepareComposite && !pSrc->alphaMap &&
!pDst->alphaMap)
{
ret = exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc,
ySrc, xMask, yMask, xDst, yDst,
width, height);
if (ret == 1)
goto done;
}
xDst += pDst->pDrawable->x;
yDst += pDst->pDrawable->y;
xSrc += pSrc->pDrawable->x;
ySrc += pSrc->pDrawable->y;
if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, xSrc,
ySrc, xMask, yMask, xDst, yDst,
width, height))
goto done;
patOrg.x = xDst - xSrc;
patOrg.y = yDst - ySrc;
ret = exaFillRegionTiled(pDst->pDrawable, ®ion,
(PixmapPtr)pSrc->pDrawable,
&patOrg, FB_ALLONES, GXcopy, CT_NONE);
RegionUninit(®ion);
if (ret)
goto done;
xDst -= pDst->pDrawable->x;
yDst -= pDst->pDrawable->y;
xSrc -= pSrc->pDrawable->x;
ySrc -= pSrc->pDrawable->y;
}
}
}
if (pMask && pMask->pDrawable && pMask->repeat && !pMask->transform &&
xMask >= 0 && (xMask + width) <= pMask->pDrawable->width &&
yMask >= 0 && (yMask + height) <= pMask->pDrawable->height)
pMask->repeat = 0;
if (pExaScr->info->PrepareComposite &&
!pSrc->alphaMap && (!pMask || !pMask->alphaMap) && !pDst->alphaMap)
{
Bool isSrcSolid;
ret = exaTryDriverComposite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask,
yMask, xDst, yDst, width, height);
if (ret == 1)
goto done;
isSrcSolid = pSrc->pDrawable ?
(pSrc->pDrawable->width == 1 && pSrc->pDrawable->height == 1 &&
pSrc->repeat) :
(pSrc->pSourcePict->type == SourcePictTypeSolidFill);
if (ret == -1 && op == PictOpOver && pMask &&
(pMask->componentAlpha || isSrcSolid)) {
ret = exaTryMagicTwoPassCompositeHelper(op, pSrc, pMask, pDst,
xSrc, ySrc,
xMask, yMask, xDst, yDst,
width, height);
if (ret == 1)
goto done;
}
}
fallback:
#if DEBUG_TRACE_FALL
exaPrintCompositeFallback (op, pSrc, pMask, pDst);
#endif
ExaCheckComposite (op, pSrc, pMask, pDst, xSrc, ySrc,
xMask, yMask, xDst, yDst, width, height);
done:
pSrc->repeat = saveSrcRepeat;
if (pMask)
pMask->repeat = saveMaskRepeat;
}
static PicturePtr
exaCreateAlphaPicture (ScreenPtr pScreen,
PicturePtr pDst,
PictFormatPtr pPictFormat,
CARD16 width,
CARD16 height)
{
PixmapPtr pPixmap;
PicturePtr pPicture;
GCPtr pGC;
int error;
xRectangle rect;
if (width > 32767 || height > 32767)
return 0;
if (!pPictFormat)
{
if (pDst->polyEdge == PolyEdgeSharp)
pPictFormat = PictureMatchFormat (pScreen, 1, PICT_a1);
else
pPictFormat = PictureMatchFormat (pScreen, 8, PICT_a8);
if (!pPictFormat)
return 0;
}
pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
pPictFormat->depth, 0);
if (!pPixmap)
return 0;
pGC = GetScratchGC (pPixmap->drawable.depth, pScreen);
if (!pGC)
{
(*pScreen->DestroyPixmap) (pPixmap);
return 0;
}
ValidateGC (&pPixmap->drawable, pGC);
rect.x = 0;
rect.y = 0;
rect.width = width;
rect.height = height;
ExaCheckPolyFillRect (&pPixmap->drawable, pGC, 1, &rect);
exaPixmapDirty (pPixmap, 0, 0, width, height);
FreeScratchGC (pGC);
pPicture = CreatePicture (0, &pPixmap->drawable, pPictFormat,
0, 0, serverClient, &error);
(*pScreen->DestroyPixmap) (pPixmap);
return pPicture;
}
void
exaTrapezoids (CARD8 op, PicturePtr pSrc, PicturePtr pDst,
PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
int ntrap, xTrapezoid *traps)
{
ScreenPtr pScreen = pDst->pDrawable->pScreen;
PictureScreenPtr ps = GetPictureScreen(pScreen);
BoxRec bounds;
if (maskFormat) {
PicturePtr pPicture;
INT16 xDst, yDst;
INT16 xRel, yRel;
miTrapezoidBounds (ntrap, traps, &bounds);
if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
return;
xDst = traps[0].left.p1.x >> 16;
yDst = traps[0].left.p1.y >> 16;
pPicture = exaCreateAlphaPicture (pScreen, pDst, maskFormat,
bounds.x2 - bounds.x1,
bounds.y2 - bounds.y1);
if (!pPicture)
return;
exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
for (; ntrap; ntrap--, traps++)
(*ps->RasterizeTrapezoid) (pPicture, traps,
-bounds.x1, -bounds.y1);
exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
xRel = bounds.x1 + xSrc - xDst;
yRel = bounds.y1 + ySrc - yDst;
CompositePicture (op, pSrc, pPicture, pDst,
xRel, yRel, 0, 0, bounds.x1, bounds.y1,
bounds.x2 - bounds.x1,
bounds.y2 - bounds.y1);
FreePicture (pPicture, 0);
} else {
if (pDst->polyEdge == PolyEdgeSharp)
maskFormat = PictureMatchFormat (pScreen, 1, PICT_a1);
else
maskFormat = PictureMatchFormat (pScreen, 8, PICT_a8);
for (; ntrap; ntrap--, traps++)
exaTrapezoids (op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, traps);
}
}
void
exaTriangles (CARD8 op, PicturePtr pSrc, PicturePtr pDst,
PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
int ntri, xTriangle *tris)
{
ScreenPtr pScreen = pDst->pDrawable->pScreen;
PictureScreenPtr ps = GetPictureScreen(pScreen);
BoxRec bounds;
if (maskFormat) {
PicturePtr pPicture;
INT16 xDst, yDst;
INT16 xRel, yRel;
miTriangleBounds (ntri, tris, &bounds);
if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
return;
xDst = tris[0].p1.x >> 16;
yDst = tris[0].p1.y >> 16;
pPicture = exaCreateAlphaPicture (pScreen, pDst, maskFormat,
bounds.x2 - bounds.x1,
bounds.y2 - bounds.y1);
if (!pPicture)
return;
exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
(*ps->AddTriangles) (pPicture, -bounds.x1, -bounds.y1, ntri, tris);
exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
xRel = bounds.x1 + xSrc - xDst;
yRel = bounds.y1 + ySrc - yDst;
CompositePicture (op, pSrc, pPicture, pDst,
xRel, yRel, 0, 0, bounds.x1, bounds.y1,
bounds.x2 - bounds.x1, bounds.y2 - bounds.y1);
FreePicture (pPicture, 0);
} else {
if (pDst->polyEdge == PolyEdgeSharp)
maskFormat = PictureMatchFormat (pScreen, 1, PICT_a1);
else
maskFormat = PictureMatchFormat (pScreen, 8, PICT_a8);
for (; ntri; ntri--, tris++)
exaTriangles (op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, tris);
}
}