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.
This commit is contained in:
Michel Dänzer 2009-09-26 01:59:39 +02:00
parent e23bffc41b
commit 1818cbd70f
6 changed files with 233 additions and 217 deletions

View File

@ -286,11 +286,10 @@ exaGetOffscreenPixmap (DrawablePtr pDrawable, int *xp, int *yp)
* Returns TRUE if pixmap can be accessed offscreen. * Returns TRUE if pixmap can be accessed offscreen.
*/ */
Bool Bool
ExaDoPrepareAccess(DrawablePtr pDrawable, int index) ExaDoPrepareAccess(PixmapPtr pPixmap, int index)
{ {
ScreenPtr pScreen = pDrawable->pScreen; ScreenPtr pScreen = pPixmap->drawable.pScreen;
ExaScreenPriv (pScreen); ExaScreenPriv (pScreen);
PixmapPtr pPixmap = exaGetDrawablePixmap (pDrawable);
ExaPixmapPriv(pPixmap); ExaPixmapPriv(pPixmap);
Bool offscreen; Bool offscreen;
int i; int i;
@ -324,7 +323,7 @@ ExaDoPrepareAccess(DrawablePtr pDrawable, int index)
offscreen = exaPixmapIsOffscreen(pPixmap); offscreen = exaPixmapIsOffscreen(pPixmap);
if (offscreen) if (offscreen && pExaPixmap->fb_ptr)
pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr; pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr;
else else
pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr; pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
@ -333,20 +332,10 @@ ExaDoPrepareAccess(DrawablePtr pDrawable, int index)
pExaScr->access[index].pixmap = pPixmap; pExaScr->access[index].pixmap = pPixmap;
pExaScr->access[index].count = 1; pExaScr->access[index].count = 1;
if (!offscreen) { 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;
}
}
return FALSE; return FALSE;
}
exaWaitSync (pDrawable->pScreen); exaWaitSync (pScreen);
if (pExaScr->info->PrepareAccess == NULL) if (pExaScr->info->PrepareAccess == NULL)
return TRUE; return TRUE;
@ -360,7 +349,8 @@ ExaDoPrepareAccess(DrawablePtr pDrawable, int index)
} }
if (!(*pExaScr->info->PrepareAccess) (pPixmap, 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"); FatalError("Driver failed PrepareAccess on a pinned pixmap.\n");
exaMoveOutPixmap (pPixmap); exaMoveOutPixmap (pPixmap);
@ -370,31 +360,6 @@ ExaDoPrepareAccess(DrawablePtr pDrawable, int index)
return TRUE; 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. * exaPrepareAccess() is EXA's wrapper for the driver's PrepareAccess() handler.
* *
@ -404,7 +369,13 @@ exaPrepareAccessReg(DrawablePtr pDrawable, int index, RegionPtr pReg)
void void
exaPrepareAccess(DrawablePtr pDrawable, int index) 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].pixmap == pPixmap) {
if (--pExaScr->access[i].count > 0) if (--pExaScr->access[i].count > 0)
return; return;
index = i;
break; break;
} }
} }
@ -442,25 +412,25 @@ exaFinishAccess(DrawablePtr pDrawable, int index)
EXA_FatalErrorDebug(("EXA bug: FinishAccess called without PrepareAccess for pixmap 0x%p.\n", EXA_FatalErrorDebug(("EXA bug: FinishAccess called without PrepareAccess for pixmap 0x%p.\n",
pPixmap)); pPixmap));
pExaScr->access[index].pixmap = NULL; pExaScr->access[i].pixmap = NULL;
/* We always hide the devPrivate.ptr. */ /* We always hide the devPrivate.ptr. */
pPixmap->devPrivate.ptr = NULL; pPixmap->devPrivate.ptr = NULL;
if (pExaScr->info->FinishAccess == NULL) if (pExaScr->finish_access)
pExaScr->finish_access(pPixmap, index);
if (!pExaScr->info->FinishAccess || !exaPixmapIsOffscreen(pPixmap))
return; return;
if (!exaPixmapIsOffscreen (pPixmap)) if (i >= EXA_PREPARE_AUX_DEST &&
return;
if (index >= EXA_PREPARE_AUX_DEST &&
!(pExaScr->info->flags & EXA_SUPPORTS_PREPARE_AUX)) { !(pExaScr->info->flags & EXA_SUPPORTS_PREPARE_AUX)) {
ErrorF("EXA bug: Trying to call driver FinishAccess hook with " ErrorF("EXA bug: Trying to call driver FinishAccess hook with "
"unsupported index EXA_PREPARE_AUX*\n"); "unsupported index EXA_PREPARE_AUX*\n");
return; 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. * For EXA_HANDLES_PIXMAPS the driver will handle whatever is needed.
* We want to signal that the pixmaps will be used as destination. * 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; return pPixmap;
} }
@ -1071,6 +1041,8 @@ exaDriverInit (ScreenPtr pScreen,
pExaScr->pixmap_is_offscreen = exaPixmapIsOffscreen_mixed; pExaScr->pixmap_is_offscreen = exaPixmapIsOffscreen_mixed;
pExaScr->do_move_in_pixmap = exaMoveInPixmap_mixed; pExaScr->do_move_in_pixmap = exaMoveInPixmap_mixed;
pExaScr->do_move_out_pixmap = NULL; pExaScr->do_move_out_pixmap = NULL;
pExaScr->prepare_access_reg = exaPrepareAccessReg_mixed;
pExaScr->finish_access = exaFinishAccess_mixed;
} else { } else {
wrap(pExaScr, pScreen, CreatePixmap, exaCreatePixmap_driver); wrap(pExaScr, pScreen, CreatePixmap, exaCreatePixmap_driver);
wrap(pExaScr, pScreen, DestroyPixmap, exaDestroyPixmap_driver); wrap(pExaScr, pScreen, DestroyPixmap, exaDestroyPixmap_driver);
@ -1079,6 +1051,8 @@ exaDriverInit (ScreenPtr pScreen,
pExaScr->pixmap_is_offscreen = exaPixmapIsOffscreen_driver; pExaScr->pixmap_is_offscreen = exaPixmapIsOffscreen_driver;
pExaScr->do_move_in_pixmap = NULL; pExaScr->do_move_in_pixmap = NULL;
pExaScr->do_move_out_pixmap = NULL; pExaScr->do_move_out_pixmap = NULL;
pExaScr->prepare_access_reg = NULL;
pExaScr->finish_access = NULL;
} }
} else { } else {
wrap(pExaScr, pScreen, CreatePixmap, exaCreatePixmap_classic); wrap(pExaScr, pScreen, CreatePixmap, exaCreatePixmap_classic);
@ -1088,6 +1062,8 @@ exaDriverInit (ScreenPtr pScreen,
pExaScr->pixmap_is_offscreen = exaPixmapIsOffscreen_classic; pExaScr->pixmap_is_offscreen = exaPixmapIsOffscreen_classic;
pExaScr->do_move_in_pixmap = exaMoveInPixmap_classic; pExaScr->do_move_in_pixmap = exaMoveInPixmap_classic;
pExaScr->do_move_out_pixmap = exaMoveOutPixmap_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)) { if (!(pExaScr->info->flags & EXA_HANDLES_PIXMAPS)) {
LogMessage(X_INFO, "EXA(%d): Offscreen pixmap area of %lu bytes\n", LogMessage(X_INFO, "EXA(%d): Offscreen pixmap area of %lu bytes\n",

View File

@ -120,7 +120,7 @@ exaCopyDirty(ExaMigrationPtr migrate, RegionPtr pValidDst, RegionPtr pValidSrc,
Bool need_sync = FALSE; Bool need_sync = FALSE;
/* Damaged bits are valid in current copy but invalid in other one */ /* 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, REGION_UNION(pScreen, &pExaPixmap->validFB, &pExaPixmap->validFB,
damage); damage);
REGION_SUBTRACT(pScreen, &pExaPixmap->validSys, &pExaPixmap->validSys, REGION_SUBTRACT(pScreen, &pExaPixmap->validSys, &pExaPixmap->validSys,
@ -225,7 +225,7 @@ exaCopyDirty(ExaMigrationPtr migrate, RegionPtr pValidDst, RegionPtr pValidSrc,
pExaPixmap->sys_pitch)) pExaPixmap->sys_pitch))
{ {
if (!access_prepared) { if (!access_prepared) {
ExaDoPrepareAccess(&pPixmap->drawable, fallback_index); ExaDoPrepareAccess(pPixmap, fallback_index);
access_prepared = TRUE; access_prepared = TRUE;
} }
exaMemcpyBox (pPixmap, pBox, 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 * the framebuffer memory copy to the system memory copy. Both areas must be
* allocated. * allocated.
*/ */
static void void
exaCopyDirtyToSys (ExaMigrationPtr migrate) exaCopyDirtyToSys (ExaMigrationPtr migrate)
{ {
PixmapPtr pPixmap = migrate->pPix; PixmapPtr pPixmap = migrate->pPix;
@ -281,7 +281,7 @@ exaCopyDirtyToSys (ExaMigrationPtr migrate)
* the system memory copy to the framebuffer memory copy. Both areas must be * the system memory copy to the framebuffer memory copy. Both areas must be
* allocated. * allocated.
*/ */
static void void
exaCopyDirtyToFb (ExaMigrationPtr migrate) exaCopyDirtyToFb (ExaMigrationPtr migrate)
{ {
PixmapPtr pPixmap = migrate->pPix; PixmapPtr pPixmap = migrate->pPix;
@ -545,7 +545,7 @@ exaAssertNotDirty (PixmapPtr pPixmap)
pExaPixmap->offscreen = TRUE; pExaPixmap->offscreen = TRUE;
pPixmap->devKind = pExaPixmap->fb_pitch; pPixmap->devKind = pExaPixmap->fb_pitch;
if (!ExaDoPrepareAccess(&pPixmap->drawable, EXA_PREPARE_SRC)) if (!ExaDoPrepareAccess(pPixmap, EXA_PREPARE_SRC))
goto skip; goto skip;
while (nbox--) { 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);
}

View File

@ -31,55 +31,16 @@
#include "exa_priv.h" #include "exa_priv.h"
#include "exa.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 void
exaCreateDriverPixmap_mixed(PixmapPtr pPixmap) exaCreateDriverPixmap_mixed(PixmapPtr pPixmap)
{ {
ScreenPtr pScreen = pPixmap->drawable.pScreen; ScreenPtr pScreen = pPixmap->drawable.pScreen;
ExaScreenPriv(pScreen); ExaScreenPriv(pScreen);
ExaPixmapPriv(pPixmap); ExaPixmapPriv(pPixmap);
RegionPtr damage = DamageRegion (pExaPixmap->pDamage);
void *sys_buffer = pExaPixmap->sys_ptr;
int w = pPixmap->drawable.width, h = pPixmap->drawable.height; int w = pPixmap->drawable.width, h = pPixmap->drawable.height;
int depth = pPixmap->drawable.depth, bpp = pPixmap->drawable.bitsPerPixel; int depth = pPixmap->drawable.depth, bpp = pPixmap->drawable.bitsPerPixel;
int usage_hint = pPixmap->usage_hint; int usage_hint = pPixmap->usage_hint;
int sys_pitch = pExaPixmap->sys_pitch; int paddedWidth = pExaPixmap->sys_pitch;
int paddedWidth = sys_pitch;
int nbox;
BoxPtr pbox;
/* Already done. */ /* Already done. */
if (pExaPixmap->driverPriv) if (pExaPixmap->driverPriv)
@ -105,50 +66,8 @@ exaCreateDriverPixmap_mixed(PixmapPtr pPixmap)
if (!pExaPixmap->driverPriv) if (!pExaPixmap->driverPriv)
return; 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, (*pScreen->ModifyPixmapHeader)(pPixmap, w, h, 0, 0,
paddedWidth, NULL); 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 void
@ -175,8 +94,16 @@ exaDoMigration_mixed(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
for (i = 0; i < npixmaps; i++) { for (i = 0; i < npixmaps; i++) {
PixmapPtr pPixmap = pixmaps[i].pPix; PixmapPtr pPixmap = pixmaps[i].pPix;
ExaPixmapPriv(pPixmap); ExaPixmapPriv(pPixmap);
if (!pExaPixmap->driverPriv) if (!pExaPixmap->driverPriv)
exaCreateDriverPixmap_mixed(pPixmap); 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); 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);
}
}

View File

@ -32,8 +32,6 @@
#include "exa.h" #include "exa.h"
/* This file holds the driver allocated pixmaps + better initial placement code. /* 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* static _X_INLINE void*
@ -46,9 +44,6 @@ ExaGetPixmapAddress(PixmapPtr p)
/** /**
* exaCreatePixmap() creates a new pixmap. * exaCreatePixmap() creates a new pixmap.
*
* Pixmaps are always marked as pinned, unless the pixmap can still be transfered to a
* driver pixmaps.
*/ */
PixmapPtr PixmapPtr
exaCreatePixmap_mixed(ScreenPtr pScreen, int w, int h, int depth, 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->sys_pitch = paddedWidth;
pExaPixmap->area = NULL; pExaPixmap->area = NULL;
pExaPixmap->offscreen = FALSE;
pExaPixmap->fb_ptr = NULL; pExaPixmap->fb_ptr = NULL;
pExaPixmap->pDamage = NULL; pExaPixmap->pDamage = NULL;
@ -93,36 +87,15 @@ exaCreatePixmap_mixed(ScreenPtr pScreen, int w, int h, int depth,
exaSetAccelBlock(pExaScr, pExaPixmap, exaSetAccelBlock(pExaScr, pExaPixmap,
w, h, bpp); w, h, bpp);
/* Avoid freeing sys_ptr. */
pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
(*pScreen->ModifyPixmapHeader)(pPixmap, w, h, 0, 0, (*pScreen->ModifyPixmapHeader)(pPixmap, w, h, 0, 0,
paddedWidth, NULL); 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. */ /* A scratch pixmap will become a driver pixmap right away. */
if (!w || !h) { if (!w || !h) {
exaCreateDriverPixmap_mixed(pPixmap); exaCreateDriverPixmap_mixed(pPixmap);
} else { pExaPixmap->offscreen = exaPixmapIsOffscreen(pPixmap);
/* Set up damage tracking */ } else
pExaPixmap->pDamage = DamageCreate (NULL, NULL, pExaPixmap->offscreen = FALSE;
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);
}
return pPixmap; return pPixmap;
} }
@ -134,7 +107,7 @@ exaModifyPixmapHeader_mixed(PixmapPtr pPixmap, int width, int height, int depth,
ScreenPtr pScreen = pPixmap->drawable.pScreen; ScreenPtr pScreen = pPixmap->drawable.pScreen;
ExaScreenPrivPtr pExaScr; ExaScreenPrivPtr pExaScr;
ExaPixmapPrivPtr pExaPixmap; ExaPixmapPrivPtr pExaPixmap;
Bool ret; Bool ret, is_offscreen;
if (!pPixmap) if (!pPixmap)
return FALSE; return FALSE;
@ -142,26 +115,23 @@ exaModifyPixmapHeader_mixed(PixmapPtr pPixmap, int width, int height, int depth,
pExaScr = ExaGetScreenPriv(pScreen); pExaScr = ExaGetScreenPriv(pScreen);
pExaPixmap = ExaGetPixmapPriv(pPixmap); pExaPixmap = ExaGetPixmapPriv(pPixmap);
if (pExaPixmap) { if (pPixData) {
if (!exaPixmapIsPinned(pPixmap)) { if (pExaPixmap->driverPriv) {
free(pExaPixmap->sys_ptr);
pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr = NULL;
pExaPixmap->sys_pitch = pPixmap->devKind = 0;
/* We no longer need this. */
if (pExaPixmap->pDamage) { if (pExaPixmap->pDamage) {
DamageUnregister(&pPixmap->drawable, pExaPixmap->pDamage); DamageUnregister(&pPixmap->drawable, pExaPixmap->pDamage);
DamageDestroy(pExaPixmap->pDamage); DamageDestroy(pExaPixmap->pDamage);
pExaPixmap->pDamage = NULL; pExaPixmap->pDamage = NULL;
} }
pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv);
pExaPixmap->driverPriv = NULL;
} }
if (pPixData) pExaPixmap->offscreen = FALSE;
pExaPixmap->sys_ptr = pPixData; pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
}
if (devKind > 0)
pExaPixmap->sys_pitch = devKind;
if (pExaPixmap->driverPriv) {
if (width > 0 && height > 0 && bitsPerPixel > 0) { if (width > 0 && height > 0 && bitsPerPixel > 0) {
exaSetFbPitch(pExaScr, pExaPixmap, exaSetFbPitch(pExaScr, pExaPixmap,
width, height, bitsPerPixel); width, height, bitsPerPixel);
@ -169,9 +139,15 @@ exaModifyPixmapHeader_mixed(PixmapPtr pPixmap, int width, int height, int depth,
exaSetAccelBlock(pExaScr, pExaPixmap, exaSetAccelBlock(pExaScr, pExaPixmap,
width, height, bitsPerPixel); width, height, bitsPerPixel);
} }
}
/* Anything can happen, don't try to predict it all. */ is_offscreen = exaPixmapIsOffscreen(pPixmap);
pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED; 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. */ /* 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. * 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. * 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) if (ret == TRUE)
goto out; goto out;
} }
@ -196,6 +168,13 @@ exaModifyPixmapHeader_mixed(PixmapPtr pPixmap, int width, int height, int depth,
swap(pExaScr, pScreen, ModifyPixmapHeader); swap(pExaScr, pScreen, ModifyPixmapHeader);
out: 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. */ /* Always NULL this, we don't want lingering pointers. */
pPixmap->devPrivate.ptr = NULL; pPixmap->devPrivate.ptr = NULL;
@ -215,10 +194,14 @@ exaDestroyPixmap_mixed(PixmapPtr pPixmap)
if (pExaPixmap->driverPriv) if (pExaPixmap->driverPriv)
pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv); pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv);
else if (pExaPixmap->sys_ptr && !exaPixmapIsPinned(pPixmap))
free(pExaPixmap->sys_ptr);
pExaPixmap->driverPriv = NULL; pExaPixmap->driverPriv = NULL;
if (pExaPixmap->pDamage) {
if (pExaPixmap->sys_ptr)
free(pExaPixmap->sys_ptr);
pExaPixmap->sys_ptr = NULL; pExaPixmap->sys_ptr = NULL;
pExaPixmap->pDamage = NULL;
}
} }
swap(pExaScr, pScreen, DestroyPixmap); swap(pExaScr, pScreen, DestroyPixmap);

View File

@ -176,6 +176,8 @@ typedef struct {
Bool (*pixmap_is_offscreen) (PixmapPtr pPixmap); Bool (*pixmap_is_offscreen) (PixmapPtr pPixmap);
void (*do_move_in_pixmap) (PixmapPtr pPixmap); void (*do_move_in_pixmap) (PixmapPtr pPixmap);
void (*do_move_out_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; Bool swappedOut;
enum ExaMigrationHeuristic migration; enum ExaMigrationHeuristic migration;
@ -511,10 +513,7 @@ ExaOffscreenFini (ScreenPtr pScreen);
/* exa.c */ /* exa.c */
Bool Bool
ExaDoPrepareAccess(DrawablePtr pDrawable, int index); ExaDoPrepareAccess(PixmapPtr pPixmap, int index);
void
exaPrepareAccessReg(DrawablePtr pDrawable, int index, RegionPtr pReg);
void void
exaPrepareAccess(DrawablePtr pDrawable, int index); exaPrepareAccess(DrawablePtr pDrawable, int index);
@ -609,6 +608,12 @@ exaDoMigration_mixed(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel);
void void
exaMoveInPixmap_mixed(PixmapPtr pPixmap); exaMoveInPixmap_mixed(PixmapPtr pPixmap);
void
exaPrepareAccessReg_mixed(PixmapPtr pPixmap, int index, RegionPtr pReg);
void
exaFinishAccess_mixed(PixmapPtr pPixmap, int index);
/* exa_render.c */ /* exa_render.c */
Bool Bool
exaOpReadsDestination (CARD8 op); exaOpReadsDestination (CARD8 op);
@ -664,6 +669,12 @@ exaGlyphs (CARD8 op,
GlyphPtr *glyphs); GlyphPtr *glyphs);
/* exa_migration_classic.c */ /* exa_migration_classic.c */
void
exaCopyDirtyToSys (ExaMigrationPtr migrate);
void
exaCopyDirtyToFb (ExaMigrationPtr migrate);
void void
exaDoMigration_classic (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel); exaDoMigration_classic (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel);
@ -676,4 +687,7 @@ exaMoveOutPixmap_classic (PixmapPtr pPixmap);
void void
exaMoveInPixmap_classic (PixmapPtr pPixmap); exaMoveInPixmap_classic (PixmapPtr pPixmap);
void
exaPrepareAccessReg_classic(PixmapPtr pPixmap, int index, RegionPtr pReg);
#endif /* EXAPRIV_H */ #endif /* EXAPRIV_H */

View File

@ -101,16 +101,19 @@ ExaCheckPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth,
int x, int y, int w, int h, int leftPad, int format, int x, int y, int w, int h, int leftPad, int format,
char *bits) char *bits)
{ {
ExaPixmapPriv(exaGetDrawablePixmap(pDrawable)); PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable);
ExaPixmapPriv(pPixmap);
ExaScreenPriv(pDrawable->pScreen);
EXA_GC_PROLOGUE(pGC); EXA_GC_PROLOGUE(pGC);
EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable))); 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)) pGC->alu, pGC->clientClipType))
exaPrepareAccess (pDrawable, EXA_PREPARE_DEST); exaPrepareAccess (pDrawable, EXA_PREPARE_DEST);
else else
exaPrepareAccessReg (pDrawable, EXA_PREPARE_DEST, pExaPixmap->pDamage ? pExaScr->prepare_access_reg(pPixmap, EXA_PREPARE_DEST,
DamagePendingRegion(pExaPixmap->pDamage) : NULL); DamagePendingRegion(pExaPixmap->pDamage));
pGC->ops->PutImage (pDrawable, pGC, depth, x, y, w, h, leftPad, format, bits); pGC->ops->PutImage (pDrawable, pGC, depth, x, y, w, h, leftPad, format, bits);
exaFinishAccess (pDrawable, EXA_PREPARE_DEST); exaFinishAccess (pDrawable, EXA_PREPARE_DEST);
EXA_GC_EPILOGUE(pGC); EXA_GC_EPILOGUE(pGC);
@ -323,9 +326,6 @@ void
ExaCheckGetImage(DrawablePtr pDrawable, int x, int y, int w, int h, ExaCheckGetImage(DrawablePtr pDrawable, int x, int y, int w, int h,
unsigned int format, unsigned long planeMask, char *d) unsigned int format, unsigned long planeMask, char *d)
{ {
BoxRec Box;
RegionRec Reg;
int xoff, yoff;
ScreenPtr pScreen = pDrawable->pScreen; ScreenPtr pScreen = pDrawable->pScreen;
PixmapPtr pPix = exaGetDrawablePixmap (pDrawable); PixmapPtr pPix = exaGetDrawablePixmap (pDrawable);
ExaScreenPriv(pScreen); ExaScreenPriv(pScreen);
@ -333,6 +333,11 @@ ExaCheckGetImage(DrawablePtr pDrawable, int x, int y, int w, int h,
EXA_FALLBACK(("from %p (%c)\n", pDrawable, EXA_FALLBACK(("from %p (%c)\n", pDrawable,
exaDrawableLocation(pDrawable))); exaDrawableLocation(pDrawable)));
if (pExaScr->prepare_access_reg) {
int xoff, yoff;
BoxRec Box;
RegionRec Reg;
exaGetDrawableDeltas(pDrawable, pPix, &xoff, &yoff); exaGetDrawableDeltas(pDrawable, pPix, &xoff, &yoff);
Box.x1 = pDrawable->y + x + xoff; Box.x1 = pDrawable->y + x + xoff;
@ -342,7 +347,10 @@ ExaCheckGetImage(DrawablePtr pDrawable, int x, int y, int w, int h,
REGION_INIT(pScreen, &Reg, &Box, 1); REGION_INIT(pScreen, &Reg, &Box, 1);
exaPrepareAccessReg (pDrawable, EXA_PREPARE_SRC, &Reg); pExaScr->prepare_access_reg(pPix, EXA_PREPARE_SRC, &Reg);
} else
exaPrepareAccess(pDrawable, EXA_PREPARE_SRC);
swap(pExaScr, pScreen, GetImage); swap(pExaScr, pScreen, GetImage);
pScreen->GetImage (pDrawable, x, y, w, h, format, planeMask, d); pScreen->GetImage (pDrawable, x, y, w, h, format, planeMask, d);
swap(pExaScr, pScreen, GetImage); swap(pExaScr, pScreen, GetImage);
@ -401,23 +409,23 @@ ExaCheckComposite (CARD8 op,
if (pMask && pMask->alphaMap && pMask->alphaMap->pDrawable) if (pMask && pMask->alphaMap && pMask->alphaMap->pDrawable)
exaPrepareAccess(pMask->alphaMap->pDrawable, EXA_PREPARE_AUX_MASK); exaPrepareAccess(pMask->alphaMap->pDrawable, EXA_PREPARE_AUX_MASK);
if (!exaOpReadsDestination(op)) { if (!exaOpReadsDestination(op) && pExaScr->prepare_access_reg) {
PixmapPtr pDstPix;
if (!miComputeCompositeRegion (&region, pSrc, pMask, pDst, if (!miComputeCompositeRegion (&region, pSrc, pMask, pDst,
xSrc, ySrc, xMask, yMask, xDst, yDst, xSrc, ySrc, xMask, yMask, xDst, yDst,
width, height)) width, height))
goto skip; goto skip;
exaGetDrawableDeltas (pDst->pDrawable, pDstPix = exaGetDrawablePixmap(pDst->pDrawable);
exaGetDrawablePixmap(pDst->pDrawable), exaGetDrawableDeltas (pDst->pDrawable, pDstPix, &xoff, &yoff);
&xoff, &yoff);
REGION_TRANSLATE(pScreen, &region, xoff, yoff); REGION_TRANSLATE(pScreen, &region, xoff, yoff);
if (pDst->alphaMap && pDst->alphaMap->pDrawable) if (pDst->alphaMap && pDst->alphaMap->pDrawable)
exaPrepareAccessReg(pDst->alphaMap->pDrawable, EXA_PREPARE_AUX_DEST, pExaScr->prepare_access_reg(exaGetDrawablePixmap(pDst->alphaMap->pDrawable),
&region); EXA_PREPARE_AUX_DEST, &region);
exaPrepareAccessReg (pDst->pDrawable, EXA_PREPARE_DEST, &region); pExaScr->prepare_access_reg(pDstPix, EXA_PREPARE_DEST, &region);
} else { } else {
if (pDst->alphaMap && pDst->alphaMap->pDrawable) if (pDst->alphaMap && pDst->alphaMap->pDrawable)
exaPrepareAccess(pDst->alphaMap->pDrawable, EXA_PREPARE_AUX_DEST); exaPrepareAccess(pDst->alphaMap->pDrawable, EXA_PREPARE_AUX_DEST);