Home | History | Annotate | Download | only in gpu
      1 /*
      2  * Copyright 2010 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #ifndef GrAllocator_DEFINED
      9 #define GrAllocator_DEFINED
     10 
     11 #include "GrConfig.h"
     12 #include "GrTypes.h"
     13 #include "SkTArray.h"
     14 #include "SkTypes.h"
     15 
     16 class GrAllocator : SkNoncopyable {
     17 public:
     18     ~GrAllocator() {
     19         reset();
     20     }
     21 
     22     /**
     23      * Create an allocator
     24      *
     25      * @param   itemSize        the size of each item to allocate
     26      * @param   itemsPerBlock   the number of items to allocate at once
     27      * @param   initialBlock    optional memory to use for the first block.
     28      *                          Must be at least itemSize*itemsPerBlock sized.
     29      *                          Caller is responsible for freeing this memory.
     30      */
     31     GrAllocator(size_t itemSize, int itemsPerBlock, void* initialBlock) :
     32             fItemSize(itemSize),
     33             fItemsPerBlock(itemsPerBlock),
     34             fOwnFirstBlock(NULL == initialBlock),
     35             fCount(0) {
     36         SkASSERT(itemsPerBlock > 0);
     37         fBlockSize = fItemSize * fItemsPerBlock;
     38         fBlocks.push_back() = initialBlock;
     39         SkDEBUGCODE(if (!fOwnFirstBlock) {*((char*)initialBlock+fBlockSize-1)='a';} );
     40     }
     41 
     42     /*
     43      * Set first block of memory to write into.  Must be called before any other methods.
     44      * This requires that you have passed NULL in the constructor.
     45      *
     46      * @param   initialBlock    optional memory to use for the first block.
     47      *                          Must be at least itemSize*itemsPerBlock sized.
     48      *                          Caller is responsible for freeing this memory.
     49      */
     50     void setInitialBlock(void* initialBlock) {
     51         SkASSERT(0 == fCount);
     52         SkASSERT(1 == fBlocks.count());
     53         SkASSERT(NULL == fBlocks.back());
     54         fOwnFirstBlock = false;
     55         fBlocks.back() = initialBlock;
     56     }
     57 
     58     /**
     59      * Adds an item and returns pointer to it.
     60      *
     61      * @return pointer to the added item.
     62      */
     63     void* push_back() {
     64         int indexInBlock = fCount % fItemsPerBlock;
     65         // we always have at least one block
     66         if (0 == indexInBlock) {
     67             if (0 != fCount) {
     68                 fBlocks.push_back() = sk_malloc_throw(fBlockSize);
     69             } else if (fOwnFirstBlock) {
     70                 fBlocks[0] = sk_malloc_throw(fBlockSize);
     71             }
     72         }
     73         void* ret = (char*)fBlocks[fCount/fItemsPerBlock] +
     74                     fItemSize * indexInBlock;
     75         ++fCount;
     76         return ret;
     77     }
     78 
     79     /**
     80      * removes all added items
     81      */
     82     void reset() {
     83         int blockCount = SkTMax((unsigned)1,
     84                                GrUIDivRoundUp(fCount, fItemsPerBlock));
     85         for (int i = 1; i < blockCount; ++i) {
     86             sk_free(fBlocks[i]);
     87         }
     88         if (fOwnFirstBlock) {
     89             sk_free(fBlocks[0]);
     90             fBlocks[0] = NULL;
     91         }
     92         fBlocks.pop_back_n(blockCount-1);
     93         fCount = 0;
     94     }
     95 
     96     /**
     97      * count of items
     98      */
     99     int count() const {
    100         return fCount;
    101     }
    102 
    103     /**
    104      * is the count 0
    105      */
    106     bool empty() const { return fCount == 0; }
    107 
    108     /**
    109      * access last item, only call if count() != 0
    110      */
    111     void* back() {
    112         SkASSERT(fCount);
    113         return (*this)[fCount-1];
    114     }
    115 
    116     /**
    117      * access last item, only call if count() != 0
    118      */
    119     const void* back() const {
    120         SkASSERT(fCount);
    121         return (*this)[fCount-1];
    122     }
    123 
    124     /**
    125      * access item by index.
    126      */
    127     void* operator[] (int i) {
    128         SkASSERT(i >= 0 && i < fCount);
    129         return (char*)fBlocks[i / fItemsPerBlock] +
    130                fItemSize * (i % fItemsPerBlock);
    131     }
    132 
    133     /**
    134      * access item by index.
    135      */
    136     const void* operator[] (int i) const {
    137         SkASSERT(i >= 0 && i < fCount);
    138         return (const char*)fBlocks[i / fItemsPerBlock] +
    139                fItemSize * (i % fItemsPerBlock);
    140     }
    141 
    142 private:
    143     static const int NUM_INIT_BLOCK_PTRS = 8;
    144 
    145     SkSTArray<NUM_INIT_BLOCK_PTRS, void*>   fBlocks;
    146     size_t                                  fBlockSize;
    147     size_t                                  fItemSize;
    148     int                                     fItemsPerBlock;
    149     bool                                    fOwnFirstBlock;
    150     int                                     fCount;
    151 
    152     typedef SkNoncopyable INHERITED;
    153 };
    154 
    155 template <typename T>
    156 class GrTAllocator : SkNoncopyable {
    157 public:
    158     virtual ~GrTAllocator() { this->reset(); };
    159 
    160     /**
    161      * Create an allocator
    162      *
    163      * @param   itemsPerBlock   the number of items to allocate at once
    164      */
    165     explicit GrTAllocator(int itemsPerBlock)
    166         : fAllocator(sizeof(T), itemsPerBlock, NULL) {}
    167 
    168     /**
    169      * Adds an item and returns it.
    170      *
    171      * @return the added item.
    172      */
    173     T& push_back() {
    174         void* item = fAllocator.push_back();
    175         SkASSERT(NULL != item);
    176         SkNEW_PLACEMENT(item, T);
    177         return *(T*)item;
    178     }
    179 
    180     T& push_back(const T& t) {
    181         void* item = fAllocator.push_back();
    182         SkASSERT(NULL != item);
    183         SkNEW_PLACEMENT_ARGS(item, T, (t));
    184         return *(T*)item;
    185     }
    186 
    187     /**
    188      * removes all added items
    189      */
    190     void reset() {
    191         int c = fAllocator.count();
    192         for (int i = 0; i < c; ++i) {
    193             ((T*)fAllocator[i])->~T();
    194         }
    195         fAllocator.reset();
    196     }
    197 
    198     /**
    199      * count of items
    200      */
    201     int count() const {
    202         return fAllocator.count();
    203     }
    204 
    205     /**
    206      * is the count 0
    207      */
    208     bool empty() const { return fAllocator.empty(); }
    209 
    210     /**
    211      * access last item, only call if count() != 0
    212      */
    213     T& back() {
    214         return *(T*)fAllocator.back();
    215     }
    216 
    217     /**
    218      * access last item, only call if count() != 0
    219      */
    220     const T& back() const {
    221         return *(const T*)fAllocator.back();
    222     }
    223 
    224     /**
    225      * access item by index.
    226      */
    227     T& operator[] (int i) {
    228         return *(T*)(fAllocator[i]);
    229     }
    230 
    231     /**
    232      * access item by index.
    233      */
    234     const T& operator[] (int i) const {
    235         return *(const T*)(fAllocator[i]);
    236     }
    237 
    238 protected:
    239     /*
    240      * Set first block of memory to write into.  Must be called before any other methods.
    241      *
    242      * @param   initialBlock    optional memory to use for the first block.
    243      *                          Must be at least size(T)*itemsPerBlock sized.
    244      *                          Caller is responsible for freeing this memory.
    245      */
    246     void setInitialBlock(void* initialBlock) {
    247         fAllocator.setInitialBlock(initialBlock);
    248     }
    249 
    250 private:
    251     GrAllocator fAllocator;
    252     typedef SkNoncopyable INHERITED;
    253 };
    254 
    255 template <int N, typename T> class GrSTAllocator : public GrTAllocator<T> {
    256 private:
    257     typedef GrTAllocator<T> INHERITED;
    258 
    259 public:
    260     GrSTAllocator() : INHERITED(N) {
    261         this->setInitialBlock(fStorage.get());
    262     }
    263 
    264 private:
    265     SkAlignedSTStorage<N, T> fStorage;
    266 };
    267 
    268 #endif
    269