#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 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;
}
}
static Bool
exaPixmapIsDirty (PixmapPtr pPix)
{
ExaPixmapPriv (pPix);
return pExaPixmap == NULL ||
REGION_NOTEMPTY (pScreen, DamageRegion(pExaPixmap->pDamage));
}
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);
RegionPtr pRegion = DamageRegion (pExaPixmap->pDamage);
CARD8 *save_ptr;
int save_pitch;
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;
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);
if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2)
continue;
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);
}
else
do_sync = TRUE;
pBox++;
}
if (do_sync)
exaWaitSync (pPixmap->drawable.pScreen);
pPixmap->devPrivate.ptr = save_ptr;
pPixmap->devKind = save_pitch;
REGION_UNION(pPixmap->drawable.pScreen,
&pExaPixmap->validReg, &pExaPixmap->validReg, pRegion);
DamageEmpty (pExaPixmap->pDamage);
}
static void
exaCopyDirtyToFb (PixmapPtr pPixmap)
{
ExaScreenPriv (pPixmap->drawable.pScreen);
ExaPixmapPriv (pPixmap);
RegionPtr pRegion = DamageRegion (pExaPixmap->pDamage);
CARD8 *save_ptr;
int save_pitch;
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;
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);
if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2)
continue;
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);
}
else
do_sync = TRUE;
pBox++;
}
if (do_sync)
exaMarkSync (pPixmap->drawable.pScreen);
pPixmap->devPrivate.ptr = save_ptr;
pPixmap->devKind = save_pitch;
REGION_UNION(pPixmap->drawable.pScreen,
&pExaPixmap->validReg, &pExaPixmap->validReg, pRegion);
DamageEmpty (pExaPixmap->pDamage);
}
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 ?
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;
REGION_UNION(pPixmap->drawable.pScreen, pDamageReg, pDamageReg,
&pExaPixmap->validReg);
}
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 (pPixmap->drawable.width > pExaScr->info->maxX ||
pPixmap->drawable.height > pExaScr->info->maxY)
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 Bool
exaAssertNotDirty (PixmapPtr pPixmap)
{
ExaPixmapPriv (pPixmap);
CARD8 *dst, *src;
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 (!nbox || exaPixmapIsPinned(pPixmap) || pExaPixmap->fb_ptr == NULL)
return ret;
dst_pitch = pExaPixmap->sys_pitch;
src_pitch = pExaPixmap->fb_pitch;
cpp = pPixmap->drawable.bitsPerPixel / 8;
exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_SRC);
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 = pExaPixmap->fb_ptr + pBox->y1 * src_pitch + pBox->x1 * cpp;
dst = pExaPixmap->sys_ptr + pBox->y1 * dst_pitch + pBox->x1 * cpp;
for (y = pBox->y1; y < pBox->y2;
y++, src += src_pitch, dst += dst_pitch) {
if (memcmp(dst, src, rowbytes) != 0) {
ret = FALSE;
exaPixmapDirty(pPixmap, pBox->x1, pBox->y1, pBox->x2,
pBox->y2);
break;
}
}
}
exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_SRC);
return ret;
}
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))
ErrorF("%s: Pixmap %d dirty but not marked as such!\n", __func__, i);
}
}
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;
}
}
}
}