• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "include/core/SkTypes.h"
12 #include "include/private/GrTypesPriv.h"
13 #include "include/private/SkNoncopyable.h"
14 #include "include/private/SkTArray.h"
15 #include "include/private/SkTDArray.h"
16 #include "src/gpu/GrCpuBuffer.h"
17 #include "src/gpu/GrDrawIndirectCommand.h"
18 #include "src/gpu/GrNonAtomicRef.h"
19 
20 class GrGpu;
21 
22 /**
23  * A pool of geometry buffers tied to a GrGpu.
24  *
25  * The pool allows a client to make space for geometry and then put back excess
26  * space if it over allocated. When a client is ready to draw from the pool
27  * it calls unmap on the pool ensure buffers are ready for drawing. The pool
28  * can be reset after drawing is completed to recycle space.
29  *
30  * At creation time a minimum per-buffer size can be specified. Additionally,
31  * a number of buffers to preallocate can be specified. These will
32  * be allocated at the min size and kept around until the pool is destroyed.
33  */
34 class GrBufferAllocPool : SkNoncopyable {
35 public:
36     inline static constexpr size_t kDefaultBufferSize = 1 << 15;
37 
38     /**
39      * A cache object that can be shared by multiple GrBufferAllocPool instances. It caches
40      * cpu buffer allocations to avoid reallocating them.
41      */
42     class CpuBufferCache : public GrNonAtomicRef<CpuBufferCache> {
43     public:
44         static sk_sp<CpuBufferCache> Make(int maxBuffersToCache);
45 
46         sk_sp<GrCpuBuffer> makeBuffer(size_t size, bool mustBeInitialized);
47         void releaseAll();
48 
49     private:
50         CpuBufferCache(int maxBuffersToCache);
51 
52         struct Buffer {
53             sk_sp<GrCpuBuffer> fBuffer;
54             bool fCleared = false;
55         };
56         std::unique_ptr<Buffer[]> fBuffers;
57         int fMaxBuffersToCache = 0;
58     };
59 
60     /**
61      * Ensures all buffers are unmapped and have all data written to them.
62      * Call before drawing using buffers from the pool.
63      */
64     void unmap();
65 
66     /**
67      *  Invalidates all the data in the pool, unrefs non-preallocated buffers.
68      */
69     void reset();
70 
71     /**
72      * Frees data from makeSpaces in LIFO order.
73      */
74     void putBack(size_t bytes);
75 
76 protected:
77     /**
78      * Constructor
79      *
80      * @param gpu                   The GrGpu used to create the buffers.
81      * @param bufferType            The type of buffers to create.
82      * @param cpuBufferCache        If non-null a cache for client side array buffers
83      *                              or staging buffers used before data is uploaded to
84      *                              GPU buffer objects.
85      */
86     GrBufferAllocPool(GrGpu* gpu, GrGpuBufferType bufferType, sk_sp<CpuBufferCache> cpuBufferCache);
87 
88     virtual ~GrBufferAllocPool();
89 
90     /**
91      * Returns a block of memory to hold data. A buffer designated to hold the
92      * data is given to the caller. The buffer may or may not be locked. The
93      * returned ptr remains valid until any of the following:
94      *      *makeSpace is called again.
95      *      *unmap is called.
96      *      *reset is called.
97      *      *this object is destroyed.
98      *
99      * Once unmap on the pool is called the data is guaranteed to be in the
100      * buffer at the offset indicated by offset. Until that time it may be
101      * in temporary storage and/or the buffer may be locked.
102      *
103      * @param size         the amount of data to make space for
104      * @param alignment    alignment constraint from start of buffer
105      * @param buffer       returns the buffer that will hold the data.
106      * @param offset       returns the offset into buffer of the data.
107      * @return pointer to where the client should write the data.
108      */
109     void* makeSpace(size_t size, size_t alignment, sk_sp<const GrBuffer>* buffer, size_t* offset);
110 
111     /**
112      * Returns a block of memory to hold data. A buffer designated to hold the
113      * data is given to the caller. The buffer may or may not be locked. The
114      * returned ptr remains valid until any of the following:
115      *      *makeSpace is called again.
116      *      *unmap is called.
117      *      *reset is called.
118      *      *this object is destroyed.
119      *
120      * Once unmap on the pool is called the data is guaranteed to be in the
121      * buffer at the offset indicated by offset. Until that time it may be
122      * in temporary storage and/or the buffer may be locked.
123      *
124      * The caller requests a minimum number of bytes, but the block may be (much)
125      * larger. Assuming that a new block must be allocated, it will be fallbackSize bytes.
126      * The actual block size is returned in actualSize.
127      *
128      * @param minSize        the minimum amount of data to make space for
129      * @param fallbackSize   the amount of data to make space for if a new block is needed
130      * @param alignment      alignment constraint from start of buffer
131      * @param buffer         returns the buffer that will hold the data.
132      * @param offset         returns the offset into buffer of the data.
133      * @param actualSize     returns the capacity of the block
134      * @return pointer to where the client should write the data.
135      */
136     void* makeSpaceAtLeast(size_t minSize,
137                            size_t fallbackSize,
138                            size_t alignment,
139                            sk_sp<const GrBuffer>* buffer,
140                            size_t* offset,
141                            size_t* actualSize);
142 
143     sk_sp<GrBuffer> getBuffer(size_t size);
144 
145 private:
146     struct BufferBlock {
147         size_t fBytesFree;
148         sk_sp<GrBuffer> fBuffer;
149     };
150 
151     bool createBlock(size_t requestSize);
152     void destroyBlock();
153     void deleteBlocks();
154     void flushCpuData(const BufferBlock& block, size_t flushSize);
155     void resetCpuData(size_t newSize);
156 #ifdef SK_DEBUG
157     void validate(bool unusedBlockAllowed = false) const;
158 #endif
159     size_t fBytesInUse = 0;
160 
161     SkTArray<BufferBlock> fBlocks;
162     sk_sp<CpuBufferCache> fCpuBufferCache;
163     sk_sp<GrCpuBuffer> fCpuStagingBuffer;
164     GrGpu* fGpu;
165     GrGpuBufferType fBufferType;
166     void* fBufferPtr = nullptr;
167 };
168 
169 /**
170  * A GrBufferAllocPool of vertex buffers
171  */
172 class GrVertexBufferAllocPool : public GrBufferAllocPool {
173 public:
174     /**
175      * Constructor
176      *
177      * @param gpu                   The GrGpu used to create the vertex buffers.
178      * @param cpuBufferCache        If non-null a cache for client side array buffers
179      *                              or staging buffers used before data is uploaded to
180      *                              GPU buffer objects.
181      */
182     GrVertexBufferAllocPool(GrGpu* gpu, sk_sp<CpuBufferCache> cpuBufferCache);
183 
184     /**
185      * Returns a block of memory to hold vertices. A buffer designated to hold
186      * the vertices given to the caller. The buffer may or may not be locked.
187      * The returned ptr remains valid until any of the following:
188      *      *makeSpace is called again.
189      *      *unmap is called.
190      *      *reset is called.
191      *      *this object is destroyed.
192      *
193      * Once unmap on the pool is called the vertices are guaranteed to be in
194      * the buffer at the offset indicated by startVertex. Until that time they
195      * may be in temporary storage and/or the buffer may be locked.
196      *
197      * @param vertexSize   specifies size of a vertex to allocate space for
198      * @param vertexCount  number of vertices to allocate space for
199      * @param buffer       returns the vertex buffer that will hold the
200      *                     vertices.
201      * @param startVertex  returns the offset into buffer of the first vertex.
202      *                     In units of the size of a vertex from layout param.
203      * @return pointer to first vertex.
204      */
205     void* makeSpace(size_t vertexSize,
206                     int vertexCount,
207                     sk_sp<const GrBuffer>* buffer,
208                     int* startVertex);
209 
210     /**
211      * Returns a block of memory to hold vertices. A buffer designated to hold
212      * the vertices given to the caller. The buffer may or may not be locked.
213      * The returned ptr remains valid until any of the following:
214      *      *makeSpace is called again.
215      *      *unmap is called.
216      *      *reset is called.
217      *      *this object is destroyed.
218      *
219      * Once unmap on the pool is called the vertices are guaranteed to be in
220      * the buffer at the offset indicated by startVertex. Until that time they
221      * may be in temporary storage and/or the buffer may be locked.
222      *
223      * The caller requests a minimum number of vertices, but the block may be (much)
224      * larger. Assuming that a new block must be allocated, it will be sized to hold
225      * fallbackVertexCount vertices. The actual block size (in vertices) is returned in
226      * actualVertexCount.
227      *
228      * @param vertexSize           specifies size of a vertex to allocate space for
229      * @param minVertexCount       minimum number of vertices to allocate space for
230      * @param fallbackVertexCount  number of vertices to allocate space for if a new block is needed
231      * @param buffer               returns the vertex buffer that will hold the vertices.
232      * @param startVertex          returns the offset into buffer of the first vertex.
233      *                             In units of the size of a vertex from layout param.
234      * @param actualVertexCount    returns the capacity of the block (in vertices)
235      * @return pointer to first vertex.
236      */
237     void* makeSpaceAtLeast(size_t vertexSize,
238                            int minVertexCount,
239                            int fallbackVertexCount,
240                            sk_sp<const GrBuffer>* buffer,
241                            int* startVertex,
242                            int* actualVertexCount);
243 
244 private:
245     using INHERITED = GrBufferAllocPool;
246 };
247 
248 /**
249  * A GrBufferAllocPool of index buffers
250  */
251 class GrIndexBufferAllocPool : public GrBufferAllocPool {
252 public:
253     /**
254      * Constructor
255      *
256      * @param gpu                   The GrGpu used to create the index buffers.
257      * @param cpuBufferCache        If non-null a cache for client side array buffers
258      *                              or staging buffers used before data is uploaded to
259      *                              GPU buffer objects.
260      */
261     GrIndexBufferAllocPool(GrGpu* gpu, sk_sp<CpuBufferCache> cpuBufferCache);
262 
263     /**
264      * Returns a block of memory to hold indices. A buffer designated to hold
265      * the indices is given to the caller. The buffer may or may not be locked.
266      * The returned ptr remains valid until any of the following:
267      *      *makeSpace is called again.
268      *      *unmap is called.
269      *      *reset is called.
270      *      *this object is destroyed.
271      *
272      * Once unmap on the pool is called the indices are guaranteed to be in the
273      * buffer at the offset indicated by startIndex. Until that time they may be
274      * in temporary storage and/or the buffer may be locked.
275      *
276      * @param indexCount   number of indices to allocate space for
277      * @param buffer       returns the index buffer that will hold the indices.
278      * @param startIndex   returns the offset into buffer of the first index.
279      * @return pointer to first index.
280      */
281     void* makeSpace(int indexCount, sk_sp<const GrBuffer>* buffer, int* startIndex);
282 
283     /**
284      * Returns a block of memory to hold indices. A buffer designated to hold
285      * the indices is given to the caller. The buffer may or may not be locked.
286      * The returned ptr remains valid until any of the following:
287      *      *makeSpace is called again.
288      *      *unmap is called.
289      *      *reset is called.
290      *      *this object is destroyed.
291      *
292      * Once unmap on the pool is called the indices are guaranteed to be in the
293      * buffer at the offset indicated by startIndex. Until that time they may be
294      * in temporary storage and/or the buffer may be locked.
295      *
296      * The caller requests a minimum number of indices, but the block may be (much)
297      * larger. Assuming that a new block must be allocated, it will be sized to hold
298      * fallbackIndexCount indices. The actual block size (in indices) is returned in
299      * actualIndexCount.
300      *
301      * @param minIndexCount        minimum number of indices to allocate space for
302      * @param fallbackIndexCount   number of indices to allocate space for if a new block is needed
303      * @param buffer               returns the index buffer that will hold the indices.
304      * @param startIndex           returns the offset into buffer of the first index.
305      * @param actualIndexCount     returns the capacity of the block (in indices)
306      * @return pointer to first index.
307      */
308     void* makeSpaceAtLeast(int minIndexCount,
309                            int fallbackIndexCount,
310                            sk_sp<const GrBuffer>* buffer,
311                            int* startIndex,
312                            int* actualIndexCount);
313 
314 private:
315     using INHERITED = GrBufferAllocPool;
316 };
317 
318 class GrDrawIndirectBufferAllocPool : private GrBufferAllocPool {
319 public:
GrDrawIndirectBufferAllocPool(GrGpu * gpu,sk_sp<CpuBufferCache> cpuBufferCache)320     GrDrawIndirectBufferAllocPool(GrGpu* gpu, sk_sp<CpuBufferCache> cpuBufferCache)
321             : GrBufferAllocPool(gpu, GrGpuBufferType::kDrawIndirect, std::move(cpuBufferCache)) {}
322 
makeSpace(int drawCount,sk_sp<const GrBuffer> * buffer,size_t * offset)323     GrDrawIndirectWriter makeSpace(int drawCount, sk_sp<const GrBuffer>* buffer, size_t* offset) {
324         return this->GrBufferAllocPool::makeSpace(drawCount * sizeof(GrDrawIndirectCommand), 4,
325                                                   buffer, offset);
326     }
327 
putBack(int drawCount)328     void putBack(int drawCount) {
329         this->GrBufferAllocPool::putBack(drawCount * sizeof(GrDrawIndirectCommand));
330     }
331 
makeIndexedSpace(int drawCount,sk_sp<const GrBuffer> * buffer,size_t * offset)332     GrDrawIndexedIndirectWriter makeIndexedSpace(int drawCount, sk_sp<const GrBuffer>* buffer,
333                                                  size_t* offset) {
334         return this->GrBufferAllocPool::makeSpace(
335                 drawCount * sizeof(GrDrawIndexedIndirectCommand), 4, buffer, offset);
336     }
337 
putBackIndexed(int drawCount)338     void putBackIndexed(int drawCount) {
339         this->GrBufferAllocPool::putBack(drawCount * sizeof(GrDrawIndexedIndirectCommand));
340     }
341 
342     using GrBufferAllocPool::unmap;
343     using GrBufferAllocPool::reset;
344 };
345 
346 #endif
347