diff options
author | Michel Dänzer <daenzer@vmware.com> | 2009-02-26 10:35:44 +0100 |
---|---|---|
committer | Michel Dänzer <daenzer@vmware.com> | 2009-02-26 10:35:44 +0100 |
commit | f07f18231a921d3ae9dd9b75881c9e58e9e2e235 (patch) | |
tree | 7cc6deae377d4d6b20f0874c9304b91d08d964e7 /exa | |
parent | b26c136ee9bf7015c583136af53d0c9e9da67ace (diff) |
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>
Diffstat (limited to 'exa')
-rw-r--r-- | exa/exa_glyphs.c | 253 | ||||
-rw-r--r-- | exa/exa_priv.h | 4 | ||||
-rw-r--r-- | 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 688081dde..918fd8553 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 ea8c3da91..8f83701bf 100644 --- a/exa/exa_priv.h +++ b/exa/exa_priv.h @@ -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); diff --git a/exa/exa_render.c b/exa/exa_render.c index bdc1ed195..d53f13bee 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. */ |