xref: /aosp_15_r20/external/skia/src/gpu/ganesh/GrResourceCache.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2014 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 GrResourceCache_DEFINED
9*c8dee2aaSAndroid Build Coastguard Worker #define GrResourceCache_DEFINED
10*c8dee2aaSAndroid Build Coastguard Worker 
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrDirectContext.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkDebug.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTArray.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTDArray.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTo.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/gpu/ganesh/GrTypesPriv.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkTDPQueue.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkMessageBus.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkTDynamicHash.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkTMultiMap.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/GpuTypesPriv.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ResourceKey.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrGpuResource.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrGpuResourceCacheAccess.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrGpuResourcePriv.h"
28*c8dee2aaSAndroid Build Coastguard Worker 
29*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef>
30*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
31*c8dee2aaSAndroid Build Coastguard Worker #include <functional>
32*c8dee2aaSAndroid Build Coastguard Worker #include <type_traits>
33*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
34*c8dee2aaSAndroid Build Coastguard Worker 
35*c8dee2aaSAndroid Build Coastguard Worker class GrProxyProvider;
36*c8dee2aaSAndroid Build Coastguard Worker class GrSurface;
37*c8dee2aaSAndroid Build Coastguard Worker class GrThreadSafeCache;
38*c8dee2aaSAndroid Build Coastguard Worker class SkString;
39*c8dee2aaSAndroid Build Coastguard Worker class SkTraceMemoryDump;
40*c8dee2aaSAndroid Build Coastguard Worker enum class GrPurgeResourceOptions;
41*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu {
42*c8dee2aaSAndroid Build Coastguard Worker class SingleOwner;
43*c8dee2aaSAndroid Build Coastguard Worker }
44*c8dee2aaSAndroid Build Coastguard Worker 
45*c8dee2aaSAndroid Build Coastguard Worker /**
46*c8dee2aaSAndroid Build Coastguard Worker  * Manages the lifetime of all GrGpuResource instances.
47*c8dee2aaSAndroid Build Coastguard Worker  *
48*c8dee2aaSAndroid Build Coastguard Worker  * Resources may have optionally have two types of keys:
49*c8dee2aaSAndroid Build Coastguard Worker  *      1) A scratch key. This is for resources whose allocations are cached but not their contents.
50*c8dee2aaSAndroid Build Coastguard Worker  *         Multiple resources can share the same scratch key. This is so a caller can have two
51*c8dee2aaSAndroid Build Coastguard Worker  *         resource instances with the same properties (e.g. multipass rendering that ping-pongs
52*c8dee2aaSAndroid Build Coastguard Worker  *         between two temporary surfaces). The scratch key is set at resource creation time and
53*c8dee2aaSAndroid Build Coastguard Worker  *         should never change. Resources need not have a scratch key.
54*c8dee2aaSAndroid Build Coastguard Worker  *      2) A unique key. This key's meaning is specific to the domain that created the key. Only one
55*c8dee2aaSAndroid Build Coastguard Worker  *         resource may have a given unique key. The unique key can be set, cleared, or changed
56*c8dee2aaSAndroid Build Coastguard Worker  *         anytime after resource creation.
57*c8dee2aaSAndroid Build Coastguard Worker  *
58*c8dee2aaSAndroid Build Coastguard Worker  * A unique key always takes precedence over a scratch key when a resource has both types of keys.
59*c8dee2aaSAndroid Build Coastguard Worker  * If a resource has neither key type then it will be deleted as soon as the last reference to it
60*c8dee2aaSAndroid Build Coastguard Worker  * is dropped.
61*c8dee2aaSAndroid Build Coastguard Worker  */
62*c8dee2aaSAndroid Build Coastguard Worker class GrResourceCache {
63*c8dee2aaSAndroid Build Coastguard Worker public:
64*c8dee2aaSAndroid Build Coastguard Worker     GrResourceCache(skgpu::SingleOwner* owner,
65*c8dee2aaSAndroid Build Coastguard Worker                     GrDirectContext::DirectContextID owningContextID,
66*c8dee2aaSAndroid Build Coastguard Worker                     uint32_t familyID);
67*c8dee2aaSAndroid Build Coastguard Worker     ~GrResourceCache();
68*c8dee2aaSAndroid Build Coastguard Worker 
69*c8dee2aaSAndroid Build Coastguard Worker     /**
70*c8dee2aaSAndroid Build Coastguard Worker      * This is used to safely return a resource to the cache when the owner may be on another
71*c8dee2aaSAndroid Build Coastguard Worker      * thread from GrDirectContext. If the context still exists then using this method ensures that
72*c8dee2aaSAndroid Build Coastguard Worker      * the resource is received by the cache for processing (recycling or destruction) on the
73*c8dee2aaSAndroid Build Coastguard Worker      * context's thread.
74*c8dee2aaSAndroid Build Coastguard Worker      *
75*c8dee2aaSAndroid Build Coastguard Worker      * This is templated as it is rather than simply taking sk_sp<GrGpuResource> in order to enforce
76*c8dee2aaSAndroid Build Coastguard Worker      * that the caller passes an rvalue. If the caller doesn't move its ref into this function
77*c8dee2aaSAndroid Build Coastguard Worker      * then it will retain ownership, defeating the purpose. (Note that sk_sp<GrGpuResource>&&
78*c8dee2aaSAndroid Build Coastguard Worker      * doesn't work either because calling with sk_sp<GrSpecificResource> will create a temporary
79*c8dee2aaSAndroid Build Coastguard Worker      * sk_sp<GrGpuResource> which is an rvalue).
80*c8dee2aaSAndroid Build Coastguard Worker      */
81*c8dee2aaSAndroid Build Coastguard Worker     template<typename T>
82*c8dee2aaSAndroid Build Coastguard Worker     static std::enable_if_t<std::is_base_of_v<GrGpuResource, T>, void>
ReturnResourceFromThread(sk_sp<T> && resource,GrDirectContext::DirectContextID id)83*c8dee2aaSAndroid Build Coastguard Worker     ReturnResourceFromThread(sk_sp<T>&& resource, GrDirectContext::DirectContextID id) {
84*c8dee2aaSAndroid Build Coastguard Worker         UnrefResourceMessage msg(std::move(resource), id);
85*c8dee2aaSAndroid Build Coastguard Worker         UnrefResourceMessage::Bus::Post(std::move(msg));
86*c8dee2aaSAndroid Build Coastguard Worker     }
87*c8dee2aaSAndroid Build Coastguard Worker 
88*c8dee2aaSAndroid Build Coastguard Worker     // Default maximum number of bytes of gpu memory of budgeted resources in the cache.
89*c8dee2aaSAndroid Build Coastguard Worker     static const size_t kDefaultMaxSize             = 256 * (1 << 20);
90*c8dee2aaSAndroid Build Coastguard Worker 
91*c8dee2aaSAndroid Build Coastguard Worker     /** Used to access functionality needed by GrGpuResource for lifetime management. */
92*c8dee2aaSAndroid Build Coastguard Worker     class ResourceAccess;
93*c8dee2aaSAndroid Build Coastguard Worker     ResourceAccess resourceAccess();
94*c8dee2aaSAndroid Build Coastguard Worker 
95*c8dee2aaSAndroid Build Coastguard Worker     /** Unique ID of the owning GrContext. */
contextUniqueID()96*c8dee2aaSAndroid Build Coastguard Worker     uint32_t contextUniqueID() const { return fContextUniqueID; }
97*c8dee2aaSAndroid Build Coastguard Worker 
98*c8dee2aaSAndroid Build Coastguard Worker     /** Sets the max gpu memory byte size of the cache. */
99*c8dee2aaSAndroid Build Coastguard Worker     void setLimit(size_t bytes);
100*c8dee2aaSAndroid Build Coastguard Worker 
101*c8dee2aaSAndroid Build Coastguard Worker     /**
102*c8dee2aaSAndroid Build Coastguard Worker      * Returns the number of resources.
103*c8dee2aaSAndroid Build Coastguard Worker      */
getResourceCount()104*c8dee2aaSAndroid Build Coastguard Worker     int getResourceCount() const {
105*c8dee2aaSAndroid Build Coastguard Worker         return fPurgeableQueue.count() + fNonpurgeableResources.size();
106*c8dee2aaSAndroid Build Coastguard Worker     }
107*c8dee2aaSAndroid Build Coastguard Worker 
108*c8dee2aaSAndroid Build Coastguard Worker     /**
109*c8dee2aaSAndroid Build Coastguard Worker      * Returns the number of resources that count against the budget.
110*c8dee2aaSAndroid Build Coastguard Worker      */
getBudgetedResourceCount()111*c8dee2aaSAndroid Build Coastguard Worker     int getBudgetedResourceCount() const { return fBudgetedCount; }
112*c8dee2aaSAndroid Build Coastguard Worker 
113*c8dee2aaSAndroid Build Coastguard Worker     /**
114*c8dee2aaSAndroid Build Coastguard Worker      * Returns the number of bytes consumed by resources.
115*c8dee2aaSAndroid Build Coastguard Worker      */
getResourceBytes()116*c8dee2aaSAndroid Build Coastguard Worker     size_t getResourceBytes() const { return fBytes; }
117*c8dee2aaSAndroid Build Coastguard Worker 
118*c8dee2aaSAndroid Build Coastguard Worker     /**
119*c8dee2aaSAndroid Build Coastguard Worker      * Returns the number of bytes held by unlocked resources which are available for purging.
120*c8dee2aaSAndroid Build Coastguard Worker      */
getPurgeableBytes()121*c8dee2aaSAndroid Build Coastguard Worker     size_t getPurgeableBytes() const { return fPurgeableBytes; }
122*c8dee2aaSAndroid Build Coastguard Worker 
123*c8dee2aaSAndroid Build Coastguard Worker     /**
124*c8dee2aaSAndroid Build Coastguard Worker      * Returns the number of bytes consumed by budgeted resources.
125*c8dee2aaSAndroid Build Coastguard Worker      */
getBudgetedResourceBytes()126*c8dee2aaSAndroid Build Coastguard Worker     size_t getBudgetedResourceBytes() const { return fBudgetedBytes; }
127*c8dee2aaSAndroid Build Coastguard Worker 
128*c8dee2aaSAndroid Build Coastguard Worker     /**
129*c8dee2aaSAndroid Build Coastguard Worker      * Returns the number of bytes consumed by cached resources.
130*c8dee2aaSAndroid Build Coastguard Worker      */
getMaxResourceBytes()131*c8dee2aaSAndroid Build Coastguard Worker     size_t getMaxResourceBytes() const { return fMaxBytes; }
132*c8dee2aaSAndroid Build Coastguard Worker 
133*c8dee2aaSAndroid Build Coastguard Worker     /**
134*c8dee2aaSAndroid Build Coastguard Worker      * Abandons the backend API resources owned by all GrGpuResource objects and removes them from
135*c8dee2aaSAndroid Build Coastguard Worker      * the cache.
136*c8dee2aaSAndroid Build Coastguard Worker      */
137*c8dee2aaSAndroid Build Coastguard Worker     void abandonAll();
138*c8dee2aaSAndroid Build Coastguard Worker 
139*c8dee2aaSAndroid Build Coastguard Worker     /**
140*c8dee2aaSAndroid Build Coastguard Worker      * Releases the backend API resources owned by all GrGpuResource objects and removes them from
141*c8dee2aaSAndroid Build Coastguard Worker      * the cache.
142*c8dee2aaSAndroid Build Coastguard Worker      */
143*c8dee2aaSAndroid Build Coastguard Worker     void releaseAll();
144*c8dee2aaSAndroid Build Coastguard Worker 
145*c8dee2aaSAndroid Build Coastguard Worker     /**
146*c8dee2aaSAndroid Build Coastguard Worker      * Find a resource that matches a scratch key.
147*c8dee2aaSAndroid Build Coastguard Worker      */
148*c8dee2aaSAndroid Build Coastguard Worker     GrGpuResource* findAndRefScratchResource(const skgpu::ScratchKey& scratchKey);
149*c8dee2aaSAndroid Build Coastguard Worker 
150*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
151*c8dee2aaSAndroid Build Coastguard Worker     // This is not particularly fast and only used for validation, so debug only.
countScratchEntriesForKey(const skgpu::ScratchKey & scratchKey)152*c8dee2aaSAndroid Build Coastguard Worker     int countScratchEntriesForKey(const skgpu::ScratchKey& scratchKey) const {
153*c8dee2aaSAndroid Build Coastguard Worker         return fScratchMap.countForKey(scratchKey);
154*c8dee2aaSAndroid Build Coastguard Worker     }
155*c8dee2aaSAndroid Build Coastguard Worker #endif
156*c8dee2aaSAndroid Build Coastguard Worker 
157*c8dee2aaSAndroid Build Coastguard Worker     /**
158*c8dee2aaSAndroid Build Coastguard Worker      * Find a resource that matches a unique key.
159*c8dee2aaSAndroid Build Coastguard Worker      */
findAndRefUniqueResource(const skgpu::UniqueKey & key)160*c8dee2aaSAndroid Build Coastguard Worker     GrGpuResource* findAndRefUniqueResource(const skgpu::UniqueKey& key) {
161*c8dee2aaSAndroid Build Coastguard Worker         GrGpuResource* resource = fUniqueHash.find(key);
162*c8dee2aaSAndroid Build Coastguard Worker         if (resource) {
163*c8dee2aaSAndroid Build Coastguard Worker             this->refAndMakeResourceMRU(resource);
164*c8dee2aaSAndroid Build Coastguard Worker         }
165*c8dee2aaSAndroid Build Coastguard Worker         return resource;
166*c8dee2aaSAndroid Build Coastguard Worker     }
167*c8dee2aaSAndroid Build Coastguard Worker 
168*c8dee2aaSAndroid Build Coastguard Worker     /**
169*c8dee2aaSAndroid Build Coastguard Worker      * Query whether a unique key exists in the cache.
170*c8dee2aaSAndroid Build Coastguard Worker      */
hasUniqueKey(const skgpu::UniqueKey & key)171*c8dee2aaSAndroid Build Coastguard Worker     bool hasUniqueKey(const skgpu::UniqueKey& key) const {
172*c8dee2aaSAndroid Build Coastguard Worker         return SkToBool(fUniqueHash.find(key));
173*c8dee2aaSAndroid Build Coastguard Worker     }
174*c8dee2aaSAndroid Build Coastguard Worker 
175*c8dee2aaSAndroid Build Coastguard Worker     /** Purges resources to become under budget and processes resources with invalidated unique
176*c8dee2aaSAndroid Build Coastguard Worker         keys. */
177*c8dee2aaSAndroid Build Coastguard Worker     void purgeAsNeeded();
178*c8dee2aaSAndroid Build Coastguard Worker 
179*c8dee2aaSAndroid Build Coastguard Worker     // Purge unlocked resources. If 'opts' is kScratchResourcesOnly, the purgeable resources
180*c8dee2aaSAndroid Build Coastguard Worker     // containing persistent data are spared. If it is kAllResources then all purgeable resources
181*c8dee2aaSAndroid Build Coastguard Worker     // will be deleted.
purgeUnlockedResources(GrPurgeResourceOptions opts)182*c8dee2aaSAndroid Build Coastguard Worker     void purgeUnlockedResources(GrPurgeResourceOptions opts) {
183*c8dee2aaSAndroid Build Coastguard Worker         this->purgeUnlockedResources(/*purgeTime=*/nullptr, opts);
184*c8dee2aaSAndroid Build Coastguard Worker     }
185*c8dee2aaSAndroid Build Coastguard Worker 
186*c8dee2aaSAndroid Build Coastguard Worker     // Purge unlocked resources not used since the passed point in time. If 'opts' is
187*c8dee2aaSAndroid Build Coastguard Worker     // kScratchResourcesOnly, the purgeable resources containing persistent data are spared.
188*c8dee2aaSAndroid Build Coastguard Worker     // If it is kAllResources then all purgeable resources older than 'purgeTime' will be deleted.
purgeResourcesNotUsedSince(skgpu::StdSteadyClock::time_point purgeTime,GrPurgeResourceOptions opts)189*c8dee2aaSAndroid Build Coastguard Worker     void purgeResourcesNotUsedSince(skgpu::StdSteadyClock::time_point purgeTime,
190*c8dee2aaSAndroid Build Coastguard Worker                                     GrPurgeResourceOptions opts) {
191*c8dee2aaSAndroid Build Coastguard Worker         this->purgeUnlockedResources(&purgeTime, opts);
192*c8dee2aaSAndroid Build Coastguard Worker     }
193*c8dee2aaSAndroid Build Coastguard Worker 
194*c8dee2aaSAndroid Build Coastguard Worker     /** If it's possible to purge enough resources to get the provided amount of budget
195*c8dee2aaSAndroid Build Coastguard Worker         headroom, do so and return true. If it's not possible, do nothing and return false.
196*c8dee2aaSAndroid Build Coastguard Worker      */
197*c8dee2aaSAndroid Build Coastguard Worker     bool purgeToMakeHeadroom(size_t desiredHeadroomBytes);
198*c8dee2aaSAndroid Build Coastguard Worker 
overBudget()199*c8dee2aaSAndroid Build Coastguard Worker     bool overBudget() const { return fBudgetedBytes > fMaxBytes; }
200*c8dee2aaSAndroid Build Coastguard Worker 
201*c8dee2aaSAndroid Build Coastguard Worker     /**
202*c8dee2aaSAndroid Build Coastguard Worker      * Purge unlocked resources from the cache until the the provided byte count has been reached
203*c8dee2aaSAndroid Build Coastguard Worker      * or we have purged all unlocked resources. The default policy is to purge in LRU order, but
204*c8dee2aaSAndroid Build Coastguard Worker      * can be overridden to prefer purging scratch resources (in LRU order) prior to purging other
205*c8dee2aaSAndroid Build Coastguard Worker      * resource types.
206*c8dee2aaSAndroid Build Coastguard Worker      *
207*c8dee2aaSAndroid Build Coastguard Worker      * @param maxBytesToPurge the desired number of bytes to be purged.
208*c8dee2aaSAndroid Build Coastguard Worker      * @param preferScratchResources If true scratch resources will be purged prior to other
209*c8dee2aaSAndroid Build Coastguard Worker      *                               resource types.
210*c8dee2aaSAndroid Build Coastguard Worker      */
211*c8dee2aaSAndroid Build Coastguard Worker     void purgeUnlockedResources(size_t bytesToPurge, bool preferScratchResources);
212*c8dee2aaSAndroid Build Coastguard Worker 
213*c8dee2aaSAndroid Build Coastguard Worker     /** Returns true if the cache would like a flush to occur in order to make more resources
214*c8dee2aaSAndroid Build Coastguard Worker         purgeable. */
215*c8dee2aaSAndroid Build Coastguard Worker     bool requestsFlush() const;
216*c8dee2aaSAndroid Build Coastguard Worker 
217*c8dee2aaSAndroid Build Coastguard Worker #if GR_CACHE_STATS
218*c8dee2aaSAndroid Build Coastguard Worker     struct Stats {
219*c8dee2aaSAndroid Build Coastguard Worker         int fTotal;
220*c8dee2aaSAndroid Build Coastguard Worker         int fNumPurgeable;
221*c8dee2aaSAndroid Build Coastguard Worker         int fNumNonPurgeable;
222*c8dee2aaSAndroid Build Coastguard Worker 
223*c8dee2aaSAndroid Build Coastguard Worker         int fScratch;
224*c8dee2aaSAndroid Build Coastguard Worker         int fWrapped;
225*c8dee2aaSAndroid Build Coastguard Worker         size_t fUnbudgetedSize;
226*c8dee2aaSAndroid Build Coastguard Worker 
StatsStats227*c8dee2aaSAndroid Build Coastguard Worker         Stats() { this->reset(); }
228*c8dee2aaSAndroid Build Coastguard Worker 
resetStats229*c8dee2aaSAndroid Build Coastguard Worker         void reset() {
230*c8dee2aaSAndroid Build Coastguard Worker             fTotal = 0;
231*c8dee2aaSAndroid Build Coastguard Worker             fNumPurgeable = 0;
232*c8dee2aaSAndroid Build Coastguard Worker             fNumNonPurgeable = 0;
233*c8dee2aaSAndroid Build Coastguard Worker             fScratch = 0;
234*c8dee2aaSAndroid Build Coastguard Worker             fWrapped = 0;
235*c8dee2aaSAndroid Build Coastguard Worker             fUnbudgetedSize = 0;
236*c8dee2aaSAndroid Build Coastguard Worker         }
237*c8dee2aaSAndroid Build Coastguard Worker 
updateStats238*c8dee2aaSAndroid Build Coastguard Worker         void update(GrGpuResource* resource) {
239*c8dee2aaSAndroid Build Coastguard Worker             if (resource->cacheAccess().isScratch()) {
240*c8dee2aaSAndroid Build Coastguard Worker                 ++fScratch;
241*c8dee2aaSAndroid Build Coastguard Worker             }
242*c8dee2aaSAndroid Build Coastguard Worker             if (resource->resourcePriv().refsWrappedObjects()) {
243*c8dee2aaSAndroid Build Coastguard Worker                 ++fWrapped;
244*c8dee2aaSAndroid Build Coastguard Worker             }
245*c8dee2aaSAndroid Build Coastguard Worker             if (GrBudgetedType::kBudgeted != resource->resourcePriv().budgetedType()) {
246*c8dee2aaSAndroid Build Coastguard Worker                 fUnbudgetedSize += resource->gpuMemorySize();
247*c8dee2aaSAndroid Build Coastguard Worker             }
248*c8dee2aaSAndroid Build Coastguard Worker         }
249*c8dee2aaSAndroid Build Coastguard Worker     };
250*c8dee2aaSAndroid Build Coastguard Worker 
251*c8dee2aaSAndroid Build Coastguard Worker     void getStats(Stats*) const;
252*c8dee2aaSAndroid Build Coastguard Worker 
253*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
254*c8dee2aaSAndroid Build Coastguard Worker     void dumpStats(SkString*) const;
255*c8dee2aaSAndroid Build Coastguard Worker 
256*c8dee2aaSAndroid Build Coastguard Worker     void dumpStatsKeyValuePairs(
257*c8dee2aaSAndroid Build Coastguard Worker             skia_private::TArray<SkString>* keys, skia_private::TArray<double>* value) const;
258*c8dee2aaSAndroid Build Coastguard Worker #endif
259*c8dee2aaSAndroid Build Coastguard Worker 
260*c8dee2aaSAndroid Build Coastguard Worker #endif // GR_CACHE_STATS
261*c8dee2aaSAndroid Build Coastguard Worker 
262*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
263*c8dee2aaSAndroid Build Coastguard Worker     int countUniqueKeysWithTag(const char* tag) const;
264*c8dee2aaSAndroid Build Coastguard Worker 
265*c8dee2aaSAndroid Build Coastguard Worker     void changeTimestamp(uint32_t newTimestamp);
266*c8dee2aaSAndroid Build Coastguard Worker 
267*c8dee2aaSAndroid Build Coastguard Worker     void visitSurfaces(const std::function<void(const GrSurface*, bool purgeable)>&) const;
268*c8dee2aaSAndroid Build Coastguard Worker #endif
269*c8dee2aaSAndroid Build Coastguard Worker 
270*c8dee2aaSAndroid Build Coastguard Worker     // Enumerates all cached resources and dumps their details to traceMemoryDump.
271*c8dee2aaSAndroid Build Coastguard Worker     void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const;
272*c8dee2aaSAndroid Build Coastguard Worker 
setProxyProvider(GrProxyProvider * proxyProvider)273*c8dee2aaSAndroid Build Coastguard Worker     void setProxyProvider(GrProxyProvider* proxyProvider) { fProxyProvider = proxyProvider; }
setThreadSafeCache(GrThreadSafeCache * threadSafeCache)274*c8dee2aaSAndroid Build Coastguard Worker     void setThreadSafeCache(GrThreadSafeCache* threadSafeCache) {
275*c8dee2aaSAndroid Build Coastguard Worker         fThreadSafeCache = threadSafeCache;
276*c8dee2aaSAndroid Build Coastguard Worker     }
277*c8dee2aaSAndroid Build Coastguard Worker 
278*c8dee2aaSAndroid Build Coastguard Worker     // It'd be nice if this could be private but SkMessageBus relies on macros to define types that
279*c8dee2aaSAndroid Build Coastguard Worker     // require this to be public.
280*c8dee2aaSAndroid Build Coastguard Worker     class UnrefResourceMessage {
281*c8dee2aaSAndroid Build Coastguard Worker     public:
recipient()282*c8dee2aaSAndroid Build Coastguard Worker         GrDirectContext::DirectContextID recipient() const { return fRecipient; }
283*c8dee2aaSAndroid Build Coastguard Worker 
284*c8dee2aaSAndroid Build Coastguard Worker         UnrefResourceMessage(UnrefResourceMessage&&) = default;
285*c8dee2aaSAndroid Build Coastguard Worker         UnrefResourceMessage& operator=(UnrefResourceMessage&&) = default;
286*c8dee2aaSAndroid Build Coastguard Worker 
287*c8dee2aaSAndroid Build Coastguard Worker     private:
288*c8dee2aaSAndroid Build Coastguard Worker         friend class GrResourceCache;
289*c8dee2aaSAndroid Build Coastguard Worker 
290*c8dee2aaSAndroid Build Coastguard Worker         using Bus = SkMessageBus<UnrefResourceMessage,
291*c8dee2aaSAndroid Build Coastguard Worker                                  GrDirectContext::DirectContextID,
292*c8dee2aaSAndroid Build Coastguard Worker                                  /*AllowCopyableMessage=*/false>;
293*c8dee2aaSAndroid Build Coastguard Worker 
UnrefResourceMessage(sk_sp<GrGpuResource> && resource,GrDirectContext::DirectContextID recipient)294*c8dee2aaSAndroid Build Coastguard Worker         UnrefResourceMessage(sk_sp<GrGpuResource>&& resource,
295*c8dee2aaSAndroid Build Coastguard Worker                              GrDirectContext::DirectContextID recipient)
296*c8dee2aaSAndroid Build Coastguard Worker                 : fResource(std::move(resource)), fRecipient(recipient) {}
297*c8dee2aaSAndroid Build Coastguard Worker 
298*c8dee2aaSAndroid Build Coastguard Worker         UnrefResourceMessage(const UnrefResourceMessage&) = delete;
299*c8dee2aaSAndroid Build Coastguard Worker         UnrefResourceMessage& operator=(const UnrefResourceMessage&) = delete;
300*c8dee2aaSAndroid Build Coastguard Worker 
301*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<GrGpuResource> fResource;
302*c8dee2aaSAndroid Build Coastguard Worker         GrDirectContext::DirectContextID fRecipient;
303*c8dee2aaSAndroid Build Coastguard Worker     };
304*c8dee2aaSAndroid Build Coastguard Worker 
305*c8dee2aaSAndroid Build Coastguard Worker private:
306*c8dee2aaSAndroid Build Coastguard Worker     ///////////////////////////////////////////////////////////////////////////
307*c8dee2aaSAndroid Build Coastguard Worker     /// @name Methods accessible via ResourceAccess
308*c8dee2aaSAndroid Build Coastguard Worker     ////
309*c8dee2aaSAndroid Build Coastguard Worker     void insertResource(GrGpuResource*);
310*c8dee2aaSAndroid Build Coastguard Worker     void removeResource(GrGpuResource*);
311*c8dee2aaSAndroid Build Coastguard Worker     void notifyARefCntReachedZero(GrGpuResource*, GrGpuResource::LastRemovedRef);
312*c8dee2aaSAndroid Build Coastguard Worker     void changeUniqueKey(GrGpuResource*, const skgpu::UniqueKey&);
313*c8dee2aaSAndroid Build Coastguard Worker     void removeUniqueKey(GrGpuResource*);
314*c8dee2aaSAndroid Build Coastguard Worker     void willRemoveScratchKey(const GrGpuResource*);
315*c8dee2aaSAndroid Build Coastguard Worker     void didChangeBudgetStatus(GrGpuResource*);
316*c8dee2aaSAndroid Build Coastguard Worker     void refResource(GrGpuResource* resource);
317*c8dee2aaSAndroid Build Coastguard Worker     /// @}
318*c8dee2aaSAndroid Build Coastguard Worker 
319*c8dee2aaSAndroid Build Coastguard Worker     void refAndMakeResourceMRU(GrGpuResource*);
320*c8dee2aaSAndroid Build Coastguard Worker     void processFreedGpuResources();
321*c8dee2aaSAndroid Build Coastguard Worker     void addToNonpurgeableArray(GrGpuResource*);
322*c8dee2aaSAndroid Build Coastguard Worker     void removeFromNonpurgeableArray(GrGpuResource*);
323*c8dee2aaSAndroid Build Coastguard Worker 
wouldFit(size_t bytes)324*c8dee2aaSAndroid Build Coastguard Worker     bool wouldFit(size_t bytes) const { return fBudgetedBytes+bytes <= fMaxBytes; }
325*c8dee2aaSAndroid Build Coastguard Worker 
326*c8dee2aaSAndroid Build Coastguard Worker     uint32_t getNextTimestamp();
327*c8dee2aaSAndroid Build Coastguard Worker 
328*c8dee2aaSAndroid Build Coastguard Worker     void purgeUnlockedResources(const skgpu::StdSteadyClock::time_point* purgeTime,
329*c8dee2aaSAndroid Build Coastguard Worker                                 GrPurgeResourceOptions opts);
330*c8dee2aaSAndroid Build Coastguard Worker 
331*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
332*c8dee2aaSAndroid Build Coastguard Worker     bool isInCache(const GrGpuResource* r) const;
333*c8dee2aaSAndroid Build Coastguard Worker     void validate() const;
334*c8dee2aaSAndroid Build Coastguard Worker #else
validate()335*c8dee2aaSAndroid Build Coastguard Worker     void validate() const {}
336*c8dee2aaSAndroid Build Coastguard Worker #endif
337*c8dee2aaSAndroid Build Coastguard Worker 
338*c8dee2aaSAndroid Build Coastguard Worker     class AutoValidate;
339*c8dee2aaSAndroid Build Coastguard Worker 
340*c8dee2aaSAndroid Build Coastguard Worker     struct ScratchMapTraits {
GetKeyScratchMapTraits341*c8dee2aaSAndroid Build Coastguard Worker         static const skgpu::ScratchKey& GetKey(const GrGpuResource& r) {
342*c8dee2aaSAndroid Build Coastguard Worker             return r.resourcePriv().getScratchKey();
343*c8dee2aaSAndroid Build Coastguard Worker         }
344*c8dee2aaSAndroid Build Coastguard Worker 
HashScratchMapTraits345*c8dee2aaSAndroid Build Coastguard Worker         static uint32_t Hash(const skgpu::ScratchKey& key) { return key.hash(); }
OnFreeScratchMapTraits346*c8dee2aaSAndroid Build Coastguard Worker         static void OnFree(GrGpuResource*) { }
347*c8dee2aaSAndroid Build Coastguard Worker     };
348*c8dee2aaSAndroid Build Coastguard Worker     typedef SkTMultiMap<GrGpuResource, skgpu::ScratchKey, ScratchMapTraits> ScratchMap;
349*c8dee2aaSAndroid Build Coastguard Worker 
350*c8dee2aaSAndroid Build Coastguard Worker     struct UniqueHashTraits {
GetKeyUniqueHashTraits351*c8dee2aaSAndroid Build Coastguard Worker         static const skgpu::UniqueKey& GetKey(const GrGpuResource& r) { return r.getUniqueKey(); }
352*c8dee2aaSAndroid Build Coastguard Worker 
HashUniqueHashTraits353*c8dee2aaSAndroid Build Coastguard Worker         static uint32_t Hash(const skgpu::UniqueKey& key) { return key.hash(); }
354*c8dee2aaSAndroid Build Coastguard Worker     };
355*c8dee2aaSAndroid Build Coastguard Worker     typedef SkTDynamicHash<GrGpuResource, skgpu::UniqueKey, UniqueHashTraits> UniqueHash;
356*c8dee2aaSAndroid Build Coastguard Worker 
CompareTimestamp(GrGpuResource * const & a,GrGpuResource * const & b)357*c8dee2aaSAndroid Build Coastguard Worker     static bool CompareTimestamp(GrGpuResource* const& a, GrGpuResource* const& b) {
358*c8dee2aaSAndroid Build Coastguard Worker         return a->cacheAccess().timestamp() < b->cacheAccess().timestamp();
359*c8dee2aaSAndroid Build Coastguard Worker     }
360*c8dee2aaSAndroid Build Coastguard Worker 
AccessResourceIndex(GrGpuResource * const & res)361*c8dee2aaSAndroid Build Coastguard Worker     static int* AccessResourceIndex(GrGpuResource* const& res) {
362*c8dee2aaSAndroid Build Coastguard Worker         return res->cacheAccess().accessCacheIndex();
363*c8dee2aaSAndroid Build Coastguard Worker     }
364*c8dee2aaSAndroid Build Coastguard Worker 
365*c8dee2aaSAndroid Build Coastguard Worker     typedef SkMessageBus<skgpu::UniqueKeyInvalidatedMessage, uint32_t>::Inbox InvalidUniqueKeyInbox;
366*c8dee2aaSAndroid Build Coastguard Worker     typedef SkTDPQueue<GrGpuResource*, CompareTimestamp, AccessResourceIndex> PurgeableQueue;
367*c8dee2aaSAndroid Build Coastguard Worker     typedef SkTDArray<GrGpuResource*> ResourceArray;
368*c8dee2aaSAndroid Build Coastguard Worker 
369*c8dee2aaSAndroid Build Coastguard Worker     GrProxyProvider*                    fProxyProvider = nullptr;
370*c8dee2aaSAndroid Build Coastguard Worker     GrThreadSafeCache*                  fThreadSafeCache = nullptr;
371*c8dee2aaSAndroid Build Coastguard Worker 
372*c8dee2aaSAndroid Build Coastguard Worker     // Whenever a resource is added to the cache or the result of a cache lookup, fTimestamp is
373*c8dee2aaSAndroid Build Coastguard Worker     // assigned as the resource's timestamp and then incremented. fPurgeableQueue orders the
374*c8dee2aaSAndroid Build Coastguard Worker     // purgeable resources by this value, and thus is used to purge resources in LRU order.
375*c8dee2aaSAndroid Build Coastguard Worker     uint32_t                            fTimestamp = 0;
376*c8dee2aaSAndroid Build Coastguard Worker     PurgeableQueue                      fPurgeableQueue;
377*c8dee2aaSAndroid Build Coastguard Worker     ResourceArray                       fNonpurgeableResources;
378*c8dee2aaSAndroid Build Coastguard Worker 
379*c8dee2aaSAndroid Build Coastguard Worker     // This map holds all resources that can be used as scratch resources.
380*c8dee2aaSAndroid Build Coastguard Worker     ScratchMap                          fScratchMap;
381*c8dee2aaSAndroid Build Coastguard Worker     // This holds all resources that have unique keys.
382*c8dee2aaSAndroid Build Coastguard Worker     UniqueHash                          fUniqueHash;
383*c8dee2aaSAndroid Build Coastguard Worker 
384*c8dee2aaSAndroid Build Coastguard Worker     // our budget, used in purgeAsNeeded()
385*c8dee2aaSAndroid Build Coastguard Worker     size_t                              fMaxBytes = kDefaultMaxSize;
386*c8dee2aaSAndroid Build Coastguard Worker 
387*c8dee2aaSAndroid Build Coastguard Worker #if GR_CACHE_STATS
388*c8dee2aaSAndroid Build Coastguard Worker     int                                 fHighWaterCount = 0;
389*c8dee2aaSAndroid Build Coastguard Worker     size_t                              fHighWaterBytes = 0;
390*c8dee2aaSAndroid Build Coastguard Worker     int                                 fBudgetedHighWaterCount = 0;
391*c8dee2aaSAndroid Build Coastguard Worker     size_t                              fBudgetedHighWaterBytes = 0;
392*c8dee2aaSAndroid Build Coastguard Worker #endif
393*c8dee2aaSAndroid Build Coastguard Worker 
394*c8dee2aaSAndroid Build Coastguard Worker     // our current stats for all resources
395*c8dee2aaSAndroid Build Coastguard Worker     SkDEBUGCODE(int                     fCount = 0;)
396*c8dee2aaSAndroid Build Coastguard Worker     size_t                              fBytes = 0;
397*c8dee2aaSAndroid Build Coastguard Worker 
398*c8dee2aaSAndroid Build Coastguard Worker     // our current stats for resources that count against the budget
399*c8dee2aaSAndroid Build Coastguard Worker     int                                 fBudgetedCount = 0;
400*c8dee2aaSAndroid Build Coastguard Worker     size_t                              fBudgetedBytes = 0;
401*c8dee2aaSAndroid Build Coastguard Worker     size_t                              fPurgeableBytes = 0;
402*c8dee2aaSAndroid Build Coastguard Worker     int                                 fNumBudgetedResourcesFlushWillMakePurgeable = 0;
403*c8dee2aaSAndroid Build Coastguard Worker 
404*c8dee2aaSAndroid Build Coastguard Worker     InvalidUniqueKeyInbox               fInvalidUniqueKeyInbox;
405*c8dee2aaSAndroid Build Coastguard Worker     UnrefResourceMessage::Bus::Inbox    fUnrefResourceInbox;
406*c8dee2aaSAndroid Build Coastguard Worker 
407*c8dee2aaSAndroid Build Coastguard Worker     GrDirectContext::DirectContextID    fOwningContextID;
408*c8dee2aaSAndroid Build Coastguard Worker     uint32_t                            fContextUniqueID = SK_InvalidUniqueID;
409*c8dee2aaSAndroid Build Coastguard Worker     skgpu::SingleOwner*                 fSingleOwner = nullptr;
410*c8dee2aaSAndroid Build Coastguard Worker 
411*c8dee2aaSAndroid Build Coastguard Worker     // This resource is allowed to be in the nonpurgeable array for the sake of validate() because
412*c8dee2aaSAndroid Build Coastguard Worker     // we're in the midst of converting it to purgeable status.
413*c8dee2aaSAndroid Build Coastguard Worker     SkDEBUGCODE(GrGpuResource*          fNewlyPurgeableResourceForValidation = nullptr;)
414*c8dee2aaSAndroid Build Coastguard Worker };
415*c8dee2aaSAndroid Build Coastguard Worker 
416*c8dee2aaSAndroid Build Coastguard Worker class GrResourceCache::ResourceAccess {
417*c8dee2aaSAndroid Build Coastguard Worker private:
ResourceAccess(GrResourceCache * cache)418*c8dee2aaSAndroid Build Coastguard Worker     ResourceAccess(GrResourceCache* cache) : fCache(cache) { }
ResourceAccess(const ResourceAccess & that)419*c8dee2aaSAndroid Build Coastguard Worker     ResourceAccess(const ResourceAccess& that) : fCache(that.fCache) { }
420*c8dee2aaSAndroid Build Coastguard Worker     ResourceAccess& operator=(const ResourceAccess&) = delete;
421*c8dee2aaSAndroid Build Coastguard Worker 
422*c8dee2aaSAndroid Build Coastguard Worker     /**
423*c8dee2aaSAndroid Build Coastguard Worker      * Insert a resource into the cache.
424*c8dee2aaSAndroid Build Coastguard Worker      */
insertResource(GrGpuResource * resource)425*c8dee2aaSAndroid Build Coastguard Worker     void insertResource(GrGpuResource* resource) { fCache->insertResource(resource); }
426*c8dee2aaSAndroid Build Coastguard Worker 
427*c8dee2aaSAndroid Build Coastguard Worker     /**
428*c8dee2aaSAndroid Build Coastguard Worker      * Removes a resource from the cache.
429*c8dee2aaSAndroid Build Coastguard Worker      */
removeResource(GrGpuResource * resource)430*c8dee2aaSAndroid Build Coastguard Worker     void removeResource(GrGpuResource* resource) { fCache->removeResource(resource); }
431*c8dee2aaSAndroid Build Coastguard Worker 
432*c8dee2aaSAndroid Build Coastguard Worker     /**
433*c8dee2aaSAndroid Build Coastguard Worker      * Adds a ref to a resource with proper tracking if the resource has 0 refs prior to
434*c8dee2aaSAndroid Build Coastguard Worker      * adding the ref.
435*c8dee2aaSAndroid Build Coastguard Worker      */
refResource(GrGpuResource * resource)436*c8dee2aaSAndroid Build Coastguard Worker     void refResource(GrGpuResource* resource) { fCache->refResource(resource); }
437*c8dee2aaSAndroid Build Coastguard Worker 
438*c8dee2aaSAndroid Build Coastguard Worker     /**
439*c8dee2aaSAndroid Build Coastguard Worker      * Notifications that should be sent to the cache when the ref/io cnt status of resources
440*c8dee2aaSAndroid Build Coastguard Worker      * changes.
441*c8dee2aaSAndroid Build Coastguard Worker      */
442*c8dee2aaSAndroid Build Coastguard Worker     enum RefNotificationFlags {
443*c8dee2aaSAndroid Build Coastguard Worker         /** All types of refs on the resource have reached zero. */
444*c8dee2aaSAndroid Build Coastguard Worker         kAllCntsReachedZero_RefNotificationFlag = 0x1,
445*c8dee2aaSAndroid Build Coastguard Worker         /** The normal (not pending IO type) ref cnt has reached zero. */
446*c8dee2aaSAndroid Build Coastguard Worker         kRefCntReachedZero_RefNotificationFlag  = 0x2,
447*c8dee2aaSAndroid Build Coastguard Worker     };
448*c8dee2aaSAndroid Build Coastguard Worker     /**
449*c8dee2aaSAndroid Build Coastguard Worker      * Called by GrGpuResources when they detect one of their ref cnts have reached zero. This may
450*c8dee2aaSAndroid Build Coastguard Worker      * either be the main ref or the command buffer usage ref.
451*c8dee2aaSAndroid Build Coastguard Worker      */
notifyARefCntReachedZero(GrGpuResource * resource,GrGpuResource::LastRemovedRef removedRef)452*c8dee2aaSAndroid Build Coastguard Worker     void notifyARefCntReachedZero(GrGpuResource* resource,
453*c8dee2aaSAndroid Build Coastguard Worker                                   GrGpuResource::LastRemovedRef removedRef) {
454*c8dee2aaSAndroid Build Coastguard Worker         fCache->notifyARefCntReachedZero(resource, removedRef);
455*c8dee2aaSAndroid Build Coastguard Worker     }
456*c8dee2aaSAndroid Build Coastguard Worker 
457*c8dee2aaSAndroid Build Coastguard Worker     /**
458*c8dee2aaSAndroid Build Coastguard Worker      * Called by GrGpuResources to change their unique keys.
459*c8dee2aaSAndroid Build Coastguard Worker      */
changeUniqueKey(GrGpuResource * resource,const skgpu::UniqueKey & newKey)460*c8dee2aaSAndroid Build Coastguard Worker     void changeUniqueKey(GrGpuResource* resource, const skgpu::UniqueKey& newKey) {
461*c8dee2aaSAndroid Build Coastguard Worker          fCache->changeUniqueKey(resource, newKey);
462*c8dee2aaSAndroid Build Coastguard Worker     }
463*c8dee2aaSAndroid Build Coastguard Worker 
464*c8dee2aaSAndroid Build Coastguard Worker     /**
465*c8dee2aaSAndroid Build Coastguard Worker      * Called by a GrGpuResource to remove its unique key.
466*c8dee2aaSAndroid Build Coastguard Worker      */
removeUniqueKey(GrGpuResource * resource)467*c8dee2aaSAndroid Build Coastguard Worker     void removeUniqueKey(GrGpuResource* resource) { fCache->removeUniqueKey(resource); }
468*c8dee2aaSAndroid Build Coastguard Worker 
469*c8dee2aaSAndroid Build Coastguard Worker     /**
470*c8dee2aaSAndroid Build Coastguard Worker      * Called by a GrGpuResource when it removes its scratch key.
471*c8dee2aaSAndroid Build Coastguard Worker      */
willRemoveScratchKey(const GrGpuResource * resource)472*c8dee2aaSAndroid Build Coastguard Worker     void willRemoveScratchKey(const GrGpuResource* resource) {
473*c8dee2aaSAndroid Build Coastguard Worker         fCache->willRemoveScratchKey(resource);
474*c8dee2aaSAndroid Build Coastguard Worker     }
475*c8dee2aaSAndroid Build Coastguard Worker 
476*c8dee2aaSAndroid Build Coastguard Worker     /**
477*c8dee2aaSAndroid Build Coastguard Worker      * Called by GrGpuResources when they change from budgeted to unbudgeted or vice versa.
478*c8dee2aaSAndroid Build Coastguard Worker      */
didChangeBudgetStatus(GrGpuResource * resource)479*c8dee2aaSAndroid Build Coastguard Worker     void didChangeBudgetStatus(GrGpuResource* resource) { fCache->didChangeBudgetStatus(resource); }
480*c8dee2aaSAndroid Build Coastguard Worker 
481*c8dee2aaSAndroid Build Coastguard Worker     // No taking addresses of this type.
482*c8dee2aaSAndroid Build Coastguard Worker     const ResourceAccess* operator&() const;
483*c8dee2aaSAndroid Build Coastguard Worker     ResourceAccess* operator&();
484*c8dee2aaSAndroid Build Coastguard Worker 
485*c8dee2aaSAndroid Build Coastguard Worker     GrResourceCache* fCache;
486*c8dee2aaSAndroid Build Coastguard Worker 
487*c8dee2aaSAndroid Build Coastguard Worker     friend class GrGpuResource; // To access all the proxy inline methods.
488*c8dee2aaSAndroid Build Coastguard Worker     friend class GrResourceCache; // To create this type.
489*c8dee2aaSAndroid Build Coastguard Worker };
490*c8dee2aaSAndroid Build Coastguard Worker 
SkShouldPostMessageToBus(const GrResourceCache::UnrefResourceMessage & msg,GrDirectContext::DirectContextID potentialRecipient)491*c8dee2aaSAndroid Build Coastguard Worker static inline bool SkShouldPostMessageToBus(const GrResourceCache::UnrefResourceMessage& msg,
492*c8dee2aaSAndroid Build Coastguard Worker                                             GrDirectContext::DirectContextID potentialRecipient) {
493*c8dee2aaSAndroid Build Coastguard Worker     return potentialRecipient == msg.recipient();
494*c8dee2aaSAndroid Build Coastguard Worker }
495*c8dee2aaSAndroid Build Coastguard Worker 
resourceAccess()496*c8dee2aaSAndroid Build Coastguard Worker inline GrResourceCache::ResourceAccess GrResourceCache::resourceAccess() {
497*c8dee2aaSAndroid Build Coastguard Worker     return ResourceAccess(this);
498*c8dee2aaSAndroid Build Coastguard Worker }
499*c8dee2aaSAndroid Build Coastguard Worker 
500*c8dee2aaSAndroid Build Coastguard Worker #endif
501