xref: /aosp_15_r20/external/skia/src/gpu/ganesh/GrThreadSafeCache.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2020 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #ifndef GrThreadSafeCache_DEFINED
9*c8dee2aaSAndroid Build Coastguard Worker #define GrThreadSafeCache_DEFINED
10*c8dee2aaSAndroid Build Coastguard Worker 
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkDebug.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkMalloc.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkThreadAnnotations.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkArenaAlloc.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkSpinlock.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkTInternalLList.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkTDynamicHash.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/GpuTypesPriv.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ResourceKey.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrGpuBuffer.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrSurfaceProxy.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrSurfaceProxyView.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrTextureProxy.h"
26*c8dee2aaSAndroid Build Coastguard Worker 
27*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef>
28*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
29*c8dee2aaSAndroid Build Coastguard Worker #include <tuple>
30*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
31*c8dee2aaSAndroid Build Coastguard Worker 
32*c8dee2aaSAndroid Build Coastguard Worker class GrDirectContext;
33*c8dee2aaSAndroid Build Coastguard Worker class GrResourceCache;
34*c8dee2aaSAndroid Build Coastguard Worker class SkData;
35*c8dee2aaSAndroid Build Coastguard Worker enum GrSurfaceOrigin : int;
36*c8dee2aaSAndroid Build Coastguard Worker enum class GrColorType;
37*c8dee2aaSAndroid Build Coastguard Worker enum class SkBackingFit;
38*c8dee2aaSAndroid Build Coastguard Worker struct SkISize;
39*c8dee2aaSAndroid Build Coastguard Worker 
40*c8dee2aaSAndroid Build Coastguard Worker // Ganesh creates a lot of utility textures (e.g., blurred-rrect masks) that need to be shared
41*c8dee2aaSAndroid Build Coastguard Worker // between the direct context and all the DDL recording contexts. This thread-safe cache
42*c8dee2aaSAndroid Build Coastguard Worker // allows this sharing.
43*c8dee2aaSAndroid Build Coastguard Worker //
44*c8dee2aaSAndroid Build Coastguard Worker // In operation, each thread will first check if the threaded cache possesses the required texture.
45*c8dee2aaSAndroid Build Coastguard Worker //
46*c8dee2aaSAndroid Build Coastguard Worker // If a DDL thread doesn't find a needed texture it will go off and create it on the cpu and then
47*c8dee2aaSAndroid Build Coastguard Worker // attempt to add it to the cache. If another thread had added it in the interim, the losing thread
48*c8dee2aaSAndroid Build Coastguard Worker // will discard its work and use the texture the winning thread had created.
49*c8dee2aaSAndroid Build Coastguard Worker //
50*c8dee2aaSAndroid Build Coastguard Worker // If the thread in possession of the direct context doesn't find the needed texture it should
51*c8dee2aaSAndroid Build Coastguard Worker // add a place holder view and then queue up the draw calls to complete it. In this way the
52*c8dee2aaSAndroid Build Coastguard Worker // gpu-thread has precedence over the recording threads.
53*c8dee2aaSAndroid Build Coastguard Worker //
54*c8dee2aaSAndroid Build Coastguard Worker // The invariants for this cache differ a bit from those of the proxy and resource caches.
55*c8dee2aaSAndroid Build Coastguard Worker // For this cache:
56*c8dee2aaSAndroid Build Coastguard Worker //
57*c8dee2aaSAndroid Build Coastguard Worker //   only this cache knows the unique key - neither the proxy nor backing resource should
58*c8dee2aaSAndroid Build Coastguard Worker //              be discoverable in any other cache by the unique key
59*c8dee2aaSAndroid Build Coastguard Worker //   if a backing resource resides in the resource cache then there should be an entry in this
60*c8dee2aaSAndroid Build Coastguard Worker //              cache
61*c8dee2aaSAndroid Build Coastguard Worker //   an entry in this cache, however, doesn't guarantee that there is a corresponding entry in
62*c8dee2aaSAndroid Build Coastguard Worker //              the resource cache - although the entry here should be able to generate that entry
63*c8dee2aaSAndroid Build Coastguard Worker //              (i.e., be a lazy proxy)
64*c8dee2aaSAndroid Build Coastguard Worker //
65*c8dee2aaSAndroid Build Coastguard Worker // Wrt interactions w/ GrContext/GrResourceCache purging, we have:
66*c8dee2aaSAndroid Build Coastguard Worker //
67*c8dee2aaSAndroid Build Coastguard Worker //    Both GrContext::abandonContext and GrContext::releaseResourcesAndAbandonContext will cause
68*c8dee2aaSAndroid Build Coastguard Worker //    all the refs held in this cache to be dropped prior to clearing out the resource cache.
69*c8dee2aaSAndroid Build Coastguard Worker //
70*c8dee2aaSAndroid Build Coastguard Worker //    For the size_t-variant of GrContext::purgeUnlockedResources, after an initial attempt
71*c8dee2aaSAndroid Build Coastguard Worker //    to purge the requested amount of resources fails, uniquely held resources in this cache
72*c8dee2aaSAndroid Build Coastguard Worker //    will be dropped in LRU to MRU order until the cache is under budget. Note that this
73*c8dee2aaSAndroid Build Coastguard Worker //    prioritizes the survival of resources in this cache over those just in the resource cache.
74*c8dee2aaSAndroid Build Coastguard Worker //
75*c8dee2aaSAndroid Build Coastguard Worker //    For the 'scratchResourcesOnly' variant of GrContext::purgeUnlockedResources, this cache
76*c8dee2aaSAndroid Build Coastguard Worker //    won't be modified in the scratch-only case unless the resource cache is over budget (in
77*c8dee2aaSAndroid Build Coastguard Worker //    which case it will purge uniquely-held resources in LRU to MRU order to get
78*c8dee2aaSAndroid Build Coastguard Worker //    back under budget). In the non-scratch-only case, all uniquely held resources in this cache
79*c8dee2aaSAndroid Build Coastguard Worker //    will be released prior to the resource cache being cleared out.
80*c8dee2aaSAndroid Build Coastguard Worker //
81*c8dee2aaSAndroid Build Coastguard Worker //    For GrContext::setResourceCacheLimit, if an initial pass through the resource cache doesn't
82*c8dee2aaSAndroid Build Coastguard Worker //    reach the budget, uniquely held resources in this cache will be released in LRU to MRU order.
83*c8dee2aaSAndroid Build Coastguard Worker //
84*c8dee2aaSAndroid Build Coastguard Worker //    For GrContext::performDeferredCleanup, any uniquely held resources that haven't been accessed
85*c8dee2aaSAndroid Build Coastguard Worker //    w/in 'msNotUsed' will be released from this cache prior to the resource cache being cleaned.
86*c8dee2aaSAndroid Build Coastguard Worker class GrThreadSafeCache {
87*c8dee2aaSAndroid Build Coastguard Worker public:
88*c8dee2aaSAndroid Build Coastguard Worker     GrThreadSafeCache();
89*c8dee2aaSAndroid Build Coastguard Worker     ~GrThreadSafeCache();
90*c8dee2aaSAndroid Build Coastguard Worker 
91*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
92*c8dee2aaSAndroid Build Coastguard Worker     int numEntries() const  SK_EXCLUDES(fSpinLock);
93*c8dee2aaSAndroid Build Coastguard Worker 
94*c8dee2aaSAndroid Build Coastguard Worker     size_t approxBytesUsedForHash() const  SK_EXCLUDES(fSpinLock);
95*c8dee2aaSAndroid Build Coastguard Worker #endif
96*c8dee2aaSAndroid Build Coastguard Worker 
97*c8dee2aaSAndroid Build Coastguard Worker     void dropAllRefs()  SK_EXCLUDES(fSpinLock);
98*c8dee2aaSAndroid Build Coastguard Worker 
99*c8dee2aaSAndroid Build Coastguard Worker     // Drop uniquely held refs until under the resource cache's budget.
100*c8dee2aaSAndroid Build Coastguard Worker     // A null parameter means drop all uniquely held refs.
101*c8dee2aaSAndroid Build Coastguard Worker     void dropUniqueRefs(GrResourceCache* resourceCache)  SK_EXCLUDES(fSpinLock);
102*c8dee2aaSAndroid Build Coastguard Worker 
103*c8dee2aaSAndroid Build Coastguard Worker     // Drop uniquely held refs that were last accessed before 'purgeTime'
104*c8dee2aaSAndroid Build Coastguard Worker     void dropUniqueRefsOlderThan(
105*c8dee2aaSAndroid Build Coastguard Worker             skgpu::StdSteadyClock::time_point purgeTime)  SK_EXCLUDES(fSpinLock);
106*c8dee2aaSAndroid Build Coastguard Worker 
107*c8dee2aaSAndroid Build Coastguard Worker     SkDEBUGCODE(bool has(const skgpu::UniqueKey&)  SK_EXCLUDES(fSpinLock);)
108*c8dee2aaSAndroid Build Coastguard Worker 
109*c8dee2aaSAndroid Build Coastguard Worker     GrSurfaceProxyView find(const skgpu::UniqueKey&)  SK_EXCLUDES(fSpinLock);
110*c8dee2aaSAndroid Build Coastguard Worker     std::tuple<GrSurfaceProxyView, sk_sp<SkData>> findWithData(
111*c8dee2aaSAndroid Build Coastguard Worker             const skgpu::UniqueKey&)  SK_EXCLUDES(fSpinLock);
112*c8dee2aaSAndroid Build Coastguard Worker 
113*c8dee2aaSAndroid Build Coastguard Worker     GrSurfaceProxyView add(
114*c8dee2aaSAndroid Build Coastguard Worker             const skgpu::UniqueKey&, const GrSurfaceProxyView&)  SK_EXCLUDES(fSpinLock);
115*c8dee2aaSAndroid Build Coastguard Worker     std::tuple<GrSurfaceProxyView, sk_sp<SkData>> addWithData(
116*c8dee2aaSAndroid Build Coastguard Worker             const skgpu::UniqueKey&, const GrSurfaceProxyView&)  SK_EXCLUDES(fSpinLock);
117*c8dee2aaSAndroid Build Coastguard Worker 
118*c8dee2aaSAndroid Build Coastguard Worker     GrSurfaceProxyView findOrAdd(const skgpu::UniqueKey&,
119*c8dee2aaSAndroid Build Coastguard Worker                                  const GrSurfaceProxyView&)  SK_EXCLUDES(fSpinLock);
120*c8dee2aaSAndroid Build Coastguard Worker     std::tuple<GrSurfaceProxyView, sk_sp<SkData>> findOrAddWithData(
121*c8dee2aaSAndroid Build Coastguard Worker             const skgpu::UniqueKey&, const GrSurfaceProxyView&)  SK_EXCLUDES(fSpinLock);
122*c8dee2aaSAndroid Build Coastguard Worker 
123*c8dee2aaSAndroid Build Coastguard Worker     // To hold vertex data in the cache and have it transparently transition from cpu-side to
124*c8dee2aaSAndroid Build Coastguard Worker     // gpu-side while being shared between all the threads we need a ref counted object that
125*c8dee2aaSAndroid Build Coastguard Worker     // keeps hold of the cpu-side data but allows deferred filling in of the mirroring gpu buffer.
126*c8dee2aaSAndroid Build Coastguard Worker     class VertexData : public SkNVRefCnt<VertexData> {
127*c8dee2aaSAndroid Build Coastguard Worker     public:
128*c8dee2aaSAndroid Build Coastguard Worker         ~VertexData();
129*c8dee2aaSAndroid Build Coastguard Worker 
vertices()130*c8dee2aaSAndroid Build Coastguard Worker         const void* vertices() const { return fVertices; }
size()131*c8dee2aaSAndroid Build Coastguard Worker         size_t size() const { return fNumVertices * fVertexSize; }
132*c8dee2aaSAndroid Build Coastguard Worker 
numVertices()133*c8dee2aaSAndroid Build Coastguard Worker         int numVertices() const { return fNumVertices; }
vertexSize()134*c8dee2aaSAndroid Build Coastguard Worker         size_t vertexSize() const { return fVertexSize; }
135*c8dee2aaSAndroid Build Coastguard Worker 
136*c8dee2aaSAndroid Build Coastguard Worker         // TODO: make these return const GrGpuBuffers?
gpuBuffer()137*c8dee2aaSAndroid Build Coastguard Worker         GrGpuBuffer* gpuBuffer() { return fGpuBuffer.get(); }
refGpuBuffer()138*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<GrGpuBuffer> refGpuBuffer() { return fGpuBuffer; }
139*c8dee2aaSAndroid Build Coastguard Worker 
setGpuBuffer(sk_sp<GrGpuBuffer> gpuBuffer)140*c8dee2aaSAndroid Build Coastguard Worker         void setGpuBuffer(sk_sp<GrGpuBuffer> gpuBuffer) {
141*c8dee2aaSAndroid Build Coastguard Worker             // TODO: once we add the gpuBuffer we could free 'fVertices'. Deinstantiable
142*c8dee2aaSAndroid Build Coastguard Worker             // DDLs could throw a monkey wrench into that plan though.
143*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(!fGpuBuffer);
144*c8dee2aaSAndroid Build Coastguard Worker             fGpuBuffer = std::move(gpuBuffer);
145*c8dee2aaSAndroid Build Coastguard Worker         }
146*c8dee2aaSAndroid Build Coastguard Worker 
reset()147*c8dee2aaSAndroid Build Coastguard Worker         void reset() {
148*c8dee2aaSAndroid Build Coastguard Worker             sk_free(const_cast<void*>(fVertices));
149*c8dee2aaSAndroid Build Coastguard Worker             fVertices = nullptr;
150*c8dee2aaSAndroid Build Coastguard Worker             fNumVertices = 0;
151*c8dee2aaSAndroid Build Coastguard Worker             fVertexSize = 0;
152*c8dee2aaSAndroid Build Coastguard Worker             fGpuBuffer.reset();
153*c8dee2aaSAndroid Build Coastguard Worker         }
154*c8dee2aaSAndroid Build Coastguard Worker 
155*c8dee2aaSAndroid Build Coastguard Worker     private:
156*c8dee2aaSAndroid Build Coastguard Worker         friend class GrThreadSafeCache;  // for access to ctor
157*c8dee2aaSAndroid Build Coastguard Worker 
VertexData(const void * vertices,int numVertices,size_t vertexSize)158*c8dee2aaSAndroid Build Coastguard Worker         VertexData(const void* vertices, int numVertices, size_t vertexSize)
159*c8dee2aaSAndroid Build Coastguard Worker                 : fVertices(vertices)
160*c8dee2aaSAndroid Build Coastguard Worker                 , fNumVertices(numVertices)
161*c8dee2aaSAndroid Build Coastguard Worker                 , fVertexSize(vertexSize) {
162*c8dee2aaSAndroid Build Coastguard Worker         }
163*c8dee2aaSAndroid Build Coastguard Worker 
VertexData(sk_sp<GrGpuBuffer> gpuBuffer,int numVertices,size_t vertexSize)164*c8dee2aaSAndroid Build Coastguard Worker         VertexData(sk_sp<GrGpuBuffer> gpuBuffer, int numVertices, size_t vertexSize)
165*c8dee2aaSAndroid Build Coastguard Worker                 : fVertices(nullptr)
166*c8dee2aaSAndroid Build Coastguard Worker                 , fNumVertices(numVertices)
167*c8dee2aaSAndroid Build Coastguard Worker                 , fVertexSize(vertexSize)
168*c8dee2aaSAndroid Build Coastguard Worker                 , fGpuBuffer(std::move(gpuBuffer)) {
169*c8dee2aaSAndroid Build Coastguard Worker         }
170*c8dee2aaSAndroid Build Coastguard Worker 
171*c8dee2aaSAndroid Build Coastguard Worker         const void*        fVertices;
172*c8dee2aaSAndroid Build Coastguard Worker         int                fNumVertices;
173*c8dee2aaSAndroid Build Coastguard Worker         size_t             fVertexSize;
174*c8dee2aaSAndroid Build Coastguard Worker 
175*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<GrGpuBuffer> fGpuBuffer;
176*c8dee2aaSAndroid Build Coastguard Worker     };
177*c8dee2aaSAndroid Build Coastguard Worker 
178*c8dee2aaSAndroid Build Coastguard Worker     // The returned VertexData object takes ownership of 'vertices' which had better have been
179*c8dee2aaSAndroid Build Coastguard Worker     // allocated with malloc!
180*c8dee2aaSAndroid Build Coastguard Worker     static sk_sp<VertexData> MakeVertexData(const void* vertices,
181*c8dee2aaSAndroid Build Coastguard Worker                                             int vertexCount,
182*c8dee2aaSAndroid Build Coastguard Worker                                             size_t vertexSize);
183*c8dee2aaSAndroid Build Coastguard Worker     static sk_sp<VertexData> MakeVertexData(sk_sp<GrGpuBuffer> buffer,
184*c8dee2aaSAndroid Build Coastguard Worker                                             int vertexCount,
185*c8dee2aaSAndroid Build Coastguard Worker                                             size_t vertexSize);
186*c8dee2aaSAndroid Build Coastguard Worker 
187*c8dee2aaSAndroid Build Coastguard Worker     std::tuple<sk_sp<VertexData>, sk_sp<SkData>> findVertsWithData(
188*c8dee2aaSAndroid Build Coastguard Worker             const skgpu::UniqueKey&)  SK_EXCLUDES(fSpinLock);
189*c8dee2aaSAndroid Build Coastguard Worker 
190*c8dee2aaSAndroid Build Coastguard Worker     typedef bool (*IsNewerBetter)(SkData* incumbent, SkData* challenger);
191*c8dee2aaSAndroid Build Coastguard Worker 
192*c8dee2aaSAndroid Build Coastguard Worker     std::tuple<sk_sp<VertexData>, sk_sp<SkData>> addVertsWithData(
193*c8dee2aaSAndroid Build Coastguard Worker                                                         const skgpu::UniqueKey&,
194*c8dee2aaSAndroid Build Coastguard Worker                                                         sk_sp<VertexData>,
195*c8dee2aaSAndroid Build Coastguard Worker                                                         IsNewerBetter)  SK_EXCLUDES(fSpinLock);
196*c8dee2aaSAndroid Build Coastguard Worker 
197*c8dee2aaSAndroid Build Coastguard Worker     void remove(const skgpu::UniqueKey&)  SK_EXCLUDES(fSpinLock);
198*c8dee2aaSAndroid Build Coastguard Worker 
199*c8dee2aaSAndroid Build Coastguard Worker     // To allow gpu-created resources to have priority, we pre-emptively place a lazy proxy
200*c8dee2aaSAndroid Build Coastguard Worker     // in the thread-safe cache (with findOrAdd). The Trampoline object allows that lazy proxy to
201*c8dee2aaSAndroid Build Coastguard Worker     // be instantiated with some later generated rendering result.
202*c8dee2aaSAndroid Build Coastguard Worker     class Trampoline : public SkRefCnt {
203*c8dee2aaSAndroid Build Coastguard Worker     public:
204*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<GrTextureProxy> fProxy;
205*c8dee2aaSAndroid Build Coastguard Worker     };
206*c8dee2aaSAndroid Build Coastguard Worker 
207*c8dee2aaSAndroid Build Coastguard Worker     static std::tuple<GrSurfaceProxyView, sk_sp<Trampoline>> CreateLazyView(GrDirectContext*,
208*c8dee2aaSAndroid Build Coastguard Worker                                                                             GrColorType,
209*c8dee2aaSAndroid Build Coastguard Worker                                                                             SkISize dimensions,
210*c8dee2aaSAndroid Build Coastguard Worker                                                                             GrSurfaceOrigin,
211*c8dee2aaSAndroid Build Coastguard Worker                                                                             SkBackingFit);
212*c8dee2aaSAndroid Build Coastguard Worker private:
213*c8dee2aaSAndroid Build Coastguard Worker     struct Entry {
EntryEntry214*c8dee2aaSAndroid Build Coastguard Worker         Entry(const skgpu::UniqueKey& key, const GrSurfaceProxyView& view)
215*c8dee2aaSAndroid Build Coastguard Worker                 : fKey(key), fView(view), fTag(Entry::Tag::kView) {}
216*c8dee2aaSAndroid Build Coastguard Worker 
EntryEntry217*c8dee2aaSAndroid Build Coastguard Worker         Entry(const skgpu::UniqueKey& key, sk_sp<VertexData> vertData)
218*c8dee2aaSAndroid Build Coastguard Worker                 : fKey(key), fVertData(std::move(vertData)), fTag(Entry::Tag::kVertData) {}
219*c8dee2aaSAndroid Build Coastguard Worker 
~EntryEntry220*c8dee2aaSAndroid Build Coastguard Worker         ~Entry() {
221*c8dee2aaSAndroid Build Coastguard Worker             this->makeEmpty();
222*c8dee2aaSAndroid Build Coastguard Worker         }
223*c8dee2aaSAndroid Build Coastguard Worker 
uniquelyHeldEntry224*c8dee2aaSAndroid Build Coastguard Worker         bool uniquelyHeld() const {
225*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(fTag != Tag::kEmpty);
226*c8dee2aaSAndroid Build Coastguard Worker 
227*c8dee2aaSAndroid Build Coastguard Worker             if (fTag == Tag::kView && fView.proxy()->unique()) {
228*c8dee2aaSAndroid Build Coastguard Worker                 return true;
229*c8dee2aaSAndroid Build Coastguard Worker             } else if (fTag == Tag::kVertData && fVertData->unique()) {
230*c8dee2aaSAndroid Build Coastguard Worker                 return true;
231*c8dee2aaSAndroid Build Coastguard Worker             }
232*c8dee2aaSAndroid Build Coastguard Worker 
233*c8dee2aaSAndroid Build Coastguard Worker             return false;
234*c8dee2aaSAndroid Build Coastguard Worker         }
235*c8dee2aaSAndroid Build Coastguard Worker 
keyEntry236*c8dee2aaSAndroid Build Coastguard Worker         const skgpu::UniqueKey& key() const {
237*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(fTag != Tag::kEmpty);
238*c8dee2aaSAndroid Build Coastguard Worker             return fKey;
239*c8dee2aaSAndroid Build Coastguard Worker         }
240*c8dee2aaSAndroid Build Coastguard Worker 
getCustomDataEntry241*c8dee2aaSAndroid Build Coastguard Worker         SkData* getCustomData() const {
242*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(fTag != Tag::kEmpty);
243*c8dee2aaSAndroid Build Coastguard Worker             return fKey.getCustomData();
244*c8dee2aaSAndroid Build Coastguard Worker         }
245*c8dee2aaSAndroid Build Coastguard Worker 
refCustomDataEntry246*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<SkData> refCustomData() const {
247*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(fTag != Tag::kEmpty);
248*c8dee2aaSAndroid Build Coastguard Worker             return fKey.refCustomData();
249*c8dee2aaSAndroid Build Coastguard Worker         }
250*c8dee2aaSAndroid Build Coastguard Worker 
viewEntry251*c8dee2aaSAndroid Build Coastguard Worker         GrSurfaceProxyView view() {
252*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(fTag == Tag::kView);
253*c8dee2aaSAndroid Build Coastguard Worker             return fView;
254*c8dee2aaSAndroid Build Coastguard Worker         }
255*c8dee2aaSAndroid Build Coastguard Worker 
vertexDataEntry256*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<VertexData> vertexData() {
257*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(fTag == Tag::kVertData);
258*c8dee2aaSAndroid Build Coastguard Worker             return fVertData;
259*c8dee2aaSAndroid Build Coastguard Worker         }
260*c8dee2aaSAndroid Build Coastguard Worker 
setEntry261*c8dee2aaSAndroid Build Coastguard Worker         void set(const skgpu::UniqueKey& key, const GrSurfaceProxyView& view) {
262*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(fTag == Tag::kEmpty);
263*c8dee2aaSAndroid Build Coastguard Worker             fKey = key;
264*c8dee2aaSAndroid Build Coastguard Worker             fView = view;
265*c8dee2aaSAndroid Build Coastguard Worker             fTag = Tag::kView;
266*c8dee2aaSAndroid Build Coastguard Worker         }
267*c8dee2aaSAndroid Build Coastguard Worker 
makeEmptyEntry268*c8dee2aaSAndroid Build Coastguard Worker         void makeEmpty() {
269*c8dee2aaSAndroid Build Coastguard Worker             fKey.reset();
270*c8dee2aaSAndroid Build Coastguard Worker             if (fTag == Tag::kView) {
271*c8dee2aaSAndroid Build Coastguard Worker                 fView.reset();
272*c8dee2aaSAndroid Build Coastguard Worker             } else if (fTag == Tag::kVertData) {
273*c8dee2aaSAndroid Build Coastguard Worker                 fVertData.reset();
274*c8dee2aaSAndroid Build Coastguard Worker             }
275*c8dee2aaSAndroid Build Coastguard Worker             fTag = Tag::kEmpty;
276*c8dee2aaSAndroid Build Coastguard Worker         }
277*c8dee2aaSAndroid Build Coastguard Worker 
setEntry278*c8dee2aaSAndroid Build Coastguard Worker         void set(const skgpu::UniqueKey& key, sk_sp<VertexData> vertData) {
279*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(fTag == Tag::kEmpty || fTag == Tag::kVertData);
280*c8dee2aaSAndroid Build Coastguard Worker             fKey = key;
281*c8dee2aaSAndroid Build Coastguard Worker             fVertData = std::move(vertData);
282*c8dee2aaSAndroid Build Coastguard Worker             fTag = Tag::kVertData;
283*c8dee2aaSAndroid Build Coastguard Worker         }
284*c8dee2aaSAndroid Build Coastguard Worker 
285*c8dee2aaSAndroid Build Coastguard Worker         // The thread-safe cache gets to directly manipulate the llist and last-access members
286*c8dee2aaSAndroid Build Coastguard Worker         skgpu::StdSteadyClock::time_point fLastAccess;
287*c8dee2aaSAndroid Build Coastguard Worker         SK_DECLARE_INTERNAL_LLIST_INTERFACE(Entry);
288*c8dee2aaSAndroid Build Coastguard Worker 
289*c8dee2aaSAndroid Build Coastguard Worker         // for SkTDynamicHash
GetKeyEntry290*c8dee2aaSAndroid Build Coastguard Worker         static const skgpu::UniqueKey& GetKey(const Entry& e) {
291*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(e.fTag != Tag::kEmpty);
292*c8dee2aaSAndroid Build Coastguard Worker             return e.fKey;
293*c8dee2aaSAndroid Build Coastguard Worker         }
HashEntry294*c8dee2aaSAndroid Build Coastguard Worker         static uint32_t Hash(const skgpu::UniqueKey& key) { return key.hash(); }
295*c8dee2aaSAndroid Build Coastguard Worker 
296*c8dee2aaSAndroid Build Coastguard Worker     private:
297*c8dee2aaSAndroid Build Coastguard Worker         // Note: the unique key is stored here bc it is never attached to a proxy or a GrTexture
298*c8dee2aaSAndroid Build Coastguard Worker         skgpu::UniqueKey             fKey;
299*c8dee2aaSAndroid Build Coastguard Worker         union {
300*c8dee2aaSAndroid Build Coastguard Worker             GrSurfaceProxyView  fView;
301*c8dee2aaSAndroid Build Coastguard Worker             sk_sp<VertexData>   fVertData;
302*c8dee2aaSAndroid Build Coastguard Worker         };
303*c8dee2aaSAndroid Build Coastguard Worker 
304*c8dee2aaSAndroid Build Coastguard Worker         enum class Tag {
305*c8dee2aaSAndroid Build Coastguard Worker             kEmpty,
306*c8dee2aaSAndroid Build Coastguard Worker             kView,
307*c8dee2aaSAndroid Build Coastguard Worker             kVertData,
308*c8dee2aaSAndroid Build Coastguard Worker         };
309*c8dee2aaSAndroid Build Coastguard Worker         Tag fTag{Tag::kEmpty};
310*c8dee2aaSAndroid Build Coastguard Worker     };
311*c8dee2aaSAndroid Build Coastguard Worker 
312*c8dee2aaSAndroid Build Coastguard Worker     void makeExistingEntryMRU(Entry*)  SK_REQUIRES(fSpinLock);
313*c8dee2aaSAndroid Build Coastguard Worker     Entry* makeNewEntryMRU(Entry*)  SK_REQUIRES(fSpinLock);
314*c8dee2aaSAndroid Build Coastguard Worker 
315*c8dee2aaSAndroid Build Coastguard Worker     Entry* getEntry(const skgpu::UniqueKey&, const GrSurfaceProxyView&)  SK_REQUIRES(fSpinLock);
316*c8dee2aaSAndroid Build Coastguard Worker     Entry* getEntry(const skgpu::UniqueKey&, sk_sp<VertexData>)  SK_REQUIRES(fSpinLock);
317*c8dee2aaSAndroid Build Coastguard Worker 
318*c8dee2aaSAndroid Build Coastguard Worker     void recycleEntry(Entry*)  SK_REQUIRES(fSpinLock);
319*c8dee2aaSAndroid Build Coastguard Worker 
320*c8dee2aaSAndroid Build Coastguard Worker     std::tuple<GrSurfaceProxyView, sk_sp<SkData>> internalFind(
321*c8dee2aaSAndroid Build Coastguard Worker             const skgpu::UniqueKey&)  SK_REQUIRES(fSpinLock);
322*c8dee2aaSAndroid Build Coastguard Worker     std::tuple<GrSurfaceProxyView, sk_sp<SkData>> internalAdd(
323*c8dee2aaSAndroid Build Coastguard Worker             const skgpu::UniqueKey&, const GrSurfaceProxyView&)  SK_REQUIRES(fSpinLock);
324*c8dee2aaSAndroid Build Coastguard Worker 
325*c8dee2aaSAndroid Build Coastguard Worker     std::tuple<sk_sp<VertexData>, sk_sp<SkData>> internalFindVerts(
326*c8dee2aaSAndroid Build Coastguard Worker             const skgpu::UniqueKey&)  SK_REQUIRES(fSpinLock);
327*c8dee2aaSAndroid Build Coastguard Worker     std::tuple<sk_sp<VertexData>, sk_sp<SkData>> internalAddVerts(
328*c8dee2aaSAndroid Build Coastguard Worker             const skgpu::UniqueKey&, sk_sp<VertexData>, IsNewerBetter)  SK_REQUIRES(fSpinLock);
329*c8dee2aaSAndroid Build Coastguard Worker 
330*c8dee2aaSAndroid Build Coastguard Worker     mutable SkSpinlock fSpinLock;
331*c8dee2aaSAndroid Build Coastguard Worker 
332*c8dee2aaSAndroid Build Coastguard Worker     SkTDynamicHash<Entry, skgpu::UniqueKey> fUniquelyKeyedEntryMap  SK_GUARDED_BY(fSpinLock);
333*c8dee2aaSAndroid Build Coastguard Worker     // The head of this list is the MRU
334*c8dee2aaSAndroid Build Coastguard Worker     SkTInternalLList<Entry>            fUniquelyKeyedEntryList  SK_GUARDED_BY(fSpinLock);
335*c8dee2aaSAndroid Build Coastguard Worker 
336*c8dee2aaSAndroid Build Coastguard Worker     // TODO: empirically determine this from the skps
337*c8dee2aaSAndroid Build Coastguard Worker     static const int kInitialArenaSize = 64 * sizeof(Entry);
338*c8dee2aaSAndroid Build Coastguard Worker 
339*c8dee2aaSAndroid Build Coastguard Worker     char                         fStorage[kInitialArenaSize];
340*c8dee2aaSAndroid Build Coastguard Worker     SkArenaAlloc                 fEntryAllocator{fStorage, kInitialArenaSize, kInitialArenaSize};
341*c8dee2aaSAndroid Build Coastguard Worker     Entry*                       fFreeEntryList  SK_GUARDED_BY(fSpinLock);
342*c8dee2aaSAndroid Build Coastguard Worker };
343*c8dee2aaSAndroid Build Coastguard Worker 
344*c8dee2aaSAndroid Build Coastguard Worker #endif // GrThreadSafeCache_DEFINED
345