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 GrBufferAllocPool_DEFINED
9#define GrBufferAllocPool_DEFINED
10
11#include "SkTArray.h"
12#include "SkTDArray.h"
13#include "SkTypes.h"
14
15class GrGeometryBuffer;
16class GrGpu;
17
18/**
19 * A pool of geometry buffers tied to a GrGpu.
20 *
21 * The pool allows a client to make space for geometry and then put back excess
22 * space if it over allocated. When a client is ready to draw from the pool
23 * it calls unmap on the pool ensure buffers are ready for drawing. The pool
24 * can be reset after drawing is completed to recycle space.
25 *
26 * At creation time a minimum per-buffer size can be specified. Additionally,
27 * a number of buffers to preallocate can be specified. These will
28 * be allocated at the min size and kept around until the pool is destroyed.
29 */
30class GrBufferAllocPool : SkNoncopyable {
31public:
32    /**
33     * Ensures all buffers are unmapped and have all data written to them.
34     * Call before drawing using buffers from the pool.
35     */
36    void unmap();
37
38    /**
39     *  Invalidates all the data in the pool, unrefs non-preallocated buffers.
40     */
41    void reset();
42
43    /**
44     * Gets the number of preallocated buffers that are yet to be used.
45     */
46    int preallocatedBuffersRemaining() const;
47
48    /**
49     * gets the number of preallocated buffers
50     */
51    int preallocatedBufferCount() const;
52
53    /**
54     * Frees data from makeSpaces in LIFO order.
55     */
56    void putBack(size_t bytes);
57
58    /**
59     * Gets the GrGpu that this pool is associated with.
60     */
61    GrGpu* getGpu() { return fGpu; }
62
63protected:
64    /**
65     * Used to determine what type of buffers to create. We could make the
66     * createBuffer a virtual except that we want to use it in the cons for
67     * pre-allocated buffers.
68     */
69    enum BufferType {
70        kVertex_BufferType,
71        kIndex_BufferType,
72    };
73
74    /**
75     * Constructor
76     *
77     * @param gpu                   The GrGpu used to create the buffers.
78     * @param bufferType            The type of buffers to create.
79     * @param frequentResetHint     A hint that indicates that the pool
80     *                              should expect frequent unmap() calls
81     *                              (as opposed to many makeSpace / acquires
82     *                              between resets).
83     * @param bufferSize            The minimum size of created buffers.
84     *                              This value will be clamped to some
85     *                              reasonable minimum.
86     * @param preallocBufferCnt     The pool will allocate this number of
87     *                              buffers at bufferSize and keep them until it
88     *                              is destroyed.
89     */
90     GrBufferAllocPool(GrGpu* gpu,
91                       BufferType bufferType,
92                       bool frequentResetHint,
93                       size_t   bufferSize = 0,
94                       int preallocBufferCnt = 0);
95
96    virtual ~GrBufferAllocPool();
97
98    /**
99     * Gets the size of the preallocated buffers.
100     *
101     * @return the size of preallocated buffers.
102     */
103    size_t preallocatedBufferSize() const {
104        return fPreallocBuffers.count() ? fMinBlockSize : 0;
105    }
106
107    /**
108     * Returns a block of memory to hold data. A buffer designated to hold the
109     * data is given to the caller. The buffer may or may not be locked. The
110     * returned ptr remains valid until any of the following:
111     *      *makeSpace is called again.
112     *      *unmap is called.
113     *      *reset is called.
114     *      *this object is destroyed.
115     *
116     * Once unmap on the pool is called the data is guaranteed to be in the
117     * buffer at the offset indicated by offset. Until that time it may be
118     * in temporary storage and/or the buffer may be locked.
119     *
120     * @param size         the amount of data to make space for
121     * @param alignment    alignment constraint from start of buffer
122     * @param buffer       returns the buffer that will hold the data.
123     * @param offset       returns the offset into buffer of the data.
124     * @return pointer to where the client should write the data.
125     */
126    void* makeSpace(size_t size,
127                    size_t alignment,
128                    const GrGeometryBuffer** buffer,
129                    size_t* offset);
130
131    /**
132     * Gets the number of items of a size that can be added to the current
133     * buffer without spilling to another buffer. If the pool has been reset, or
134     * the previous makeSpace completely exhausted a buffer then the returned
135     * size will be the size of the next available preallocated buffer, or zero
136     * if no preallocated buffer remains available. It is assumed that items
137     * should be itemSize-aligned from the start of a buffer.
138     *
139     * @return the number of items that would fit in the current buffer.
140     */
141    int currentBufferItems(size_t itemSize) const;
142
143    GrGeometryBuffer* createBuffer(size_t size);
144
145private:
146
147    // The GrGpu must be able to clear the ref of pools it creates as members
148    friend class GrGpu;
149    void releaseGpuRef();
150
151    struct BufferBlock {
152        size_t              fBytesFree;
153        GrGeometryBuffer*   fBuffer;
154    };
155
156    bool createBlock(size_t requestSize);
157    void destroyBlock();
158    void flushCpuData(const BufferBlock& block, size_t flushSize);
159#ifdef SK_DEBUG
160    void validate(bool unusedBlockAllowed = false) const;
161#endif
162
163    size_t                          fBytesInUse;
164
165    GrGpu*                          fGpu;
166    bool                            fGpuIsReffed;
167    bool                            fFrequentResetHint;
168    SkTDArray<GrGeometryBuffer*>    fPreallocBuffers;
169    size_t                          fMinBlockSize;
170    BufferType                      fBufferType;
171
172    SkTArray<BufferBlock>           fBlocks;
173    int                             fPreallocBuffersInUse;
174    // We attempt to cycle through the preallocated buffers rather than
175    // always starting from the first.
176    int                             fPreallocBufferStartIdx;
177    SkAutoMalloc                    fCpuData;
178    void*                           fBufferPtr;
179};
180
181class GrVertexBuffer;
182
183/**
184 * A GrBufferAllocPool of vertex buffers
185 */
186class GrVertexBufferAllocPool : public GrBufferAllocPool {
187public:
188    /**
189     * Constructor
190     *
191     * @param gpu                   The GrGpu used to create the vertex buffers.
192     * @param frequentResetHint     A hint that indicates that the pool
193     *                              should expect frequent unmap() calls
194     *                              (as opposed to many makeSpace / acquires
195     *                              between resets).
196     * @param bufferSize            The minimum size of created VBs This value
197     *                              will be clamped to some reasonable minimum.
198     * @param preallocBufferCnt     The pool will allocate this number of VBs at
199     *                              bufferSize and keep them until it is
200     *                              destroyed.
201     */
202    GrVertexBufferAllocPool(GrGpu* gpu,
203                            bool frequentResetHint,
204                            size_t bufferSize = 0,
205                            int preallocBufferCnt = 0);
206
207    /**
208     * Returns a block of memory to hold vertices. A buffer designated to hold
209     * the vertices given to the caller. The buffer may or may not be locked.
210     * The returned ptr remains valid until any of the following:
211     *      *makeSpace is called again.
212     *      *unmap is called.
213     *      *reset is called.
214     *      *this object is destroyed.
215     *
216     * Once unmap on the pool is called the vertices are guaranteed to be in
217     * the buffer at the offset indicated by startVertex. Until that time they
218     * may be in temporary storage and/or the buffer may be locked.
219     *
220     * @param vertexSize   specifies size of a vertex to allocate space for
221     * @param vertexCount  number of vertices to allocate space for
222     * @param buffer       returns the vertex buffer that will hold the
223     *                     vertices.
224     * @param startVertex  returns the offset into buffer of the first vertex.
225     *                     In units of the size of a vertex from layout param.
226     * @return pointer to first vertex.
227     */
228    void* makeSpace(size_t vertexSize,
229                    int vertexCount,
230                    const GrVertexBuffer** buffer,
231                    int* startVertex);
232
233    /**
234     * Shortcut to make space and then write verts into the made space.
235     */
236    bool appendVertices(size_t vertexSize,
237                        int vertexCount,
238                        const void* vertices,
239                        const GrVertexBuffer** buffer,
240                        int* startVertex);
241
242    /**
243     * Gets the number of vertices that can be added to the current VB without
244     * spilling to another VB. If the pool has been reset, or the previous
245     * makeSpace completely exhausted a VB then the returned number of vertices
246     * would fit in the next available preallocated buffer. If any makeSpace
247     * would force a new VB to be created the return value will be zero.
248     *
249     * @param   the size of a vertex to compute space for.
250     * @return the number of vertices that would fit in the current buffer.
251     */
252    int currentBufferVertices(size_t vertexSize) const;
253
254    /**
255     * Gets the number of vertices that can fit in a  preallocated vertex buffer.
256     * Zero if no preallocated buffers.
257     *
258     * @param   the size of a vertex to compute space for.
259     *
260     * @return number of vertices that fit in one of the preallocated vertex
261     *         buffers.
262     */
263    int preallocatedBufferVertices(size_t vertexSize) const;
264
265private:
266    typedef GrBufferAllocPool INHERITED;
267};
268
269class GrIndexBuffer;
270
271/**
272 * A GrBufferAllocPool of index buffers
273 */
274class GrIndexBufferAllocPool : public GrBufferAllocPool {
275public:
276    /**
277     * Constructor
278     *
279     * @param gpu                   The GrGpu used to create the index buffers.
280     * @param frequentResetHint     A hint that indicates that the pool
281     *                              should expect frequent unmap() calls
282     *                              (as opposed to many makeSpace / acquires
283     *                              between resets).
284     * @param bufferSize            The minimum size of created IBs This value
285     *                              will be clamped to some reasonable minimum.
286     * @param preallocBufferCnt     The pool will allocate this number of VBs at
287     *                              bufferSize and keep them until it is
288     *                              destroyed.
289     */
290    GrIndexBufferAllocPool(GrGpu* gpu,
291                           bool frequentResetHint,
292                           size_t bufferSize = 0,
293                           int preallocBufferCnt = 0);
294
295    /**
296     * Returns a block of memory to hold indices. A buffer designated to hold
297     * the indices is given to the caller. The buffer may or may not be locked.
298     * The returned ptr remains valid until any of the following:
299     *      *makeSpace is called again.
300     *      *unmap is called.
301     *      *reset is called.
302     *      *this object is destroyed.
303     *
304     * Once unmap on the pool is called the indices are guaranteed to be in the
305     * buffer at the offset indicated by startIndex. Until that time they may be
306     * in temporary storage and/or the buffer may be locked.
307     *
308     * @param indexCount   number of indices to allocate space for
309     * @param buffer       returns the index buffer that will hold the indices.
310     * @param startIndex   returns the offset into buffer of the first index.
311     * @return pointer to first index.
312     */
313    void* makeSpace(int indexCount,
314                    const GrIndexBuffer** buffer,
315                    int* startIndex);
316
317    /**
318     * Shortcut to make space and then write indices into the made space.
319     */
320    bool appendIndices(int indexCount,
321                       const void* indices,
322                       const GrIndexBuffer** buffer,
323                       int* startIndex);
324
325    /**
326     * Gets the number of indices that can be added to the current IB without
327     * spilling to another IB. If the pool has been reset, or the previous
328     * makeSpace completely exhausted a IB then the returned number of indices
329     * would fit in the next available preallocated buffer. If any makeSpace
330     * would force a new IB to be created the return value will be zero.
331     */
332    int currentBufferIndices() const;
333
334    /**
335     * Gets the number of indices that can fit in a preallocated index buffer.
336     * Zero if no preallocated buffers.
337     *
338     * @return number of indices that fit in one of the preallocated index
339     *         buffers.
340     */
341    int preallocatedBufferIndices() const;
342
343private:
344    typedef GrBufferAllocPool INHERITED;
345};
346
347#endif
348