blob: 71e40f1a5364fff5f31919231d527de982f1bb07 [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"
bsalomon7775c852014-12-30 12:50:52 -080014#include "SkChecksum.h"
bsalomon71cb0c22014-11-14 12:10:14 -080015#include "SkGr.h"
16#include "SkMessageBus.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) {
mtklein56da0252015-11-16 11:16:23 -080046 return SkChecksum::Murmur3(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)
halcanary96fcdcc2015-08-27 07:41:13 -070076 , fOverBudgetCB(nullptr)
77 , fOverBudgetData(nullptr)
78 , fFlushTimestamps(nullptr)
robertphillips63926682015-08-20 09:39:02 -070079 , fLastFlushTimestampIndex(0)
80 , fPreferVRAMUseOverFlushes(caps->preferVRAMUseOverFlushes()) {
bsalomonf320e042015-02-17 15:09:34 -080081 SkDEBUGCODE(fCount = 0;)
halcanary96fcdcc2015-08-27 07:41:13 -070082 SkDEBUGCODE(fNewlyPurgeableResourceForValidation = nullptr;)
bsalomon3f324322015-04-08 11:01:54 -070083 this->resetFlushTimestamps();
bsalomon71cb0c22014-11-14 12:10:14 -080084}
85
bsalomon0ea80f42015-02-11 10:49:59 -080086GrResourceCache::~GrResourceCache() {
bsalomonc8dc1f72014-08-21 13:02:13 -070087 this->releaseAll();
halcanary385fe4d2015-08-26 13:07:48 -070088 delete[] fFlushTimestamps;
bsalomonc8dc1f72014-08-21 13:02:13 -070089}
90
bsalomon3f324322015-04-08 11:01:54 -070091void GrResourceCache::setLimits(int count, size_t bytes, int maxUnusedFlushes) {
bsalomon71cb0c22014-11-14 12:10:14 -080092 fMaxCount = count;
93 fMaxBytes = bytes;
bsalomon3f324322015-04-08 11:01:54 -070094 fMaxUnusedFlushes = maxUnusedFlushes;
95 this->resetFlushTimestamps();
bsalomon71cb0c22014-11-14 12:10:14 -080096 this->purgeAsNeeded();
97}
98
bsalomon3f324322015-04-08 11:01:54 -070099void GrResourceCache::resetFlushTimestamps() {
halcanary385fe4d2015-08-26 13:07:48 -0700100 delete[] fFlushTimestamps;
bsalomon3f324322015-04-08 11:01:54 -0700101
102 // We assume this number is a power of two when wrapping indices into the timestamp array.
103 fMaxUnusedFlushes = SkNextPow2(fMaxUnusedFlushes);
104
105 // Since our implementation is to store the timestamps of the last fMaxUnusedFlushes flush calls
106 // we just turn the feature off if that array would be large.
107 static const int kMaxSupportedTimestampHistory = 128;
108
109 if (fMaxUnusedFlushes > kMaxSupportedTimestampHistory) {
halcanary96fcdcc2015-08-27 07:41:13 -0700110 fFlushTimestamps = nullptr;
bsalomon3f324322015-04-08 11:01:54 -0700111 return;
112 }
113
halcanary385fe4d2015-08-26 13:07:48 -0700114 fFlushTimestamps = new uint32_t[fMaxUnusedFlushes];
bsalomon3f324322015-04-08 11:01:54 -0700115 fLastFlushTimestampIndex = 0;
116 // Set all the historical flush timestamps to initially be at the beginning of time (timestamp
117 // 0).
118 sk_bzero(fFlushTimestamps, fMaxUnusedFlushes * sizeof(uint32_t));
119}
120
bsalomon0ea80f42015-02-11 10:49:59 -0800121void GrResourceCache::insertResource(GrGpuResource* resource) {
bsalomon49f085d2014-09-05 13:34:00 -0700122 SkASSERT(resource);
bsalomon16961262014-08-26 14:01:07 -0700123 SkASSERT(!this->isInCache(resource));
bsalomonf320e042015-02-17 15:09:34 -0800124 SkASSERT(!resource->wasDestroyed());
125 SkASSERT(!resource->isPurgeable());
bsalomonddf30e62015-02-19 11:38:44 -0800126
127 // We must set the timestamp before adding to the array in case the timestamp wraps and we wind
128 // up iterating over all the resources that already have timestamps.
129 resource->cacheAccess().setTimestamp(this->getNextTimestamp());
130
bsalomonf320e042015-02-17 15:09:34 -0800131 this->addToNonpurgeableArray(resource);
bsalomon71cb0c22014-11-14 12:10:14 -0800132
bsalomondace19e2014-11-17 07:34:06 -0800133 size_t size = resource->gpuMemorySize();
bsalomonf320e042015-02-17 15:09:34 -0800134 SkDEBUGCODE(++fCount;)
bsalomon84c8e622014-11-17 09:33:27 -0800135 fBytes += size;
bsalomon82b1d622014-11-14 13:59:57 -0800136#if GR_CACHE_STATS
bsalomonf320e042015-02-17 15:09:34 -0800137 fHighWaterCount = SkTMax(this->getResourceCount(), fHighWaterCount);
bsalomon82b1d622014-11-14 13:59:57 -0800138 fHighWaterBytes = SkTMax(fBytes, fHighWaterBytes);
139#endif
bsalomon5ec26ae2016-02-25 08:33:02 -0800140 if (SkBudgeted::kYes == resource->resourcePriv().isBudgeted()) {
bsalomondace19e2014-11-17 07:34:06 -0800141 ++fBudgetedCount;
142 fBudgetedBytes += size;
hendrikw876c3132015-03-04 10:33:49 -0800143 TRACE_COUNTER2(TRACE_DISABLED_BY_DEFAULT("skia.gpu.cache"), "skia budget", "used",
144 fBudgetedBytes, "free", fMaxBytes - fBudgetedBytes);
bsalomondace19e2014-11-17 07:34:06 -0800145#if GR_CACHE_STATS
146 fBudgetedHighWaterCount = SkTMax(fBudgetedCount, fBudgetedHighWaterCount);
147 fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes);
148#endif
149 }
robertphillipsc4ed6842016-05-24 14:17:12 -0700150 if (resource->resourcePriv().getScratchKey().isValid() &&
151 !resource->getUniqueKey().isValid()) {
kkinnunen2e6055b2016-04-22 01:48:29 -0700152 SkASSERT(!resource->resourcePriv().refsWrappedObjects());
bsalomon3582d3e2015-02-13 14:20:05 -0800153 fScratchMap.insert(resource->resourcePriv().getScratchKey(), resource);
bsalomon744998e2014-08-28 09:54:34 -0700154 }
bsalomon9f2d1572015-02-17 11:47:40 -0800155
bsalomon71cb0c22014-11-14 12:10:14 -0800156 this->purgeAsNeeded();
bsalomonc8dc1f72014-08-21 13:02:13 -0700157}
158
bsalomon0ea80f42015-02-11 10:49:59 -0800159void GrResourceCache::removeResource(GrGpuResource* resource) {
bsalomon9f2d1572015-02-17 11:47:40 -0800160 this->validate();
bsalomon16961262014-08-26 14:01:07 -0700161 SkASSERT(this->isInCache(resource));
bsalomondace19e2014-11-17 07:34:06 -0800162
bsalomon9f2d1572015-02-17 11:47:40 -0800163 if (resource->isPurgeable()) {
164 fPurgeableQueue.remove(resource);
bsalomonf320e042015-02-17 15:09:34 -0800165 } else {
166 this->removeFromNonpurgeableArray(resource);
bsalomon9f2d1572015-02-17 11:47:40 -0800167 }
168
bsalomondace19e2014-11-17 07:34:06 -0800169 size_t size = resource->gpuMemorySize();
bsalomonf320e042015-02-17 15:09:34 -0800170 SkDEBUGCODE(--fCount;)
bsalomondace19e2014-11-17 07:34:06 -0800171 fBytes -= size;
bsalomon5ec26ae2016-02-25 08:33:02 -0800172 if (SkBudgeted::kYes == resource->resourcePriv().isBudgeted()) {
bsalomondace19e2014-11-17 07:34:06 -0800173 --fBudgetedCount;
174 fBudgetedBytes -= size;
hendrikw876c3132015-03-04 10:33:49 -0800175 TRACE_COUNTER2(TRACE_DISABLED_BY_DEFAULT("skia.gpu.cache"), "skia budget", "used",
176 fBudgetedBytes, "free", fMaxBytes - fBudgetedBytes);
bsalomondace19e2014-11-17 07:34:06 -0800177 }
178
robertphillipsc4ed6842016-05-24 14:17:12 -0700179 if (resource->resourcePriv().getScratchKey().isValid() &&
180 !resource->getUniqueKey().isValid()) {
bsalomon3582d3e2015-02-13 14:20:05 -0800181 fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource);
bsalomon744998e2014-08-28 09:54:34 -0700182 }
bsalomon8718aaf2015-02-19 07:24:21 -0800183 if (resource->getUniqueKey().isValid()) {
184 fUniqueHash.remove(resource->getUniqueKey());
bsalomon8b79d232014-11-10 10:19:06 -0800185 }
bsalomonb436ed62014-11-17 12:15:56 -0800186 this->validate();
bsalomonc8dc1f72014-08-21 13:02:13 -0700187}
188
bsalomon0ea80f42015-02-11 10:49:59 -0800189void GrResourceCache::abandonAll() {
bsalomon71cb0c22014-11-14 12:10:14 -0800190 AutoValidate av(this);
191
bsalomonf320e042015-02-17 15:09:34 -0800192 while (fNonpurgeableResources.count()) {
193 GrGpuResource* back = *(fNonpurgeableResources.end() - 1);
194 SkASSERT(!back->wasDestroyed());
195 back->cacheAccess().abandon();
bsalomonc8dc1f72014-08-21 13:02:13 -0700196 }
bsalomonf320e042015-02-17 15:09:34 -0800197
198 while (fPurgeableQueue.count()) {
199 GrGpuResource* top = fPurgeableQueue.peek();
200 SkASSERT(!top->wasDestroyed());
201 top->cacheAccess().abandon();
202 }
203
bsalomon744998e2014-08-28 09:54:34 -0700204 SkASSERT(!fScratchMap.count());
bsalomon8718aaf2015-02-19 07:24:21 -0800205 SkASSERT(!fUniqueHash.count());
bsalomonc8dc1f72014-08-21 13:02:13 -0700206 SkASSERT(!fCount);
bsalomonf320e042015-02-17 15:09:34 -0800207 SkASSERT(!this->getResourceCount());
bsalomondace19e2014-11-17 07:34:06 -0800208 SkASSERT(!fBytes);
209 SkASSERT(!fBudgetedCount);
210 SkASSERT(!fBudgetedBytes);
bsalomonc8dc1f72014-08-21 13:02:13 -0700211}
212
bsalomon0ea80f42015-02-11 10:49:59 -0800213void GrResourceCache::releaseAll() {
bsalomon71cb0c22014-11-14 12:10:14 -0800214 AutoValidate av(this);
215
bsalomonf320e042015-02-17 15:09:34 -0800216 while(fNonpurgeableResources.count()) {
217 GrGpuResource* back = *(fNonpurgeableResources.end() - 1);
218 SkASSERT(!back->wasDestroyed());
219 back->cacheAccess().release();
bsalomonc8dc1f72014-08-21 13:02:13 -0700220 }
bsalomonf320e042015-02-17 15:09:34 -0800221
222 while (fPurgeableQueue.count()) {
223 GrGpuResource* top = fPurgeableQueue.peek();
224 SkASSERT(!top->wasDestroyed());
225 top->cacheAccess().release();
226 }
227
bsalomon744998e2014-08-28 09:54:34 -0700228 SkASSERT(!fScratchMap.count());
bsalomon8718aaf2015-02-19 07:24:21 -0800229 SkASSERT(!fUniqueHash.count());
bsalomonc8dc1f72014-08-21 13:02:13 -0700230 SkASSERT(!fCount);
bsalomonf320e042015-02-17 15:09:34 -0800231 SkASSERT(!this->getResourceCount());
bsalomondace19e2014-11-17 07:34:06 -0800232 SkASSERT(!fBytes);
233 SkASSERT(!fBudgetedCount);
234 SkASSERT(!fBudgetedBytes);
bsalomonc8dc1f72014-08-21 13:02:13 -0700235}
bsalomonbcf0a522014-10-08 08:40:09 -0700236
bsalomon0ea80f42015-02-11 10:49:59 -0800237class GrResourceCache::AvailableForScratchUse {
bsalomonbcf0a522014-10-08 08:40:09 -0700238public:
bsalomon000f8292014-10-15 19:04:14 -0700239 AvailableForScratchUse(bool rejectPendingIO) : fRejectPendingIO(rejectPendingIO) { }
bsalomonbcf0a522014-10-08 08:40:09 -0700240
241 bool operator()(const GrGpuResource* resource) const {
robertphillipsc4ed6842016-05-24 14:17:12 -0700242 SkASSERT(!resource->getUniqueKey().isValid() &&
243 resource->resourcePriv().getScratchKey().isValid());
bsalomon12299ab2014-11-14 13:33:09 -0800244 if (resource->internalHasRef() || !resource->cacheAccess().isScratch()) {
bsalomon000f8292014-10-15 19:04:14 -0700245 return false;
bsalomonbcf0a522014-10-08 08:40:09 -0700246 }
bsalomon000f8292014-10-15 19:04:14 -0700247 return !fRejectPendingIO || !resource->internalHasPendingIO();
bsalomonbcf0a522014-10-08 08:40:09 -0700248 }
bsalomon1e2530b2014-10-09 09:57:18 -0700249
bsalomonbcf0a522014-10-08 08:40:09 -0700250private:
bsalomon000f8292014-10-15 19:04:14 -0700251 bool fRejectPendingIO;
bsalomonbcf0a522014-10-08 08:40:09 -0700252};
253
bsalomon0ea80f42015-02-11 10:49:59 -0800254GrGpuResource* GrResourceCache::findAndRefScratchResource(const GrScratchKey& scratchKey,
robertphillips6e83ac72015-08-13 05:19:14 -0700255 size_t resourceSize,
bsalomon9f2d1572015-02-17 11:47:40 -0800256 uint32_t flags) {
bsalomon7775c852014-12-30 12:50:52 -0800257 SkASSERT(scratchKey.isValid());
bsalomon000f8292014-10-15 19:04:14 -0700258
bsalomon71cb0c22014-11-14 12:10:14 -0800259 GrGpuResource* resource;
bsalomon000f8292014-10-15 19:04:14 -0700260 if (flags & (kPreferNoPendingIO_ScratchFlag | kRequireNoPendingIO_ScratchFlag)) {
bsalomon71cb0c22014-11-14 12:10:14 -0800261 resource = fScratchMap.find(scratchKey, AvailableForScratchUse(true));
bsalomon000f8292014-10-15 19:04:14 -0700262 if (resource) {
bsalomon9f2d1572015-02-17 11:47:40 -0800263 this->refAndMakeResourceMRU(resource);
bsalomonb436ed62014-11-17 12:15:56 -0800264 this->validate();
265 return resource;
bsalomon000f8292014-10-15 19:04:14 -0700266 } else if (flags & kRequireNoPendingIO_ScratchFlag) {
halcanary96fcdcc2015-08-27 07:41:13 -0700267 return nullptr;
bsalomon000f8292014-10-15 19:04:14 -0700268 }
robertphillips63926682015-08-20 09:39:02 -0700269 // We would prefer to consume more available VRAM rather than flushing
270 // immediately, but on ANGLE this can lead to starving of the GPU.
271 if (fPreferVRAMUseOverFlushes && this->wouldFit(resourceSize)) {
robertphillips6e83ac72015-08-13 05:19:14 -0700272 // kPrefer is specified, we didn't find a resource without pending io,
robertphillips63926682015-08-20 09:39:02 -0700273 // but there is still space in our budget for the resource so force
274 // the caller to allocate a new resource.
halcanary96fcdcc2015-08-27 07:41:13 -0700275 return nullptr;
robertphillips6e83ac72015-08-13 05:19:14 -0700276 }
bsalomon000f8292014-10-15 19:04:14 -0700277 }
bsalomon71cb0c22014-11-14 12:10:14 -0800278 resource = fScratchMap.find(scratchKey, AvailableForScratchUse(false));
279 if (resource) {
bsalomon9f2d1572015-02-17 11:47:40 -0800280 this->refAndMakeResourceMRU(resource);
bsalomonb436ed62014-11-17 12:15:56 -0800281 this->validate();
bsalomon71cb0c22014-11-14 12:10:14 -0800282 }
283 return resource;
bsalomonbcf0a522014-10-08 08:40:09 -0700284}
bsalomon8b79d232014-11-10 10:19:06 -0800285
bsalomon0ea80f42015-02-11 10:49:59 -0800286void GrResourceCache::willRemoveScratchKey(const GrGpuResource* resource) {
bsalomon3582d3e2015-02-13 14:20:05 -0800287 SkASSERT(resource->resourcePriv().getScratchKey().isValid());
robertphillipsc4ed6842016-05-24 14:17:12 -0700288 if (!resource->getUniqueKey().isValid()) {
289 fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource);
290 }
bsalomon10e23ca2014-11-25 05:52:06 -0800291}
292
bsalomonf99e9612015-02-19 08:24:16 -0800293void GrResourceCache::removeUniqueKey(GrGpuResource* resource) {
bsalomon3f324322015-04-08 11:01:54 -0700294 // Someone has a ref to this resource in order to have removed the key. When the ref count
295 // reaches zero we will get a ref cnt notification and figure out what to do with it.
bsalomonf99e9612015-02-19 08:24:16 -0800296 if (resource->getUniqueKey().isValid()) {
297 SkASSERT(resource == fUniqueHash.find(resource->getUniqueKey()));
298 fUniqueHash.remove(resource->getUniqueKey());
299 }
300 resource->cacheAccess().removeUniqueKey();
robertphillipsc4ed6842016-05-24 14:17:12 -0700301
302 if (resource->resourcePriv().getScratchKey().isValid()) {
303 fScratchMap.insert(resource->resourcePriv().getScratchKey(), resource);
304 }
305
bsalomonf99e9612015-02-19 08:24:16 -0800306 this->validate();
bsalomon23e619c2015-02-06 11:54:28 -0800307}
308
bsalomonf99e9612015-02-19 08:24:16 -0800309void GrResourceCache::changeUniqueKey(GrGpuResource* resource, const GrUniqueKey& newKey) {
bsalomon8b79d232014-11-10 10:19:06 -0800310 SkASSERT(resource);
bsalomon71cb0c22014-11-14 12:10:14 -0800311 SkASSERT(this->isInCache(resource));
bsalomon8b79d232014-11-10 10:19:06 -0800312
bsalomonf99e9612015-02-19 08:24:16 -0800313 // If another resource has the new key, remove its key then install the key on this resource.
314 if (newKey.isValid()) {
robertphillipsc4ed6842016-05-24 14:17:12 -0700315 // Remove the entry for this resource if it already has a unique key.
316 if (resource->getUniqueKey().isValid()) {
317 SkASSERT(resource == fUniqueHash.find(resource->getUniqueKey()));
318 fUniqueHash.remove(resource->getUniqueKey());
319 SkASSERT(nullptr == fUniqueHash.find(resource->getUniqueKey()));
320 } else {
321 // 'resource' didn't have a valid unique key before so it is switching sides. Remove it
322 // from the ScratchMap
323 if (resource->resourcePriv().getScratchKey().isValid()) {
324 fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource);
325 }
326 }
327
bsalomonf99e9612015-02-19 08:24:16 -0800328 if (GrGpuResource* old = fUniqueHash.find(newKey)) {
329 // If the old resource using the key is purgeable and is unreachable, then remove it.
330 if (!old->resourcePriv().getScratchKey().isValid() && old->isPurgeable()) {
331 // release may call validate() which will assert that resource is in fUniqueHash
332 // if it has a valid key. So in debug reset the key here before we assign it.
333 SkDEBUGCODE(resource->cacheAccess().removeUniqueKey();)
334 old->cacheAccess().release();
335 } else {
robertphillipsc4ed6842016-05-24 14:17:12 -0700336 this->removeUniqueKey(old);
bsalomonf99e9612015-02-19 08:24:16 -0800337 }
338 }
halcanary96fcdcc2015-08-27 07:41:13 -0700339 SkASSERT(nullptr == fUniqueHash.find(newKey));
bsalomonf99e9612015-02-19 08:24:16 -0800340 resource->cacheAccess().setUniqueKey(newKey);
341 fUniqueHash.add(resource);
342 } else {
robertphillipsc4ed6842016-05-24 14:17:12 -0700343 this->removeUniqueKey(resource);
bsalomonf99e9612015-02-19 08:24:16 -0800344 }
345
bsalomon71cb0c22014-11-14 12:10:14 -0800346 this->validate();
bsalomon8b79d232014-11-10 10:19:06 -0800347}
bsalomon71cb0c22014-11-14 12:10:14 -0800348
bsalomon9f2d1572015-02-17 11:47:40 -0800349void GrResourceCache::refAndMakeResourceMRU(GrGpuResource* resource) {
bsalomon71cb0c22014-11-14 12:10:14 -0800350 SkASSERT(resource);
351 SkASSERT(this->isInCache(resource));
bsalomonddf30e62015-02-19 11:38:44 -0800352
bsalomon9f2d1572015-02-17 11:47:40 -0800353 if (resource->isPurgeable()) {
354 // It's about to become unpurgeable.
355 fPurgeableQueue.remove(resource);
bsalomonf320e042015-02-17 15:09:34 -0800356 this->addToNonpurgeableArray(resource);
bsalomon9f2d1572015-02-17 11:47:40 -0800357 }
358 resource->ref();
bsalomonddf30e62015-02-19 11:38:44 -0800359
360 resource->cacheAccess().setTimestamp(this->getNextTimestamp());
bsalomonf320e042015-02-17 15:09:34 -0800361 this->validate();
bsalomon71cb0c22014-11-14 12:10:14 -0800362}
363
bsalomon3f324322015-04-08 11:01:54 -0700364void GrResourceCache::notifyCntReachedZero(GrGpuResource* resource, uint32_t flags) {
bsalomon71cb0c22014-11-14 12:10:14 -0800365 SkASSERT(resource);
bsalomon3f324322015-04-08 11:01:54 -0700366 SkASSERT(!resource->wasDestroyed());
367 SkASSERT(flags);
bsalomon71cb0c22014-11-14 12:10:14 -0800368 SkASSERT(this->isInCache(resource));
bsalomon3f324322015-04-08 11:01:54 -0700369 // This resource should always be in the nonpurgeable array when this function is called. It
370 // will be moved to the queue if it is newly purgeable.
371 SkASSERT(fNonpurgeableResources[*resource->cacheAccess().accessCacheIndex()] == resource);
bsalomon71cb0c22014-11-14 12:10:14 -0800372
bsalomon3f324322015-04-08 11:01:54 -0700373 if (SkToBool(ResourceAccess::kRefCntReachedZero_RefNotificationFlag & flags)) {
374#ifdef SK_DEBUG
375 // When the timestamp overflows validate() is called. validate() checks that resources in
376 // the nonpurgeable array are indeed not purgeable. However, the movement from the array to
377 // the purgeable queue happens just below in this function. So we mark it as an exception.
378 if (resource->isPurgeable()) {
379 fNewlyPurgeableResourceForValidation = resource;
380 }
381#endif
382 resource->cacheAccess().setTimestamp(this->getNextTimestamp());
halcanary96fcdcc2015-08-27 07:41:13 -0700383 SkDEBUGCODE(fNewlyPurgeableResourceForValidation = nullptr);
bsalomon3f324322015-04-08 11:01:54 -0700384 }
385
386 if (!SkToBool(ResourceAccess::kAllCntsReachedZero_RefNotificationFlag & flags)) {
387 SkASSERT(!resource->isPurgeable());
388 return;
389 }
390
391 SkASSERT(resource->isPurgeable());
bsalomonf320e042015-02-17 15:09:34 -0800392 this->removeFromNonpurgeableArray(resource);
bsalomon9f2d1572015-02-17 11:47:40 -0800393 fPurgeableQueue.insert(resource);
bsalomon71cb0c22014-11-14 12:10:14 -0800394
bsalomon5ec26ae2016-02-25 08:33:02 -0800395 if (SkBudgeted::kNo == resource->resourcePriv().isBudgeted()) {
bsalomonc2f35b72015-01-23 07:19:22 -0800396 // Check whether this resource could still be used as a scratch resource.
kkinnunen2e6055b2016-04-22 01:48:29 -0700397 if (!resource->resourcePriv().refsWrappedObjects() &&
bsalomon9f2d1572015-02-17 11:47:40 -0800398 resource->resourcePriv().getScratchKey().isValid()) {
bsalomonc2f35b72015-01-23 07:19:22 -0800399 // We won't purge an existing resource to make room for this one.
bsalomonf320e042015-02-17 15:09:34 -0800400 if (fBudgetedCount < fMaxCount &&
401 fBudgetedBytes + resource->gpuMemorySize() <= fMaxBytes) {
bsalomon3582d3e2015-02-13 14:20:05 -0800402 resource->resourcePriv().makeBudgeted();
bsalomon9f2d1572015-02-17 11:47:40 -0800403 return;
bsalomonc2f35b72015-01-23 07:19:22 -0800404 }
bsalomonc2f35b72015-01-23 07:19:22 -0800405 }
406 } else {
bsalomon9f2d1572015-02-17 11:47:40 -0800407 // Purge the resource immediately if we're over budget
bsalomon8718aaf2015-02-19 07:24:21 -0800408 // Also purge if the resource has neither a valid scratch key nor a unique key.
bsalomon3582d3e2015-02-13 14:20:05 -0800409 bool noKey = !resource->resourcePriv().getScratchKey().isValid() &&
bsalomon8718aaf2015-02-19 07:24:21 -0800410 !resource->getUniqueKey().isValid();
bsalomonf320e042015-02-17 15:09:34 -0800411 if (!this->overBudget() && !noKey) {
bsalomon9f2d1572015-02-17 11:47:40 -0800412 return;
bsalomonc2f35b72015-01-23 07:19:22 -0800413 }
414 }
bsalomondace19e2014-11-17 07:34:06 -0800415
bsalomonf320e042015-02-17 15:09:34 -0800416 SkDEBUGCODE(int beforeCount = this->getResourceCount();)
bsalomon9f2d1572015-02-17 11:47:40 -0800417 resource->cacheAccess().release();
418 // We should at least free this resource, perhaps dependent resources as well.
bsalomonf320e042015-02-17 15:09:34 -0800419 SkASSERT(this->getResourceCount() < beforeCount);
bsalomon71cb0c22014-11-14 12:10:14 -0800420 this->validate();
421}
422
bsalomon0ea80f42015-02-11 10:49:59 -0800423void GrResourceCache::didChangeGpuMemorySize(const GrGpuResource* resource, size_t oldSize) {
bsalomon71cb0c22014-11-14 12:10:14 -0800424 // SkASSERT(!fPurging); GrPathRange increases size during flush. :(
425 SkASSERT(resource);
426 SkASSERT(this->isInCache(resource));
427
bsalomondace19e2014-11-17 07:34:06 -0800428 ptrdiff_t delta = resource->gpuMemorySize() - oldSize;
429
430 fBytes += delta;
bsalomon82b1d622014-11-14 13:59:57 -0800431#if GR_CACHE_STATS
432 fHighWaterBytes = SkTMax(fBytes, fHighWaterBytes);
433#endif
bsalomon5ec26ae2016-02-25 08:33:02 -0800434 if (SkBudgeted::kYes == resource->resourcePriv().isBudgeted()) {
bsalomondace19e2014-11-17 07:34:06 -0800435 fBudgetedBytes += delta;
hendrikw876c3132015-03-04 10:33:49 -0800436 TRACE_COUNTER2(TRACE_DISABLED_BY_DEFAULT("skia.gpu.cache"), "skia budget", "used",
437 fBudgetedBytes, "free", fMaxBytes - fBudgetedBytes);
bsalomondace19e2014-11-17 07:34:06 -0800438#if GR_CACHE_STATS
439 fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes);
440#endif
441 }
bsalomon71cb0c22014-11-14 12:10:14 -0800442
443 this->purgeAsNeeded();
444 this->validate();
445}
446
bsalomon0ea80f42015-02-11 10:49:59 -0800447void GrResourceCache::didChangeBudgetStatus(GrGpuResource* resource) {
bsalomon84c8e622014-11-17 09:33:27 -0800448 SkASSERT(resource);
449 SkASSERT(this->isInCache(resource));
450
451 size_t size = resource->gpuMemorySize();
452
bsalomon5ec26ae2016-02-25 08:33:02 -0800453 if (SkBudgeted::kYes == resource->resourcePriv().isBudgeted()) {
bsalomon84c8e622014-11-17 09:33:27 -0800454 ++fBudgetedCount;
455 fBudgetedBytes += size;
bsalomonafe30052015-01-16 07:32:33 -0800456#if GR_CACHE_STATS
457 fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes);
458 fBudgetedHighWaterCount = SkTMax(fBudgetedCount, fBudgetedHighWaterCount);
459#endif
bsalomon84c8e622014-11-17 09:33:27 -0800460 this->purgeAsNeeded();
461 } else {
462 --fBudgetedCount;
463 fBudgetedBytes -= size;
464 }
hendrikw876c3132015-03-04 10:33:49 -0800465 TRACE_COUNTER2(TRACE_DISABLED_BY_DEFAULT("skia.gpu.cache"), "skia budget", "used",
466 fBudgetedBytes, "free", fMaxBytes - fBudgetedBytes);
bsalomon84c8e622014-11-17 09:33:27 -0800467
468 this->validate();
469}
470
bsalomon3f324322015-04-08 11:01:54 -0700471void GrResourceCache::purgeAsNeeded() {
472 SkTArray<GrUniqueKeyInvalidatedMessage> invalidKeyMsgs;
473 fInvalidUniqueKeyInbox.poll(&invalidKeyMsgs);
474 if (invalidKeyMsgs.count()) {
475 this->processInvalidUniqueKeys(invalidKeyMsgs);
476 }
bsalomon71cb0c22014-11-14 12:10:14 -0800477
bsalomon3f324322015-04-08 11:01:54 -0700478 if (fFlushTimestamps) {
479 // Assuming kNumFlushesToDeleteUnusedResource is a power of 2.
480 SkASSERT(SkIsPow2(fMaxUnusedFlushes));
481 int oldestFlushIndex = (fLastFlushTimestampIndex + 1) & (fMaxUnusedFlushes - 1);
482
483 uint32_t oldestAllowedTimestamp = fFlushTimestamps[oldestFlushIndex];
484 while (fPurgeableQueue.count()) {
485 uint32_t oldestResourceTimestamp = fPurgeableQueue.peek()->cacheAccess().timestamp();
486 if (oldestAllowedTimestamp < oldestResourceTimestamp) {
487 break;
488 }
489 GrGpuResource* resource = fPurgeableQueue.peek();
490 SkASSERT(resource->isPurgeable());
491 resource->cacheAccess().release();
492 }
493 }
494
495 bool stillOverbudget = this->overBudget();
496 while (stillOverbudget && fPurgeableQueue.count()) {
bsalomon9f2d1572015-02-17 11:47:40 -0800497 GrGpuResource* resource = fPurgeableQueue.peek();
498 SkASSERT(resource->isPurgeable());
499 resource->cacheAccess().release();
bsalomon3f324322015-04-08 11:01:54 -0700500 stillOverbudget = this->overBudget();
bsalomon9f2d1572015-02-17 11:47:40 -0800501 }
bsalomon71cb0c22014-11-14 12:10:14 -0800502
bsalomonb436ed62014-11-17 12:15:56 -0800503 this->validate();
bsalomon9f2d1572015-02-17 11:47:40 -0800504
505 if (stillOverbudget) {
506 // Despite the purge we're still over budget. Call our over budget callback. If this frees
bsalomon3f324322015-04-08 11:01:54 -0700507 // any resources then we'll get notified and take appropriate action.
bsalomon9f2d1572015-02-17 11:47:40 -0800508 (*fOverBudgetCB)(fOverBudgetData);
509 this->validate();
510 }
bsalomon71cb0c22014-11-14 12:10:14 -0800511}
512
bsalomon0ea80f42015-02-11 10:49:59 -0800513void GrResourceCache::purgeAllUnlocked() {
bsalomon9f2d1572015-02-17 11:47:40 -0800514 // We could disable maintaining the heap property here, but it would add a lot of complexity.
515 // Moreover, this is rarely called.
516 while (fPurgeableQueue.count()) {
517 GrGpuResource* resource = fPurgeableQueue.peek();
518 SkASSERT(resource->isPurgeable());
519 resource->cacheAccess().release();
520 }
bsalomon71cb0c22014-11-14 12:10:14 -0800521
bsalomonb436ed62014-11-17 12:15:56 -0800522 this->validate();
bsalomon71cb0c22014-11-14 12:10:14 -0800523}
524
bsalomon8718aaf2015-02-19 07:24:21 -0800525void GrResourceCache::processInvalidUniqueKeys(
526 const SkTArray<GrUniqueKeyInvalidatedMessage>& msgs) {
bsalomon23e619c2015-02-06 11:54:28 -0800527 for (int i = 0; i < msgs.count(); ++i) {
bsalomon8718aaf2015-02-19 07:24:21 -0800528 GrGpuResource* resource = this->findAndRefUniqueResource(msgs[i].key());
bsalomon23e619c2015-02-06 11:54:28 -0800529 if (resource) {
bsalomon8718aaf2015-02-19 07:24:21 -0800530 resource->resourcePriv().removeUniqueKey();
bsalomon3f324322015-04-08 11:01:54 -0700531 resource->unref(); // If this resource is now purgeable, the cache will be notified.
bsalomon23e619c2015-02-06 11:54:28 -0800532 }
533 }
534}
535
bsalomonf320e042015-02-17 15:09:34 -0800536void GrResourceCache::addToNonpurgeableArray(GrGpuResource* resource) {
537 int index = fNonpurgeableResources.count();
538 *fNonpurgeableResources.append() = resource;
539 *resource->cacheAccess().accessCacheIndex() = index;
540}
541
542void GrResourceCache::removeFromNonpurgeableArray(GrGpuResource* resource) {
543 int* index = resource->cacheAccess().accessCacheIndex();
544 // Fill the whole we will create in the array with the tail object, adjust its index, and
545 // then pop the array
546 GrGpuResource* tail = *(fNonpurgeableResources.end() - 1);
547 SkASSERT(fNonpurgeableResources[*index] == resource);
548 fNonpurgeableResources[*index] = tail;
549 *tail->cacheAccess().accessCacheIndex() = *index;
550 fNonpurgeableResources.pop();
551 SkDEBUGCODE(*index = -1);
552}
553
bsalomonddf30e62015-02-19 11:38:44 -0800554uint32_t GrResourceCache::getNextTimestamp() {
555 // If we wrap then all the existing resources will appear older than any resources that get
556 // a timestamp after the wrap.
557 if (0 == fTimestamp) {
558 int count = this->getResourceCount();
559 if (count) {
560 // Reset all the timestamps. We sort the resources by timestamp and then assign
561 // sequential timestamps beginning with 0. This is O(n*lg(n)) but it should be extremely
562 // rare.
563 SkTDArray<GrGpuResource*> sortedPurgeableResources;
564 sortedPurgeableResources.setReserve(fPurgeableQueue.count());
565
566 while (fPurgeableQueue.count()) {
567 *sortedPurgeableResources.append() = fPurgeableQueue.peek();
568 fPurgeableQueue.pop();
569 }
570
571 struct Less {
572 bool operator()(GrGpuResource* a, GrGpuResource* b) {
573 return CompareTimestamp(a,b);
574 }
575 };
576 Less less;
577 SkTQSort(fNonpurgeableResources.begin(), fNonpurgeableResources.end() - 1, less);
578
579 // Pick resources out of the purgeable and non-purgeable arrays based on lowest
580 // timestamp and assign new timestamps.
581 int currP = 0;
582 int currNP = 0;
583 while (currP < sortedPurgeableResources.count() &&
mtklein56da0252015-11-16 11:16:23 -0800584 currNP < fNonpurgeableResources.count()) {
bsalomonddf30e62015-02-19 11:38:44 -0800585 uint32_t tsP = sortedPurgeableResources[currP]->cacheAccess().timestamp();
586 uint32_t tsNP = fNonpurgeableResources[currNP]->cacheAccess().timestamp();
587 SkASSERT(tsP != tsNP);
588 if (tsP < tsNP) {
589 sortedPurgeableResources[currP++]->cacheAccess().setTimestamp(fTimestamp++);
590 } else {
591 // Correct the index in the nonpurgeable array stored on the resource post-sort.
592 *fNonpurgeableResources[currNP]->cacheAccess().accessCacheIndex() = currNP;
593 fNonpurgeableResources[currNP++]->cacheAccess().setTimestamp(fTimestamp++);
594 }
595 }
596
597 // The above loop ended when we hit the end of one array. Finish the other one.
598 while (currP < sortedPurgeableResources.count()) {
599 sortedPurgeableResources[currP++]->cacheAccess().setTimestamp(fTimestamp++);
600 }
601 while (currNP < fNonpurgeableResources.count()) {
602 *fNonpurgeableResources[currNP]->cacheAccess().accessCacheIndex() = currNP;
603 fNonpurgeableResources[currNP++]->cacheAccess().setTimestamp(fTimestamp++);
604 }
605
606 // Rebuild the queue.
607 for (int i = 0; i < sortedPurgeableResources.count(); ++i) {
608 fPurgeableQueue.insert(sortedPurgeableResources[i]);
609 }
610
611 this->validate();
612 SkASSERT(count == this->getResourceCount());
613
614 // count should be the next timestamp we return.
615 SkASSERT(fTimestamp == SkToU32(count));
mtklein56da0252015-11-16 11:16:23 -0800616
bsalomon3f324322015-04-08 11:01:54 -0700617 // The historical timestamps of flushes are now invalid.
618 this->resetFlushTimestamps();
mtklein56da0252015-11-16 11:16:23 -0800619 }
bsalomonddf30e62015-02-19 11:38:44 -0800620 }
621 return fTimestamp++;
622}
623
bsalomon3f324322015-04-08 11:01:54 -0700624void GrResourceCache::notifyFlushOccurred() {
625 if (fFlushTimestamps) {
626 SkASSERT(SkIsPow2(fMaxUnusedFlushes));
627 fLastFlushTimestampIndex = (fLastFlushTimestampIndex + 1) & (fMaxUnusedFlushes - 1);
628 // get the timestamp before accessing fFlushTimestamps because getNextTimestamp will
629 // reallocate fFlushTimestamps on timestamp overflow.
630 uint32_t timestamp = this->getNextTimestamp();
631 fFlushTimestamps[fLastFlushTimestampIndex] = timestamp;
632 this->purgeAsNeeded();
633 }
634}
635
ericrk0a5fa482015-09-15 14:16:10 -0700636void GrResourceCache::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
637 for (int i = 0; i < fNonpurgeableResources.count(); ++i) {
638 fNonpurgeableResources[i]->dumpMemoryStatistics(traceMemoryDump);
639 }
640 for (int i = 0; i < fPurgeableQueue.count(); ++i) {
641 fPurgeableQueue.at(i)->dumpMemoryStatistics(traceMemoryDump);
642 }
643}
644
bsalomon71cb0c22014-11-14 12:10:14 -0800645#ifdef SK_DEBUG
bsalomon0ea80f42015-02-11 10:49:59 -0800646void GrResourceCache::validate() const {
bsalomonc2f35b72015-01-23 07:19:22 -0800647 // Reduce the frequency of validations for large resource counts.
648 static SkRandom gRandom;
649 int mask = (SkNextPow2(fCount + 1) >> 5) - 1;
650 if (~mask && (gRandom.nextU() & mask)) {
651 return;
652 }
653
bsalomonf320e042015-02-17 15:09:34 -0800654 struct Stats {
655 size_t fBytes;
656 int fBudgetedCount;
657 size_t fBudgetedBytes;
658 int fLocked;
659 int fScratch;
660 int fCouldBeScratch;
661 int fContent;
662 const ScratchMap* fScratchMap;
bsalomon8718aaf2015-02-19 07:24:21 -0800663 const UniqueHash* fUniqueHash;
bsalomon71cb0c22014-11-14 12:10:14 -0800664
bsalomonf320e042015-02-17 15:09:34 -0800665 Stats(const GrResourceCache* cache) {
666 memset(this, 0, sizeof(*this));
667 fScratchMap = &cache->fScratchMap;
bsalomon8718aaf2015-02-19 07:24:21 -0800668 fUniqueHash = &cache->fUniqueHash;
bsalomon71cb0c22014-11-14 12:10:14 -0800669 }
670
bsalomonf320e042015-02-17 15:09:34 -0800671 void update(GrGpuResource* resource) {
672 fBytes += resource->gpuMemorySize();
bsalomondace19e2014-11-17 07:34:06 -0800673
bsalomonf320e042015-02-17 15:09:34 -0800674 if (!resource->isPurgeable()) {
675 ++fLocked;
676 }
bsalomon9f2d1572015-02-17 11:47:40 -0800677
robertphillipsc4ed6842016-05-24 14:17:12 -0700678 const GrScratchKey& scratchKey = resource->resourcePriv().getScratchKey();
679 const GrUniqueKey& uniqueKey = resource->getUniqueKey();
680
bsalomonf320e042015-02-17 15:09:34 -0800681 if (resource->cacheAccess().isScratch()) {
robertphillipsc4ed6842016-05-24 14:17:12 -0700682 SkASSERT(!uniqueKey.isValid());
bsalomonf320e042015-02-17 15:09:34 -0800683 ++fScratch;
robertphillipsc4ed6842016-05-24 14:17:12 -0700684 SkASSERT(fScratchMap->countForKey(scratchKey));
kkinnunen2e6055b2016-04-22 01:48:29 -0700685 SkASSERT(!resource->resourcePriv().refsWrappedObjects());
robertphillipsc4ed6842016-05-24 14:17:12 -0700686 } else if (scratchKey.isValid()) {
bsalomon5ec26ae2016-02-25 08:33:02 -0800687 SkASSERT(SkBudgeted::kNo == resource->resourcePriv().isBudgeted() ||
robertphillipsc4ed6842016-05-24 14:17:12 -0700688 uniqueKey.isValid());
689 if (!uniqueKey.isValid()) {
690 ++fCouldBeScratch;
691 SkASSERT(fScratchMap->countForKey(scratchKey));
692 }
kkinnunen2e6055b2016-04-22 01:48:29 -0700693 SkASSERT(!resource->resourcePriv().refsWrappedObjects());
bsalomonf320e042015-02-17 15:09:34 -0800694 }
bsalomon8718aaf2015-02-19 07:24:21 -0800695 if (uniqueKey.isValid()) {
bsalomonf320e042015-02-17 15:09:34 -0800696 ++fContent;
bsalomon8718aaf2015-02-19 07:24:21 -0800697 SkASSERT(fUniqueHash->find(uniqueKey) == resource);
kkinnunen2e6055b2016-04-22 01:48:29 -0700698 SkASSERT(!resource->resourcePriv().refsWrappedObjects());
bsalomon5ec26ae2016-02-25 08:33:02 -0800699 SkASSERT(SkBudgeted::kYes == resource->resourcePriv().isBudgeted());
robertphillipsc4ed6842016-05-24 14:17:12 -0700700
701 if (scratchKey.isValid()) {
702 SkASSERT(!fScratchMap->has(resource, scratchKey));
703 }
bsalomonf320e042015-02-17 15:09:34 -0800704 }
705
bsalomon5ec26ae2016-02-25 08:33:02 -0800706 if (SkBudgeted::kYes == resource->resourcePriv().isBudgeted()) {
bsalomonf320e042015-02-17 15:09:34 -0800707 ++fBudgetedCount;
708 fBudgetedBytes += resource->gpuMemorySize();
709 }
bsalomon9f2d1572015-02-17 11:47:40 -0800710 }
bsalomonf320e042015-02-17 15:09:34 -0800711 };
712
robertphillipsc4ed6842016-05-24 14:17:12 -0700713 {
714 ScratchMap::ConstIter iter(&fScratchMap);
715
716 int count = 0;
717 for ( ; !iter.done(); ++iter) {
718 const GrGpuResource* resource = *iter;
719 SkASSERT(resource->resourcePriv().getScratchKey().isValid());
720 SkASSERT(!resource->getUniqueKey().isValid());
721 count++;
722 }
723 SkASSERT(count == fScratchMap.count()); // ensure the iterator is working correctly
724 }
725
bsalomonf320e042015-02-17 15:09:34 -0800726 Stats stats(this);
727
728 for (int i = 0; i < fNonpurgeableResources.count(); ++i) {
bsalomon3f324322015-04-08 11:01:54 -0700729 SkASSERT(!fNonpurgeableResources[i]->isPurgeable() ||
730 fNewlyPurgeableResourceForValidation == fNonpurgeableResources[i]);
bsalomonf320e042015-02-17 15:09:34 -0800731 SkASSERT(*fNonpurgeableResources[i]->cacheAccess().accessCacheIndex() == i);
732 SkASSERT(!fNonpurgeableResources[i]->wasDestroyed());
733 stats.update(fNonpurgeableResources[i]);
bsalomon71cb0c22014-11-14 12:10:14 -0800734 }
bsalomon9f2d1572015-02-17 11:47:40 -0800735 for (int i = 0; i < fPurgeableQueue.count(); ++i) {
736 SkASSERT(fPurgeableQueue.at(i)->isPurgeable());
bsalomonf320e042015-02-17 15:09:34 -0800737 SkASSERT(*fPurgeableQueue.at(i)->cacheAccess().accessCacheIndex() == i);
738 SkASSERT(!fPurgeableQueue.at(i)->wasDestroyed());
739 stats.update(fPurgeableQueue.at(i));
bsalomon9f2d1572015-02-17 11:47:40 -0800740 }
741
bsalomonf320e042015-02-17 15:09:34 -0800742 SkASSERT(fCount == this->getResourceCount());
bsalomondace19e2014-11-17 07:34:06 -0800743 SkASSERT(fBudgetedCount <= fCount);
bsalomonf320e042015-02-17 15:09:34 -0800744 SkASSERT(fBudgetedBytes <= fBytes);
745 SkASSERT(stats.fBytes == fBytes);
746 SkASSERT(stats.fBudgetedBytes == fBudgetedBytes);
747 SkASSERT(stats.fBudgetedCount == fBudgetedCount);
bsalomon71cb0c22014-11-14 12:10:14 -0800748#if GR_CACHE_STATS
bsalomondace19e2014-11-17 07:34:06 -0800749 SkASSERT(fBudgetedHighWaterCount <= fHighWaterCount);
750 SkASSERT(fBudgetedHighWaterBytes <= fHighWaterBytes);
bsalomonf320e042015-02-17 15:09:34 -0800751 SkASSERT(fBytes <= fHighWaterBytes);
752 SkASSERT(fCount <= fHighWaterCount);
753 SkASSERT(fBudgetedBytes <= fBudgetedHighWaterBytes);
754 SkASSERT(fBudgetedCount <= fBudgetedHighWaterCount);
bsalomon71cb0c22014-11-14 12:10:14 -0800755#endif
bsalomon8718aaf2015-02-19 07:24:21 -0800756 SkASSERT(stats.fContent == fUniqueHash.count());
bsalomonf320e042015-02-17 15:09:34 -0800757 SkASSERT(stats.fScratch + stats.fCouldBeScratch == fScratchMap.count());
bsalomon71cb0c22014-11-14 12:10:14 -0800758
bsalomon3f324322015-04-08 11:01:54 -0700759 // This assertion is not currently valid because we can be in recursive notifyCntReachedZero()
bsalomon12299ab2014-11-14 13:33:09 -0800760 // calls. This will be fixed when subresource registration is explicit.
bsalomondace19e2014-11-17 07:34:06 -0800761 // bool overBudget = budgetedBytes > fMaxBytes || budgetedCount > fMaxCount;
bsalomon12299ab2014-11-14 13:33:09 -0800762 // SkASSERT(!overBudget || locked == count || fPurging);
bsalomon71cb0c22014-11-14 12:10:14 -0800763}
bsalomonf320e042015-02-17 15:09:34 -0800764
765bool GrResourceCache::isInCache(const GrGpuResource* resource) const {
766 int index = *resource->cacheAccess().accessCacheIndex();
767 if (index < 0) {
768 return false;
769 }
770 if (index < fPurgeableQueue.count() && fPurgeableQueue.at(index) == resource) {
771 return true;
772 }
773 if (index < fNonpurgeableResources.count() && fNonpurgeableResources[index] == resource) {
774 return true;
775 }
776 SkDEBUGFAIL("Resource index should be -1 or the resource should be in the cache.");
777 return false;
778}
779
bsalomon71cb0c22014-11-14 12:10:14 -0800780#endif