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.
This commit is contained in:
parent
54184110f6
commit
40eb14c948
|
@ -56,16 +56,6 @@
|
||||||
#define DBG_GLYPH_CACHE(a)
|
#define DBG_GLYPH_CACHE(a)
|
||||||
#endif
|
#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
|
/* 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
|
* max texture size of the driver; this may need to actually come from
|
||||||
* the driver.
|
* the driver.
|
||||||
|
@ -79,7 +69,7 @@ typedef struct {
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PicturePtr source;
|
PicturePtr source;
|
||||||
ExaGlyphRenderRec glyphs[GLYPH_BUFFER_SIZE];
|
ExaCompositeRectRec rects[GLYPH_BUFFER_SIZE];
|
||||||
int count;
|
int count;
|
||||||
} ExaGlyphBuffer, *ExaGlyphBufferPtr;
|
} ExaGlyphBuffer, *ExaGlyphBufferPtr;
|
||||||
|
|
||||||
|
@ -364,7 +354,7 @@ exaGlyphCacheBufferGlyph(ScreenPtr pScreen,
|
||||||
int xGlyph,
|
int xGlyph,
|
||||||
int yGlyph)
|
int yGlyph)
|
||||||
{
|
{
|
||||||
ExaGlyphRenderPtr glyphRec;
|
ExaCompositeRectPtr rect;
|
||||||
int pos;
|
int pos;
|
||||||
|
|
||||||
if (buffer->source && buffer->source != cache->picture)
|
if (buffer->source && buffer->source != cache->picture)
|
||||||
|
@ -407,7 +397,7 @@ exaGlyphCacheBufferGlyph(ScreenPtr pScreen,
|
||||||
y = (pos / cache->columns) * cache->glyphHeight;
|
y = (pos / cache->columns) * cache->glyphHeight;
|
||||||
|
|
||||||
for (i = 0; i < buffer->count; i++) {
|
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"));
|
DBG_GLYPH_CACHE((" must flush buffer\n"));
|
||||||
return ExaGlyphNeedFlush;
|
return ExaGlyphNeedFlush;
|
||||||
}
|
}
|
||||||
|
@ -439,13 +429,13 @@ exaGlyphCacheBufferGlyph(ScreenPtr pScreen,
|
||||||
|
|
||||||
buffer->source = cache->picture;
|
buffer->source = cache->picture;
|
||||||
|
|
||||||
glyphRec = &buffer->glyphs[buffer->count];
|
rect = &buffer->rects[buffer->count];
|
||||||
glyphRec->xSrc = (pos % cache->columns) * cache->glyphWidth;
|
rect->xSrc = (pos % cache->columns) * cache->glyphWidth;
|
||||||
glyphRec->ySrc = (pos / cache->columns) * cache->glyphHeight;
|
rect->ySrc = (pos / cache->columns) * cache->glyphHeight;
|
||||||
glyphRec->xDst = xGlyph - pGlyph->info.x;
|
rect->xDst = xGlyph - pGlyph->info.x;
|
||||||
glyphRec->yDst = yGlyph - pGlyph->info.y;
|
rect->yDst = yGlyph - pGlyph->info.y;
|
||||||
glyphRec->width = pGlyph->info.width;
|
rect->width = pGlyph->info.width;
|
||||||
glyphRec->height = pGlyph->info.height;
|
rect->height = pGlyph->info.height;
|
||||||
|
|
||||||
buffer->count++;
|
buffer->count++;
|
||||||
|
|
||||||
|
@ -463,7 +453,7 @@ exaBufferGlyph(ScreenPtr pScreen,
|
||||||
unsigned int format = (GlyphPicture(pGlyph)[pScreen->myNum])->format;
|
unsigned int format = (GlyphPicture(pGlyph)[pScreen->myNum])->format;
|
||||||
int width = pGlyph->info.width;
|
int width = pGlyph->info.width;
|
||||||
int height = pGlyph->info.width;
|
int height = pGlyph->info.width;
|
||||||
ExaGlyphRenderPtr glyphRec;
|
ExaCompositeRectPtr rect;
|
||||||
PicturePtr source;
|
PicturePtr source;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -497,13 +487,13 @@ exaBufferGlyph(ScreenPtr pScreen,
|
||||||
|
|
||||||
buffer->source = source;
|
buffer->source = source;
|
||||||
|
|
||||||
glyphRec = &buffer->glyphs[buffer->count];
|
rect = &buffer->rects[buffer->count];
|
||||||
glyphRec->xSrc = 0;
|
rect->xSrc = 0;
|
||||||
glyphRec->ySrc = 0;
|
rect->ySrc = 0;
|
||||||
glyphRec->xDst = xGlyph - pGlyph->info.x;
|
rect->xDst = xGlyph - pGlyph->info.x;
|
||||||
glyphRec->yDst = yGlyph - pGlyph->info.y;
|
rect->yDst = yGlyph - pGlyph->info.y;
|
||||||
glyphRec->width = pGlyph->info.width;
|
rect->width = pGlyph->info.width;
|
||||||
glyphRec->height = pGlyph->info.height;
|
rect->height = pGlyph->info.height;
|
||||||
|
|
||||||
buffer->count++;
|
buffer->count++;
|
||||||
|
|
||||||
|
@ -514,23 +504,8 @@ static void
|
||||||
exaGlyphsToMask(PicturePtr pMask,
|
exaGlyphsToMask(PicturePtr pMask,
|
||||||
ExaGlyphBufferPtr buffer)
|
ExaGlyphBufferPtr buffer)
|
||||||
{
|
{
|
||||||
int i;
|
exaCompositeRects(PictOpAdd, buffer->source, pMask,
|
||||||
|
buffer->count, buffer->rects);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer->count = 0;
|
buffer->count = 0;
|
||||||
buffer->source = NULL;
|
buffer->source = NULL;
|
||||||
|
@ -549,20 +524,20 @@ exaGlyphsToDst(CARD8 op,
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < buffer->count; i++) {
|
for (i = 0; i < buffer->count; i++) {
|
||||||
ExaGlyphRenderPtr glyphRec = &buffer->glyphs[i];
|
ExaCompositeRectPtr rect = &buffer->rects[i];
|
||||||
|
|
||||||
CompositePicture (op,
|
CompositePicture (op,
|
||||||
pSrc,
|
pSrc,
|
||||||
buffer->source,
|
buffer->source,
|
||||||
pDst,
|
pDst,
|
||||||
xSrc + glyphRec->xDst - xDst,
|
xSrc + rect->xDst - xDst,
|
||||||
ySrc + glyphRec->yDst - yDst,
|
ySrc + rect->yDst - yDst,
|
||||||
glyphRec->xSrc,
|
rect->xSrc,
|
||||||
glyphRec->ySrc,
|
rect->ySrc,
|
||||||
glyphRec->xDst,
|
rect->xDst,
|
||||||
glyphRec->yDst,
|
rect->yDst,
|
||||||
glyphRec->width,
|
rect->width,
|
||||||
glyphRec->height);
|
rect->height);
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer->count = 0;
|
buffer->count = 0;
|
||||||
|
|
|
@ -243,6 +243,15 @@ typedef struct _ExaMigrationRec {
|
||||||
RegionPtr pReg;
|
RegionPtr pReg;
|
||||||
} ExaMigrationRec, *ExaMigrationPtr;
|
} 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
|
* 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.
|
* to set EXA options or hook in screen functions to handle using EXA as the AA.
|
||||||
|
@ -456,6 +465,13 @@ exaComposite(CARD8 op,
|
||||||
CARD16 width,
|
CARD16 width,
|
||||||
CARD16 height);
|
CARD16 height);
|
||||||
|
|
||||||
|
void
|
||||||
|
exaCompositeRects(CARD8 op,
|
||||||
|
PicturePtr Src,
|
||||||
|
PicturePtr pDst,
|
||||||
|
int nrect,
|
||||||
|
ExaCompositeRectPtr rects);
|
||||||
|
|
||||||
void
|
void
|
||||||
exaTrapezoids (CARD8 op, PicturePtr pSrc, PicturePtr pDst,
|
exaTrapezoids (CARD8 op, PicturePtr pSrc, PicturePtr pDst,
|
||||||
PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
|
PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
|
||||||
|
|
222
exa/exa_render.c
222
exa/exa_render.c
|
@ -331,6 +331,228 @@ exaTryDriverSolidFill(PicturePtr pSrc,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
static int
|
||||||
exaTryDriverComposite(CARD8 op,
|
exaTryDriverComposite(CARD8 op,
|
||||||
PicturePtr pSrc,
|
PicturePtr pSrc,
|
||||||
|
|
Loading…
Reference in New Issue