1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2014 Google Inc.
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/ganesh/GrResourceCache.h"
9*c8dee2aaSAndroid Build Coastguard Worker
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrDirectContext.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrTypes.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SingleOwner.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkNoncopyable.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTo.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkMathPriv.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkRandom.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkTSort.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkMessageBus.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkTraceEvent.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrDirectContextPriv.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrGpuResourceCacheAccess.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrProxyProvider.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrThreadSafeCache.h"
25*c8dee2aaSAndroid Build Coastguard Worker
26*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
27*c8dee2aaSAndroid Build Coastguard Worker #include <chrono>
28*c8dee2aaSAndroid Build Coastguard Worker #include <cstring>
29*c8dee2aaSAndroid Build Coastguard Worker #include <vector>
30*c8dee2aaSAndroid Build Coastguard Worker
31*c8dee2aaSAndroid Build Coastguard Worker using namespace skia_private;
32*c8dee2aaSAndroid Build Coastguard Worker
33*c8dee2aaSAndroid Build Coastguard Worker DECLARE_SKMESSAGEBUS_MESSAGE(skgpu::UniqueKeyInvalidatedMessage, uint32_t, true)
34*c8dee2aaSAndroid Build Coastguard Worker
35*c8dee2aaSAndroid Build Coastguard Worker DECLARE_SKMESSAGEBUS_MESSAGE(GrResourceCache::UnrefResourceMessage,
36*c8dee2aaSAndroid Build Coastguard Worker GrDirectContext::DirectContextID,
37*c8dee2aaSAndroid Build Coastguard Worker /*AllowCopyableMessage=*/false)
38*c8dee2aaSAndroid Build Coastguard Worker
39*c8dee2aaSAndroid Build Coastguard Worker #define ASSERT_SINGLE_OWNER SKGPU_ASSERT_SINGLE_OWNER(fSingleOwner)
40*c8dee2aaSAndroid Build Coastguard Worker
41*c8dee2aaSAndroid Build Coastguard Worker //////////////////////////////////////////////////////////////////////////////
42*c8dee2aaSAndroid Build Coastguard Worker
43*c8dee2aaSAndroid Build Coastguard Worker class GrResourceCache::AutoValidate : ::SkNoncopyable {
44*c8dee2aaSAndroid Build Coastguard Worker public:
AutoValidate(GrResourceCache * cache)45*c8dee2aaSAndroid Build Coastguard Worker AutoValidate(GrResourceCache* cache) : fCache(cache) { cache->validate(); }
~AutoValidate()46*c8dee2aaSAndroid Build Coastguard Worker ~AutoValidate() { fCache->validate(); }
47*c8dee2aaSAndroid Build Coastguard Worker private:
48*c8dee2aaSAndroid Build Coastguard Worker GrResourceCache* fCache;
49*c8dee2aaSAndroid Build Coastguard Worker };
50*c8dee2aaSAndroid Build Coastguard Worker
51*c8dee2aaSAndroid Build Coastguard Worker //////////////////////////////////////////////////////////////////////////////
52*c8dee2aaSAndroid Build Coastguard Worker
GrResourceCache(skgpu::SingleOwner * singleOwner,GrDirectContext::DirectContextID owningContextID,uint32_t familyID)53*c8dee2aaSAndroid Build Coastguard Worker GrResourceCache::GrResourceCache(skgpu::SingleOwner* singleOwner,
54*c8dee2aaSAndroid Build Coastguard Worker GrDirectContext::DirectContextID owningContextID,
55*c8dee2aaSAndroid Build Coastguard Worker uint32_t familyID)
56*c8dee2aaSAndroid Build Coastguard Worker : fInvalidUniqueKeyInbox(familyID)
57*c8dee2aaSAndroid Build Coastguard Worker , fUnrefResourceInbox(owningContextID)
58*c8dee2aaSAndroid Build Coastguard Worker , fOwningContextID(owningContextID)
59*c8dee2aaSAndroid Build Coastguard Worker , fContextUniqueID(familyID)
60*c8dee2aaSAndroid Build Coastguard Worker , fSingleOwner(singleOwner) {
61*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(owningContextID.isValid());
62*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(familyID != SK_InvalidUniqueID);
63*c8dee2aaSAndroid Build Coastguard Worker }
64*c8dee2aaSAndroid Build Coastguard Worker
~GrResourceCache()65*c8dee2aaSAndroid Build Coastguard Worker GrResourceCache::~GrResourceCache() {
66*c8dee2aaSAndroid Build Coastguard Worker this->releaseAll();
67*c8dee2aaSAndroid Build Coastguard Worker }
68*c8dee2aaSAndroid Build Coastguard Worker
setLimit(size_t bytes)69*c8dee2aaSAndroid Build Coastguard Worker void GrResourceCache::setLimit(size_t bytes) {
70*c8dee2aaSAndroid Build Coastguard Worker fMaxBytes = bytes;
71*c8dee2aaSAndroid Build Coastguard Worker this->purgeAsNeeded();
72*c8dee2aaSAndroid Build Coastguard Worker }
73*c8dee2aaSAndroid Build Coastguard Worker
insertResource(GrGpuResource * resource)74*c8dee2aaSAndroid Build Coastguard Worker void GrResourceCache::insertResource(GrGpuResource* resource) {
75*c8dee2aaSAndroid Build Coastguard Worker ASSERT_SINGLE_OWNER
76*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(resource);
77*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!this->isInCache(resource));
78*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!resource->wasDestroyed());
79*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!resource->resourcePriv().isPurgeable());
80*c8dee2aaSAndroid Build Coastguard Worker
81*c8dee2aaSAndroid Build Coastguard Worker // We must set the timestamp before adding to the array in case the timestamp wraps and we wind
82*c8dee2aaSAndroid Build Coastguard Worker // up iterating over all the resources that already have timestamps.
83*c8dee2aaSAndroid Build Coastguard Worker resource->cacheAccess().setTimestamp(this->getNextTimestamp());
84*c8dee2aaSAndroid Build Coastguard Worker
85*c8dee2aaSAndroid Build Coastguard Worker this->addToNonpurgeableArray(resource);
86*c8dee2aaSAndroid Build Coastguard Worker
87*c8dee2aaSAndroid Build Coastguard Worker size_t size = resource->gpuMemorySize();
88*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(++fCount;)
89*c8dee2aaSAndroid Build Coastguard Worker fBytes += size;
90*c8dee2aaSAndroid Build Coastguard Worker #if GR_CACHE_STATS
91*c8dee2aaSAndroid Build Coastguard Worker fHighWaterCount = std::max(this->getResourceCount(), fHighWaterCount);
92*c8dee2aaSAndroid Build Coastguard Worker fHighWaterBytes = std::max(fBytes, fHighWaterBytes);
93*c8dee2aaSAndroid Build Coastguard Worker #endif
94*c8dee2aaSAndroid Build Coastguard Worker if (GrBudgetedType::kBudgeted == resource->resourcePriv().budgetedType()) {
95*c8dee2aaSAndroid Build Coastguard Worker ++fBudgetedCount;
96*c8dee2aaSAndroid Build Coastguard Worker fBudgetedBytes += size;
97*c8dee2aaSAndroid Build Coastguard Worker TRACE_COUNTER2("skia.gpu.cache", "skia budget", "used",
98*c8dee2aaSAndroid Build Coastguard Worker fBudgetedBytes, "free", fMaxBytes - fBudgetedBytes);
99*c8dee2aaSAndroid Build Coastguard Worker #if GR_CACHE_STATS
100*c8dee2aaSAndroid Build Coastguard Worker fBudgetedHighWaterCount = std::max(fBudgetedCount, fBudgetedHighWaterCount);
101*c8dee2aaSAndroid Build Coastguard Worker fBudgetedHighWaterBytes = std::max(fBudgetedBytes, fBudgetedHighWaterBytes);
102*c8dee2aaSAndroid Build Coastguard Worker #endif
103*c8dee2aaSAndroid Build Coastguard Worker }
104*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!resource->cacheAccess().isUsableAsScratch());
105*c8dee2aaSAndroid Build Coastguard Worker this->purgeAsNeeded();
106*c8dee2aaSAndroid Build Coastguard Worker }
107*c8dee2aaSAndroid Build Coastguard Worker
removeResource(GrGpuResource * resource)108*c8dee2aaSAndroid Build Coastguard Worker void GrResourceCache::removeResource(GrGpuResource* resource) {
109*c8dee2aaSAndroid Build Coastguard Worker ASSERT_SINGLE_OWNER
110*c8dee2aaSAndroid Build Coastguard Worker this->validate();
111*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(this->isInCache(resource));
112*c8dee2aaSAndroid Build Coastguard Worker
113*c8dee2aaSAndroid Build Coastguard Worker size_t size = resource->gpuMemorySize();
114*c8dee2aaSAndroid Build Coastguard Worker if (resource->resourcePriv().isPurgeable()) {
115*c8dee2aaSAndroid Build Coastguard Worker fPurgeableQueue.remove(resource);
116*c8dee2aaSAndroid Build Coastguard Worker fPurgeableBytes -= size;
117*c8dee2aaSAndroid Build Coastguard Worker } else {
118*c8dee2aaSAndroid Build Coastguard Worker this->removeFromNonpurgeableArray(resource);
119*c8dee2aaSAndroid Build Coastguard Worker }
120*c8dee2aaSAndroid Build Coastguard Worker
121*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(--fCount;)
122*c8dee2aaSAndroid Build Coastguard Worker fBytes -= size;
123*c8dee2aaSAndroid Build Coastguard Worker if (GrBudgetedType::kBudgeted == resource->resourcePriv().budgetedType()) {
124*c8dee2aaSAndroid Build Coastguard Worker --fBudgetedCount;
125*c8dee2aaSAndroid Build Coastguard Worker fBudgetedBytes -= size;
126*c8dee2aaSAndroid Build Coastguard Worker TRACE_COUNTER2("skia.gpu.cache", "skia budget", "used",
127*c8dee2aaSAndroid Build Coastguard Worker fBudgetedBytes, "free", fMaxBytes - fBudgetedBytes);
128*c8dee2aaSAndroid Build Coastguard Worker }
129*c8dee2aaSAndroid Build Coastguard Worker
130*c8dee2aaSAndroid Build Coastguard Worker if (resource->cacheAccess().isUsableAsScratch()) {
131*c8dee2aaSAndroid Build Coastguard Worker fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource);
132*c8dee2aaSAndroid Build Coastguard Worker }
133*c8dee2aaSAndroid Build Coastguard Worker if (resource->getUniqueKey().isValid()) {
134*c8dee2aaSAndroid Build Coastguard Worker fUniqueHash.remove(resource->getUniqueKey());
135*c8dee2aaSAndroid Build Coastguard Worker }
136*c8dee2aaSAndroid Build Coastguard Worker this->validate();
137*c8dee2aaSAndroid Build Coastguard Worker }
138*c8dee2aaSAndroid Build Coastguard Worker
abandonAll()139*c8dee2aaSAndroid Build Coastguard Worker void GrResourceCache::abandonAll() {
140*c8dee2aaSAndroid Build Coastguard Worker AutoValidate av(this);
141*c8dee2aaSAndroid Build Coastguard Worker
142*c8dee2aaSAndroid Build Coastguard Worker while (!fNonpurgeableResources.empty()) {
143*c8dee2aaSAndroid Build Coastguard Worker GrGpuResource* back = *(fNonpurgeableResources.end() - 1);
144*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!back->wasDestroyed());
145*c8dee2aaSAndroid Build Coastguard Worker back->cacheAccess().abandon();
146*c8dee2aaSAndroid Build Coastguard Worker }
147*c8dee2aaSAndroid Build Coastguard Worker
148*c8dee2aaSAndroid Build Coastguard Worker while (fPurgeableQueue.count()) {
149*c8dee2aaSAndroid Build Coastguard Worker GrGpuResource* top = fPurgeableQueue.peek();
150*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!top->wasDestroyed());
151*c8dee2aaSAndroid Build Coastguard Worker top->cacheAccess().abandon();
152*c8dee2aaSAndroid Build Coastguard Worker }
153*c8dee2aaSAndroid Build Coastguard Worker
154*c8dee2aaSAndroid Build Coastguard Worker fThreadSafeCache->dropAllRefs();
155*c8dee2aaSAndroid Build Coastguard Worker
156*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!fScratchMap.count());
157*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!fUniqueHash.count());
158*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!fCount);
159*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!this->getResourceCount());
160*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!fBytes);
161*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!fBudgetedCount);
162*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!fBudgetedBytes);
163*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!fPurgeableBytes);
164*c8dee2aaSAndroid Build Coastguard Worker }
165*c8dee2aaSAndroid Build Coastguard Worker
releaseAll()166*c8dee2aaSAndroid Build Coastguard Worker void GrResourceCache::releaseAll() {
167*c8dee2aaSAndroid Build Coastguard Worker AutoValidate av(this);
168*c8dee2aaSAndroid Build Coastguard Worker
169*c8dee2aaSAndroid Build Coastguard Worker fThreadSafeCache->dropAllRefs();
170*c8dee2aaSAndroid Build Coastguard Worker
171*c8dee2aaSAndroid Build Coastguard Worker this->processFreedGpuResources();
172*c8dee2aaSAndroid Build Coastguard Worker
173*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fProxyProvider); // better have called setProxyProvider
174*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fThreadSafeCache); // better have called setThreadSafeCache too
175*c8dee2aaSAndroid Build Coastguard Worker
176*c8dee2aaSAndroid Build Coastguard Worker // We must remove the uniqueKeys from the proxies here. While they possess a uniqueKey
177*c8dee2aaSAndroid Build Coastguard Worker // they also have a raw pointer back to this class (which is presumably going away)!
178*c8dee2aaSAndroid Build Coastguard Worker fProxyProvider->removeAllUniqueKeys();
179*c8dee2aaSAndroid Build Coastguard Worker
180*c8dee2aaSAndroid Build Coastguard Worker while (!fNonpurgeableResources.empty()) {
181*c8dee2aaSAndroid Build Coastguard Worker GrGpuResource* back = *(fNonpurgeableResources.end() - 1);
182*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!back->wasDestroyed());
183*c8dee2aaSAndroid Build Coastguard Worker back->cacheAccess().release();
184*c8dee2aaSAndroid Build Coastguard Worker }
185*c8dee2aaSAndroid Build Coastguard Worker
186*c8dee2aaSAndroid Build Coastguard Worker while (fPurgeableQueue.count()) {
187*c8dee2aaSAndroid Build Coastguard Worker GrGpuResource* top = fPurgeableQueue.peek();
188*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!top->wasDestroyed());
189*c8dee2aaSAndroid Build Coastguard Worker top->cacheAccess().release();
190*c8dee2aaSAndroid Build Coastguard Worker }
191*c8dee2aaSAndroid Build Coastguard Worker
192*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!fScratchMap.count());
193*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!fUniqueHash.count());
194*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!fCount);
195*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!this->getResourceCount());
196*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!fBytes);
197*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!fBudgetedCount);
198*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!fBudgetedBytes);
199*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!fPurgeableBytes);
200*c8dee2aaSAndroid Build Coastguard Worker }
201*c8dee2aaSAndroid Build Coastguard Worker
refResource(GrGpuResource * resource)202*c8dee2aaSAndroid Build Coastguard Worker void GrResourceCache::refResource(GrGpuResource* resource) {
203*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(resource);
204*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(resource->getContext()->priv().getResourceCache() == this);
205*c8dee2aaSAndroid Build Coastguard Worker if (resource->cacheAccess().hasRef()) {
206*c8dee2aaSAndroid Build Coastguard Worker resource->ref();
207*c8dee2aaSAndroid Build Coastguard Worker } else {
208*c8dee2aaSAndroid Build Coastguard Worker this->refAndMakeResourceMRU(resource);
209*c8dee2aaSAndroid Build Coastguard Worker }
210*c8dee2aaSAndroid Build Coastguard Worker this->validate();
211*c8dee2aaSAndroid Build Coastguard Worker }
212*c8dee2aaSAndroid Build Coastguard Worker
findAndRefScratchResource(const skgpu::ScratchKey & scratchKey)213*c8dee2aaSAndroid Build Coastguard Worker GrGpuResource* GrResourceCache::findAndRefScratchResource(const skgpu::ScratchKey& scratchKey) {
214*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(scratchKey.isValid());
215*c8dee2aaSAndroid Build Coastguard Worker
216*c8dee2aaSAndroid Build Coastguard Worker GrGpuResource* resource = fScratchMap.find(scratchKey);
217*c8dee2aaSAndroid Build Coastguard Worker if (resource) {
218*c8dee2aaSAndroid Build Coastguard Worker fScratchMap.remove(scratchKey, resource);
219*c8dee2aaSAndroid Build Coastguard Worker this->refAndMakeResourceMRU(resource);
220*c8dee2aaSAndroid Build Coastguard Worker this->validate();
221*c8dee2aaSAndroid Build Coastguard Worker }
222*c8dee2aaSAndroid Build Coastguard Worker return resource;
223*c8dee2aaSAndroid Build Coastguard Worker }
224*c8dee2aaSAndroid Build Coastguard Worker
willRemoveScratchKey(const GrGpuResource * resource)225*c8dee2aaSAndroid Build Coastguard Worker void GrResourceCache::willRemoveScratchKey(const GrGpuResource* resource) {
226*c8dee2aaSAndroid Build Coastguard Worker ASSERT_SINGLE_OWNER
227*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(resource->resourcePriv().getScratchKey().isValid());
228*c8dee2aaSAndroid Build Coastguard Worker if (resource->cacheAccess().isUsableAsScratch()) {
229*c8dee2aaSAndroid Build Coastguard Worker fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource);
230*c8dee2aaSAndroid Build Coastguard Worker }
231*c8dee2aaSAndroid Build Coastguard Worker }
232*c8dee2aaSAndroid Build Coastguard Worker
removeUniqueKey(GrGpuResource * resource)233*c8dee2aaSAndroid Build Coastguard Worker void GrResourceCache::removeUniqueKey(GrGpuResource* resource) {
234*c8dee2aaSAndroid Build Coastguard Worker ASSERT_SINGLE_OWNER
235*c8dee2aaSAndroid Build Coastguard Worker // Someone has a ref to this resource in order to have removed the key. When the ref count
236*c8dee2aaSAndroid Build Coastguard Worker // reaches zero we will get a ref cnt notification and figure out what to do with it.
237*c8dee2aaSAndroid Build Coastguard Worker if (resource->getUniqueKey().isValid()) {
238*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(resource == fUniqueHash.find(resource->getUniqueKey()));
239*c8dee2aaSAndroid Build Coastguard Worker fUniqueHash.remove(resource->getUniqueKey());
240*c8dee2aaSAndroid Build Coastguard Worker }
241*c8dee2aaSAndroid Build Coastguard Worker resource->cacheAccess().removeUniqueKey();
242*c8dee2aaSAndroid Build Coastguard Worker if (resource->cacheAccess().isUsableAsScratch()) {
243*c8dee2aaSAndroid Build Coastguard Worker fScratchMap.insert(resource->resourcePriv().getScratchKey(), resource);
244*c8dee2aaSAndroid Build Coastguard Worker }
245*c8dee2aaSAndroid Build Coastguard Worker
246*c8dee2aaSAndroid Build Coastguard Worker // Removing a unique key from a kUnbudgetedCacheable resource would make the resource
247*c8dee2aaSAndroid Build Coastguard Worker // require purging. However, the resource must be ref'ed to get here and therefore can't
248*c8dee2aaSAndroid Build Coastguard Worker // be purgeable. We'll purge it when the refs reach zero.
249*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!resource->resourcePriv().isPurgeable());
250*c8dee2aaSAndroid Build Coastguard Worker this->validate();
251*c8dee2aaSAndroid Build Coastguard Worker }
252*c8dee2aaSAndroid Build Coastguard Worker
changeUniqueKey(GrGpuResource * resource,const skgpu::UniqueKey & newKey)253*c8dee2aaSAndroid Build Coastguard Worker void GrResourceCache::changeUniqueKey(GrGpuResource* resource, const skgpu::UniqueKey& newKey) {
254*c8dee2aaSAndroid Build Coastguard Worker ASSERT_SINGLE_OWNER
255*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(resource);
256*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(this->isInCache(resource));
257*c8dee2aaSAndroid Build Coastguard Worker
258*c8dee2aaSAndroid Build Coastguard Worker // If another resource has the new key, remove its key then install the key on this resource.
259*c8dee2aaSAndroid Build Coastguard Worker if (newKey.isValid()) {
260*c8dee2aaSAndroid Build Coastguard Worker if (GrGpuResource* old = fUniqueHash.find(newKey)) {
261*c8dee2aaSAndroid Build Coastguard Worker // If the old resource using the key is purgeable and is unreachable, then remove it.
262*c8dee2aaSAndroid Build Coastguard Worker if (!old->resourcePriv().getScratchKey().isValid() &&
263*c8dee2aaSAndroid Build Coastguard Worker old->resourcePriv().isPurgeable()) {
264*c8dee2aaSAndroid Build Coastguard Worker old->cacheAccess().release();
265*c8dee2aaSAndroid Build Coastguard Worker } else {
266*c8dee2aaSAndroid Build Coastguard Worker // removeUniqueKey expects an external owner of the resource.
267*c8dee2aaSAndroid Build Coastguard Worker this->removeUniqueKey(sk_ref_sp(old).get());
268*c8dee2aaSAndroid Build Coastguard Worker }
269*c8dee2aaSAndroid Build Coastguard Worker }
270*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(nullptr == fUniqueHash.find(newKey));
271*c8dee2aaSAndroid Build Coastguard Worker
272*c8dee2aaSAndroid Build Coastguard Worker // Remove the entry for this resource if it already has a unique key.
273*c8dee2aaSAndroid Build Coastguard Worker if (resource->getUniqueKey().isValid()) {
274*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(resource == fUniqueHash.find(resource->getUniqueKey()));
275*c8dee2aaSAndroid Build Coastguard Worker fUniqueHash.remove(resource->getUniqueKey());
276*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(nullptr == fUniqueHash.find(resource->getUniqueKey()));
277*c8dee2aaSAndroid Build Coastguard Worker } else {
278*c8dee2aaSAndroid Build Coastguard Worker // 'resource' didn't have a valid unique key before so it is switching sides. Remove it
279*c8dee2aaSAndroid Build Coastguard Worker // from the ScratchMap. The isUsableAsScratch call depends on us not adding the new
280*c8dee2aaSAndroid Build Coastguard Worker // unique key until after this check.
281*c8dee2aaSAndroid Build Coastguard Worker if (resource->cacheAccess().isUsableAsScratch()) {
282*c8dee2aaSAndroid Build Coastguard Worker fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource);
283*c8dee2aaSAndroid Build Coastguard Worker }
284*c8dee2aaSAndroid Build Coastguard Worker }
285*c8dee2aaSAndroid Build Coastguard Worker
286*c8dee2aaSAndroid Build Coastguard Worker resource->cacheAccess().setUniqueKey(newKey);
287*c8dee2aaSAndroid Build Coastguard Worker fUniqueHash.add(resource);
288*c8dee2aaSAndroid Build Coastguard Worker } else {
289*c8dee2aaSAndroid Build Coastguard Worker this->removeUniqueKey(resource);
290*c8dee2aaSAndroid Build Coastguard Worker }
291*c8dee2aaSAndroid Build Coastguard Worker
292*c8dee2aaSAndroid Build Coastguard Worker this->validate();
293*c8dee2aaSAndroid Build Coastguard Worker }
294*c8dee2aaSAndroid Build Coastguard Worker
refAndMakeResourceMRU(GrGpuResource * resource)295*c8dee2aaSAndroid Build Coastguard Worker void GrResourceCache::refAndMakeResourceMRU(GrGpuResource* resource) {
296*c8dee2aaSAndroid Build Coastguard Worker ASSERT_SINGLE_OWNER
297*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(resource);
298*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(this->isInCache(resource));
299*c8dee2aaSAndroid Build Coastguard Worker
300*c8dee2aaSAndroid Build Coastguard Worker if (resource->resourcePriv().isPurgeable()) {
301*c8dee2aaSAndroid Build Coastguard Worker // It's about to become unpurgeable.
302*c8dee2aaSAndroid Build Coastguard Worker fPurgeableBytes -= resource->gpuMemorySize();
303*c8dee2aaSAndroid Build Coastguard Worker fPurgeableQueue.remove(resource);
304*c8dee2aaSAndroid Build Coastguard Worker this->addToNonpurgeableArray(resource);
305*c8dee2aaSAndroid Build Coastguard Worker } else if (!resource->cacheAccess().hasRefOrCommandBufferUsage() &&
306*c8dee2aaSAndroid Build Coastguard Worker resource->resourcePriv().budgetedType() == GrBudgetedType::kBudgeted) {
307*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fNumBudgetedResourcesFlushWillMakePurgeable > 0);
308*c8dee2aaSAndroid Build Coastguard Worker fNumBudgetedResourcesFlushWillMakePurgeable--;
309*c8dee2aaSAndroid Build Coastguard Worker }
310*c8dee2aaSAndroid Build Coastguard Worker resource->cacheAccess().ref();
311*c8dee2aaSAndroid Build Coastguard Worker
312*c8dee2aaSAndroid Build Coastguard Worker resource->cacheAccess().setTimestamp(this->getNextTimestamp());
313*c8dee2aaSAndroid Build Coastguard Worker this->validate();
314*c8dee2aaSAndroid Build Coastguard Worker }
315*c8dee2aaSAndroid Build Coastguard Worker
notifyARefCntReachedZero(GrGpuResource * resource,GrGpuResource::LastRemovedRef removedRef)316*c8dee2aaSAndroid Build Coastguard Worker void GrResourceCache::notifyARefCntReachedZero(GrGpuResource* resource,
317*c8dee2aaSAndroid Build Coastguard Worker GrGpuResource::LastRemovedRef removedRef) {
318*c8dee2aaSAndroid Build Coastguard Worker ASSERT_SINGLE_OWNER
319*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(resource);
320*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!resource->wasDestroyed());
321*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(this->isInCache(resource));
322*c8dee2aaSAndroid Build Coastguard Worker // This resource should always be in the nonpurgeable array when this function is called. It
323*c8dee2aaSAndroid Build Coastguard Worker // will be moved to the queue if it is newly purgeable.
324*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fNonpurgeableResources[*resource->cacheAccess().accessCacheIndex()] == resource);
325*c8dee2aaSAndroid Build Coastguard Worker
326*c8dee2aaSAndroid Build Coastguard Worker if (removedRef == GrGpuResource::LastRemovedRef::kMainRef) {
327*c8dee2aaSAndroid Build Coastguard Worker if (resource->cacheAccess().isUsableAsScratch()) {
328*c8dee2aaSAndroid Build Coastguard Worker fScratchMap.insert(resource->resourcePriv().getScratchKey(), resource);
329*c8dee2aaSAndroid Build Coastguard Worker }
330*c8dee2aaSAndroid Build Coastguard Worker }
331*c8dee2aaSAndroid Build Coastguard Worker
332*c8dee2aaSAndroid Build Coastguard Worker if (resource->cacheAccess().hasRefOrCommandBufferUsage()) {
333*c8dee2aaSAndroid Build Coastguard Worker this->validate();
334*c8dee2aaSAndroid Build Coastguard Worker return;
335*c8dee2aaSAndroid Build Coastguard Worker }
336*c8dee2aaSAndroid Build Coastguard Worker
337*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
338*c8dee2aaSAndroid Build Coastguard Worker // When the timestamp overflows validate() is called. validate() checks that resources in
339*c8dee2aaSAndroid Build Coastguard Worker // the nonpurgeable array are indeed not purgeable. However, the movement from the array to
340*c8dee2aaSAndroid Build Coastguard Worker // the purgeable queue happens just below in this function. So we mark it as an exception.
341*c8dee2aaSAndroid Build Coastguard Worker if (resource->resourcePriv().isPurgeable()) {
342*c8dee2aaSAndroid Build Coastguard Worker fNewlyPurgeableResourceForValidation = resource;
343*c8dee2aaSAndroid Build Coastguard Worker }
344*c8dee2aaSAndroid Build Coastguard Worker #endif
345*c8dee2aaSAndroid Build Coastguard Worker resource->cacheAccess().setTimestamp(this->getNextTimestamp());
346*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(fNewlyPurgeableResourceForValidation = nullptr);
347*c8dee2aaSAndroid Build Coastguard Worker
348*c8dee2aaSAndroid Build Coastguard Worker if (!resource->resourcePriv().isPurgeable() &&
349*c8dee2aaSAndroid Build Coastguard Worker resource->resourcePriv().budgetedType() == GrBudgetedType::kBudgeted) {
350*c8dee2aaSAndroid Build Coastguard Worker ++fNumBudgetedResourcesFlushWillMakePurgeable;
351*c8dee2aaSAndroid Build Coastguard Worker }
352*c8dee2aaSAndroid Build Coastguard Worker
353*c8dee2aaSAndroid Build Coastguard Worker if (!resource->resourcePriv().isPurgeable()) {
354*c8dee2aaSAndroid Build Coastguard Worker this->validate();
355*c8dee2aaSAndroid Build Coastguard Worker return;
356*c8dee2aaSAndroid Build Coastguard Worker }
357*c8dee2aaSAndroid Build Coastguard Worker
358*c8dee2aaSAndroid Build Coastguard Worker this->removeFromNonpurgeableArray(resource);
359*c8dee2aaSAndroid Build Coastguard Worker fPurgeableQueue.insert(resource);
360*c8dee2aaSAndroid Build Coastguard Worker resource->cacheAccess().setTimeWhenResourceBecomePurgeable();
361*c8dee2aaSAndroid Build Coastguard Worker fPurgeableBytes += resource->gpuMemorySize();
362*c8dee2aaSAndroid Build Coastguard Worker
363*c8dee2aaSAndroid Build Coastguard Worker bool hasUniqueKey = resource->getUniqueKey().isValid();
364*c8dee2aaSAndroid Build Coastguard Worker
365*c8dee2aaSAndroid Build Coastguard Worker GrBudgetedType budgetedType = resource->resourcePriv().budgetedType();
366*c8dee2aaSAndroid Build Coastguard Worker
367*c8dee2aaSAndroid Build Coastguard Worker if (budgetedType == GrBudgetedType::kBudgeted) {
368*c8dee2aaSAndroid Build Coastguard Worker // Purge the resource immediately if we're over budget
369*c8dee2aaSAndroid Build Coastguard Worker // Also purge if the resource has neither a valid scratch key nor a unique key.
370*c8dee2aaSAndroid Build Coastguard Worker bool hasKey = resource->resourcePriv().getScratchKey().isValid() || hasUniqueKey;
371*c8dee2aaSAndroid Build Coastguard Worker if (!this->overBudget() && hasKey) {
372*c8dee2aaSAndroid Build Coastguard Worker return;
373*c8dee2aaSAndroid Build Coastguard Worker }
374*c8dee2aaSAndroid Build Coastguard Worker } else {
375*c8dee2aaSAndroid Build Coastguard Worker // We keep unbudgeted resources with a unique key in the purgeable queue of the cache so
376*c8dee2aaSAndroid Build Coastguard Worker // they can be reused again by the image connected to the unique key.
377*c8dee2aaSAndroid Build Coastguard Worker if (hasUniqueKey && budgetedType == GrBudgetedType::kUnbudgetedCacheable) {
378*c8dee2aaSAndroid Build Coastguard Worker return;
379*c8dee2aaSAndroid Build Coastguard Worker }
380*c8dee2aaSAndroid Build Coastguard Worker // Check whether this resource could still be used as a scratch resource.
381*c8dee2aaSAndroid Build Coastguard Worker if (!resource->resourcePriv().refsWrappedObjects() &&
382*c8dee2aaSAndroid Build Coastguard Worker resource->resourcePriv().getScratchKey().isValid()) {
383*c8dee2aaSAndroid Build Coastguard Worker // We won't purge an existing resource to make room for this one.
384*c8dee2aaSAndroid Build Coastguard Worker if (this->wouldFit(resource->gpuMemorySize())) {
385*c8dee2aaSAndroid Build Coastguard Worker resource->resourcePriv().makeBudgeted();
386*c8dee2aaSAndroid Build Coastguard Worker return;
387*c8dee2aaSAndroid Build Coastguard Worker }
388*c8dee2aaSAndroid Build Coastguard Worker }
389*c8dee2aaSAndroid Build Coastguard Worker }
390*c8dee2aaSAndroid Build Coastguard Worker
391*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(int beforeCount = this->getResourceCount();)
392*c8dee2aaSAndroid Build Coastguard Worker resource->cacheAccess().release();
393*c8dee2aaSAndroid Build Coastguard Worker // We should at least free this resource, perhaps dependent resources as well.
394*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(this->getResourceCount() < beforeCount);
395*c8dee2aaSAndroid Build Coastguard Worker this->validate();
396*c8dee2aaSAndroid Build Coastguard Worker }
397*c8dee2aaSAndroid Build Coastguard Worker
didChangeBudgetStatus(GrGpuResource * resource)398*c8dee2aaSAndroid Build Coastguard Worker void GrResourceCache::didChangeBudgetStatus(GrGpuResource* resource) {
399*c8dee2aaSAndroid Build Coastguard Worker ASSERT_SINGLE_OWNER
400*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(resource);
401*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(this->isInCache(resource));
402*c8dee2aaSAndroid Build Coastguard Worker
403*c8dee2aaSAndroid Build Coastguard Worker size_t size = resource->gpuMemorySize();
404*c8dee2aaSAndroid Build Coastguard Worker // Changing from BudgetedType::kUnbudgetedCacheable to another budgeted type could make
405*c8dee2aaSAndroid Build Coastguard Worker // resource become purgeable. However, we should never allow that transition. Wrapped
406*c8dee2aaSAndroid Build Coastguard Worker // resources are the only resources that can be in that state and they aren't allowed to
407*c8dee2aaSAndroid Build Coastguard Worker // transition from one budgeted state to another.
408*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(bool wasPurgeable = resource->resourcePriv().isPurgeable());
409*c8dee2aaSAndroid Build Coastguard Worker if (resource->resourcePriv().budgetedType() == GrBudgetedType::kBudgeted) {
410*c8dee2aaSAndroid Build Coastguard Worker ++fBudgetedCount;
411*c8dee2aaSAndroid Build Coastguard Worker fBudgetedBytes += size;
412*c8dee2aaSAndroid Build Coastguard Worker #if GR_CACHE_STATS
413*c8dee2aaSAndroid Build Coastguard Worker fBudgetedHighWaterBytes = std::max(fBudgetedBytes, fBudgetedHighWaterBytes);
414*c8dee2aaSAndroid Build Coastguard Worker fBudgetedHighWaterCount = std::max(fBudgetedCount, fBudgetedHighWaterCount);
415*c8dee2aaSAndroid Build Coastguard Worker #endif
416*c8dee2aaSAndroid Build Coastguard Worker if (!resource->resourcePriv().isPurgeable() &&
417*c8dee2aaSAndroid Build Coastguard Worker !resource->cacheAccess().hasRefOrCommandBufferUsage()) {
418*c8dee2aaSAndroid Build Coastguard Worker ++fNumBudgetedResourcesFlushWillMakePurgeable;
419*c8dee2aaSAndroid Build Coastguard Worker }
420*c8dee2aaSAndroid Build Coastguard Worker if (resource->cacheAccess().isUsableAsScratch()) {
421*c8dee2aaSAndroid Build Coastguard Worker fScratchMap.insert(resource->resourcePriv().getScratchKey(), resource);
422*c8dee2aaSAndroid Build Coastguard Worker }
423*c8dee2aaSAndroid Build Coastguard Worker this->purgeAsNeeded();
424*c8dee2aaSAndroid Build Coastguard Worker } else {
425*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(resource->resourcePriv().budgetedType() != GrBudgetedType::kUnbudgetedCacheable);
426*c8dee2aaSAndroid Build Coastguard Worker --fBudgetedCount;
427*c8dee2aaSAndroid Build Coastguard Worker fBudgetedBytes -= size;
428*c8dee2aaSAndroid Build Coastguard Worker if (!resource->resourcePriv().isPurgeable() &&
429*c8dee2aaSAndroid Build Coastguard Worker !resource->cacheAccess().hasRefOrCommandBufferUsage()) {
430*c8dee2aaSAndroid Build Coastguard Worker --fNumBudgetedResourcesFlushWillMakePurgeable;
431*c8dee2aaSAndroid Build Coastguard Worker }
432*c8dee2aaSAndroid Build Coastguard Worker if (!resource->cacheAccess().hasRef() && !resource->getUniqueKey().isValid() &&
433*c8dee2aaSAndroid Build Coastguard Worker resource->resourcePriv().getScratchKey().isValid()) {
434*c8dee2aaSAndroid Build Coastguard Worker fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource);
435*c8dee2aaSAndroid Build Coastguard Worker }
436*c8dee2aaSAndroid Build Coastguard Worker }
437*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(wasPurgeable == resource->resourcePriv().isPurgeable());
438*c8dee2aaSAndroid Build Coastguard Worker TRACE_COUNTER2("skia.gpu.cache", "skia budget", "used",
439*c8dee2aaSAndroid Build Coastguard Worker fBudgetedBytes, "free", fMaxBytes - fBudgetedBytes);
440*c8dee2aaSAndroid Build Coastguard Worker
441*c8dee2aaSAndroid Build Coastguard Worker this->validate();
442*c8dee2aaSAndroid Build Coastguard Worker }
443*c8dee2aaSAndroid Build Coastguard Worker
purgeAsNeeded()444*c8dee2aaSAndroid Build Coastguard Worker void GrResourceCache::purgeAsNeeded() {
445*c8dee2aaSAndroid Build Coastguard Worker TArray<skgpu::UniqueKeyInvalidatedMessage> invalidKeyMsgs;
446*c8dee2aaSAndroid Build Coastguard Worker fInvalidUniqueKeyInbox.poll(&invalidKeyMsgs);
447*c8dee2aaSAndroid Build Coastguard Worker if (!invalidKeyMsgs.empty()) {
448*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fProxyProvider);
449*c8dee2aaSAndroid Build Coastguard Worker
450*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < invalidKeyMsgs.size(); ++i) {
451*c8dee2aaSAndroid Build Coastguard Worker if (invalidKeyMsgs[i].inThreadSafeCache()) {
452*c8dee2aaSAndroid Build Coastguard Worker fThreadSafeCache->remove(invalidKeyMsgs[i].key());
453*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!fThreadSafeCache->has(invalidKeyMsgs[i].key()));
454*c8dee2aaSAndroid Build Coastguard Worker } else {
455*c8dee2aaSAndroid Build Coastguard Worker fProxyProvider->processInvalidUniqueKey(
456*c8dee2aaSAndroid Build Coastguard Worker invalidKeyMsgs[i].key(), nullptr,
457*c8dee2aaSAndroid Build Coastguard Worker GrProxyProvider::InvalidateGPUResource::kYes);
458*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!this->findAndRefUniqueResource(invalidKeyMsgs[i].key()));
459*c8dee2aaSAndroid Build Coastguard Worker }
460*c8dee2aaSAndroid Build Coastguard Worker }
461*c8dee2aaSAndroid Build Coastguard Worker }
462*c8dee2aaSAndroid Build Coastguard Worker
463*c8dee2aaSAndroid Build Coastguard Worker this->processFreedGpuResources();
464*c8dee2aaSAndroid Build Coastguard Worker
465*c8dee2aaSAndroid Build Coastguard Worker bool stillOverbudget = this->overBudget();
466*c8dee2aaSAndroid Build Coastguard Worker while (stillOverbudget && fPurgeableQueue.count()) {
467*c8dee2aaSAndroid Build Coastguard Worker GrGpuResource* resource = fPurgeableQueue.peek();
468*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(resource->resourcePriv().isPurgeable());
469*c8dee2aaSAndroid Build Coastguard Worker resource->cacheAccess().release();
470*c8dee2aaSAndroid Build Coastguard Worker stillOverbudget = this->overBudget();
471*c8dee2aaSAndroid Build Coastguard Worker }
472*c8dee2aaSAndroid Build Coastguard Worker
473*c8dee2aaSAndroid Build Coastguard Worker if (stillOverbudget) {
474*c8dee2aaSAndroid Build Coastguard Worker fThreadSafeCache->dropUniqueRefs(this);
475*c8dee2aaSAndroid Build Coastguard Worker
476*c8dee2aaSAndroid Build Coastguard Worker stillOverbudget = this->overBudget();
477*c8dee2aaSAndroid Build Coastguard Worker while (stillOverbudget && fPurgeableQueue.count()) {
478*c8dee2aaSAndroid Build Coastguard Worker GrGpuResource* resource = fPurgeableQueue.peek();
479*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(resource->resourcePriv().isPurgeable());
480*c8dee2aaSAndroid Build Coastguard Worker resource->cacheAccess().release();
481*c8dee2aaSAndroid Build Coastguard Worker stillOverbudget = this->overBudget();
482*c8dee2aaSAndroid Build Coastguard Worker }
483*c8dee2aaSAndroid Build Coastguard Worker }
484*c8dee2aaSAndroid Build Coastguard Worker
485*c8dee2aaSAndroid Build Coastguard Worker this->validate();
486*c8dee2aaSAndroid Build Coastguard Worker }
487*c8dee2aaSAndroid Build Coastguard Worker
purgeUnlockedResources(const skgpu::StdSteadyClock::time_point * purgeTime,GrPurgeResourceOptions opts)488*c8dee2aaSAndroid Build Coastguard Worker void GrResourceCache::purgeUnlockedResources(const skgpu::StdSteadyClock::time_point* purgeTime,
489*c8dee2aaSAndroid Build Coastguard Worker GrPurgeResourceOptions opts) {
490*c8dee2aaSAndroid Build Coastguard Worker if (opts == GrPurgeResourceOptions::kAllResources) {
491*c8dee2aaSAndroid Build Coastguard Worker if (purgeTime) {
492*c8dee2aaSAndroid Build Coastguard Worker fThreadSafeCache->dropUniqueRefsOlderThan(*purgeTime);
493*c8dee2aaSAndroid Build Coastguard Worker } else {
494*c8dee2aaSAndroid Build Coastguard Worker fThreadSafeCache->dropUniqueRefs(nullptr);
495*c8dee2aaSAndroid Build Coastguard Worker }
496*c8dee2aaSAndroid Build Coastguard Worker
497*c8dee2aaSAndroid Build Coastguard Worker // We could disable maintaining the heap property here, but it would add a lot of
498*c8dee2aaSAndroid Build Coastguard Worker // complexity. Moreover, this is rarely called.
499*c8dee2aaSAndroid Build Coastguard Worker while (fPurgeableQueue.count()) {
500*c8dee2aaSAndroid Build Coastguard Worker GrGpuResource* resource = fPurgeableQueue.peek();
501*c8dee2aaSAndroid Build Coastguard Worker
502*c8dee2aaSAndroid Build Coastguard Worker const skgpu::StdSteadyClock::time_point resourceTime =
503*c8dee2aaSAndroid Build Coastguard Worker resource->cacheAccess().timeWhenResourceBecamePurgeable();
504*c8dee2aaSAndroid Build Coastguard Worker if (purgeTime && resourceTime >= *purgeTime) {
505*c8dee2aaSAndroid Build Coastguard Worker // Resources were given both LRU timestamps and tagged with a frame number when
506*c8dee2aaSAndroid Build Coastguard Worker // they first became purgeable. The LRU timestamp won't change again until the
507*c8dee2aaSAndroid Build Coastguard Worker // resource is made non-purgeable again. So, at this point all the remaining
508*c8dee2aaSAndroid Build Coastguard Worker // resources in the timestamp-sorted queue will have a frame number >= to this
509*c8dee2aaSAndroid Build Coastguard Worker // one.
510*c8dee2aaSAndroid Build Coastguard Worker break;
511*c8dee2aaSAndroid Build Coastguard Worker }
512*c8dee2aaSAndroid Build Coastguard Worker
513*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(resource->resourcePriv().isPurgeable());
514*c8dee2aaSAndroid Build Coastguard Worker resource->cacheAccess().release();
515*c8dee2aaSAndroid Build Coastguard Worker }
516*c8dee2aaSAndroid Build Coastguard Worker } else {
517*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(opts == GrPurgeResourceOptions::kScratchResourcesOnly);
518*c8dee2aaSAndroid Build Coastguard Worker // Early out if the very first item is too new to purge to avoid sorting the queue when
519*c8dee2aaSAndroid Build Coastguard Worker // nothing will be deleted.
520*c8dee2aaSAndroid Build Coastguard Worker if (purgeTime && fPurgeableQueue.count() &&
521*c8dee2aaSAndroid Build Coastguard Worker fPurgeableQueue.peek()->cacheAccess().timeWhenResourceBecamePurgeable() >= *purgeTime) {
522*c8dee2aaSAndroid Build Coastguard Worker return;
523*c8dee2aaSAndroid Build Coastguard Worker }
524*c8dee2aaSAndroid Build Coastguard Worker
525*c8dee2aaSAndroid Build Coastguard Worker // Sort the queue
526*c8dee2aaSAndroid Build Coastguard Worker fPurgeableQueue.sort();
527*c8dee2aaSAndroid Build Coastguard Worker
528*c8dee2aaSAndroid Build Coastguard Worker // Make a list of the scratch resources to delete
529*c8dee2aaSAndroid Build Coastguard Worker SkTDArray<GrGpuResource*> scratchResources;
530*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < fPurgeableQueue.count(); i++) {
531*c8dee2aaSAndroid Build Coastguard Worker GrGpuResource* resource = fPurgeableQueue.at(i);
532*c8dee2aaSAndroid Build Coastguard Worker
533*c8dee2aaSAndroid Build Coastguard Worker const skgpu::StdSteadyClock::time_point resourceTime =
534*c8dee2aaSAndroid Build Coastguard Worker resource->cacheAccess().timeWhenResourceBecamePurgeable();
535*c8dee2aaSAndroid Build Coastguard Worker if (purgeTime && resourceTime >= *purgeTime) {
536*c8dee2aaSAndroid Build Coastguard Worker // scratch or not, all later iterations will be too recently used to purge.
537*c8dee2aaSAndroid Build Coastguard Worker break;
538*c8dee2aaSAndroid Build Coastguard Worker }
539*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(resource->resourcePriv().isPurgeable());
540*c8dee2aaSAndroid Build Coastguard Worker if (!resource->getUniqueKey().isValid()) {
541*c8dee2aaSAndroid Build Coastguard Worker *scratchResources.append() = resource;
542*c8dee2aaSAndroid Build Coastguard Worker }
543*c8dee2aaSAndroid Build Coastguard Worker }
544*c8dee2aaSAndroid Build Coastguard Worker
545*c8dee2aaSAndroid Build Coastguard Worker // Delete the scratch resources. This must be done as a separate pass
546*c8dee2aaSAndroid Build Coastguard Worker // to avoid messing up the sorted order of the queue
547*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < scratchResources.size(); i++) {
548*c8dee2aaSAndroid Build Coastguard Worker scratchResources[i]->cacheAccess().release();
549*c8dee2aaSAndroid Build Coastguard Worker }
550*c8dee2aaSAndroid Build Coastguard Worker }
551*c8dee2aaSAndroid Build Coastguard Worker
552*c8dee2aaSAndroid Build Coastguard Worker this->validate();
553*c8dee2aaSAndroid Build Coastguard Worker }
554*c8dee2aaSAndroid Build Coastguard Worker
purgeToMakeHeadroom(size_t desiredHeadroomBytes)555*c8dee2aaSAndroid Build Coastguard Worker bool GrResourceCache::purgeToMakeHeadroom(size_t desiredHeadroomBytes) {
556*c8dee2aaSAndroid Build Coastguard Worker AutoValidate av(this);
557*c8dee2aaSAndroid Build Coastguard Worker if (desiredHeadroomBytes > fMaxBytes) {
558*c8dee2aaSAndroid Build Coastguard Worker return false;
559*c8dee2aaSAndroid Build Coastguard Worker }
560*c8dee2aaSAndroid Build Coastguard Worker if (this->wouldFit(desiredHeadroomBytes)) {
561*c8dee2aaSAndroid Build Coastguard Worker return true;
562*c8dee2aaSAndroid Build Coastguard Worker }
563*c8dee2aaSAndroid Build Coastguard Worker fPurgeableQueue.sort();
564*c8dee2aaSAndroid Build Coastguard Worker
565*c8dee2aaSAndroid Build Coastguard Worker size_t projectedBudget = fBudgetedBytes;
566*c8dee2aaSAndroid Build Coastguard Worker int purgeCnt = 0;
567*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < fPurgeableQueue.count(); i++) {
568*c8dee2aaSAndroid Build Coastguard Worker GrGpuResource* resource = fPurgeableQueue.at(i);
569*c8dee2aaSAndroid Build Coastguard Worker if (GrBudgetedType::kBudgeted == resource->resourcePriv().budgetedType()) {
570*c8dee2aaSAndroid Build Coastguard Worker projectedBudget -= resource->gpuMemorySize();
571*c8dee2aaSAndroid Build Coastguard Worker }
572*c8dee2aaSAndroid Build Coastguard Worker if (projectedBudget + desiredHeadroomBytes <= fMaxBytes) {
573*c8dee2aaSAndroid Build Coastguard Worker purgeCnt = i + 1;
574*c8dee2aaSAndroid Build Coastguard Worker break;
575*c8dee2aaSAndroid Build Coastguard Worker }
576*c8dee2aaSAndroid Build Coastguard Worker }
577*c8dee2aaSAndroid Build Coastguard Worker if (purgeCnt == 0) {
578*c8dee2aaSAndroid Build Coastguard Worker return false;
579*c8dee2aaSAndroid Build Coastguard Worker }
580*c8dee2aaSAndroid Build Coastguard Worker
581*c8dee2aaSAndroid Build Coastguard Worker // Success! Release the resources.
582*c8dee2aaSAndroid Build Coastguard Worker // Copy to array first so we don't mess with the queue.
583*c8dee2aaSAndroid Build Coastguard Worker std::vector<GrGpuResource*> resources;
584*c8dee2aaSAndroid Build Coastguard Worker resources.reserve(purgeCnt);
585*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < purgeCnt; i++) {
586*c8dee2aaSAndroid Build Coastguard Worker resources.push_back(fPurgeableQueue.at(i));
587*c8dee2aaSAndroid Build Coastguard Worker }
588*c8dee2aaSAndroid Build Coastguard Worker for (GrGpuResource* resource : resources) {
589*c8dee2aaSAndroid Build Coastguard Worker resource->cacheAccess().release();
590*c8dee2aaSAndroid Build Coastguard Worker }
591*c8dee2aaSAndroid Build Coastguard Worker return true;
592*c8dee2aaSAndroid Build Coastguard Worker }
593*c8dee2aaSAndroid Build Coastguard Worker
purgeUnlockedResources(size_t bytesToPurge,bool preferScratchResources)594*c8dee2aaSAndroid Build Coastguard Worker void GrResourceCache::purgeUnlockedResources(size_t bytesToPurge, bool preferScratchResources) {
595*c8dee2aaSAndroid Build Coastguard Worker
596*c8dee2aaSAndroid Build Coastguard Worker const size_t tmpByteBudget = std::max((size_t)0, fBytes - bytesToPurge);
597*c8dee2aaSAndroid Build Coastguard Worker bool stillOverbudget = tmpByteBudget < fBytes;
598*c8dee2aaSAndroid Build Coastguard Worker
599*c8dee2aaSAndroid Build Coastguard Worker if (preferScratchResources && bytesToPurge < fPurgeableBytes) {
600*c8dee2aaSAndroid Build Coastguard Worker // Sort the queue
601*c8dee2aaSAndroid Build Coastguard Worker fPurgeableQueue.sort();
602*c8dee2aaSAndroid Build Coastguard Worker
603*c8dee2aaSAndroid Build Coastguard Worker // Make a list of the scratch resources to delete
604*c8dee2aaSAndroid Build Coastguard Worker SkTDArray<GrGpuResource*> scratchResources;
605*c8dee2aaSAndroid Build Coastguard Worker size_t scratchByteCount = 0;
606*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < fPurgeableQueue.count() && stillOverbudget; i++) {
607*c8dee2aaSAndroid Build Coastguard Worker GrGpuResource* resource = fPurgeableQueue.at(i);
608*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(resource->resourcePriv().isPurgeable());
609*c8dee2aaSAndroid Build Coastguard Worker if (!resource->getUniqueKey().isValid()) {
610*c8dee2aaSAndroid Build Coastguard Worker *scratchResources.append() = resource;
611*c8dee2aaSAndroid Build Coastguard Worker scratchByteCount += resource->gpuMemorySize();
612*c8dee2aaSAndroid Build Coastguard Worker stillOverbudget = tmpByteBudget < fBytes - scratchByteCount;
613*c8dee2aaSAndroid Build Coastguard Worker }
614*c8dee2aaSAndroid Build Coastguard Worker }
615*c8dee2aaSAndroid Build Coastguard Worker
616*c8dee2aaSAndroid Build Coastguard Worker // Delete the scratch resources. This must be done as a separate pass
617*c8dee2aaSAndroid Build Coastguard Worker // to avoid messing up the sorted order of the queue
618*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < scratchResources.size(); i++) {
619*c8dee2aaSAndroid Build Coastguard Worker scratchResources[i]->cacheAccess().release();
620*c8dee2aaSAndroid Build Coastguard Worker }
621*c8dee2aaSAndroid Build Coastguard Worker stillOverbudget = tmpByteBudget < fBytes;
622*c8dee2aaSAndroid Build Coastguard Worker
623*c8dee2aaSAndroid Build Coastguard Worker this->validate();
624*c8dee2aaSAndroid Build Coastguard Worker }
625*c8dee2aaSAndroid Build Coastguard Worker
626*c8dee2aaSAndroid Build Coastguard Worker // Purge any remaining resources in LRU order
627*c8dee2aaSAndroid Build Coastguard Worker if (stillOverbudget) {
628*c8dee2aaSAndroid Build Coastguard Worker const size_t cachedByteCount = fMaxBytes;
629*c8dee2aaSAndroid Build Coastguard Worker fMaxBytes = tmpByteBudget;
630*c8dee2aaSAndroid Build Coastguard Worker this->purgeAsNeeded();
631*c8dee2aaSAndroid Build Coastguard Worker fMaxBytes = cachedByteCount;
632*c8dee2aaSAndroid Build Coastguard Worker }
633*c8dee2aaSAndroid Build Coastguard Worker }
634*c8dee2aaSAndroid Build Coastguard Worker
requestsFlush() const635*c8dee2aaSAndroid Build Coastguard Worker bool GrResourceCache::requestsFlush() const {
636*c8dee2aaSAndroid Build Coastguard Worker return this->overBudget() && !fPurgeableQueue.count() &&
637*c8dee2aaSAndroid Build Coastguard Worker fNumBudgetedResourcesFlushWillMakePurgeable > 0;
638*c8dee2aaSAndroid Build Coastguard Worker }
639*c8dee2aaSAndroid Build Coastguard Worker
processFreedGpuResources()640*c8dee2aaSAndroid Build Coastguard Worker void GrResourceCache::processFreedGpuResources() {
641*c8dee2aaSAndroid Build Coastguard Worker TArray<UnrefResourceMessage> msgs;
642*c8dee2aaSAndroid Build Coastguard Worker fUnrefResourceInbox.poll(&msgs);
643*c8dee2aaSAndroid Build Coastguard Worker // We don't need to do anything other than let the messages delete themselves and call unref.
644*c8dee2aaSAndroid Build Coastguard Worker }
645*c8dee2aaSAndroid Build Coastguard Worker
addToNonpurgeableArray(GrGpuResource * resource)646*c8dee2aaSAndroid Build Coastguard Worker void GrResourceCache::addToNonpurgeableArray(GrGpuResource* resource) {
647*c8dee2aaSAndroid Build Coastguard Worker int index = fNonpurgeableResources.size();
648*c8dee2aaSAndroid Build Coastguard Worker *fNonpurgeableResources.append() = resource;
649*c8dee2aaSAndroid Build Coastguard Worker *resource->cacheAccess().accessCacheIndex() = index;
650*c8dee2aaSAndroid Build Coastguard Worker }
651*c8dee2aaSAndroid Build Coastguard Worker
removeFromNonpurgeableArray(GrGpuResource * resource)652*c8dee2aaSAndroid Build Coastguard Worker void GrResourceCache::removeFromNonpurgeableArray(GrGpuResource* resource) {
653*c8dee2aaSAndroid Build Coastguard Worker int* index = resource->cacheAccess().accessCacheIndex();
654*c8dee2aaSAndroid Build Coastguard Worker // Fill the hole we will create in the array with the tail object, adjust its index, and
655*c8dee2aaSAndroid Build Coastguard Worker // then pop the array
656*c8dee2aaSAndroid Build Coastguard Worker GrGpuResource* tail = *(fNonpurgeableResources.end() - 1);
657*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fNonpurgeableResources[*index] == resource);
658*c8dee2aaSAndroid Build Coastguard Worker fNonpurgeableResources[*index] = tail;
659*c8dee2aaSAndroid Build Coastguard Worker *tail->cacheAccess().accessCacheIndex() = *index;
660*c8dee2aaSAndroid Build Coastguard Worker fNonpurgeableResources.pop_back();
661*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(*index = -1);
662*c8dee2aaSAndroid Build Coastguard Worker }
663*c8dee2aaSAndroid Build Coastguard Worker
getNextTimestamp()664*c8dee2aaSAndroid Build Coastguard Worker uint32_t GrResourceCache::getNextTimestamp() {
665*c8dee2aaSAndroid Build Coastguard Worker // If we wrap then all the existing resources will appear older than any resources that get
666*c8dee2aaSAndroid Build Coastguard Worker // a timestamp after the wrap.
667*c8dee2aaSAndroid Build Coastguard Worker if (0 == fTimestamp) {
668*c8dee2aaSAndroid Build Coastguard Worker int count = this->getResourceCount();
669*c8dee2aaSAndroid Build Coastguard Worker if (count) {
670*c8dee2aaSAndroid Build Coastguard Worker // Reset all the timestamps. We sort the resources by timestamp and then assign
671*c8dee2aaSAndroid Build Coastguard Worker // sequential timestamps beginning with 0. This is O(n*lg(n)) but it should be extremely
672*c8dee2aaSAndroid Build Coastguard Worker // rare.
673*c8dee2aaSAndroid Build Coastguard Worker SkTDArray<GrGpuResource*> sortedPurgeableResources;
674*c8dee2aaSAndroid Build Coastguard Worker sortedPurgeableResources.reserve(fPurgeableQueue.count());
675*c8dee2aaSAndroid Build Coastguard Worker
676*c8dee2aaSAndroid Build Coastguard Worker while (fPurgeableQueue.count()) {
677*c8dee2aaSAndroid Build Coastguard Worker *sortedPurgeableResources.append() = fPurgeableQueue.peek();
678*c8dee2aaSAndroid Build Coastguard Worker fPurgeableQueue.pop();
679*c8dee2aaSAndroid Build Coastguard Worker }
680*c8dee2aaSAndroid Build Coastguard Worker
681*c8dee2aaSAndroid Build Coastguard Worker SkTQSort(fNonpurgeableResources.begin(), fNonpurgeableResources.end(),
682*c8dee2aaSAndroid Build Coastguard Worker CompareTimestamp);
683*c8dee2aaSAndroid Build Coastguard Worker
684*c8dee2aaSAndroid Build Coastguard Worker // Pick resources out of the purgeable and non-purgeable arrays based on lowest
685*c8dee2aaSAndroid Build Coastguard Worker // timestamp and assign new timestamps.
686*c8dee2aaSAndroid Build Coastguard Worker int currP = 0;
687*c8dee2aaSAndroid Build Coastguard Worker int currNP = 0;
688*c8dee2aaSAndroid Build Coastguard Worker while (currP < sortedPurgeableResources.size() &&
689*c8dee2aaSAndroid Build Coastguard Worker currNP < fNonpurgeableResources.size()) {
690*c8dee2aaSAndroid Build Coastguard Worker uint32_t tsP = sortedPurgeableResources[currP]->cacheAccess().timestamp();
691*c8dee2aaSAndroid Build Coastguard Worker uint32_t tsNP = fNonpurgeableResources[currNP]->cacheAccess().timestamp();
692*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(tsP != tsNP);
693*c8dee2aaSAndroid Build Coastguard Worker if (tsP < tsNP) {
694*c8dee2aaSAndroid Build Coastguard Worker sortedPurgeableResources[currP++]->cacheAccess().setTimestamp(fTimestamp++);
695*c8dee2aaSAndroid Build Coastguard Worker } else {
696*c8dee2aaSAndroid Build Coastguard Worker // Correct the index in the nonpurgeable array stored on the resource post-sort.
697*c8dee2aaSAndroid Build Coastguard Worker *fNonpurgeableResources[currNP]->cacheAccess().accessCacheIndex() = currNP;
698*c8dee2aaSAndroid Build Coastguard Worker fNonpurgeableResources[currNP++]->cacheAccess().setTimestamp(fTimestamp++);
699*c8dee2aaSAndroid Build Coastguard Worker }
700*c8dee2aaSAndroid Build Coastguard Worker }
701*c8dee2aaSAndroid Build Coastguard Worker
702*c8dee2aaSAndroid Build Coastguard Worker // The above loop ended when we hit the end of one array. Finish the other one.
703*c8dee2aaSAndroid Build Coastguard Worker while (currP < sortedPurgeableResources.size()) {
704*c8dee2aaSAndroid Build Coastguard Worker sortedPurgeableResources[currP++]->cacheAccess().setTimestamp(fTimestamp++);
705*c8dee2aaSAndroid Build Coastguard Worker }
706*c8dee2aaSAndroid Build Coastguard Worker while (currNP < fNonpurgeableResources.size()) {
707*c8dee2aaSAndroid Build Coastguard Worker *fNonpurgeableResources[currNP]->cacheAccess().accessCacheIndex() = currNP;
708*c8dee2aaSAndroid Build Coastguard Worker fNonpurgeableResources[currNP++]->cacheAccess().setTimestamp(fTimestamp++);
709*c8dee2aaSAndroid Build Coastguard Worker }
710*c8dee2aaSAndroid Build Coastguard Worker
711*c8dee2aaSAndroid Build Coastguard Worker // Rebuild the queue.
712*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < sortedPurgeableResources.size(); ++i) {
713*c8dee2aaSAndroid Build Coastguard Worker fPurgeableQueue.insert(sortedPurgeableResources[i]);
714*c8dee2aaSAndroid Build Coastguard Worker }
715*c8dee2aaSAndroid Build Coastguard Worker
716*c8dee2aaSAndroid Build Coastguard Worker this->validate();
717*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(count == this->getResourceCount());
718*c8dee2aaSAndroid Build Coastguard Worker
719*c8dee2aaSAndroid Build Coastguard Worker // count should be the next timestamp we return.
720*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fTimestamp == SkToU32(count));
721*c8dee2aaSAndroid Build Coastguard Worker }
722*c8dee2aaSAndroid Build Coastguard Worker }
723*c8dee2aaSAndroid Build Coastguard Worker return fTimestamp++;
724*c8dee2aaSAndroid Build Coastguard Worker }
725*c8dee2aaSAndroid Build Coastguard Worker
dumpMemoryStatistics(SkTraceMemoryDump * traceMemoryDump) const726*c8dee2aaSAndroid Build Coastguard Worker void GrResourceCache::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
727*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < fNonpurgeableResources.size(); ++i) {
728*c8dee2aaSAndroid Build Coastguard Worker fNonpurgeableResources[i]->dumpMemoryStatistics(traceMemoryDump);
729*c8dee2aaSAndroid Build Coastguard Worker }
730*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < fPurgeableQueue.count(); ++i) {
731*c8dee2aaSAndroid Build Coastguard Worker fPurgeableQueue.at(i)->dumpMemoryStatistics(traceMemoryDump);
732*c8dee2aaSAndroid Build Coastguard Worker }
733*c8dee2aaSAndroid Build Coastguard Worker }
734*c8dee2aaSAndroid Build Coastguard Worker
735*c8dee2aaSAndroid Build Coastguard Worker #if GR_CACHE_STATS
getStats(Stats * stats) const736*c8dee2aaSAndroid Build Coastguard Worker void GrResourceCache::getStats(Stats* stats) const {
737*c8dee2aaSAndroid Build Coastguard Worker stats->reset();
738*c8dee2aaSAndroid Build Coastguard Worker
739*c8dee2aaSAndroid Build Coastguard Worker stats->fTotal = this->getResourceCount();
740*c8dee2aaSAndroid Build Coastguard Worker stats->fNumNonPurgeable = fNonpurgeableResources.size();
741*c8dee2aaSAndroid Build Coastguard Worker stats->fNumPurgeable = fPurgeableQueue.count();
742*c8dee2aaSAndroid Build Coastguard Worker
743*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < fNonpurgeableResources.size(); ++i) {
744*c8dee2aaSAndroid Build Coastguard Worker stats->update(fNonpurgeableResources[i]);
745*c8dee2aaSAndroid Build Coastguard Worker }
746*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < fPurgeableQueue.count(); ++i) {
747*c8dee2aaSAndroid Build Coastguard Worker stats->update(fPurgeableQueue.at(i));
748*c8dee2aaSAndroid Build Coastguard Worker }
749*c8dee2aaSAndroid Build Coastguard Worker }
750*c8dee2aaSAndroid Build Coastguard Worker
751*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
dumpStats(SkString * out) const752*c8dee2aaSAndroid Build Coastguard Worker void GrResourceCache::dumpStats(SkString* out) const {
753*c8dee2aaSAndroid Build Coastguard Worker this->validate();
754*c8dee2aaSAndroid Build Coastguard Worker
755*c8dee2aaSAndroid Build Coastguard Worker Stats stats;
756*c8dee2aaSAndroid Build Coastguard Worker
757*c8dee2aaSAndroid Build Coastguard Worker this->getStats(&stats);
758*c8dee2aaSAndroid Build Coastguard Worker
759*c8dee2aaSAndroid Build Coastguard Worker float byteUtilization = (100.f * fBudgetedBytes) / fMaxBytes;
760*c8dee2aaSAndroid Build Coastguard Worker
761*c8dee2aaSAndroid Build Coastguard Worker out->appendf("Budget: %d bytes\n", (int)fMaxBytes);
762*c8dee2aaSAndroid Build Coastguard Worker out->appendf("\t\tEntry Count: current %d"
763*c8dee2aaSAndroid Build Coastguard Worker " (%d budgeted, %d wrapped, %d locked, %d scratch), high %d\n",
764*c8dee2aaSAndroid Build Coastguard Worker stats.fTotal, fBudgetedCount, stats.fWrapped, stats.fNumNonPurgeable,
765*c8dee2aaSAndroid Build Coastguard Worker stats.fScratch, fHighWaterCount);
766*c8dee2aaSAndroid Build Coastguard Worker out->appendf("\t\tEntry Bytes: current %d (budgeted %d, %.2g%% full, %d unbudgeted) high %d\n",
767*c8dee2aaSAndroid Build Coastguard Worker SkToInt(fBytes), SkToInt(fBudgetedBytes), byteUtilization,
768*c8dee2aaSAndroid Build Coastguard Worker SkToInt(stats.fUnbudgetedSize), SkToInt(fHighWaterBytes));
769*c8dee2aaSAndroid Build Coastguard Worker }
770*c8dee2aaSAndroid Build Coastguard Worker
dumpStatsKeyValuePairs(TArray<SkString> * keys,TArray<double> * values) const771*c8dee2aaSAndroid Build Coastguard Worker void GrResourceCache::dumpStatsKeyValuePairs(TArray<SkString>* keys,
772*c8dee2aaSAndroid Build Coastguard Worker TArray<double>* values) const {
773*c8dee2aaSAndroid Build Coastguard Worker this->validate();
774*c8dee2aaSAndroid Build Coastguard Worker
775*c8dee2aaSAndroid Build Coastguard Worker Stats stats;
776*c8dee2aaSAndroid Build Coastguard Worker this->getStats(&stats);
777*c8dee2aaSAndroid Build Coastguard Worker
778*c8dee2aaSAndroid Build Coastguard Worker keys->push_back(SkString("gpu_cache_purgable_entries")); values->push_back(stats.fNumPurgeable);
779*c8dee2aaSAndroid Build Coastguard Worker }
780*c8dee2aaSAndroid Build Coastguard Worker #endif // defined(GPU_TEST_UTILS)
781*c8dee2aaSAndroid Build Coastguard Worker #endif // GR_CACHE_STATS
782*c8dee2aaSAndroid Build Coastguard Worker
783*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
validate() const784*c8dee2aaSAndroid Build Coastguard Worker void GrResourceCache::validate() const {
785*c8dee2aaSAndroid Build Coastguard Worker // Reduce the frequency of validations for large resource counts.
786*c8dee2aaSAndroid Build Coastguard Worker static SkRandom gRandom;
787*c8dee2aaSAndroid Build Coastguard Worker int mask = (SkNextPow2(fCount + 1) >> 5) - 1;
788*c8dee2aaSAndroid Build Coastguard Worker if (~mask && (gRandom.nextU() & mask)) {
789*c8dee2aaSAndroid Build Coastguard Worker return;
790*c8dee2aaSAndroid Build Coastguard Worker }
791*c8dee2aaSAndroid Build Coastguard Worker
792*c8dee2aaSAndroid Build Coastguard Worker struct Stats {
793*c8dee2aaSAndroid Build Coastguard Worker size_t fBytes;
794*c8dee2aaSAndroid Build Coastguard Worker int fBudgetedCount;
795*c8dee2aaSAndroid Build Coastguard Worker size_t fBudgetedBytes;
796*c8dee2aaSAndroid Build Coastguard Worker int fLocked;
797*c8dee2aaSAndroid Build Coastguard Worker int fScratch;
798*c8dee2aaSAndroid Build Coastguard Worker int fCouldBeScratch;
799*c8dee2aaSAndroid Build Coastguard Worker int fContent;
800*c8dee2aaSAndroid Build Coastguard Worker const ScratchMap* fScratchMap;
801*c8dee2aaSAndroid Build Coastguard Worker const UniqueHash* fUniqueHash;
802*c8dee2aaSAndroid Build Coastguard Worker
803*c8dee2aaSAndroid Build Coastguard Worker Stats(const GrResourceCache* cache) {
804*c8dee2aaSAndroid Build Coastguard Worker memset(this, 0, sizeof(*this));
805*c8dee2aaSAndroid Build Coastguard Worker fScratchMap = &cache->fScratchMap;
806*c8dee2aaSAndroid Build Coastguard Worker fUniqueHash = &cache->fUniqueHash;
807*c8dee2aaSAndroid Build Coastguard Worker }
808*c8dee2aaSAndroid Build Coastguard Worker
809*c8dee2aaSAndroid Build Coastguard Worker void update(GrGpuResource* resource) {
810*c8dee2aaSAndroid Build Coastguard Worker fBytes += resource->gpuMemorySize();
811*c8dee2aaSAndroid Build Coastguard Worker
812*c8dee2aaSAndroid Build Coastguard Worker if (!resource->resourcePriv().isPurgeable()) {
813*c8dee2aaSAndroid Build Coastguard Worker ++fLocked;
814*c8dee2aaSAndroid Build Coastguard Worker }
815*c8dee2aaSAndroid Build Coastguard Worker
816*c8dee2aaSAndroid Build Coastguard Worker const skgpu::ScratchKey& scratchKey = resource->resourcePriv().getScratchKey();
817*c8dee2aaSAndroid Build Coastguard Worker const skgpu::UniqueKey& uniqueKey = resource->getUniqueKey();
818*c8dee2aaSAndroid Build Coastguard Worker
819*c8dee2aaSAndroid Build Coastguard Worker if (resource->cacheAccess().isUsableAsScratch()) {
820*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!uniqueKey.isValid());
821*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(GrBudgetedType::kBudgeted == resource->resourcePriv().budgetedType());
822*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!resource->cacheAccess().hasRef());
823*c8dee2aaSAndroid Build Coastguard Worker ++fScratch;
824*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fScratchMap->countForKey(scratchKey));
825*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!resource->resourcePriv().refsWrappedObjects());
826*c8dee2aaSAndroid Build Coastguard Worker } else if (scratchKey.isValid()) {
827*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(GrBudgetedType::kBudgeted != resource->resourcePriv().budgetedType() ||
828*c8dee2aaSAndroid Build Coastguard Worker uniqueKey.isValid() || resource->cacheAccess().hasRef());
829*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!resource->resourcePriv().refsWrappedObjects());
830*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!fScratchMap->has(resource, scratchKey));
831*c8dee2aaSAndroid Build Coastguard Worker }
832*c8dee2aaSAndroid Build Coastguard Worker if (uniqueKey.isValid()) {
833*c8dee2aaSAndroid Build Coastguard Worker ++fContent;
834*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fUniqueHash->find(uniqueKey) == resource);
835*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(GrBudgetedType::kBudgeted == resource->resourcePriv().budgetedType() ||
836*c8dee2aaSAndroid Build Coastguard Worker resource->resourcePriv().refsWrappedObjects());
837*c8dee2aaSAndroid Build Coastguard Worker }
838*c8dee2aaSAndroid Build Coastguard Worker
839*c8dee2aaSAndroid Build Coastguard Worker if (GrBudgetedType::kBudgeted == resource->resourcePriv().budgetedType()) {
840*c8dee2aaSAndroid Build Coastguard Worker ++fBudgetedCount;
841*c8dee2aaSAndroid Build Coastguard Worker fBudgetedBytes += resource->gpuMemorySize();
842*c8dee2aaSAndroid Build Coastguard Worker }
843*c8dee2aaSAndroid Build Coastguard Worker }
844*c8dee2aaSAndroid Build Coastguard Worker };
845*c8dee2aaSAndroid Build Coastguard Worker
846*c8dee2aaSAndroid Build Coastguard Worker {
847*c8dee2aaSAndroid Build Coastguard Worker int count = 0;
848*c8dee2aaSAndroid Build Coastguard Worker fScratchMap.foreach([&](const GrGpuResource& resource) {
849*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(resource.cacheAccess().isUsableAsScratch());
850*c8dee2aaSAndroid Build Coastguard Worker count++;
851*c8dee2aaSAndroid Build Coastguard Worker });
852*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(count == fScratchMap.count());
853*c8dee2aaSAndroid Build Coastguard Worker }
854*c8dee2aaSAndroid Build Coastguard Worker
855*c8dee2aaSAndroid Build Coastguard Worker Stats stats(this);
856*c8dee2aaSAndroid Build Coastguard Worker size_t purgeableBytes = 0;
857*c8dee2aaSAndroid Build Coastguard Worker int numBudgetedResourcesFlushWillMakePurgeable = 0;
858*c8dee2aaSAndroid Build Coastguard Worker
859*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < fNonpurgeableResources.size(); ++i) {
860*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!fNonpurgeableResources[i]->resourcePriv().isPurgeable() ||
861*c8dee2aaSAndroid Build Coastguard Worker fNewlyPurgeableResourceForValidation == fNonpurgeableResources[i]);
862*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(*fNonpurgeableResources[i]->cacheAccess().accessCacheIndex() == i);
863*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!fNonpurgeableResources[i]->wasDestroyed());
864*c8dee2aaSAndroid Build Coastguard Worker if (fNonpurgeableResources[i]->resourcePriv().budgetedType() == GrBudgetedType::kBudgeted &&
865*c8dee2aaSAndroid Build Coastguard Worker !fNonpurgeableResources[i]->cacheAccess().hasRefOrCommandBufferUsage() &&
866*c8dee2aaSAndroid Build Coastguard Worker fNewlyPurgeableResourceForValidation != fNonpurgeableResources[i]) {
867*c8dee2aaSAndroid Build Coastguard Worker ++numBudgetedResourcesFlushWillMakePurgeable;
868*c8dee2aaSAndroid Build Coastguard Worker }
869*c8dee2aaSAndroid Build Coastguard Worker stats.update(fNonpurgeableResources[i]);
870*c8dee2aaSAndroid Build Coastguard Worker }
871*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < fPurgeableQueue.count(); ++i) {
872*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fPurgeableQueue.at(i)->resourcePriv().isPurgeable());
873*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(*fPurgeableQueue.at(i)->cacheAccess().accessCacheIndex() == i);
874*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!fPurgeableQueue.at(i)->wasDestroyed());
875*c8dee2aaSAndroid Build Coastguard Worker stats.update(fPurgeableQueue.at(i));
876*c8dee2aaSAndroid Build Coastguard Worker purgeableBytes += fPurgeableQueue.at(i)->gpuMemorySize();
877*c8dee2aaSAndroid Build Coastguard Worker }
878*c8dee2aaSAndroid Build Coastguard Worker
879*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fCount == this->getResourceCount());
880*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fBudgetedCount <= fCount);
881*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fBudgetedBytes <= fBytes);
882*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(stats.fBytes == fBytes);
883*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fNumBudgetedResourcesFlushWillMakePurgeable ==
884*c8dee2aaSAndroid Build Coastguard Worker numBudgetedResourcesFlushWillMakePurgeable);
885*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(stats.fBudgetedBytes == fBudgetedBytes);
886*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(stats.fBudgetedCount == fBudgetedCount);
887*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(purgeableBytes == fPurgeableBytes);
888*c8dee2aaSAndroid Build Coastguard Worker #if GR_CACHE_STATS
889*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fBudgetedHighWaterCount <= fHighWaterCount);
890*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fBudgetedHighWaterBytes <= fHighWaterBytes);
891*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fBytes <= fHighWaterBytes);
892*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fCount <= fHighWaterCount);
893*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fBudgetedBytes <= fBudgetedHighWaterBytes);
894*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fBudgetedCount <= fBudgetedHighWaterCount);
895*c8dee2aaSAndroid Build Coastguard Worker #endif
896*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(stats.fContent == fUniqueHash.count());
897*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(stats.fScratch == fScratchMap.count());
898*c8dee2aaSAndroid Build Coastguard Worker
899*c8dee2aaSAndroid Build Coastguard Worker // This assertion is not currently valid because we can be in recursive notifyCntReachedZero()
900*c8dee2aaSAndroid Build Coastguard Worker // calls. This will be fixed when subresource registration is explicit.
901*c8dee2aaSAndroid Build Coastguard Worker // bool overBudget = budgetedBytes > fMaxBytes || budgetedCount > fMaxCount;
902*c8dee2aaSAndroid Build Coastguard Worker // SkASSERT(!overBudget || locked == count || fPurging);
903*c8dee2aaSAndroid Build Coastguard Worker }
904*c8dee2aaSAndroid Build Coastguard Worker
isInCache(const GrGpuResource * resource) const905*c8dee2aaSAndroid Build Coastguard Worker bool GrResourceCache::isInCache(const GrGpuResource* resource) const {
906*c8dee2aaSAndroid Build Coastguard Worker int index = *resource->cacheAccess().accessCacheIndex();
907*c8dee2aaSAndroid Build Coastguard Worker if (index < 0) {
908*c8dee2aaSAndroid Build Coastguard Worker return false;
909*c8dee2aaSAndroid Build Coastguard Worker }
910*c8dee2aaSAndroid Build Coastguard Worker if (index < fPurgeableQueue.count() && fPurgeableQueue.at(index) == resource) {
911*c8dee2aaSAndroid Build Coastguard Worker return true;
912*c8dee2aaSAndroid Build Coastguard Worker }
913*c8dee2aaSAndroid Build Coastguard Worker if (index < fNonpurgeableResources.size() && fNonpurgeableResources[index] == resource) {
914*c8dee2aaSAndroid Build Coastguard Worker return true;
915*c8dee2aaSAndroid Build Coastguard Worker }
916*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGFAIL("Resource index should be -1 or the resource should be in the cache.");
917*c8dee2aaSAndroid Build Coastguard Worker return false;
918*c8dee2aaSAndroid Build Coastguard Worker }
919*c8dee2aaSAndroid Build Coastguard Worker
920*c8dee2aaSAndroid Build Coastguard Worker #endif // SK_DEBUG
921*c8dee2aaSAndroid Build Coastguard Worker
922*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
923*c8dee2aaSAndroid Build Coastguard Worker
countUniqueKeysWithTag(const char * tag) const924*c8dee2aaSAndroid Build Coastguard Worker int GrResourceCache::countUniqueKeysWithTag(const char* tag) const {
925*c8dee2aaSAndroid Build Coastguard Worker int count = 0;
926*c8dee2aaSAndroid Build Coastguard Worker fUniqueHash.foreach([&](const GrGpuResource& resource){
927*c8dee2aaSAndroid Build Coastguard Worker if (0 == strcmp(tag, resource.getUniqueKey().tag())) {
928*c8dee2aaSAndroid Build Coastguard Worker ++count;
929*c8dee2aaSAndroid Build Coastguard Worker }
930*c8dee2aaSAndroid Build Coastguard Worker });
931*c8dee2aaSAndroid Build Coastguard Worker return count;
932*c8dee2aaSAndroid Build Coastguard Worker }
933*c8dee2aaSAndroid Build Coastguard Worker
changeTimestamp(uint32_t newTimestamp)934*c8dee2aaSAndroid Build Coastguard Worker void GrResourceCache::changeTimestamp(uint32_t newTimestamp) {
935*c8dee2aaSAndroid Build Coastguard Worker fTimestamp = newTimestamp;
936*c8dee2aaSAndroid Build Coastguard Worker }
937*c8dee2aaSAndroid Build Coastguard Worker
visitSurfaces(const std::function<void (const GrSurface *,bool purgeable)> & func) const938*c8dee2aaSAndroid Build Coastguard Worker void GrResourceCache::visitSurfaces(
939*c8dee2aaSAndroid Build Coastguard Worker const std::function<void(const GrSurface*, bool purgeable)>& func) const {
940*c8dee2aaSAndroid Build Coastguard Worker
941*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < fNonpurgeableResources.size(); ++i) {
942*c8dee2aaSAndroid Build Coastguard Worker if (const GrSurface* surf = fNonpurgeableResources[i]->asSurface()) {
943*c8dee2aaSAndroid Build Coastguard Worker func(surf, /* purgeable= */ false);
944*c8dee2aaSAndroid Build Coastguard Worker }
945*c8dee2aaSAndroid Build Coastguard Worker }
946*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < fPurgeableQueue.count(); ++i) {
947*c8dee2aaSAndroid Build Coastguard Worker if (const GrSurface* surf = fPurgeableQueue.at(i)->asSurface()) {
948*c8dee2aaSAndroid Build Coastguard Worker func(surf, /* purgeable= */ true);
949*c8dee2aaSAndroid Build Coastguard Worker }
950*c8dee2aaSAndroid Build Coastguard Worker }
951*c8dee2aaSAndroid Build Coastguard Worker }
952*c8dee2aaSAndroid Build Coastguard Worker
953*c8dee2aaSAndroid Build Coastguard Worker #endif // defined(GPU_TEST_UTILS)
954