ws_dri_slabpool.c

Go to the documentation of this file.
00001 /**************************************************************************
00002  *
00003  * Copyright 2006-2008 Tungsten Graphics, Inc., Cedar Park, TX., USA
00004  * All Rights Reserved.
00005  *
00006  * Permission is hereby granted, free of charge, to any person obtaining a
00007  * copy of this software and associated documentation files (the
00008  * "Software"), to deal in the Software without restriction, including
00009  * without limitation the rights to use, copy, modify, merge, publish,
00010  * distribute, sub license, and/or sell copies of the Software, and to
00011  * permit persons to whom the Software is furnished to do so, subject to
00012  * the following conditions:
00013  *
00014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00016  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
00017  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
00018  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
00019  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
00020  * USE OR OTHER DEALINGS IN THE SOFTWARE.
00021  *
00022  * The above copyright notice and this permission notice (including the
00023  * next paragraph) shall be included in all copies or substantial portions
00024  * of the Software.
00025  *
00026  *
00027  **************************************************************************/
00028 /*
00029  * Authors: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
00030  */
00031 
00032 #include <stdint.h>
00033 #include <sys/time.h>
00034 #include <errno.h>
00035 #include <unistd.h>
00036 #include <assert.h>
00037 #include "ws_dri_bufpool.h"
00038 #include "ws_dri_fencemgr.h"
00039 #include "ws_dri_bufmgr.h"
00040 #include "pipe/p_thread.h"
00041 
00042 #define DRI_SLABPOOL_ALLOC_RETRIES 100
00043 
00044 struct _DriSlab;
00045 
00046 struct _DriSlabBuffer {
00047     int isSlabBuffer;
00048     drmBO *bo;
00049     struct _DriFenceObject *fence;
00050     struct _DriSlab *parent;
00051     drmMMListHead head;
00052     uint32_t mapCount;
00053     uint32_t start;
00054     uint32_t fenceType;
00055     int unFenced;
00056     pipe_condvar event;
00057 };
00058 
00059 struct _DriKernelBO {
00060     int fd;
00061     drmBO bo;
00062     drmMMListHead timeoutHead;
00063     drmMMListHead head;
00064     struct timeval timeFreed;
00065     uint32_t pageAlignment;
00066     void *virtual;
00067 };
00068 
00069 struct _DriSlab{
00070     drmMMListHead head;
00071     drmMMListHead freeBuffers;
00072     uint32_t numBuffers;
00073     uint32_t numFree;
00074     struct _DriSlabBuffer *buffers;
00075     struct _DriSlabSizeHeader *header;
00076     struct _DriKernelBO *kbo;
00077 };
00078 
00079 
00080 struct _DriSlabSizeHeader {
00081     drmMMListHead slabs;
00082     drmMMListHead freeSlabs;
00083     drmMMListHead delayedBuffers;
00084     uint32_t numDelayed;
00085     struct _DriSlabPool *slabPool;
00086     uint32_t bufSize;
00087     pipe_mutex mutex;
00088 };
00089 
00090 struct _DriFreeSlabManager {
00091     struct timeval slabTimeout;
00092     struct timeval checkInterval;
00093     struct timeval nextCheck;
00094     drmMMListHead timeoutList;
00095     drmMMListHead unCached;
00096     drmMMListHead cached;
00097     pipe_mutex mutex;
00098 };
00099 
00100 
00101 struct _DriSlabPool {
00102 
00103     /*
00104      * The data of this structure remains constant after
00105      * initialization and thus needs no mutex protection.
00106      */
00107 
00108     struct _DriFreeSlabManager *fMan;
00109     uint64_t proposedFlags;
00110     uint64_t validMask;
00111     uint32_t *bucketSizes;
00112     uint32_t numBuckets;
00113     uint32_t pageSize;
00114     int fd;
00115     int pageAlignment;
00116     int maxSlabSize;
00117     int desiredNumBuffers;
00118     struct _DriSlabSizeHeader *headers;
00119 };
00120 
00121 /*
00122  * FIXME: Perhaps arrange timeout slabs in size buckets for fast
00123  * retreival??
00124  */
00125 
00126 
00127 static inline int
00128 driTimeAfterEq(struct timeval *arg1, struct timeval *arg2)
00129 {
00130     return ((arg1->tv_sec > arg2->tv_sec) ||
00131             ((arg1->tv_sec == arg2->tv_sec) &&
00132              (arg1->tv_usec > arg2->tv_usec)));
00133 }
00134 
00135 static inline void
00136 driTimeAdd(struct timeval *arg, struct timeval *add)
00137 {
00138     unsigned int sec;
00139 
00140     arg->tv_sec += add->tv_sec;
00141     arg->tv_usec += add->tv_usec;
00142     sec = arg->tv_usec / 1000000;
00143     arg->tv_sec += sec;
00144     arg->tv_usec -= sec*1000000;
00145 }
00146 
00147 static void
00148 driFreeKernelBO(struct _DriKernelBO *kbo)
00149 {
00150     if (!kbo)
00151         return;
00152 
00153     (void) drmBOUnreference(kbo->fd, &kbo->bo);
00154     free(kbo);
00155 }
00156 
00157 
00158 static void
00159 driFreeTimeoutKBOsLocked(struct _DriFreeSlabManager *fMan,
00160                          struct timeval *time)
00161 {
00162     drmMMListHead *list, *next;
00163     struct _DriKernelBO *kbo;
00164 
00165     if (!driTimeAfterEq(time, &fMan->nextCheck))
00166         return;
00167 
00168     for (list = fMan->timeoutList.next, next = list->next;
00169          list != &fMan->timeoutList;
00170          list = next, next = list->next) {
00171 
00172         kbo = DRMLISTENTRY(struct _DriKernelBO, list, timeoutHead);
00173 
00174         if (!driTimeAfterEq(time, &kbo->timeFreed))
00175             break;
00176 
00177         DRMLISTDELINIT(&kbo->timeoutHead);
00178         DRMLISTDELINIT(&kbo->head);
00179         driFreeKernelBO(kbo);
00180     }
00181 
00182     fMan->nextCheck = *time;
00183     driTimeAdd(&fMan->nextCheck, &fMan->checkInterval);
00184 }
00185 
00186 
00187 /*
00188  * Add a _DriKernelBO to the free slab manager.
00189  * This means that it is available for reuse, but if it's not
00190  * reused in a while, it will be freed.
00191  */
00192 
00193 static void
00194 driSetKernelBOFree(struct _DriFreeSlabManager *fMan,
00195                    struct _DriKernelBO *kbo)
00196 {
00197     struct timeval time;
00198 
00199     pipe_mutex_lock(fMan->mutex);
00200     gettimeofday(&time, NULL);
00201     driTimeAdd(&time, &fMan->slabTimeout);
00202 
00203     kbo->timeFreed = time;
00204 
00205     if (kbo->bo.flags & DRM_BO_FLAG_CACHED)
00206         DRMLISTADD(&kbo->head, &fMan->cached);
00207     else
00208         DRMLISTADD(&kbo->head, &fMan->unCached);
00209 
00210     DRMLISTADDTAIL(&kbo->timeoutHead, &fMan->timeoutList);
00211     driFreeTimeoutKBOsLocked(fMan, &time);
00212 
00213     pipe_mutex_unlock(fMan->mutex);
00214 }
00215 
00216 /*
00217  * Get a _DriKernelBO for us to use as storage for a slab.
00218  *
00219  */
00220 
00221 static struct _DriKernelBO *
00222 driAllocKernelBO(struct _DriSlabSizeHeader *header)
00223 
00224 {
00225     struct _DriSlabPool *slabPool = header->slabPool;
00226     struct _DriFreeSlabManager *fMan = slabPool->fMan;
00227     drmMMListHead *list, *next, *head;
00228     uint32_t size = header->bufSize * slabPool->desiredNumBuffers;
00229     struct _DriKernelBO *kbo;
00230     struct _DriKernelBO *kboTmp;
00231     int ret;
00232 
00233     /*
00234      * FIXME: We should perhaps allow some variation in slabsize in order
00235      * to efficiently reuse slabs.
00236      */
00237 
00238     size = (size <= slabPool->maxSlabSize) ? size : slabPool->maxSlabSize;
00239     size = (size + slabPool->pageSize - 1) & ~(slabPool->pageSize - 1);
00240     pipe_mutex_lock(fMan->mutex);
00241 
00242     kbo = NULL;
00243 
00244   retry:
00245     head = (slabPool->proposedFlags & DRM_BO_FLAG_CACHED) ?
00246         &fMan->cached : &fMan->unCached;
00247 
00248     for (list = head->next, next = list->next;
00249          list != head;
00250          list = next, next = list->next) {
00251 
00252         kboTmp = DRMLISTENTRY(struct _DriKernelBO, list, head);
00253 
00254         if ((kboTmp->bo.size == size) &&
00255             (slabPool->pageAlignment == 0 ||
00256              (kboTmp->pageAlignment % slabPool->pageAlignment) == 0)) {
00257 
00258             if (!kbo)
00259                 kbo = kboTmp;
00260 
00261             if ((kbo->bo.proposedFlags ^ slabPool->proposedFlags) == 0)
00262                 break;
00263 
00264         }
00265     }
00266 
00267     if (kbo) {
00268         DRMLISTDELINIT(&kbo->head);
00269         DRMLISTDELINIT(&kbo->timeoutHead);
00270     }
00271 
00272     pipe_mutex_unlock(fMan->mutex);
00273 
00274     if (kbo) {
00275         uint64_t new_mask = kbo->bo.proposedFlags ^ slabPool->proposedFlags;
00276 
00277         ret = 0;
00278         if (new_mask) {
00279             ret = drmBOSetStatus(kbo->fd, &kbo->bo, slabPool->proposedFlags,
00280                                  new_mask, DRM_BO_HINT_DONT_FENCE, 0, 0);
00281         }
00282         if (ret == 0)
00283             return kbo;
00284 
00285         driFreeKernelBO(kbo);
00286         kbo = NULL;
00287         goto retry;
00288     }
00289 
00290     kbo = calloc(1, sizeof(struct _DriKernelBO));
00291     if (!kbo)
00292         return NULL;
00293 
00294     kbo->fd = slabPool->fd;
00295     DRMINITLISTHEAD(&kbo->head);
00296     DRMINITLISTHEAD(&kbo->timeoutHead);
00297     ret = drmBOCreate(kbo->fd, size, slabPool->pageAlignment, NULL,
00298                       slabPool->proposedFlags,
00299                       DRM_BO_HINT_DONT_FENCE, &kbo->bo);
00300     if (ret)
00301         goto out_err0;
00302 
00303     ret = drmBOMap(kbo->fd, &kbo->bo,
00304                    DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE,
00305                    0, &kbo->virtual);
00306 
00307     if (ret)
00308         goto out_err1;
00309 
00310     ret = drmBOUnmap(kbo->fd, &kbo->bo);
00311     if (ret)
00312         goto out_err1;
00313 
00314     return kbo;
00315 
00316   out_err1:
00317     drmBOUnreference(kbo->fd, &kbo->bo);
00318   out_err0:
00319     free(kbo);
00320     return NULL;
00321 }
00322 
00323 
00324 static int
00325 driAllocSlab(struct _DriSlabSizeHeader *header)
00326 {
00327     struct _DriSlab *slab;
00328     struct _DriSlabBuffer *buf;
00329     uint32_t numBuffers;
00330     int ret;
00331     int i;
00332 
00333     slab = calloc(1, sizeof(*slab));
00334     if (!slab)
00335         return -ENOMEM;
00336 
00337     slab->kbo = driAllocKernelBO(header);
00338     if (!slab->kbo) {
00339         ret = -ENOMEM;
00340         goto out_err0;
00341     }
00342 
00343     numBuffers = slab->kbo->bo.size / header->bufSize;
00344 
00345     slab->buffers = calloc(numBuffers, sizeof(*slab->buffers));
00346     if (!slab->buffers) {
00347         ret = -ENOMEM;
00348         goto out_err1;
00349     }
00350 
00351     DRMINITLISTHEAD(&slab->head);
00352     DRMINITLISTHEAD(&slab->freeBuffers);
00353     slab->numBuffers = numBuffers;
00354     slab->numFree = 0;
00355     slab->header = header;
00356 
00357     buf = slab->buffers;
00358     for (i=0; i < numBuffers; ++i) {
00359         buf->parent = slab;
00360         buf->start = i* header->bufSize;
00361         buf->mapCount = 0;
00362         buf->isSlabBuffer = 1;
00363         pipe_condvar_init(buf->event);
00364         DRMLISTADDTAIL(&buf->head, &slab->freeBuffers);
00365         slab->numFree++;
00366         buf++;
00367     }
00368 
00369     DRMLISTADDTAIL(&slab->head, &header->slabs);
00370 
00371     return 0;
00372 
00373   out_err1:
00374     driSetKernelBOFree(header->slabPool->fMan, slab->kbo);
00375     free(slab->buffers);
00376   out_err0:
00377     free(slab);
00378     return ret;
00379 }
00380 
00381 /*
00382  * Delete a buffer from the slab header delayed list and put
00383  * it on the slab free list.
00384  */
00385 
00386 static void
00387 driSlabFreeBufferLocked(struct _DriSlabBuffer *buf)
00388 {
00389     struct _DriSlab *slab = buf->parent;
00390     struct _DriSlabSizeHeader *header = slab->header;
00391     drmMMListHead *list = &buf->head;
00392 
00393     DRMLISTDEL(list);
00394     DRMLISTADDTAIL(list, &slab->freeBuffers);
00395     slab->numFree++;
00396 
00397     if (slab->head.next == &slab->head)
00398         DRMLISTADDTAIL(&slab->head, &header->slabs);
00399 
00400     if (slab->numFree == slab->numBuffers) {
00401         list = &slab->head;
00402         DRMLISTDEL(list);
00403         DRMLISTADDTAIL(list, &header->freeSlabs);
00404     }
00405 
00406     if (header->slabs.next == &header->slabs ||
00407         slab->numFree != slab->numBuffers) {
00408 
00409         drmMMListHead *next;
00410         struct _DriFreeSlabManager *fMan = header->slabPool->fMan;
00411 
00412         for (list = header->freeSlabs.next, next = list->next;
00413              list != &header->freeSlabs;
00414              list = next, next = list->next) {
00415 
00416             slab = DRMLISTENTRY(struct _DriSlab, list, head);
00417 
00418             DRMLISTDELINIT(list);
00419             driSetKernelBOFree(fMan, slab->kbo);
00420             free(slab->buffers);
00421             free(slab);
00422         }
00423     }
00424 }
00425 
00426 static void
00427 driSlabCheckFreeLocked(struct _DriSlabSizeHeader *header, int wait)
00428 {
00429   drmMMListHead *list, *prev, *first;
00430    struct _DriSlabBuffer *buf;
00431    struct _DriSlab *slab;
00432    int firstWasSignaled = 1;
00433    int signaled;
00434    int i;
00435    int ret;
00436 
00437    /*
00438     * Rerun the freeing test if the youngest tested buffer
00439     * was signaled, since there might be more idle buffers
00440     * in the delay list.
00441     */
00442 
00443    while (firstWasSignaled) {
00444        firstWasSignaled = 0;
00445        signaled = 0;
00446        first = header->delayedBuffers.next;
00447 
00448        /* Only examine the oldest 1/3 of delayed buffers:
00449         */
00450        if (header->numDelayed > 3) {
00451            for (i = 0; i < header->numDelayed; i += 3) {
00452                first = first->next;
00453            }
00454        }
00455 
00456        for (list = first, prev = list->prev;
00457             list != &header->delayedBuffers;
00458             list = prev, prev = list->prev) {
00459            buf = DRMLISTENTRY(struct _DriSlabBuffer, list, head);
00460            slab = buf->parent;
00461 
00462            if (!signaled) {
00463                if (wait) {
00464                    ret = driFenceFinish(buf->fence, buf->fenceType, 0);
00465                    if (ret)
00466                        break;
00467                    signaled = 1;
00468                    wait = 0;
00469                } else {
00470                    signaled = driFenceSignaled(buf->fence, buf->fenceType);
00471                }
00472                if (signaled) {
00473                    if (list == first)
00474                        firstWasSignaled = 1;
00475                    driFenceUnReference(&buf->fence);
00476                    header->numDelayed--;
00477                    driSlabFreeBufferLocked(buf);
00478                }
00479            } else if (driFenceSignaledCached(buf->fence, buf->fenceType)) {
00480                driFenceUnReference(&buf->fence);
00481                header->numDelayed--;
00482                driSlabFreeBufferLocked(buf);
00483            }
00484        }
00485    }
00486 }
00487 
00488 
00489 static struct _DriSlabBuffer *
00490 driSlabAllocBuffer(struct _DriSlabSizeHeader *header)
00491 {
00492     static struct _DriSlabBuffer *buf;
00493     struct _DriSlab *slab;
00494     drmMMListHead *list;
00495     int count = DRI_SLABPOOL_ALLOC_RETRIES;
00496 
00497     pipe_mutex_lock(header->mutex);
00498     while(header->slabs.next == &header->slabs && count > 0) {
00499         driSlabCheckFreeLocked(header, 0);
00500         if (header->slabs.next != &header->slabs)
00501           break;
00502 
00503         pipe_mutex_unlock(header->mutex);
00504         if (count != DRI_SLABPOOL_ALLOC_RETRIES)
00505             usleep(1);
00506         pipe_mutex_lock(header->mutex);
00507         (void) driAllocSlab(header);
00508         count--;
00509     }
00510 
00511     list = header->slabs.next;
00512     if (list == &header->slabs) {
00513         pipe_mutex_unlock(header->mutex);
00514         return NULL;
00515     }
00516     slab = DRMLISTENTRY(struct _DriSlab, list, head);
00517     if (--slab->numFree == 0)
00518         DRMLISTDELINIT(list);
00519 
00520     list = slab->freeBuffers.next;
00521     DRMLISTDELINIT(list);
00522 
00523     pipe_mutex_unlock(header->mutex);
00524     buf = DRMLISTENTRY(struct _DriSlabBuffer, list, head);
00525     return buf;
00526 }
00527 
00528 static void *
00529 pool_create(struct _DriBufferPool *driPool, unsigned long size,
00530             uint64_t flags, unsigned hint, unsigned alignment)
00531 {
00532     struct _DriSlabPool *pool = (struct _DriSlabPool *) driPool->data;
00533     struct _DriSlabSizeHeader *header;
00534     struct _DriSlabBuffer *buf;
00535     void *dummy;
00536     int i;
00537     int ret;
00538 
00539     /*
00540      * FIXME: Check for compatibility.
00541      */
00542 
00543     header = pool->headers;
00544     for (i=0; i<pool->numBuckets; ++i) {
00545       if (header->bufSize >= size)
00546         break;
00547       header++;
00548     }
00549 
00550     if (i < pool->numBuckets)
00551         return driSlabAllocBuffer(header);
00552 
00553 
00554     /*
00555      * Fall back to allocate a buffer object directly from DRM.
00556      * and wrap it in a driBO structure.
00557      */
00558 
00559 
00560     buf = calloc(1, sizeof(*buf));
00561 
00562     if (!buf)
00563         return NULL;
00564 
00565     buf->bo = calloc(1, sizeof(*buf->bo));
00566     if (!buf->bo)
00567         goto out_err0;
00568 
00569     if (alignment) {
00570         if ((alignment < pool->pageSize) && (pool->pageSize % alignment))
00571             goto out_err1;
00572         if ((alignment > pool->pageSize) && (alignment % pool->pageSize))
00573             goto out_err1;
00574     }
00575 
00576     ret = drmBOCreate(pool->fd, size, alignment / pool->pageSize, NULL,
00577                         flags, hint, buf->bo);
00578     if (ret)
00579         goto out_err1;
00580 
00581     ret  = drmBOMap(pool->fd, buf->bo, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE,
00582                     0, &dummy);
00583     if (ret)
00584         goto out_err2;
00585 
00586     ret = drmBOUnmap(pool->fd, buf->bo);
00587     if (ret)
00588         goto out_err2;
00589 
00590     return buf;
00591   out_err2:
00592     drmBOUnreference(pool->fd, buf->bo);
00593   out_err1:
00594     free(buf->bo);
00595   out_err0:
00596     free(buf);
00597     return NULL;
00598 }
00599 
00600 static int
00601 pool_destroy(struct _DriBufferPool *driPool, void *private)
00602 {
00603     struct _DriSlabBuffer *buf =
00604         (struct _DriSlabBuffer *) private;
00605     struct _DriSlab *slab;
00606     struct _DriSlabSizeHeader *header;
00607 
00608     if (!buf->isSlabBuffer) {
00609         struct _DriSlabPool *pool = (struct _DriSlabPool *) driPool->data;
00610         int ret;
00611 
00612         ret = drmBOUnreference(pool->fd, buf->bo);
00613         free(buf->bo);
00614         free(buf);
00615         return ret;
00616     }
00617 
00618     slab = buf->parent;
00619     header = slab->header;
00620 
00621     pipe_mutex_lock(header->mutex);
00622     buf->unFenced = 0;
00623     buf->mapCount = 0;
00624 
00625     if (buf->fence && !driFenceSignaledCached(buf->fence, buf->fenceType)) {
00626         DRMLISTADDTAIL(&buf->head, &header->delayedBuffers);
00627         header->numDelayed++;
00628     } else {
00629         if (buf->fence)
00630             driFenceUnReference(&buf->fence);
00631         driSlabFreeBufferLocked(buf);
00632     }
00633 
00634     pipe_mutex_unlock(header->mutex);
00635     return 0;
00636 }
00637 
00638 static int
00639 pool_waitIdle(struct _DriBufferPool *driPool, void *private,
00640               pipe_mutex *mutex, int lazy)
00641 {
00642    struct _DriSlabBuffer *buf = (struct _DriSlabBuffer *) private;
00643 
00644    while(buf->unFenced)
00645        pipe_condvar_wait(buf->event, *mutex);
00646 
00647    if (!buf->fence)
00648      return 0;
00649 
00650    driFenceFinish(buf->fence, buf->fenceType, lazy);
00651    driFenceUnReference(&buf->fence);
00652 
00653    return 0;
00654 }
00655 
00656 static int
00657 pool_map(struct _DriBufferPool *pool, void *private, unsigned flags,
00658          int hint, pipe_mutex *mutex, void **virtual)
00659 {
00660    struct _DriSlabBuffer *buf = (struct _DriSlabBuffer *) private;
00661    int busy;
00662 
00663    if (buf->isSlabBuffer)
00664        busy = buf->unFenced || (buf->fence && !driFenceSignaledCached(buf->fence, buf->fenceType));
00665    else
00666        busy = buf->fence && !driFenceSignaled(buf->fence, buf->fenceType);
00667 
00668 
00669    if (busy) {
00670        if (hint & DRM_BO_HINT_DONT_BLOCK)
00671            return -EBUSY;
00672        else {
00673            (void) pool_waitIdle(pool, private, mutex, 0);
00674        }
00675    }
00676 
00677    ++buf->mapCount;
00678    *virtual = (buf->isSlabBuffer) ?
00679        (void *) ((uint8_t *) buf->parent->kbo->virtual + buf->start) :
00680        (void *) buf->bo->virtual;
00681 
00682    return 0;
00683 }
00684 
00685 static int
00686 pool_unmap(struct _DriBufferPool *pool, void *private)
00687 {
00688    struct _DriSlabBuffer *buf = (struct _DriSlabBuffer *) private;
00689 
00690    --buf->mapCount;
00691    if (buf->mapCount == 0 && buf->isSlabBuffer)
00692       pipe_condvar_broadcast(buf->event);
00693 
00694    return 0;
00695 }
00696 
00697 static unsigned long
00698 pool_offset(struct _DriBufferPool *pool, void *private)
00699 {
00700    struct _DriSlabBuffer *buf = (struct _DriSlabBuffer *) private;
00701    struct _DriSlab *slab;
00702    struct _DriSlabSizeHeader *header;
00703 
00704    if (!buf->isSlabBuffer) {
00705        assert(buf->bo->proposedFlags & DRM_BO_FLAG_NO_MOVE);
00706        return buf->bo->offset;
00707    }
00708 
00709    slab = buf->parent;
00710    header = slab->header;
00711 
00712    (void) header;
00713    assert(header->slabPool->proposedFlags & DRM_BO_FLAG_NO_MOVE);
00714    return slab->kbo->bo.offset + buf->start;
00715 }
00716 
00717 static unsigned long
00718 pool_poolOffset(struct _DriBufferPool *pool, void *private)
00719 {
00720    struct _DriSlabBuffer *buf = (struct _DriSlabBuffer *) private;
00721 
00722    return buf->start;
00723 }
00724 
00725 static uint64_t
00726 pool_flags(struct _DriBufferPool *pool, void *private)
00727 {
00728    struct _DriSlabBuffer *buf = (struct _DriSlabBuffer *) private;
00729 
00730    if (!buf->isSlabBuffer)
00731        return buf->bo->flags;
00732 
00733    return buf->parent->kbo->bo.flags;
00734 }
00735 
00736 static unsigned long
00737 pool_size(struct _DriBufferPool *pool, void *private)
00738 {
00739    struct _DriSlabBuffer *buf = (struct _DriSlabBuffer *) private;
00740    if (!buf->isSlabBuffer)
00741        return buf->bo->size;
00742 
00743    return buf->parent->header->bufSize;
00744 }
00745 
00746 static int
00747 pool_fence(struct _DriBufferPool *pool, void *private,
00748            struct _DriFenceObject *fence)
00749 {
00750    struct _DriSlabBuffer *buf = (struct _DriSlabBuffer *) private;
00751    drmBO *bo;
00752 
00753    if (buf->fence)
00754       driFenceUnReference(&buf->fence);
00755 
00756    buf->fence = driFenceReference(fence);
00757    bo = (buf->isSlabBuffer) ?
00758      &buf->parent->kbo->bo:
00759      buf->bo;
00760    buf->fenceType = bo->fenceFlags;
00761 
00762    buf->unFenced = 0;
00763    pipe_condvar_broadcast(buf->event);
00764 
00765    return 0;
00766 }
00767 
00768 static drmBO *
00769 pool_kernel(struct _DriBufferPool *pool, void *private)
00770 {
00771    struct _DriSlabBuffer *buf = (struct _DriSlabBuffer *) private;
00772 
00773    return (buf->isSlabBuffer) ? &buf->parent->kbo->bo : buf->bo;
00774 }
00775 
00776 static int
00777 pool_validate(struct _DriBufferPool *pool, void *private,
00778               pipe_mutex *mutex)
00779 {
00780    struct _DriSlabBuffer *buf = (struct _DriSlabBuffer *) private;
00781 
00782    if (!buf->isSlabBuffer)
00783        return 0;
00784 
00785    while(buf->mapCount != 0)
00786       pipe_condvar_wait(buf->event, *mutex);
00787 
00788    buf->unFenced = 1;
00789    return 0;
00790 }
00791 
00792 
00793 struct _DriFreeSlabManager *
00794 driInitFreeSlabManager(uint32_t checkIntervalMsec, uint32_t slabTimeoutMsec)
00795 {
00796     struct _DriFreeSlabManager *tmp;
00797 
00798     tmp = calloc(1, sizeof(*tmp));
00799     if (!tmp)
00800         return NULL;
00801 
00802     pipe_mutex_init(tmp->mutex);
00803     pipe_mutex_lock(tmp->mutex);
00804     tmp->slabTimeout.tv_usec = slabTimeoutMsec*1000;
00805     tmp->slabTimeout.tv_sec = tmp->slabTimeout.tv_usec / 1000000;
00806     tmp->slabTimeout.tv_usec -=  tmp->slabTimeout.tv_sec*1000000;
00807 
00808     tmp->checkInterval.tv_usec = checkIntervalMsec*1000;
00809     tmp->checkInterval.tv_sec = tmp->checkInterval.tv_usec / 1000000;
00810     tmp->checkInterval.tv_usec -=  tmp->checkInterval.tv_sec*1000000;
00811 
00812     gettimeofday(&tmp->nextCheck, NULL);
00813     driTimeAdd(&tmp->nextCheck, &tmp->checkInterval);
00814     DRMINITLISTHEAD(&tmp->timeoutList);
00815     DRMINITLISTHEAD(&tmp->unCached);
00816     DRMINITLISTHEAD(&tmp->cached);
00817     pipe_mutex_unlock(tmp->mutex);
00818 
00819     return tmp;
00820 }
00821 
00822 void
00823 driFinishFreeSlabManager(struct _DriFreeSlabManager *fMan)
00824 {
00825     struct timeval time;
00826 
00827     time = fMan->nextCheck;
00828     driTimeAdd(&time, &fMan->checkInterval);
00829 
00830     pipe_mutex_lock(fMan->mutex);
00831     driFreeTimeoutKBOsLocked(fMan, &time);
00832     pipe_mutex_unlock(fMan->mutex);
00833 
00834     assert(fMan->timeoutList.next == &fMan->timeoutList);
00835     assert(fMan->unCached.next == &fMan->unCached);
00836     assert(fMan->cached.next == &fMan->cached);
00837 
00838     free(fMan);
00839 }
00840 
00841 static void
00842 driInitSizeHeader(struct _DriSlabPool *pool, uint32_t size,
00843                   struct _DriSlabSizeHeader *header)
00844 {
00845     pipe_mutex_init(header->mutex);
00846     pipe_mutex_lock(header->mutex);
00847 
00848     DRMINITLISTHEAD(&header->slabs);
00849     DRMINITLISTHEAD(&header->freeSlabs);
00850     DRMINITLISTHEAD(&header->delayedBuffers);
00851 
00852     header->numDelayed = 0;
00853     header->slabPool = pool;
00854     header->bufSize = size;
00855 
00856     pipe_mutex_unlock(header->mutex);
00857 }
00858 
00859 static void
00860 driFinishSizeHeader(struct _DriSlabSizeHeader *header)
00861 {
00862     drmMMListHead *list, *next;
00863     struct _DriSlabBuffer *buf;
00864 
00865     pipe_mutex_lock(header->mutex);
00866     for (list = header->delayedBuffers.next, next = list->next;
00867          list != &header->delayedBuffers;
00868          list = next, next = list->next) {
00869 
00870         buf = DRMLISTENTRY(struct _DriSlabBuffer, list , head);
00871         if (buf->fence) {
00872             (void) driFenceFinish(buf->fence, buf->fenceType, 0);
00873             driFenceUnReference(&buf->fence);
00874         }
00875         header->numDelayed--;
00876         driSlabFreeBufferLocked(buf);
00877     }
00878     pipe_mutex_unlock(header->mutex);
00879 }
00880 
00881 static void
00882 pool_takedown(struct _DriBufferPool *driPool)
00883 {
00884    struct _DriSlabPool *pool = driPool->data;
00885    int i;
00886 
00887    for (i=0; i<pool->numBuckets; ++i) {
00888      driFinishSizeHeader(&pool->headers[i]);
00889    }
00890 
00891    free(pool->headers);
00892    free(pool->bucketSizes);
00893    free(pool);
00894    free(driPool);
00895 }
00896 
00897 struct _DriBufferPool *
00898 driSlabPoolInit(int fd, uint64_t flags,
00899                 uint64_t validMask,
00900                 uint32_t smallestSize,
00901                 uint32_t numSizes,
00902                 uint32_t desiredNumBuffers,
00903                 uint32_t maxSlabSize,
00904                 uint32_t pageAlignment,
00905                 struct _DriFreeSlabManager *fMan)
00906 {
00907     struct _DriBufferPool *driPool;
00908     struct _DriSlabPool *pool;
00909     uint32_t i;
00910 
00911     driPool = calloc(1, sizeof(*driPool));
00912     if (!driPool)
00913         return NULL;
00914 
00915     pool = calloc(1, sizeof(*pool));
00916     if (!pool)
00917         goto out_err0;
00918 
00919     pool->bucketSizes = calloc(numSizes, sizeof(*pool->bucketSizes));
00920     if (!pool->bucketSizes)
00921         goto out_err1;
00922 
00923     pool->headers = calloc(numSizes, sizeof(*pool->headers));
00924     if (!pool->headers)
00925         goto out_err2;
00926 
00927     pool->fMan = fMan;
00928     pool->proposedFlags = flags;
00929     pool->validMask = validMask;
00930     pool->numBuckets = numSizes;
00931     pool->pageSize = getpagesize();
00932     pool->fd = fd;
00933     pool->pageAlignment = pageAlignment;
00934     pool->maxSlabSize = maxSlabSize;
00935     pool->desiredNumBuffers = desiredNumBuffers;
00936 
00937     for (i=0; i<pool->numBuckets; ++i) {
00938         pool->bucketSizes[i] = (smallestSize << i);
00939         driInitSizeHeader(pool, pool->bucketSizes[i],
00940                           &pool->headers[i]);
00941     }
00942 
00943     driPool->data = (void *) pool;
00944     driPool->map = &pool_map;
00945     driPool->unmap = &pool_unmap;
00946     driPool->destroy = &pool_destroy;
00947     driPool->offset = &pool_offset;
00948     driPool->poolOffset = &pool_poolOffset;
00949     driPool->flags = &pool_flags;
00950     driPool->size = &pool_size;
00951     driPool->create = &pool_create;
00952     driPool->fence = &pool_fence;
00953     driPool->kernel = &pool_kernel;
00954     driPool->validate = &pool_validate;
00955     driPool->waitIdle = &pool_waitIdle;
00956     driPool->takeDown = &pool_takedown;
00957 
00958     return driPool;
00959 
00960   out_err2:
00961     free(pool->bucketSizes);
00962   out_err1:
00963     free(pool);
00964   out_err0:
00965     free(driPool);
00966 
00967     return NULL;
00968 }

Generated on Tue Sep 29 06:25:17 2009 for Gallium3D by  doxygen 1.5.4