xref: /aosp_15_r20/external/skia/src/gpu/graphite/ProxyCache.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2023 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 #include "src/gpu/graphite/ProxyCache.h"
9 
10 #include "include/core/SkBitmap.h"
11 #include "include/core/SkPixelRef.h"
12 #include "include/gpu/GpuTypes.h"
13 #include "src/core/SkMipmap.h"
14 #include "src/gpu/ResourceKey.h"
15 #include "src/gpu/graphite/RecorderPriv.h"
16 #include "src/gpu/graphite/Texture.h"
17 #include "src/gpu/graphite/TextureProxy.h"
18 #include "src/gpu/graphite/TextureUtils.h"
19 
20 using namespace skia_private;
21 
22 DECLARE_SKMESSAGEBUS_MESSAGE(skgpu::UniqueKeyInvalidatedMsg_Graphite, uint32_t,
23                              /* AllowCopyableMessage= */ true)
24 
25 namespace {
26 
make_bitmap_key(skgpu::UniqueKey * key,const SkBitmap & bm)27 void make_bitmap_key(skgpu::UniqueKey* key, const SkBitmap& bm) {
28     SkASSERT(key);
29 
30     SkIPoint origin = bm.pixelRefOrigin();
31     SkIRect subset = SkIRect::MakePtSize(origin, bm.dimensions());
32 
33     static const skgpu::UniqueKey::Domain kProxyCacheDomain = skgpu::UniqueKey::GenerateDomain();
34     skgpu::UniqueKey::Builder builder(key, kProxyCacheDomain, 5, "ProxyCache");
35     builder[0] = bm.pixelRef()->getGenerationID();
36     builder[1] = subset.fLeft;
37     builder[2] = subset.fTop;
38     builder[3] = subset.fRight;
39     builder[4] = subset.fBottom;
40 }
41 
make_unique_key_invalidation_listener(const skgpu::UniqueKey & key,uint32_t recorderID)42 sk_sp<SkIDChangeListener> make_unique_key_invalidation_listener(const skgpu::UniqueKey& key,
43                                                                 uint32_t recorderID) {
44     class Listener : public SkIDChangeListener {
45     public:
46         Listener(const skgpu::UniqueKey& key, uint32_t recorderUniqueID)
47                 : fMsg(key, recorderUniqueID) {}
48 
49         void changed() override {
50             SkMessageBus<skgpu::UniqueKeyInvalidatedMsg_Graphite, uint32_t>::Post(fMsg);
51         }
52 
53     private:
54         skgpu::UniqueKeyInvalidatedMsg_Graphite fMsg;
55     };
56 
57     return sk_make_sp<Listener>(key, recorderID);
58 }
59 
60 } // anonymous namespace
61 
62 namespace skgpu::graphite {
63 
ProxyCache(uint32_t recorderID)64 ProxyCache::ProxyCache(uint32_t recorderID) : fInvalidUniqueKeyInbox(recorderID) {
65     SkASSERT(recorderID != SK_InvalidGenID);
66 }
67 
~ProxyCache()68 ProxyCache::~ProxyCache() {}
69 
operator ()(const UniqueKey & key) const70 uint32_t ProxyCache::UniqueKeyHash::operator()(const UniqueKey& key) const {
71     return key.hash();
72 }
73 
findOrCreateCachedProxy(Recorder * recorder,const SkBitmap & bitmap,std::string_view label)74 sk_sp<TextureProxy> ProxyCache::findOrCreateCachedProxy(Recorder* recorder,
75                                                         const SkBitmap& bitmap,
76                                                         std::string_view label) {
77 
78     skgpu::UniqueKey key;
79     make_bitmap_key(&key, bitmap);
80     return this->findOrCreateCachedProxy(
81             recorder, key, &bitmap,
82             [](const void* context) { return *static_cast<const SkBitmap*>(context); },
83             label);
84 }
85 
findOrCreateCachedProxy(Recorder * recorder,const UniqueKey & key,BitmapGeneratorContext context,BitmapGeneratorFn generator,std::string_view label)86 sk_sp<TextureProxy> ProxyCache::findOrCreateCachedProxy(Recorder* recorder,
87                                                         const UniqueKey& key,
88                                                         BitmapGeneratorContext context,
89                                                         BitmapGeneratorFn generator,
90                                                         std::string_view label) {
91     this->processInvalidKeyMsgs();
92 
93     if (sk_sp<TextureProxy>* cached = fCache.find(key)) {
94         if (Resource* resource = (*cached)->texture()) {
95             resource->updateAccessTime();
96         }
97         return *cached;
98     }
99 
100     SkBitmap bitmap = generator(context);
101     if (bitmap.empty()) {
102         return nullptr;
103     }
104     auto [ view, ct ] = MakeBitmapProxyView(recorder, bitmap, nullptr, Mipmapped::kNo,
105                                             Budgeted::kYes, label.empty() ? key.tag() : label);
106     if (view) {
107         // Since if the bitmap is held by more than just this function call (e.g. it likely came
108         // from findOrCreateCachedProxy() that takes an existing SkBitmap), it's worth adding a
109         // listener to remove them from the cache automatically when no one holds on to it anymore.
110         // Skip adding a listener for immutable bitmaps since those should never be invalidated.
111         const bool addListener = !bitmap.isImmutable() && !bitmap.pixelRef()->unique();
112         if (addListener) {
113             auto listener = make_unique_key_invalidation_listener(key, recorder->priv().uniqueID());
114             bitmap.pixelRef()->addGenIDChangeListener(std::move(listener));
115         }
116         fCache.set(key, view.refProxy());
117     }
118     return view.refProxy();
119 }
120 
purgeAll()121 void ProxyCache::purgeAll() {
122     fCache.reset();
123 }
124 
processInvalidKeyMsgs()125 void ProxyCache::processInvalidKeyMsgs() {
126     TArray<skgpu::UniqueKeyInvalidatedMsg_Graphite> invalidKeyMsgs;
127     fInvalidUniqueKeyInbox.poll(&invalidKeyMsgs);
128 
129     if (!invalidKeyMsgs.empty()) {
130         for (int i = 0; i < invalidKeyMsgs.size(); ++i) {
131             // TODO: this should stop crbug.com/1480570 for now but more investigation needs to be
132             // done into how we're getting into the situation where an invalid key has been
133             // purged from the cache prior to processing of the invalid key messages.
134             if (fCache.find(invalidKeyMsgs[i].key())) {
135                 fCache.remove(invalidKeyMsgs[i].key());
136             }
137         }
138     }
139 }
140 
freeUniquelyHeld()141 void ProxyCache::freeUniquelyHeld() {
142     this->processInvalidKeyMsgs();
143 
144     std::vector<skgpu::UniqueKey> toRemove;
145 
146     fCache.foreach([&](const skgpu::UniqueKey& key, const sk_sp<TextureProxy>* proxy) {
147         if ((*proxy)->unique()) {
148             toRemove.push_back(key);
149         }
150     });
151 
152     for (const skgpu::UniqueKey& k : toRemove) {
153         fCache.remove(k);
154     }
155 }
156 
purgeProxiesNotUsedSince(const skgpu::StdSteadyClock::time_point * purgeTime)157 void ProxyCache::purgeProxiesNotUsedSince(const skgpu::StdSteadyClock::time_point* purgeTime) {
158     this->processInvalidKeyMsgs();
159 
160     std::vector<skgpu::UniqueKey> toRemove;
161 
162     fCache.foreach([&](const skgpu::UniqueKey& key, const sk_sp<TextureProxy>* proxy) {
163         if (Resource* resource = (*proxy)->texture();
164             resource &&
165             (!purgeTime || resource->lastAccessTime() < *purgeTime)) {
166             toRemove.push_back(key);
167         }
168     });
169 
170     for (const skgpu::UniqueKey& k : toRemove) {
171         fCache.remove(k);
172     }
173 }
174 
175 #if defined(GPU_TEST_UTILS)
numCached() const176 int ProxyCache::numCached() const {
177     return fCache.count();
178 }
179 
find(const SkBitmap & bitmap)180 sk_sp<TextureProxy> ProxyCache::find(const SkBitmap& bitmap) {
181 
182     skgpu::UniqueKey key;
183 
184     make_bitmap_key(&key, bitmap);
185 
186     if (sk_sp<TextureProxy>* cached = fCache.find(key)) {
187         return *cached;
188     }
189 
190     return nullptr;
191 }
192 
forceProcessInvalidKeyMsgs()193 void ProxyCache::forceProcessInvalidKeyMsgs() {
194     this->processInvalidKeyMsgs();
195 }
196 
forceFreeUniquelyHeld()197 void ProxyCache::forceFreeUniquelyHeld() {
198     this->freeUniquelyHeld();
199 }
200 
forcePurgeProxiesNotUsedSince(skgpu::StdSteadyClock::time_point purgeTime)201 void ProxyCache::forcePurgeProxiesNotUsedSince(skgpu::StdSteadyClock::time_point purgeTime) {
202     this->purgeProxiesNotUsedSince(&purgeTime);
203 }
204 
205 #endif // defined(GPU_TEST_UTILS)
206 
207 } // namespace skgpu::graphite
208