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