blob: d87e1a5b588211fe70716f6cc6cd1024487b23c3 [file] [log] [blame]
bsalomonc8dc1f72014-08-21 13:02:13 -07001
2/*
3 * Copyright 2014 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
bsalomon0ea80f42015-02-11 10:49:59 -080010#include "GrResourceCache.h"
bsalomon3582d3e2015-02-13 14:20:05 -080011#include "GrGpuResourceCacheAccess.h"
bsalomon7775c852014-12-30 12:50:52 -080012#include "SkChecksum.h"
bsalomon71cb0c22014-11-14 12:10:14 -080013#include "SkGr.h"
14#include "SkMessageBus.h"
15
bsalomon23e619c2015-02-06 11:54:28 -080016DECLARE_SKMESSAGEBUS_MESSAGE(GrContentKeyInvalidatedMessage);
bsalomon71cb0c22014-11-14 12:10:14 -080017
18//////////////////////////////////////////////////////////////////////////////
19
bsalomon7775c852014-12-30 12:50:52 -080020GrScratchKey::ResourceType GrScratchKey::GenerateResourceType() {
bsalomon24db3b12015-01-23 04:24:04 -080021 static int32_t gType = INHERITED::kInvalidDomain + 1;
bsalomonfe369ee2014-11-10 11:59:06 -080022
bsalomon7775c852014-12-30 12:50:52 -080023 int32_t type = sk_atomic_inc(&gType);
robertphillips9790a7b2015-01-05 12:29:15 -080024 if (type > SK_MaxU16) {
bsalomon71cb0c22014-11-14 12:10:14 -080025 SkFAIL("Too many Resource Types");
26 }
27
28 return static_cast<ResourceType>(type);
29}
30
bsalomon24db3b12015-01-23 04:24:04 -080031GrContentKey::Domain GrContentKey::GenerateDomain() {
32 static int32_t gDomain = INHERITED::kInvalidDomain + 1;
bsalomon7775c852014-12-30 12:50:52 -080033
bsalomon24db3b12015-01-23 04:24:04 -080034 int32_t domain = sk_atomic_inc(&gDomain);
kkinnunen016dffb2015-01-23 06:43:05 -080035 if (domain > SK_MaxU16) {
bsalomon24db3b12015-01-23 04:24:04 -080036 SkFAIL("Too many Content Key Domains");
bsalomon7775c852014-12-30 12:50:52 -080037 }
bsalomon24db3b12015-01-23 04:24:04 -080038
39 return static_cast<Domain>(domain);
40}
41uint32_t GrResourceKeyHash(const uint32_t* data, size_t size) {
42 return SkChecksum::Compute(data, size);
bsalomon7775c852014-12-30 12:50:52 -080043}
44
bsalomonfe369ee2014-11-10 11:59:06 -080045//////////////////////////////////////////////////////////////////////////////
46
bsalomon0ea80f42015-02-11 10:49:59 -080047class GrResourceCache::AutoValidate : ::SkNoncopyable {
bsalomon71cb0c22014-11-14 12:10:14 -080048public:
bsalomon0ea80f42015-02-11 10:49:59 -080049 AutoValidate(GrResourceCache* cache) : fCache(cache) { cache->validate(); }
bsalomon71cb0c22014-11-14 12:10:14 -080050 ~AutoValidate() { fCache->validate(); }
51private:
bsalomon0ea80f42015-02-11 10:49:59 -080052 GrResourceCache* fCache;
bsalomon71cb0c22014-11-14 12:10:14 -080053};
54
55 //////////////////////////////////////////////////////////////////////////////
56
57static const int kDefaultMaxCount = 2 * (1 << 10);
58static const size_t kDefaultMaxSize = 96 * (1 << 20);
59
bsalomon0ea80f42015-02-11 10:49:59 -080060GrResourceCache::GrResourceCache()
bsalomon9f2d1572015-02-17 11:47:40 -080061 : fTimestamp(0)
62 , fMaxCount(kDefaultMaxCount)
bsalomon71cb0c22014-11-14 12:10:14 -080063 , fMaxBytes(kDefaultMaxSize)
64#if GR_CACHE_STATS
65 , fHighWaterCount(0)
66 , fHighWaterBytes(0)
bsalomondace19e2014-11-17 07:34:06 -080067 , fBudgetedHighWaterCount(0)
68 , fBudgetedHighWaterBytes(0)
bsalomon71cb0c22014-11-14 12:10:14 -080069#endif
70 , fCount(0)
71 , fBytes(0)
bsalomondace19e2014-11-17 07:34:06 -080072 , fBudgetedCount(0)
73 , fBudgetedBytes(0)
bsalomon71cb0c22014-11-14 12:10:14 -080074 , fOverBudgetCB(NULL)
75 , fOverBudgetData(NULL) {
76}
77
bsalomon0ea80f42015-02-11 10:49:59 -080078GrResourceCache::~GrResourceCache() {
bsalomonc8dc1f72014-08-21 13:02:13 -070079 this->releaseAll();
80}
81
bsalomon0ea80f42015-02-11 10:49:59 -080082void GrResourceCache::setLimits(int count, size_t bytes) {
bsalomon71cb0c22014-11-14 12:10:14 -080083 fMaxCount = count;
84 fMaxBytes = bytes;
85 this->purgeAsNeeded();
86}
87
bsalomon0ea80f42015-02-11 10:49:59 -080088void GrResourceCache::insertResource(GrGpuResource* resource) {
bsalomon49f085d2014-09-05 13:34:00 -070089 SkASSERT(resource);
bsalomonc8dc1f72014-08-21 13:02:13 -070090 SkASSERT(!resource->wasDestroyed());
bsalomon16961262014-08-26 14:01:07 -070091 SkASSERT(!this->isInCache(resource));
bsalomonc8dc1f72014-08-21 13:02:13 -070092 fResources.addToHead(resource);
bsalomon71cb0c22014-11-14 12:10:14 -080093
bsalomondace19e2014-11-17 07:34:06 -080094 size_t size = resource->gpuMemorySize();
bsalomonc8dc1f72014-08-21 13:02:13 -070095 ++fCount;
bsalomon84c8e622014-11-17 09:33:27 -080096 fBytes += size;
bsalomon82b1d622014-11-14 13:59:57 -080097#if GR_CACHE_STATS
98 fHighWaterCount = SkTMax(fCount, fHighWaterCount);
99 fHighWaterBytes = SkTMax(fBytes, fHighWaterBytes);
100#endif
bsalomon3582d3e2015-02-13 14:20:05 -0800101 if (resource->resourcePriv().isBudgeted()) {
bsalomondace19e2014-11-17 07:34:06 -0800102 ++fBudgetedCount;
103 fBudgetedBytes += size;
104#if GR_CACHE_STATS
105 fBudgetedHighWaterCount = SkTMax(fBudgetedCount, fBudgetedHighWaterCount);
106 fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes);
107#endif
108 }
bsalomon3582d3e2015-02-13 14:20:05 -0800109 if (resource->resourcePriv().getScratchKey().isValid()) {
bsalomon84c8e622014-11-17 09:33:27 -0800110 SkASSERT(!resource->cacheAccess().isWrapped());
bsalomon3582d3e2015-02-13 14:20:05 -0800111 fScratchMap.insert(resource->resourcePriv().getScratchKey(), resource);
bsalomon744998e2014-08-28 09:54:34 -0700112 }
bsalomon9f2d1572015-02-17 11:47:40 -0800113
114 resource->cacheAccess().setTimestamp(fTimestamp++);
115
bsalomon71cb0c22014-11-14 12:10:14 -0800116 this->purgeAsNeeded();
bsalomonc8dc1f72014-08-21 13:02:13 -0700117}
118
bsalomon0ea80f42015-02-11 10:49:59 -0800119void GrResourceCache::removeResource(GrGpuResource* resource) {
bsalomon9f2d1572015-02-17 11:47:40 -0800120 this->validate();
bsalomon16961262014-08-26 14:01:07 -0700121 SkASSERT(this->isInCache(resource));
bsalomondace19e2014-11-17 07:34:06 -0800122
bsalomon9f2d1572015-02-17 11:47:40 -0800123 if (resource->isPurgeable()) {
124 fPurgeableQueue.remove(resource);
125 }
126
bsalomondace19e2014-11-17 07:34:06 -0800127 size_t size = resource->gpuMemorySize();
128 --fCount;
129 fBytes -= size;
bsalomon3582d3e2015-02-13 14:20:05 -0800130 if (resource->resourcePriv().isBudgeted()) {
bsalomondace19e2014-11-17 07:34:06 -0800131 --fBudgetedCount;
132 fBudgetedBytes -= size;
133 }
134
135 fResources.remove(resource);
bsalomon3582d3e2015-02-13 14:20:05 -0800136 if (resource->resourcePriv().getScratchKey().isValid()) {
137 fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource);
bsalomon744998e2014-08-28 09:54:34 -0700138 }
bsalomon563ff602015-02-02 17:25:26 -0800139 if (resource->getContentKey().isValid()) {
140 fContentHash.remove(resource->getContentKey());
bsalomon8b79d232014-11-10 10:19:06 -0800141 }
bsalomonb436ed62014-11-17 12:15:56 -0800142 this->validate();
bsalomonc8dc1f72014-08-21 13:02:13 -0700143}
144
bsalomon0ea80f42015-02-11 10:49:59 -0800145void GrResourceCache::abandonAll() {
bsalomon71cb0c22014-11-14 12:10:14 -0800146 AutoValidate av(this);
147
bsalomonc8dc1f72014-08-21 13:02:13 -0700148 while (GrGpuResource* head = fResources.head()) {
149 SkASSERT(!head->wasDestroyed());
bsalomon12299ab2014-11-14 13:33:09 -0800150 head->cacheAccess().abandon();
bsalomonc8dc1f72014-08-21 13:02:13 -0700151 // abandon should have already removed this from the list.
152 SkASSERT(head != fResources.head());
153 }
bsalomon744998e2014-08-28 09:54:34 -0700154 SkASSERT(!fScratchMap.count());
bsalomon8b79d232014-11-10 10:19:06 -0800155 SkASSERT(!fContentHash.count());
bsalomonc8dc1f72014-08-21 13:02:13 -0700156 SkASSERT(!fCount);
bsalomondace19e2014-11-17 07:34:06 -0800157 SkASSERT(!fBytes);
158 SkASSERT(!fBudgetedCount);
159 SkASSERT(!fBudgetedBytes);
bsalomonc8dc1f72014-08-21 13:02:13 -0700160}
161
bsalomon0ea80f42015-02-11 10:49:59 -0800162void GrResourceCache::releaseAll() {
bsalomon71cb0c22014-11-14 12:10:14 -0800163 AutoValidate av(this);
164
bsalomonc8dc1f72014-08-21 13:02:13 -0700165 while (GrGpuResource* head = fResources.head()) {
166 SkASSERT(!head->wasDestroyed());
bsalomon12299ab2014-11-14 13:33:09 -0800167 head->cacheAccess().release();
bsalomonc8dc1f72014-08-21 13:02:13 -0700168 // release should have already removed this from the list.
169 SkASSERT(head != fResources.head());
170 }
bsalomon744998e2014-08-28 09:54:34 -0700171 SkASSERT(!fScratchMap.count());
bsalomonc8dc1f72014-08-21 13:02:13 -0700172 SkASSERT(!fCount);
bsalomondace19e2014-11-17 07:34:06 -0800173 SkASSERT(!fBytes);
174 SkASSERT(!fBudgetedCount);
175 SkASSERT(!fBudgetedBytes);
bsalomonc8dc1f72014-08-21 13:02:13 -0700176}
bsalomonbcf0a522014-10-08 08:40:09 -0700177
bsalomon0ea80f42015-02-11 10:49:59 -0800178class GrResourceCache::AvailableForScratchUse {
bsalomonbcf0a522014-10-08 08:40:09 -0700179public:
bsalomon000f8292014-10-15 19:04:14 -0700180 AvailableForScratchUse(bool rejectPendingIO) : fRejectPendingIO(rejectPendingIO) { }
bsalomonbcf0a522014-10-08 08:40:09 -0700181
182 bool operator()(const GrGpuResource* resource) const {
bsalomon12299ab2014-11-14 13:33:09 -0800183 if (resource->internalHasRef() || !resource->cacheAccess().isScratch()) {
bsalomon000f8292014-10-15 19:04:14 -0700184 return false;
bsalomonbcf0a522014-10-08 08:40:09 -0700185 }
bsalomon000f8292014-10-15 19:04:14 -0700186 return !fRejectPendingIO || !resource->internalHasPendingIO();
bsalomonbcf0a522014-10-08 08:40:09 -0700187 }
bsalomon1e2530b2014-10-09 09:57:18 -0700188
bsalomonbcf0a522014-10-08 08:40:09 -0700189private:
bsalomon000f8292014-10-15 19:04:14 -0700190 bool fRejectPendingIO;
bsalomonbcf0a522014-10-08 08:40:09 -0700191};
192
bsalomon0ea80f42015-02-11 10:49:59 -0800193GrGpuResource* GrResourceCache::findAndRefScratchResource(const GrScratchKey& scratchKey,
bsalomon9f2d1572015-02-17 11:47:40 -0800194 uint32_t flags) {
bsalomon7775c852014-12-30 12:50:52 -0800195 SkASSERT(scratchKey.isValid());
bsalomon000f8292014-10-15 19:04:14 -0700196
bsalomon71cb0c22014-11-14 12:10:14 -0800197 GrGpuResource* resource;
bsalomon000f8292014-10-15 19:04:14 -0700198 if (flags & (kPreferNoPendingIO_ScratchFlag | kRequireNoPendingIO_ScratchFlag)) {
bsalomon71cb0c22014-11-14 12:10:14 -0800199 resource = fScratchMap.find(scratchKey, AvailableForScratchUse(true));
bsalomon000f8292014-10-15 19:04:14 -0700200 if (resource) {
bsalomon9f2d1572015-02-17 11:47:40 -0800201 this->refAndMakeResourceMRU(resource);
bsalomonb436ed62014-11-17 12:15:56 -0800202 this->validate();
203 return resource;
bsalomon000f8292014-10-15 19:04:14 -0700204 } else if (flags & kRequireNoPendingIO_ScratchFlag) {
205 return NULL;
206 }
207 // TODO: fail here when kPrefer is specified, we didn't find a resource without pending io,
208 // but there is still space in our budget for the resource.
209 }
bsalomon71cb0c22014-11-14 12:10:14 -0800210 resource = fScratchMap.find(scratchKey, AvailableForScratchUse(false));
211 if (resource) {
bsalomon9f2d1572015-02-17 11:47:40 -0800212 this->refAndMakeResourceMRU(resource);
bsalomonb436ed62014-11-17 12:15:56 -0800213 this->validate();
bsalomon71cb0c22014-11-14 12:10:14 -0800214 }
215 return resource;
bsalomonbcf0a522014-10-08 08:40:09 -0700216}
bsalomon8b79d232014-11-10 10:19:06 -0800217
bsalomon0ea80f42015-02-11 10:49:59 -0800218void GrResourceCache::willRemoveScratchKey(const GrGpuResource* resource) {
bsalomon3582d3e2015-02-13 14:20:05 -0800219 SkASSERT(resource->resourcePriv().getScratchKey().isValid());
220 fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource);
bsalomon10e23ca2014-11-25 05:52:06 -0800221}
222
bsalomon0ea80f42015-02-11 10:49:59 -0800223void GrResourceCache::willRemoveContentKey(const GrGpuResource* resource) {
bsalomon23e619c2015-02-06 11:54:28 -0800224 // Someone has a ref to this resource in order to invalidate it. When the ref count reaches
225 // zero we will get a notifyPurgable() and figure out what to do with it.
226 SkASSERT(resource->getContentKey().isValid());
227 fContentHash.remove(resource->getContentKey());
228}
229
bsalomon0ea80f42015-02-11 10:49:59 -0800230bool GrResourceCache::didSetContentKey(GrGpuResource* resource) {
bsalomon8b79d232014-11-10 10:19:06 -0800231 SkASSERT(resource);
bsalomon71cb0c22014-11-14 12:10:14 -0800232 SkASSERT(this->isInCache(resource));
bsalomon563ff602015-02-02 17:25:26 -0800233 SkASSERT(resource->getContentKey().isValid());
bsalomon8b79d232014-11-10 10:19:06 -0800234
bsalomon563ff602015-02-02 17:25:26 -0800235 GrGpuResource* res = fContentHash.find(resource->getContentKey());
bsalomon8b79d232014-11-10 10:19:06 -0800236 if (NULL != res) {
237 return false;
238 }
239
240 fContentHash.add(resource);
bsalomon71cb0c22014-11-14 12:10:14 -0800241 this->validate();
bsalomon8b79d232014-11-10 10:19:06 -0800242 return true;
243}
bsalomon71cb0c22014-11-14 12:10:14 -0800244
bsalomon9f2d1572015-02-17 11:47:40 -0800245void GrResourceCache::refAndMakeResourceMRU(GrGpuResource* resource) {
bsalomon71cb0c22014-11-14 12:10:14 -0800246 SkASSERT(resource);
247 SkASSERT(this->isInCache(resource));
bsalomon9f2d1572015-02-17 11:47:40 -0800248 if (resource->isPurgeable()) {
249 // It's about to become unpurgeable.
250 fPurgeableQueue.remove(resource);
251 }
252 resource->ref();
253 resource->cacheAccess().setTimestamp(fTimestamp++);
254 SkASSERT(!resource->isPurgeable());
bsalomon71cb0c22014-11-14 12:10:14 -0800255}
256
bsalomon0ea80f42015-02-11 10:49:59 -0800257void GrResourceCache::notifyPurgeable(GrGpuResource* resource) {
bsalomon71cb0c22014-11-14 12:10:14 -0800258 SkASSERT(resource);
259 SkASSERT(this->isInCache(resource));
bsalomon63c992f2015-01-23 12:47:59 -0800260 SkASSERT(resource->isPurgeable());
bsalomon71cb0c22014-11-14 12:10:14 -0800261
bsalomon9f2d1572015-02-17 11:47:40 -0800262 SkASSERT(-1 == *resource->cacheAccess().accessCacheIndex());
263 fPurgeableQueue.insert(resource);
bsalomon71cb0c22014-11-14 12:10:14 -0800264
bsalomon9f2d1572015-02-17 11:47:40 -0800265 if (!resource->resourcePriv().isBudgeted()) {
bsalomonc2f35b72015-01-23 07:19:22 -0800266 // Check whether this resource could still be used as a scratch resource.
bsalomon9f2d1572015-02-17 11:47:40 -0800267 if (!resource->cacheAccess().isWrapped() &&
268 resource->resourcePriv().getScratchKey().isValid()) {
bsalomonc2f35b72015-01-23 07:19:22 -0800269 // We won't purge an existing resource to make room for this one.
270 bool underBudget = fBudgetedCount < fMaxCount &&
271 fBudgetedBytes + resource->gpuMemorySize() <= fMaxBytes;
272 if (underBudget) {
bsalomon3582d3e2015-02-13 14:20:05 -0800273 resource->resourcePriv().makeBudgeted();
bsalomon9f2d1572015-02-17 11:47:40 -0800274 return;
bsalomonc2f35b72015-01-23 07:19:22 -0800275 }
bsalomonc2f35b72015-01-23 07:19:22 -0800276 }
277 } else {
bsalomon9f2d1572015-02-17 11:47:40 -0800278 // Purge the resource immediately if we're over budget
bsalomonc2f35b72015-01-23 07:19:22 -0800279 bool overBudget = fBudgetedCount > fMaxCount || fBudgetedBytes > fMaxBytes;
bsalomon71cb0c22014-11-14 12:10:14 -0800280
bsalomonc2f35b72015-01-23 07:19:22 -0800281 // Also purge if the resource has neither a valid scratch key nor a content key.
bsalomon3582d3e2015-02-13 14:20:05 -0800282 bool noKey = !resource->resourcePriv().getScratchKey().isValid() &&
bsalomon9f2d1572015-02-17 11:47:40 -0800283 !resource->getContentKey().isValid();
284 if (!overBudget && !noKey) {
285 return;
bsalomonc2f35b72015-01-23 07:19:22 -0800286 }
287 }
bsalomondace19e2014-11-17 07:34:06 -0800288
bsalomon9f2d1572015-02-17 11:47:40 -0800289 SkDEBUGCODE(int beforeCount = fCount;)
290 resource->cacheAccess().release();
291 // We should at least free this resource, perhaps dependent resources as well.
292 SkASSERT(fCount < beforeCount);
bsalomon71cb0c22014-11-14 12:10:14 -0800293 this->validate();
294}
295
bsalomon0ea80f42015-02-11 10:49:59 -0800296void GrResourceCache::didChangeGpuMemorySize(const GrGpuResource* resource, size_t oldSize) {
bsalomon71cb0c22014-11-14 12:10:14 -0800297 // SkASSERT(!fPurging); GrPathRange increases size during flush. :(
298 SkASSERT(resource);
299 SkASSERT(this->isInCache(resource));
300
bsalomondace19e2014-11-17 07:34:06 -0800301 ptrdiff_t delta = resource->gpuMemorySize() - oldSize;
302
303 fBytes += delta;
bsalomon82b1d622014-11-14 13:59:57 -0800304#if GR_CACHE_STATS
305 fHighWaterBytes = SkTMax(fBytes, fHighWaterBytes);
306#endif
bsalomon3582d3e2015-02-13 14:20:05 -0800307 if (resource->resourcePriv().isBudgeted()) {
bsalomondace19e2014-11-17 07:34:06 -0800308 fBudgetedBytes += delta;
309#if GR_CACHE_STATS
310 fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes);
311#endif
312 }
bsalomon71cb0c22014-11-14 12:10:14 -0800313
314 this->purgeAsNeeded();
315 this->validate();
316}
317
bsalomon0ea80f42015-02-11 10:49:59 -0800318void GrResourceCache::didChangeBudgetStatus(GrGpuResource* resource) {
bsalomon84c8e622014-11-17 09:33:27 -0800319 SkASSERT(resource);
320 SkASSERT(this->isInCache(resource));
321
322 size_t size = resource->gpuMemorySize();
323
bsalomon3582d3e2015-02-13 14:20:05 -0800324 if (resource->resourcePriv().isBudgeted()) {
bsalomon84c8e622014-11-17 09:33:27 -0800325 ++fBudgetedCount;
326 fBudgetedBytes += size;
bsalomonafe30052015-01-16 07:32:33 -0800327#if GR_CACHE_STATS
328 fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes);
329 fBudgetedHighWaterCount = SkTMax(fBudgetedCount, fBudgetedHighWaterCount);
330#endif
bsalomon84c8e622014-11-17 09:33:27 -0800331 this->purgeAsNeeded();
332 } else {
333 --fBudgetedCount;
334 fBudgetedBytes -= size;
335 }
336
337 this->validate();
338}
339
bsalomon0ea80f42015-02-11 10:49:59 -0800340void GrResourceCache::internalPurgeAsNeeded() {
bsalomondace19e2014-11-17 07:34:06 -0800341 SkASSERT(fBudgetedCount > fMaxCount || fBudgetedBytes > fMaxBytes);
bsalomon71cb0c22014-11-14 12:10:14 -0800342
bsalomon9f2d1572015-02-17 11:47:40 -0800343 bool stillOverbudget = true;
344 while (fPurgeableQueue.count()) {
345 GrGpuResource* resource = fPurgeableQueue.peek();
346 SkASSERT(resource->isPurgeable());
347 resource->cacheAccess().release();
348 if (fBudgetedCount <= fMaxCount && fBudgetedBytes <= fMaxBytes) {
349 stillOverbudget = false;
350 break;
bsalomon71cb0c22014-11-14 12:10:14 -0800351 }
bsalomon9f2d1572015-02-17 11:47:40 -0800352 }
bsalomon71cb0c22014-11-14 12:10:14 -0800353
bsalomonb436ed62014-11-17 12:15:56 -0800354 this->validate();
bsalomon9f2d1572015-02-17 11:47:40 -0800355
356 if (stillOverbudget) {
357 // Despite the purge we're still over budget. Call our over budget callback. If this frees
358 // any resources then we'll get notifyPurgeable() calls and take appropriate action.
359 (*fOverBudgetCB)(fOverBudgetData);
360 this->validate();
361 }
bsalomon71cb0c22014-11-14 12:10:14 -0800362}
363
bsalomon0ea80f42015-02-11 10:49:59 -0800364void GrResourceCache::purgeAllUnlocked() {
bsalomon9f2d1572015-02-17 11:47:40 -0800365 // We could disable maintaining the heap property here, but it would add a lot of complexity.
366 // Moreover, this is rarely called.
367 while (fPurgeableQueue.count()) {
368 GrGpuResource* resource = fPurgeableQueue.peek();
369 SkASSERT(resource->isPurgeable());
370 resource->cacheAccess().release();
371 }
bsalomon71cb0c22014-11-14 12:10:14 -0800372
bsalomonb436ed62014-11-17 12:15:56 -0800373 this->validate();
bsalomon71cb0c22014-11-14 12:10:14 -0800374}
375
bsalomon0ea80f42015-02-11 10:49:59 -0800376void GrResourceCache::processInvalidContentKeys(
bsalomon23e619c2015-02-06 11:54:28 -0800377 const SkTArray<GrContentKeyInvalidatedMessage>& msgs) {
378 for (int i = 0; i < msgs.count(); ++i) {
379 GrGpuResource* resource = this->findAndRefContentResource(msgs[i].key());
380 if (resource) {
bsalomon3582d3e2015-02-13 14:20:05 -0800381 resource->resourcePriv().removeContentKey();
bsalomon23e619c2015-02-06 11:54:28 -0800382 resource->unref(); // will call notifyPurgeable, if it is indeed now purgeable.
383 }
384 }
385}
386
bsalomon71cb0c22014-11-14 12:10:14 -0800387#ifdef SK_DEBUG
bsalomon0ea80f42015-02-11 10:49:59 -0800388void GrResourceCache::validate() const {
bsalomonc2f35b72015-01-23 07:19:22 -0800389 // Reduce the frequency of validations for large resource counts.
390 static SkRandom gRandom;
391 int mask = (SkNextPow2(fCount + 1) >> 5) - 1;
392 if (~mask && (gRandom.nextU() & mask)) {
393 return;
394 }
395
bsalomon71cb0c22014-11-14 12:10:14 -0800396 size_t bytes = 0;
397 int count = 0;
bsalomondace19e2014-11-17 07:34:06 -0800398 int budgetedCount = 0;
399 size_t budgetedBytes = 0;
bsalomon71cb0c22014-11-14 12:10:14 -0800400 int locked = 0;
401 int scratch = 0;
402 int couldBeScratch = 0;
403 int content = 0;
404
405 ResourceList::Iter iter;
406 GrGpuResource* resource = iter.init(fResources, ResourceList::Iter::kHead_IterStart);
407 for ( ; resource; resource = iter.next()) {
408 bytes += resource->gpuMemorySize();
409 ++count;
410
bsalomon63c992f2015-01-23 12:47:59 -0800411 if (!resource->isPurgeable()) {
bsalomon71cb0c22014-11-14 12:10:14 -0800412 ++locked;
413 }
414
415 if (resource->cacheAccess().isScratch()) {
bsalomon563ff602015-02-02 17:25:26 -0800416 SkASSERT(!resource->getContentKey().isValid());
bsalomon71cb0c22014-11-14 12:10:14 -0800417 ++scratch;
bsalomon3582d3e2015-02-13 14:20:05 -0800418 SkASSERT(fScratchMap.countForKey(resource->resourcePriv().getScratchKey()));
bsalomondace19e2014-11-17 07:34:06 -0800419 SkASSERT(!resource->cacheAccess().isWrapped());
bsalomon3582d3e2015-02-13 14:20:05 -0800420 } else if (resource->resourcePriv().getScratchKey().isValid()) {
421 SkASSERT(!resource->resourcePriv().isBudgeted() ||
bsalomon563ff602015-02-02 17:25:26 -0800422 resource->getContentKey().isValid());
bsalomon71cb0c22014-11-14 12:10:14 -0800423 ++couldBeScratch;
bsalomon3582d3e2015-02-13 14:20:05 -0800424 SkASSERT(fScratchMap.countForKey(resource->resourcePriv().getScratchKey()));
bsalomondace19e2014-11-17 07:34:06 -0800425 SkASSERT(!resource->cacheAccess().isWrapped());
bsalomon71cb0c22014-11-14 12:10:14 -0800426 }
bsalomon563ff602015-02-02 17:25:26 -0800427 const GrContentKey& contentKey = resource->getContentKey();
bsalomon24db3b12015-01-23 04:24:04 -0800428 if (contentKey.isValid()) {
bsalomon71cb0c22014-11-14 12:10:14 -0800429 ++content;
bsalomon24db3b12015-01-23 04:24:04 -0800430 SkASSERT(fContentHash.find(contentKey) == resource);
bsalomondace19e2014-11-17 07:34:06 -0800431 SkASSERT(!resource->cacheAccess().isWrapped());
bsalomon3582d3e2015-02-13 14:20:05 -0800432 SkASSERT(resource->resourcePriv().isBudgeted());
bsalomondace19e2014-11-17 07:34:06 -0800433 }
434
bsalomon3582d3e2015-02-13 14:20:05 -0800435 if (resource->resourcePriv().isBudgeted()) {
bsalomondace19e2014-11-17 07:34:06 -0800436 ++budgetedCount;
437 budgetedBytes += resource->gpuMemorySize();
bsalomon71cb0c22014-11-14 12:10:14 -0800438 }
bsalomon9f2d1572015-02-17 11:47:40 -0800439
440 if (!resource->isPurgeable()) {
441 SkASSERT(-1 == *resource->cacheAccess().accessCacheIndex());
442 }
bsalomon71cb0c22014-11-14 12:10:14 -0800443 }
444
bsalomon9f2d1572015-02-17 11:47:40 -0800445 for (int i = 0; i < fPurgeableQueue.count(); ++i) {
446 SkASSERT(fPurgeableQueue.at(i)->isPurgeable());
447 }
448
449 SkASSERT(fCount - locked == fPurgeableQueue.count());
bsalomondace19e2014-11-17 07:34:06 -0800450 SkASSERT(fBudgetedCount <= fCount);
451 SkASSERT(fBudgetedBytes <= fBudgetedBytes);
bsalomon71cb0c22014-11-14 12:10:14 -0800452 SkASSERT(bytes == fBytes);
453 SkASSERT(count == fCount);
bsalomondace19e2014-11-17 07:34:06 -0800454 SkASSERT(budgetedBytes == fBudgetedBytes);
455 SkASSERT(budgetedCount == fBudgetedCount);
bsalomon71cb0c22014-11-14 12:10:14 -0800456#if GR_CACHE_STATS
bsalomondace19e2014-11-17 07:34:06 -0800457 SkASSERT(fBudgetedHighWaterCount <= fHighWaterCount);
458 SkASSERT(fBudgetedHighWaterBytes <= fHighWaterBytes);
bsalomon71cb0c22014-11-14 12:10:14 -0800459 SkASSERT(bytes <= fHighWaterBytes);
460 SkASSERT(count <= fHighWaterCount);
bsalomondace19e2014-11-17 07:34:06 -0800461 SkASSERT(budgetedBytes <= fBudgetedHighWaterBytes);
462 SkASSERT(budgetedCount <= fBudgetedHighWaterCount);
bsalomon71cb0c22014-11-14 12:10:14 -0800463#endif
464 SkASSERT(content == fContentHash.count());
465 SkASSERT(scratch + couldBeScratch == fScratchMap.count());
466
bsalomon63c992f2015-01-23 12:47:59 -0800467 // This assertion is not currently valid because we can be in recursive notifyIsPurgeable()
bsalomon12299ab2014-11-14 13:33:09 -0800468 // calls. This will be fixed when subresource registration is explicit.
bsalomondace19e2014-11-17 07:34:06 -0800469 // bool overBudget = budgetedBytes > fMaxBytes || budgetedCount > fMaxCount;
bsalomon12299ab2014-11-14 13:33:09 -0800470 // SkASSERT(!overBudget || locked == count || fPurging);
bsalomon71cb0c22014-11-14 12:10:14 -0800471}
472#endif