xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

exa_offscreen.c (20668B)


      1 /*
      2  * Copyright © 2003 Anders Carlsson
      3  *
      4  * Permission to use, copy, modify, distribute, and sell this software and its
      5  * documentation for any purpose is hereby granted without fee, provided that
      6  * the above copyright notice appear in all copies and that both that
      7  * copyright notice and this permission notice appear in supporting
      8  * documentation, and that the name of Anders Carlsson not be used in
      9  * advertising or publicity pertaining to distribution of the software without
     10  * specific, written prior permission.  Anders Carlsson makes no
     11  * representations about the suitability of this software for any purpose.  It
     12  * is provided "as is" without express or implied warranty.
     13  *
     14  * ANDERS CARLSSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
     15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
     16  * EVENT SHALL ANDERS CARLSSON BE LIABLE FOR ANY SPECIAL, INDIRECT OR
     17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
     18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
     19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
     20  * PERFORMANCE OF THIS SOFTWARE.
     21  */
     22 
     23 /** @file
     24  * This allocator allocates blocks of memory by maintaining a list of areas.
     25  * When allocating, the contiguous block of areas with the minimum eviction
     26  * cost is found and evicted in order to make room for the new allocation.
     27  */
     28 
     29 #include "exa_priv.h"
     30 
     31 #include <limits.h>
     32 #include <assert.h>
     33 #include <stdlib.h>
     34 
     35 #if DEBUG_OFFSCREEN
     36 #define DBG_OFFSCREEN(a) ErrorF a
     37 #else
     38 #define DBG_OFFSCREEN(a)
     39 #endif
     40 
     41 #if DEBUG_OFFSCREEN
     42 static void
     43 ExaOffscreenValidate(ScreenPtr pScreen)
     44 {
     45     ExaScreenPriv(pScreen);
     46     ExaOffscreenArea *prev = 0, *area;
     47 
     48     assert(pExaScr->info->offScreenAreas->base_offset ==
     49            pExaScr->info->offScreenBase);
     50     for (area = pExaScr->info->offScreenAreas; area; area = area->next) {
     51         assert(area->offset >= area->base_offset);
     52         assert(area->offset < (area->base_offset + area->size));
     53         if (prev)
     54             assert(prev->base_offset + prev->size == area->base_offset);
     55         prev = area;
     56     }
     57     assert(prev->base_offset + prev->size == pExaScr->info->memorySize);
     58 }
     59 #else
     60 #define ExaOffscreenValidate(s)
     61 #endif
     62 
     63 static ExaOffscreenArea *
     64 ExaOffscreenKickOut(ScreenPtr pScreen, ExaOffscreenArea * area)
     65 {
     66     if (area->save)
     67         (*area->save) (pScreen, area);
     68     return exaOffscreenFree(pScreen, area);
     69 }
     70 
     71 static void
     72 exaUpdateEvictionCost(ExaOffscreenArea * area, unsigned offScreenCounter)
     73 {
     74     unsigned age;
     75 
     76     if (area->state == ExaOffscreenAvail)
     77         return;
     78 
     79     age = offScreenCounter - area->last_use;
     80 
     81     /* This is unlikely to happen, but could result in a division by zero... */
     82     if (age > (UINT_MAX / 2)) {
     83         age = UINT_MAX / 2;
     84         area->last_use = offScreenCounter - age;
     85     }
     86 
     87     area->eviction_cost = area->size / age;
     88 }
     89 
     90 static ExaOffscreenArea *
     91 exaFindAreaToEvict(ExaScreenPrivPtr pExaScr, int size, int align)
     92 {
     93     ExaOffscreenArea *begin, *end, *best;
     94     unsigned cost, best_cost;
     95     int avail, real_size;
     96 
     97     best_cost = UINT_MAX;
     98     begin = end = pExaScr->info->offScreenAreas;
     99     avail = 0;
    100     cost = 0;
    101     best = 0;
    102 
    103     while (end != NULL) {
    104  restart:
    105         while (begin != NULL && begin->state == ExaOffscreenLocked)
    106             begin = end = begin->next;
    107 
    108         if (begin == NULL)
    109             break;
    110 
    111         /* adjust size needed to account for alignment loss for this area */
    112         real_size = size + (begin->base_offset + begin->size - size) % align;
    113 
    114         while (avail < real_size && end != NULL) {
    115             if (end->state == ExaOffscreenLocked) {
    116                 /* Can't more room here, restart after this locked area */
    117                 avail = 0;
    118                 cost = 0;
    119                 begin = end;
    120                 goto restart;
    121             }
    122             avail += end->size;
    123             exaUpdateEvictionCost(end, pExaScr->offScreenCounter);
    124             cost += end->eviction_cost;
    125             end = end->next;
    126         }
    127 
    128         /* Check the cost, update best */
    129         if (avail >= real_size && cost < best_cost) {
    130             best = begin;
    131             best_cost = cost;
    132         }
    133 
    134         avail -= begin->size;
    135         cost -= begin->eviction_cost;
    136         begin = begin->next;
    137     }
    138 
    139     return best;
    140 }
    141 
    142 /**
    143  * exaOffscreenAlloc allocates offscreen memory
    144  *
    145  * @param pScreen current screen
    146  * @param size size in bytes of the allocation
    147  * @param align byte alignment requirement for the offset of the allocated area
    148  * @param locked whether the allocated area is locked and can't be kicked out
    149  * @param save callback for when the area is evicted from memory
    150  * @param privdata private data for the save callback.
    151  *
    152  * Allocates offscreen memory from the device associated with pScreen.  size
    153  * and align determine where and how large the allocated area is, and locked
    154  * will mark whether it should be held in card memory.  privdata may be any
    155  * pointer for the save callback when the area is removed.
    156  *
    157  * Note that locked areas do get evicted on VT switch unless the driver
    158  * requested version 2.1 or newer behavior.  In that case, the save callback is
    159  * still called.
    160  */
    161 ExaOffscreenArea *
    162 exaOffscreenAlloc(ScreenPtr pScreen, int size, int align,
    163                   Bool locked, ExaOffscreenSaveProc save, void *privData)
    164 {
    165     ExaOffscreenArea *area;
    166 
    167     ExaScreenPriv(pScreen);
    168     int real_size = 0, largest_avail = 0;
    169 
    170 #if DEBUG_OFFSCREEN
    171     static int number = 0;
    172 
    173     ErrorF("================= ============ allocating a new pixmap %d\n",
    174            ++number);
    175 #endif
    176 
    177     ExaOffscreenValidate(pScreen);
    178     if (!align)
    179         align = 1;
    180 
    181     if (!size) {
    182         DBG_OFFSCREEN(("Alloc 0x%x -> EMPTY\n", size));
    183         return NULL;
    184     }
    185 
    186     /* throw out requests that cannot fit */
    187     if (size > (pExaScr->info->memorySize - pExaScr->info->offScreenBase)) {
    188         DBG_OFFSCREEN(("Alloc 0x%x vs (0x%lx) -> TOBIG\n", size,
    189                        pExaScr->info->memorySize -
    190                        pExaScr->info->offScreenBase));
    191         return NULL;
    192     }
    193 
    194     /* Try to find a free space that'll fit. */
    195     for (area = pExaScr->info->offScreenAreas; area; area = area->next) {
    196         /* skip allocated areas */
    197         if (area->state != ExaOffscreenAvail)
    198             continue;
    199 
    200         /* adjust size to match alignment requirement */
    201         real_size = size + (area->base_offset + area->size - size) % align;
    202 
    203         /* does it fit? */
    204         if (real_size <= area->size)
    205             break;
    206 
    207         if (area->size > largest_avail)
    208             largest_avail = area->size;
    209     }
    210 
    211     if (!area) {
    212         area = exaFindAreaToEvict(pExaScr, size, align);
    213 
    214         if (!area) {
    215             DBG_OFFSCREEN(("Alloc 0x%x -> NOSPACE\n", size));
    216             /* Could not allocate memory */
    217             ExaOffscreenValidate(pScreen);
    218             return NULL;
    219         }
    220 
    221         /* adjust size needed to account for alignment loss for this area */
    222         real_size = size + (area->base_offset + area->size - size) % align;
    223 
    224         /*
    225          * Kick out first area if in use
    226          */
    227         if (area->state != ExaOffscreenAvail)
    228             area = ExaOffscreenKickOut(pScreen, area);
    229         /*
    230          * Now get the system to merge the other needed areas together
    231          */
    232         while (area->size < real_size) {
    233             assert(area->next);
    234             assert(area->next->state == ExaOffscreenRemovable);
    235             (void) ExaOffscreenKickOut(pScreen, area->next);
    236         }
    237     }
    238 
    239     /* save extra space in new area */
    240     if (real_size < area->size) {
    241         ExaOffscreenArea *new_area = malloc(sizeof(ExaOffscreenArea));
    242 
    243         if (!new_area)
    244             return NULL;
    245         new_area->base_offset = area->base_offset;
    246 
    247         new_area->offset = new_area->base_offset;
    248         new_area->align = 0;
    249         new_area->size = area->size - real_size;
    250         new_area->state = ExaOffscreenAvail;
    251         new_area->save = NULL;
    252         new_area->last_use = 0;
    253         new_area->eviction_cost = 0;
    254         new_area->next = area;
    255         new_area->prev = area->prev;
    256         if (area->prev->next)
    257             area->prev->next = new_area;
    258         else
    259             pExaScr->info->offScreenAreas = new_area;
    260         area->prev = new_area;
    261         area->base_offset = new_area->base_offset + new_area->size;
    262         area->size = real_size;
    263     }
    264     else
    265         pExaScr->numOffscreenAvailable--;
    266 
    267     /*
    268      * Mark this area as in use
    269      */
    270     if (locked)
    271         area->state = ExaOffscreenLocked;
    272     else
    273         area->state = ExaOffscreenRemovable;
    274     area->privData = privData;
    275     area->save = save;
    276     area->last_use = pExaScr->offScreenCounter++;
    277     area->offset = (area->base_offset + align - 1);
    278     area->offset -= area->offset % align;
    279     area->align = align;
    280 
    281     ExaOffscreenValidate(pScreen);
    282 
    283     DBG_OFFSCREEN(("Alloc 0x%x -> 0x%x (0x%x)\n", size,
    284                    area->base_offset, area->offset));
    285     return area;
    286 }
    287 
    288 /**
    289  * Ejects all offscreen areas, and uninitializes the offscreen memory manager.
    290  */
    291 void
    292 ExaOffscreenSwapOut(ScreenPtr pScreen)
    293 {
    294     ExaScreenPriv(pScreen);
    295 
    296     ExaOffscreenValidate(pScreen);
    297     /* loop until a single free area spans the space */
    298     for (;;) {
    299         ExaOffscreenArea *area = pExaScr->info->offScreenAreas;
    300 
    301         if (!area)
    302             break;
    303         if (area->state == ExaOffscreenAvail) {
    304             area = area->next;
    305             if (!area)
    306                 break;
    307         }
    308         assert(area->state != ExaOffscreenAvail);
    309         (void) ExaOffscreenKickOut(pScreen, area);
    310         ExaOffscreenValidate(pScreen);
    311     }
    312     ExaOffscreenValidate(pScreen);
    313     ExaOffscreenFini(pScreen);
    314 }
    315 
    316 /** Ejects all pixmaps managed by EXA. */
    317 static void
    318 ExaOffscreenEjectPixmaps(ScreenPtr pScreen)
    319 {
    320     ExaScreenPriv(pScreen);
    321 
    322     ExaOffscreenValidate(pScreen);
    323     /* loop until a single free area spans the space */
    324     for (;;) {
    325         ExaOffscreenArea *area;
    326 
    327         for (area = pExaScr->info->offScreenAreas; area != NULL;
    328              area = area->next) {
    329             if (area->state == ExaOffscreenRemovable &&
    330                 area->save == exaPixmapSave) {
    331                 (void) ExaOffscreenKickOut(pScreen, area);
    332                 ExaOffscreenValidate(pScreen);
    333                 break;
    334             }
    335         }
    336         if (area == NULL)
    337             break;
    338     }
    339     ExaOffscreenValidate(pScreen);
    340 }
    341 
    342 void
    343 ExaOffscreenSwapIn(ScreenPtr pScreen)
    344 {
    345     exaOffscreenInit(pScreen);
    346 }
    347 
    348 /**
    349  * Prepares EXA for disabling of FB access, or restoring it.
    350  *
    351  * In version 2.1, the disabling results in pixmaps being ejected, while other
    352  * allocations remain.  With this plus the prevention of migration while
    353  * swappedOut is set, EXA by itself should not cause any access of the
    354  * framebuffer to occur while swapped out.  Any remaining issues are the
    355  * responsibility of the driver.
    356  *
    357  * Prior to version 2.1, all allocations, including locked ones, are ejected
    358  * when access is disabled, and the allocator is torn down while swappedOut
    359  * is set.  This is more drastic, and caused implementation difficulties for
    360  * many drivers that could otherwise handle the lack of FB access while
    361  * swapped out.
    362  */
    363 void
    364 exaEnableDisableFBAccess(ScreenPtr pScreen, Bool enable)
    365 {
    366     ExaScreenPriv(pScreen);
    367 
    368     if (pExaScr->info->flags & EXA_HANDLES_PIXMAPS)
    369         return;
    370 
    371     if (!enable && pExaScr->disableFbCount++ == 0) {
    372         if (pExaScr->info->exa_minor < 1)
    373             ExaOffscreenSwapOut(pScreen);
    374         else
    375             ExaOffscreenEjectPixmaps(pScreen);
    376         pExaScr->swappedOut = TRUE;
    377     }
    378 
    379     if (enable && --pExaScr->disableFbCount == 0) {
    380         if (pExaScr->info->exa_minor < 1)
    381             ExaOffscreenSwapIn(pScreen);
    382         pExaScr->swappedOut = FALSE;
    383     }
    384 }
    385 
    386 /* merge the next free area into this one */
    387 static void
    388 ExaOffscreenMerge(ExaScreenPrivPtr pExaScr, ExaOffscreenArea * area)
    389 {
    390     ExaOffscreenArea *next = area->next;
    391 
    392     /* account for space */
    393     area->size += next->size;
    394     /* frob pointer */
    395     area->next = next->next;
    396     if (area->next)
    397         area->next->prev = area;
    398     else
    399         pExaScr->info->offScreenAreas->prev = area;
    400     free(next);
    401 
    402     pExaScr->numOffscreenAvailable--;
    403 }
    404 
    405 /**
    406  * exaOffscreenFree frees an allocation.
    407  *
    408  * @param pScreen current screen
    409  * @param area offscreen area to free
    410  *
    411  * exaOffscreenFree frees an allocation created by exaOffscreenAlloc.  Note that
    412  * the save callback of the area is not called, and it is up to the driver to
    413  * do any cleanup necessary as a result.
    414  *
    415  * @return pointer to the newly freed area. This behavior should not be relied
    416  * on.
    417  */
    418 ExaOffscreenArea *
    419 exaOffscreenFree(ScreenPtr pScreen, ExaOffscreenArea * area)
    420 {
    421     ExaScreenPriv(pScreen);
    422     ExaOffscreenArea *next = area->next;
    423     ExaOffscreenArea *prev;
    424 
    425     DBG_OFFSCREEN(("Free 0x%x -> 0x%x (0x%x)\n", area->size,
    426                    area->base_offset, area->offset));
    427     ExaOffscreenValidate(pScreen);
    428 
    429     area->state = ExaOffscreenAvail;
    430     area->save = NULL;
    431     area->last_use = 0;
    432     area->eviction_cost = 0;
    433     /*
    434      * Find previous area
    435      */
    436     if (area == pExaScr->info->offScreenAreas)
    437         prev = NULL;
    438     else
    439         prev = area->prev;
    440 
    441     pExaScr->numOffscreenAvailable++;
    442 
    443     /* link with next area if free */
    444     if (next && next->state == ExaOffscreenAvail)
    445         ExaOffscreenMerge(pExaScr, area);
    446 
    447     /* link with prev area if free */
    448     if (prev && prev->state == ExaOffscreenAvail) {
    449         area = prev;
    450         ExaOffscreenMerge(pExaScr, area);
    451     }
    452 
    453     ExaOffscreenValidate(pScreen);
    454     DBG_OFFSCREEN(("\tdone freeing\n"));
    455     return area;
    456 }
    457 
    458 void
    459 ExaOffscreenMarkUsed(PixmapPtr pPixmap)
    460 {
    461     ExaPixmapPriv(pPixmap);
    462     ExaScreenPriv(pPixmap->drawable.pScreen);
    463 
    464     if (!pExaPixmap || !pExaPixmap->area)
    465         return;
    466 
    467     pExaPixmap->area->last_use = pExaScr->offScreenCounter++;
    468 }
    469 
    470 /**
    471  * Defragment offscreen memory by compacting allocated areas at the end of it,
    472  * leaving the total amount of memory available as a single area at the
    473  * beginning (when there are no pinned allocations).
    474  */
    475 _X_HIDDEN ExaOffscreenArea *
    476 ExaOffscreenDefragment(ScreenPtr pScreen)
    477 {
    478     ExaScreenPriv(pScreen);
    479     ExaOffscreenArea *area, *largest_available = NULL;
    480     int largest_size = 0;
    481     PixmapPtr pDstPix;
    482     ExaPixmapPrivPtr pExaDstPix;
    483 
    484     pDstPix = (*pScreen->CreatePixmap) (pScreen, 0, 0, 0, 0);
    485 
    486     if (!pDstPix)
    487         return NULL;
    488 
    489     pExaDstPix = ExaGetPixmapPriv(pDstPix);
    490     pExaDstPix->use_gpu_copy = TRUE;
    491 
    492     for (area = pExaScr->info->offScreenAreas->prev;
    493          area != pExaScr->info->offScreenAreas;) {
    494         ExaOffscreenArea *prev = area->prev;
    495         PixmapPtr pSrcPix;
    496         ExaPixmapPrivPtr pExaSrcPix;
    497         Bool save_use_gpu_copy;
    498         int save_pitch;
    499 
    500         if (area->state != ExaOffscreenAvail ||
    501             prev->state == ExaOffscreenLocked ||
    502             (prev->state == ExaOffscreenRemovable &&
    503              prev->save != exaPixmapSave)) {
    504             area = prev;
    505             continue;
    506         }
    507 
    508         if (prev->state == ExaOffscreenAvail) {
    509             if (area == largest_available) {
    510                 largest_available = prev;
    511                 largest_size += prev->size;
    512             }
    513             area = prev;
    514             ExaOffscreenMerge(pExaScr, area);
    515             continue;
    516         }
    517 
    518         if (area->size > largest_size) {
    519             largest_available = area;
    520             largest_size = area->size;
    521         }
    522 
    523         pSrcPix = prev->privData;
    524         pExaSrcPix = ExaGetPixmapPriv(pSrcPix);
    525 
    526         pExaDstPix->fb_ptr = pExaScr->info->memoryBase +
    527             area->base_offset + area->size - prev->size + prev->base_offset -
    528             prev->offset;
    529         pExaDstPix->fb_ptr -= (unsigned long) pExaDstPix->fb_ptr % prev->align;
    530 
    531         if (pExaDstPix->fb_ptr <= pExaSrcPix->fb_ptr) {
    532             area = prev;
    533             continue;
    534         }
    535 
    536         if (!(pExaScr->info->flags & EXA_SUPPORTS_OFFSCREEN_OVERLAPS) &&
    537             (pExaSrcPix->fb_ptr + prev->size) > pExaDstPix->fb_ptr) {
    538             area = prev;
    539             continue;
    540         }
    541 
    542         save_use_gpu_copy = pExaSrcPix->use_gpu_copy;
    543         save_pitch = pSrcPix->devKind;
    544 
    545         pExaSrcPix->use_gpu_copy = TRUE;
    546         pSrcPix->devKind = pExaSrcPix->fb_pitch;
    547 
    548         pDstPix->drawable.width = pSrcPix->drawable.width;
    549         pDstPix->devKind = pSrcPix->devKind;
    550         pDstPix->drawable.height = pSrcPix->drawable.height;
    551         pDstPix->drawable.depth = pSrcPix->drawable.depth;
    552         pDstPix->drawable.bitsPerPixel = pSrcPix->drawable.bitsPerPixel;
    553 
    554         if (!pExaScr->info->PrepareCopy(pSrcPix, pDstPix, -1, -1, GXcopy, ~0)) {
    555             pExaSrcPix->use_gpu_copy = save_use_gpu_copy;
    556             pSrcPix->devKind = save_pitch;
    557             area = prev;
    558             continue;
    559         }
    560 
    561         pExaScr->info->Copy(pDstPix, 0, 0, 0, 0, pDstPix->drawable.width,
    562                             pDstPix->drawable.height);
    563         pExaScr->info->DoneCopy(pDstPix);
    564         exaMarkSync(pScreen);
    565 
    566         DBG_OFFSCREEN(("Before swap: prev=0x%08x-0x%08x-0x%08x area=0x%08x-0x%08x-0x%08x\n", prev->base_offset, prev->offset, prev->base_offset + prev->size, area->base_offset, area->offset, area->base_offset + area->size));
    567 
    568         /* Calculate swapped area offsets and sizes */
    569         area->base_offset = prev->base_offset;
    570         area->offset = area->base_offset;
    571         prev->offset += pExaDstPix->fb_ptr - pExaSrcPix->fb_ptr;
    572         assert(prev->offset >= pExaScr->info->offScreenBase);
    573         assert(prev->offset < pExaScr->info->memorySize);
    574         prev->base_offset = prev->offset;
    575         if (area->next)
    576             prev->size = area->next->base_offset - prev->base_offset;
    577         else
    578             prev->size = pExaScr->info->memorySize - prev->base_offset;
    579         area->size = prev->base_offset - area->base_offset;
    580 
    581         DBG_OFFSCREEN(("After swap: area=0x%08x-0x%08x-0x%08x prev=0x%08x-0x%08x-0x%08x\n", area->base_offset, area->offset, area->base_offset + area->size, prev->base_offset, prev->offset, prev->base_offset + prev->size));
    582 
    583         /* Swap areas in list */
    584         if (area->next)
    585             area->next->prev = prev;
    586         else
    587             pExaScr->info->offScreenAreas->prev = prev;
    588         if (prev->prev->next)
    589             prev->prev->next = area;
    590         else
    591             pExaScr->info->offScreenAreas = area;
    592         prev->next = area->next;
    593         area->next = prev;
    594         area->prev = prev->prev;
    595         prev->prev = area;
    596         if (!area->prev->next)
    597             pExaScr->info->offScreenAreas = area;
    598 
    599 #if DEBUG_OFFSCREEN
    600         if (prev->prev == prev || prev->next == prev)
    601             ErrorF("Whoops, prev points to itself!\n");
    602 
    603         if (area->prev == area || area->next == area)
    604             ErrorF("Whoops, area points to itself!\n");
    605 #endif
    606 
    607         pExaSrcPix->fb_ptr = pExaDstPix->fb_ptr;
    608         pExaSrcPix->use_gpu_copy = save_use_gpu_copy;
    609         pSrcPix->devKind = save_pitch;
    610     }
    611 
    612     pDstPix->drawable.width = 0;
    613     pDstPix->drawable.height = 0;
    614     pDstPix->drawable.depth = 0;
    615     pDstPix->drawable.bitsPerPixel = 0;
    616 
    617     (*pScreen->DestroyPixmap) (pDstPix);
    618 
    619     if (area->state == ExaOffscreenAvail && area->size > largest_size)
    620         return area;
    621 
    622     return largest_available;
    623 }
    624 
    625 /**
    626  * exaOffscreenInit initializes the offscreen memory manager.
    627  *
    628  * @param pScreen current screen
    629  *
    630  * exaOffscreenInit is called by exaDriverInit to set up the memory manager for
    631  * the screen, if any offscreen memory is available.
    632  */
    633 Bool
    634 exaOffscreenInit(ScreenPtr pScreen)
    635 {
    636     ExaScreenPriv(pScreen);
    637     ExaOffscreenArea *area;
    638 
    639     /* Allocate a big free area */
    640     area = malloc(sizeof(ExaOffscreenArea));
    641 
    642     if (!area)
    643         return FALSE;
    644 
    645     area->state = ExaOffscreenAvail;
    646     area->base_offset = pExaScr->info->offScreenBase;
    647     area->offset = area->base_offset;
    648     area->align = 0;
    649     area->size = pExaScr->info->memorySize - area->base_offset;
    650     area->save = NULL;
    651     area->next = NULL;
    652     area->prev = area;
    653     area->last_use = 0;
    654     area->eviction_cost = 0;
    655 
    656     /* Add it to the free areas */
    657     pExaScr->info->offScreenAreas = area;
    658     pExaScr->offScreenCounter = 1;
    659     pExaScr->numOffscreenAvailable = 1;
    660 
    661     ExaOffscreenValidate(pScreen);
    662 
    663     return TRUE;
    664 }
    665 
    666 void
    667 ExaOffscreenFini(ScreenPtr pScreen)
    668 {
    669     ExaScreenPriv(pScreen);
    670     ExaOffscreenArea *area;
    671 
    672     /* just free all of the area records */
    673     while ((area = pExaScr->info->offScreenAreas)) {
    674         pExaScr->info->offScreenAreas = area->next;
    675         free(area);
    676     }
    677 }