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