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#include "GrTypesPriv.h"
15
16class GrBuffer;
17class GrGpu;
18
19/**
20 * A pool of geometry buffers tied to a GrGpu.
21 *
22 * The pool allows a client to make space for geometry and then put back excess
23 * space if it over allocated. When a client is ready to draw from the pool
24 * it calls unmap on the pool ensure buffers are ready for drawing. The pool
25 * can be reset after drawing is completed to recycle space.
26 *
27 * At creation time a minimum per-buffer size can be specified. Additionally,
28 * a number of buffers to preallocate can be specified. These will
29 * be allocated at the min size and kept around until the pool is destroyed.
30 */
31class GrBufferAllocPool : SkNoncopyable {
32public:
33    /**
34     * Ensures all buffers are unmapped and have all data written to them.
35     * Call before drawing using buffers from the pool.
36     */
37    void unmap();
38
39    /**
40     *  Invalidates all the data in the pool, unrefs non-preallocated buffers.
41     */
42    void reset();
43
44    /**
45     * Frees data from makeSpaces in LIFO order.
46     */
47    void putBack(size_t bytes);
48
49protected:
50    /**
51     * Constructor
52     *
53     * @param gpu                   The GrGpu used to create the buffers.
54     * @param bufferType            The type of buffers to create.
55     * @param bufferSize            The minimum size of created buffers.
56     *                              This value will be clamped to some
57     *                              reasonable minimum.
58     */
59     GrBufferAllocPool(GrGpu* gpu,
60                       GrBufferType bufferType,
61                       size_t   bufferSize = 0);
62
63     virtual ~GrBufferAllocPool();
64
65    /**
66     * Returns a block of memory to hold data. A buffer designated to hold the
67     * data is given to the caller. The buffer may or may not be locked. The
68     * returned ptr remains valid until any of the following:
69     *      *makeSpace is called again.
70     *      *unmap is called.
71     *      *reset is called.
72     *      *this object is destroyed.
73     *
74     * Once unmap on the pool is called the data is guaranteed to be in the
75     * buffer at the offset indicated by offset. Until that time it may be
76     * in temporary storage and/or the buffer may be locked.
77     *
78     * @param size         the amount of data to make space for
79     * @param alignment    alignment constraint from start of buffer
80     * @param buffer       returns the buffer that will hold the data.
81     * @param offset       returns the offset into buffer of the data.
82     * @return pointer to where the client should write the data.
83     */
84    void* makeSpace(size_t size,
85                    size_t alignment,
86                    const GrBuffer** buffer,
87                    size_t* offset);
88
89    /**
90     * Returns a block of memory to hold data. A buffer designated to hold the
91     * data is given to the caller. The buffer may or may not be locked. The
92     * returned ptr remains valid until any of the following:
93     *      *makeSpace is called again.
94     *      *unmap is called.
95     *      *reset is called.
96     *      *this object is destroyed.
97     *
98     * Once unmap on the pool is called the data is guaranteed to be in the
99     * buffer at the offset indicated by offset. Until that time it may be
100     * in temporary storage and/or the buffer may be locked.
101     *
102     * The caller requests a minimum number of bytes, but the block may be (much)
103     * larger. Assuming that a new block must be allocated, it will be fallbackSize bytes.
104     * The actual block size is returned in actualSize.
105     *
106     * @param minSize        the minimum amount of data to make space for
107     * @param fallbackSize   the amount of data to make space for if a new block is needed
108     * @param alignment      alignment constraint from start of buffer
109     * @param buffer         returns the buffer that will hold the data.
110     * @param offset         returns the offset into buffer of the data.
111     * @param actualSize     returns the capacity of the block
112     * @return pointer to where the client should write the data.
113     */
114    void* makeSpaceAtLeast(size_t minSize,
115                           size_t fallbackSize,
116                           size_t alignment,
117                           const GrBuffer** buffer,
118                           size_t* offset,
119                           size_t* actualSize);
120
121    GrBuffer* getBuffer(size_t size);
122
123private:
124    struct BufferBlock {
125        size_t      fBytesFree;
126        GrBuffer*   fBuffer;
127    };
128
129    bool createBlock(size_t requestSize);
130    void destroyBlock();
131    void deleteBlocks();
132    void flushCpuData(const BufferBlock& block, size_t flushSize);
133    void* resetCpuData(size_t newSize);
134#ifdef SK_DEBUG
135    void validate(bool unusedBlockAllowed = false) const;
136#endif
137    size_t                          fBytesInUse;
138
139    GrGpu*                          fGpu;
140    size_t                          fMinBlockSize;
141    GrBufferType                    fBufferType;
142
143    SkTArray<BufferBlock>           fBlocks;
144    void*                           fCpuData;
145    void*                           fBufferPtr;
146    size_t                          fBufferMapThreshold;
147};
148
149/**
150 * A GrBufferAllocPool of vertex buffers
151 */
152class GrVertexBufferAllocPool : public GrBufferAllocPool {
153public:
154    /**
155     * Constructor
156     *
157     * @param gpu                   The GrGpu used to create the vertex buffers.
158     */
159    GrVertexBufferAllocPool(GrGpu* gpu);
160
161    /**
162     * Returns a block of memory to hold vertices. A buffer designated to hold
163     * the vertices given to the caller. The buffer may or may not be locked.
164     * The returned ptr remains valid until any of the following:
165     *      *makeSpace is called again.
166     *      *unmap is called.
167     *      *reset is called.
168     *      *this object is destroyed.
169     *
170     * Once unmap on the pool is called the vertices are guaranteed to be in
171     * the buffer at the offset indicated by startVertex. Until that time they
172     * may be in temporary storage and/or the buffer may be locked.
173     *
174     * @param vertexSize   specifies size of a vertex to allocate space for
175     * @param vertexCount  number of vertices to allocate space for
176     * @param buffer       returns the vertex buffer that will hold the
177     *                     vertices.
178     * @param startVertex  returns the offset into buffer of the first vertex.
179     *                     In units of the size of a vertex from layout param.
180     * @return pointer to first vertex.
181     */
182    void* makeSpace(size_t vertexSize,
183                    int vertexCount,
184                    const GrBuffer** buffer,
185                    int* startVertex);
186
187    /**
188     * Returns a block of memory to hold vertices. A buffer designated to hold
189     * the vertices given to the caller. The buffer may or may not be locked.
190     * The returned ptr remains valid until any of the following:
191     *      *makeSpace is called again.
192     *      *unmap is called.
193     *      *reset is called.
194     *      *this object is destroyed.
195     *
196     * Once unmap on the pool is called the vertices are guaranteed to be in
197     * the buffer at the offset indicated by startVertex. Until that time they
198     * may be in temporary storage and/or the buffer may be locked.
199     *
200     * The caller requests a minimum number of vertices, but the block may be (much)
201     * larger. Assuming that a new block must be allocated, it will be sized to hold
202     * fallbackVertexCount vertices. The actual block size (in vertices) is returned in
203     * actualVertexCount.
204     *
205     * @param vertexSize           specifies size of a vertex to allocate space for
206     * @param minVertexCount       minimum number of vertices to allocate space for
207     * @param fallbackVertexCount  number of vertices to allocate space for if a new block is needed
208     * @param buffer               returns the vertex buffer that will hold the vertices.
209     * @param startVertex          returns the offset into buffer of the first vertex.
210     *                             In units of the size of a vertex from layout param.
211     * @param actualVertexCount    returns the capacity of the block (in vertices)
212     * @return pointer to first vertex.
213     */
214    void* makeSpaceAtLeast(size_t vertexSize,
215                           int minVertexCount,
216                           int fallbackVertexCount,
217                           const GrBuffer** buffer,
218                           int* startVertex,
219                           int* actualVertexCount);
220
221private:
222    typedef GrBufferAllocPool INHERITED;
223};
224
225/**
226 * A GrBufferAllocPool of index buffers
227 */
228class GrIndexBufferAllocPool : public GrBufferAllocPool {
229public:
230    /**
231     * Constructor
232     *
233     * @param gpu                   The GrGpu used to create the index buffers.
234     */
235    GrIndexBufferAllocPool(GrGpu* gpu);
236
237    /**
238     * Returns a block of memory to hold indices. A buffer designated to hold
239     * the indices is given to the caller. The buffer may or may not be locked.
240     * The returned ptr remains valid until any of the following:
241     *      *makeSpace is called again.
242     *      *unmap is called.
243     *      *reset is called.
244     *      *this object is destroyed.
245     *
246     * Once unmap on the pool is called the indices are guaranteed to be in the
247     * buffer at the offset indicated by startIndex. Until that time they may be
248     * in temporary storage and/or the buffer may be locked.
249     *
250     * @param indexCount   number of indices to allocate space for
251     * @param buffer       returns the index buffer that will hold the indices.
252     * @param startIndex   returns the offset into buffer of the first index.
253     * @return pointer to first index.
254     */
255    void* makeSpace(int indexCount,
256                    const GrBuffer** buffer,
257                    int* startIndex);
258
259    /**
260     * Returns a block of memory to hold indices. A buffer designated to hold
261     * the indices is given to the caller. The buffer may or may not be locked.
262     * The returned ptr remains valid until any of the following:
263     *      *makeSpace is called again.
264     *      *unmap is called.
265     *      *reset is called.
266     *      *this object is destroyed.
267     *
268     * Once unmap on the pool is called the indices are guaranteed to be in the
269     * buffer at the offset indicated by startIndex. Until that time they may be
270     * in temporary storage and/or the buffer may be locked.
271     *
272     * The caller requests a minimum number of indices, but the block may be (much)
273     * larger. Assuming that a new block must be allocated, it will be sized to hold
274     * fallbackIndexCount indices. The actual block size (in indices) is returned in
275     * actualIndexCount.
276     *
277     * @param minIndexCount        minimum number of indices to allocate space for
278     * @param fallbackIndexCount   number of indices to allocate space for if a new block is needed
279     * @param buffer               returns the index buffer that will hold the indices.
280     * @param startIndex           returns the offset into buffer of the first index.
281     * @param actualIndexCount     returns the capacity of the block (in indices)
282     * @return pointer to first index.
283     */
284    void* makeSpaceAtLeast(int minIndexCount,
285                           int fallbackIndexCount,
286                           const GrBuffer** buffer,
287                           int* startIndex,
288                           int* actualIndexCount);
289
290private:
291    typedef GrBufferAllocPool INHERITED;
292};
293
294#endif
295