Flutter Engine
The Flutter Engine
ResourceCache.h
Go to the documentation of this file.
1/*
2 * Copyright 2022 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef skgpu_graphite_ResourceCache_DEFINED
9#define skgpu_graphite_ResourceCache_DEFINED
10
14#include "src/base/SkTDPQueue.h"
15#include "src/core/SkTHash.h"
19
20#if defined(GRAPHITE_TEST_UTILS)
21#include <functional>
22#endif
23#include <vector>
24
26
27namespace skgpu {
28class SingleOwner;
29}
30
31namespace skgpu::graphite {
32
33class GraphiteResourceKey;
34class ProxyCache;
35class Resource;
36
37#if defined(GRAPHITE_TEST_UTILS)
38class Texture;
39#endif
40
41class ResourceCache : public SkRefCnt {
42public:
43 static sk_sp<ResourceCache> Make(SingleOwner*, uint32_t recorderID, size_t maxBytes);
44 ~ResourceCache() override;
45
46 ResourceCache(const ResourceCache&) = delete;
50
51 // Returns the number of resources.
52 int getResourceCount() const {
53 return fPurgeableQueue.count() + fNonpurgeableResources.size();
54 }
55
57
58 // Find a resource that matches a key.
60
61 // This is a thread safe call. If it fails the ResourceCache is no longer valid and the
62 // Resource should clean itself up if it is the last ref.
64
65 // Purge resources not used since the passed point in time. Resources that have a gpu memory
66 // size of zero will not be purged.
67 // TODO: Should we add an optional flag to also allow purging of zero sized resources? Would we
68 // want to be able to differentiate between things like Pipelines (probably never want to purge)
69 // and things like descriptor sets.
70 void purgeResourcesNotUsedSince(StdSteadyClock::time_point purgeTime);
71
72 // Purge any unlocked resources. Resources that have a gpu memory size of zero will not be
73 // purged.
74 void purgeResources();
75
76 // Called by the ResourceProvider when it is dropping its ref to the ResourceCache. After this
77 // is called no more Resources can be returned to the ResourceCache (besides those already in
78 // the return queue). Also no new Resources can be retrieved from the ResourceCache.
79 void shutdown();
80
81 size_t getMaxBudget() const { return fMaxBytes; }
82
83 size_t currentBudgetedBytes() const { return fBudgetedBytes; }
84
85 void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const;
86
87#if defined(GRAPHITE_TEST_UTILS)
88 void forceProcessReturnedResources() { this->processReturnedResources(); }
89
90 void forcePurgeAsNeeded() { this->purgeAsNeeded(); }
91
92 // Returns the numbers of Resources that can currently be found in the cache. This includes all
93 // shared Resources and all non-shareable resources that have been returned to the cache.
94 int numFindableResources() const;
95
96 // This will probably end up being a public function to change the current budget size, but for
97 // now just making this a testing only function.
98 void setMaxBudget(size_t bytes);
99
100 Resource* topOfPurgeableQueue();
101
102 bool testingInPurgeableQueue(Resource* resource) { return this->inPurgeableQueue(resource); }
103
104 void visitTextures(const std::function<void(const Texture*, bool purgeable)>&) const;
105#endif
106
107 ProxyCache* proxyCache() { return fProxyCache.get(); }
108
109private:
110 ResourceCache(SingleOwner*, uint32_t recorderID, size_t maxBytes);
111
112 // All these private functions are not meant to be thread safe. We don't check for is single
113 // owner in them as we assume that has already been checked by the public api calls.
114 void refAndMakeResourceMRU(Resource*);
115 void addToNonpurgeableArray(Resource* resource);
116 void removeFromNonpurgeableArray(Resource* resource);
117 void removeFromPurgeableQueue(Resource* resource);
118
119 // This will return true if any resources were actually returned to the cache
120 bool processReturnedResources();
121 void returnResourceToCache(Resource*, LastRemovedRef);
122
123 uint32_t getNextTimestamp();
124 void setResourceTimestamp(Resource*, uint32_t timestamp);
125
126 bool inPurgeableQueue(Resource*) const;
127
128 bool overbudget() const { return fBudgetedBytes > fMaxBytes; }
129 void purgeAsNeeded();
130 void purgeResource(Resource*);
131 // Passing in a nullptr for purgeTime will trigger us to try and free all unlocked resources.
132 void purgeResources(const StdSteadyClock::time_point* purgeTime);
133
134#ifdef SK_DEBUG
135 bool isInCache(const Resource* r) const;
136 void validate() const;
137#else
138 void validate() const {}
139#endif
140
141 struct MapTraits {
142 static const GraphiteResourceKey& GetKey(const Resource& r);
143
144 static uint32_t Hash(const GraphiteResourceKey& key);
145 static void OnFree(Resource*) {}
146 };
148
149 static bool CompareTimestamp(Resource* const& a, Resource* const& b);
150 static int* AccessResourceIndex(Resource* const& res);
151
153 using ResourceArray = SkTDArray<Resource*>;
154
155 // Whenever a resource is added to the cache or the result of a cache lookup, fTimestamp is
156 // assigned as the resource's timestamp and then incremented. fPurgeableQueue orders the
157 // purgeable resources by this value, and thus is used to purge resources in LRU order.
158 // Resources with a size of zero are set to have max uint32_t value. This will also put them at
159 // the end of the LRU priority queue. This will allow us to not purge these resources even when
160 // we are over budget.
161 uint32_t fTimestamp = 0;
162 static const uint32_t kMaxTimestamp = 0xFFFFFFFF;
163
164 PurgeableQueue fPurgeableQueue;
165 ResourceArray fNonpurgeableResources;
166 std::unique_ptr<ProxyCache> fProxyCache;
167
168 SkDEBUGCODE(int fCount = 0;)
169
170 ResourceMap fResourceMap;
171
172 // Our budget
173 size_t fMaxBytes;
174 size_t fBudgetedBytes = 0;
175
176 SingleOwner* fSingleOwner = nullptr;
177
178 bool fIsShutdown = false;
179
180 SkMutex fReturnMutex;
181 using ReturnQueue = std::vector<std::pair<Resource*, LastRemovedRef>>;
182 ReturnQueue fReturnQueue SK_GUARDED_BY(fReturnMutex);
183};
184
185} // namespace skgpu::graphite
186
187#endif // skgpu_graphite_ResourceCache_DEFINED
static SkString resource(SkPDFResourceType type, int index)
int size() const
Definition: SkTDArray.h:138
int count() const
Definition: SkTDPQueue.h:45
bool returnResource(Resource *, LastRemovedRef)
ResourceCache(const ResourceCache &)=delete
size_t currentBudgetedBytes() const
Definition: ResourceCache.h:83
ResourceCache & operator=(ResourceCache &&)=delete
void purgeResourcesNotUsedSince(StdSteadyClock::time_point purgeTime)
static sk_sp< ResourceCache > Make(SingleOwner *, uint32_t recorderID, size_t maxBytes)
void dumpMemoryStatistics(SkTraceMemoryDump *traceMemoryDump) const
ResourceCache(ResourceCache &&)=delete
Resource * findAndRefResource(const GraphiteResourceKey &key, skgpu::Budgeted)
ResourceCache & operator=(const ResourceCache &)=delete
static bool b
struct MyStruct a[10]
Dart_NativeFunction function
Definition: fuchsia.cc:51
static uint32_t Hash(uint32_t key)
Definition: hashmap_test.cc:65
Definition: GpuTools.h:21
Budgeted
Definition: GpuTypes.h:35