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