/** * exaOffscreenFree frees an allocation. * * @param pScreen current screen * @param area offscreen area to free * * exaOffscreenFree frees an allocation created by exaOffscreenAlloc. Note that * the save callback of the area is not called, and it is up to the driver to * do any cleanup necessary as a result. * * @return pointer to the newly freed area. This behavior should not be relied * on. */ ExaOffscreenArea * exaOffscreenFree (ScreenPtr pScreen, ExaOffscreenArea *area) { ExaScreenPriv(pScreen); ExaOffscreenArea *next = area->next; ExaOffscreenArea *prev; DBG_OFFSCREEN (("Free 0x%x -> 0x%x (0x%x)\n", area->size, area->base_offset, area->offset)); ExaOffscreenValidate (pScreen); area->state = ExaOffscreenAvail; area->save = NULL; area->score = 0; /* * Find previous area */ if (area == pExaScr->info->offScreenAreas) prev = NULL; else for (prev = pExaScr->info->offScreenAreas; prev; prev = prev->next) if (prev->next == area) break; /* link with next area if free */ if (next && next->state == ExaOffscreenAvail) ExaOffscreenMerge (area); /* link with prev area if free */ if (prev && prev->state == ExaOffscreenAvail) { area = prev; ExaOffscreenMerge (area); } ExaOffscreenValidate (pScreen); DBG_OFFSCREEN(("\tdone freeing\n")); return area; }
KdOffscreenArea * KdOffscreenFree (ScreenPtr pScreen, KdOffscreenArea *area) { KdScreenPriv(pScreen); KdOffscreenArea *next = area->next; KdOffscreenArea *prev; DBG_OFFSCREEN (("Free 0x%x -> 0x%x\n", area->size, area->offset)); KdOffscreenValidate (pScreen); area->state = KdOffscreenAvail; area->save = 0; area->offset = area->save_offset; area->score = 0; /* * Find previous area */ if (area == pScreenPriv->off_screen_areas) prev = 0; else for (prev = pScreenPriv->off_screen_areas; prev; prev = prev->next) if (prev->next == area) break; /* link with next area if free */ if (next && next->state == KdOffscreenAvail) KdOffscreenMerge (area); /* link with prev area if free */ if (prev && prev->state == KdOffscreenAvail) { area = prev; KdOffscreenMerge (area); } KdOffscreenValidate (pScreen); return area; }
KdOffscreenArea * KdOffscreenAlloc (ScreenPtr pScreen, int size, int align, Bool locked, KdOffscreenSaveProc save, pointer privData) { KdOffscreenArea *area, *begin, *best; KdScreenPriv (pScreen); int tmp, real_size = 0, best_score; 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->memory_size - pScreenPriv->screen->off_screen_base)) { DBG_OFFSCREEN (("Alloc 0x%x -> TOBIG\n", size)); return NULL; } /* Try to find a free space that'll fit. */ for (area = pScreenPriv->off_screen_areas; area; area = area->next) { /* skip allocated areas */ if (area->state != KdOffscreenAvail) continue; /* adjust size to match alignment requirement */ real_size = size; tmp = area->offset % align; if (tmp) real_size += (align - tmp); /* does it fit? */ if (real_size <= area->size) break; } if (!area) { /* * Kick out existing users to make space. * * First, locate a region which can hold the desired object. */ /* prev points at the first object to boot */ best = NULL; best_score = MAXINT; for (begin = pScreenPriv->off_screen_areas; begin != NULL; begin = begin->next) { int avail, score; KdOffscreenArea *scan; if (begin->state == KdOffscreenLocked) continue; /* adjust size to match alignment requirement */ real_size = size; tmp = begin->offset % align; if (tmp) real_size += (align - tmp); avail = 0; 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) { /* 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; } /* 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)); /* Could not allocate memory */ KdOffscreenValidate (pScreen); 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 */ if (area->state != KdOffscreenAvail) area = KdOffscreenKickOut (pScreen, area); /* * Now get the system to merge the other needed areas together */ while (area->size < real_size) { assert (area->next && area->next->state == KdOffscreenRemovable); (void) KdOffscreenKickOut (pScreen, area->next); } } /* save extra space in new area */ if (real_size < area->size) { KdOffscreenArea *new_area = xalloc (sizeof (KdOffscreenArea)); if (!new_area) return NULL; new_area->offset = area->offset + real_size; 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; } /* * Mark this area as in use */ if (locked) area->state = KdOffscreenLocked; else area->state = KdOffscreenRemovable; area->privData = privData; area->save = save; area->score = 0; area->save_offset = area->offset; { int tmp = area->offset % align; if (tmp) area->offset += (align - tmp); } KdOffscreenValidate (pScreen); DBG_OFFSCREEN (("Alloc 0x%x -> 0x%x\n", size, area->offset)); return area; }