• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2020 Google Inc.
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/GrThreadSafeCache.h"
9 
10 #include "include/gpu/GrDirectContext.h"
11 #include "src/gpu/GrDirectContextPriv.h"
12 #include "src/gpu/GrGpuBuffer.h"
13 #include "src/gpu/GrProxyProvider.h"
14 #include "src/gpu/GrResourceCache.h"
15 
~VertexData()16 GrThreadSafeCache::VertexData::~VertexData () {
17     this->reset();
18 }
19 
GrThreadSafeCache()20 GrThreadSafeCache::GrThreadSafeCache()
21     : fFreeEntryList(nullptr) {
22 }
23 
~GrThreadSafeCache()24 GrThreadSafeCache::~GrThreadSafeCache() {
25     this->dropAllRefs();
26 }
27 
28 #if GR_TEST_UTILS
numEntries() const29 int GrThreadSafeCache::numEntries() const {
30     SkAutoSpinlock lock{fSpinLock};
31 
32     return fUniquelyKeyedEntryMap.count();
33 }
34 
approxBytesUsedForHash() const35 size_t GrThreadSafeCache::approxBytesUsedForHash() const {
36     SkAutoSpinlock lock{fSpinLock};
37 
38     return fUniquelyKeyedEntryMap.approxBytesUsed();
39 }
40 #endif
41 
dropAllRefs()42 void GrThreadSafeCache::dropAllRefs() {
43     SkAutoSpinlock lock{fSpinLock};
44 
45     fUniquelyKeyedEntryMap.reset();
46     while (auto tmp = fUniquelyKeyedEntryList.head()) {
47         fUniquelyKeyedEntryList.remove(tmp);
48         this->recycleEntry(tmp);
49     }
50     // TODO: should we empty out the fFreeEntryList and reset fEntryAllocator?
51 }
52 
53 // TODO: If iterating becomes too expensive switch to using something like GrIORef for the
54 // GrSurfaceProxy
dropUniqueRefs(GrResourceCache * resourceCache)55 void GrThreadSafeCache::dropUniqueRefs(GrResourceCache* resourceCache) {
56     SkAutoSpinlock lock{fSpinLock};
57 
58     // Iterate from LRU to MRU
59     Entry* cur = fUniquelyKeyedEntryList.tail();
60     Entry* prev = cur ? cur->fPrev : nullptr;
61 
62     while (cur) {
63         if (resourceCache && !resourceCache->overBudget()) {
64             return;
65         }
66 
67         if (cur->uniquelyHeld()) {
68             fUniquelyKeyedEntryMap.remove(cur->key());
69             fUniquelyKeyedEntryList.remove(cur);
70             this->recycleEntry(cur);
71         }
72 
73         cur = prev;
74         prev = cur ? cur->fPrev : nullptr;
75     }
76 }
77 
dropUniqueRefsOlderThan(GrStdSteadyClock::time_point purgeTime)78 void GrThreadSafeCache::dropUniqueRefsOlderThan(GrStdSteadyClock::time_point purgeTime) {
79     SkAutoSpinlock lock{fSpinLock};
80 
81     // Iterate from LRU to MRU
82     Entry* cur = fUniquelyKeyedEntryList.tail();
83     Entry* prev = cur ? cur->fPrev : nullptr;
84 
85     while (cur) {
86         if (cur->fLastAccess >= purgeTime) {
87             // This entry and all the remaining ones in the list will be newer than 'purgeTime'
88             return;
89         }
90 
91         if (cur->uniquelyHeld()) {
92             fUniquelyKeyedEntryMap.remove(cur->key());
93             fUniquelyKeyedEntryList.remove(cur);
94             this->recycleEntry(cur);
95         }
96 
97         cur = prev;
98         prev = cur ? cur->fPrev : nullptr;
99     }
100 }
101 
makeExistingEntryMRU(Entry * entry)102 void GrThreadSafeCache::makeExistingEntryMRU(Entry* entry) {
103     SkASSERT(fUniquelyKeyedEntryList.isInList(entry));
104 
105     entry->fLastAccess = GrStdSteadyClock::now();
106     fUniquelyKeyedEntryList.remove(entry);
107     fUniquelyKeyedEntryList.addToHead(entry);
108 }
109 
internalFind(const GrUniqueKey & key)110 std::tuple<GrSurfaceProxyView, sk_sp<SkData>> GrThreadSafeCache::internalFind(
111                                                        const GrUniqueKey& key) {
112     Entry* tmp = fUniquelyKeyedEntryMap.find(key);
113     if (tmp) {
114         this->makeExistingEntryMRU(tmp);
115         return { tmp->view(), tmp->refCustomData() };
116     }
117 
118     return {};
119 }
120 
121 #ifdef SK_DEBUG
has(const GrUniqueKey & key)122 bool GrThreadSafeCache::has(const GrUniqueKey& key) {
123     SkAutoSpinlock lock{fSpinLock};
124 
125     Entry* tmp = fUniquelyKeyedEntryMap.find(key);
126     return SkToBool(tmp);
127 }
128 #endif
129 
find(const GrUniqueKey & key)130 GrSurfaceProxyView GrThreadSafeCache::find(const GrUniqueKey& key) {
131     SkAutoSpinlock lock{fSpinLock};
132 
133     GrSurfaceProxyView view;
134     std::tie(view, std::ignore) = this->internalFind(key);
135     return view;
136 }
137 
findWithData(const GrUniqueKey & key)138 std::tuple<GrSurfaceProxyView, sk_sp<SkData>> GrThreadSafeCache::findWithData(
139                                                                         const GrUniqueKey& key) {
140     SkAutoSpinlock lock{fSpinLock};
141 
142     return this->internalFind(key);
143 }
144 
getEntry(const GrUniqueKey & key,const GrSurfaceProxyView & view)145 GrThreadSafeCache::Entry* GrThreadSafeCache::getEntry(const GrUniqueKey& key,
146                                                       const GrSurfaceProxyView& view) {
147     Entry* entry;
148 
149     if (fFreeEntryList) {
150         entry = fFreeEntryList;
151         fFreeEntryList = entry->fNext;
152         entry->fNext = nullptr;
153 
154         entry->set(key, view);
155     } else {
156         entry = fEntryAllocator.make<Entry>(key, view);
157     }
158 
159     return this->makeNewEntryMRU(entry);
160 }
161 
makeNewEntryMRU(Entry * entry)162 GrThreadSafeCache::Entry* GrThreadSafeCache::makeNewEntryMRU(Entry* entry) {
163     entry->fLastAccess = GrStdSteadyClock::now();
164     fUniquelyKeyedEntryList.addToHead(entry);
165     fUniquelyKeyedEntryMap.add(entry);
166     return entry;
167 }
168 
getEntry(const GrUniqueKey & key,sk_sp<VertexData> vertData)169 GrThreadSafeCache::Entry* GrThreadSafeCache::getEntry(const GrUniqueKey& key,
170                                                       sk_sp<VertexData> vertData) {
171     Entry* entry;
172 
173     if (fFreeEntryList) {
174         entry = fFreeEntryList;
175         fFreeEntryList = entry->fNext;
176         entry->fNext = nullptr;
177 
178         entry->set(key, std::move(vertData));
179     } else {
180         entry = fEntryAllocator.make<Entry>(key, std::move(vertData));
181     }
182 
183     return this->makeNewEntryMRU(entry);
184 }
185 
recycleEntry(Entry * dead)186 void GrThreadSafeCache::recycleEntry(Entry* dead) {
187     SkASSERT(!dead->fPrev && !dead->fNext && !dead->fList);
188 
189     dead->makeEmpty();
190 
191     dead->fNext = fFreeEntryList;
192     fFreeEntryList = dead;
193 }
194 
internalAdd(const GrUniqueKey & key,const GrSurfaceProxyView & view)195 std::tuple<GrSurfaceProxyView, sk_sp<SkData>> GrThreadSafeCache::internalAdd(
196                                                                 const GrUniqueKey& key,
197                                                                 const GrSurfaceProxyView& view) {
198     Entry* tmp = fUniquelyKeyedEntryMap.find(key);
199     if (!tmp) {
200         tmp = this->getEntry(key, view);
201 
202         SkASSERT(fUniquelyKeyedEntryMap.find(key));
203     }
204 
205     return { tmp->view(), tmp->refCustomData() };
206 }
207 
add(const GrUniqueKey & key,const GrSurfaceProxyView & view)208 GrSurfaceProxyView GrThreadSafeCache::add(const GrUniqueKey& key, const GrSurfaceProxyView& view) {
209     SkAutoSpinlock lock{fSpinLock};
210 
211     GrSurfaceProxyView newView;
212     std::tie(newView, std::ignore) = this->internalAdd(key, view);
213     return newView;
214 }
215 
addWithData(const GrUniqueKey & key,const GrSurfaceProxyView & view)216 std::tuple<GrSurfaceProxyView, sk_sp<SkData>> GrThreadSafeCache::addWithData(
217                                                                 const GrUniqueKey& key,
218                                                                 const GrSurfaceProxyView& view) {
219     SkAutoSpinlock lock{fSpinLock};
220 
221     return this->internalAdd(key, view);
222 }
223 
findOrAdd(const GrUniqueKey & key,const GrSurfaceProxyView & v)224 GrSurfaceProxyView GrThreadSafeCache::findOrAdd(const GrUniqueKey& key,
225                                                 const GrSurfaceProxyView& v) {
226     SkAutoSpinlock lock{fSpinLock};
227 
228     GrSurfaceProxyView view;
229     std::tie(view, std::ignore) = this->internalFind(key);
230     if (view) {
231         return view;
232     }
233 
234     std::tie(view, std::ignore) = this->internalAdd(key, v);
235     return view;
236 }
237 
findOrAddWithData(const GrUniqueKey & key,const GrSurfaceProxyView & v)238 std::tuple<GrSurfaceProxyView, sk_sp<SkData>> GrThreadSafeCache::findOrAddWithData(
239                                                                       const GrUniqueKey& key,
240                                                                       const GrSurfaceProxyView& v) {
241     SkAutoSpinlock lock{fSpinLock};
242 
243     auto [view, data] = this->internalFind(key);
244     if (view) {
245         return { std::move(view), std::move(data) };
246     }
247 
248     return this->internalAdd(key, v);
249 }
250 
MakeVertexData(const void * vertices,int vertexCount,size_t vertexSize)251 sk_sp<GrThreadSafeCache::VertexData> GrThreadSafeCache::MakeVertexData(const void* vertices,
252                                                                        int vertexCount,
253                                                                        size_t vertexSize) {
254     return sk_sp<VertexData>(new VertexData(vertices, vertexCount, vertexSize));
255 }
256 
MakeVertexData(sk_sp<GrGpuBuffer> buffer,int vertexCount,size_t vertexSize)257 sk_sp<GrThreadSafeCache::VertexData> GrThreadSafeCache::MakeVertexData(sk_sp<GrGpuBuffer> buffer,
258                                                                        int vertexCount,
259                                                                        size_t vertexSize) {
260     return sk_sp<VertexData>(new VertexData(std::move(buffer), vertexCount, vertexSize));
261 }
262 
internalFindVerts(const GrUniqueKey & key)263 std::tuple<sk_sp<GrThreadSafeCache::VertexData>, sk_sp<SkData>> GrThreadSafeCache::internalFindVerts(
264                                                                          const GrUniqueKey& key) {
265     Entry* tmp = fUniquelyKeyedEntryMap.find(key);
266     if (tmp) {
267         this->makeExistingEntryMRU(tmp);
268         return { tmp->vertexData(), tmp->refCustomData() };
269     }
270 
271     return {};
272 }
273 
findVertsWithData(const GrUniqueKey & key)274 std::tuple<sk_sp<GrThreadSafeCache::VertexData>, sk_sp<SkData>> GrThreadSafeCache::findVertsWithData(
275                                                                           const GrUniqueKey& key) {
276     SkAutoSpinlock lock{fSpinLock};
277 
278     return this->internalFindVerts(key);
279 }
280 
internalAddVerts(const GrUniqueKey & key,sk_sp<VertexData> vertData,IsNewerBetter isNewerBetter)281 std::tuple<sk_sp<GrThreadSafeCache::VertexData>, sk_sp<SkData>> GrThreadSafeCache::internalAddVerts(
282                                                                     const GrUniqueKey& key,
283                                                                     sk_sp<VertexData> vertData,
284                                                                     IsNewerBetter isNewerBetter) {
285     Entry* tmp = fUniquelyKeyedEntryMap.find(key);
286     if (!tmp) {
287         tmp = this->getEntry(key, std::move(vertData));
288 
289         SkASSERT(fUniquelyKeyedEntryMap.find(key));
290     } else if (isNewerBetter(tmp->getCustomData(), key.getCustomData())) {
291         // This orphans any existing uses of the prior vertex data but ensures the best
292         // version is in the cache.
293         tmp->set(key, std::move(vertData));
294     }
295 
296     return { tmp->vertexData(), tmp->refCustomData() };
297 }
298 
addVertsWithData(const GrUniqueKey & key,sk_sp<VertexData> vertData,IsNewerBetter isNewerBetter)299 std::tuple<sk_sp<GrThreadSafeCache::VertexData>, sk_sp<SkData>> GrThreadSafeCache::addVertsWithData(
300                                                                     const GrUniqueKey& key,
301                                                                     sk_sp<VertexData> vertData,
302                                                                     IsNewerBetter isNewerBetter) {
303     SkAutoSpinlock lock{fSpinLock};
304 
305     return this->internalAddVerts(key, std::move(vertData), isNewerBetter);
306 }
307 
remove(const GrUniqueKey & key)308 void GrThreadSafeCache::remove(const GrUniqueKey& key) {
309     SkAutoSpinlock lock{fSpinLock};
310 
311     Entry* tmp = fUniquelyKeyedEntryMap.find(key);
312     if (tmp) {
313         fUniquelyKeyedEntryMap.remove(key);
314         fUniquelyKeyedEntryList.remove(tmp);
315         this->recycleEntry(tmp);
316     }
317 }
318 
319 std::tuple<GrSurfaceProxyView, sk_sp<GrThreadSafeCache::Trampoline>>
CreateLazyView(GrDirectContext * dContext,GrColorType origCT,SkISize dimensions,GrSurfaceOrigin origin,SkBackingFit fit)320 GrThreadSafeCache::CreateLazyView(GrDirectContext* dContext,
321                                   GrColorType origCT,
322                                   SkISize dimensions,
323                                   GrSurfaceOrigin origin,
324                                   SkBackingFit fit) {
325     GrProxyProvider* proxyProvider = dContext->priv().proxyProvider();
326     const GrCaps* caps = dContext->priv().caps();
327 
328     constexpr int kSampleCnt = 1;
329     auto [newCT, format] = caps->getFallbackColorTypeAndFormat(origCT, kSampleCnt);
330 
331     if (newCT == GrColorType::kUnknown) {
332         return {GrSurfaceProxyView(nullptr), nullptr};
333     }
334 
335     sk_sp<Trampoline> trampoline(new Trampoline);
336 
337     GrProxyProvider::TextureInfo texInfo{ GrMipMapped::kNo, GrTextureType::k2D };
338 
339     sk_sp<GrRenderTargetProxy> proxy = proxyProvider->createLazyRenderTargetProxy(
340             [trampoline](
341                     GrResourceProvider* resourceProvider,
342                     const GrSurfaceProxy::LazySurfaceDesc&) -> GrSurfaceProxy::LazyCallbackResult {
343                 if (!resourceProvider || !trampoline->fProxy ||
344                     !trampoline->fProxy->isInstantiated()) {
345                     return GrSurfaceProxy::LazyCallbackResult(nullptr, true);
346                 }
347 
348                 SkASSERT(!trampoline->fProxy->peekTexture()->getUniqueKey().isValid());
349                 return GrSurfaceProxy::LazyCallbackResult(
350                         sk_ref_sp(trampoline->fProxy->peekTexture()));
351             },
352             format,
353             dimensions,
354             kSampleCnt,
355             GrInternalSurfaceFlags::kNone,
356             &texInfo,
357             GrMipmapStatus::kNotAllocated,
358             fit,
359             SkBudgeted::kYes,
360             GrProtected::kNo,
361             /* wrapsVkSecondaryCB */ false,
362             GrSurfaceProxy::UseAllocator::kYes);
363 
364     // TODO: It seems like this 'newCT' usage should be 'origCT' but this is
365     // what skgpu::v1::SurfaceDrawContext::MakeWithFallback does
366     GrSwizzle swizzle = dContext->priv().caps()->getReadSwizzle(format, newCT);
367 
368     return {{std::move(proxy), origin, swizzle}, std::move(trampoline)};
369 }
370