diff --git a/hw/kdrive/src/kaa.c b/hw/kdrive/src/kaa.c index 62314c87c650375da3232fe3d1c4c6cdbb1a40e3..0159e5e496a40c3b1c2cd09198fe5cdb88c8b583 100644 --- a/hw/kdrive/src/kaa.c +++ b/hw/kdrive/src/kaa.c @@ -31,43 +31,50 @@ #include "fontstruct.h" #include "dixfontstr.h" +#define DEBUG_MIGRATE 0 +#if DEBUG_MIGRATE +#define DBG_MIGRATE(a) ErrorF a +#else +#define DBG_MIGRATE(a) +#endif + int kaaGeneration; int kaaScreenPrivateIndex; int kaaPixmapPrivateIndex; -typedef struct _PixmapLink { - PixmapPtr pPixmap; - - struct _PixmapLink *next; -} PixmapLink; - typedef struct { KaaScreenInfoPtr info; - int offscreenSize; - int offscreenBase; - PixmapLink *offscreenPixmaps; - CreatePixmapProcPtr CreatePixmap; DestroyPixmapProcPtr DestroyPixmap; + int pixelOffset; /* offset from pPixmap to pixels */ } KaaScreenPrivRec, *KaaScreenPrivPtr; typedef struct { - KdOffscreenArea *offscreenArea; + KdOffscreenArea *area; + int score; + int devKind; + DevUnion devPrivate; } KaaPixmapPrivRec, *KaaPixmapPrivPtr; +#define KAA_PIXMAP_SCORE_MOVE_IN 10 +#define KAA_PIXMAP_SCORE_MAX 20 +#define KAA_PIXMAP_SCORE_MOVE_OUT -10 +#define KAA_PIXMAP_SCORE_MIN -20 #define KaaGetScreenPriv(s) ((KaaScreenPrivPtr)(s)->devPrivates[kaaScreenPrivateIndex].ptr) #define KaaScreenPriv(s) KaaScreenPrivPtr pKaaScr = KaaGetScreenPriv(s) #define KaaGetPixmapPriv(p) ((KaaPixmapPrivPtr)(p)->devPrivates[kaaPixmapPrivateIndex].ptr) -#define KaaPixmapPriv(p) KaaPixmapPrivPtr pKaaPixmap = KaaGetPixmapPriv (p) +#define KaaSetPixmapPriv(p,a) ((p)->devPrivates[kaaPixmapPrivateIndex].ptr = (pointer) (a)) +#define KaaPixmapPriv(p) KaaPixmapPrivPtr pKaaPixmap = KaaGetPixmapPriv(p) #define KaaPixmapPitch(w) (((w) + (pKaaScr->info->offscreenPitch - 1)) & ~(pKaaScr->info->offscreenPitch - 1)) #define KaaDrawableIsOffscreenPixmap(d) (d->type == DRAWABLE_PIXMAP && \ - KaaGetPixmapPriv ((PixmapPtr)(d)) != NULL && \ - KaaGetPixmapPriv ((PixmapPtr)(d))->offscreenArea != NULL && \ - !KaaGetPixmapPriv ((PixmapPtr)(d))->offscreenArea->swappedOut) + KaaGetPixmapPriv((PixmapPtr)(d)) && \ + KaaGetPixmapPriv((PixmapPtr)(d))->area) +#define KaaDrawableIsScreen(d) (((d)->type == DRAWABLE_WINDOW) || \ + KaaDrawableIsOffscreenPixmap(d)) #define KAA_SCREEN_PROLOGUE(pScreen, field) ((pScreen)->field = \ ((KaaScreenPrivPtr) (pScreen)->devPrivates[kaaScreenPrivateIndex].ptr)->field) @@ -75,102 +82,186 @@ typedef struct { #define KAA_SCREEN_EPILOGUE(pScreen, field, wrapper)\ ((pScreen)->field = wrapper) -#define MIN_OFFPIX_SIZE (320*200) +#define MIN_OFFPIX_SIZE (4096) static void -kaaMoveOutPixmap (KdOffscreenArea *area) +kaaPixmapSave (KdOffscreenArea *area) { PixmapPtr pPixmap = area->privData; - int dst_pitch, src_pitch; + KaaPixmapPriv(pPixmap); + int dst_pitch, src_pitch, bytes; unsigned char *dst, *src; int i; + DBG_MIGRATE (("Save 0x%08x (0x%x) (%dx%d)\n", + pPixmap->drawable.id, + KaaGetPixmapPriv(pPixmap)->area ? + KaaGetPixmapPriv(pPixmap)->area->offset : -1, + pPixmap->drawable.width, + pPixmap->drawable.height)); + + KdCheckSync (pPixmap->drawable.pScreen); + src_pitch = pPixmap->devKind; - dst_pitch = BitmapBytePad (pPixmap->drawable.width * pPixmap->drawable.bitsPerPixel); + dst_pitch = pKaaPixmap->devKind; src = pPixmap->devPrivate.ptr; - dst = xalloc (dst_pitch * pPixmap->drawable.height); - if (!dst) - FatalError("Out of memory\n"); - + dst = pKaaPixmap->devPrivate.ptr; + pPixmap->devKind = dst_pitch; pPixmap->devPrivate.ptr = dst; pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; + pKaaPixmap->area = NULL; + bytes = src_pitch < dst_pitch ? src_pitch : dst_pitch; + i = pPixmap->drawable.height; while (i--) { - memcpy (dst, src, dst_pitch); + memcpy (dst, src, bytes); dst += dst_pitch; src += src_pitch; } } -static void -kaaMoveInPixmap (KdOffscreenArea *area) +static Bool +kaaPixmapAllocArea (PixmapPtr pPixmap) { - PixmapPtr pPixmap = area->privData; - ScreenPtr pScreen = pPixmap->drawable.pScreen; + ScreenPtr pScreen = pPixmap->drawable.pScreen; KaaScreenPriv (pScreen); - PixmapPtr pScreenPixmap = (*pScreen->GetScreenPixmap) (pScreen); - int dst_pitch, src_pitch; + KaaPixmapPriv (pPixmap); + int bpp = pPixmap->drawable.bitsPerPixel; + CARD16 h = pPixmap->drawable.height; + CARD16 w = pPixmap->drawable.width; + int pitch = KaaPixmapPitch (w); + PixmapPtr pScreenPixmap = (*pScreen->GetScreenPixmap)(pScreen); + + pKaaPixmap->devKind = pPixmap->devKind; + pKaaPixmap->devPrivate = pPixmap->devPrivate; + pKaaPixmap->area = KdOffscreenAlloc (pScreen, pitch * h * (bpp >> 3), + pKaaScr->info->offscreenByteAlign, + FALSE, + kaaPixmapSave, (pointer) pPixmap); + if (!pKaaPixmap->area) + return FALSE; + + DBG_MIGRATE(("++ 0x%08x (0x%x) (%dx%d)\n", + pPixmap->drawable.id, + KaaGetPixmapPriv(pPixmap)->area ? + KaaGetPixmapPriv(pPixmap)->area->offset : -1, + pPixmap->drawable.width, + pPixmap->drawable.height)); + pPixmap->devKind = pitch * (bpp >> 3); + pPixmap->devPrivate.ptr = (pointer) ((CARD8 *) pScreenPixmap->devPrivate.ptr + pKaaPixmap->area->offset); + pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; + return TRUE; +} + +static void +kaaMoveInPixmap (PixmapPtr pPixmap) +{ + int dst_pitch, src_pitch, bytes; unsigned char *dst, *src; int i; + + return; + KdCheckSync (pPixmap->drawable.pScreen); - src_pitch = pPixmap->devKind; - dst_pitch = BitmapBytePad (KaaPixmapPitch (pPixmap->drawable.width * pPixmap->drawable.bitsPerPixel)); + DBG_MIGRATE (("-> 0x%08x (0x%x) (%dx%d)\n", + pPixmap->drawable.id, + KaaGetPixmapPriv(pPixmap)->area ? + KaaGetPixmapPriv(pPixmap)->area->offset : -1, + pPixmap->drawable.width, + pPixmap->drawable.height)); src = pPixmap->devPrivate.ptr; - dst = pScreenPixmap->devPrivate.ptr + area->offset; + src_pitch = pPixmap->devKind; + + if (!kaaPixmapAllocArea (pPixmap)) + return; + + dst = pPixmap->devPrivate.ptr; + dst_pitch = pPixmap->devKind; + + bytes = src_pitch < dst_pitch ? src_pitch : dst_pitch; - pPixmap->devKind = dst_pitch; - pPixmap->devPrivate.ptr = dst; - pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; - i = pPixmap->drawable.height; while (i--) { - memcpy (dst, src, dst_pitch); + memcpy (dst, src, bytes); dst += dst_pitch; src += src_pitch; } } +static void +kaaMoveOutPixmap (PixmapPtr pPixmap) +{ + KaaPixmapPriv (pPixmap); + KdOffscreenArea *area = pKaaPixmap->area; + + DBG_MIGRATE (("<- 0x%08x (0x%x) (%dx%d)\n", + pPixmap->drawable.id, + KaaGetPixmapPriv(pPixmap)->area ? + KaaGetPixmapPriv(pPixmap)->area->offset : -1, + pPixmap->drawable.width, + pPixmap->drawable.height)); + if (area) + { + kaaPixmapSave (area); + KdOffscreenFree (area); + } +} + +static void +kaaPixmapUseScreen (PixmapPtr pPixmap) +{ + KaaPixmapPriv (pPixmap); + + if (pKaaPixmap->score < KAA_PIXMAP_SCORE_MAX) + { + pKaaPixmap->score++; + DBG_MIGRATE (("UseScreen 0x%x (%d)\n", pPixmap->drawable.id, pKaaPixmap->score)); + if (!pKaaPixmap->area && + pKaaPixmap->score >= KAA_PIXMAP_SCORE_MOVE_IN) + kaaMoveInPixmap (pPixmap); + } +} + +static void +kaaPixmapUseMemory (PixmapPtr pPixmap) +{ + KaaPixmapPriv (pPixmap); + + if (pKaaPixmap->score > KAA_PIXMAP_SCORE_MIN) + { + pKaaPixmap->score--; + DBG_MIGRATE (("UseMemory 0x%x (%d)\n", pPixmap->drawable.id, pKaaPixmap->score)); + if (pKaaPixmap->area && + pKaaPixmap->score <= KAA_PIXMAP_SCORE_MOVE_OUT) + kaaMoveOutPixmap (pPixmap); + } +} + static Bool kaaDestroyPixmap (PixmapPtr pPixmap) { ScreenPtr pScreen = pPixmap->drawable.pScreen; - KaaPixmapPriv (pPixmap); - KaaScreenPriv (pScreen); Bool ret; if (pPixmap->refcnt == 1) { - if (pKaaPixmap->offscreenArea) + KaaPixmapPriv (pPixmap); + if (pKaaPixmap->area) { - PixmapLink *link, *prev; - + DBG_MIGRATE(("-- 0x%08x (0x%x) (%dx%d)\n", + pPixmap->drawable.id, + KaaGetPixmapPriv(pPixmap)->area->offset, + pPixmap->drawable.width, + pPixmap->drawable.height)); /* Free the offscreen area */ - KdOffscreenFree (pKaaPixmap->offscreenArea); - - if (pKaaPixmap->offscreenArea->swappedOut) - { - xfree (pPixmap->devPrivate.ptr); - pPixmap->devPrivate.ptr = NULL; - } - - link = pKaaScr->offscreenPixmaps; - prev = NULL; - while (link->pPixmap != pPixmap) - { - prev = link; - link = link->next; - } - - if (prev) - prev->next = link->next; - else - pKaaScr->offscreenPixmaps = link->next; - - xfree (link); + KdCheckSync (pScreen); + KdOffscreenFree (pKaaPixmap->area); + pPixmap->devPrivate = pKaaPixmap->devPrivate; + pPixmap->devKind = pKaaPixmap->devKind; } } @@ -184,72 +275,21 @@ kaaDestroyPixmap (PixmapPtr pPixmap) static PixmapPtr kaaCreatePixmap(ScreenPtr pScreen, int w, int h, int depth) { - KaaScreenPriv (pScreen); - int size = w * h; - int pitch; - int bpp; PixmapPtr pPixmap = NULL; - KaaPixmapPrivPtr pKaaPixmap; + KaaPixmapPrivPtr pKaaPixmap; - if (kdEnabled && - size > MIN_OFFPIX_SIZE) - { - KdOffscreenArea *area; - PixmapLink *link; - PixmapPtr pScreenPixmap; - - bpp = BitsPerPixel (depth); - pitch = KaaPixmapPitch (w); - - area = KdOffscreenAlloc (pScreen, pitch * h * (bpp >> 3), pKaaScr->info->offscreenByteAlign, - FALSE, kaaMoveInPixmap, kaaMoveOutPixmap, NULL); - - if (!area) - goto oom; - - link = xalloc (sizeof (PixmapLink)); - if (!link) - { - KdOffscreenFree (area); - goto oom; - } - - KAA_SCREEN_PROLOGUE (pScreen, CreatePixmap); - pPixmap = (* pScreen->CreatePixmap) (pScreen, 0, 0, depth); - KAA_SCREEN_EPILOGUE (pScreen, CreatePixmap, kaaCreatePixmap); - - pKaaPixmap = (KaaPixmapPrivPtr)pPixmap->devPrivates[kaaPixmapPrivateIndex].ptr; - pKaaPixmap->offscreenArea = area; - - pScreenPixmap = (*pScreen->GetScreenPixmap)(pScreen); - - pPixmap->drawable.width = w; - pPixmap->drawable.height = h; - pPixmap->drawable.bitsPerPixel = bpp; - pPixmap->devKind = pitch * (bpp >> 3); - pPixmap->devPrivate.ptr = pScreenPixmap->devPrivate.ptr + area->offset; - - link->pPixmap = pPixmap; - link->next = pKaaScr->offscreenPixmaps; - - area->privData = pPixmap; - - pKaaScr->offscreenPixmaps = link; - - return pPixmap; - } - - oom: KAA_SCREEN_PROLOGUE (pScreen, CreatePixmap); pPixmap = (* pScreen->CreatePixmap) (pScreen, w, h, depth); KAA_SCREEN_EPILOGUE (pScreen, CreatePixmap, kaaCreatePixmap); - - if (pPixmap) - { - pKaaPixmap = (KaaPixmapPrivPtr)pPixmap->devPrivates[kaaPixmapPrivateIndex].ptr; - pKaaPixmap->offscreenArea = NULL; - } + if (!pPixmap) + return NULL; + pKaaPixmap = KaaGetPixmapPriv(pPixmap); + pKaaPixmap->score = 0; + pKaaPixmap->area = NULL; +/* if ((pPixmap->devKind * h >= MIN_OFFPIX_SIZE) */ + if (w * h > 100 * 100) + kaaPixmapAllocArea (pPixmap); return pPixmap; } @@ -374,6 +414,14 @@ kaaCopyNtoN (DrawablePtr pSrcDrawable, KaaScreenPriv (pDstDrawable->pScreen); PixmapPtr pSrcPixmap, pDstPixmap; + /* Migrate pixmaps to same place as destination */ + if (pScreenPriv->enabled && pSrcDrawable->type == DRAWABLE_PIXMAP) { + if (KaaDrawableIsScreen (pDstDrawable)) + kaaPixmapUseScreen ((PixmapPtr) pSrcDrawable); + else + kaaPixmapUseMemory ((PixmapPtr) pSrcDrawable); + } + if (pScreenPriv->enabled && (pSrcPixmap = kaaGetDrawingPixmap (pSrcDrawable, NULL, NULL)) && (pDstPixmap = kaaGetDrawingPixmap (pDstDrawable, NULL, NULL)) && @@ -731,8 +779,7 @@ kaaValidateGC (GCPtr pGC, Mask changes, DrawablePtr pDrawable) { fbValidateGC (pGC, changes, pDrawable); - if (pDrawable->type == DRAWABLE_WINDOW || - KaaDrawableIsOffscreenPixmap (pDrawable)) + if (KaaDrawableIsScreen (pDrawable)) pGC->ops = (GCOps *) &kaaOps; else pGC->ops = (GCOps *) &kdAsyncPixmapGCOps; @@ -850,12 +897,44 @@ kaaPaintWindow(WindowPtr pWin, RegionPtr pRegion, int what) KdCheckPaintWindow (pWin, pRegion, what); } +#ifdef RENDER +static void +kaaComposite(CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ +#if 0 + if (pSrc->pDrawable->type == DRAWABLE_PIXMAP) + kaaPixmapUseMemory ((PixmapPtr) pSrc->pDrawable); + if (pMask && pMask->pDrawable->type == DRAWABLE_PIXMAP) + kaaPixmapUseMemory ((PixmapPtr) pMask->pDrawable); + if (pDst->pDrawable->type == DRAWABLE_PIXMAP) + kaaPixmapUseMemory ((PixmapPtr) pDst->pDrawable); +#endif + + KdCheckComposite (op, pSrc, pMask, pDst, xSrc, ySrc, + xMask, yMask, xDst, yDst, width, height); +} +#endif + Bool kaaDrawInit (ScreenPtr pScreen, KaaScreenInfoPtr pScreenInfo) { KaaScreenPrivPtr pKaaScr; KdScreenInfo *screen = KdGetScreenPriv (pScreen)->screen; +#ifdef RENDER + PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); +#endif if (kaaGeneration != serverGeneration) { @@ -870,7 +949,6 @@ kaaDrawInit (ScreenPtr pScreen, return FALSE; pKaaScr->info = pScreenInfo; - pKaaScr->offscreenPixmaps = NULL; pScreen->devPrivates[kaaScreenPrivateIndex].ptr = (pointer) pKaaScr; @@ -885,6 +963,10 @@ kaaDrawInit (ScreenPtr pScreen, pScreen->CopyWindow = kaaCopyWindow; pScreen->PaintWindowBackground = kaaPaintWindow; pScreen->PaintWindowBorder = kaaPaintWindow; +#ifdef RENDER + if (ps) + ps->Composite = kaaComposite; +#endif /* * Hookup offscreen pixmaps @@ -892,13 +974,13 @@ kaaDrawInit (ScreenPtr pScreen, if ((pKaaScr->info->flags & KAA_OFFSCREEN_PIXMAPS) && screen->off_screen_size > 0) { - if (!AllocatePixmapPrivate(pScreen, kaaPixmapPrivateIndex, sizeof(KaaPixmapPrivRec))) - return FALSE; - pKaaScr->CreatePixmap = pScreen->CreatePixmap; pScreen->CreatePixmap = kaaCreatePixmap; pKaaScr->DestroyPixmap = pScreen->DestroyPixmap; pScreen->DestroyPixmap = kaaDestroyPixmap; + if (!AllocatePixmapPrivate(pScreen, kaaPixmapPrivateIndex, + sizeof (KaaPixmapPrivRec))) + return FALSE; } else { diff --git a/hw/kdrive/src/kasync.c b/hw/kdrive/src/kasync.c index 560e7243e948f3d1b7a00ce59b207bfad901ff0a..3c9158d9f239c2504da4454a5c671e61da0ad0ee 100644 --- a/hw/kdrive/src/kasync.c +++ b/hw/kdrive/src/kasync.c @@ -63,8 +63,7 @@ RegionPtr KdCheckCopyArea (DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, int srcx, int srcy, int w, int h, int dstx, int dsty) { - if (pSrc->type == DRAWABLE_WINDOW || pDst->type == DRAWABLE_WINDOW) - KdCheckSync (pSrc->pScreen); + KdCheckSync (pSrc->pScreen); return fbCopyArea (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty); } @@ -73,8 +72,7 @@ KdCheckCopyPlane (DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, int srcx, int srcy, int w, int h, int dstx, int dsty, unsigned long bitPlane) { - if (pSrc->type == DRAWABLE_WINDOW || pDst->type == DRAWABLE_WINDOW) - KdCheckSync (pSrc->pScreen); + KdCheckSync (pSrc->pScreen); return fbCopyPlane (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, bitPlane); } @@ -199,8 +197,7 @@ KdCheckGetSpans (DrawablePtr pDrawable, int nspans, char *pdstStart) { - if (pDrawable->type != DRAWABLE_PIXMAP) - KdCheckSync(pDrawable->pScreen); + KdCheckSync(pDrawable->pScreen); fbGetSpans (pDrawable, wMax, ppt, pwidth, nspans, pdstStart); } @@ -308,3 +305,11 @@ const GCOps kdAsyncPixmapGCOps = { ,NULL #endif }; + +void +KdAssertSync (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdCardInfo *card = pScreenPriv->card; + assert (!card->needSync); +} diff --git a/hw/kdrive/src/kdrive.c b/hw/kdrive/src/kdrive.c index cead4302daac41a6a0ff19b2b8e8a3a77a99ff38..a3ed0e76439df1eb80aded17460af94ba7cfc3a9 100644 --- a/hw/kdrive/src/kdrive.c +++ b/hw/kdrive/src/kdrive.c @@ -844,6 +844,9 @@ KdCloseScreen (int index, ScreenPtr pScreen) pScreen->CloseScreen = pScreenPriv->CloseScreen; ret = (*pScreen->CloseScreen) (index, pScreen); + if (screen->off_screen_size > 0) + KdOffscreenFini (pScreen); + if (pScreenPriv->dpmsState != KD_DPMS_NORMAL) (*card->cfuncs->dpms) (pScreen, KD_DPMS_NORMAL); diff --git a/hw/kdrive/src/kdrive.h b/hw/kdrive/src/kdrive.h index 8b51f12cdb0f7050ab74cb79ba9f0e33ae175423..71d58e009dda1a28f82b3a31e55d786b2755cad4 100644 --- a/hw/kdrive/src/kdrive.h +++ b/hw/kdrive/src/kdrive.h @@ -267,7 +267,6 @@ typedef struct _KdOffscreenArea { int offset; int size; pointer privData; - Bool swappedOut; } KdOffscreenArea; extern const KdMonitorTiming kdMonitorTimings[]; @@ -753,6 +752,22 @@ KdRandRGetTiming (ScreenPtr pScreen, void KdPictureInitAsync (ScreenPtr pScreen); +#ifdef RENDER +void +KdCheckComposite (CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height); +#endif + /* kshadow.c */ Bool KdShadowScreenInit (KdScreenInfo *screen); @@ -771,7 +786,7 @@ int KdFrameBufferSize (CARD8 *base, int max); /* koffscreen.c */ -typedef void (*KdOffscreenMoveDataProc) (KdOffscreenArea *area); +typedef void (*KdOffscreenSaveProc) (KdOffscreenArea *area); Bool KdOffscreenInit (ScreenPtr pScreen); @@ -779,8 +794,7 @@ KdOffscreenInit (ScreenPtr pScreen); KdOffscreenArea * KdOffscreenAlloc (ScreenPtr pScreen, int size, int align, Bool locked, - KdOffscreenMoveDataProc moveIn, - KdOffscreenMoveDataProc moveOut, + KdOffscreenSaveProc save, pointer privData); void @@ -792,6 +806,9 @@ KdOffscreenSwapOut (ScreenPtr pScreen); void KdOffscreenSwapIn (ScreenPtr pScreen); +void +KdOffscreenFini (ScreenPtr pScreen); + /* function prototypes to be implemented by the drivers */ void InitCard (char *name); diff --git a/hw/kdrive/src/koffscreen.c b/hw/kdrive/src/koffscreen.c index 62df0fcd684c01a66e6ecabc037fe5e2b60275f6..1454c4a64de750abb7ca8c0e5d9706d884d947ba 100644 --- a/hw/kdrive/src/koffscreen.c +++ b/hw/kdrive/src/koffscreen.c @@ -28,91 +28,171 @@ #endif #include "kdrive.h" +#define DEBUG_OFFSCREEN 0 +#if DEBUG_OFFSCREEN +#define DBG_OFFSCREEN(a) ErrorF a +#else +#define DBG_OFFSCREEN(a) +#endif + typedef struct _RealOffscreenArea { KdOffscreenArea area; - KdOffscreenMoveDataProc moveIn; - KdOffscreenMoveDataProc moveOut; + KdOffscreenSaveProc save; Bool locked; - struct _RealOffscreenArea *next; struct _RealOffscreenArea *prev; + struct _RealOffscreenArea *next; } RealOffscreenArea; +#if DEBUG_OFFSCREEN +static void +KdOffscreenValidate (ScreenPtr pScreen) +{ + KdScreenPriv (pScreen); + RealOffscreenArea *prev = 0, *area; + + assert (pScreenPriv->screen->off_screen_areas->area.offset == 0); + for (area = pScreenPriv->screen->off_screen_areas; area; area = area->next) + { + if (prev) + assert (prev->area.offset + prev->area.size == area->area.offset); + + prev = area; + } + assert (prev->area.offset + prev->area.size == pScreenPriv->screen->off_screen_size); +} +#else +#define KdOffscreenValidate(s) +#endif + +static void +KdOffscreenKickOut (KdOffscreenArea *area) +{ + RealOffscreenArea *real_area = (RealOffscreenArea *) area; + KdCheckSync (area->screen); + if (real_area->save) + (*real_area->save) (area); + KdOffscreenFree (area); +} + KdOffscreenArea * KdOffscreenAlloc (ScreenPtr pScreen, int size, int align, Bool locked, - KdOffscreenMoveDataProc moveIn, - KdOffscreenMoveDataProc moveOut, + KdOffscreenSaveProc save, pointer privData) { - RealOffscreenArea *area; + RealOffscreenArea *area, **prev; KdScreenPriv (pScreen); int tmp, real_size; - + KdOffscreenValidate (pScreen); if (!align) align = 1; + if (!size) + { + DBG_OFFSCREEN (("Alloc 0x%x -> EMPTY\n", size)); + return NULL; + } + + /* throw out requests that cannot fit */ + if (size > pScreenPriv->screen->off_screen_size) + { + DBG_OFFSCREEN (("Alloc 0x%x -> TOBIG\n", size)); + return NULL; + } + +retry: + /* Go through the areas */ - area = pScreenPriv->screen->off_screen_areas; - while (area != NULL) + for (area = pScreenPriv->screen->off_screen_areas; area; area = area->next) { - if (area->area.screen != NULL) - { - area = area->next; + /* skip allocated areas */ + if (area->area.screen) continue; - } + /* adjust size to match alignment requirement */ real_size = size; - tmp = (area->area.offset + area->area.size - size) % align; - + tmp = area->area.offset % align; if (tmp) real_size += (align - tmp); + /* does it fit? */ if (real_size <= area->area.size) { RealOffscreenArea *new_area; - if (real_size == area->area.size) + /* save extra space in new area */ + if (real_size < area->area.size) { - area->area.screen = pScreen; - area->area.privData = privData; - area->area.swappedOut = FALSE; - area->locked = locked; - area->moveIn = moveIn; - area->moveOut = moveOut; - - return (KdOffscreenArea *)area; + new_area = xalloc (sizeof (RealOffscreenArea)); + if (!new_area) + return NULL; + new_area->area.offset = area->area.offset + real_size; + new_area->area.size = area->area.size - real_size; + new_area->area.screen = 0; + new_area->locked = FALSE; + new_area->save = 0; + if ((new_area->next = area->next)) + new_area->next->prev = new_area; + new_area->prev = area; + area->next = new_area; + area->area.size = real_size; } - - /* Create a new area */ - new_area = xalloc (sizeof (RealOffscreenArea)); - new_area->area.offset = area->area.offset + area->area.size - real_size; - new_area->area.size = real_size; - new_area->area.screen = pScreen; - new_area->area.swappedOut = FALSE; - new_area->locked = locked; - new_area->moveIn = moveIn; - new_area->moveOut = moveOut; - - area->area.size -= real_size; - - new_area->prev = area; - new_area->next = area->next; + area->area.screen = pScreen; + area->area.privData = privData; + area->locked = locked; + area->save = save; - if (area->next) - area->next->prev = new_area; - area->next = new_area; - - return (KdOffscreenArea *)new_area; + KdOffscreenValidate (pScreen); + + DBG_OFFSCREEN (("Alloc 0x%x -> 0x%x\n", size, area->area.offset)); + return &area->area; + } + } + + /* + * Kick out existing users. This is pretty simplistic; it just + * keeps deleting areas until the first area is free and has enough room + */ + + prev = (RealOffscreenArea **) &pScreenPriv->screen->off_screen_areas; + while ((area = *prev)) + { + if (area->area.screen && !area->locked) + { + KdOffscreenKickOut (&area->area); + continue; } + /* adjust size to match alignment requirement */ + real_size = size; + tmp = area->area.offset % align; + if (tmp) + real_size += (align - tmp); + /* does it fit? */ + if (real_size <= area->area.size) + goto retry; + + /* kick out the next area */ area = area->next; + if (!area) + break; + /* skip over locked areas */ + if (area->locked) + { + prev = &area->next; + continue; + } + assert (area->area.screen); + KdOffscreenKickOut (&area->area); } - + + DBG_OFFSCREEN (("Alloc 0x%x -> NOSPACE\n", size)); /* Could not allocate memory */ + KdOffscreenValidate (pScreen); return NULL; } @@ -120,68 +200,73 @@ void KdOffscreenSwapOut (ScreenPtr pScreen) { KdScreenPriv (pScreen); - RealOffscreenArea *area = pScreenPriv->screen->off_screen_areas; - while (area) + KdOffscreenValidate (pScreen); + /* loop until a single free area spans the space */ + for (;;) { - if (area->area.screen && area->moveOut) - (*area->moveOut) ((KdOffscreenArea *)area); - - area->area.swappedOut = TRUE; - + RealOffscreenArea *area = pScreenPriv->screen->off_screen_areas; + + if (!area) + break; + if (area->area.screen) + { + KdOffscreenKickOut (&area->area); + continue; + } area = area->next; + if (!area) + break; + assert (area->area.screen); + KdOffscreenKickOut (&area->area); + KdOffscreenValidate (pScreen); } + KdOffscreenValidate (pScreen); } void KdOffscreenSwapIn (ScreenPtr pScreen) { - KdScreenPriv (pScreen); - RealOffscreenArea *area = pScreenPriv->screen->off_screen_areas; - - while (area) - { - if (area->area.screen && area->moveIn) - (*area->moveIn) ((KdOffscreenArea *)area); + /* nothing to do here; page in on usage */ +} - area->area.swappedOut = FALSE; - area = area->next; - } +/* merge the next free area into this one */ +static void +KdOffscreenMerge (KdOffscreenArea *area) +{ + RealOffscreenArea *real_area = (RealOffscreenArea *) area; + RealOffscreenArea *next = real_area->next; + + /* account for space */ + real_area->area.size += next->area.size; + /* frob pointers */ + if ((real_area->next = next->next)) + real_area->next->prev = real_area; + xfree (next); } void KdOffscreenFree (KdOffscreenArea *area) { - RealOffscreenArea *real_area = (RealOffscreenArea *)area; + ScreenPtr pScreen = area->screen; + RealOffscreenArea *real_area = (RealOffscreenArea *) area; + RealOffscreenArea *next = real_area->next; + RealOffscreenArea *prev = real_area->prev; - real_area->area.screen = NULL; - - if (real_area && real_area->next && !real_area->next->area.screen) - { - RealOffscreenArea *tmp; - - real_area->next->prev = real_area->prev; - if (real_area->prev) - real_area->prev->next = real_area->next; + DBG_OFFSCREEN (("Free 0x%x -> 0x%x\n", area->size, area->offset)); + KdOffscreenValidate (pScreen); - real_area->next->area.size += real_area->area.size; - real_area->next->area.offset = real_area->area.offset; + area->screen = NULL; - tmp = real_area->next; - xfree (real_area); - real_area = tmp; - } + /* link with next area if free */ + if (next && !next->area.screen) + KdOffscreenMerge (&real_area->area); - if (real_area->prev && !real_area->prev->area.screen) - { - real_area->prev->next = real_area->next; - if (real_area->next) - real_area->next->prev = real_area->prev; - - real_area->prev->area.size += real_area->area.size; - - xfree (real_area); - } + /* link with prev area if free */ + if (prev && !prev->area.screen) + KdOffscreenMerge (&prev->area); + + KdOffscreenValidate (pScreen); } Bool @@ -199,13 +284,29 @@ KdOffscreenInit (ScreenPtr pScreen) area->area.screen = NULL; area->area.offset = pScreenPriv->screen->off_screen_base; area->area.size = pScreenPriv->screen->off_screen_size; - area->area.swappedOut = FALSE; + area->save = 0; + area->locked = FALSE; area->next = NULL; area->prev = NULL; /* Add it to the free areas */ pScreenPriv->screen->off_screen_areas = area; + KdOffscreenValidate (pScreen); + return TRUE; } +void +KdOffscreenFini (ScreenPtr pScreen) +{ + KdScreenPriv (pScreen); + RealOffscreenArea *area; + + /* just free all of the area records */ + while ((area = pScreenPriv->screen->off_screen_areas)) + { + pScreenPriv->screen->off_screen_areas = area->next; + xfree (area); + } +}