diff options
Diffstat (limited to 'hw/kdrive/src/koffscreen.c')
-rw-r--r-- | hw/kdrive/src/koffscreen.c | 84 |
1 files changed, 63 insertions, 21 deletions
diff --git a/hw/kdrive/src/koffscreen.c b/hw/kdrive/src/koffscreen.c index 09e7273d0..ef42ebbe8 100644 --- a/hw/kdrive/src/koffscreen.c +++ b/hw/kdrive/src/koffscreen.c @@ -26,6 +26,7 @@ #include <config.h> #endif #include "kdrive.h" +#include "kaa.h" #define DEBUG_OFFSCREEN 0 #if DEBUG_OFFSCREEN @@ -69,9 +70,9 @@ KdOffscreenAlloc (ScreenPtr pScreen, int size, int align, KdOffscreenSaveProc save, pointer privData) { - KdOffscreenArea *area, **prev; + KdOffscreenArea *area, *begin, *best; KdScreenPriv (pScreen); - int tmp, real_size = 0; + int tmp, real_size = 0, best_score; KdOffscreenValidate (pScreen); if (!align) @@ -90,7 +91,7 @@ KdOffscreenAlloc (ScreenPtr pScreen, int size, int align, return NULL; } - /* Go through the areas */ + /* Try to find a free space that'll fit. */ for (area = pScreenPriv->off_screen_areas; area; area = area->next) { /* skip allocated areas */ @@ -117,38 +118,46 @@ KdOffscreenAlloc (ScreenPtr pScreen, int size, int align, */ /* prev points at the first object to boot */ - prev = (KdOffscreenArea **) &pScreenPriv->off_screen_areas; - while ((area = *prev)) + best = NULL; + best_score = MAXINT; + for (begin = pScreenPriv->off_screen_areas; begin != NULL; + begin = begin->next) { - int avail; - KdOffscreenArea *scan, **nprev; - + int avail, score; + KdOffscreenArea *scan; + + if (begin->state == KdOffscreenLocked) + continue; + /* adjust size to match alignment requirement */ real_size = size; - tmp = area->offset % align; + tmp = begin->offset % align; if (tmp) real_size += (align - tmp); avail = 0; - /* now see if we can make room here */ - for (nprev = prev; (scan = *nprev); nprev = &scan->next) + score = 0; + /* now see if we can make room here, and how "costly" it'll be. */ + for (scan = begin; scan != NULL; scan = scan->next) { - if (scan->state == KdOffscreenLocked) + if (scan->state == KdOffscreenLocked) { + /* Can't make room here, start after this locked area. */ + begin = scan->next; break; + } + /* Score should only be non-zero for KdOffscreenRemovable */ + score += scan->score; avail += scan->size; if (avail >= real_size) break; } - /* space? */ - if (avail >= real_size) - break; - - /* nope, try the next area */ - prev = nprev; - /* skip to next unlocked area */ - while ((area = *prev) && area->state == KdOffscreenLocked) - prev = &area->next; + /* Is it the best option we've found so far? */ + if (avail >= real_size && score < best_score) { + best = begin; + best_score = score; + } } + area = best; if (!area) { DBG_OFFSCREEN (("Alloc 0x%x -> NOSPACE\n", size)); @@ -157,6 +166,12 @@ KdOffscreenAlloc (ScreenPtr pScreen, int size, int align, return NULL; } + /* adjust size to match alignment requirement */ + real_size = size; + tmp = begin->offset % align; + if (tmp) + real_size += (align - tmp); + /* * Kick out first area if in use */ @@ -182,6 +197,7 @@ KdOffscreenAlloc (ScreenPtr pScreen, int size, int align, new_area->size = area->size - real_size; new_area->state = KdOffscreenAvail; new_area->save = 0; + new_area->score = 0; new_area->next = area->next; area->next = new_area; area->size = real_size; @@ -195,6 +211,7 @@ KdOffscreenAlloc (ScreenPtr pScreen, int size, int align, area->state = KdOffscreenRemovable; area->privData = privData; area->save = save; + area->score = 0; area->save_offset = area->offset; area->offset = (area->offset + align - 1) & ~(align - 1); @@ -264,6 +281,7 @@ KdOffscreenFree (ScreenPtr pScreen, KdOffscreenArea *area) area->state = KdOffscreenAvail; area->save = 0; area->offset = area->save_offset; + area->score = 0; /* * Find previous area @@ -290,6 +308,29 @@ KdOffscreenFree (ScreenPtr pScreen, KdOffscreenArea *area) return area; } +void +KdOffscreenMarkUsed (PixmapPtr pPixmap) +{ + KaaPixmapPriv (pPixmap); + KdScreenPriv (pPixmap->drawable.pScreen); + static int iter = 0; + + if (!pKaaPixmap->area) + return; + + /* The numbers here are arbitrary. We may want to tune these. */ + pKaaPixmap->area->score += 100; + if (++iter == 10) { + KdOffscreenArea *area; + for (area = pScreenPriv->off_screen_areas; area != NULL; + area = area->next) + { + if (area->state == KdOffscreenRemovable) + area->score = (area->score * 7) / 8; + } + } +} + Bool KdOffscreenInit (ScreenPtr pScreen) { @@ -307,6 +348,7 @@ KdOffscreenInit (ScreenPtr pScreen) area->size = pScreenPriv->screen->memory_size - area->offset; area->save = 0; area->next = NULL; + area->score = 0; /* Add it to the free areas */ pScreenPriv->off_screen_areas = area; |