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