1 /* 2 * Copyright 2020 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 GrEagerVertexAllocator_DEFINED 9 #define GrEagerVertexAllocator_DEFINED 10 11 #include "src/gpu/GrThreadSafeCache.h" 12 #include "src/gpu/ops/GrMeshDrawOp.h" 13 14 // This interface is used to allocate and map GPU vertex data before the exact number of required 15 // vertices is known. Usage pattern: 16 // 17 // 1. Call lock(eagerCount) with an upper bound on the number of required vertices. 18 // 2. Compute and write vertex data to the returned pointer (if not null). 19 // 3. Call unlock(actualCount) and provide the actual number of vertices written during step #2. 20 // 21 // On step #3, the implementation will attempt to shrink the underlying GPU memory slot to fit the 22 // actual vertex count. 23 class GrEagerVertexAllocator { 24 public: lock(int eagerCount)25 template<typename T> T* lock(int eagerCount) { 26 return static_cast<T*>(this->lock(sizeof(T), eagerCount)); 27 } 28 virtual void* lock(size_t stride, int eagerCount) = 0; 29 30 virtual void unlock(int actualCount) = 0; 31 ~GrEagerVertexAllocator()32 virtual ~GrEagerVertexAllocator() {} 33 }; 34 35 // GrEagerVertexAllocator implementation that uses GrMeshDrawOp::Target::makeVertexSpace and 36 // GrMeshDrawOp::Target::putBackVertices. 37 class GrEagerDynamicVertexAllocator : public GrEagerVertexAllocator { 38 public: GrEagerDynamicVertexAllocator(GrMeshDrawOp::Target * target,sk_sp<const GrBuffer> * vertexBuffer,int * baseVertex)39 GrEagerDynamicVertexAllocator(GrMeshDrawOp::Target* target, 40 sk_sp<const GrBuffer>* vertexBuffer, 41 int* baseVertex) 42 : fTarget(target) 43 , fVertexBuffer(vertexBuffer) 44 , fBaseVertex(baseVertex) { 45 } 46 47 #ifdef SK_DEBUG ~GrEagerDynamicVertexAllocator()48 ~GrEagerDynamicVertexAllocator() override { 49 SkASSERT(!fLockCount); 50 } 51 #endif 52 53 // Un-shadow GrEagerVertexAllocator::lock<T>. 54 using GrEagerVertexAllocator::lock; 55 56 // Mark "final" as a hint for the compiler to not use the vtable. lock(size_t stride,int eagerCount)57 void* lock(size_t stride, int eagerCount) final { 58 SkASSERT(!fLockCount); 59 SkASSERT(eagerCount); 60 if (void* data = fTarget->makeVertexSpace(stride, eagerCount, fVertexBuffer, fBaseVertex)) { 61 fLockStride = stride; 62 fLockCount = eagerCount; 63 return data; 64 } 65 fVertexBuffer->reset(); 66 *fBaseVertex = 0; 67 return nullptr; 68 } 69 70 // Mark "final" as a hint for the compiler to not use the vtable. unlock(int actualCount)71 void unlock(int actualCount) final { 72 SkASSERT(fLockCount); 73 SkASSERT(actualCount <= fLockCount); 74 fTarget->putBackVertices(fLockCount - actualCount, fLockStride); 75 if (!actualCount) { 76 fVertexBuffer->reset(); 77 *fBaseVertex = 0; 78 } 79 fLockCount = 0; 80 } 81 82 private: 83 GrMeshDrawOp::Target* const fTarget; 84 sk_sp<const GrBuffer>* const fVertexBuffer; 85 int* const fBaseVertex; 86 87 size_t fLockStride; 88 int fLockCount = 0; 89 }; 90 91 class GrCpuVertexAllocator : public GrEagerVertexAllocator { 92 public: 93 GrCpuVertexAllocator() = default; 94 95 #ifdef SK_DEBUG ~GrCpuVertexAllocator()96 ~GrCpuVertexAllocator() override { 97 SkASSERT(!fLockStride && !fVertices && !fVertexData); 98 } 99 #endif 100 101 void* lock(size_t stride, int eagerCount) override; 102 void unlock(int actualCount) override; 103 104 sk_sp<GrThreadSafeCache::VertexData> detachVertexData(); 105 106 private: 107 sk_sp<GrThreadSafeCache::VertexData> fVertexData; 108 109 void* fVertices = nullptr; 110 size_t fLockStride = 0; 111 }; 112 113 #endif 114