diff --git a/exa/exa.c b/exa/exa.c index b49065303..e9f42df45 100644 --- a/exa/exa.c +++ b/exa/exa.c @@ -32,6 +32,10 @@ #include #endif +#ifdef MITSHM +#include "shmint.h" +#endif + #include #include "exa_priv.h" @@ -117,18 +121,78 @@ exaGetDrawablePixmap(DrawablePtr pDrawable) return (PixmapPtr) pDrawable; } +/** + * Sets the offsets to add to coordinates to make them address the same bits in + * the backing drawable. These coordinates are nonzero only for redirected + * windows. + */ +static void +exaGetDrawableDeltas (DrawablePtr pDrawable, PixmapPtr pPixmap, + int *xp, int *yp) +{ +#ifdef COMPOSITE + if (pDrawable->type == DRAWABLE_WINDOW) { + *xp = -pPixmap->screen_x; + *yp = -pPixmap->screen_y; + return; + } +#endif + + *xp = 0; + *yp = 0; +} + +/** + * exaPixmapDirty() marks a pixmap as dirty, allowing for + * optimizations in pixmap migration when no changes have occurred. + */ +void +exaPixmapDirty (PixmapPtr pPix, int x1, int y1, int x2, int y2) +{ + ExaPixmapPriv(pPix); + BoxRec box; + RegionPtr pDamageReg; + RegionRec region; + + if (!pExaPixmap) + return; + + box.x1 = max(x1, 0); + box.y1 = max(y1, 0); + box.x2 = min(x2, pPix->drawable.width); + box.y2 = min(y2, pPix->drawable.height); + + if (box.x1 >= box.x2 || box.y1 >= box.y2) + return; + + pDamageReg = DamageRegion(pExaPixmap->pDamage); + + REGION_INIT(pScreen, ®ion, &box, 1); + REGION_UNION(pScreen, pDamageReg, pDamageReg, ®ion); + REGION_UNINIT(pScreen, ®ion); +} + /** * exaDrawableDirty() marks a pixmap backing a drawable as dirty, allowing for * optimizations in pixmap migration when no changes have occurred. */ void -exaDrawableDirty (DrawablePtr pDrawable) +exaDrawableDirty (DrawablePtr pDrawable, int x1, int y1, int x2, int y2) { - ExaPixmapPrivPtr pExaPixmap; + PixmapPtr pPix = exaGetDrawablePixmap(pDrawable); + int xoff, yoff; - pExaPixmap = ExaGetPixmapPriv(exaGetDrawablePixmap (pDrawable)); - if (pExaPixmap != NULL) - pExaPixmap->dirty = TRUE; + x1 = max(x1, pDrawable->x); + y1 = max(y1, pDrawable->y); + x2 = min(x2, pDrawable->x + pDrawable->width); + y2 = min(y2, pDrawable->y + pDrawable->height); + + if (x1 >= x2 || y1 >= y2) + return; + + exaGetDrawableDeltas(pDrawable, pPix, &xoff, &yoff); + + exaPixmapDirty(pPix, x1 + xoff, y1 + yoff, x2 + xoff, y2 + yoff); } static Bool @@ -149,6 +213,7 @@ exaDestroyPixmap (PixmapPtr pPixmap) pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr; pPixmap->devKind = pExaPixmap->sys_pitch; } + REGION_UNINIT(pPixmap->drawable.pScreen, &pExaPixmap->validReg); } return fbDestroyPixmap (pPixmap); } @@ -216,7 +281,20 @@ exaCreatePixmap(ScreenPtr pScreen, int w, int h, int depth) return NULL; } - pExaPixmap->dirty = FALSE; + /* Set up damage tracking */ + pExaPixmap->pDamage = DamageCreate (NULL, NULL, DamageReportNone, TRUE, + pScreen, pPixmap); + + if (pExaPixmap->pDamage == NULL) { + fbDestroyPixmap (pPixmap); + return NULL; + } + + DamageRegister (&pPixmap->drawable, pExaPixmap->pDamage); + DamageSetReportAfterOp (pExaPixmap->pDamage, TRUE); + + /* None of the pixmap bits are valid initially */ + REGION_NULL(pScreen, &pExaPixmap->validReg); return pPixmap; } @@ -261,32 +339,14 @@ exaDrawableIsOffscreen (DrawablePtr pDrawable) /** * Returns the pixmap which backs a drawable, and the offsets to add to * coordinates to make them address the same bits in the backing drawable. - * These coordinates are nonzero only for redirected windows. */ PixmapPtr exaGetOffscreenPixmap (DrawablePtr pDrawable, int *xp, int *yp) { - PixmapPtr pPixmap; - int x, y; + PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable); + + exaGetDrawableDeltas (pDrawable, pPixmap, xp, yp); - if (pDrawable->type == DRAWABLE_WINDOW) { - pPixmap = (*pDrawable->pScreen->GetWindowPixmap) ((WindowPtr) pDrawable); -#ifdef COMPOSITE - x = -pPixmap->screen_x; - y = -pPixmap->screen_y; -#else - x = 0; - y = 0; -#endif - } - else - { - pPixmap = (PixmapPtr) pDrawable; - x = 0; - y = 0; - } - *xp = x; - *yp = y; if (exaPixmapIsOffscreen (pPixmap)) return pPixmap; else @@ -334,8 +394,7 @@ exaPrepareAccess(DrawablePtr pDrawable, int index) /** * exaFinishAccess() is EXA's wrapper for the driver's FinishAccess() handler. * - * It deals with marking drawables as dirty, and calling the driver's - * FinishAccess() only if necessary. + * It deals with calling the driver's FinishAccess() only if necessary. */ void exaFinishAccess(DrawablePtr pDrawable, int index) @@ -345,9 +404,6 @@ exaFinishAccess(DrawablePtr pDrawable, int index) PixmapPtr pPixmap; ExaPixmapPrivPtr pExaPixmap; - if (index == EXA_PREPARE_DEST) - exaDrawableDirty (pDrawable); - pPixmap = exaGetDrawablePixmap (pDrawable); pExaPixmap = ExaGetPixmapPriv(pPixmap); @@ -373,7 +429,7 @@ exaFinishAccess(DrawablePtr pDrawable, int index) * accelerated or may sync the card and fall back to fb. */ static void -exaValidateGC (GCPtr pGC, Mask changes, DrawablePtr pDrawable) +exaValidateGC (GCPtr pGC, unsigned long changes, DrawablePtr pDrawable) { /* fbValidateGC will do direct access to pixmaps if the tiling has changed. * Preempt fbValidateGC by doing its work and masking the change out, so @@ -404,6 +460,7 @@ exaValidateGC (GCPtr pGC, Mask changes, DrawablePtr pDrawable) exaPrepareAccess(&pOldTile->drawable, EXA_PREPARE_SRC); pNewTile = fb24_32ReformatTile (pOldTile, pDrawable->bitsPerPixel); + exaPixmapDirty(pNewTile, 0, 0, pNewTile->drawable.width, pNewTile->drawable.height); exaFinishAccess(&pOldTile->drawable, EXA_PREPARE_SRC); } if (pNewTile) @@ -419,9 +476,14 @@ exaValidateGC (GCPtr pGC, Mask changes, DrawablePtr pDrawable) if (!pGC->tileIsPixel && FbEvenTile (pGC->tile.pixmap->drawable.width * pDrawable->bitsPerPixel)) { - exaPrepareAccess(&pGC->tile.pixmap->drawable, EXA_PREPARE_SRC); + /* XXX This fixes corruption with tiled pixmaps, but may just be a + * workaround for broken drivers + */ + exaMoveOutPixmap(pGC->tile.pixmap); fbPadPixmap (pGC->tile.pixmap); - exaFinishAccess(&pGC->tile.pixmap->drawable, EXA_PREPARE_SRC); + exaPixmapDirty(pGC->tile.pixmap, 0, 0, + pGC->tile.pixmap->drawable.width, + pGC->tile.pixmap->drawable.height); } /* Mask out the GCTile change notification, now that we've done FB's * job for it. @@ -560,7 +622,7 @@ exaDriverInit (ScreenPtr pScreen, pScreen->devPrivates[exaScreenPrivateIndex].ptr = (pointer) pExaScr; - pExaScr->migration = ExaMigrationSmart; + pExaScr->migration = ExaMigrationAlways; exaDDXDriverInit(pScreen); @@ -610,6 +672,13 @@ exaDriverInit (ScreenPtr pScreen, miDisableCompositeWrapper(pScreen); #endif +#ifdef MITSHM + /* Re-register with the MI funcs, which don't allow shared pixmaps. + * Shared pixmaps are almost always a performance loss for us, but this + * still allows for SHM PutImage. + */ + ShmRegisterFuncs(pScreen, NULL); +#endif /* * Hookup offscreen pixmaps */ diff --git a/exa/exa.h b/exa/exa.h index 96465a775..bf723f723 100644 --- a/exa/exa.h +++ b/exa/exa.h @@ -39,7 +39,7 @@ #include "fb.h" #define EXA_VERSION_MAJOR 2 -#define EXA_VERSION_MINOR 0 +#define EXA_VERSION_MINOR 1 #define EXA_VERSION_RELEASE 0 typedef struct _ExaOffscreenArea ExaOffscreenArea; @@ -73,8 +73,8 @@ struct _ExaOffscreenArea { typedef struct _ExaDriver { /** * exa_major and exa_minor should be set by the driver to the version of - * EXA which the driver was compiled for (or configures itself at runtime to - * support). This allows EXA to extend the structure for new features + * EXA which the driver was compiled for (or configures itself at runtime + * to support). This allows EXA to extend the structure for new features * without breaking ABI for drivers compiled against older versions. */ int exa_major, exa_minor; @@ -716,6 +716,12 @@ exaGetPixmapSize(PixmapPtr pPix); void exaEnableDisableFBAccess (int index, Bool enable); +void +exaMoveInPixmap (PixmapPtr pPixmap); + +void +exaMoveOutPixmap (PixmapPtr pPixmap); + /** * Returns TRUE if the given planemask covers all the significant bits in the * pixel values for pDrawable. diff --git a/exa/exa_accel.c b/exa/exa_accel.c index bc77a4071..6fa481ad0 100644 --- a/exa/exa_accel.c +++ b/exa/exa_accel.c @@ -20,6 +20,11 @@ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. + * + * Authors: + * Eric Anholt + * Michel Dänzer + * */ #ifdef HAVE_DIX_CONFIG_H @@ -49,12 +54,12 @@ exaFillSpans(DrawablePtr pDrawable, GCPtr pGC, int n, pixmaps[0].as_dst = TRUE; pixmaps[0].as_src = FALSE; - pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable); + pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable); if (pExaScr->swappedOut || pGC->fillStyle != FillSolid || - pDrawable->width > pExaScr->info->maxX || - pDrawable->height > pExaScr->info->maxY) + pPixmap->drawable.width > pExaScr->info->maxX || + pPixmap->drawable.height > pExaScr->info->maxY) { exaDoMigration (pixmaps, 1, FALSE); ExaCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted); @@ -104,6 +109,8 @@ exaFillSpans(DrawablePtr pDrawable, GCPtr pGC, int n, (*pExaScr->info->Solid) (pPixmap, fullX1 + off_x, fullY1 + off_y, fullX2 + off_x, fullY1 + 1 + off_y); + exaPixmapDirty (pPixmap, fullX1 + off_x, fullY1 + off_y, + fullX2 + off_x, fullY1 + 1 + off_y); } else { @@ -118,17 +125,19 @@ exaFillSpans(DrawablePtr pDrawable, GCPtr pGC, int n, partX2 = pbox->x2; if (partX2 > fullX2) partX2 = fullX2; - if (partX2 > partX1) + if (partX2 > partX1) { (*pExaScr->info->Solid) (pPixmap, partX1 + off_x, fullY1 + off_y, partX2 + off_x, fullY1 + 1 + off_y); + exaPixmapDirty (pPixmap, partX1 + off_x, fullY1 + off_y, + partX2 + off_x, fullY1 + 1 + off_y); + } } pbox++; } } } (*pExaScr->info->DoneSolid) (pPixmap); - exaDrawableDirty (pDrawable); exaMarkSync(pScreen); } @@ -222,8 +231,8 @@ exaPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, exaFinishAccess(pDrawable, EXA_PREPARE_DEST); } + exaPixmapDirty(pPix, x1 + xoff, y1 + yoff, x2 + xoff, y2 + yoff); } - exaDrawableDirty(pDrawable); return; @@ -351,11 +360,12 @@ exaCopyNtoNTwoDir (DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, dst_off_y + pbox->y1 + i, pbox->x2 - pbox->x1, 1); } + exaPixmapDirty(pDstPixmap, dst_off_x + pbox->x1, dst_off_y + pbox->y1, + dst_off_x + pbox->x2, dst_off_y + pbox->y2); } if (dirsetup != 0) pExaScr->info->DoneCopy(pDstPixmap); exaMarkSync(pDstDrawable->pScreen); - exaDrawableDirty(pDstDrawable); return TRUE; } @@ -380,19 +390,19 @@ exaCopyNtoN (DrawablePtr pSrcDrawable, pixmaps[0].as_dst = TRUE; pixmaps[0].as_src = FALSE; - pixmaps[0].pPix = exaGetDrawablePixmap (pDstDrawable); + pixmaps[0].pPix = pDstPixmap = exaGetDrawablePixmap (pDstDrawable); pixmaps[1].as_dst = FALSE; pixmaps[1].as_src = TRUE; - pixmaps[1].pPix = exaGetDrawablePixmap (pSrcDrawable); + pixmaps[1].pPix = pSrcPixmap = exaGetDrawablePixmap (pSrcDrawable); /* Respect maxX/maxY in a trivial way: don't set up drawing when we might * violate the limits. The proper solution would be a temporary pixmap * adjusted so that the drawing happened within limits. */ - if (pSrcDrawable->width > pExaScr->info->maxX || - pSrcDrawable->height > pExaScr->info->maxY || - pDstDrawable->width > pExaScr->info->maxX || - pDstDrawable->height > pExaScr->info->maxY) + if (pSrcPixmap->drawable.width > pExaScr->info->maxX || + pSrcPixmap->drawable.height > pExaScr->info->maxY || + pDstPixmap->drawable.width > pExaScr->info->maxX || + pDstPixmap->drawable.height > pExaScr->info->maxY) { exaDoMigration (pixmaps, 2, FALSE); goto fallback; @@ -401,7 +411,8 @@ exaCopyNtoN (DrawablePtr pSrcDrawable, } /* Mixed directions must be handled specially if the card is lame */ - if (pExaScr->info->flags & EXA_TWO_BITBLT_DIRECTIONS && (dx*dy) < 0) { + if (pExaScr->info->flags & EXA_TWO_BITBLT_DIRECTIONS && + reverse != upsidedown) { if (!exaCopyNtoNTwoDir(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy)) goto fallback; @@ -411,7 +422,7 @@ exaCopyNtoN (DrawablePtr pSrcDrawable, if ((pSrcPixmap = exaGetOffscreenPixmap (pSrcDrawable, &src_off_x, &src_off_y)) && (pDstPixmap = exaGetOffscreenPixmap (pDstDrawable, &dst_off_x, &dst_off_y)) && (*pExaScr->info->PrepareCopy) (pSrcPixmap, pDstPixmap, - dx, dy, + reverse ? -1 : 1, upsidedown ? -1 : 1, pGC ? pGC->alu : GXcopy, pGC ? pGC->planemask : FB_ALLONES)) { @@ -423,11 +434,13 @@ exaCopyNtoN (DrawablePtr pSrcDrawable, pbox->x1 + dst_off_x, pbox->y1 + dst_off_y, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); + exaPixmapDirty (pDstPixmap, + pbox->x1 + dst_off_x, pbox->y1 + dst_off_y, + pbox->x2 + dst_off_x, pbox->y2 + dst_off_y); pbox++; } (*pExaScr->info->DoneCopy) (pDstPixmap); exaMarkSync(pDstDrawable->pScreen); - exaDrawableDirty (pDstDrawable); return; } @@ -442,6 +455,11 @@ fallback: bitplane, closure); exaFinishAccess (pSrcDrawable, EXA_PREPARE_SRC); exaFinishAccess (pDstDrawable, EXA_PREPARE_DEST); + while (nbox--) + { + exaDrawableDirty (pDstDrawable, pbox->x1, pbox->y1, pbox->x2, pbox->y2); + pbox++; + } } RegionPtr @@ -621,12 +639,12 @@ exaPolyFillRect(DrawablePtr pDrawable, pixmaps[0].as_dst = TRUE; pixmaps[0].as_src = FALSE; - pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable); + pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable); if (pExaScr->swappedOut || pGC->fillStyle != FillSolid || - pDrawable->width > pExaScr->info->maxX || - pDrawable->height > pExaScr->info->maxY) + pPixmap->drawable.width > pExaScr->info->maxX || + pPixmap->drawable.height > pExaScr->info->maxY) { exaDoMigration (pixmaps, 1, FALSE); ExaCheckPolyFillRect (pDrawable, pGC, nrect, prect); @@ -681,6 +699,8 @@ exaPolyFillRect(DrawablePtr pDrawable, (*pExaScr->info->Solid) (pPixmap, fullX1 + xoff, fullY1 + yoff, fullX2 + xoff, fullY2 + yoff); + exaPixmapDirty (pPixmap, fullX1 + xoff, fullY1 + yoff, + fullX2 + xoff, fullY2 + yoff); } else { @@ -706,15 +726,17 @@ exaPolyFillRect(DrawablePtr pDrawable, pbox++; - if (partX1 < partX2 && partY1 < partY2) + if (partX1 < partX2 && partY1 < partY2) { (*pExaScr->info->Solid) (pPixmap, partX1 + xoff, partY1 + yoff, partX2 + xoff, partY2 + yoff); + exaPixmapDirty (pPixmap, partX1 + xoff, partY1 + yoff, + partX2 + xoff, partY2 + yoff); + } } } } (*pExaScr->info->DoneSolid) (pPixmap); - exaDrawableDirty (pDrawable); exaMarkSync(pDrawable->pScreen); } @@ -735,14 +757,15 @@ exaSolidBoxClipped (DrawablePtr pDrawable, int xoff, yoff; int partX1, partX2, partY1, partY2; ExaMigrationRec pixmaps[1]; + Bool fallback = FALSE; pixmaps[0].as_dst = TRUE; pixmaps[0].as_src = FALSE; - pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable); - + pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable); + if (pExaScr->swappedOut || - pDrawable->width > pExaScr->info->maxX || - pDrawable->height > pExaScr->info->maxY) + pPixmap->drawable.width > pExaScr->info->maxX || + pPixmap->drawable.height > pExaScr->info->maxY) { exaDoMigration (pixmaps, 1, FALSE); goto fallback; @@ -750,19 +773,21 @@ exaSolidBoxClipped (DrawablePtr pDrawable, exaDoMigration (pixmaps, 1, TRUE); } - if (!(pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff)) || + pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff); + + if (!pPixmap || !(*pExaScr->info->PrepareSolid) (pPixmap, GXcopy, pm, fg)) { fallback: EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable))); + fallback = TRUE; exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); fg = fbReplicatePixel (fg, pDrawable->bitsPerPixel); fbSolidBoxClipped (pDrawable, pClip, x1, y1, x2, y2, fbAnd (GXcopy, fg, pm), fbXor (GXcopy, fg, pm)); exaFinishAccess (pDrawable, EXA_PREPARE_DEST); - return; } for (nbox = REGION_NUM_RECTS(pClip), pbox = REGION_RECTS(pClip); nbox--; @@ -790,12 +815,20 @@ fallback: if (partY2 <= partY1) continue; - (*pExaScr->info->Solid) (pPixmap, - partX1 + xoff, partY1 + yoff, - partX2 + xoff, partY2 + yoff); + if (!fallback) { + (*pExaScr->info->Solid) (pPixmap, + partX1 + xoff, partY1 + yoff, + partX2 + xoff, partY2 + yoff); + exaPixmapDirty (pPixmap, partX1 + xoff, partY1 + yoff, + partX2 + xoff, partY2 + yoff); + } else + exaDrawableDirty (pDrawable, partX1, partY1, partX2, partY2); } + + if (fallback) + return; + (*pExaScr->info->DoneSolid) (pPixmap); - exaDrawableDirty (pDrawable); exaMarkSync(pDrawable->pScreen); } @@ -908,12 +941,17 @@ exaImageGlyphBlt (DrawablePtr pDrawable, pPriv->fg, gx + dstXoff, gHeight); + exaDrawableDirty (pDrawable, gx, gy, gx + gWidth, gy + gHeight); } else { + RegionPtr pClip = fbGetCompositeClip(pGC); + int nbox; + BoxPtr pbox; + gStride = GLYPHWIDTHBYTESPADDED(pci) / sizeof (FbStip); fbPutXYImage (pDrawable, - fbGetCompositeClip(pGC), + pClip, pPriv->fg, pPriv->bg, pPriv->pm, @@ -927,6 +965,18 @@ exaImageGlyphBlt (DrawablePtr pDrawable, (FbStip *) pglyph, gStride, 0); + + for (nbox = REGION_NUM_RECTS(pClip), pbox = REGION_RECTS(pClip); + nbox--; pbox++) { + int x1 = max(gx, pbox->x1), x2 = min(gx + gWidth, pbox->x2); + int y1 = max(gy, pbox->y1), y2 = min(gy + gHeight, pbox->y2); + + if (x1 >= x2 || y1 >= y2) + continue; + + exaDrawableDirty (pDrawable, gx, gy, gx + gWidth, + gy + gHeight); + } } } x += pci->metrics.characterWidth; @@ -994,13 +1044,15 @@ exaFillRegionSolid (DrawablePtr pDrawable, PixmapPtr pPixmap; int xoff, yoff; ExaMigrationRec pixmaps[1]; + int nbox = REGION_NUM_RECTS (pRegion); + BoxPtr pBox = REGION_RECTS (pRegion); pixmaps[0].as_dst = TRUE; pixmaps[0].as_src = FALSE; - pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable); + pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable); - if (pDrawable->width > pExaScr->info->maxX || - pDrawable->height > pExaScr->info->maxY) + if (pPixmap->drawable.width > pExaScr->info->maxX || + pPixmap->drawable.height > pExaScr->info->maxY) { exaDoMigration (pixmaps, 1, FALSE); goto fallback; @@ -1011,19 +1063,17 @@ exaFillRegionSolid (DrawablePtr pDrawable, if ((pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff)) && (*pExaScr->info->PrepareSolid) (pPixmap, GXcopy, FB_ALLONES, pixel)) { - int nbox = REGION_NUM_RECTS (pRegion); - BoxPtr pBox = REGION_RECTS (pRegion); - while (nbox--) { (*pExaScr->info->Solid) (pPixmap, pBox->x1 + xoff, pBox->y1 + yoff, pBox->x2 + xoff, pBox->y2 + yoff); + exaPixmapDirty (pPixmap, pBox->x1 + xoff, pBox->y1 + yoff, + pBox->x2 + xoff, pBox->y2 + yoff); pBox++; } (*pExaScr->info->DoneSolid) (pPixmap); exaMarkSync(pDrawable->pScreen); - exaDrawableDirty (pDrawable); } else { @@ -1034,6 +1084,11 @@ fallback: fbFillRegionSolid (pDrawable, pRegion, 0, fbReplicatePixel (pixel, pDrawable->bitsPerPixel)); exaFinishAccess (pDrawable, EXA_PREPARE_DEST); + while (nbox--) + { + exaDrawableDirty (pDrawable, pBox->x1, pBox->y1, pBox->x2, pBox->y2); + pBox++; + } } } @@ -1047,9 +1102,11 @@ exaFillRegionTiled (DrawablePtr pDrawable, { ExaScreenPriv(pDrawable->pScreen); PixmapPtr pPixmap; - int xoff, yoff; + int xoff, yoff, tileXoff, tileYoff; int tileWidth, tileHeight; ExaMigrationRec pixmaps[2]; + int nbox = REGION_NUM_RECTS (pRegion); + BoxPtr pBox = REGION_RECTS (pRegion); tileWidth = pTile->drawable.width; tileHeight = pTile->drawable.height; @@ -1064,13 +1121,13 @@ exaFillRegionTiled (DrawablePtr pDrawable, pixmaps[0].as_dst = TRUE; pixmaps[0].as_src = FALSE; - pixmaps[0].pPix = exaGetDrawablePixmap (pDrawable); + pixmaps[0].pPix = pPixmap = exaGetDrawablePixmap (pDrawable); pixmaps[1].as_dst = FALSE; pixmaps[1].as_src = TRUE; pixmaps[1].pPix = pTile; - if (pDrawable->width > pExaScr->info->maxX || - pDrawable->height > pExaScr->info->maxY || + if (pPixmap->drawable.width > pExaScr->info->maxX || + pPixmap->drawable.height > pExaScr->info->maxY || tileWidth > pExaScr->info->maxX || tileHeight > pExaScr->info->maxY) { @@ -1081,18 +1138,16 @@ exaFillRegionTiled (DrawablePtr pDrawable, } pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff); + if (!pPixmap) goto fallback; if (!exaPixmapIsOffscreen(pTile)) goto fallback; - if ((*pExaScr->info->PrepareCopy) (pTile, pPixmap, 0, 0, GXcopy, + if ((*pExaScr->info->PrepareCopy) (exaGetOffscreenPixmap((DrawablePtr)pTile, &tileXoff, &tileYoff), pPixmap, 0, 0, GXcopy, FB_ALLONES)) { - int nbox = REGION_NUM_RECTS (pRegion); - BoxPtr pBox = REGION_RECTS (pRegion); - while (nbox--) { int height = pBox->y2 - pBox->y1; @@ -1118,7 +1173,7 @@ exaFillRegionTiled (DrawablePtr pDrawable, width -= w; (*pExaScr->info->Copy) (pPixmap, - tileX, tileY, + tileX + tileXoff, tileY + tileYoff, dstX + xoff, dstY + yoff, w, h); dstX += w; @@ -1127,11 +1182,12 @@ exaFillRegionTiled (DrawablePtr pDrawable, dstY += h; tileY = 0; } + exaPixmapDirty (pPixmap, pBox->x1 + xoff, pBox->y1 + yoff, + pBox->x2 + xoff, pBox->y2 + yoff); pBox++; } (*pExaScr->info->DoneCopy) (pPixmap); exaMarkSync(pDrawable->pScreen); - exaDrawableDirty (pDrawable); return; } @@ -1144,6 +1200,11 @@ fallback: fbFillRegionTiled (pDrawable, pRegion, pTile); exaFinishAccess ((DrawablePtr)pTile, EXA_PREPARE_SRC); exaFinishAccess (pDrawable, EXA_PREPARE_DEST); + while (nbox--) + { + exaDrawableDirty (pDrawable, pBox->x1, pBox->y1, pBox->x2, pBox->y2); + pBox++; + } } void diff --git a/exa/exa_migration.c b/exa/exa_migration.c index 06a4b9330..eedc5fd03 100644 --- a/exa/exa_migration.c +++ b/exa/exa_migration.c @@ -22,6 +22,7 @@ * * Authors: * Eric Anholt + * Michel Dänzer * */ @@ -57,6 +58,27 @@ exaPixmapIsPinned (PixmapPtr pPix) return pExaPixmap == NULL || pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED; } +/** + * The fallback path for UTS/DFS failing is to just memcpy. exaCopyDirtyToSys + * and exaCopyDirtyToFb both needed to do this loop. + */ +static void +exaMemcpyBox (PixmapPtr pPixmap, BoxPtr pbox, CARD8 *src, int src_pitch, + CARD8 *dst, int dst_pitch) + { + int i, cpp = pPixmap->drawable.bitsPerPixel / 8; + int bytes = (pbox->x2 - pbox->x1) * cpp; + + src += pbox->y1 * src_pitch + pbox->x1 * cpp; + dst += pbox->y1 * dst_pitch + pbox->x1 * cpp; + + for (i = pbox->y2 - pbox->y1; i; i--) { + memcpy (dst, src, bytes); + src += src_pitch; + dst += dst_pitch; + } +} + /** * Returns TRUE if the pixmap is dirty (has been modified in its current * location compared to the other), or lacks a private for tracking @@ -67,7 +89,8 @@ exaPixmapIsDirty (PixmapPtr pPix) { ExaPixmapPriv (pPix); - return pExaPixmap == NULL || pExaPixmap->dirty == TRUE; + return pExaPixmap == NULL || + REGION_NOTEMPTY (pScreen, DamageRegion(pExaPixmap->pDamage)); } /** @@ -98,54 +121,62 @@ exaCopyDirtyToSys (PixmapPtr pPixmap) { ExaScreenPriv (pPixmap->drawable.pScreen); ExaPixmapPriv (pPixmap); + RegionPtr pRegion = DamageRegion (pExaPixmap->pDamage); CARD8 *save_ptr; int save_pitch; - - if (!pExaPixmap->dirty) - return; + BoxPtr pBox = REGION_RECTS(pRegion); + int nbox = REGION_NUM_RECTS(pRegion); + Bool do_sync = FALSE; save_ptr = pPixmap->devPrivate.ptr; save_pitch = pPixmap->devKind; pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr; pPixmap->devKind = pExaPixmap->fb_pitch; - if (pExaScr->info->DownloadFromScreen == NULL || - !pExaScr->info->DownloadFromScreen (pPixmap, - 0, - 0, - pPixmap->drawable.width, - pPixmap->drawable.height, - pExaPixmap->sys_ptr, - pExaPixmap->sys_pitch)) - { - char *src, *dst; - int src_pitch, dst_pitch, i, bytes; + while (nbox--) { + pBox->x1 = max(pBox->x1, 0); + pBox->y1 = max(pBox->y1, 0); + pBox->x2 = min(pBox->x2, pPixmap->drawable.width); + pBox->y2 = min(pBox->y2, pPixmap->drawable.height); - exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_SRC); + if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2) + continue; - dst = pExaPixmap->sys_ptr; - dst_pitch = pExaPixmap->sys_pitch; - src = pExaPixmap->fb_ptr; - src_pitch = pExaPixmap->fb_pitch; - bytes = src_pitch < dst_pitch ? src_pitch : dst_pitch; - - for (i = 0; i < pPixmap->drawable.height; i++) { - memcpy (dst, src, bytes); - dst += dst_pitch; - src += src_pitch; + if (pExaScr->info->DownloadFromScreen == NULL || + !pExaScr->info->DownloadFromScreen (pPixmap, + pBox->x1, pBox->y1, + pBox->x2 - pBox->x1, + pBox->y2 - pBox->y1, + pExaPixmap->sys_ptr + + pBox->y1 * pExaPixmap->sys_pitch + + pBox->x1 * pPixmap->drawable.bitsPerPixel / 8, + pExaPixmap->sys_pitch)) + { + exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_SRC); + exaMemcpyBox (pPixmap, pBox, + pExaPixmap->fb_ptr, pExaPixmap->fb_pitch, + pExaPixmap->sys_ptr, pExaPixmap->sys_pitch); + exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_SRC); } - exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_SRC); + else + do_sync = TRUE; + + pBox++; } /* Make sure the bits have actually landed, since we don't necessarily sync * when accessing pixmaps in system memory. */ - exaWaitSync (pPixmap->drawable.pScreen); + if (do_sync) + exaWaitSync (pPixmap->drawable.pScreen); pPixmap->devPrivate.ptr = save_ptr; pPixmap->devKind = save_pitch; - pExaPixmap->dirty = FALSE; + /* The previously damaged bits are now no longer damaged but valid */ + REGION_UNION(pPixmap->drawable.pScreen, + &pExaPixmap->validReg, &pExaPixmap->validReg, pRegion); + DamageEmpty (pExaPixmap->pDamage); } /** @@ -158,49 +189,59 @@ exaCopyDirtyToFb (PixmapPtr pPixmap) { ExaScreenPriv (pPixmap->drawable.pScreen); ExaPixmapPriv (pPixmap); + RegionPtr pRegion = DamageRegion (pExaPixmap->pDamage); CARD8 *save_ptr; int save_pitch; - - if (!pExaPixmap->dirty) - return; + BoxPtr pBox = REGION_RECTS(pRegion); + int nbox = REGION_NUM_RECTS(pRegion); + Bool do_sync = FALSE; save_ptr = pPixmap->devPrivate.ptr; save_pitch = pPixmap->devKind; pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr; pPixmap->devKind = pExaPixmap->fb_pitch; - if (pExaScr->info->UploadToScreen == NULL || - !pExaScr->info->UploadToScreen (pPixmap, - 0, - 0, - pPixmap->drawable.width, - pPixmap->drawable.height, - pExaPixmap->sys_ptr, - pExaPixmap->sys_pitch)) - { - char *src, *dst; - int src_pitch, dst_pitch, i, bytes; + while (nbox--) { + pBox->x1 = max(pBox->x1, 0); + pBox->y1 = max(pBox->y1, 0); + pBox->x2 = min(pBox->x2, pPixmap->drawable.width); + pBox->y2 = min(pBox->y2, pPixmap->drawable.height); - exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_DEST); + if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2) + continue; - dst = pExaPixmap->fb_ptr; - dst_pitch = pExaPixmap->fb_pitch; - src = pExaPixmap->sys_ptr; - src_pitch = pExaPixmap->sys_pitch; - bytes = src_pitch < dst_pitch ? src_pitch : dst_pitch; - - for (i = 0; i < pPixmap->drawable.height; i++) { - memcpy (dst, src, bytes); - dst += dst_pitch; - src += src_pitch; + if (pExaScr->info->UploadToScreen == NULL || + !pExaScr->info->UploadToScreen (pPixmap, + pBox->x1, pBox->y1, + pBox->x2 - pBox->x1, + pBox->y2 - pBox->y1, + pExaPixmap->sys_ptr + + pBox->y1 * pExaPixmap->sys_pitch + + pBox->x1 * pPixmap->drawable.bitsPerPixel / 8, + pExaPixmap->sys_pitch)) + { + exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_DEST); + exaMemcpyBox (pPixmap, pBox, + pExaPixmap->sys_ptr, pExaPixmap->sys_pitch, + pExaPixmap->fb_ptr, pExaPixmap->fb_pitch); + exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_DEST); } - exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_DEST); + else + do_sync = TRUE; + + pBox++; } + if (do_sync) + exaMarkSync (pPixmap->drawable.pScreen); + pPixmap->devPrivate.ptr = save_ptr; pPixmap->devKind = save_pitch; - pExaPixmap->dirty = FALSE; + /* The previously damaged bits are now no longer damaged but valid */ + REGION_UNION(pPixmap->drawable.pScreen, + &pExaPixmap->validReg, &pExaPixmap->validReg, pRegion); + DamageEmpty (pExaPixmap->pDamage); } /** @@ -208,11 +249,12 @@ exaCopyDirtyToFb (PixmapPtr pPixmap) * Called when the memory manager decides it's time to kick the pixmap out of * framebuffer entirely. */ -static void +void exaPixmapSave (ScreenPtr pScreen, ExaOffscreenArea *area) { PixmapPtr pPixmap = area->privData; ExaPixmapPriv(pPixmap); + RegionPtr pDamageReg = DamageRegion(pExaPixmap->pDamage); DBG_MIGRATE (("Save %p (%p) (%dx%d) (%c)\n", pPixmap, (void*)(ExaGetPixmapPriv(pPixmap)->area ? @@ -231,10 +273,9 @@ exaPixmapSave (ScreenPtr pScreen, ExaOffscreenArea *area) pExaPixmap->fb_ptr = NULL; pExaPixmap->area = NULL; - /* Mark it dirty now, to say that there is important data in the - * system-memory copy. - */ - pExaPixmap->dirty = TRUE; + /* Mark all valid bits as damaged, so they'll get copied to FB next time */ + REGION_UNION(pPixmap->drawable.pScreen, pDamageReg, pDamageReg, + &pExaPixmap->validReg); } /** @@ -413,32 +454,57 @@ exaMigrateTowardSys (PixmapPtr pPixmap) * If the pixmap has both a framebuffer and system memory copy, this function * asserts that both of them are the same. */ -static void +static Bool exaAssertNotDirty (PixmapPtr pPixmap) { ExaPixmapPriv (pPixmap); CARD8 *dst, *src; - int dst_pitch, src_pitch, data_row_bytes, y; + RegionPtr pValidReg = &pExaPixmap->validReg; + int dst_pitch, src_pitch, cpp, y, nbox = REGION_NUM_RECTS(pValidReg); + BoxPtr pBox = REGION_RECTS(pValidReg); + Bool ret = TRUE; if (pExaPixmap == NULL || pExaPixmap->fb_ptr == NULL) - return; + return ret; dst = pExaPixmap->sys_ptr; dst_pitch = pExaPixmap->sys_pitch; src = pExaPixmap->fb_ptr; src_pitch = pExaPixmap->fb_pitch; - data_row_bytes = pPixmap->drawable.width * - pPixmap->drawable.bitsPerPixel / 8; + cpp = pPixmap->drawable.bitsPerPixel / 8; exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_SRC); - for (y = 0; y < pPixmap->drawable.height; y++) { - if (memcmp(dst, src, data_row_bytes) != 0) { - abort(); - } - dst += dst_pitch; - src += src_pitch; + while (nbox--) { + int rowbytes; + + pBox->x1 = max(pBox->x1, 0); + pBox->y1 = max(pBox->y1, 0); + pBox->x2 = min(pBox->x2, pPixmap->drawable.width); + pBox->y2 = min(pBox->y2, pPixmap->drawable.height); + + if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2) + continue; + + rowbytes = (pBox->x2 - pBox->x1) * cpp; + src += pBox->y1 * src_pitch + pBox->x1 * cpp; + dst += pBox->y1 * dst_pitch + pBox->x1 * cpp; + + for (y = pBox->y2 - pBox->y1; y; y--) { + if (memcmp(dst + pBox->y1 * dst_pitch + pBox->x1 * cpp, + src + pBox->y1 * src_pitch + pBox->x1 * cpp, + (pBox->x2 - pBox->x1) * cpp) != 0) { + ret = FALSE; + break; + } + src += src_pitch; + dst += dst_pitch; + } + src -= pBox->y1 * src_pitch + pBox->x1 * cpp; + dst -= pBox->y1 * dst_pitch + pBox->x1 * cpp; } exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_SRC); + + return ret; } /** @@ -462,8 +528,9 @@ exaDoMigration (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel) */ if (pExaScr->checkDirtyCorrectness) { for (i = 0; i < npixmaps; i++) { - if (!exaPixmapIsDirty (pixmaps[i].pPix)) - exaAssertNotDirty (pixmaps[i].pPix); + if (!exaPixmapIsDirty (pixmaps[i].pPix) && + !exaAssertNotDirty (pixmaps[i].pPix)) + ErrorF("%s: Pixmap %d dirty but not marked as such!\n", __func__, i); } } /* If anything is pinned in system memory, we won't be able to diff --git a/exa/exa_offscreen.c b/exa/exa_offscreen.c index 9e0aa5d25..7708dd739 100644 --- a/exa/exa_offscreen.c +++ b/exa/exa_offscreen.c @@ -81,15 +81,14 @@ ExaOffscreenKickOut (ScreenPtr pScreen, ExaOffscreenArea *area) * @param save callback for when the area is evicted from memory * @param privdata private data for the save callback. * - * Allocates offscreen memory from the device associated with pScreen. size and - * align deteremine where and how large the allocated area is, and locked will - * mark whether it should be held in card memory. privdata may be any pointer - * for the save callback when the area is removed. + * Allocates offscreen memory from the device associated with pScreen. size + * and align deteremine where and how large the allocated area is, and locked + * will mark whether it should be held in card memory. privdata may be any + * pointer for the save callback when the area is removed. * - * Note that locked areas do get evicted on VT switch, because during that time - * all offscreen memory becomes inaccessible. This may change in the future, - * but drivers should be aware of this and provide a callback to mark that their - * locked allocation was evicted, and then restore it if necessary on EnterVT. + * Note that locked areas do get evicted on VT switch unless the driver + * requested version 2.1 or newer behavior. In that case, the save callback is + * still called. */ ExaOffscreenArea * exaOffscreenAlloc (ScreenPtr pScreen, int size, int align, @@ -256,6 +255,9 @@ exaOffscreenAlloc (ScreenPtr pScreen, int size, int align, return area; } +/** + * Ejects all offscreen areas, and uninitializes the offscreen memory manager. + */ void ExaOffscreenSwapOut (ScreenPtr pScreen) { @@ -283,12 +285,56 @@ ExaOffscreenSwapOut (ScreenPtr pScreen) ExaOffscreenFini (pScreen); } +/** Ejects all pixmaps managed by EXA. */ +static void +ExaOffscreenEjectPixmaps (ScreenPtr pScreen) +{ + ExaScreenPriv (pScreen); + + ExaOffscreenValidate (pScreen); + /* loop until a single free area spans the space */ + for (;;) + { + ExaOffscreenArea *area; + + for (area = pExaScr->info->offScreenAreas; area != NULL; + area = area->next) + { + if (area->state == ExaOffscreenRemovable && + area->save == exaPixmapSave) + { + (void) ExaOffscreenKickOut (pScreen, area); + ExaOffscreenValidate (pScreen); + break; + } + } + if (area == NULL) + break; + } + ExaOffscreenValidate (pScreen); +} + void ExaOffscreenSwapIn (ScreenPtr pScreen) { exaOffscreenInit (pScreen); } +/** + * Prepares EXA for disabling of FB access, or restoring it. + * + * In version 2.1, the disabling results in pixmaps being ejected, while other + * allocations remain. With this plus the prevention of migration while + * swappedOut is set, EXA by itself should not cause any access of the + * framebuffer to occur while swapped out. Any remaining issues are the + * responsibility of the driver. + * + * Prior to version 2.1, all allocations, including locked ones, are ejected + * when access is disabled, and the allocator is torn down while swappedOut + * is set. This is more drastic, and caused implementation difficulties for + * many drivers that could otherwise handle the lack of FB access while + * swapped out. + */ void exaEnableDisableFBAccess (int index, Bool enable) { @@ -296,10 +342,14 @@ exaEnableDisableFBAccess (int index, Bool enable) ExaScreenPriv (pScreen); if (!enable) { - ExaOffscreenSwapOut (pScreen); + if (pExaScr->info->exa_minor < 1) + ExaOffscreenSwapOut (pScreen); + else + ExaOffscreenEjectPixmaps (pScreen); pExaScr->swappedOut = TRUE; } else { - ExaOffscreenSwapIn (pScreen); + if (pExaScr->info->exa_minor < 1) + ExaOffscreenSwapIn (pScreen); pExaScr->swappedOut = FALSE; } } @@ -390,6 +440,7 @@ ExaOffscreenMarkUsed (PixmapPtr pPixmap) if (area->state == ExaOffscreenRemovable) area->score = (area->score * 7) / 8; } + iter = 0; } } diff --git a/exa/exa_priv.h b/exa/exa_priv.h index 03ee0eddb..984cb669b 100644 --- a/exa/exa_priv.h +++ b/exa/exa_priv.h @@ -51,6 +51,7 @@ #ifdef RENDER #include "fbpict.h" #endif +#include "damage.h" #define DEBUG_TRACE_FALL 0 #define DEBUG_MIGRATE 0 @@ -160,16 +161,16 @@ typedef struct { unsigned int fb_size; /**< size of pixmap in framebuffer memory */ /** - * If area is NULL, then dirty == TRUE means that the pixmap has been - * modified, so the contents are defined. Used to avoid uploads of - * undefined data. - * - * If area is non-NULL, then dirty == TRUE means that the pixmap data at - * pPixmap->devPrivate.ptr (either fb_ptr or sys_ptr) has been changed - * compared to the copy in the other location. This is used to avoid - * uploads/downloads of unmodified data. + * The damage record contains the areas of the pixmap's current location + * (framebuffer or system) that have been damaged compared to the other + * location. */ - Bool dirty; + DamagePtr pDamage; + /** + * The valid region marks the valid bits of a drawable (at least, as it's + * derived from damage, which may be overreported). + */ + RegionRec validReg; } ExaPixmapPrivRec, *ExaPixmapPrivPtr; typedef struct _ExaMigrationRec { @@ -315,7 +316,7 @@ ExaCheckComposite (CARD8 op, CARD16 height); #endif -/* exaoffscreen.c */ +/* exa_offscreen.c */ void ExaOffscreenMarkUsed (PixmapPtr pPixmap); @@ -339,7 +340,10 @@ void exaFinishAccess(DrawablePtr pDrawable, int index); void -exaDrawableDirty(DrawablePtr pDrawable); +exaPixmapDirty(PixmapPtr pPix, int x1, int y1, int x2, int y2); + +void +exaDrawableDirty(DrawablePtr pDrawable, int x1, int y1, int x2, int y2); Bool exaDrawableIsOffscreen (DrawablePtr pDrawable); @@ -409,9 +413,6 @@ void exaDoMigration (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel); void -exaMoveInPixmap (PixmapPtr pPixmap); - -void -exaMoveOutPixmap (PixmapPtr pPixmap); +exaPixmapSave (ScreenPtr pScreen, ExaOffscreenArea *area); #endif /* EXAPRIV_H */ diff --git a/exa/exa_render.c b/exa/exa_render.c index 9affb9f11..75108a75c 100644 --- a/exa/exa_render.c +++ b/exa/exa_render.c @@ -302,12 +302,12 @@ exaTryDriverSolidFill(PicturePtr pSrc, (*pExaScr->info->Solid) (pDstPix, pbox->x1 + dst_off_x, pbox->y1 + dst_off_y, pbox->x2 + dst_off_x, pbox->y2 + dst_off_y); + exaPixmapDirty (pDstPix, pbox->x1 + dst_off_x, pbox->y1 + dst_off_y, + pbox->x2 + dst_off_x, pbox->y2 + dst_off_y); pbox++; } - (*pExaScr->info->DoneSolid) (pDstPix); exaMarkSync(pDst->pDrawable->pScreen); - exaDrawableDirty (pDst->pDrawable); REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); return 1; @@ -336,16 +336,21 @@ exaTryDriverComposite(CARD8 op, struct _Pixmap scratch; ExaMigrationRec pixmaps[3]; + pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable); + pDstPix = exaGetDrawablePixmap(pDst->pDrawable); + if (pMask) + pMaskPix = exaGetDrawablePixmap(pMask->pDrawable); + /* Bail if we might exceed coord limits by rendering from/to these. We * should really be making some scratch pixmaps with offsets and coords * adjusted to deal with this, but it hasn't been done yet. */ - if (pSrc->pDrawable->width > pExaScr->info->maxX || - pSrc->pDrawable->height > pExaScr->info->maxY || - pDst->pDrawable->width > pExaScr->info->maxX || - pDst->pDrawable->height > pExaScr->info->maxY || - (pMask && (pMask->pDrawable->width > pExaScr->info->maxX || - pMask->pDrawable->height > pExaScr->info->maxY))) + if (pSrcPix->drawable.width > pExaScr->info->maxX || + pSrcPix->drawable.height > pExaScr->info->maxY || + pDstPix->drawable.width > pExaScr->info->maxX || + pDstPix->drawable.height > pExaScr->info->maxY || + (pMask && (pMaskPix->drawable.width > pExaScr->info->maxX || + pMaskPix->drawable.height > pExaScr->info->maxY))) { return -1; } @@ -441,12 +446,12 @@ exaTryDriverComposite(CARD8 op, pbox->y1 + dst_off_y, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); + exaPixmapDirty (pDstPix, pbox->x1 + dst_off_x, pbox->y1 + dst_off_y, + pbox->x2 + dst_off_x, pbox->y2 + dst_off_y); pbox++; } - (*pExaScr->info->DoneComposite) (pDstPix); exaMarkSync(pDst->pDrawable->pScreen); - exaDrawableDirty (pDst->pDrawable); REGION_UNINIT(pDst->pDrawable->pScreen, ®ion); return 1; @@ -705,16 +710,19 @@ void exaRasterizeTrapezoid (PicturePtr pPicture, xTrapezoid *trap, int x_off, int y_off) { + DrawablePtr pDraw = pPicture->pDrawable; ExaMigrationRec pixmaps[1]; pixmaps[0].as_dst = TRUE; pixmaps[0].as_src = TRUE; - pixmaps[0].pPix = exaGetDrawablePixmap (pPicture->pDrawable); + pixmaps[0].pPix = exaGetDrawablePixmap (pDraw); exaDoMigration(pixmaps, 1, FALSE); - exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST); + exaPrepareAccess(pDraw, EXA_PREPARE_DEST); fbRasterizeTrapezoid(pPicture, trap, x_off, y_off); - exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST); + exaDrawableDirty(pDraw, pDraw->x, pDraw->y, + pDraw->x + pDraw->width, pDraw->y + pDraw->height); + exaFinishAccess(pDraw, EXA_PREPARE_DEST); } /** @@ -725,16 +733,19 @@ void exaAddTriangles (PicturePtr pPicture, INT16 x_off, INT16 y_off, int ntri, xTriangle *tris) { + DrawablePtr pDraw = pPicture->pDrawable; ExaMigrationRec pixmaps[1]; pixmaps[0].as_dst = TRUE; pixmaps[0].as_src = TRUE; - pixmaps[0].pPix = exaGetDrawablePixmap (pPicture->pDrawable); + pixmaps[0].pPix = exaGetDrawablePixmap (pDraw); exaDoMigration(pixmaps, 1, FALSE); - exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST); + exaPrepareAccess(pDraw, EXA_PREPARE_DEST); fbAddTriangles(pPicture, x_off, y_off, ntri, tris); - exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST); + exaDrawableDirty(pDraw, pDraw->x, pDraw->y, + pDraw->x + pDraw->width, pDraw->y + pDraw->height); + exaFinishAccess(pDraw, EXA_PREPARE_DEST); } /** @@ -1023,10 +1034,11 @@ exaGlyphs (CARD8 op, exaCopyArea (&pScratchPixmap->drawable, &pPixmap->drawable, pGC, 0, 0, glyph->info.width, glyph->info.height, 0, 0); - } else { - exaDrawableDirty (&pPixmap->drawable); } + exaPixmapDirty (pPixmap, 0, 0, + glyph->info.width, glyph->info.height); + if (maskFormat) { exaComposite (PictOpAdd, pPicture, NULL, pMask, 0, 0, 0, 0, diff --git a/exa/exa_unaccel.c b/exa/exa_unaccel.c index f9df6adc4..7713a08c9 100644 --- a/exa/exa_unaccel.c +++ b/exa/exa_unaccel.c @@ -200,11 +200,33 @@ ExaCheckPolyFillRect (DrawablePtr pDrawable, GCPtr pGC, int nrect, xRectangle *prect) { EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable))); - exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); - exaPrepareAccessGC (pGC); - fbPolyFillRect (pDrawable, pGC, nrect, prect); - exaFinishAccessGC (pGC); - exaFinishAccess (pDrawable, EXA_PREPARE_DEST); + + if (nrect) { + int x1 = max(prect->x, 0), y1 = max(prect->y, 0); + int x2 = min(prect->x + prect->width, pDrawable->width); + int y2 = min(prect->y + prect->height, pDrawable->height); + + exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); + exaPrepareAccessGC (pGC); + fbPolyFillRect (pDrawable, pGC, nrect, prect); + exaFinishAccessGC (pGC); + exaFinishAccess (pDrawable, EXA_PREPARE_DEST); + + /* Only track bounding box of damage, as this path can degenerate to + * zillions of damage boxes + */ + while (--nrect) + { + prect++; + x1 = min(x1, prect->x); + x2 = max(x2, prect->x + prect->width); + y1 = min(y1, prect->y); + y2 = max(y2, prect->y + prect->height); + } + + exaDrawableDirty (pDrawable, pDrawable->x + x1, pDrawable->y + y1, + pDrawable->x + x2, pDrawable->y + y2); + } } void diff --git a/hw/xfree86/exa/Makefile.am b/hw/xfree86/exa/Makefile.am index 31682c425..9eb2e1797 100644 --- a/hw/xfree86/exa/Makefile.am +++ b/hw/xfree86/exa/Makefile.am @@ -7,7 +7,7 @@ INCLUDES = \ -I$(srcdir)/../../../exa \ -I$(srcdir)/../../../miext/cw -AM_CFLAGS = $(XORG_CFLAGS) +AM_CFLAGS = $(DIX_CFLAGS) $(XORG_CFLAGS) libexa_la_SOURCES = \ examodule.c diff --git a/hw/xfree86/exa/exa.man.pre b/hw/xfree86/exa/exa.man.pre index ea41b90e4..b0eecd5cc 100644 --- a/hw/xfree86/exa/exa.man.pre +++ b/hw/xfree86/exa/exa.man.pre @@ -35,6 +35,6 @@ Default: No. Chooses an alternate pixmap migration heuristic, for debugging purposes. The default is intended to be the best performing one for general use, though others may help with specific use cases. Available options include \*qalways\*q, -\*qgreedy\*q, and \*qsmart\*q. Default: smart. +\*qgreedy\*q, and \*qsmart\*q. Default: always. .SH AUTHORS Authors include: Keith Packard, Eric Anholt, Zack Rusin, and Michel Dänzer