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 "GrCpuBuffer.h" 12 #include "GrNonAtomicRef.h" 13 #include "GrTypesPriv.h" 14 #include "SkNoncopyable.h" 15 #include "SkTArray.h" 16 #include "SkTDArray.h" 17 #include "SkTypes.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 #endif 318