pb_bufmgr_slab.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 
00039 #include "pipe/p_compiler.h"
00040 #include "pipe/p_error.h"
00041 #include "pipe/p_debug.h"
00042 #include "pipe/p_thread.h"
00043 #include "pipe/p_defines.h"
00044 #include "util/u_memory.h"
00045 #include "util/u_double_list.h"
00046 #include "util/u_time.h"
00047 
00048 #include "pb_buffer.h"
00049 #include "pb_bufmgr.h"
00050 
00051 
00052 struct pb_slab;
00053 
00054 
00060 struct pb_slab_buffer
00061 {
00062    struct pb_buffer base;
00063    
00064    struct pb_slab *slab;
00065    
00066    struct list_head head;
00067    
00068    unsigned mapCount;
00069    
00071    size_t start;
00072    
00074    /* TODO: Actually validation does not reach this stage yet */
00075    pipe_condvar event;
00076 };
00077 
00078 
00082 struct pb_slab
00083 {
00084    struct list_head head;
00085    struct list_head freeBuffers;
00086    size_t numBuffers;
00087    size_t numFree;
00088    
00089    struct pb_slab_buffer *buffers;
00090    struct pb_slab_manager *mgr;
00091    
00093    struct pb_buffer *bo;
00094    
00095    void *virtual;   
00096 };
00097 
00098 
00103 struct pb_slab_manager 
00104 {
00105    struct pb_manager base;
00106    
00108    struct pb_manager *provider;
00109    
00111    size_t bufSize;
00112    
00114    size_t slabSize;
00115    
00122    struct pb_desc desc;
00123 
00130    struct list_head slabs;
00131    
00132    pipe_mutex mutex;
00133 };
00134 
00135 
00147 struct pb_slab_range_manager 
00148 {
00149    struct pb_manager base;
00150 
00151    struct pb_manager *provider;
00152    
00153    size_t minBufSize;
00154    size_t maxBufSize;
00155    
00157    struct pb_desc desc;
00158    
00159    unsigned numBuckets;
00160    size_t *bucketSizes;
00161    
00163    struct pb_manager **buckets;
00164 };
00165 
00166 
00167 static INLINE struct pb_slab_buffer *
00168 pb_slab_buffer(struct pb_buffer *buf)
00169 {
00170    assert(buf);
00171    return (struct pb_slab_buffer *)buf;
00172 }
00173 
00174 
00175 static INLINE struct pb_slab_manager *
00176 pb_slab_manager(struct pb_manager *mgr)
00177 {
00178    assert(mgr);
00179    return (struct pb_slab_manager *)mgr;
00180 }
00181 
00182 
00183 static INLINE struct pb_slab_range_manager *
00184 pb_slab_range_manager(struct pb_manager *mgr)
00185 {
00186    assert(mgr);
00187    return (struct pb_slab_range_manager *)mgr;
00188 }
00189 
00190 
00195 static void
00196 pb_slab_buffer_destroy(struct pb_buffer *_buf)
00197 {
00198    struct pb_slab_buffer *buf = pb_slab_buffer(_buf);
00199    struct pb_slab *slab = buf->slab;
00200    struct pb_slab_manager *mgr = slab->mgr;
00201    struct list_head *list = &buf->head;
00202 
00203    pipe_mutex_lock(mgr->mutex);
00204    
00205    assert(buf->base.base.refcount == 0);
00206    
00207    buf->mapCount = 0;
00208 
00209    LIST_DEL(list);
00210    LIST_ADDTAIL(list, &slab->freeBuffers);
00211    slab->numFree++;
00212 
00213    if (slab->head.next == &slab->head)
00214       LIST_ADDTAIL(&slab->head, &mgr->slabs);
00215 
00216    /* If the slab becomes totally empty, free it */
00217    if (slab->numFree == slab->numBuffers) {
00218       list = &slab->head;
00219       LIST_DELINIT(list);
00220       pb_reference(&slab->bo, NULL);
00221       FREE(slab->buffers);
00222       FREE(slab);
00223    }
00224 
00225    pipe_mutex_unlock(mgr->mutex);
00226 }
00227 
00228 
00229 static void *
00230 pb_slab_buffer_map(struct pb_buffer *_buf, 
00231                    unsigned flags)
00232 {
00233    struct pb_slab_buffer *buf = pb_slab_buffer(_buf);
00234 
00235    ++buf->mapCount;
00236    return (void *) ((uint8_t *) buf->slab->virtual + buf->start);
00237 }
00238 
00239 
00240 static void
00241 pb_slab_buffer_unmap(struct pb_buffer *_buf)
00242 {
00243    struct pb_slab_buffer *buf = pb_slab_buffer(_buf);
00244 
00245    --buf->mapCount;
00246    if (buf->mapCount == 0) 
00247        pipe_condvar_broadcast(buf->event);
00248 }
00249 
00250 
00251 static void
00252 pb_slab_buffer_get_base_buffer(struct pb_buffer *_buf,
00253                                struct pb_buffer **base_buf,
00254                                unsigned *offset)
00255 {
00256    struct pb_slab_buffer *buf = pb_slab_buffer(_buf);
00257    pb_get_base_buffer(buf->slab->bo, base_buf, offset);
00258    *offset += buf->start;
00259 }
00260 
00261 
00262 static const struct pb_vtbl 
00263 pb_slab_buffer_vtbl = {
00264       pb_slab_buffer_destroy,
00265       pb_slab_buffer_map,
00266       pb_slab_buffer_unmap,
00267       pb_slab_buffer_get_base_buffer
00268 };
00269 
00270 
00276 static enum pipe_error
00277 pb_slab_create(struct pb_slab_manager *mgr)
00278 {
00279    struct pb_slab *slab;
00280    struct pb_slab_buffer *buf;
00281    unsigned numBuffers;
00282    unsigned i;
00283    enum pipe_error ret;
00284 
00285    slab = CALLOC_STRUCT(pb_slab);
00286    if (!slab)
00287       return PIPE_ERROR_OUT_OF_MEMORY;
00288 
00289    slab->bo = mgr->provider->create_buffer(mgr->provider, mgr->slabSize, &mgr->desc);
00290    if(!slab->bo) {
00291       ret = PIPE_ERROR_OUT_OF_MEMORY;
00292       goto out_err0;
00293    }
00294 
00295    /* Note down the slab virtual address. All mappings are accessed directly 
00296     * through this address so it is required that the buffer is pinned. */
00297    slab->virtual = pb_map(slab->bo, 
00298                           PIPE_BUFFER_USAGE_CPU_READ |
00299                           PIPE_BUFFER_USAGE_CPU_WRITE);
00300    if(!slab->virtual) {
00301       ret = PIPE_ERROR_OUT_OF_MEMORY;
00302       goto out_err1;
00303    }
00304    pb_unmap(slab->bo);
00305 
00306    numBuffers = slab->bo->base.size / mgr->bufSize;
00307 
00308    slab->buffers = CALLOC(numBuffers, sizeof(*slab->buffers));
00309    if (!slab->buffers) {
00310       ret = PIPE_ERROR_OUT_OF_MEMORY;
00311       goto out_err1;
00312    }
00313 
00314    LIST_INITHEAD(&slab->head);
00315    LIST_INITHEAD(&slab->freeBuffers);
00316    slab->numBuffers = numBuffers;
00317    slab->numFree = 0;
00318    slab->mgr = mgr;
00319 
00320    buf = slab->buffers;
00321    for (i=0; i < numBuffers; ++i) {
00322       buf->base.base.refcount = 0;
00323       buf->base.base.size = mgr->bufSize;
00324       buf->base.base.alignment = 0;
00325       buf->base.base.usage = 0;
00326       buf->base.vtbl = &pb_slab_buffer_vtbl;
00327       buf->slab = slab;
00328       buf->start = i* mgr->bufSize;
00329       buf->mapCount = 0;
00330       pipe_condvar_init(buf->event);
00331       LIST_ADDTAIL(&buf->head, &slab->freeBuffers);
00332       slab->numFree++;
00333       buf++;
00334    }
00335 
00336    /* Add this slab to the list of partial slabs */
00337    LIST_ADDTAIL(&slab->head, &mgr->slabs);
00338 
00339    return PIPE_OK;
00340 
00341 out_err1: 
00342    pb_reference(&slab->bo, NULL);
00343 out_err0: 
00344    FREE(slab);
00345    return ret;
00346 }
00347 
00348 
00349 static struct pb_buffer *
00350 pb_slab_manager_create_buffer(struct pb_manager *_mgr,
00351                               size_t size,
00352                               const struct pb_desc *desc)
00353 {
00354    struct pb_slab_manager *mgr = pb_slab_manager(_mgr);
00355    static struct pb_slab_buffer *buf;
00356    struct pb_slab *slab;
00357    struct list_head *list;
00358 
00359    /* check size */
00360    assert(size <= mgr->bufSize);
00361    if(size > mgr->bufSize)
00362       return NULL;
00363    
00364    /* check if we can provide the requested alignment */
00365    assert(pb_check_alignment(desc->alignment, mgr->desc.alignment));
00366    if(!pb_check_alignment(desc->alignment, mgr->desc.alignment))
00367       return NULL;
00368    assert(pb_check_alignment(desc->alignment, mgr->bufSize));
00369    if(!pb_check_alignment(desc->alignment, mgr->bufSize))
00370       return NULL;
00371 
00372    assert(pb_check_usage(desc->usage, mgr->desc.usage));
00373    if(!pb_check_usage(desc->usage, mgr->desc.usage))
00374       return NULL;
00375 
00376    pipe_mutex_lock(mgr->mutex);
00377    
00378    /* Create a new slab, if we run out of partial slabs */
00379    if (mgr->slabs.next == &mgr->slabs) {
00380       (void) pb_slab_create(mgr);
00381       if (mgr->slabs.next == &mgr->slabs) {
00382          pipe_mutex_unlock(mgr->mutex);
00383          return NULL;
00384       }
00385    }
00386    
00387    /* Allocate the buffer from a partial (or just created) slab */
00388    list = mgr->slabs.next;
00389    slab = LIST_ENTRY(struct pb_slab, list, head);
00390    
00391    /* If totally full remove from the partial slab list */
00392    if (--slab->numFree == 0)
00393       LIST_DELINIT(list);
00394 
00395    list = slab->freeBuffers.next;
00396    LIST_DELINIT(list);
00397 
00398    pipe_mutex_unlock(mgr->mutex);
00399    buf = LIST_ENTRY(struct pb_slab_buffer, list, head);
00400    
00401    ++buf->base.base.refcount;
00402    buf->base.base.alignment = desc->alignment;
00403    buf->base.base.usage = desc->usage;
00404    
00405    return &buf->base;
00406 }
00407 
00408 
00409 static void
00410 pb_slab_manager_flush(struct pb_manager *_mgr)
00411 {
00412    struct pb_slab_manager *mgr = pb_slab_manager(_mgr);
00413 
00414    assert(mgr->provider->flush);
00415    if(mgr->provider->flush)
00416       mgr->provider->flush(mgr->provider);
00417 }
00418 
00419 
00420 static void
00421 pb_slab_manager_destroy(struct pb_manager *_mgr)
00422 {
00423    struct pb_slab_manager *mgr = pb_slab_manager(_mgr);
00424 
00425    /* TODO: cleanup all allocated buffers */
00426    FREE(mgr);
00427 }
00428 
00429 
00430 struct pb_manager *
00431 pb_slab_manager_create(struct pb_manager *provider,
00432                        size_t bufSize,
00433                        size_t slabSize,
00434                        const struct pb_desc *desc)
00435 {
00436    struct pb_slab_manager *mgr;
00437 
00438    mgr = CALLOC_STRUCT(pb_slab_manager);
00439    if (!mgr)
00440       return NULL;
00441 
00442    mgr->base.destroy = pb_slab_manager_destroy;
00443    mgr->base.create_buffer = pb_slab_manager_create_buffer;
00444    mgr->base.flush = pb_slab_manager_flush;
00445 
00446    mgr->provider = provider;
00447    mgr->bufSize = bufSize;
00448    mgr->slabSize = slabSize;
00449    mgr->desc = *desc;
00450 
00451    LIST_INITHEAD(&mgr->slabs);
00452    
00453    pipe_mutex_init(mgr->mutex);
00454 
00455    return &mgr->base;
00456 }
00457 
00458 
00459 static struct pb_buffer *
00460 pb_slab_range_manager_create_buffer(struct pb_manager *_mgr,
00461                                     size_t size,
00462                                     const struct pb_desc *desc)
00463 {
00464    struct pb_slab_range_manager *mgr = pb_slab_range_manager(_mgr);
00465    size_t bufSize;
00466    unsigned i;
00467 
00468    bufSize = mgr->minBufSize;
00469    for (i = 0; i < mgr->numBuckets; ++i) {
00470       if(bufSize >= size)
00471          return mgr->buckets[i]->create_buffer(mgr->buckets[i], size, desc);
00472       bufSize *= 2;
00473    }
00474 
00475    /* Fall back to allocate a buffer object directly from the provider. */
00476    return mgr->provider->create_buffer(mgr->provider, size, desc);
00477 }
00478 
00479 
00480 static void
00481 pb_slab_range_manager_flush(struct pb_manager *_mgr)
00482 {
00483    struct pb_slab_range_manager *mgr = pb_slab_range_manager(_mgr);
00484 
00485    /* Individual slabs don't hold any temporary buffers so no need to call them */
00486    
00487    assert(mgr->provider->flush);
00488    if(mgr->provider->flush)
00489       mgr->provider->flush(mgr->provider);
00490 }
00491 
00492 
00493 static void
00494 pb_slab_range_manager_destroy(struct pb_manager *_mgr)
00495 {
00496    struct pb_slab_range_manager *mgr = pb_slab_range_manager(_mgr);
00497    unsigned i;
00498    
00499    for (i = 0; i < mgr->numBuckets; ++i)
00500       mgr->buckets[i]->destroy(mgr->buckets[i]);
00501    FREE(mgr->buckets);
00502    FREE(mgr->bucketSizes);
00503    FREE(mgr);
00504 }
00505 
00506 
00507 struct pb_manager *
00508 pb_slab_range_manager_create(struct pb_manager *provider,
00509                              size_t minBufSize,
00510                              size_t maxBufSize,
00511                              size_t slabSize,
00512                              const struct pb_desc *desc)
00513 {
00514    struct pb_slab_range_manager *mgr;
00515    size_t bufSize;
00516    unsigned i;
00517 
00518    if(!provider)
00519       return NULL;
00520    
00521    mgr = CALLOC_STRUCT(pb_slab_range_manager);
00522    if (!mgr)
00523       goto out_err0;
00524 
00525    mgr->base.destroy = pb_slab_range_manager_destroy;
00526    mgr->base.create_buffer = pb_slab_range_manager_create_buffer;
00527    mgr->base.flush = pb_slab_range_manager_flush;
00528 
00529    mgr->provider = provider;
00530    mgr->minBufSize = minBufSize;
00531    mgr->maxBufSize = maxBufSize;
00532 
00533    mgr->numBuckets = 1;
00534    bufSize = minBufSize;
00535    while(bufSize < maxBufSize) {
00536       bufSize *= 2;
00537       ++mgr->numBuckets;
00538    }
00539    
00540    mgr->buckets = CALLOC(mgr->numBuckets, sizeof(*mgr->buckets));
00541    if (!mgr->buckets)
00542       goto out_err1;
00543 
00544    bufSize = minBufSize;
00545    for (i = 0; i < mgr->numBuckets; ++i) {
00546       mgr->buckets[i] = pb_slab_manager_create(provider, bufSize, slabSize, desc);
00547       if(!mgr->buckets[i])
00548          goto out_err2;
00549       bufSize *= 2;
00550    }
00551 
00552    return &mgr->base;
00553 
00554 out_err2: 
00555    for (i = 0; i < mgr->numBuckets; ++i)
00556       if(mgr->buckets[i])
00557             mgr->buckets[i]->destroy(mgr->buckets[i]);
00558    FREE(mgr->buckets);
00559 out_err1: 
00560    FREE(mgr);
00561 out_err0:
00562    return NULL;
00563 }

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