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