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