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