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