diff options
author | Owen Taylor <otaylor@huygens.home.fishsoup.net> | 2008-04-28 21:00:54 +0200 |
---|---|---|
committer | Michel Dänzer <michel@tungstengraphics.com> | 2008-04-28 21:00:54 +0200 |
commit | 40eb14c9482457969e0bde97c49edad536285e02 (patch) | |
tree | 9dd0886b5a138f45e39fc5b777a1b544d6527b45 /exa | |
parent | 54184110f6f3e5d7276d5431e739a4fcf0c3523e (diff) |
EXA: Add exaCompositeRects()
Add a function to composite multiple independent rectangles
from the same source to the same destination in a single
operation: this is useful for building a glyph mask.
Diffstat (limited to 'exa')
-rw-r--r-- | exa/exa_glyphs.c | 83 | ||||
-rw-r--r-- | exa/exa_priv.h | 16 | ||||
-rw-r--r-- | exa/exa_render.c | 222 |
3 files changed, 267 insertions, 54 deletions
diff --git a/exa/exa_glyphs.c b/exa/exa_glyphs.c index 3fe433aa7..55fdb0197 100644 --- a/exa/exa_glyphs.c +++ b/exa/exa_glyphs.c @@ -56,16 +56,6 @@ #define DBG_GLYPH_CACHE(a) #endif -/* Instructions for rendering a single glyph */ -typedef struct { - INT16 xSrc; - INT16 ySrc; - INT16 xDst; - INT16 yDst; - INT16 width; - INT16 height; -} ExaGlyphRenderRec, *ExaGlyphRenderPtr; - /* Width of the pixmaps we use for the caches; this should be less than * max texture size of the driver; this may need to actually come from * the driver. @@ -79,7 +69,7 @@ typedef struct { typedef struct { PicturePtr source; - ExaGlyphRenderRec glyphs[GLYPH_BUFFER_SIZE]; + ExaCompositeRectRec rects[GLYPH_BUFFER_SIZE]; int count; } ExaGlyphBuffer, *ExaGlyphBufferPtr; @@ -364,7 +354,7 @@ exaGlyphCacheBufferGlyph(ScreenPtr pScreen, int xGlyph, int yGlyph) { - ExaGlyphRenderPtr glyphRec; + ExaCompositeRectPtr rect; int pos; if (buffer->source && buffer->source != cache->picture) @@ -407,7 +397,7 @@ exaGlyphCacheBufferGlyph(ScreenPtr pScreen, y = (pos / cache->columns) * cache->glyphHeight; for (i = 0; i < buffer->count; i++) { - if (buffer->glyphs[i].xSrc == x && buffer->glyphs[i].ySrc == y) { + if (buffer->rects[i].xSrc == x && buffer->rects[i].ySrc == y) { DBG_GLYPH_CACHE((" must flush buffer\n")); return ExaGlyphNeedFlush; } @@ -439,13 +429,13 @@ exaGlyphCacheBufferGlyph(ScreenPtr pScreen, buffer->source = cache->picture; - glyphRec = &buffer->glyphs[buffer->count]; - glyphRec->xSrc = (pos % cache->columns) * cache->glyphWidth; - glyphRec->ySrc = (pos / cache->columns) * cache->glyphHeight; - glyphRec->xDst = xGlyph - pGlyph->info.x; - glyphRec->yDst = yGlyph - pGlyph->info.y; - glyphRec->width = pGlyph->info.width; - glyphRec->height = pGlyph->info.height; + rect = &buffer->rects[buffer->count]; + rect->xSrc = (pos % cache->columns) * cache->glyphWidth; + rect->ySrc = (pos / cache->columns) * cache->glyphHeight; + rect->xDst = xGlyph - pGlyph->info.x; + rect->yDst = yGlyph - pGlyph->info.y; + rect->width = pGlyph->info.width; + rect->height = pGlyph->info.height; buffer->count++; @@ -463,7 +453,7 @@ exaBufferGlyph(ScreenPtr pScreen, unsigned int format = (GlyphPicture(pGlyph)[pScreen->myNum])->format; int width = pGlyph->info.width; int height = pGlyph->info.width; - ExaGlyphRenderPtr glyphRec; + ExaCompositeRectPtr rect; PicturePtr source; int i; @@ -497,13 +487,13 @@ exaBufferGlyph(ScreenPtr pScreen, buffer->source = source; - glyphRec = &buffer->glyphs[buffer->count]; - glyphRec->xSrc = 0; - glyphRec->ySrc = 0; - glyphRec->xDst = xGlyph - pGlyph->info.x; - glyphRec->yDst = yGlyph - pGlyph->info.y; - glyphRec->width = pGlyph->info.width; - glyphRec->height = pGlyph->info.height; + 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; buffer->count++; @@ -514,23 +504,8 @@ static void exaGlyphsToMask(PicturePtr pMask, ExaGlyphBufferPtr buffer) { - int i; - - for (i = 0; i < buffer->count; i++) { - ExaGlyphRenderPtr glyphRec = &buffer->glyphs[i]; - - CompositePicture (PictOpAdd, - buffer->source, - None, - pMask, - glyphRec->xSrc, - glyphRec->ySrc, - 0, 0, - glyphRec->xDst, - glyphRec->yDst, - glyphRec->width, - glyphRec->height); - } + exaCompositeRects(PictOpAdd, buffer->source, pMask, + buffer->count, buffer->rects); buffer->count = 0; buffer->source = NULL; @@ -549,20 +524,20 @@ exaGlyphsToDst(CARD8 op, int i; for (i = 0; i < buffer->count; i++) { - ExaGlyphRenderPtr glyphRec = &buffer->glyphs[i]; + ExaCompositeRectPtr rect = &buffer->rects[i]; CompositePicture (op, pSrc, buffer->source, pDst, - xSrc + glyphRec->xDst - xDst, - ySrc + glyphRec->yDst - yDst, - glyphRec->xSrc, - glyphRec->ySrc, - glyphRec->xDst, - glyphRec->yDst, - glyphRec->width, - glyphRec->height); + xSrc + rect->xDst - xDst, + ySrc + rect->yDst - yDst, + rect->xSrc, + rect->ySrc, + rect->xDst, + rect->yDst, + rect->width, + rect->height); } buffer->count = 0; diff --git a/exa/exa_priv.h b/exa/exa_priv.h index aaceeb81d..0d5d0f5d2 100644 --- a/exa/exa_priv.h +++ b/exa/exa_priv.h @@ -243,6 +243,15 @@ typedef struct _ExaMigrationRec { RegionPtr pReg; } ExaMigrationRec, *ExaMigrationPtr; +typedef struct { + INT16 xSrc; + INT16 ySrc; + INT16 xDst; + INT16 yDst; + INT16 width; + INT16 height; +} ExaCompositeRectRec, *ExaCompositeRectPtr; + /** * exaDDXDriverInit must be implemented by the DDX using EXA, and is the place * to set EXA options or hook in screen functions to handle using EXA as the AA. @@ -457,6 +466,13 @@ exaComposite(CARD8 op, CARD16 height); void +exaCompositeRects(CARD8 op, + PicturePtr Src, + PicturePtr pDst, + int nrect, + ExaCompositeRectPtr rects); + +void exaTrapezoids (CARD8 op, PicturePtr pSrc, PicturePtr pDst, PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int ntrap, xTrapezoid *traps); diff --git a/exa/exa_render.c b/exa/exa_render.c index 1d7b8974c..43b0029e5 100644 --- a/exa/exa_render.c +++ b/exa/exa_render.c @@ -332,6 +332,228 @@ exaTryDriverSolidFill(PicturePtr pSrc, } static int +exaTryDriverCompositeRects(CARD8 op, + PicturePtr pSrc, + 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; + struct _Pixmap scratch; + ExaMigrationRec pixmaps[2]; + + pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable); + pSrcExaPix = ExaGetPixmapPriv(pSrcPix); + + pDstPix = exaGetDrawablePixmap(pDst->pDrawable); + pDstExaPix = ExaGetPixmapPriv(pDstPix); + + /* Check whether the accelerator can use these pixmaps. + * FIXME: If it cannot, use temporary pixmaps so that the drawing + * happens within limits. + */ + if (pSrcExaPix->accel_blocked || + pDstExaPix->accel_blocked) + { + return -1; + } + + if (pExaScr->info->CheckComposite && + !(*pExaScr->info->CheckComposite) (op, pSrc, NULL, 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; + pixmaps[0].pReg = NULL; + pixmaps[1].as_dst = FALSE; + pixmaps[1].as_src = TRUE; + pixmaps[1].pPix = pSrcPix; + pixmaps[1].pReg = NULL; + exaDoMigration(pixmaps, 2, TRUE); + + pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y); + if (!exaPixmapIsOffscreen(pDstPix)) + return 0; + + if (!pSrcPix && pExaScr->info->UploadToScratch) + { + pSrcPix = exaGetDrawablePixmap (pSrc->pDrawable); + if ((*pExaScr->info->UploadToScratch) (pSrcPix, &scratch)) + pSrcPix = &scratch; + } + + if (!pSrcPix) + return 0; + + if (!(*pExaScr->info->PrepareComposite) (op, pSrc, NULL, pDst, pSrcPix, + NULL, pDstPix)) + return -1; + + while (nrect--) + { + INT16 xDst = rects->xDst + pDst->pDrawable->x; + INT16 yDst = rects->yDst + pDst->pDrawable->y; + 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, + rects->width, rects->height)) + goto next_rect; + + REGION_TRANSLATE(pScreen, ®ion, dst_off_x, dst_off_y); + + nbox = REGION_NUM_RECTS(®ion); + pbox = REGION_RECTS(®ion); + + 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, + 0, 0, + pbox->x1, + pbox->y1, + pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1); + pbox++; + } + + next_rect: + REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); + + rects++; + } + + (*pExaScr->info->DoneComposite) (pDstPix); + exaMarkSync(pDst->pDrawable->pScreen); + + return 1; +} + +/** + * 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. + */ +void +exaCompositeRects(CARD8 op, + PicturePtr pSrc, + PicturePtr pDst, + int nrect, + ExaCompositeRectPtr rects) +{ + PixmapPtr pPixmap = exaGetDrawablePixmap(pDst->pDrawable); + ExaPixmapPriv(pPixmap); + + int xoff, yoff; + int x1 = MAXSHORT; + int y1 = MAXSHORT; + int x2 = MINSHORT; + int y2 = MINSHORT; + RegionRec region; + RegionPtr pending_damage; + BoxRec box; + int n; + ExaCompositeRectPtr r; + + /* We have to manage the damage ourselves, since CompositeRects isn't + * something in the screen that can be managed by the damage extension, + * and EXA depends on damage to track what needs to be migrated between + * offscreen and onscreen. + */ + + /* Compute the overall extents of the composited region - we're making + * the assumption here that we are compositing a bunch of glyphs that + * cluster closely together and damaging each glyph individually would + * be a loss compared to damaging the bounding box. + */ + n = nrect; + r = rects; + while (n--) { + int rect_x2 = r->xDst + r->width; + int rect_y2 = r->yDst + r->width; + + if (r->xDst < x1) x1 = r->xDst; + if (r->xDst < y1) y1 = r->xDst; + 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; + + /* The pixmap migration code relies on pendingDamage indicating + * the bounds of the current rendering, so we need to force + * the actual damage into that region before we do anything, and + * (see use of DamagePendingRegion in exaCopyDirty) + */ + + REGION_INIT(pScreen, ®ion, &box, 1); + + exaGetDrawableDeltas(pDst->pDrawable, pPixmap, &xoff, &yoff); + + REGION_TRANSLATE(pScreen, ®ion, xoff, yoff); + pending_damage = DamagePendingRegion(pExaPixmap->pDamage); + REGION_UNION(pScreen, pending_damage, pending_damage, ®ion); + REGION_TRANSLATE(pScreen, ®ion, -xoff, -yoff); + + /************************************************************/ + + ValidatePicture (pSrc); + 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++; + } + } + + /************************************************************/ + + /* Now we have to flush the damage out from pendingDamage => damage + * Calling DamageDamageRegion has that effect. (We could pass + * in an empty region here, but we pass in the same region we + * use above; the effect is the same.) + */ + + DamageDamageRegion(pDst->pDrawable, ®ion); + REGION_UNINIT(pScreen, ®ion); +} + +static int exaTryDriverComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, |