EXA: Allow using exaCompositeRects also when we can't use a mask in exaGlyphs.

This should give the full benefits of the glyph cache even when we can't use a
mask.

This also means we no longer need to scan the glyphs to see if they overlap,
we can just use a mask or not as the client asks.

Signed-off-by: Michel Dänzer <daenzer@vmware.com>
This commit is contained in:
Michel Dänzer 2009-02-26 10:35:44 +01:00
parent b26c136ee9
commit f07f18231a
3 changed files with 182 additions and 198 deletions

View File

@ -68,7 +68,7 @@
#define GLYPH_BUFFER_SIZE 256
typedef struct {
PicturePtr source;
PicturePtr mask;
ExaCompositeRectRec rects[GLYPH_BUFFER_SIZE];
int count;
} ExaGlyphBuffer, *ExaGlyphBufferPtr;
@ -144,7 +144,7 @@ exaUnrealizeGlyphCaches(ScreenPtr pScreen,
/* All caches for a single format share a single pixmap for glyph storage,
* allowing mixing glyphs of different sizes without paying a penalty
* for switching between source pixmaps. (Note that for a size of font
* for switching between mask pixmaps. (Note that for a size of font
* right at the border between two sizes, we might be switching for almost
* every glyph.)
*
@ -417,13 +417,19 @@ exaGlyphCacheBufferGlyph(ScreenPtr pScreen,
ExaGlyphCachePtr cache,
ExaGlyphBufferPtr buffer,
GlyphPtr pGlyph,
int xGlyph,
int yGlyph)
PicturePtr pSrc,
PicturePtr pDst,
INT16 xSrc,
INT16 ySrc,
INT16 xMask,
INT16 yMask,
INT16 xDst,
INT16 yDst)
{
ExaCompositeRectPtr rect;
int pos;
if (buffer->source && buffer->source != cache->picture)
if (buffer->mask && buffer->mask != cache->picture)
return ExaGlyphNeedFlush;
if (!cache->picture) {
@ -497,13 +503,28 @@ exaGlyphCacheBufferGlyph(ScreenPtr pScreen,
}
buffer->source = cache->picture;
buffer->mask = cache->picture;
rect = &buffer->rects[buffer->count];
rect->xSrc = CACHE_X(pos);
rect->ySrc = CACHE_Y(pos);
rect->xDst = xGlyph - pGlyph->info.x;
rect->yDst = yGlyph - pGlyph->info.y;
if (pSrc)
{
rect->xSrc = xSrc;
rect->ySrc = ySrc;
rect->xMask = CACHE_X(pos);
rect->yMask = CACHE_Y(pos);
}
else
{
rect->xSrc = CACHE_X(pos);
rect->ySrc = CACHE_Y(pos);
rect->xMask = 0;
rect->yMask = 0;
}
rect->pDst = pDst;
rect->xDst = xDst - pGlyph->info.x;
rect->yDst = yDst - pGlyph->info.y;
rect->width = pGlyph->info.width;
rect->height = pGlyph->info.height;
@ -519,15 +540,21 @@ static ExaGlyphCacheResult
exaBufferGlyph(ScreenPtr pScreen,
ExaGlyphBufferPtr buffer,
GlyphPtr pGlyph,
int xGlyph,
int yGlyph)
PicturePtr pSrc,
PicturePtr pDst,
INT16 xSrc,
INT16 ySrc,
INT16 xMask,
INT16 yMask,
INT16 xDst,
INT16 yDst)
{
ExaScreenPriv(pScreen);
unsigned int format = (GlyphPicture(pGlyph)[pScreen->myNum])->format;
int width = pGlyph->info.width;
int height = pGlyph->info.height;
ExaCompositeRectPtr rect;
PicturePtr source;
PicturePtr mask;
int i;
if (buffer->count == GLYPH_BUFFER_SIZE)
@ -542,9 +569,15 @@ exaBufferGlyph(ScreenPtr pScreen,
if (format == cache->format &&
width <= cache->glyphWidth &&
height <= cache->glyphHeight) {
ExaGlyphCacheResult result = exaGlyphCacheBufferGlyph(pScreen, &pExaScr->glyphCaches[i],
ExaGlyphCacheResult result = exaGlyphCacheBufferGlyph(pScreen,
&pExaScr->glyphCaches[i],
buffer,
pGlyph, xGlyph, yGlyph);
pGlyph,
pSrc,
pDst,
xSrc, ySrc,
xMask, yMask,
xDst, yDst);
switch (result) {
case ExaGlyphFail:
break;
@ -557,19 +590,21 @@ exaBufferGlyph(ScreenPtr pScreen,
/* Couldn't find the glyph in the cache, use the glyph picture directly */
source = GlyphPicture(pGlyph)[pScreen->myNum];
if (buffer->source && buffer->source != source)
mask = GlyphPicture(pGlyph)[pScreen->myNum];
if (buffer->mask && buffer->mask != mask)
return ExaGlyphNeedFlush;
buffer->source = source;
buffer->mask = mask;
rect = &buffer->rects[buffer->count];
rect->xSrc = 0;
rect->ySrc = 0;
rect->xDst = xGlyph - pGlyph->info.x;
rect->yDst = yGlyph - pGlyph->info.y;
rect->width = pGlyph->info.width;
rect->height = pGlyph->info.height;
rect->xSrc = xSrc;
rect->ySrc = ySrc;
rect->xMask = xMask;
rect->yMask = yMask;
rect->xDst = xDst - pGlyph->info.x;
rect->yDst = yDst - pGlyph->info.y;
rect->width = width;
rect->height = height;
buffer->count++;
@ -580,44 +615,23 @@ static void
exaGlyphsToMask(PicturePtr pMask,
ExaGlyphBufferPtr buffer)
{
exaCompositeRects(PictOpAdd, buffer->source, pMask,
exaCompositeRects(PictOpAdd, buffer->mask, NULL, pMask,
buffer->count, buffer->rects);
buffer->count = 0;
buffer->source = NULL;
buffer->mask = NULL;
}
static void
exaGlyphsToDst(CARD8 op,
PicturePtr pSrc,
exaGlyphsToDst(PicturePtr pSrc,
PicturePtr pDst,
ExaGlyphBufferPtr buffer,
INT16 xSrc,
INT16 ySrc,
INT16 xDst,
INT16 yDst)
ExaGlyphBufferPtr buffer)
{
int i;
for (i = 0; i < buffer->count; i++) {
ExaCompositeRectPtr rect = &buffer->rects[i];
CompositePicture (op,
pSrc,
buffer->source,
pDst,
xSrc + rect->xDst - xDst,
ySrc + rect->yDst - yDst,
rect->xSrc,
rect->ySrc,
rect->xDst,
rect->yDst,
rect->width,
rect->height);
}
exaCompositeRects(PictOpOver, pSrc, buffer->mask, pDst, buffer->count,
buffer->rects);
buffer->count = 0;
buffer->source = NULL;
buffer->mask = NULL;
}
/* Cut and paste from render/glyph.c - probably should export it instead */
@ -673,79 +687,6 @@ GlyphExtents (int nlist,
}
}
/**
* Returns TRUE if the glyphs in the lists intersect. Only checks based on
* bounding box, which appears to be good enough to catch most cases at least.
*/
static Bool
exaGlyphsIntersect(int nlist, GlyphListPtr list, GlyphPtr *glyphs)
{
int x1, x2, y1, y2;
int n;
GlyphPtr glyph;
int x, y;
BoxRec extents;
Bool first = TRUE;
x = 0;
y = 0;
while (nlist--) {
x += list->xOff;
y += list->yOff;
n = list->len;
list++;
while (n--) {
glyph = *glyphs++;
if (glyph->info.width == 0 || glyph->info.height == 0) {
x += glyph->info.xOff;
y += glyph->info.yOff;
continue;
}
x1 = x - glyph->info.x;
if (x1 < MINSHORT)
x1 = MINSHORT;
y1 = y - glyph->info.y;
if (y1 < MINSHORT)
y1 = MINSHORT;
x2 = x1 + glyph->info.width;
if (x2 > MAXSHORT)
x2 = MAXSHORT;
y2 = y1 + glyph->info.height;
if (y2 > MAXSHORT)
y2 = MAXSHORT;
if (first) {
extents.x1 = x1;
extents.y1 = y1;
extents.x2 = x2;
extents.y2 = y2;
first = FALSE;
} else {
if (x1 < extents.x2 && x2 > extents.x1 &&
y1 < extents.y2 && y2 > extents.y1)
{
return TRUE;
}
if (x1 < extents.x1)
extents.x1 = x1;
if (x2 > extents.x2)
extents.x2 = x2;
if (y1 < extents.y1)
extents.y1 = y1;
if (y2 > extents.y2)
extents.y2 = y2;
}
x += glyph->info.xOff;
y += glyph->info.yOff;
}
}
return FALSE;
}
void
exaGlyphs (CARD8 op,
PicturePtr pSrc,
@ -759,7 +700,7 @@ exaGlyphs (CARD8 op,
{
PicturePtr pPicture;
PixmapPtr pMaskPixmap = 0;
PicturePtr pMask;
PicturePtr pMask = NULL;
ScreenPtr pScreen = pDst->pDrawable->pScreen;
int width = 0, height = 0;
int x, y;
@ -771,29 +712,6 @@ exaGlyphs (CARD8 op,
CARD32 component_alpha;
ExaGlyphBuffer buffer;
/* If we don't have a mask format but all the glyphs have the same format
* and don't intersect, use the glyph format as mask format for the full
* benefits of the glyph cache.
*/
if (!maskFormat) {
Bool sameFormat = TRUE;
int i;
maskFormat = list[0].format;
for (i = 0; i < nlist; i++) {
if (maskFormat->format != list[i].format->format) {
sameFormat = FALSE;
break;
}
}
if (!sameFormat || (maskFormat->depth != 1 &&
exaGlyphsIntersect(nlist, list, glyphs))) {
maskFormat = NULL;
}
}
if (maskFormat)
{
GCPtr pGC;
@ -840,12 +758,11 @@ exaGlyphs (CARD8 op,
}
else
{
pMask = pDst;
x = 0;
y = 0;
}
buffer.count = 0;
buffer.source = NULL;
buffer.mask = NULL;
while (nlist--)
{
x += list->xOff;
@ -856,16 +773,31 @@ exaGlyphs (CARD8 op,
glyph = *glyphs++;
pPicture = GlyphPicture (glyph)[pScreen->myNum];
if (glyph->info.width > 0 && glyph->info.height > 0 &&
exaBufferGlyph(pScreen, &buffer, glyph, x, y) == ExaGlyphNeedFlush)
if (glyph->info.width > 0 && glyph->info.height > 0)
{
if (maskFormat)
exaGlyphsToMask(pMask, &buffer);
{
if (exaBufferGlyph(pScreen, &buffer, glyph, NULL, pMask,
0, 0, 0, 0, x, y) == ExaGlyphNeedFlush)
{
exaGlyphsToMask(pMask, &buffer);
exaBufferGlyph(pScreen, &buffer, glyph, NULL, pMask,
0, 0, 0, 0, x, y);
}
}
else
exaGlyphsToDst(op, pSrc, pDst, &buffer,
xSrc, ySrc, xDst, yDst);
exaBufferGlyph(pScreen, &buffer, glyph, x, y);
{
if (exaBufferGlyph(pScreen, &buffer, glyph, pSrc, pDst,
xSrc + x - xDst, ySrc + y - yDst,
x, y, x + extents.x1, y + extents.y1)
== ExaGlyphNeedFlush)
{
exaGlyphsToDst(pSrc, pDst, &buffer);
exaBufferGlyph(pScreen, &buffer, glyph, pSrc, pDst,
xSrc + x - xDst, ySrc + y - yDst,
x, y, x + extents.x1, y + extents.y1);
}
}
}
x += glyph->info.xOff;
@ -878,8 +810,7 @@ exaGlyphs (CARD8 op,
if (maskFormat)
exaGlyphsToMask(pMask, &buffer);
else
exaGlyphsToDst(op, pSrc, pDst, &buffer,
xSrc, ySrc, xDst, yDst);
exaGlyphsToDst(pSrc, pDst, &buffer);
}
if (maskFormat)

View File

@ -287,8 +287,11 @@ typedef struct _ExaMigrationRec {
} ExaMigrationRec, *ExaMigrationPtr;
typedef struct {
PicturePtr pDst;
INT16 xSrc;
INT16 ySrc;
INT16 xMask;
INT16 yMask;
INT16 xDst;
INT16 yDst;
INT16 width;
@ -519,6 +522,7 @@ exaComposite(CARD8 op,
void
exaCompositeRects(CARD8 op,
PicturePtr Src,
PicturePtr pMask,
PicturePtr pDst,
int nrect,
ExaCompositeRectPtr rects);

View File

@ -334,15 +334,16 @@ exaTryDriverSolidFill(PicturePtr pSrc,
static int
exaTryDriverCompositeRects(CARD8 op,
PicturePtr pSrc,
PicturePtr pMask,
PicturePtr pDst,
int nrect,
ExaCompositeRectPtr rects)
{
ExaScreenPriv (pDst->pDrawable->pScreen);
int src_off_x, src_off_y, dst_off_x, dst_off_y;
PixmapPtr pSrcPix, pDstPix;
ExaPixmapPrivPtr pSrcExaPix, pDstExaPix;
ExaMigrationRec pixmaps[2];
int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y;
PixmapPtr pSrcPix, pMaskPix = NULL, pDstPix;
ExaPixmapPrivPtr pSrcExaPix, pMaskExaPix = NULL, pDstExaPix;
ExaMigrationRec pixmaps[3];
if (!pExaScr->info->PrepareComposite)
return -1;
@ -350,6 +351,11 @@ exaTryDriverCompositeRects(CARD8 op,
pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable);
pSrcExaPix = ExaGetPixmapPriv(pSrcPix);
if (pMask) {
pMaskPix = exaGetDrawablePixmap(pMask->pDrawable);
pMaskExaPix = ExaGetPixmapPriv(pMaskPix);
}
pDstPix = exaGetDrawablePixmap(pDst->pDrawable);
pDstExaPix = ExaGetPixmapPriv(pDstPix);
@ -357,20 +363,18 @@ exaTryDriverCompositeRects(CARD8 op,
* FIXME: If it cannot, use temporary pixmaps so that the drawing
* happens within limits.
*/
if (pSrcExaPix->accel_blocked ||
pDstExaPix->accel_blocked)
if (pSrcExaPix->accel_blocked || pDstExaPix->accel_blocked ||
(pMask && pMaskExaPix->accel_blocked))
{
return -1;
}
if (pExaScr->info->CheckComposite &&
!(*pExaScr->info->CheckComposite) (op, pSrc, NULL, pDst))
!(*pExaScr->info->CheckComposite) (op, pSrc, pMask, pDst))
{
return -1;
}
exaGetDrawableDeltas (pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y);
pixmaps[0].as_dst = TRUE;
pixmaps[0].as_src = exaOpReadsDestination(op);
pixmaps[0].pPix = pDstPix;
@ -379,32 +383,49 @@ exaTryDriverCompositeRects(CARD8 op,
pixmaps[1].as_src = TRUE;
pixmaps[1].pPix = pSrcPix;
pixmaps[1].pReg = NULL;
exaDoMigration(pixmaps, 2, TRUE);
if (pMask) {
pixmaps[2].as_dst = FALSE;
pixmaps[2].as_src = TRUE;
pixmaps[2].pPix = pMaskPix;
pixmaps[2].pReg = NULL;
exaDoMigration(pixmaps, 3, TRUE);
} else
exaDoMigration(pixmaps, 2, TRUE);
pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y);
if (!exaPixmapIsOffscreen(pDstPix))
pDstPix = exaGetOffscreenPixmap (pDst->pDrawable, &dst_off_x, &dst_off_y);
if (!pDstPix)
return 0;
pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y);
if (!pSrcPix)
return 0;
if (!(*pExaScr->info->PrepareComposite) (op, pSrc, NULL, pDst, pSrcPix,
NULL, pDstPix))
if (pMask) {
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 = pMask ? rects->xMask + pMask->pDrawable->x : 0;
INT16 yMask = pMask ? rects->yMask + pMask->pDrawable->y : 0;
INT16 xSrc = rects->xSrc + pSrc->pDrawable->x;
INT16 ySrc = rects->ySrc + pSrc->pDrawable->y;
RegionRec region;
BoxPtr pbox;
int nbox;
if (!miComputeCompositeRegion (&region, pSrc, NULL, pDst,
xSrc, ySrc, 0, 0, xDst, yDst,
if (!miComputeCompositeRegion (&region, pSrc, pMask, pDst,
xSrc, ySrc, xMask, yMask, xDst, yDst,
rects->width, rects->height))
goto next_rect;
@ -413,6 +434,8 @@ exaTryDriverCompositeRects(CARD8 op,
nbox = REGION_NUM_RECTS(&region);
pbox = REGION_RECTS(&region);
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;
@ -421,7 +444,8 @@ exaTryDriverCompositeRects(CARD8 op,
(*pExaScr->info->Composite) (pDstPix,
pbox->x1 + xSrc,
pbox->y1 + ySrc,
0, 0,
pbox->x1 + xMask,
pbox->y1 + yMask,
pbox->x1,
pbox->y1,
pbox->x2 - pbox->x1,
@ -443,25 +467,30 @@ exaTryDriverCompositeRects(CARD8 op,
/**
* Copy a number of rectangles from source to destination in a single
* operation. This is specialized for building a glyph mask: we don'y
* have a mask argument because we don't need it for that, and we
* don't have he special-case fallbacks found in exaComposite() - if the
* driver can support it, we use the driver functionality, otherwise we
* fallback straight to software.
* operation. This is specialized for glyph rendering: we don't have the
* special-case fallbacks found in exaComposite() - if the driver can support
* it, we use the driver functionality, otherwise we fall back straight to
* software.
*/
void
exaCompositeRects(CARD8 op,
PicturePtr pSrc,
PicturePtr pMask,
PicturePtr pDst,
int nrect,
ExaCompositeRectPtr rects)
{
ExaScreenPriv (pDst->pDrawable->pScreen);
PixmapPtr pPixmap = exaGetDrawablePixmap(pDst->pDrawable);
ExaPixmapPriv(pPixmap);
int n;
ExaCompositeRectPtr r;
if (pExaPixmap->pDamage) {
int ret;
/* If we get a mask, that means we're rendering to the exaGlyphs
* destination directly, so the damage layer takes care of this.
*/
if (!pMask && pExaPixmap->pDamage) {
RegionRec region;
int x1 = MAXSHORT;
int y1 = MAXSHORT;
@ -518,24 +547,44 @@ exaCompositeRects(CARD8 op,
/************************************************************/
ValidatePicture (pSrc);
if (pMask)
ValidatePicture (pMask);
ValidatePicture (pDst);
if (exaTryDriverCompositeRects(op, pSrc, pDst, nrect, rects) != 1) {
n = nrect;
r = rects;
while (n--) {
ExaCheckComposite (op, pSrc, NULL, pDst,
r->xSrc, r->ySrc,
0, 0,
r->xDst, r->yDst,
r->width, r->height);
r++;
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 (pExaPixmap->pDamage) {
if (!pMask && pExaPixmap->pDamage) {
/* Now we have to flush the damage out from pendingDamage => damage
* Calling DamageRegionProcessPending has that effect.
*/