1 /* 2 * Copyright 2021 Google LLC. 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 GrVertexChunkArray_DEFINED 9 #define GrVertexChunkArray_DEFINED 10 11 #include "include/private/SkNoncopyable.h" 12 #include "include/private/SkTArray.h" 13 #include "src/gpu/GrBuffer.h" 14 #include "src/gpu/GrVertexWriter.h" 15 #include "src/gpu/ops/GrMeshDrawOp.h" 16 17 // Represents a chunk of vertex data. Use with GrVertexChunkArray and GrVertexChunkBuilder. We write 18 // the data out in chunks when we don't start out knowing exactly how many vertices (or instances) 19 // we will end up writing. 20 struct GrVertexChunk { 21 sk_sp<const GrBuffer> fBuffer; 22 int fCount = 0; 23 int fBase; // baseVertex or baseInstance, depending on the use case. 24 }; 25 26 // Represents an array of GrVertexChunks. 27 // 28 // We only preallocate 1 chunk because if the array needs to grow, then we're also allocating a 29 // brand new GPU buffer anyway. 30 using GrVertexChunkArray = SkSTArray<1, GrVertexChunk>; 31 32 // Builds a GrVertexChunkArray. The provided Target must not be used externally throughout the 33 // entire lifetime of this object. 34 class GrVertexChunkBuilder : SkNoncopyable { 35 public: GrVertexChunkBuilder(GrMeshDrawOp::Target * target,GrVertexChunkArray * chunks,size_t stride,int minVerticesPerChunk)36 GrVertexChunkBuilder(GrMeshDrawOp::Target* target, GrVertexChunkArray* chunks, size_t stride, 37 int minVerticesPerChunk) 38 : fTarget(target) 39 , fChunks(chunks) 40 , fStride(stride) 41 , fMinVerticesPerChunk(minVerticesPerChunk) { 42 SkASSERT(fMinVerticesPerChunk > 0); 43 } 44 ~GrVertexChunkBuilder()45 ~GrVertexChunkBuilder() { 46 if (!fChunks->empty()) { 47 fTarget->putBackVertices(fCurrChunkVertexCapacity - fCurrChunkVertexCount, fStride); 48 fChunks->back().fCount = fCurrChunkVertexCount; 49 } 50 } 51 52 // Appends 'count' contiguous vertices. These vertices are not guaranteed to be contiguous with 53 // previous or future calls to appendVertices. appendVertices(int count)54 SK_ALWAYS_INLINE GrVertexWriter appendVertices(int count) { 55 SkASSERT(count > 0); 56 if (fCurrChunkVertexCount + count > fCurrChunkVertexCapacity && !this->allocChunk(count)) { 57 return {nullptr}; 58 } 59 SkASSERT(fCurrChunkVertexCount + count <= fCurrChunkVertexCapacity); 60 fCurrChunkVertexCount += count; 61 return std::exchange(fCurrChunkVertexWriter, 62 fCurrChunkVertexWriter.makeOffset(fStride * count)); 63 } 64 appendVertex()65 SK_ALWAYS_INLINE GrVertexWriter appendVertex() { return this->appendVertices(1); } 66 67 private: allocChunk(int minCount)68 bool allocChunk(int minCount) { 69 if (!fChunks->empty()) { 70 // No need to put back vertices; the buffer is full. 71 fChunks->back().fCount = fCurrChunkVertexCount; 72 } 73 fCurrChunkVertexCount = 0; 74 GrVertexChunk* chunk = &fChunks->push_back(); 75 fCurrChunkVertexWriter = {fTarget->makeVertexSpaceAtLeast(fStride, 76 fMinVerticesPerChunk * minCount, 77 fMinVerticesPerChunk * minCount, 78 &chunk->fBuffer, 79 &chunk->fBase, 80 &fCurrChunkVertexCapacity)}; 81 if (!fCurrChunkVertexWriter || !chunk->fBuffer || fCurrChunkVertexCapacity < minCount) { 82 SkDebugf("WARNING: Failed to allocate vertex buffer for GrVertexChunk.\n"); 83 fChunks->pop_back(); 84 SkASSERT(fCurrChunkVertexCount == 0); 85 fCurrChunkVertexCapacity = 0; 86 return false; 87 } 88 fMinVerticesPerChunk *= 2; 89 return true; 90 } 91 92 GrMeshDrawOp::Target* const fTarget; 93 GrVertexChunkArray* const fChunks; 94 const size_t fStride; 95 size_t fMinVerticesPerChunk; 96 97 GrVertexWriter fCurrChunkVertexWriter; 98 int fCurrChunkVertexCount = 0; 99 int fCurrChunkVertexCapacity = 0; 100 }; 101 102 #endif 103