diff options
author | Michel Dänzer <daenzer@vmware.com> | 2009-09-26 01:59:39 +0200 |
---|---|---|
committer | Michel Dänzer <daenzer@vmware.com> | 2009-09-26 01:59:39 +0200 |
commit | 1818cbd70fc1f2e1487b4c678e67e28f1265c0ef (patch) | |
tree | c19cc48b73ed6885079f48a321aa775068fae57e | |
parent | e23bffc41b007f1bc2b8f5cd4ac54213062c95cc (diff) |
EXA: Extend mixed pixmaps scheme to allow driver PrepareAccess hook to fail.
If the PrepareAccess hook fails, use the DownloadFromScreen hook to retrieve
driver pixmap contents to a system RAM copy, perform software rendering on that
and copy the results back using the UploadToScreen hook. Use the classic
migration logic to minimize transfers (which as a bonus allows slightly
cleaning up some of the existing mixed pixmap code).
This enables things that weren't possible before with driver-allocated pixmap
storage: If some (or all) GPU pixmap storage can't be mapped directly by the
CPU, this can be handled between the PrepareAccess and
DownloadFrom/UploadToScreen hooks, e.g.:
* Radeon KMS on big endian machines can fail PrepareAccess if the pixmap
requires byte-swapping and swap bytes in DownloadFrom/UploadToScreen.
* Environments where GPU and CPU don't have a shared address space at all.
Here the driver PrepareAccess hook will always fail and leave all transfers
between GPU / CPU storage to the Download/From/UploadToScreen hooks.
Drivers which can handle all pixmaps in the PrepareAccess hook should notice
little if any difference.
-rw-r--r-- | exa/exa.c | 78 | ||||
-rw-r--r-- | exa/exa_migration_classic.c | 30 | ||||
-rw-r--r-- | exa/exa_migration_mixed.c | 179 | ||||
-rw-r--r-- | exa/exa_mixed.c | 87 | ||||
-rw-r--r-- | exa/exa_priv.h | 22 | ||||
-rw-r--r-- | exa/exa_unaccel.c | 52 |
6 files changed, 232 insertions, 216 deletions
@@ -286,11 +286,10 @@ exaGetOffscreenPixmap (DrawablePtr pDrawable, int *xp, int *yp) * Returns TRUE if pixmap can be accessed offscreen. */ Bool -ExaDoPrepareAccess(DrawablePtr pDrawable, int index) +ExaDoPrepareAccess(PixmapPtr pPixmap, int index) { - ScreenPtr pScreen = pDrawable->pScreen; + ScreenPtr pScreen = pPixmap->drawable.pScreen; ExaScreenPriv (pScreen); - PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable); ExaPixmapPriv(pPixmap); Bool offscreen; int i; @@ -324,7 +323,7 @@ ExaDoPrepareAccess(DrawablePtr pDrawable, int index) offscreen = exaPixmapIsOffscreen(pPixmap); - if (offscreen) + if (offscreen && pExaPixmap->fb_ptr) pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr; else pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr; @@ -333,20 +332,10 @@ ExaDoPrepareAccess(DrawablePtr pDrawable, int index) pExaScr->access[index].pixmap = pPixmap; pExaScr->access[index].count = 1; - if (!offscreen) { - /* Do we need to allocate our system buffer? */ - if ((pExaScr->info->flags & EXA_HANDLES_PIXMAPS) && (pExaScr->info->flags & EXA_MIXED_PIXMAPS)) { - if (!pExaPixmap->sys_ptr && !exaPixmapIsPinned(pPixmap)) { - pExaPixmap->sys_ptr = malloc(pExaPixmap->sys_pitch * pDrawable->height); - if (!pExaPixmap->sys_ptr) - FatalError("EXA: malloc failed for size %d bytes\n", pExaPixmap->sys_pitch * pDrawable->height); - pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr; - } - } + if (!offscreen) return FALSE; - } - exaWaitSync (pDrawable->pScreen); + exaWaitSync (pScreen); if (pExaScr->info->PrepareAccess == NULL) return TRUE; @@ -360,7 +349,8 @@ ExaDoPrepareAccess(DrawablePtr pDrawable, int index) } if (!(*pExaScr->info->PrepareAccess) (pPixmap, index)) { - if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED) + if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED && + !(pExaScr->info->flags & EXA_MIXED_PIXMAPS)) FatalError("Driver failed PrepareAccess on a pinned pixmap.\n"); exaMoveOutPixmap (pPixmap); @@ -370,31 +360,6 @@ ExaDoPrepareAccess(DrawablePtr pDrawable, int index) return TRUE; } -void -exaPrepareAccessReg(DrawablePtr pDrawable, int index, RegionPtr pReg) -{ - PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable); - ExaScreenPriv(pPixmap->drawable.pScreen); - - if (pExaScr->do_migration) { - ExaMigrationRec pixmaps[1]; - - if (index == EXA_PREPARE_DEST || index == EXA_PREPARE_AUX_DEST) { - pixmaps[0].as_dst = TRUE; - pixmaps[0].as_src = FALSE; - } else { - pixmaps[0].as_dst = FALSE; - pixmaps[0].as_src = TRUE; - } - pixmaps[0].pPix = pPixmap; - pixmaps[0].pReg = pReg; - - exaDoMigration(pixmaps, 1, FALSE); - } - - ExaDoPrepareAccess(pDrawable, index); -} - /** * exaPrepareAccess() is EXA's wrapper for the driver's PrepareAccess() handler. * @@ -404,7 +369,13 @@ exaPrepareAccessReg(DrawablePtr pDrawable, int index, RegionPtr pReg) void exaPrepareAccess(DrawablePtr pDrawable, int index) { - exaPrepareAccessReg(pDrawable, index, NULL); + PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable); + ExaScreenPriv(pDrawable->pScreen); + + if (pExaScr->prepare_access_reg) + pExaScr->prepare_access_reg(pPixmap, index, NULL); + else + (void)ExaDoPrepareAccess(pPixmap, index); } /** @@ -432,7 +403,6 @@ exaFinishAccess(DrawablePtr pDrawable, int index) if (pExaScr->access[i].pixmap == pPixmap) { if (--pExaScr->access[i].count > 0) return; - index = i; break; } } @@ -442,25 +412,25 @@ exaFinishAccess(DrawablePtr pDrawable, int index) EXA_FatalErrorDebug(("EXA bug: FinishAccess called without PrepareAccess for pixmap 0x%p.\n", pPixmap)); - pExaScr->access[index].pixmap = NULL; + pExaScr->access[i].pixmap = NULL; /* We always hide the devPrivate.ptr. */ pPixmap->devPrivate.ptr = NULL; - if (pExaScr->info->FinishAccess == NULL) - return; + if (pExaScr->finish_access) + pExaScr->finish_access(pPixmap, index); - if (!exaPixmapIsOffscreen (pPixmap)) + if (!pExaScr->info->FinishAccess || !exaPixmapIsOffscreen(pPixmap)) return; - if (index >= EXA_PREPARE_AUX_DEST && + if (i >= EXA_PREPARE_AUX_DEST && !(pExaScr->info->flags & EXA_SUPPORTS_PREPARE_AUX)) { ErrorF("EXA bug: Trying to call driver FinishAccess hook with " "unsupported index EXA_PREPARE_AUX*\n"); return; } - (*pExaScr->info->FinishAccess) (pPixmap, index); + (*pExaScr->info->FinishAccess) (pPixmap, i); } /** @@ -537,7 +507,7 @@ exaCreatePixmapWithPrepare(ScreenPtr pScreen, int w, int h, int depth, * For EXA_HANDLES_PIXMAPS the driver will handle whatever is needed. * We want to signal that the pixmaps will be used as destination. */ - ExaDoPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST); + ExaDoPrepareAccess(pPixmap, EXA_PREPARE_AUX_DEST); return pPixmap; } @@ -1071,6 +1041,8 @@ exaDriverInit (ScreenPtr pScreen, pExaScr->pixmap_is_offscreen = exaPixmapIsOffscreen_mixed; pExaScr->do_move_in_pixmap = exaMoveInPixmap_mixed; pExaScr->do_move_out_pixmap = NULL; + pExaScr->prepare_access_reg = exaPrepareAccessReg_mixed; + pExaScr->finish_access = exaFinishAccess_mixed; } else { wrap(pExaScr, pScreen, CreatePixmap, exaCreatePixmap_driver); wrap(pExaScr, pScreen, DestroyPixmap, exaDestroyPixmap_driver); @@ -1079,6 +1051,8 @@ exaDriverInit (ScreenPtr pScreen, pExaScr->pixmap_is_offscreen = exaPixmapIsOffscreen_driver; pExaScr->do_move_in_pixmap = NULL; pExaScr->do_move_out_pixmap = NULL; + pExaScr->prepare_access_reg = NULL; + pExaScr->finish_access = NULL; } } else { wrap(pExaScr, pScreen, CreatePixmap, exaCreatePixmap_classic); @@ -1088,6 +1062,8 @@ exaDriverInit (ScreenPtr pScreen, pExaScr->pixmap_is_offscreen = exaPixmapIsOffscreen_classic; pExaScr->do_move_in_pixmap = exaMoveInPixmap_classic; pExaScr->do_move_out_pixmap = exaMoveOutPixmap_classic; + pExaScr->prepare_access_reg = exaPrepareAccessReg_classic; + pExaScr->finish_access = NULL; } if (!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS)) { LogMessage(X_INFO, "EXA(%d): Offscreen pixmap area of %lu bytes\n", diff --git a/exa/exa_migration_classic.c b/exa/exa_migration_classic.c index d8e1e86da..0032f02f9 100644 --- a/exa/exa_migration_classic.c +++ b/exa/exa_migration_classic.c @@ -120,7 +120,7 @@ exaCopyDirty(ExaMigrationPtr migrate, RegionPtr pValidDst, RegionPtr pValidSrc, Bool need_sync = FALSE; /* Damaged bits are valid in current copy but invalid in other one */ - if (exaPixmapIsOffscreen(pPixmap)) { + if (pExaPixmap->offscreen) { REGION_UNION(pScreen, &pExaPixmap->validFB, &pExaPixmap->validFB, damage); REGION_SUBTRACT(pScreen, &pExaPixmap->validSys, &pExaPixmap->validSys, @@ -225,7 +225,7 @@ exaCopyDirty(ExaMigrationPtr migrate, RegionPtr pValidDst, RegionPtr pValidSrc, pExaPixmap->sys_pitch)) { if (!access_prepared) { - ExaDoPrepareAccess(&pPixmap->drawable, fallback_index); + ExaDoPrepareAccess(pPixmap, fallback_index); access_prepared = TRUE; } exaMemcpyBox (pPixmap, pBox, @@ -263,7 +263,7 @@ exaCopyDirty(ExaMigrationPtr migrate, RegionPtr pValidDst, RegionPtr pValidSrc, * the framebuffer memory copy to the system memory copy. Both areas must be * allocated. */ -static void +void exaCopyDirtyToSys (ExaMigrationPtr migrate) { PixmapPtr pPixmap = migrate->pPix; @@ -281,7 +281,7 @@ exaCopyDirtyToSys (ExaMigrationPtr migrate) * the system memory copy to the framebuffer memory copy. Both areas must be * allocated. */ -static void +void exaCopyDirtyToFb (ExaMigrationPtr migrate) { PixmapPtr pPixmap = migrate->pPix; @@ -545,7 +545,7 @@ exaAssertNotDirty (PixmapPtr pPixmap) pExaPixmap->offscreen = TRUE; pPixmap->devKind = pExaPixmap->fb_pitch; - if (!ExaDoPrepareAccess(&pPixmap->drawable, EXA_PREPARE_SRC)) + if (!ExaDoPrepareAccess(pPixmap, EXA_PREPARE_SRC)) goto skip; while (nbox--) { @@ -718,3 +718,23 @@ exaDoMigration_classic (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel) } } } + +void +exaPrepareAccessReg_classic(PixmapPtr pPixmap, int index, RegionPtr pReg) +{ + ExaMigrationRec pixmaps[1]; + + if (index == EXA_PREPARE_DEST || index == EXA_PREPARE_AUX_DEST) { + pixmaps[0].as_dst = TRUE; + pixmaps[0].as_src = FALSE; + } else { + pixmaps[0].as_dst = FALSE; + pixmaps[0].as_src = TRUE; + } + pixmaps[0].pPix = pPixmap; + pixmaps[0].pReg = pReg; + + exaDoMigration(pixmaps, 1, FALSE); + + (void)ExaDoPrepareAccess(pPixmap, index); +} diff --git a/exa/exa_migration_mixed.c b/exa/exa_migration_mixed.c index d1ee9871b..f42c9c233 100644 --- a/exa/exa_migration_mixed.c +++ b/exa/exa_migration_mixed.c @@ -31,55 +31,16 @@ #include "exa_priv.h" #include "exa.h" -static void -exaUploadFallback(PixmapPtr pPixmap, CARD8 *src, int src_pitch) -{ - ExaPixmapPriv(pPixmap); - RegionPtr damage = DamageRegion (pExaPixmap->pDamage); - GCPtr pGC = GetScratchGC (pPixmap->drawable.depth, - pPixmap->drawable.pScreen); - int nbox, cpp = pPixmap->drawable.bitsPerPixel / 8; - DamagePtr backup = pExaPixmap->pDamage; - BoxPtr pbox; - CARD8 *src2; - - /* We don't want damage optimisations. */ - pExaPixmap->pDamage = NULL; - ValidateGC (&pPixmap->drawable, pGC); - - pbox = REGION_RECTS(damage); - nbox = REGION_NUM_RECTS(damage); - - while (nbox--) { - src2 = src + pbox->y1 * src_pitch + pbox->x1 * cpp; - - ExaCheckPutImage(&pPixmap->drawable, pGC, - pPixmap->drawable.depth, pbox->x1, pbox->y1, - pbox->x2 - pbox->x1, pbox->y2 - pbox->y1, 0, - ZPixmap, (char*) src2); - - pbox++; - } - - FreeScratchGC (pGC); - pExaPixmap->pDamage = backup; -} - void exaCreateDriverPixmap_mixed(PixmapPtr pPixmap) { ScreenPtr pScreen = pPixmap->drawable.pScreen; ExaScreenPriv(pScreen); ExaPixmapPriv(pPixmap); - RegionPtr damage = DamageRegion (pExaPixmap->pDamage); - void *sys_buffer = pExaPixmap->sys_ptr; int w = pPixmap->drawable.width, h = pPixmap->drawable.height; int depth = pPixmap->drawable.depth, bpp = pPixmap->drawable.bitsPerPixel; int usage_hint = pPixmap->usage_hint; - int sys_pitch = pExaPixmap->sys_pitch; - int paddedWidth = sys_pitch; - int nbox; - BoxPtr pbox; + int paddedWidth = pExaPixmap->sys_pitch; /* Already done. */ if (pExaPixmap->driverPriv) @@ -105,50 +66,8 @@ exaCreateDriverPixmap_mixed(PixmapPtr pPixmap) if (!pExaPixmap->driverPriv) return; - pExaPixmap->offscreen = TRUE; - pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr = NULL; - pExaPixmap->sys_pitch = pPixmap->devKind = 0; - - pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED; (*pScreen->ModifyPixmapHeader)(pPixmap, w, h, 0, 0, paddedWidth, NULL); - - /* scratch pixmaps */ - if (!w || !h) - goto finish; - - /* we do not malloc memory by default. */ - if (!sys_buffer) - goto finish; - - if (!pExaScr->info->UploadToScreen) - goto fallback; - - pbox = REGION_RECTS(damage); - nbox = REGION_NUM_RECTS(damage); - - while (nbox--) { - if (!pExaScr->info->UploadToScreen(pPixmap, pbox->x1, pbox->y1, pbox->x2 - pbox->x1, - pbox->y2 - pbox->y1, (char *) (sys_buffer) + pbox->y1 * sys_pitch + pbox->x1 * (bpp / 8), sys_pitch)) - goto fallback; - - pbox++; - } - - goto finish; - -fallback: - exaUploadFallback(pPixmap, sys_buffer, sys_pitch); - -finish: - free(sys_buffer); - - /* We no longer need this. */ - if (pExaPixmap->pDamage) { - DamageUnregister(&pPixmap->drawable, pExaPixmap->pDamage); - DamageDestroy(pExaPixmap->pDamage); - pExaPixmap->pDamage = NULL; - } } void @@ -175,8 +94,16 @@ exaDoMigration_mixed(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel) for (i = 0; i < npixmaps; i++) { PixmapPtr pPixmap = pixmaps[i].pPix; ExaPixmapPriv(pPixmap); + if (!pExaPixmap->driverPriv) exaCreateDriverPixmap_mixed(pPixmap); + + if (pExaPixmap->pDamage && exaPixmapIsOffscreen(pPixmap)) { + pPixmap->devKind = pExaPixmap->fb_pitch; + exaCopyDirtyToFb(pixmaps + i); + } + + pExaPixmap->offscreen = exaPixmapIsOffscreen(pPixmap); } } @@ -192,3 +119,91 @@ exaMoveInPixmap_mixed(PixmapPtr pPixmap) exaDoMigration(pixmaps, 1, TRUE); } + +/* With mixed pixmaps, if we fail to get direct access to the driver pixmap, we + * use the DownloadFromScreen hook to retrieve contents to a copy in system + * memory, perform software rendering on that and move back the results with the + * UploadToScreen hook (see exaFinishAccess_mixed). + */ +void +exaPrepareAccessReg_mixed(PixmapPtr pPixmap, int index, RegionPtr pReg) +{ + if (!ExaDoPrepareAccess(pPixmap, index)) { + ExaPixmapPriv(pPixmap); + Bool is_offscreen = exaPixmapIsOffscreen(pPixmap); + ExaMigrationRec pixmaps[1]; + + /* Do we need to allocate our system buffer? */ + if (!pExaPixmap->sys_ptr) { + pExaPixmap->sys_ptr = malloc(pExaPixmap->sys_pitch * + pPixmap->drawable.height); + if (!pExaPixmap->sys_ptr) + FatalError("EXA: malloc failed for size %d bytes\n", + pExaPixmap->sys_pitch * pPixmap->drawable.height); + } + + if (index == EXA_PREPARE_DEST || index == EXA_PREPARE_AUX_DEST) { + pixmaps[0].as_dst = TRUE; + pixmaps[0].as_src = FALSE; + } else { + pixmaps[0].as_dst = FALSE; + pixmaps[0].as_src = TRUE; + } + pixmaps[0].pPix = pPixmap; + pixmaps[0].pReg = pReg; + + if (!pExaPixmap->pDamage && (is_offscreen || !exaPixmapIsPinned(pPixmap))) { + Bool as_dst = pixmaps[0].as_dst; + + /* Set up damage tracking */ + pExaPixmap->pDamage = DamageCreate(NULL, NULL, DamageReportNone, + TRUE, pPixmap->drawable.pScreen, + pPixmap); + + DamageRegister(&pPixmap->drawable, pExaPixmap->pDamage); + /* This ensures that pending damage reflects the current operation. */ + /* This is used by exa to optimize migration. */ + DamageSetReportAfterOp(pExaPixmap->pDamage, TRUE); + + if (is_offscreen) { + exaPixmapDirty(pPixmap, 0, 0, pPixmap->drawable.width, + pPixmap->drawable.height); + + /* We don't know which region of the destination will be damaged, + * have to assume all of it + */ + if (as_dst) { + pixmaps[0].as_dst = FALSE; + pixmaps[0].as_src = TRUE; + pixmaps[0].pReg = NULL; + } + pPixmap->devKind = pExaPixmap->fb_pitch; + exaCopyDirtyToSys(pixmaps); + } + + if (as_dst) + exaPixmapDirty(pPixmap, 0, 0, pPixmap->drawable.width, + pPixmap->drawable.height); + } else if (is_offscreen) { + pPixmap->devKind = pExaPixmap->fb_pitch; + exaCopyDirtyToSys(pixmaps); + } + + pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr; + pPixmap->devKind = pExaPixmap->sys_pitch; + pExaPixmap->offscreen = FALSE; + } +} + +/* Move back results of software rendering on system memory copy of mixed driver + * pixmap (see exaPrepareAccessReg_mixed). + */ +void exaFinishAccess_mixed(PixmapPtr pPixmap, int index) +{ + ExaPixmapPriv(pPixmap); + + if (pExaPixmap->pDamage && exaPixmapIsOffscreen(pPixmap)) { + DamageRegionProcessPending(&pPixmap->drawable); + exaMoveInPixmap_mixed(pPixmap); + } +} diff --git a/exa/exa_mixed.c b/exa/exa_mixed.c index 6aa73f2b6..167ffa9d5 100644 --- a/exa/exa_mixed.c +++ b/exa/exa_mixed.c @@ -32,8 +32,6 @@ #include "exa.h" /* This file holds the driver allocated pixmaps + better initial placement code. - * A pinned pixmap implies one that is either driver based already or otherwise altered. - * Proper care is taken to free the initially allocated buffer. */ static _X_INLINE void* @@ -46,9 +44,6 @@ ExaGetPixmapAddress(PixmapPtr p) /** * exaCreatePixmap() creates a new pixmap. - * - * Pixmaps are always marked as pinned, unless the pixmap can still be transfered to a - * driver pixmaps. */ PixmapPtr exaCreatePixmap_mixed(ScreenPtr pScreen, int w, int h, int depth, @@ -85,7 +80,6 @@ exaCreatePixmap_mixed(ScreenPtr pScreen, int w, int h, int depth, pExaPixmap->sys_pitch = paddedWidth; pExaPixmap->area = NULL; - pExaPixmap->offscreen = FALSE; pExaPixmap->fb_ptr = NULL; pExaPixmap->pDamage = NULL; @@ -93,36 +87,15 @@ exaCreatePixmap_mixed(ScreenPtr pScreen, int w, int h, int depth, exaSetAccelBlock(pExaScr, pExaPixmap, w, h, bpp); - /* Avoid freeing sys_ptr. */ - pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED; - (*pScreen->ModifyPixmapHeader)(pPixmap, w, h, 0, 0, paddedWidth, NULL); - /* We want to be able to transfer the pixmap to driver memory later on. */ - pExaPixmap->score = EXA_PIXMAP_SCORE_INIT; - /* A scratch pixmap will become a driver pixmap right away. */ if (!w || !h) { exaCreateDriverPixmap_mixed(pPixmap); - } else { - /* Set up damage tracking */ - pExaPixmap->pDamage = DamageCreate (NULL, NULL, - DamageReportNone, TRUE, - pScreen, pPixmap); - - if (pExaPixmap->pDamage == NULL) { - swap(pExaScr, pScreen, DestroyPixmap); - pScreen->DestroyPixmap (pPixmap); - swap(pExaScr, pScreen, DestroyPixmap); - return NULL; - } - - DamageRegister (&pPixmap->drawable, pExaPixmap->pDamage); - /* This ensures that pending damage reflects the current operation. */ - /* This is used by exa to optimize migration. */ - DamageSetReportAfterOp (pExaPixmap->pDamage, TRUE); - } + pExaPixmap->offscreen = exaPixmapIsOffscreen(pPixmap); + } else + pExaPixmap->offscreen = FALSE; return pPixmap; } @@ -134,7 +107,7 @@ exaModifyPixmapHeader_mixed(PixmapPtr pPixmap, int width, int height, int depth, ScreenPtr pScreen = pPixmap->drawable.pScreen; ExaScreenPrivPtr pExaScr; ExaPixmapPrivPtr pExaPixmap; - Bool ret; + Bool ret, is_offscreen; if (!pPixmap) return FALSE; @@ -142,26 +115,23 @@ exaModifyPixmapHeader_mixed(PixmapPtr pPixmap, int width, int height, int depth, pExaScr = ExaGetScreenPriv(pScreen); pExaPixmap = ExaGetPixmapPriv(pPixmap); - if (pExaPixmap) { - if (!exaPixmapIsPinned(pPixmap)) { - free(pExaPixmap->sys_ptr); - pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr = NULL; - pExaPixmap->sys_pitch = pPixmap->devKind = 0; - - /* We no longer need this. */ + if (pPixData) { + if (pExaPixmap->driverPriv) { if (pExaPixmap->pDamage) { DamageUnregister(&pPixmap->drawable, pExaPixmap->pDamage); DamageDestroy(pExaPixmap->pDamage); pExaPixmap->pDamage = NULL; } - } - if (pPixData) - pExaPixmap->sys_ptr = pPixData; + pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv); + pExaPixmap->driverPriv = NULL; + } - if (devKind > 0) - pExaPixmap->sys_pitch = devKind; + pExaPixmap->offscreen = FALSE; + pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED; + } + if (pExaPixmap->driverPriv) { if (width > 0 && height > 0 && bitsPerPixel > 0) { exaSetFbPitch(pExaScr, pExaPixmap, width, height, bitsPerPixel); @@ -169,9 +139,15 @@ exaModifyPixmapHeader_mixed(PixmapPtr pPixmap, int width, int height, int depth, exaSetAccelBlock(pExaScr, pExaPixmap, width, height, bitsPerPixel); } + } - /* Anything can happen, don't try to predict it all. */ - pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED; + is_offscreen = exaPixmapIsOffscreen(pPixmap); + if (is_offscreen) { + pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr; + pPixmap->devKind = pExaPixmap->fb_pitch; + } else { + pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr; + pPixmap->devKind = pExaPixmap->sys_pitch; } /* Only pass driver pixmaps to the driver. */ @@ -182,10 +158,6 @@ exaModifyPixmapHeader_mixed(PixmapPtr pPixmap, int width, int height, int depth, * If pPixmap->devPrivate.ptr is non-NULL, then we've got a non-offscreen pixmap. * We need to store the pointer, because PrepareAccess won't be called. */ - if (!pPixData && pPixmap->devPrivate.ptr && pPixmap->devKind) { - pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr; - pExaPixmap->sys_pitch = pPixmap->devKind; - } if (ret == TRUE) goto out; } @@ -196,6 +168,13 @@ exaModifyPixmapHeader_mixed(PixmapPtr pPixmap, int width, int height, int depth, swap(pExaScr, pScreen, ModifyPixmapHeader); out: + if (is_offscreen) { + pExaPixmap->fb_ptr = pPixmap->devPrivate.ptr; + pExaPixmap->fb_pitch = pPixmap->devKind; + } else { + pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr; + pExaPixmap->sys_pitch = pPixmap->devKind; + } /* Always NULL this, we don't want lingering pointers. */ pPixmap->devPrivate.ptr = NULL; @@ -215,10 +194,14 @@ exaDestroyPixmap_mixed(PixmapPtr pPixmap) if (pExaPixmap->driverPriv) pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv); - else if (pExaPixmap->sys_ptr && !exaPixmapIsPinned(pPixmap)) - free(pExaPixmap->sys_ptr); pExaPixmap->driverPriv = NULL; - pExaPixmap->sys_ptr = NULL; + + if (pExaPixmap->pDamage) { + if (pExaPixmap->sys_ptr) + free(pExaPixmap->sys_ptr); + pExaPixmap->sys_ptr = NULL; + pExaPixmap->pDamage = NULL; + } } swap(pExaScr, pScreen, DestroyPixmap); diff --git a/exa/exa_priv.h b/exa/exa_priv.h index 869cf1772..1aec8e966 100644 --- a/exa/exa_priv.h +++ b/exa/exa_priv.h @@ -176,6 +176,8 @@ typedef struct { Bool (*pixmap_is_offscreen) (PixmapPtr pPixmap); void (*do_move_in_pixmap) (PixmapPtr pPixmap); void (*do_move_out_pixmap) (PixmapPtr pPixmap); + void (*prepare_access_reg)(PixmapPtr pPixmap, int index, RegionPtr pReg); + void (*finish_access)(PixmapPtr pPixmap, int index); Bool swappedOut; enum ExaMigrationHeuristic migration; @@ -511,10 +513,7 @@ ExaOffscreenFini (ScreenPtr pScreen); /* exa.c */ Bool -ExaDoPrepareAccess(DrawablePtr pDrawable, int index); - -void -exaPrepareAccessReg(DrawablePtr pDrawable, int index, RegionPtr pReg); +ExaDoPrepareAccess(PixmapPtr pPixmap, int index); void exaPrepareAccess(DrawablePtr pDrawable, int index); @@ -609,6 +608,12 @@ exaDoMigration_mixed(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel); void exaMoveInPixmap_mixed(PixmapPtr pPixmap); +void +exaPrepareAccessReg_mixed(PixmapPtr pPixmap, int index, RegionPtr pReg); + +void +exaFinishAccess_mixed(PixmapPtr pPixmap, int index); + /* exa_render.c */ Bool exaOpReadsDestination (CARD8 op); @@ -665,6 +670,12 @@ exaGlyphs (CARD8 op, /* exa_migration_classic.c */ void +exaCopyDirtyToSys (ExaMigrationPtr migrate); + +void +exaCopyDirtyToFb (ExaMigrationPtr migrate); + +void exaDoMigration_classic (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel); void @@ -676,4 +687,7 @@ exaMoveOutPixmap_classic (PixmapPtr pPixmap); void exaMoveInPixmap_classic (PixmapPtr pPixmap); +void +exaPrepareAccessReg_classic(PixmapPtr pPixmap, int index, RegionPtr pReg); + #endif /* EXAPRIV_H */ diff --git a/exa/exa_unaccel.c b/exa/exa_unaccel.c index f4700adac..c8f017243 100644 --- a/exa/exa_unaccel.c +++ b/exa/exa_unaccel.c @@ -101,16 +101,19 @@ ExaCheckPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, int w, int h, int leftPad, int format, char *bits) { - ExaPixmapPriv(exaGetDrawablePixmap(pDrawable)); + PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable); + ExaPixmapPriv(pPixmap); + ExaScreenPriv(pDrawable->pScreen); EXA_GC_PROLOGUE(pGC); EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable))); - if (exaGCReadsDestination(pDrawable, pGC->planemask, pGC->fillStyle, + if (!pExaScr->prepare_access_reg || !pExaPixmap->pDamage || + exaGCReadsDestination(pDrawable, pGC->planemask, pGC->fillStyle, pGC->alu, pGC->clientClipType)) exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); else - exaPrepareAccessReg (pDrawable, EXA_PREPARE_DEST, pExaPixmap->pDamage ? - DamagePendingRegion(pExaPixmap->pDamage) : NULL); + pExaScr->prepare_access_reg(pPixmap, EXA_PREPARE_DEST, + DamagePendingRegion(pExaPixmap->pDamage)); pGC->ops->PutImage (pDrawable, pGC, depth, x, y, w, h, leftPad, format, bits); exaFinishAccess (pDrawable, EXA_PREPARE_DEST); EXA_GC_EPILOGUE(pGC); @@ -323,9 +326,6 @@ void ExaCheckGetImage(DrawablePtr pDrawable, int x, int y, int w, int h, unsigned int format, unsigned long planeMask, char *d) { - BoxRec Box; - RegionRec Reg; - int xoff, yoff; ScreenPtr pScreen = pDrawable->pScreen; PixmapPtr pPix = exaGetDrawablePixmap (pDrawable); ExaScreenPriv(pScreen); @@ -333,16 +333,24 @@ ExaCheckGetImage(DrawablePtr pDrawable, int x, int y, int w, int h, EXA_FALLBACK(("from %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable))); - exaGetDrawableDeltas(pDrawable, pPix, &xoff, &yoff); + if (pExaScr->prepare_access_reg) { + int xoff, yoff; + BoxRec Box; + RegionRec Reg; + + exaGetDrawableDeltas(pDrawable, pPix, &xoff, &yoff); + + Box.x1 = pDrawable->y + x + xoff; + Box.y1 = pDrawable->y + y + yoff; + Box.x2 = Box.x1 + w; + Box.y2 = Box.y1 + h; - Box.x1 = pDrawable->y + x + xoff; - Box.y1 = pDrawable->y + y + yoff; - Box.x2 = Box.x1 + w; - Box.y2 = Box.y1 + h; + REGION_INIT(pScreen, &Reg, &Box, 1); - REGION_INIT(pScreen, &Reg, &Box, 1); + pExaScr->prepare_access_reg(pPix, EXA_PREPARE_SRC, &Reg); + } else + exaPrepareAccess(pDrawable, EXA_PREPARE_SRC); - exaPrepareAccessReg (pDrawable, EXA_PREPARE_SRC, &Reg); swap(pExaScr, pScreen, GetImage); pScreen->GetImage (pDrawable, x, y, w, h, format, planeMask, d); swap(pExaScr, pScreen, GetImage); @@ -401,23 +409,23 @@ ExaCheckComposite (CARD8 op, if (pMask && pMask->alphaMap && pMask->alphaMap->pDrawable) exaPrepareAccess(pMask->alphaMap->pDrawable, EXA_PREPARE_AUX_MASK); - if (!exaOpReadsDestination(op)) { + if (!exaOpReadsDestination(op) && pExaScr->prepare_access_reg) { + PixmapPtr pDstPix; + if (!miComputeCompositeRegion (®ion, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, xDst, yDst, width, height)) goto skip; - exaGetDrawableDeltas (pDst->pDrawable, - exaGetDrawablePixmap(pDst->pDrawable), - &xoff, &yoff); - + pDstPix = exaGetDrawablePixmap(pDst->pDrawable); + exaGetDrawableDeltas (pDst->pDrawable, pDstPix, &xoff, &yoff); REGION_TRANSLATE(pScreen, ®ion, xoff, yoff); if (pDst->alphaMap && pDst->alphaMap->pDrawable) - exaPrepareAccessReg(pDst->alphaMap->pDrawable, EXA_PREPARE_AUX_DEST, - ®ion); + pExaScr->prepare_access_reg(exaGetDrawablePixmap(pDst->alphaMap->pDrawable), + EXA_PREPARE_AUX_DEST, ®ion); - exaPrepareAccessReg (pDst->pDrawable, EXA_PREPARE_DEST, ®ion); + pExaScr->prepare_access_reg(pDstPix, EXA_PREPARE_DEST, ®ion); } else { if (pDst->alphaMap && pDst->alphaMap->pDrawable) exaPrepareAccess(pDst->alphaMap->pDrawable, EXA_PREPARE_AUX_DEST); |