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