#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <string.h>
#include "exa_priv.h"
#include <X11/fonts/fontstruct.h>
#include "dixfontstr.h"
#include "exa.h"
#include "cw.h"
#if DEBUG_MIGRATE
#define DBG_MIGRATE(a) ErrorF a
#else
#define DBG_MIGRATE(a)
#endif
static Bool
exaPixmapIsPinned (PixmapPtr pPix)
{
ExaPixmapPriv (pPix);
return pExaPixmap == NULL || pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED;
}
static Bool
exaPixmapIsDirty (PixmapPtr pPix)
{
ExaPixmapPriv (pPix);
return pExaPixmap == NULL || pExaPixmap->dirty == TRUE;
}
static Bool
exaPixmapShouldBeInFB (PixmapPtr pPix)
{
ExaPixmapPriv (pPix);
if (exaPixmapIsPinned (pPix))
return TRUE;
return pExaPixmap->score >= 0;
}
static void
exaCopyDirtyToSys (PixmapPtr pPixmap)
{
ExaScreenPriv (pPixmap->drawable.pScreen);
ExaPixmapPriv (pPixmap);
CARD8 *save_ptr;
int save_pitch;
if (!pExaPixmap->dirty)
return;
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;
exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_SRC);
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;
}
exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_SRC);
}
exaWaitSync (pPixmap->drawable.pScreen);
pPixmap->devPrivate.ptr = save_ptr;
pPixmap->devKind = save_pitch;
pExaPixmap->dirty = FALSE;
}
static void
exaCopyDirtyToFb (PixmapPtr pPixmap)
{
ExaScreenPriv (pPixmap->drawable.pScreen);
ExaPixmapPriv (pPixmap);
CARD8 *save_ptr;
int save_pitch;
if (!pExaPixmap->dirty)
return;
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;
exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_DEST);
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;
}
exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_DEST);
}
pPixmap->devPrivate.ptr = save_ptr;
pPixmap->devKind = save_pitch;
pExaPixmap->dirty = FALSE;
}
static void
exaPixmapSave (ScreenPtr pScreen, ExaOffscreenArea *area)
{
PixmapPtr pPixmap = area->privData;
ExaPixmapPriv(pPixmap);
DBG_MIGRATE (("Save %p (%p) (%dx%d) (%c)\n", pPixmap,
(void*)(ExaGetPixmapPriv(pPixmap)->area ?
ExaGetPixmapPriv(pPixmap)->area->offset : 0),
pPixmap->drawable.width,
pPixmap->drawable.height,
exaPixmapIsDirty(pPixmap) ? 'd' : 'c'));
if (exaPixmapIsOffscreen(pPixmap)) {
exaCopyDirtyToSys (pPixmap);
pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
pPixmap->devKind = pExaPixmap->sys_pitch;
pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
}
pExaPixmap->fb_ptr = NULL;
pExaPixmap->area = NULL;
pExaPixmap->dirty = TRUE;
}
void
exaMoveInPixmap (PixmapPtr pPixmap)
{
ScreenPtr pScreen = pPixmap->drawable.pScreen;
ExaScreenPriv (pScreen);
ExaPixmapPriv (pPixmap);
if (pExaScr->swappedOut)
return;
if (exaPixmapIsOffscreen(pPixmap))
return;
if (exaPixmapIsPinned(pPixmap))
return;
if (pPixmap->drawable.bitsPerPixel < 8)
return;
if (pExaPixmap->area == NULL) {
pExaPixmap->area =
exaOffscreenAlloc (pScreen, pExaPixmap->fb_size,
pExaScr->info->pixmapOffsetAlign, FALSE,
exaPixmapSave, (pointer) pPixmap);
if (pExaPixmap->area == NULL)
return;
pExaPixmap->fb_ptr = (CARD8 *) pExaScr->info->memoryBase +
pExaPixmap->area->offset;
}
DBG_MIGRATE (("-> %p (0x%x) (%dx%d) (%c)\n", pPixmap,
(ExaGetPixmapPriv(pPixmap)->area ?
ExaGetPixmapPriv(pPixmap)->area->offset : 0),
pPixmap->drawable.width,
pPixmap->drawable.height,
exaPixmapIsDirty(pPixmap) ? 'd' : 'c'));
exaCopyDirtyToFb (pPixmap);
if (pExaScr->hideOffscreenPixmapData)
pPixmap->devPrivate.ptr = NULL;
else
pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr;
pPixmap->devKind = pExaPixmap->fb_pitch;
pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
}
void
exaMoveOutPixmap (PixmapPtr pPixmap)
{
ExaPixmapPriv (pPixmap);
if (exaPixmapIsPinned(pPixmap))
return;
if (exaPixmapIsOffscreen(pPixmap)) {
DBG_MIGRATE (("<- %p (%p) (%dx%d) (%c)\n", pPixmap,
(void*)(ExaGetPixmapPriv(pPixmap)->area ?
ExaGetPixmapPriv(pPixmap)->area->offset : 0),
pPixmap->drawable.width,
pPixmap->drawable.height,
exaPixmapIsDirty(pPixmap) ? 'd' : 'c'));
exaCopyDirtyToSys (pPixmap);
pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
pPixmap->devKind = pExaPixmap->sys_pitch;
pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
}
}
static void
exaMigrateTowardFb (PixmapPtr pPixmap)
{
ExaPixmapPriv (pPixmap);
if (pExaPixmap == NULL) {
DBG_MIGRATE(("UseScreen: ignoring exa-uncontrolled pixmap %p (%s)\n",
(pointer)pPixmap,
exaPixmapIsOffscreen(pPixmap) ? "s" : "m"));
return;
}
if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED) {
DBG_MIGRATE(("UseScreen: not migrating pinned pixmap %p\n",
(pointer)pPixmap));
return;
}
DBG_MIGRATE(("UseScreen %p score %d\n",
(pointer)pPixmap, pExaPixmap->score));
if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT) {
exaMoveInPixmap(pPixmap);
pExaPixmap->score = 0;
}
if (pExaPixmap->score < EXA_PIXMAP_SCORE_MAX)
pExaPixmap->score++;
if (pExaPixmap->score >= EXA_PIXMAP_SCORE_MOVE_IN &&
!exaPixmapIsOffscreen(pPixmap))
{
exaMoveInPixmap (pPixmap);
}
ExaOffscreenMarkUsed (pPixmap);
}
static void
exaMigrateTowardSys (PixmapPtr pPixmap)
{
ExaPixmapPriv (pPixmap);
if (pExaPixmap == NULL) {
DBG_MIGRATE(("UseMem: ignoring exa-uncontrolled pixmap %p (%s)\n",
(pointer)pPixmap,
exaPixmapIsOffscreen(pPixmap) ? "s" : "m"));
return;
}
DBG_MIGRATE(("UseMem: %p score %d\n", (pointer)pPixmap, pExaPixmap->score));
if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED)
return;
if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT)
pExaPixmap->score = 0;
if (pExaPixmap->score > EXA_PIXMAP_SCORE_MIN)
pExaPixmap->score--;
if (pExaPixmap->score <= EXA_PIXMAP_SCORE_MOVE_OUT && pExaPixmap->area)
exaMoveOutPixmap (pPixmap);
}
static void
exaAssertNotDirty (PixmapPtr pPixmap)
{
ExaPixmapPriv (pPixmap);
CARD8 *dst, *src;
int dst_pitch, src_pitch, data_row_bytes, y;
if (pExaPixmap == NULL || pExaPixmap->fb_ptr == NULL)
return;
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;
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;
}
exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_SRC);
}
void
exaDoMigration (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
{
ScreenPtr pScreen = pixmaps[0].pPix->drawable.pScreen;
ExaScreenPriv(pScreen);
int i, j;
if (pExaScr->checkDirtyCorrectness) {
for (i = 0; i < npixmaps; i++) {
if (!exaPixmapIsDirty (pixmaps[i].pPix))
exaAssertNotDirty (pixmaps[i].pPix);
}
}
for (i = 0; i < npixmaps; i++) {
if (exaPixmapIsPinned (pixmaps[i].pPix) &&
!exaPixmapIsOffscreen (pixmaps[i].pPix))
{
EXA_FALLBACK(("Pixmap %p (%dx%d) pinned in sys\n", pixmaps[i].pPix,
pixmaps[i].pPix->drawable.width,
pixmaps[i].pPix->drawable.height));
can_accel = FALSE;
break;
}
}
if (pExaScr->migration == ExaMigrationSmart) {
for (i = 0; i < npixmaps; i++) {
if (pixmaps[i].as_dst && !exaPixmapShouldBeInFB (pixmaps[i].pPix) &&
!exaPixmapIsDirty (pixmaps[i].pPix))
{
for (i = 0; i < npixmaps; i++) {
if (!exaPixmapIsDirty (pixmaps[i].pPix))
exaMoveOutPixmap (pixmaps[i].pPix);
}
return;
}
}
if (!can_accel) {
for (i = 0; i < npixmaps; i++) {
exaMigrateTowardSys (pixmaps[i].pPix);
if (!exaPixmapIsDirty (pixmaps[i].pPix))
exaMoveOutPixmap (pixmaps[i].pPix);
}
return;
}
for (i = 0; i < npixmaps; i++) {
exaMigrateTowardFb(pixmaps[i].pPix);
exaMoveInPixmap(pixmaps[i].pPix);
}
} else if (pExaScr->migration == ExaMigrationGreedy) {
if (!can_accel) {
for (i = 0; i < npixmaps; i++)
exaMigrateTowardSys (pixmaps[i].pPix);
return;
}
for (i = 0; i < npixmaps; i++) {
if (exaPixmapIsOffscreen(pixmaps[i].pPix)) {
for (j = 0; j < npixmaps; j++)
exaMigrateTowardFb(pixmaps[j].pPix);
return;
}
}
for (i = 0; i < npixmaps; i++)
exaMigrateTowardSys(pixmaps[i].pPix);
} else if (pExaScr->migration == ExaMigrationAlways) {
if (!can_accel) {
for (i = 0; i < npixmaps; i++)
exaMoveOutPixmap(pixmaps[i].pPix);
return;
}
for (i = 0; i < npixmaps; i++) {
exaMoveInPixmap(pixmaps[i].pPix);
ExaOffscreenMarkUsed (pixmaps[i].pPix);
}
for (i = 0; i < npixmaps; i++) {
if (!exaPixmapIsOffscreen(pixmaps[i].pPix)) {
EXA_FALLBACK(("Pixmap %p (%dx%d) not in fb\n", pixmaps[i].pPix,
pixmaps[i].pPix->drawable.width,
pixmaps[i].pPix->drawable.height));
for (j = 0; j < npixmaps; j++)
exaMoveOutPixmap(pixmaps[j].pPix);
break;
}
}
}
}