| 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 |  | 
|---|