blob: 529f87c124880bbefd0c724bd2e48016841d4cd9 [file] [log] [blame]
bsalomonc8dc1f72014-08-21 13:02:13 -07001/*
2 * Copyright 2014 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8
bsalomon0ea80f42015-02-11 10:49:59 -08009#include "GrResourceCache.h"
robertphillips28a838e2016-06-23 14:07:00 -070010
11#include "GrCaps.h"
bsalomon3582d3e2015-02-13 14:20:05 -080012#include "GrGpuResourceCacheAccess.h"
hendrikw876c3132015-03-04 10:33:49 -080013#include "GrTracing.h"
bsalomon71cb0c22014-11-14 12:10:14 -080014#include "SkGr.h"
15#include "SkMessageBus.h"
mtklein4e976072016-08-08 09:06:27 -070016#include "SkOpts.h"
bsalomonddf30e62015-02-19 11:38:44 -080017#include "SkTSort.h"
bsalomon71cb0c22014-11-14 12:10:14 -080018
bsalomon8718aaf2015-02-19 07:24:21 -080019DECLARE_SKMESSAGEBUS_MESSAGE(GrUniqueKeyInvalidatedMessage);
bsalomon71cb0c22014-11-14 12:10:14 -080020
21//////////////////////////////////////////////////////////////////////////////
22
bsalomon7775c852014-12-30 12:50:52 -080023GrScratchKey::ResourceType GrScratchKey::GenerateResourceType() {
bsalomon24db3b12015-01-23 04:24:04 -080024 static int32_t gType = INHERITED::kInvalidDomain + 1;
bsalomonfe369ee2014-11-10 11:59:06 -080025
bsalomon7775c852014-12-30 12:50:52 -080026 int32_t type = sk_atomic_inc(&gType);
robertphillips9790a7b2015-01-05 12:29:15 -080027 if (type > SK_MaxU16) {
bsalomon71cb0c22014-11-14 12:10:14 -080028 SkFAIL("Too many Resource Types");
29 }
30
31 return static_cast<ResourceType>(type);
32}
33
bsalomon8718aaf2015-02-19 07:24:21 -080034GrUniqueKey::Domain GrUniqueKey::GenerateDomain() {
bsalomon24db3b12015-01-23 04:24:04 -080035 static int32_t gDomain = INHERITED::kInvalidDomain + 1;
bsalomon7775c852014-12-30 12:50:52 -080036
bsalomon24db3b12015-01-23 04:24:04 -080037 int32_t domain = sk_atomic_inc(&gDomain);
kkinnunen016dffb2015-01-23 06:43:05 -080038 if (domain > SK_MaxU16) {
bsalomon8718aaf2015-02-19 07:24:21 -080039 SkFAIL("Too many GrUniqueKey Domains");
bsalomon7775c852014-12-30 12:50:52 -080040 }
bsalomon24db3b12015-01-23 04:24:04 -080041
42 return static_cast<Domain>(domain);
43}
bsalomon3f324322015-04-08 11:01:54 -070044
bsalomon24db3b12015-01-23 04:24:04 -080045uint32_t GrResourceKeyHash(const uint32_t* data, size_t size) {
mtklein4e976072016-08-08 09:06:27 -070046 return SkOpts::hash(data, size);
bsalomon7775c852014-12-30 12:50:52 -080047}
48
bsalomonfe369ee2014-11-10 11:59:06 -080049//////////////////////////////////////////////////////////////////////////////
50
bsalomon0ea80f42015-02-11 10:49:59 -080051class GrResourceCache::AutoValidate : ::SkNoncopyable {
bsalomon71cb0c22014-11-14 12:10:14 -080052public:
bsalomon0ea80f42015-02-11 10:49:59 -080053 AutoValidate(GrResourceCache* cache) : fCache(cache) { cache->validate(); }
bsalomon71cb0c22014-11-14 12:10:14 -080054 ~AutoValidate() { fCache->validate(); }
55private:
bsalomon0ea80f42015-02-11 10:49:59 -080056 GrResourceCache* fCache;
bsalomon71cb0c22014-11-14 12:10:14 -080057};
58
59 //////////////////////////////////////////////////////////////////////////////
60
bsalomon71cb0c22014-11-14 12:10:14 -080061
robertphillips63926682015-08-20 09:39:02 -070062GrResourceCache::GrResourceCache(const GrCaps* caps)
bsalomon9f2d1572015-02-17 11:47:40 -080063 : fTimestamp(0)
64 , fMaxCount(kDefaultMaxCount)
bsalomon71cb0c22014-11-14 12:10:14 -080065 , fMaxBytes(kDefaultMaxSize)
bsalomon3f324322015-04-08 11:01:54 -070066 , fMaxUnusedFlushes(kDefaultMaxUnusedFlushes)
bsalomon71cb0c22014-11-14 12:10:14 -080067#if GR_CACHE_STATS
68 , fHighWaterCount(0)
69 , fHighWaterBytes(0)
bsalomondace19e2014-11-17 07:34:06 -080070 , fBudgetedHighWaterCount(0)
71 , fBudgetedHighWaterBytes(0)
bsalomon71cb0c22014-11-14 12:10:14 -080072#endif
bsalomon71cb0c22014-11-14 12:10:14 -080073 , fBytes(0)
bsalomondace19e2014-11-17 07:34:06 -080074 , fBudgetedCount(0)
75 , fBudgetedBytes(0)
bsalomonb77a9072016-09-07 10:02:04 -070076 , fRequestFlush(false)
halcanary96fcdcc2015-08-27 07:41:13 -070077 , fFlushTimestamps(nullptr)
robertphillips63926682015-08-20 09:39:02 -070078 , fLastFlushTimestampIndex(0)
79 , fPreferVRAMUseOverFlushes(caps->preferVRAMUseOverFlushes()) {
bsalomonf320e042015-02-17 15:09:34 -080080 SkDEBUGCODE(fCount = 0;)
halcanary96fcdcc2015-08-27 07:41:13 -070081 SkDEBUGCODE(fNewlyPurgeableResourceForValidation = nullptr;)
bsalomon3f324322015-04-08 11:01:54 -070082 this->resetFlushTimestamps();
bsalomon71cb0c22014-11-14 12:10:14 -080083}
84
bsalomon0ea80f42015-02-11 10:49:59 -080085GrResourceCache::~GrResourceCache() {
bsalomonc8dc1f72014-08-21 13:02:13 -070086 this->releaseAll();
halcanary385fe4d2015-08-26 13:07:48 -070087 delete[] fFlushTimestamps;
bsalomonc8dc1f72014-08-21 13:02:13 -070088}
89
bsalomon3f324322015-04-08 11:01:54 -070090void GrResourceCache::setLimits(int count, size_t bytes, int maxUnusedFlushes) {
bsalomon71cb0c22014-11-14 12:10:14 -080091 fMaxCount = count;
92 fMaxBytes = bytes;
bsalomon3f324322015-04-08 11:01:54 -070093 fMaxUnusedFlushes = maxUnusedFlushes;
94 this->resetFlushTimestamps();
bsalomon71cb0c22014-11-14 12:10:14 -080095 this->purgeAsNeeded();
96}
97
bsalomon3f324322015-04-08 11:01:54 -070098void GrResourceCache::resetFlushTimestamps() {
halcanary385fe4d2015-08-26 13:07:48 -070099 delete[] fFlushTimestamps;
bsalomon3f324322015-04-08 11:01:54 -0700100
101 // We assume this number is a power of two when wrapping indices into the timestamp array.
102 fMaxUnusedFlushes = SkNextPow2(fMaxUnusedFlushes);
103
104 // Since our implementation is to store the timestamps of the last fMaxUnusedFlushes flush calls
105 // we just turn the feature off if that array would be large.
106 static const int kMaxSupportedTimestampHistory = 128;
107
108 if (fMaxUnusedFlushes > kMaxSupportedTimestampHistory) {
halcanary96fcdcc2015-08-27 07:41:13 -0700109 fFlushTimestamps = nullptr;
bsalomon3f324322015-04-08 11:01:54 -0700110 return;
111 }
112
halcanary385fe4d2015-08-26 13:07:48 -0700113 fFlushTimestamps = new uint32_t[fMaxUnusedFlushes];
bsalomon3f324322015-04-08 11:01:54 -0700114 fLastFlushTimestampIndex = 0;
115 // Set all the historical flush timestamps to initially be at the beginning of time (timestamp
116 // 0).
117 sk_bzero(fFlushTimestamps, fMaxUnusedFlushes * sizeof(uint32_t));
118}
119
bsalomon0ea80f42015-02-11 10:49:59 -0800120void GrResourceCache::insertResource(GrGpuResource* resource) {
bsalomon49f085d2014-09-05 13:34:00 -0700121 SkASSERT(resource);
bsalomon16961262014-08-26 14:01:07 -0700122 SkASSERT(!this->isInCache(resource));
bsalomonf320e042015-02-17 15:09:34 -0800123 SkASSERT(!resource->wasDestroyed());
124 SkASSERT(!resource->isPurgeable());
bsalomonddf30e62015-02-19 11:38:44 -0800125
126 // We must set the timestamp before adding to the array in case the timestamp wraps and we wind
127 // up iterating over all the resources that already have timestamps.
128 resource->cacheAccess().setTimestamp(this->getNextTimestamp());
129
bsalomonf320e042015-02-17 15:09:34 -0800130 this->addToNonpurgeableArray(resource);
bsalomon71cb0c22014-11-14 12:10:14 -0800131
bsalomondace19e2014-11-17 07:34:06 -0800132 size_t size = resource->gpuMemorySize();
bsalomonf320e042015-02-17 15:09:34 -0800133 SkDEBUGCODE(++fCount;)
bsalomon84c8e622014-11-17 09:33:27 -0800134 fBytes += size;
bsalomon82b1d622014-11-14 13:59:57 -0800135#if GR_CACHE_STATS
bsalomonf320e042015-02-17 15:09:34 -0800136 fHighWaterCount = SkTMax(this->getResourceCount(), fHighWaterCount);
bsalomon82b1d622014-11-14 13:59:57 -0800137 fHighWaterBytes = SkTMax(fBytes, fHighWaterBytes);
138#endif
bsalomon5ec26ae2016-02-25 08:33:02 -0800139 if (SkBudgeted::kYes == resource->resourcePriv().isBudgeted()) {
bsalomondace19e2014-11-17 07:34:06 -0800140 ++fBudgetedCount;
141 fBudgetedBytes += size;
hendrikw876c3132015-03-04 10:33:49 -0800142 TRACE_COUNTER2(TRACE_DISABLED_BY_DEFAULT("skia.gpu.cache"), "skia budget", "used",
143 fBudgetedBytes, "free", fMaxBytes - fBudgetedBytes);
bsalomondace19e2014-11-17 07:34:06 -0800144#if GR_CACHE_STATS
145 fBudgetedHighWaterCount = SkTMax(fBudgetedCount, fBudgetedHighWaterCount);
146 fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes);
147#endif
148 }
robertphillipsc4ed6842016-05-24 14:17:12 -0700149 if (resource->resourcePriv().getScratchKey().isValid() &&
150 !resource->getUniqueKey().isValid()) {
kkinnunen2e6055b2016-04-22 01:48:29 -0700151 SkASSERT(!resource->resourcePriv().refsWrappedObjects());
bsalomon3582d3e2015-02-13 14:20:05 -0800152 fScratchMap.insert(resource->resourcePriv().getScratchKey(), resource);
bsalomon744998e2014-08-28 09:54:34 -0700153 }
bsalomon9f2d1572015-02-17 11:47:40 -0800154
bsalomon71cb0c22014-11-14 12:10:14 -0800155 this->purgeAsNeeded();
bsalomonc8dc1f72014-08-21 13:02:13 -0700156}
157
bsalomon0ea80f42015-02-11 10:49:59 -0800158void GrResourceCache::removeResource(GrGpuResource* resource) {
bsalomon9f2d1572015-02-17 11:47:40 -0800159 this->validate();
bsalomon16961262014-08-26 14:01:07 -0700160 SkASSERT(this->isInCache(resource));
bsalomondace19e2014-11-17 07:34:06 -0800161
bsalomon9f2d1572015-02-17 11:47:40 -0800162 if (resource->isPurgeable()) {
163 fPurgeableQueue.remove(resource);
bsalomonf320e042015-02-17 15:09:34 -0800164 } else {
165 this->removeFromNonpurgeableArray(resource);
bsalomon9f2d1572015-02-17 11:47:40 -0800166 }
167
bsalomondace19e2014-11-17 07:34:06 -0800168 size_t size = resource->gpuMemorySize();
bsalomonf320e042015-02-17 15:09:34 -0800169 SkDEBUGCODE(--fCount;)
bsalomondace19e2014-11-17 07:34:06 -0800170 fBytes -= size;
bsalomon5ec26ae2016-02-25 08:33:02 -0800171 if (SkBudgeted::kYes == resource->resourcePriv().isBudgeted()) {
bsalomondace19e2014-11-17 07:34:06 -0800172 --fBudgetedCount;
173 fBudgetedBytes -= size;
hendrikw876c3132015-03-04 10:33:49 -0800174 TRACE_COUNTER2(TRACE_DISABLED_BY_DEFAULT("skia.gpu.cache"), "skia budget", "used",
175 fBudgetedBytes, "free", fMaxBytes - fBudgetedBytes);
bsalomondace19e2014-11-17 07:34:06 -0800176 }
177
robertphillipsc4ed6842016-05-24 14:17:12 -0700178 if (resource->resourcePriv().getScratchKey().isValid() &&
179 !resource->getUniqueKey().isValid()) {
bsalomon3582d3e2015-02-13 14:20:05 -0800180 fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource);
bsalomon744998e2014-08-28 09:54:34 -0700181 }
bsalomon8718aaf2015-02-19 07:24:21 -0800182 if (resource->getUniqueKey().isValid()) {
183 fUniqueHash.remove(resource->getUniqueKey());
bsalomon8b79d232014-11-10 10:19:06 -0800184 }
bsalomonb436ed62014-11-17 12:15:56 -0800185 this->validate();
bsalomonc8dc1f72014-08-21 13:02:13 -0700186}
187
bsalomon0ea80f42015-02-11 10:49:59 -0800188void GrResourceCache::abandonAll() {
bsalomon71cb0c22014-11-14 12:10:14 -0800189 AutoValidate av(this);
190
bsalomonf320e042015-02-17 15:09:34 -0800191 while (fNonpurgeableResources.count()) {
192 GrGpuResource* back = *(fNonpurgeableResources.end() - 1);
193 SkASSERT(!back->wasDestroyed());
194 back->cacheAccess().abandon();
bsalomonc8dc1f72014-08-21 13:02:13 -0700195 }
bsalomonf320e042015-02-17 15:09:34 -0800196
197 while (fPurgeableQueue.count()) {
198 GrGpuResource* top = fPurgeableQueue.peek();
199 SkASSERT(!top->wasDestroyed());
200 top->cacheAccess().abandon();
201 }
202
bsalomon744998e2014-08-28 09:54:34 -0700203 SkASSERT(!fScratchMap.count());
bsalomon8718aaf2015-02-19 07:24:21 -0800204 SkASSERT(!fUniqueHash.count());
bsalomonc8dc1f72014-08-21 13:02:13 -0700205 SkASSERT(!fCount);
bsalomonf320e042015-02-17 15:09:34 -0800206 SkASSERT(!this->getResourceCount());
bsalomondace19e2014-11-17 07:34:06 -0800207 SkASSERT(!fBytes);
208 SkASSERT(!fBudgetedCount);
209 SkASSERT(!fBudgetedBytes);
bsalomonc8dc1f72014-08-21 13:02:13 -0700210}
211
bsalomon0ea80f42015-02-11 10:49:59 -0800212void GrResourceCache::releaseAll() {
bsalomon71cb0c22014-11-14 12:10:14 -0800213 AutoValidate av(this);
214
bsalomonf320e042015-02-17 15:09:34 -0800215 while(fNonpurgeableResources.count()) {
216 GrGpuResource* back = *(fNonpurgeableResources.end() - 1);
217 SkASSERT(!back->wasDestroyed());
218 back->cacheAccess().release();
bsalomonc8dc1f72014-08-21 13:02:13 -0700219 }
bsalomonf320e042015-02-17 15:09:34 -0800220
221 while (fPurgeableQueue.count()) {
222 GrGpuResource* top = fPurgeableQueue.peek();
223 SkASSERT(!top->wasDestroyed());
224 top->cacheAccess().release();
225 }
226
bsalomon744998e2014-08-28 09:54:34 -0700227 SkASSERT(!fScratchMap.count());
bsalomon8718aaf2015-02-19 07:24:21 -0800228 SkASSERT(!fUniqueHash.count());
bsalomonc8dc1f72014-08-21 13:02:13 -0700229 SkASSERT(!fCount);
bsalomonf320e042015-02-17 15:09:34 -0800230 SkASSERT(!this->getResourceCount());
bsalomondace19e2014-11-17 07:34:06 -0800231 SkASSERT(!fBytes);
232 SkASSERT(!fBudgetedCount);
233 SkASSERT(!fBudgetedBytes);
bsalomonc8dc1f72014-08-21 13:02:13 -0700234}
bsalomonbcf0a522014-10-08 08:40:09 -0700235
bsalomon0ea80f42015-02-11 10:49:59 -0800236class GrResourceCache::AvailableForScratchUse {
bsalomonbcf0a522014-10-08 08:40:09 -0700237public:
bsalomon000f8292014-10-15 19:04:14 -0700238 AvailableForScratchUse(bool rejectPendingIO) : fRejectPendingIO(rejectPendingIO) { }
bsalomonbcf0a522014-10-08 08:40:09 -0700239
240 bool operator()(const GrGpuResource* resource) const {
robertphillipsc4ed6842016-05-24 14:17:12 -0700241 SkASSERT(!resource->getUniqueKey().isValid() &&
242 resource->resourcePriv().getScratchKey().isValid());
bsalomon12299ab2014-11-14 13:33:09 -0800243 if (resource->internalHasRef() || !resource->cacheAccess().isScratch()) {
bsalomon000f8292014-10-15 19:04:14 -0700244 return false;
bsalomonbcf0a522014-10-08 08:40:09 -0700245 }
bsalomon000f8292014-10-15 19:04:14 -0700246 return !fRejectPendingIO || !resource->internalHasPendingIO();
bsalomonbcf0a522014-10-08 08:40:09 -0700247 }
bsalomon1e2530b2014-10-09 09:57:18 -0700248
bsalomonbcf0a522014-10-08 08:40:09 -0700249private:
bsalomon000f8292014-10-15 19:04:14 -0700250 bool fRejectPendingIO;
bsalomonbcf0a522014-10-08 08:40:09 -0700251};
252
bsalomon0ea80f42015-02-11 10:49:59 -0800253GrGpuResource* GrResourceCache::findAndRefScratchResource(const GrScratchKey& scratchKey,
robertphillips6e83ac72015-08-13 05:19:14 -0700254 size_t resourceSize,
bsalomon9f2d1572015-02-17 11:47:40 -0800255 uint32_t flags) {
bsalomon7775c852014-12-30 12:50:52 -0800256 SkASSERT(scratchKey.isValid());
bsalomon000f8292014-10-15 19:04:14 -0700257
bsalomon71cb0c22014-11-14 12:10:14 -0800258 GrGpuResource* resource;
bsalomon000f8292014-10-15 19:04:14 -0700259 if (flags & (kPreferNoPendingIO_ScratchFlag | kRequireNoPendingIO_ScratchFlag)) {
bsalomon71cb0c22014-11-14 12:10:14 -0800260 resource = fScratchMap.find(scratchKey, AvailableForScratchUse(true));
bsalomon000f8292014-10-15 19:04:14 -0700261 if (resource) {
bsalomon9f2d1572015-02-17 11:47:40 -0800262 this->refAndMakeResourceMRU(resource);
bsalomonb436ed62014-11-17 12:15:56 -0800263 this->validate();
264 return resource;
bsalomon000f8292014-10-15 19:04:14 -0700265 } else if (flags & kRequireNoPendingIO_ScratchFlag) {
halcanary96fcdcc2015-08-27 07:41:13 -0700266 return nullptr;
bsalomon000f8292014-10-15 19:04:14 -0700267 }
robertphillips63926682015-08-20 09:39:02 -0700268 // We would prefer to consume more available VRAM rather than flushing
269 // immediately, but on ANGLE this can lead to starving of the GPU.
270 if (fPreferVRAMUseOverFlushes && this->wouldFit(resourceSize)) {
robertphillips6e83ac72015-08-13 05:19:14 -0700271 // kPrefer is specified, we didn't find a resource without pending io,
robertphillips63926682015-08-20 09:39:02 -0700272 // but there is still space in our budget for the resource so force
273 // the caller to allocate a new resource.
halcanary96fcdcc2015-08-27 07:41:13 -0700274 return nullptr;
robertphillips6e83ac72015-08-13 05:19:14 -0700275 }
bsalomon000f8292014-10-15 19:04:14 -0700276 }
bsalomon71cb0c22014-11-14 12:10:14 -0800277 resource = fScratchMap.find(scratchKey, AvailableForScratchUse(false));
278 if (resource) {
bsalomon9f2d1572015-02-17 11:47:40 -0800279 this->refAndMakeResourceMRU(resource);
bsalomonb436ed62014-11-17 12:15:56 -0800280 this->validate();
bsalomon71cb0c22014-11-14 12:10:14 -0800281 }
282 return resource;
bsalomonbcf0a522014-10-08 08:40:09 -0700283}
bsalomon8b79d232014-11-10 10:19:06 -0800284
bsalomon0ea80f42015-02-11 10:49:59 -0800285void GrResourceCache::willRemoveScratchKey(const GrGpuResource* resource) {
bsalomon3582d3e2015-02-13 14:20:05 -0800286 SkASSERT(resource->resourcePriv().getScratchKey().isValid());
robertphillipsc4ed6842016-05-24 14:17:12 -0700287 if (!resource->getUniqueKey().isValid()) {
288 fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource);
289 }
bsalomon10e23ca2014-11-25 05:52:06 -0800290}
291
bsalomonf99e9612015-02-19 08:24:16 -0800292void GrResourceCache::removeUniqueKey(GrGpuResource* resource) {
bsalomon3f324322015-04-08 11:01:54 -0700293 // Someone has a ref to this resource in order to have removed the key. When the ref count
294 // reaches zero we will get a ref cnt notification and figure out what to do with it.
bsalomonf99e9612015-02-19 08:24:16 -0800295 if (resource->getUniqueKey().isValid()) {
296 SkASSERT(resource == fUniqueHash.find(resource->getUniqueKey()));
297 fUniqueHash.remove(resource->getUniqueKey());
298 }
299 resource->cacheAccess().removeUniqueKey();
robertphillipsc4ed6842016-05-24 14:17:12 -0700300
301 if (resource->resourcePriv().getScratchKey().isValid()) {
302 fScratchMap.insert(resource->resourcePriv().getScratchKey(), resource);
303 }
304
bsalomonf99e9612015-02-19 08:24:16 -0800305 this->validate();
bsalomon23e619c2015-02-06 11:54:28 -0800306}
307
bsalomonf99e9612015-02-19 08:24:16 -0800308void GrResourceCache::changeUniqueKey(GrGpuResource* resource, const GrUniqueKey& newKey) {
bsalomon8b79d232014-11-10 10:19:06 -0800309 SkASSERT(resource);
bsalomon71cb0c22014-11-14 12:10:14 -0800310 SkASSERT(this->isInCache(resource));
bsalomon8b79d232014-11-10 10:19:06 -0800311
bsalomonf99e9612015-02-19 08:24:16 -0800312 // If another resource has the new key, remove its key then install the key on this resource.
313 if (newKey.isValid()) {
robertphillipsc4ed6842016-05-24 14:17:12 -0700314 // Remove the entry for this resource if it already has a unique key.
315 if (resource->getUniqueKey().isValid()) {
316 SkASSERT(resource == fUniqueHash.find(resource->getUniqueKey()));
317 fUniqueHash.remove(resource->getUniqueKey());
318 SkASSERT(nullptr == fUniqueHash.find(resource->getUniqueKey()));
319 } else {
320 // 'resource' didn't have a valid unique key before so it is switching sides. Remove it
321 // from the ScratchMap
322 if (resource->resourcePriv().getScratchKey().isValid()) {
323 fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource);
324 }
325 }
326
bsalomonf99e9612015-02-19 08:24:16 -0800327 if (GrGpuResource* old = fUniqueHash.find(newKey)) {
328 // If the old resource using the key is purgeable and is unreachable, then remove it.
329 if (!old->resourcePriv().getScratchKey().isValid() && old->isPurgeable()) {
330 // release may call validate() which will assert that resource is in fUniqueHash
331 // if it has a valid key. So in debug reset the key here before we assign it.
332 SkDEBUGCODE(resource->cacheAccess().removeUniqueKey();)
333 old->cacheAccess().release();
334 } else {
robertphillipsc4ed6842016-05-24 14:17:12 -0700335 this->removeUniqueKey(old);
bsalomonf99e9612015-02-19 08:24:16 -0800336 }
337 }
halcanary96fcdcc2015-08-27 07:41:13 -0700338 SkASSERT(nullptr == fUniqueHash.find(newKey));
bsalomonf99e9612015-02-19 08:24:16 -0800339 resource->cacheAccess().setUniqueKey(newKey);
340 fUniqueHash.add(resource);
341 } else {
robertphillipsc4ed6842016-05-24 14:17:12 -0700342 this->removeUniqueKey(resource);
bsalomonf99e9612015-02-19 08:24:16 -0800343 }
344
bsalomon71cb0c22014-11-14 12:10:14 -0800345 this->validate();
bsalomon8b79d232014-11-10 10:19:06 -0800346}
bsalomon71cb0c22014-11-14 12:10:14 -0800347
bsalomon9f2d1572015-02-17 11:47:40 -0800348void GrResourceCache::refAndMakeResourceMRU(GrGpuResource* resource) {
bsalomon71cb0c22014-11-14 12:10:14 -0800349 SkASSERT(resource);
350 SkASSERT(this->isInCache(resource));
bsalomonddf30e62015-02-19 11:38:44 -0800351
bsalomon9f2d1572015-02-17 11:47:40 -0800352 if (resource->isPurgeable()) {
353 // It's about to become unpurgeable.
354 fPurgeableQueue.remove(resource);
bsalomonf320e042015-02-17 15:09:34 -0800355 this->addToNonpurgeableArray(resource);
bsalomon9f2d1572015-02-17 11:47:40 -0800356 }
357 resource->ref();
bsalomonddf30e62015-02-19 11:38:44 -0800358
359 resource->cacheAccess().setTimestamp(this->getNextTimestamp());
bsalomonf320e042015-02-17 15:09:34 -0800360 this->validate();
bsalomon71cb0c22014-11-14 12:10:14 -0800361}
362
bsalomon3f324322015-04-08 11:01:54 -0700363void GrResourceCache::notifyCntReachedZero(GrGpuResource* resource, uint32_t flags) {
bsalomon71cb0c22014-11-14 12:10:14 -0800364 SkASSERT(resource);
bsalomon3f324322015-04-08 11:01:54 -0700365 SkASSERT(!resource->wasDestroyed());
366 SkASSERT(flags);
bsalomon71cb0c22014-11-14 12:10:14 -0800367 SkASSERT(this->isInCache(resource));
bsalomon3f324322015-04-08 11:01:54 -0700368 // This resource should always be in the nonpurgeable array when this function is called. It
369 // will be moved to the queue if it is newly purgeable.
370 SkASSERT(fNonpurgeableResources[*resource->cacheAccess().accessCacheIndex()] == resource);
bsalomon71cb0c22014-11-14 12:10:14 -0800371
bsalomon3f324322015-04-08 11:01:54 -0700372 if (SkToBool(ResourceAccess::kRefCntReachedZero_RefNotificationFlag & flags)) {
373#ifdef SK_DEBUG
374 // When the timestamp overflows validate() is called. validate() checks that resources in
375 // the nonpurgeable array are indeed not purgeable. However, the movement from the array to
376 // the purgeable queue happens just below in this function. So we mark it as an exception.
377 if (resource->isPurgeable()) {
378 fNewlyPurgeableResourceForValidation = resource;
379 }
380#endif
381 resource->cacheAccess().setTimestamp(this->getNextTimestamp());
halcanary96fcdcc2015-08-27 07:41:13 -0700382 SkDEBUGCODE(fNewlyPurgeableResourceForValidation = nullptr);
bsalomon3f324322015-04-08 11:01:54 -0700383 }
384
385 if (!SkToBool(ResourceAccess::kAllCntsReachedZero_RefNotificationFlag & flags)) {
386 SkASSERT(!resource->isPurgeable());
387 return;
388 }
389
390 SkASSERT(resource->isPurgeable());
bsalomonf320e042015-02-17 15:09:34 -0800391 this->removeFromNonpurgeableArray(resource);
bsalomon9f2d1572015-02-17 11:47:40 -0800392 fPurgeableQueue.insert(resource);
bsalomon71cb0c22014-11-14 12:10:14 -0800393
bsalomon5ec26ae2016-02-25 08:33:02 -0800394 if (SkBudgeted::kNo == resource->resourcePriv().isBudgeted()) {
bsalomonc2f35b72015-01-23 07:19:22 -0800395 // Check whether this resource could still be used as a scratch resource.
kkinnunen2e6055b2016-04-22 01:48:29 -0700396 if (!resource->resourcePriv().refsWrappedObjects() &&
bsalomon9f2d1572015-02-17 11:47:40 -0800397 resource->resourcePriv().getScratchKey().isValid()) {
bsalomonc2f35b72015-01-23 07:19:22 -0800398 // We won't purge an existing resource to make room for this one.
bsalomonf320e042015-02-17 15:09:34 -0800399 if (fBudgetedCount < fMaxCount &&
400 fBudgetedBytes + resource->gpuMemorySize() <= fMaxBytes) {
bsalomon3582d3e2015-02-13 14:20:05 -0800401 resource->resourcePriv().makeBudgeted();
bsalomon9f2d1572015-02-17 11:47:40 -0800402 return;
bsalomonc2f35b72015-01-23 07:19:22 -0800403 }
bsalomonc2f35b72015-01-23 07:19:22 -0800404 }
405 } else {
bsalomon9f2d1572015-02-17 11:47:40 -0800406 // Purge the resource immediately if we're over budget
bsalomon8718aaf2015-02-19 07:24:21 -0800407 // Also purge if the resource has neither a valid scratch key nor a unique key.
bsalomon3582d3e2015-02-13 14:20:05 -0800408 bool noKey = !resource->resourcePriv().getScratchKey().isValid() &&
bsalomon8718aaf2015-02-19 07:24:21 -0800409 !resource->getUniqueKey().isValid();
bsalomonf320e042015-02-17 15:09:34 -0800410 if (!this->overBudget() && !noKey) {
bsalomon9f2d1572015-02-17 11:47:40 -0800411 return;
bsalomonc2f35b72015-01-23 07:19:22 -0800412 }
413 }
bsalomondace19e2014-11-17 07:34:06 -0800414
bsalomonf320e042015-02-17 15:09:34 -0800415 SkDEBUGCODE(int beforeCount = this->getResourceCount();)
bsalomon9f2d1572015-02-17 11:47:40 -0800416 resource->cacheAccess().release();
417 // We should at least free this resource, perhaps dependent resources as well.
bsalomonf320e042015-02-17 15:09:34 -0800418 SkASSERT(this->getResourceCount() < beforeCount);
bsalomon71cb0c22014-11-14 12:10:14 -0800419 this->validate();
420}
421
bsalomon0ea80f42015-02-11 10:49:59 -0800422void GrResourceCache::didChangeGpuMemorySize(const GrGpuResource* resource, size_t oldSize) {
bsalomon71cb0c22014-11-14 12:10:14 -0800423 // SkASSERT(!fPurging); GrPathRange increases size during flush. :(
424 SkASSERT(resource);
425 SkASSERT(this->isInCache(resource));
426
bsalomondace19e2014-11-17 07:34:06 -0800427 ptrdiff_t delta = resource->gpuMemorySize() - oldSize;
428
429 fBytes += delta;
bsalomon82b1d622014-11-14 13:59:57 -0800430#if GR_CACHE_STATS
431 fHighWaterBytes = SkTMax(fBytes, fHighWaterBytes);
432#endif
bsalomon5ec26ae2016-02-25 08:33:02 -0800433 if (SkBudgeted::kYes == resource->resourcePriv().isBudgeted()) {
bsalomondace19e2014-11-17 07:34:06 -0800434 fBudgetedBytes += delta;
hendrikw876c3132015-03-04 10:33:49 -0800435 TRACE_COUNTER2(TRACE_DISABLED_BY_DEFAULT("skia.gpu.cache"), "skia budget", "used",
436 fBudgetedBytes, "free", fMaxBytes - fBudgetedBytes);
bsalomondace19e2014-11-17 07:34:06 -0800437#if GR_CACHE_STATS
438 fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes);
439#endif
440 }
bsalomon71cb0c22014-11-14 12:10:14 -0800441
442 this->purgeAsNeeded();
443 this->validate();
444}
445
bsalomon0ea80f42015-02-11 10:49:59 -0800446void GrResourceCache::didChangeBudgetStatus(GrGpuResource* resource) {
bsalomon84c8e622014-11-17 09:33:27 -0800447 SkASSERT(resource);
448 SkASSERT(this->isInCache(resource));
449
450 size_t size = resource->gpuMemorySize();
451
bsalomon5ec26ae2016-02-25 08:33:02 -0800452 if (SkBudgeted::kYes == resource->resourcePriv().isBudgeted()) {
bsalomon84c8e622014-11-17 09:33:27 -0800453 ++fBudgetedCount;
454 fBudgetedBytes += size;
bsalomonafe30052015-01-16 07:32:33 -0800455#if GR_CACHE_STATS
456 fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes);
457 fBudgetedHighWaterCount = SkTMax(fBudgetedCount, fBudgetedHighWaterCount);
458#endif
bsalomon84c8e622014-11-17 09:33:27 -0800459 this->purgeAsNeeded();
460 } else {
461 --fBudgetedCount;
462 fBudgetedBytes -= size;
463 }
hendrikw876c3132015-03-04 10:33:49 -0800464 TRACE_COUNTER2(TRACE_DISABLED_BY_DEFAULT("skia.gpu.cache"), "skia budget", "used",
465 fBudgetedBytes, "free", fMaxBytes - fBudgetedBytes);
bsalomon84c8e622014-11-17 09:33:27 -0800466
467 this->validate();
468}
469
bsalomon3f324322015-04-08 11:01:54 -0700470void GrResourceCache::purgeAsNeeded() {
471 SkTArray<GrUniqueKeyInvalidatedMessage> invalidKeyMsgs;
472 fInvalidUniqueKeyInbox.poll(&invalidKeyMsgs);
473 if (invalidKeyMsgs.count()) {
474 this->processInvalidUniqueKeys(invalidKeyMsgs);
475 }
bsalomon71cb0c22014-11-14 12:10:14 -0800476
bsalomon3f324322015-04-08 11:01:54 -0700477 if (fFlushTimestamps) {
478 // Assuming kNumFlushesToDeleteUnusedResource is a power of 2.
479 SkASSERT(SkIsPow2(fMaxUnusedFlushes));
480 int oldestFlushIndex = (fLastFlushTimestampIndex + 1) & (fMaxUnusedFlushes - 1);
481
482 uint32_t oldestAllowedTimestamp = fFlushTimestamps[oldestFlushIndex];
483 while (fPurgeableQueue.count()) {
484 uint32_t oldestResourceTimestamp = fPurgeableQueue.peek()->cacheAccess().timestamp();
485 if (oldestAllowedTimestamp < oldestResourceTimestamp) {
486 break;
487 }
488 GrGpuResource* resource = fPurgeableQueue.peek();
489 SkASSERT(resource->isPurgeable());
490 resource->cacheAccess().release();
491 }
492 }
493
494 bool stillOverbudget = this->overBudget();
495 while (stillOverbudget && fPurgeableQueue.count()) {
bsalomon9f2d1572015-02-17 11:47:40 -0800496 GrGpuResource* resource = fPurgeableQueue.peek();
497 SkASSERT(resource->isPurgeable());
498 resource->cacheAccess().release();
bsalomon3f324322015-04-08 11:01:54 -0700499 stillOverbudget = this->overBudget();
bsalomon9f2d1572015-02-17 11:47:40 -0800500 }
bsalomon71cb0c22014-11-14 12:10:14 -0800501
bsalomonb436ed62014-11-17 12:15:56 -0800502 this->validate();
bsalomon9f2d1572015-02-17 11:47:40 -0800503
504 if (stillOverbudget) {
bsalomonb77a9072016-09-07 10:02:04 -0700505 // Set this so that GrDrawingManager will issue a flush to free up resources with pending
506 // IO that we were unable to purge in this pass.
507 fRequestFlush = true;
bsalomon9f2d1572015-02-17 11:47:40 -0800508 }
bsalomon71cb0c22014-11-14 12:10:14 -0800509}
510
bsalomon0ea80f42015-02-11 10:49:59 -0800511void GrResourceCache::purgeAllUnlocked() {
bsalomon9f2d1572015-02-17 11:47:40 -0800512 // We could disable maintaining the heap property here, but it would add a lot of complexity.
513 // Moreover, this is rarely called.
514 while (fPurgeableQueue.count()) {
515 GrGpuResource* resource = fPurgeableQueue.peek();
516 SkASSERT(resource->isPurgeable());
517 resource->cacheAccess().release();
518 }
bsalomon71cb0c22014-11-14 12:10:14 -0800519
bsalomonb436ed62014-11-17 12:15:56 -0800520 this->validate();
bsalomon71cb0c22014-11-14 12:10:14 -0800521}
522
bsalomon8718aaf2015-02-19 07:24:21 -0800523void GrResourceCache::processInvalidUniqueKeys(
524 const SkTArray<GrUniqueKeyInvalidatedMessage>& msgs) {
bsalomon23e619c2015-02-06 11:54:28 -0800525 for (int i = 0; i < msgs.count(); ++i) {
bsalomon8718aaf2015-02-19 07:24:21 -0800526 GrGpuResource* resource = this->findAndRefUniqueResource(msgs[i].key());
bsalomon23e619c2015-02-06 11:54:28 -0800527 if (resource) {
bsalomon8718aaf2015-02-19 07:24:21 -0800528 resource->resourcePriv().removeUniqueKey();
bsalomon3f324322015-04-08 11:01:54 -0700529 resource->unref(); // If this resource is now purgeable, the cache will be notified.
bsalomon23e619c2015-02-06 11:54:28 -0800530 }
531 }
532}
533
bsalomonf320e042015-02-17 15:09:34 -0800534void GrResourceCache::addToNonpurgeableArray(GrGpuResource* resource) {
535 int index = fNonpurgeableResources.count();
536 *fNonpurgeableResources.append() = resource;
537 *resource->cacheAccess().accessCacheIndex() = index;
538}
539
540void GrResourceCache::removeFromNonpurgeableArray(GrGpuResource* resource) {
541 int* index = resource->cacheAccess().accessCacheIndex();
542 // Fill the whole we will create in the array with the tail object, adjust its index, and
543 // then pop the array
544 GrGpuResource* tail = *(fNonpurgeableResources.end() - 1);
545 SkASSERT(fNonpurgeableResources[*index] == resource);
546 fNonpurgeableResources[*index] = tail;
547 *tail->cacheAccess().accessCacheIndex() = *index;
548 fNonpurgeableResources.pop();
549 SkDEBUGCODE(*index = -1);
550}
551
bsalomonddf30e62015-02-19 11:38:44 -0800552uint32_t GrResourceCache::getNextTimestamp() {
553 // If we wrap then all the existing resources will appear older than any resources that get
554 // a timestamp after the wrap.
555 if (0 == fTimestamp) {
556 int count = this->getResourceCount();
557 if (count) {
558 // Reset all the timestamps. We sort the resources by timestamp and then assign
559 // sequential timestamps beginning with 0. This is O(n*lg(n)) but it should be extremely
560 // rare.
561 SkTDArray<GrGpuResource*> sortedPurgeableResources;
562 sortedPurgeableResources.setReserve(fPurgeableQueue.count());
563
564 while (fPurgeableQueue.count()) {
565 *sortedPurgeableResources.append() = fPurgeableQueue.peek();
566 fPurgeableQueue.pop();
567 }
568
569 struct Less {
570 bool operator()(GrGpuResource* a, GrGpuResource* b) {
571 return CompareTimestamp(a,b);
572 }
573 };
574 Less less;
575 SkTQSort(fNonpurgeableResources.begin(), fNonpurgeableResources.end() - 1, less);
576
577 // Pick resources out of the purgeable and non-purgeable arrays based on lowest
578 // timestamp and assign new timestamps.
579 int currP = 0;
580 int currNP = 0;
581 while (currP < sortedPurgeableResources.count() &&
mtklein56da0252015-11-16 11:16:23 -0800582 currNP < fNonpurgeableResources.count()) {
bsalomonddf30e62015-02-19 11:38:44 -0800583 uint32_t tsP = sortedPurgeableResources[currP]->cacheAccess().timestamp();
584 uint32_t tsNP = fNonpurgeableResources[currNP]->cacheAccess().timestamp();
585 SkASSERT(tsP != tsNP);
586 if (tsP < tsNP) {
587 sortedPurgeableResources[currP++]->cacheAccess().setTimestamp(fTimestamp++);
588 } else {
589 // Correct the index in the nonpurgeable array stored on the resource post-sort.
590 *fNonpurgeableResources[currNP]->cacheAccess().accessCacheIndex() = currNP;
591 fNonpurgeableResources[currNP++]->cacheAccess().setTimestamp(fTimestamp++);
592 }
593 }
594
595 // The above loop ended when we hit the end of one array. Finish the other one.
596 while (currP < sortedPurgeableResources.count()) {
597 sortedPurgeableResources[currP++]->cacheAccess().setTimestamp(fTimestamp++);
598 }
599 while (currNP < fNonpurgeableResources.count()) {
600 *fNonpurgeableResources[currNP]->cacheAccess().accessCacheIndex() = currNP;
601 fNonpurgeableResources[currNP++]->cacheAccess().setTimestamp(fTimestamp++);
602 }
603
604 // Rebuild the queue.
605 for (int i = 0; i < sortedPurgeableResources.count(); ++i) {
606 fPurgeableQueue.insert(sortedPurgeableResources[i]);
607 }
608
609 this->validate();
610 SkASSERT(count == this->getResourceCount());
611
612 // count should be the next timestamp we return.
613 SkASSERT(fTimestamp == SkToU32(count));
mtklein56da0252015-11-16 11:16:23 -0800614
bsalomon3f324322015-04-08 11:01:54 -0700615 // The historical timestamps of flushes are now invalid.
616 this->resetFlushTimestamps();
mtklein56da0252015-11-16 11:16:23 -0800617 }
bsalomonddf30e62015-02-19 11:38:44 -0800618 }
619 return fTimestamp++;
620}
621
bsalomonb77a9072016-09-07 10:02:04 -0700622void GrResourceCache::notifyFlushOccurred(FlushType type) {
623 switch (type) {
624 case FlushType::kImmediateMode:
625 break;
626 case FlushType::kCacheRequested:
627 SkASSERT(fRequestFlush);
628 fRequestFlush = false;
629 break;
630 case FlushType::kExternal:
631 if (fFlushTimestamps) {
632 SkASSERT(SkIsPow2(fMaxUnusedFlushes));
633 fLastFlushTimestampIndex = (fLastFlushTimestampIndex + 1) & (fMaxUnusedFlushes - 1);
634 // get the timestamp before accessing fFlushTimestamps because getNextTimestamp will
635 // reallocate fFlushTimestamps on timestamp overflow.
636 uint32_t timestamp = this->getNextTimestamp();
637 fFlushTimestamps[fLastFlushTimestampIndex] = timestamp;
638 }
639 break;
bsalomon3f324322015-04-08 11:01:54 -0700640 }
bsalomonb77a9072016-09-07 10:02:04 -0700641 this->purgeAsNeeded();
bsalomon3f324322015-04-08 11:01:54 -0700642}
643
ericrk0a5fa482015-09-15 14:16:10 -0700644void GrResourceCache::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
645 for (int i = 0; i < fNonpurgeableResources.count(); ++i) {
646 fNonpurgeableResources[i]->dumpMemoryStatistics(traceMemoryDump);
647 }
648 for (int i = 0; i < fPurgeableQueue.count(); ++i) {
649 fPurgeableQueue.at(i)->dumpMemoryStatistics(traceMemoryDump);
650 }
651}
652
bsalomon71cb0c22014-11-14 12:10:14 -0800653#ifdef SK_DEBUG
bsalomon0ea80f42015-02-11 10:49:59 -0800654void GrResourceCache::validate() const {
bsalomonc2f35b72015-01-23 07:19:22 -0800655 // Reduce the frequency of validations for large resource counts.
656 static SkRandom gRandom;
657 int mask = (SkNextPow2(fCount + 1) >> 5) - 1;
658 if (~mask && (gRandom.nextU() & mask)) {
659 return;
660 }
661
bsalomonf320e042015-02-17 15:09:34 -0800662 struct Stats {
663 size_t fBytes;
664 int fBudgetedCount;
665 size_t fBudgetedBytes;
666 int fLocked;
667 int fScratch;
668 int fCouldBeScratch;
669 int fContent;
670 const ScratchMap* fScratchMap;
bsalomon8718aaf2015-02-19 07:24:21 -0800671 const UniqueHash* fUniqueHash;
bsalomon71cb0c22014-11-14 12:10:14 -0800672
bsalomonf320e042015-02-17 15:09:34 -0800673 Stats(const GrResourceCache* cache) {
674 memset(this, 0, sizeof(*this));
675 fScratchMap = &cache->fScratchMap;
bsalomon8718aaf2015-02-19 07:24:21 -0800676 fUniqueHash = &cache->fUniqueHash;
bsalomon71cb0c22014-11-14 12:10:14 -0800677 }
678
bsalomonf320e042015-02-17 15:09:34 -0800679 void update(GrGpuResource* resource) {
680 fBytes += resource->gpuMemorySize();
bsalomondace19e2014-11-17 07:34:06 -0800681
bsalomonf320e042015-02-17 15:09:34 -0800682 if (!resource->isPurgeable()) {
683 ++fLocked;
684 }
bsalomon9f2d1572015-02-17 11:47:40 -0800685
robertphillipsc4ed6842016-05-24 14:17:12 -0700686 const GrScratchKey& scratchKey = resource->resourcePriv().getScratchKey();
687 const GrUniqueKey& uniqueKey = resource->getUniqueKey();
688
bsalomonf320e042015-02-17 15:09:34 -0800689 if (resource->cacheAccess().isScratch()) {
robertphillipsc4ed6842016-05-24 14:17:12 -0700690 SkASSERT(!uniqueKey.isValid());
bsalomonf320e042015-02-17 15:09:34 -0800691 ++fScratch;
robertphillipsc4ed6842016-05-24 14:17:12 -0700692 SkASSERT(fScratchMap->countForKey(scratchKey));
kkinnunen2e6055b2016-04-22 01:48:29 -0700693 SkASSERT(!resource->resourcePriv().refsWrappedObjects());
robertphillipsc4ed6842016-05-24 14:17:12 -0700694 } else if (scratchKey.isValid()) {
bsalomon5ec26ae2016-02-25 08:33:02 -0800695 SkASSERT(SkBudgeted::kNo == resource->resourcePriv().isBudgeted() ||
robertphillipsc4ed6842016-05-24 14:17:12 -0700696 uniqueKey.isValid());
697 if (!uniqueKey.isValid()) {
mtklein4e976072016-08-08 09:06:27 -0700698 ++fCouldBeScratch;
robertphillipsc4ed6842016-05-24 14:17:12 -0700699 SkASSERT(fScratchMap->countForKey(scratchKey));
700 }
kkinnunen2e6055b2016-04-22 01:48:29 -0700701 SkASSERT(!resource->resourcePriv().refsWrappedObjects());
bsalomonf320e042015-02-17 15:09:34 -0800702 }
bsalomon8718aaf2015-02-19 07:24:21 -0800703 if (uniqueKey.isValid()) {
bsalomonf320e042015-02-17 15:09:34 -0800704 ++fContent;
bsalomon8718aaf2015-02-19 07:24:21 -0800705 SkASSERT(fUniqueHash->find(uniqueKey) == resource);
kkinnunen2e6055b2016-04-22 01:48:29 -0700706 SkASSERT(!resource->resourcePriv().refsWrappedObjects());
bsalomon5ec26ae2016-02-25 08:33:02 -0800707 SkASSERT(SkBudgeted::kYes == resource->resourcePriv().isBudgeted());
robertphillipsc4ed6842016-05-24 14:17:12 -0700708
709 if (scratchKey.isValid()) {
710 SkASSERT(!fScratchMap->has(resource, scratchKey));
711 }
bsalomonf320e042015-02-17 15:09:34 -0800712 }
713
bsalomon5ec26ae2016-02-25 08:33:02 -0800714 if (SkBudgeted::kYes == resource->resourcePriv().isBudgeted()) {
bsalomonf320e042015-02-17 15:09:34 -0800715 ++fBudgetedCount;
716 fBudgetedBytes += resource->gpuMemorySize();
717 }
bsalomon9f2d1572015-02-17 11:47:40 -0800718 }
bsalomonf320e042015-02-17 15:09:34 -0800719 };
720
robertphillipsc4ed6842016-05-24 14:17:12 -0700721 {
722 ScratchMap::ConstIter iter(&fScratchMap);
723
724 int count = 0;
725 for ( ; !iter.done(); ++iter) {
726 const GrGpuResource* resource = *iter;
727 SkASSERT(resource->resourcePriv().getScratchKey().isValid());
728 SkASSERT(!resource->getUniqueKey().isValid());
729 count++;
730 }
731 SkASSERT(count == fScratchMap.count()); // ensure the iterator is working correctly
732 }
733
bsalomonf320e042015-02-17 15:09:34 -0800734 Stats stats(this);
735
736 for (int i = 0; i < fNonpurgeableResources.count(); ++i) {
bsalomon3f324322015-04-08 11:01:54 -0700737 SkASSERT(!fNonpurgeableResources[i]->isPurgeable() ||
738 fNewlyPurgeableResourceForValidation == fNonpurgeableResources[i]);
bsalomonf320e042015-02-17 15:09:34 -0800739 SkASSERT(*fNonpurgeableResources[i]->cacheAccess().accessCacheIndex() == i);
740 SkASSERT(!fNonpurgeableResources[i]->wasDestroyed());
741 stats.update(fNonpurgeableResources[i]);
bsalomon71cb0c22014-11-14 12:10:14 -0800742 }
bsalomon9f2d1572015-02-17 11:47:40 -0800743 for (int i = 0; i < fPurgeableQueue.count(); ++i) {
744 SkASSERT(fPurgeableQueue.at(i)->isPurgeable());
bsalomonf320e042015-02-17 15:09:34 -0800745 SkASSERT(*fPurgeableQueue.at(i)->cacheAccess().accessCacheIndex() == i);
746 SkASSERT(!fPurgeableQueue.at(i)->wasDestroyed());
747 stats.update(fPurgeableQueue.at(i));
bsalomon9f2d1572015-02-17 11:47:40 -0800748 }
749
bsalomonf320e042015-02-17 15:09:34 -0800750 SkASSERT(fCount == this->getResourceCount());
bsalomondace19e2014-11-17 07:34:06 -0800751 SkASSERT(fBudgetedCount <= fCount);
bsalomonf320e042015-02-17 15:09:34 -0800752 SkASSERT(fBudgetedBytes <= fBytes);
753 SkASSERT(stats.fBytes == fBytes);
754 SkASSERT(stats.fBudgetedBytes == fBudgetedBytes);
755 SkASSERT(stats.fBudgetedCount == fBudgetedCount);
bsalomon71cb0c22014-11-14 12:10:14 -0800756#if GR_CACHE_STATS
bsalomondace19e2014-11-17 07:34:06 -0800757 SkASSERT(fBudgetedHighWaterCount <= fHighWaterCount);
758 SkASSERT(fBudgetedHighWaterBytes <= fHighWaterBytes);
bsalomonf320e042015-02-17 15:09:34 -0800759 SkASSERT(fBytes <= fHighWaterBytes);
760 SkASSERT(fCount <= fHighWaterCount);
761 SkASSERT(fBudgetedBytes <= fBudgetedHighWaterBytes);
762 SkASSERT(fBudgetedCount <= fBudgetedHighWaterCount);
bsalomon71cb0c22014-11-14 12:10:14 -0800763#endif
bsalomon8718aaf2015-02-19 07:24:21 -0800764 SkASSERT(stats.fContent == fUniqueHash.count());
bsalomonf320e042015-02-17 15:09:34 -0800765 SkASSERT(stats.fScratch + stats.fCouldBeScratch == fScratchMap.count());
bsalomon71cb0c22014-11-14 12:10:14 -0800766
bsalomon3f324322015-04-08 11:01:54 -0700767 // This assertion is not currently valid because we can be in recursive notifyCntReachedZero()
bsalomon12299ab2014-11-14 13:33:09 -0800768 // calls. This will be fixed when subresource registration is explicit.
bsalomondace19e2014-11-17 07:34:06 -0800769 // bool overBudget = budgetedBytes > fMaxBytes || budgetedCount > fMaxCount;
bsalomon12299ab2014-11-14 13:33:09 -0800770 // SkASSERT(!overBudget || locked == count || fPurging);
bsalomon71cb0c22014-11-14 12:10:14 -0800771}
bsalomonf320e042015-02-17 15:09:34 -0800772
773bool GrResourceCache::isInCache(const GrGpuResource* resource) const {
774 int index = *resource->cacheAccess().accessCacheIndex();
775 if (index < 0) {
776 return false;
777 }
778 if (index < fPurgeableQueue.count() && fPurgeableQueue.at(index) == resource) {
779 return true;
780 }
781 if (index < fNonpurgeableResources.count() && fNonpurgeableResources[index] == resource) {
782 return true;
783 }
784 SkDEBUGFAIL("Resource index should be -1 or the resource should be in the cache.");
785 return false;
786}
787
bsalomon71cb0c22014-11-14 12:10:14 -0800788#endif