Refactor how Gr handles vertex and index data. GrGpu and GrInOrderDrawBuffer both GrBufferAllocPool to manage reserved and set-to-array vertex and index data.

rietveld issue 4188049

git-svn-id: http://skia.googlecode.com/svn/trunk@786 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/src/GrBufferAllocPool.h b/gpu/src/GrBufferAllocPool.h
new file mode 100644
index 0000000..80f16ab
--- /dev/null
+++ b/gpu/src/GrBufferAllocPool.h
@@ -0,0 +1,349 @@
+/*
+    Copyright 2010 Google Inc.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+ */
+
+
+#ifndef GrBufferAllocPool_DEFINED
+#define GrBufferAllocPool_DEFINED
+
+#include "GrNoncopyable.h"
+#include "GrTDArray.h"
+#include "GrTArray.h"
+#include "GrMemory.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 unlock 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 : GrNoncopyable {
+protected:
+
+    // 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 unlock() 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();
+
+public:
+    /**
+     * Ensures all buffers are unlocked and have all data written to them.
+     * Call before drawing using buffers from the pool.
+     */
+    void unlock();
+
+    /**
+     *  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:
+    /**
+     * 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.
+     *      *unlock is called.
+     *      *reset is called.
+     *      *this object is destroyed.
+     *
+     * Once unlock 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:
+
+    struct BufferBlock {
+        size_t              fBytesFree;
+        GrGeometryBuffer*   fBuffer;
+    };
+
+    bool createBlock(size_t requestSize);
+    void destroyBlock();
+    void flushCpuData(GrGeometryBuffer* buffer, size_t flushSize);
+#if GR_DEBUG
+    void validate() const;
+#endif
+
+    GrGpu*                          fGpu;
+    bool                            fFrequentResetHint;
+    GrTDArray<GrGeometryBuffer*>    fPreallocBuffers;
+    size_t                          fMinBlockSize;
+    BufferType                      fBufferType;
+
+    GrTArray<BufferBlock>           fBlocks;
+    int                             fPreallocBuffersInUse;
+    int                             fFirstPreallocBuffer;
+    GrAutoMalloc                    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 unlock() 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.
+     *      *unlock is called.
+     *      *reset is called.
+     *      *this object is destroyed.
+     *
+     * Once unlock 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 layout       specifies type of vertices 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(GrVertexLayout layout,
+                    int vertexCount,
+                    const GrVertexBuffer** buffer,
+                    int* startVertex);
+
+    /**
+     * Shortcut to make space and then write verts into the made space.
+     */
+    bool appendVertices(GrVertexLayout layout,
+                        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 format of vertices to compute space for.
+     * @return the number of vertices that would fit in the current buffer.
+     */
+    int currentBufferVertices(GrVertexLayout layout) const;
+
+    /**
+     * Gets the number of vertices that can fit in a  preallocated vertex buffer.
+     * Zero if no preallocated buffers.
+     *
+     * @param   the format of vertices to compute space for.
+     *
+     * @return number of vertices that fit in one of the preallocated vertex
+     *         buffers.
+     */
+    int preallocatedBufferVertices(GrVertexLayout layout) 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 unlock() 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.
+     *      *unlock is called.
+     *      *reset is called.
+     *      *this object is destroyed.
+     *
+     * Once unlock 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