[PATCH] EXA: Allow using exaCompositeRects also when there's no mask in exaGlyphs.
Michel Dänzer
michel at daenzer.net
Tue Feb 24 01:41:32 PST 2009
From: Michel Dänzer <daenzer at vmware.com>
This should give the full benefits of the glyph cache also when there's no
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 at vmware.com>
---
exa/exa_glyphs.c | 253 ++++++++++++++++++++----------------------------------
exa/exa_priv.h | 4 +
exa/exa_render.c | 123 ++++++++++++++++++--------
3 files changed, 182 insertions(+), 198 deletions(-)
diff --git a/exa/exa_glyphs.c b/exa/exa_glyphs.c
index 688081d..918fd85 100644
--- a/exa/exa_glyphs.c
+++ b/exa/exa_glyphs.c
@@ -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)
diff --git a/exa/exa_priv.h b/exa/exa_priv.h
index 957d176..3bfdcda 100644
--- a/exa/exa_priv.h
+++ b/exa/exa_priv.h
@@ -292,8 +292,11 @@ typedef struct _ExaMigrationRec {
} ExaMigrationRec, *ExaMigrationPtr;
typedef struct {
+ PicturePtr pDst;
INT16 xSrc;
INT16 ySrc;
+ INT16 xMask;
+ INT16 yMask;
INT16 xDst;
INT16 yDst;
INT16 width;
@@ -527,6 +530,7 @@ exaComposite(CARD8 op,
void
exaCompositeRects(CARD8 op,
PicturePtr Src,
+ PicturePtr pMask,
PicturePtr pDst,
int nrect,
ExaCompositeRectPtr rects);
diff --git a/exa/exa_render.c b/exa/exa_render.c
index bdc1ed1..d53f13b 100644
--- a/exa/exa_render.c
+++ b/exa/exa_render.c
@@ -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 (®ion, pSrc, NULL, pDst,
- xSrc, ySrc, 0, 0, xDst, yDst,
+
+ if (!miComputeCompositeRegion (®ion, 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(®ion);
pbox = REGION_RECTS(®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;
@@ -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.
*/
--
1.6.2.rc1
More information about the xorg-devel
mailing list