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