| /* | 
 |  * Copyright 2010 Google Inc. | 
 |  * | 
 |  * Use of this source code is governed by a BSD-style license that can be | 
 |  * found in the LICENSE file. | 
 |  */ | 
 |  | 
 | #ifndef GrBufferAllocPool_DEFINED | 
 | #define GrBufferAllocPool_DEFINED | 
 |  | 
 | #include "SkTArray.h" | 
 | #include "SkTDArray.h" | 
 | #include "SkTypes.h" | 
 |  | 
 | class GrGeometryBuffer; | 
 | class GrGpu; | 
 |  | 
 | /** | 
 |  * A pool of geometry buffers tied to a GrGpu. | 
 |  * | 
 |  * The pool allows a client to make space for geometry and then put back excess | 
 |  * space if it over allocated. When a client is ready to draw from the pool | 
 |  * it calls unmap on the pool ensure buffers are ready for drawing. The pool | 
 |  * can be reset after drawing is completed to recycle space. | 
 |  * | 
 |  * At creation time a minimum per-buffer size can be specified. Additionally, | 
 |  * a number of buffers to preallocate can be specified. These will | 
 |  * be allocated at the min size and kept around until the pool is destroyed. | 
 |  */ | 
 | class GrBufferAllocPool : SkNoncopyable { | 
 | public: | 
 |     /** | 
 |      * Ensures all buffers are unmapped and have all data written to them. | 
 |      * Call before drawing using buffers from the pool. | 
 |      */ | 
 |     void unmap(); | 
 |  | 
 |     /** | 
 |      *  Invalidates all the data in the pool, unrefs non-preallocated buffers. | 
 |      */ | 
 |     void reset(); | 
 |  | 
 |     /** | 
 |      * Gets the number of preallocated buffers that are yet to be used. | 
 |      */ | 
 |     int preallocatedBuffersRemaining() const; | 
 |  | 
 |     /** | 
 |      * gets the number of preallocated buffers | 
 |      */ | 
 |     int preallocatedBufferCount() const; | 
 |  | 
 |     /** | 
 |      * Frees data from makeSpaces in LIFO order. | 
 |      */ | 
 |     void putBack(size_t bytes); | 
 |  | 
 |     /** | 
 |      * Gets the GrGpu that this pool is associated with. | 
 |      */ | 
 |     GrGpu* getGpu() { return fGpu; } | 
 |  | 
 | protected: | 
 |     /** | 
 |      * Used to determine what type of buffers to create. We could make the | 
 |      * createBuffer a virtual except that we want to use it in the cons for | 
 |      * pre-allocated buffers. | 
 |      */ | 
 |     enum BufferType { | 
 |         kVertex_BufferType, | 
 |         kIndex_BufferType, | 
 |     }; | 
 |  | 
 |     /** | 
 |      * Constructor | 
 |      * | 
 |      * @param gpu                   The GrGpu used to create the buffers. | 
 |      * @param bufferType            The type of buffers to create. | 
 |      * @param frequentResetHint     A hint that indicates that the pool | 
 |      *                              should expect frequent unmap() calls | 
 |      *                              (as opposed to many makeSpace / acquires | 
 |      *                              between resets). | 
 |      * @param bufferSize            The minimum size of created buffers. | 
 |      *                              This value will be clamped to some | 
 |      *                              reasonable minimum. | 
 |      * @param preallocBufferCnt     The pool will allocate this number of | 
 |      *                              buffers at bufferSize and keep them until it | 
 |      *                              is destroyed. | 
 |      */ | 
 |      GrBufferAllocPool(GrGpu* gpu, | 
 |                        BufferType bufferType, | 
 |                        bool frequentResetHint, | 
 |                        size_t   bufferSize = 0, | 
 |                        int preallocBufferCnt = 0); | 
 |  | 
 |     virtual ~GrBufferAllocPool(); | 
 |  | 
 |     /** | 
 |      * Gets the size of the preallocated buffers. | 
 |      * | 
 |      * @return the size of preallocated buffers. | 
 |      */ | 
 |     size_t preallocatedBufferSize() const { | 
 |         return fPreallocBuffers.count() ? fMinBlockSize : 0; | 
 |     } | 
 |  | 
 |     /** | 
 |      * Returns a block of memory to hold data. A buffer designated to hold the | 
 |      * data is given to the caller. The buffer may or may not be locked. The | 
 |      * returned ptr remains valid until any of the following: | 
 |      *      *makeSpace is called again. | 
 |      *      *unmap is called. | 
 |      *      *reset is called. | 
 |      *      *this object is destroyed. | 
 |      * | 
 |      * Once unmap on the pool is called the data is guaranteed to be in the | 
 |      * buffer at the offset indicated by offset. Until that time it may be | 
 |      * in temporary storage and/or the buffer may be locked. | 
 |      * | 
 |      * @param size         the amount of data to make space for | 
 |      * @param alignment    alignment constraint from start of buffer | 
 |      * @param buffer       returns the buffer that will hold the data. | 
 |      * @param offset       returns the offset into buffer of the data. | 
 |      * @return pointer to where the client should write the data. | 
 |      */ | 
 |     void* makeSpace(size_t size, | 
 |                     size_t alignment, | 
 |                     const GrGeometryBuffer** buffer, | 
 |                     size_t* offset); | 
 |  | 
 |     /** | 
 |      * Gets the number of items of a size that can be added to the current | 
 |      * buffer without spilling to another buffer. If the pool has been reset, or | 
 |      * the previous makeSpace completely exhausted a buffer then the returned | 
 |      * size will be the size of the next available preallocated buffer, or zero | 
 |      * if no preallocated buffer remains available. It is assumed that items | 
 |      * should be itemSize-aligned from the start of a buffer. | 
 |      * | 
 |      * @return the number of items that would fit in the current buffer. | 
 |      */ | 
 |     int currentBufferItems(size_t itemSize) const; | 
 |  | 
 |     GrGeometryBuffer* createBuffer(size_t size); | 
 |  | 
 | private: | 
 |  | 
 |     // The GrGpu must be able to clear the ref of pools it creates as members | 
 |     friend class GrGpu; | 
 |     void releaseGpuRef(); | 
 |  | 
 |     struct BufferBlock { | 
 |         size_t              fBytesFree; | 
 |         GrGeometryBuffer*   fBuffer; | 
 |     }; | 
 |  | 
 |     bool createBlock(size_t requestSize); | 
 |     void destroyBlock(); | 
 |     void flushCpuData(const BufferBlock& block, size_t flushSize); | 
 | #ifdef SK_DEBUG | 
 |     void validate(bool unusedBlockAllowed = false) const; | 
 | #endif | 
 |  | 
 |     size_t                          fBytesInUse; | 
 |  | 
 |     GrGpu*                          fGpu; | 
 |     bool                            fGpuIsReffed; | 
 |     bool                            fFrequentResetHint; | 
 |     SkTDArray<GrGeometryBuffer*>    fPreallocBuffers; | 
 |     size_t                          fMinBlockSize; | 
 |     BufferType                      fBufferType; | 
 |  | 
 |     SkTArray<BufferBlock>           fBlocks; | 
 |     int                             fPreallocBuffersInUse; | 
 |     // We attempt to cycle through the preallocated buffers rather than | 
 |     // always starting from the first. | 
 |     int                             fPreallocBufferStartIdx; | 
 |     SkAutoMalloc                    fCpuData; | 
 |     void*                           fBufferPtr; | 
 | }; | 
 |  | 
 | class GrVertexBuffer; | 
 |  | 
 | /** | 
 |  * A GrBufferAllocPool of vertex buffers | 
 |  */ | 
 | class GrVertexBufferAllocPool : public GrBufferAllocPool { | 
 | public: | 
 |     /** | 
 |      * Constructor | 
 |      * | 
 |      * @param gpu                   The GrGpu used to create the vertex buffers. | 
 |      * @param frequentResetHint     A hint that indicates that the pool | 
 |      *                              should expect frequent unmap() calls | 
 |      *                              (as opposed to many makeSpace / acquires | 
 |      *                              between resets). | 
 |      * @param bufferSize            The minimum size of created VBs This value | 
 |      *                              will be clamped to some reasonable minimum. | 
 |      * @param preallocBufferCnt     The pool will allocate this number of VBs at | 
 |      *                              bufferSize and keep them until it is | 
 |      *                              destroyed. | 
 |      */ | 
 |     GrVertexBufferAllocPool(GrGpu* gpu, | 
 |                             bool frequentResetHint, | 
 |                             size_t bufferSize = 0, | 
 |                             int preallocBufferCnt = 0); | 
 |  | 
 |     /** | 
 |      * Returns a block of memory to hold vertices. A buffer designated to hold | 
 |      * the vertices given to the caller. The buffer may or may not be locked. | 
 |      * The returned ptr remains valid until any of the following: | 
 |      *      *makeSpace is called again. | 
 |      *      *unmap is called. | 
 |      *      *reset is called. | 
 |      *      *this object is destroyed. | 
 |      * | 
 |      * Once unmap on the pool is called the vertices are guaranteed to be in | 
 |      * the buffer at the offset indicated by startVertex. Until that time they | 
 |      * may be in temporary storage and/or the buffer may be locked. | 
 |      * | 
 |      * @param vertexSize   specifies size of a vertex to allocate space for | 
 |      * @param vertexCount  number of vertices to allocate space for | 
 |      * @param buffer       returns the vertex buffer that will hold the | 
 |      *                     vertices. | 
 |      * @param startVertex  returns the offset into buffer of the first vertex. | 
 |      *                     In units of the size of a vertex from layout param. | 
 |      * @return pointer to first vertex. | 
 |      */ | 
 |     void* makeSpace(size_t vertexSize, | 
 |                     int vertexCount, | 
 |                     const GrVertexBuffer** buffer, | 
 |                     int* startVertex); | 
 |  | 
 |     /** | 
 |      * Shortcut to make space and then write verts into the made space. | 
 |      */ | 
 |     bool appendVertices(size_t vertexSize, | 
 |                         int vertexCount, | 
 |                         const void* vertices, | 
 |                         const GrVertexBuffer** buffer, | 
 |                         int* startVertex); | 
 |  | 
 |     /** | 
 |      * Gets the number of vertices that can be added to the current VB without | 
 |      * spilling to another VB. If the pool has been reset, or the previous | 
 |      * makeSpace completely exhausted a VB then the returned number of vertices | 
 |      * would fit in the next available preallocated buffer. If any makeSpace | 
 |      * would force a new VB to be created the return value will be zero. | 
 |      * | 
 |      * @param   the size of a vertex to compute space for. | 
 |      * @return the number of vertices that would fit in the current buffer. | 
 |      */ | 
 |     int currentBufferVertices(size_t vertexSize) const; | 
 |  | 
 |     /** | 
 |      * Gets the number of vertices that can fit in a  preallocated vertex buffer. | 
 |      * Zero if no preallocated buffers. | 
 |      * | 
 |      * @param   the size of a vertex to compute space for. | 
 |      * | 
 |      * @return number of vertices that fit in one of the preallocated vertex | 
 |      *         buffers. | 
 |      */ | 
 |     int preallocatedBufferVertices(size_t vertexSize) const; | 
 |  | 
 | private: | 
 |     typedef GrBufferAllocPool INHERITED; | 
 | }; | 
 |  | 
 | class GrIndexBuffer; | 
 |  | 
 | /** | 
 |  * A GrBufferAllocPool of index buffers | 
 |  */ | 
 | class GrIndexBufferAllocPool : public GrBufferAllocPool { | 
 | public: | 
 |     /** | 
 |      * Constructor | 
 |      * | 
 |      * @param gpu                   The GrGpu used to create the index buffers. | 
 |      * @param frequentResetHint     A hint that indicates that the pool | 
 |      *                              should expect frequent unmap() calls | 
 |      *                              (as opposed to many makeSpace / acquires | 
 |      *                              between resets). | 
 |      * @param bufferSize            The minimum size of created IBs This value | 
 |      *                              will be clamped to some reasonable minimum. | 
 |      * @param preallocBufferCnt     The pool will allocate this number of VBs at | 
 |      *                              bufferSize and keep them until it is | 
 |      *                              destroyed. | 
 |      */ | 
 |     GrIndexBufferAllocPool(GrGpu* gpu, | 
 |                            bool frequentResetHint, | 
 |                            size_t bufferSize = 0, | 
 |                            int preallocBufferCnt = 0); | 
 |  | 
 |     /** | 
 |      * Returns a block of memory to hold indices. A buffer designated to hold | 
 |      * the indices is given to the caller. The buffer may or may not be locked. | 
 |      * The returned ptr remains valid until any of the following: | 
 |      *      *makeSpace is called again. | 
 |      *      *unmap is called. | 
 |      *      *reset is called. | 
 |      *      *this object is destroyed. | 
 |      * | 
 |      * Once unmap on the pool is called the indices are guaranteed to be in the | 
 |      * buffer at the offset indicated by startIndex. Until that time they may be | 
 |      * in temporary storage and/or the buffer may be locked. | 
 |      * | 
 |      * @param indexCount   number of indices to allocate space for | 
 |      * @param buffer       returns the index buffer that will hold the indices. | 
 |      * @param startIndex   returns the offset into buffer of the first index. | 
 |      * @return pointer to first index. | 
 |      */ | 
 |     void* makeSpace(int indexCount, | 
 |                     const GrIndexBuffer** buffer, | 
 |                     int* startIndex); | 
 |  | 
 |     /** | 
 |      * Shortcut to make space and then write indices into the made space. | 
 |      */ | 
 |     bool appendIndices(int indexCount, | 
 |                        const void* indices, | 
 |                        const GrIndexBuffer** buffer, | 
 |                        int* startIndex); | 
 |  | 
 |     /** | 
 |      * Gets the number of indices that can be added to the current IB without | 
 |      * spilling to another IB. If the pool has been reset, or the previous | 
 |      * makeSpace completely exhausted a IB then the returned number of indices | 
 |      * would fit in the next available preallocated buffer. If any makeSpace | 
 |      * would force a new IB to be created the return value will be zero. | 
 |      */ | 
 |     int currentBufferIndices() const; | 
 |  | 
 |     /** | 
 |      * Gets the number of indices that can fit in a preallocated index buffer. | 
 |      * Zero if no preallocated buffers. | 
 |      * | 
 |      * @return number of indices that fit in one of the preallocated index | 
 |      *         buffers. | 
 |      */ | 
 |     int preallocatedBufferIndices() const; | 
 |  | 
 | private: | 
 |     typedef GrBufferAllocPool INHERITED; | 
 | }; | 
 |  | 
 | #endif |