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