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