Home | History | Annotate | Download | only in pipebuffer
      1 /**************************************************************************
      2  *
      3  * Copyright 2006-2008 Tungsten Graphics, Inc., Cedar Park, TX., USA
      4  * All Rights Reserved.
      5  *
      6  * Permission is hereby granted, FREE of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the
      8  * "Software"), to deal in the Software without restriction, including
      9  * without limitation the rights to use, copy, modify, merge, publish,
     10  * distribute, sub license, and/or sell copies of the Software, and to
     11  * permit persons to whom the Software is furnished to do so, subject to
     12  * the following conditions:
     13  *
     14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
     17  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
     18  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
     19  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
     20  * USE OR OTHER DEALINGS IN THE SOFTWARE.
     21  *
     22  * The above copyright notice and this permission notice (including the
     23  * next paragraph) shall be included in all copies or substantial portions
     24  * of the Software.
     25  *
     26  *
     27  **************************************************************************/
     28 
     29 /**
     30  * @file
     31  * S-lab pool implementation.
     32  *
     33  * @sa http://en.wikipedia.org/wiki/Slab_allocation
     34  *
     35  * @author Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
     36  * @author Jose Fonseca <jrfonseca (at) tungstengraphics.com>
     37  */
     38 
     39 #include "pipe/p_compiler.h"
     40 #include "util/u_debug.h"
     41 #include "os/os_thread.h"
     42 #include "pipe/p_defines.h"
     43 #include "util/u_memory.h"
     44 #include "util/u_double_list.h"
     45 #include "util/u_time.h"
     46 
     47 #include "pb_buffer.h"
     48 #include "pb_bufmgr.h"
     49 
     50 
     51 struct pb_slab;
     52 
     53 
     54 /**
     55  * Buffer in a slab.
     56  *
     57  * Sub-allocation of a contiguous buffer.
     58  */
     59 struct pb_slab_buffer
     60 {
     61    struct pb_buffer base;
     62 
     63    struct pb_slab *slab;
     64 
     65    struct list_head head;
     66 
     67    unsigned mapCount;
     68 
     69    /** Offset relative to the start of the slab buffer. */
     70    pb_size start;
     71 
     72    /** Use when validating, to signal that all mappings are finished */
     73    /* TODO: Actually validation does not reach this stage yet */
     74    pipe_condvar event;
     75 };
     76 
     77 
     78 /**
     79  * Slab -- a contiguous piece of memory.
     80  */
     81 struct pb_slab
     82 {
     83    struct list_head head;
     84    struct list_head freeBuffers;
     85    pb_size numBuffers;
     86    pb_size numFree;
     87 
     88    struct pb_slab_buffer *buffers;
     89    struct pb_slab_manager *mgr;
     90 
     91    /** Buffer from the provider */
     92    struct pb_buffer *bo;
     93 
     94    void *virtual;
     95 };
     96 
     97 
     98 /**
     99  * It adds/removes slabs as needed in order to meet the allocation/destruction
    100  * of individual buffers.
    101  */
    102 struct pb_slab_manager
    103 {
    104    struct pb_manager base;
    105 
    106    /** From where we get our buffers */
    107    struct pb_manager *provider;
    108 
    109    /** Size of the buffers we hand on downstream */
    110    pb_size bufSize;
    111 
    112    /** Size of the buffers we request upstream */
    113    pb_size slabSize;
    114 
    115    /**
    116     * Alignment, usage to be used to allocate the slab buffers.
    117     *
    118     * We can only provide buffers which are consistent (in alignment, usage)
    119     * with this description.
    120     */
    121    struct pb_desc desc;
    122 
    123    /**
    124     * Partial slabs
    125     *
    126     * Full slabs are not stored in any list. Empty slabs are destroyed
    127     * immediatly.
    128     */
    129    struct list_head slabs;
    130 
    131    pipe_mutex mutex;
    132 };
    133 
    134 
    135 /**
    136  * Wrapper around several slabs, therefore capable of handling buffers of
    137  * multiple sizes.
    138  *
    139  * This buffer manager just dispatches buffer allocations to the appropriate slab
    140  * manager, according to the requested buffer size, or by passes the slab
    141  * managers altogether for even greater sizes.
    142  *
    143  * The data of this structure remains constant after
    144  * initialization and thus needs no mutex protection.
    145  */
    146 struct pb_slab_range_manager
    147 {
    148    struct pb_manager base;
    149 
    150    struct pb_manager *provider;
    151 
    152    pb_size minBufSize;
    153    pb_size maxBufSize;
    154 
    155    /** @sa pb_slab_manager::desc */
    156    struct pb_desc desc;
    157 
    158    unsigned numBuckets;
    159    pb_size *bucketSizes;
    160 
    161    /** Array of pb_slab_manager, one for each bucket size */
    162    struct pb_manager **buckets;
    163 };
    164 
    165 
    166 static INLINE struct pb_slab_buffer *
    167 pb_slab_buffer(struct pb_buffer *buf)
    168 {
    169    assert(buf);
    170    return (struct pb_slab_buffer *)buf;
    171 }
    172 
    173 
    174 static INLINE struct pb_slab_manager *
    175 pb_slab_manager(struct pb_manager *mgr)
    176 {
    177    assert(mgr);
    178    return (struct pb_slab_manager *)mgr;
    179 }
    180 
    181 
    182 static INLINE struct pb_slab_range_manager *
    183 pb_slab_range_manager(struct pb_manager *mgr)
    184 {
    185    assert(mgr);
    186    return (struct pb_slab_range_manager *)mgr;
    187 }
    188 
    189 
    190 /**
    191  * Delete a buffer from the slab delayed list and put
    192  * it on the slab FREE list.
    193  */
    194 static void
    195 pb_slab_buffer_destroy(struct pb_buffer *_buf)
    196 {
    197    struct pb_slab_buffer *buf = pb_slab_buffer(_buf);
    198    struct pb_slab *slab = buf->slab;
    199    struct pb_slab_manager *mgr = slab->mgr;
    200    struct list_head *list = &buf->head;
    201 
    202    pipe_mutex_lock(mgr->mutex);
    203 
    204    assert(!pipe_is_referenced(&buf->base.reference));
    205 
    206    buf->mapCount = 0;
    207 
    208    LIST_DEL(list);
    209    LIST_ADDTAIL(list, &slab->freeBuffers);
    210    slab->numFree++;
    211 
    212    if (slab->head.next == &slab->head)
    213       LIST_ADDTAIL(&slab->head, &mgr->slabs);
    214 
    215    /* If the slab becomes totally empty, free it */
    216    if (slab->numFree == slab->numBuffers) {
    217       list = &slab->head;
    218       LIST_DELINIT(list);
    219       pb_reference(&slab->bo, NULL);
    220       FREE(slab->buffers);
    221       FREE(slab);
    222    }
    223 
    224    pipe_mutex_unlock(mgr->mutex);
    225 }
    226 
    227 
    228 static void *
    229 pb_slab_buffer_map(struct pb_buffer *_buf,
    230                    unsigned flags,
    231                    void *flush_ctx)
    232 {
    233    struct pb_slab_buffer *buf = pb_slab_buffer(_buf);
    234 
    235    /* XXX: it will be necessary to remap here to propagate flush_ctx */
    236 
    237    ++buf->mapCount;
    238    return (void *) ((uint8_t *) buf->slab->virtual + buf->start);
    239 }
    240 
    241 
    242 static void
    243 pb_slab_buffer_unmap(struct pb_buffer *_buf)
    244 {
    245    struct pb_slab_buffer *buf = pb_slab_buffer(_buf);
    246 
    247    --buf->mapCount;
    248    if (buf->mapCount == 0)
    249        pipe_condvar_broadcast(buf->event);
    250 }
    251 
    252 
    253 static enum pipe_error
    254 pb_slab_buffer_validate(struct pb_buffer *_buf,
    255                          struct pb_validate *vl,
    256                          unsigned flags)
    257 {
    258    struct pb_slab_buffer *buf = pb_slab_buffer(_buf);
    259    return pb_validate(buf->slab->bo, vl, flags);
    260 }
    261 
    262 
    263 static void
    264 pb_slab_buffer_fence(struct pb_buffer *_buf,
    265                       struct pipe_fence_handle *fence)
    266 {
    267    struct pb_slab_buffer *buf = pb_slab_buffer(_buf);
    268    pb_fence(buf->slab->bo, fence);
    269 }
    270 
    271 
    272 static void
    273 pb_slab_buffer_get_base_buffer(struct pb_buffer *_buf,
    274                                struct pb_buffer **base_buf,
    275                                pb_size *offset)
    276 {
    277    struct pb_slab_buffer *buf = pb_slab_buffer(_buf);
    278    pb_get_base_buffer(buf->slab->bo, base_buf, offset);
    279    *offset += buf->start;
    280 }
    281 
    282 
    283 static const struct pb_vtbl
    284 pb_slab_buffer_vtbl = {
    285       pb_slab_buffer_destroy,
    286       pb_slab_buffer_map,
    287       pb_slab_buffer_unmap,
    288       pb_slab_buffer_validate,
    289       pb_slab_buffer_fence,
    290       pb_slab_buffer_get_base_buffer
    291 };
    292 
    293 
    294 /**
    295  * Create a new slab.
    296  *
    297  * Called when we ran out of free slabs.
    298  */
    299 static enum pipe_error
    300 pb_slab_create(struct pb_slab_manager *mgr)
    301 {
    302    struct pb_slab *slab;
    303    struct pb_slab_buffer *buf;
    304    unsigned numBuffers;
    305    unsigned i;
    306    enum pipe_error ret;
    307 
    308    slab = CALLOC_STRUCT(pb_slab);
    309    if (!slab)
    310       return PIPE_ERROR_OUT_OF_MEMORY;
    311 
    312    slab->bo = mgr->provider->create_buffer(mgr->provider, mgr->slabSize, &mgr->desc);
    313    if(!slab->bo) {
    314       ret = PIPE_ERROR_OUT_OF_MEMORY;
    315       goto out_err0;
    316    }
    317 
    318    /* Note down the slab virtual address. All mappings are accessed directly
    319     * through this address so it is required that the buffer is pinned. */
    320    slab->virtual = pb_map(slab->bo,
    321                           PB_USAGE_CPU_READ |
    322                           PB_USAGE_CPU_WRITE, NULL);
    323    if(!slab->virtual) {
    324       ret = PIPE_ERROR_OUT_OF_MEMORY;
    325       goto out_err1;
    326    }
    327    pb_unmap(slab->bo);
    328 
    329    numBuffers = slab->bo->size / mgr->bufSize;
    330 
    331    slab->buffers = CALLOC(numBuffers, sizeof(*slab->buffers));
    332    if (!slab->buffers) {
    333       ret = PIPE_ERROR_OUT_OF_MEMORY;
    334       goto out_err1;
    335    }
    336 
    337    LIST_INITHEAD(&slab->head);
    338    LIST_INITHEAD(&slab->freeBuffers);
    339    slab->numBuffers = numBuffers;
    340    slab->numFree = 0;
    341    slab->mgr = mgr;
    342 
    343    buf = slab->buffers;
    344    for (i=0; i < numBuffers; ++i) {
    345       pipe_reference_init(&buf->base.reference, 0);
    346       buf->base.size = mgr->bufSize;
    347       buf->base.alignment = 0;
    348       buf->base.usage = 0;
    349       buf->base.vtbl = &pb_slab_buffer_vtbl;
    350       buf->slab = slab;
    351       buf->start = i* mgr->bufSize;
    352       buf->mapCount = 0;
    353       pipe_condvar_init(buf->event);
    354       LIST_ADDTAIL(&buf->head, &slab->freeBuffers);
    355       slab->numFree++;
    356       buf++;
    357    }
    358 
    359    /* Add this slab to the list of partial slabs */
    360    LIST_ADDTAIL(&slab->head, &mgr->slabs);
    361 
    362    return PIPE_OK;
    363 
    364 out_err1:
    365    pb_reference(&slab->bo, NULL);
    366 out_err0:
    367    FREE(slab);
    368    return ret;
    369 }
    370 
    371 
    372 static struct pb_buffer *
    373 pb_slab_manager_create_buffer(struct pb_manager *_mgr,
    374                               pb_size size,
    375                               const struct pb_desc *desc)
    376 {
    377    struct pb_slab_manager *mgr = pb_slab_manager(_mgr);
    378    static struct pb_slab_buffer *buf;
    379    struct pb_slab *slab;
    380    struct list_head *list;
    381 
    382    /* check size */
    383    assert(size <= mgr->bufSize);
    384    if(size > mgr->bufSize)
    385       return NULL;
    386 
    387    /* check if we can provide the requested alignment */
    388    assert(pb_check_alignment(desc->alignment, mgr->desc.alignment));
    389    if(!pb_check_alignment(desc->alignment, mgr->desc.alignment))
    390       return NULL;
    391    assert(pb_check_alignment(desc->alignment, mgr->bufSize));
    392    if(!pb_check_alignment(desc->alignment, mgr->bufSize))
    393       return NULL;
    394 
    395    assert(pb_check_usage(desc->usage, mgr->desc.usage));
    396    if(!pb_check_usage(desc->usage, mgr->desc.usage))
    397       return NULL;
    398 
    399    pipe_mutex_lock(mgr->mutex);
    400 
    401    /* Create a new slab, if we run out of partial slabs */
    402    if (mgr->slabs.next == &mgr->slabs) {
    403       (void) pb_slab_create(mgr);
    404       if (mgr->slabs.next == &mgr->slabs) {
    405 	 pipe_mutex_unlock(mgr->mutex);
    406 	 return NULL;
    407       }
    408    }
    409 
    410    /* Allocate the buffer from a partial (or just created) slab */
    411    list = mgr->slabs.next;
    412    slab = LIST_ENTRY(struct pb_slab, list, head);
    413 
    414    /* If totally full remove from the partial slab list */
    415    if (--slab->numFree == 0)
    416       LIST_DELINIT(list);
    417 
    418    list = slab->freeBuffers.next;
    419    LIST_DELINIT(list);
    420 
    421    pipe_mutex_unlock(mgr->mutex);
    422    buf = LIST_ENTRY(struct pb_slab_buffer, list, head);
    423 
    424    pipe_reference_init(&buf->base.reference, 1);
    425    buf->base.alignment = desc->alignment;
    426    buf->base.usage = desc->usage;
    427 
    428    return &buf->base;
    429 }
    430 
    431 
    432 static void
    433 pb_slab_manager_flush(struct pb_manager *_mgr)
    434 {
    435    struct pb_slab_manager *mgr = pb_slab_manager(_mgr);
    436 
    437    assert(mgr->provider->flush);
    438    if(mgr->provider->flush)
    439       mgr->provider->flush(mgr->provider);
    440 }
    441 
    442 
    443 static void
    444 pb_slab_manager_destroy(struct pb_manager *_mgr)
    445 {
    446    struct pb_slab_manager *mgr = pb_slab_manager(_mgr);
    447 
    448    /* TODO: cleanup all allocated buffers */
    449    FREE(mgr);
    450 }
    451 
    452 
    453 struct pb_manager *
    454 pb_slab_manager_create(struct pb_manager *provider,
    455                        pb_size bufSize,
    456                        pb_size slabSize,
    457                        const struct pb_desc *desc)
    458 {
    459    struct pb_slab_manager *mgr;
    460 
    461    mgr = CALLOC_STRUCT(pb_slab_manager);
    462    if (!mgr)
    463       return NULL;
    464 
    465    mgr->base.destroy = pb_slab_manager_destroy;
    466    mgr->base.create_buffer = pb_slab_manager_create_buffer;
    467    mgr->base.flush = pb_slab_manager_flush;
    468 
    469    mgr->provider = provider;
    470    mgr->bufSize = bufSize;
    471    mgr->slabSize = slabSize;
    472    mgr->desc = *desc;
    473 
    474    LIST_INITHEAD(&mgr->slabs);
    475 
    476    pipe_mutex_init(mgr->mutex);
    477 
    478    return &mgr->base;
    479 }
    480 
    481 
    482 static struct pb_buffer *
    483 pb_slab_range_manager_create_buffer(struct pb_manager *_mgr,
    484                                     pb_size size,
    485                                     const struct pb_desc *desc)
    486 {
    487    struct pb_slab_range_manager *mgr = pb_slab_range_manager(_mgr);
    488    pb_size bufSize;
    489    pb_size reqSize = size;
    490    unsigned i;
    491 
    492    if(desc->alignment > reqSize)
    493 	   reqSize = desc->alignment;
    494 
    495    bufSize = mgr->minBufSize;
    496    for (i = 0; i < mgr->numBuckets; ++i) {
    497       if(bufSize >= reqSize)
    498 	 return mgr->buckets[i]->create_buffer(mgr->buckets[i], size, desc);
    499       bufSize *= 2;
    500    }
    501 
    502    /* Fall back to allocate a buffer object directly from the provider. */
    503    return mgr->provider->create_buffer(mgr->provider, size, desc);
    504 }
    505 
    506 
    507 static void
    508 pb_slab_range_manager_flush(struct pb_manager *_mgr)
    509 {
    510    struct pb_slab_range_manager *mgr = pb_slab_range_manager(_mgr);
    511 
    512    /* Individual slabs don't hold any temporary buffers so no need to call them */
    513 
    514    assert(mgr->provider->flush);
    515    if(mgr->provider->flush)
    516       mgr->provider->flush(mgr->provider);
    517 }
    518 
    519 
    520 static void
    521 pb_slab_range_manager_destroy(struct pb_manager *_mgr)
    522 {
    523    struct pb_slab_range_manager *mgr = pb_slab_range_manager(_mgr);
    524    unsigned i;
    525 
    526    for (i = 0; i < mgr->numBuckets; ++i)
    527       mgr->buckets[i]->destroy(mgr->buckets[i]);
    528    FREE(mgr->buckets);
    529    FREE(mgr->bucketSizes);
    530    FREE(mgr);
    531 }
    532 
    533 
    534 struct pb_manager *
    535 pb_slab_range_manager_create(struct pb_manager *provider,
    536                              pb_size minBufSize,
    537                              pb_size maxBufSize,
    538                              pb_size slabSize,
    539                              const struct pb_desc *desc)
    540 {
    541    struct pb_slab_range_manager *mgr;
    542    pb_size bufSize;
    543    unsigned i;
    544 
    545    if(!provider)
    546       return NULL;
    547 
    548    mgr = CALLOC_STRUCT(pb_slab_range_manager);
    549    if (!mgr)
    550       goto out_err0;
    551 
    552    mgr->base.destroy = pb_slab_range_manager_destroy;
    553    mgr->base.create_buffer = pb_slab_range_manager_create_buffer;
    554    mgr->base.flush = pb_slab_range_manager_flush;
    555 
    556    mgr->provider = provider;
    557    mgr->minBufSize = minBufSize;
    558    mgr->maxBufSize = maxBufSize;
    559 
    560    mgr->numBuckets = 1;
    561    bufSize = minBufSize;
    562    while(bufSize < maxBufSize) {
    563       bufSize *= 2;
    564       ++mgr->numBuckets;
    565    }
    566 
    567    mgr->buckets = CALLOC(mgr->numBuckets, sizeof(*mgr->buckets));
    568    if (!mgr->buckets)
    569       goto out_err1;
    570 
    571    bufSize = minBufSize;
    572    for (i = 0; i < mgr->numBuckets; ++i) {
    573       mgr->buckets[i] = pb_slab_manager_create(provider, bufSize, slabSize, desc);
    574       if(!mgr->buckets[i])
    575 	 goto out_err2;
    576       bufSize *= 2;
    577    }
    578 
    579    return &mgr->base;
    580 
    581 out_err2:
    582    for (i = 0; i < mgr->numBuckets; ++i)
    583       if(mgr->buckets[i])
    584 	    mgr->buckets[i]->destroy(mgr->buckets[i]);
    585    FREE(mgr->buckets);
    586 out_err1:
    587    FREE(mgr);
    588 out_err0:
    589    return NULL;
    590 }
    591