blob: 299f63fd86773ed72dceb953ae3ed93bb044dab3 [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
Brian Osman13dddce2017-05-09 13:19:50 -040021DECLARE_SKMESSAGEBUS_MESSAGE(GrGpuResourceFreedMessage);
22
bsalomon71cb0c22014-11-14 12:10:14 -080023//////////////////////////////////////////////////////////////////////////////
24
bsalomon7775c852014-12-30 12:50:52 -080025GrScratchKey::ResourceType GrScratchKey::GenerateResourceType() {
bsalomon24db3b12015-01-23 04:24:04 -080026 static int32_t gType = INHERITED::kInvalidDomain + 1;
bsalomonfe369ee2014-11-10 11:59:06 -080027
bsalomon7775c852014-12-30 12:50:52 -080028 int32_t type = sk_atomic_inc(&gType);
robertphillips9790a7b2015-01-05 12:29:15 -080029 if (type > SK_MaxU16) {
bsalomon71cb0c22014-11-14 12:10:14 -080030 SkFAIL("Too many Resource Types");
31 }
32
33 return static_cast<ResourceType>(type);
34}
35
bsalomon8718aaf2015-02-19 07:24:21 -080036GrUniqueKey::Domain GrUniqueKey::GenerateDomain() {
bsalomon24db3b12015-01-23 04:24:04 -080037 static int32_t gDomain = INHERITED::kInvalidDomain + 1;
bsalomon7775c852014-12-30 12:50:52 -080038
bsalomon24db3b12015-01-23 04:24:04 -080039 int32_t domain = sk_atomic_inc(&gDomain);
kkinnunen016dffb2015-01-23 06:43:05 -080040 if (domain > SK_MaxU16) {
bsalomon8718aaf2015-02-19 07:24:21 -080041 SkFAIL("Too many GrUniqueKey Domains");
bsalomon7775c852014-12-30 12:50:52 -080042 }
bsalomon24db3b12015-01-23 04:24:04 -080043
44 return static_cast<Domain>(domain);
45}
bsalomon3f324322015-04-08 11:01:54 -070046
bsalomon24db3b12015-01-23 04:24:04 -080047uint32_t GrResourceKeyHash(const uint32_t* data, size_t size) {
mtklein4e976072016-08-08 09:06:27 -070048 return SkOpts::hash(data, size);
bsalomon7775c852014-12-30 12:50:52 -080049}
50
bsalomonfe369ee2014-11-10 11:59:06 -080051//////////////////////////////////////////////////////////////////////////////
52
bsalomon0ea80f42015-02-11 10:49:59 -080053class GrResourceCache::AutoValidate : ::SkNoncopyable {
bsalomon71cb0c22014-11-14 12:10:14 -080054public:
bsalomon0ea80f42015-02-11 10:49:59 -080055 AutoValidate(GrResourceCache* cache) : fCache(cache) { cache->validate(); }
bsalomon71cb0c22014-11-14 12:10:14 -080056 ~AutoValidate() { fCache->validate(); }
57private:
bsalomon0ea80f42015-02-11 10:49:59 -080058 GrResourceCache* fCache;
bsalomon71cb0c22014-11-14 12:10:14 -080059};
60
61 //////////////////////////////////////////////////////////////////////////////
robertphillipsee843b22016-10-04 05:30:20 -070062
bsalomon71cb0c22014-11-14 12:10:14 -080063
Brian Osman13dddce2017-05-09 13:19:50 -040064GrResourceCache::GrResourceCache(const GrCaps* caps, uint32_t contextUniqueID)
bsalomon9f2d1572015-02-17 11:47:40 -080065 : fTimestamp(0)
66 , fMaxCount(kDefaultMaxCount)
bsalomon71cb0c22014-11-14 12:10:14 -080067 , fMaxBytes(kDefaultMaxSize)
bsalomon3f324322015-04-08 11:01:54 -070068 , fMaxUnusedFlushes(kDefaultMaxUnusedFlushes)
bsalomon71cb0c22014-11-14 12:10:14 -080069#if GR_CACHE_STATS
70 , fHighWaterCount(0)
71 , fHighWaterBytes(0)
bsalomondace19e2014-11-17 07:34:06 -080072 , fBudgetedHighWaterCount(0)
73 , fBudgetedHighWaterBytes(0)
bsalomon71cb0c22014-11-14 12:10:14 -080074#endif
bsalomon71cb0c22014-11-14 12:10:14 -080075 , fBytes(0)
bsalomondace19e2014-11-17 07:34:06 -080076 , fBudgetedCount(0)
77 , fBudgetedBytes(0)
robertphillipsee843b22016-10-04 05:30:20 -070078 , fRequestFlush(false)
bsalomone2e87f32016-09-22 12:42:11 -070079 , fExternalFlushCnt(0)
Brian Osman13dddce2017-05-09 13:19:50 -040080 , fContextUniqueID(contextUniqueID)
robertphillips63926682015-08-20 09:39:02 -070081 , fPreferVRAMUseOverFlushes(caps->preferVRAMUseOverFlushes()) {
bsalomonf320e042015-02-17 15:09:34 -080082 SkDEBUGCODE(fCount = 0;)
halcanary96fcdcc2015-08-27 07:41:13 -070083 SkDEBUGCODE(fNewlyPurgeableResourceForValidation = nullptr;)
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();
88}
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;
bsalomon71cb0c22014-11-14 12:10:14 -080094 this->purgeAsNeeded();
95}
96
bsalomon0ea80f42015-02-11 10:49:59 -080097void GrResourceCache::insertResource(GrGpuResource* resource) {
bsalomon49f085d2014-09-05 13:34:00 -070098 SkASSERT(resource);
bsalomon16961262014-08-26 14:01:07 -070099 SkASSERT(!this->isInCache(resource));
bsalomonf320e042015-02-17 15:09:34 -0800100 SkASSERT(!resource->wasDestroyed());
101 SkASSERT(!resource->isPurgeable());
bsalomonddf30e62015-02-19 11:38:44 -0800102
103 // We must set the timestamp before adding to the array in case the timestamp wraps and we wind
104 // up iterating over all the resources that already have timestamps.
105 resource->cacheAccess().setTimestamp(this->getNextTimestamp());
106
bsalomonf320e042015-02-17 15:09:34 -0800107 this->addToNonpurgeableArray(resource);
bsalomon71cb0c22014-11-14 12:10:14 -0800108
bsalomondace19e2014-11-17 07:34:06 -0800109 size_t size = resource->gpuMemorySize();
bsalomonf320e042015-02-17 15:09:34 -0800110 SkDEBUGCODE(++fCount;)
bsalomon84c8e622014-11-17 09:33:27 -0800111 fBytes += size;
bsalomon82b1d622014-11-14 13:59:57 -0800112#if GR_CACHE_STATS
bsalomonf320e042015-02-17 15:09:34 -0800113 fHighWaterCount = SkTMax(this->getResourceCount(), fHighWaterCount);
bsalomon82b1d622014-11-14 13:59:57 -0800114 fHighWaterBytes = SkTMax(fBytes, fHighWaterBytes);
115#endif
bsalomon5ec26ae2016-02-25 08:33:02 -0800116 if (SkBudgeted::kYes == resource->resourcePriv().isBudgeted()) {
bsalomondace19e2014-11-17 07:34:06 -0800117 ++fBudgetedCount;
118 fBudgetedBytes += size;
hendrikw876c3132015-03-04 10:33:49 -0800119 TRACE_COUNTER2(TRACE_DISABLED_BY_DEFAULT("skia.gpu.cache"), "skia budget", "used",
120 fBudgetedBytes, "free", fMaxBytes - fBudgetedBytes);
bsalomondace19e2014-11-17 07:34:06 -0800121#if GR_CACHE_STATS
122 fBudgetedHighWaterCount = SkTMax(fBudgetedCount, fBudgetedHighWaterCount);
123 fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes);
124#endif
125 }
robertphillipsc4ed6842016-05-24 14:17:12 -0700126 if (resource->resourcePriv().getScratchKey().isValid() &&
127 !resource->getUniqueKey().isValid()) {
kkinnunen2e6055b2016-04-22 01:48:29 -0700128 SkASSERT(!resource->resourcePriv().refsWrappedObjects());
bsalomon3582d3e2015-02-13 14:20:05 -0800129 fScratchMap.insert(resource->resourcePriv().getScratchKey(), resource);
bsalomon744998e2014-08-28 09:54:34 -0700130 }
bsalomon9f2d1572015-02-17 11:47:40 -0800131
bsalomon71cb0c22014-11-14 12:10:14 -0800132 this->purgeAsNeeded();
bsalomonc8dc1f72014-08-21 13:02:13 -0700133}
134
bsalomon0ea80f42015-02-11 10:49:59 -0800135void GrResourceCache::removeResource(GrGpuResource* resource) {
bsalomon9f2d1572015-02-17 11:47:40 -0800136 this->validate();
bsalomon16961262014-08-26 14:01:07 -0700137 SkASSERT(this->isInCache(resource));
bsalomondace19e2014-11-17 07:34:06 -0800138
bsalomon9f2d1572015-02-17 11:47:40 -0800139 if (resource->isPurgeable()) {
140 fPurgeableQueue.remove(resource);
bsalomonf320e042015-02-17 15:09:34 -0800141 } else {
142 this->removeFromNonpurgeableArray(resource);
bsalomon9f2d1572015-02-17 11:47:40 -0800143 }
144
bsalomondace19e2014-11-17 07:34:06 -0800145 size_t size = resource->gpuMemorySize();
bsalomonf320e042015-02-17 15:09:34 -0800146 SkDEBUGCODE(--fCount;)
bsalomondace19e2014-11-17 07:34:06 -0800147 fBytes -= size;
bsalomon5ec26ae2016-02-25 08:33:02 -0800148 if (SkBudgeted::kYes == resource->resourcePriv().isBudgeted()) {
bsalomondace19e2014-11-17 07:34:06 -0800149 --fBudgetedCount;
150 fBudgetedBytes -= size;
hendrikw876c3132015-03-04 10:33:49 -0800151 TRACE_COUNTER2(TRACE_DISABLED_BY_DEFAULT("skia.gpu.cache"), "skia budget", "used",
152 fBudgetedBytes, "free", fMaxBytes - fBudgetedBytes);
bsalomondace19e2014-11-17 07:34:06 -0800153 }
154
robertphillipsc4ed6842016-05-24 14:17:12 -0700155 if (resource->resourcePriv().getScratchKey().isValid() &&
156 !resource->getUniqueKey().isValid()) {
bsalomon3582d3e2015-02-13 14:20:05 -0800157 fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource);
bsalomon744998e2014-08-28 09:54:34 -0700158 }
bsalomon8718aaf2015-02-19 07:24:21 -0800159 if (resource->getUniqueKey().isValid()) {
160 fUniqueHash.remove(resource->getUniqueKey());
bsalomon8b79d232014-11-10 10:19:06 -0800161 }
bsalomonb436ed62014-11-17 12:15:56 -0800162 this->validate();
bsalomonc8dc1f72014-08-21 13:02:13 -0700163}
164
bsalomon0ea80f42015-02-11 10:49:59 -0800165void GrResourceCache::abandonAll() {
bsalomon71cb0c22014-11-14 12:10:14 -0800166 AutoValidate av(this);
167
bsalomonf320e042015-02-17 15:09:34 -0800168 while (fNonpurgeableResources.count()) {
169 GrGpuResource* back = *(fNonpurgeableResources.end() - 1);
170 SkASSERT(!back->wasDestroyed());
171 back->cacheAccess().abandon();
bsalomonc8dc1f72014-08-21 13:02:13 -0700172 }
bsalomonf320e042015-02-17 15:09:34 -0800173
174 while (fPurgeableQueue.count()) {
175 GrGpuResource* top = fPurgeableQueue.peek();
176 SkASSERT(!top->wasDestroyed());
177 top->cacheAccess().abandon();
178 }
179
bsalomon744998e2014-08-28 09:54:34 -0700180 SkASSERT(!fScratchMap.count());
bsalomon8718aaf2015-02-19 07:24:21 -0800181 SkASSERT(!fUniqueHash.count());
bsalomonc8dc1f72014-08-21 13:02:13 -0700182 SkASSERT(!fCount);
bsalomonf320e042015-02-17 15:09:34 -0800183 SkASSERT(!this->getResourceCount());
bsalomondace19e2014-11-17 07:34:06 -0800184 SkASSERT(!fBytes);
185 SkASSERT(!fBudgetedCount);
186 SkASSERT(!fBudgetedBytes);
bsalomonc8dc1f72014-08-21 13:02:13 -0700187}
188
bsalomon0ea80f42015-02-11 10:49:59 -0800189void GrResourceCache::releaseAll() {
bsalomon71cb0c22014-11-14 12:10:14 -0800190 AutoValidate av(this);
191
Brian Osman13dddce2017-05-09 13:19:50 -0400192 this->processFreedGpuResources();
193
bsalomonf320e042015-02-17 15:09:34 -0800194 while(fNonpurgeableResources.count()) {
195 GrGpuResource* back = *(fNonpurgeableResources.end() - 1);
196 SkASSERT(!back->wasDestroyed());
197 back->cacheAccess().release();
bsalomonc8dc1f72014-08-21 13:02:13 -0700198 }
bsalomonf320e042015-02-17 15:09:34 -0800199
200 while (fPurgeableQueue.count()) {
201 GrGpuResource* top = fPurgeableQueue.peek();
202 SkASSERT(!top->wasDestroyed());
203 top->cacheAccess().release();
204 }
205
bsalomon744998e2014-08-28 09:54:34 -0700206 SkASSERT(!fScratchMap.count());
bsalomon8718aaf2015-02-19 07:24:21 -0800207 SkASSERT(!fUniqueHash.count());
bsalomonc8dc1f72014-08-21 13:02:13 -0700208 SkASSERT(!fCount);
bsalomonf320e042015-02-17 15:09:34 -0800209 SkASSERT(!this->getResourceCount());
bsalomondace19e2014-11-17 07:34:06 -0800210 SkASSERT(!fBytes);
211 SkASSERT(!fBudgetedCount);
212 SkASSERT(!fBudgetedBytes);
bsalomonc8dc1f72014-08-21 13:02:13 -0700213}
bsalomonbcf0a522014-10-08 08:40:09 -0700214
bsalomon0ea80f42015-02-11 10:49:59 -0800215class GrResourceCache::AvailableForScratchUse {
bsalomonbcf0a522014-10-08 08:40:09 -0700216public:
bsalomon000f8292014-10-15 19:04:14 -0700217 AvailableForScratchUse(bool rejectPendingIO) : fRejectPendingIO(rejectPendingIO) { }
bsalomonbcf0a522014-10-08 08:40:09 -0700218
219 bool operator()(const GrGpuResource* resource) const {
robertphillipsc4ed6842016-05-24 14:17:12 -0700220 SkASSERT(!resource->getUniqueKey().isValid() &&
221 resource->resourcePriv().getScratchKey().isValid());
bsalomon12299ab2014-11-14 13:33:09 -0800222 if (resource->internalHasRef() || !resource->cacheAccess().isScratch()) {
bsalomon000f8292014-10-15 19:04:14 -0700223 return false;
bsalomonbcf0a522014-10-08 08:40:09 -0700224 }
bsalomon000f8292014-10-15 19:04:14 -0700225 return !fRejectPendingIO || !resource->internalHasPendingIO();
bsalomonbcf0a522014-10-08 08:40:09 -0700226 }
bsalomon1e2530b2014-10-09 09:57:18 -0700227
bsalomonbcf0a522014-10-08 08:40:09 -0700228private:
bsalomon000f8292014-10-15 19:04:14 -0700229 bool fRejectPendingIO;
bsalomonbcf0a522014-10-08 08:40:09 -0700230};
231
bsalomon0ea80f42015-02-11 10:49:59 -0800232GrGpuResource* GrResourceCache::findAndRefScratchResource(const GrScratchKey& scratchKey,
robertphillips6e83ac72015-08-13 05:19:14 -0700233 size_t resourceSize,
bsalomon9f2d1572015-02-17 11:47:40 -0800234 uint32_t flags) {
bsalomon7775c852014-12-30 12:50:52 -0800235 SkASSERT(scratchKey.isValid());
robertphillipsee843b22016-10-04 05:30:20 -0700236
bsalomon71cb0c22014-11-14 12:10:14 -0800237 GrGpuResource* resource;
bsalomon000f8292014-10-15 19:04:14 -0700238 if (flags & (kPreferNoPendingIO_ScratchFlag | kRequireNoPendingIO_ScratchFlag)) {
bsalomon71cb0c22014-11-14 12:10:14 -0800239 resource = fScratchMap.find(scratchKey, AvailableForScratchUse(true));
bsalomon000f8292014-10-15 19:04:14 -0700240 if (resource) {
bsalomon9f2d1572015-02-17 11:47:40 -0800241 this->refAndMakeResourceMRU(resource);
bsalomonb436ed62014-11-17 12:15:56 -0800242 this->validate();
243 return resource;
bsalomon000f8292014-10-15 19:04:14 -0700244 } else if (flags & kRequireNoPendingIO_ScratchFlag) {
halcanary96fcdcc2015-08-27 07:41:13 -0700245 return nullptr;
bsalomon000f8292014-10-15 19:04:14 -0700246 }
robertphillips63926682015-08-20 09:39:02 -0700247 // We would prefer to consume more available VRAM rather than flushing
248 // immediately, but on ANGLE this can lead to starving of the GPU.
249 if (fPreferVRAMUseOverFlushes && this->wouldFit(resourceSize)) {
robertphillips6e83ac72015-08-13 05:19:14 -0700250 // kPrefer is specified, we didn't find a resource without pending io,
robertphillips63926682015-08-20 09:39:02 -0700251 // but there is still space in our budget for the resource so force
252 // the caller to allocate a new resource.
halcanary96fcdcc2015-08-27 07:41:13 -0700253 return nullptr;
robertphillips6e83ac72015-08-13 05:19:14 -0700254 }
bsalomon000f8292014-10-15 19:04:14 -0700255 }
bsalomon71cb0c22014-11-14 12:10:14 -0800256 resource = fScratchMap.find(scratchKey, AvailableForScratchUse(false));
257 if (resource) {
bsalomon9f2d1572015-02-17 11:47:40 -0800258 this->refAndMakeResourceMRU(resource);
bsalomonb436ed62014-11-17 12:15:56 -0800259 this->validate();
bsalomon71cb0c22014-11-14 12:10:14 -0800260 }
261 return resource;
bsalomonbcf0a522014-10-08 08:40:09 -0700262}
bsalomon8b79d232014-11-10 10:19:06 -0800263
bsalomon0ea80f42015-02-11 10:49:59 -0800264void GrResourceCache::willRemoveScratchKey(const GrGpuResource* resource) {
bsalomon3582d3e2015-02-13 14:20:05 -0800265 SkASSERT(resource->resourcePriv().getScratchKey().isValid());
robertphillipsc4ed6842016-05-24 14:17:12 -0700266 if (!resource->getUniqueKey().isValid()) {
267 fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource);
268 }
bsalomon10e23ca2014-11-25 05:52:06 -0800269}
270
bsalomonf99e9612015-02-19 08:24:16 -0800271void GrResourceCache::removeUniqueKey(GrGpuResource* resource) {
bsalomon3f324322015-04-08 11:01:54 -0700272 // Someone has a ref to this resource in order to have removed the key. When the ref count
273 // reaches zero we will get a ref cnt notification and figure out what to do with it.
bsalomonf99e9612015-02-19 08:24:16 -0800274 if (resource->getUniqueKey().isValid()) {
275 SkASSERT(resource == fUniqueHash.find(resource->getUniqueKey()));
276 fUniqueHash.remove(resource->getUniqueKey());
277 }
278 resource->cacheAccess().removeUniqueKey();
robertphillipsc4ed6842016-05-24 14:17:12 -0700279
280 if (resource->resourcePriv().getScratchKey().isValid()) {
281 fScratchMap.insert(resource->resourcePriv().getScratchKey(), resource);
282 }
283
bsalomonf99e9612015-02-19 08:24:16 -0800284 this->validate();
bsalomon23e619c2015-02-06 11:54:28 -0800285}
286
bsalomonf99e9612015-02-19 08:24:16 -0800287void GrResourceCache::changeUniqueKey(GrGpuResource* resource, const GrUniqueKey& newKey) {
bsalomon8b79d232014-11-10 10:19:06 -0800288 SkASSERT(resource);
bsalomon71cb0c22014-11-14 12:10:14 -0800289 SkASSERT(this->isInCache(resource));
bsalomon8b79d232014-11-10 10:19:06 -0800290
bsalomonf99e9612015-02-19 08:24:16 -0800291 // If another resource has the new key, remove its key then install the key on this resource.
292 if (newKey.isValid()) {
robertphillipsc4ed6842016-05-24 14:17:12 -0700293 // Remove the entry for this resource if it already has a unique key.
294 if (resource->getUniqueKey().isValid()) {
295 SkASSERT(resource == fUniqueHash.find(resource->getUniqueKey()));
296 fUniqueHash.remove(resource->getUniqueKey());
297 SkASSERT(nullptr == fUniqueHash.find(resource->getUniqueKey()));
298 } else {
299 // 'resource' didn't have a valid unique key before so it is switching sides. Remove it
300 // from the ScratchMap
301 if (resource->resourcePriv().getScratchKey().isValid()) {
302 fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource);
303 }
304 }
305
bsalomonf99e9612015-02-19 08:24:16 -0800306 if (GrGpuResource* old = fUniqueHash.find(newKey)) {
307 // If the old resource using the key is purgeable and is unreachable, then remove it.
308 if (!old->resourcePriv().getScratchKey().isValid() && old->isPurgeable()) {
309 // release may call validate() which will assert that resource is in fUniqueHash
310 // if it has a valid key. So in debug reset the key here before we assign it.
311 SkDEBUGCODE(resource->cacheAccess().removeUniqueKey();)
312 old->cacheAccess().release();
313 } else {
robertphillipsc4ed6842016-05-24 14:17:12 -0700314 this->removeUniqueKey(old);
bsalomonf99e9612015-02-19 08:24:16 -0800315 }
316 }
halcanary96fcdcc2015-08-27 07:41:13 -0700317 SkASSERT(nullptr == fUniqueHash.find(newKey));
bsalomonf99e9612015-02-19 08:24:16 -0800318 resource->cacheAccess().setUniqueKey(newKey);
319 fUniqueHash.add(resource);
320 } else {
robertphillipsc4ed6842016-05-24 14:17:12 -0700321 this->removeUniqueKey(resource);
bsalomonf99e9612015-02-19 08:24:16 -0800322 }
323
bsalomon71cb0c22014-11-14 12:10:14 -0800324 this->validate();
bsalomon8b79d232014-11-10 10:19:06 -0800325}
bsalomon71cb0c22014-11-14 12:10:14 -0800326
bsalomon9f2d1572015-02-17 11:47:40 -0800327void GrResourceCache::refAndMakeResourceMRU(GrGpuResource* resource) {
bsalomon71cb0c22014-11-14 12:10:14 -0800328 SkASSERT(resource);
329 SkASSERT(this->isInCache(resource));
bsalomonddf30e62015-02-19 11:38:44 -0800330
bsalomon9f2d1572015-02-17 11:47:40 -0800331 if (resource->isPurgeable()) {
332 // It's about to become unpurgeable.
333 fPurgeableQueue.remove(resource);
bsalomonf320e042015-02-17 15:09:34 -0800334 this->addToNonpurgeableArray(resource);
bsalomon9f2d1572015-02-17 11:47:40 -0800335 }
336 resource->ref();
bsalomonddf30e62015-02-19 11:38:44 -0800337
338 resource->cacheAccess().setTimestamp(this->getNextTimestamp());
bsalomonf320e042015-02-17 15:09:34 -0800339 this->validate();
bsalomon71cb0c22014-11-14 12:10:14 -0800340}
341
bsalomon3f324322015-04-08 11:01:54 -0700342void GrResourceCache::notifyCntReachedZero(GrGpuResource* resource, uint32_t flags) {
bsalomon71cb0c22014-11-14 12:10:14 -0800343 SkASSERT(resource);
bsalomon3f324322015-04-08 11:01:54 -0700344 SkASSERT(!resource->wasDestroyed());
345 SkASSERT(flags);
bsalomon71cb0c22014-11-14 12:10:14 -0800346 SkASSERT(this->isInCache(resource));
bsalomon3f324322015-04-08 11:01:54 -0700347 // This resource should always be in the nonpurgeable array when this function is called. It
348 // will be moved to the queue if it is newly purgeable.
349 SkASSERT(fNonpurgeableResources[*resource->cacheAccess().accessCacheIndex()] == resource);
bsalomon71cb0c22014-11-14 12:10:14 -0800350
bsalomon3f324322015-04-08 11:01:54 -0700351 if (SkToBool(ResourceAccess::kRefCntReachedZero_RefNotificationFlag & flags)) {
352#ifdef SK_DEBUG
353 // When the timestamp overflows validate() is called. validate() checks that resources in
354 // the nonpurgeable array are indeed not purgeable. However, the movement from the array to
355 // the purgeable queue happens just below in this function. So we mark it as an exception.
356 if (resource->isPurgeable()) {
357 fNewlyPurgeableResourceForValidation = resource;
358 }
359#endif
360 resource->cacheAccess().setTimestamp(this->getNextTimestamp());
halcanary96fcdcc2015-08-27 07:41:13 -0700361 SkDEBUGCODE(fNewlyPurgeableResourceForValidation = nullptr);
bsalomon3f324322015-04-08 11:01:54 -0700362 }
363
364 if (!SkToBool(ResourceAccess::kAllCntsReachedZero_RefNotificationFlag & flags)) {
365 SkASSERT(!resource->isPurgeable());
366 return;
367 }
368
369 SkASSERT(resource->isPurgeable());
bsalomonf320e042015-02-17 15:09:34 -0800370 this->removeFromNonpurgeableArray(resource);
bsalomon9f2d1572015-02-17 11:47:40 -0800371 fPurgeableQueue.insert(resource);
bsalomone2e87f32016-09-22 12:42:11 -0700372 resource->cacheAccess().setFlushCntWhenResourceBecamePurgeable(fExternalFlushCnt);
Brian Salomon5e150852017-03-22 14:53:13 -0400373 resource->cacheAccess().setTimeWhenResourceBecomePurgeable();
bsalomon71cb0c22014-11-14 12:10:14 -0800374
bsalomon5ec26ae2016-02-25 08:33:02 -0800375 if (SkBudgeted::kNo == resource->resourcePriv().isBudgeted()) {
bsalomonc2f35b72015-01-23 07:19:22 -0800376 // Check whether this resource could still be used as a scratch resource.
kkinnunen2e6055b2016-04-22 01:48:29 -0700377 if (!resource->resourcePriv().refsWrappedObjects() &&
bsalomon9f2d1572015-02-17 11:47:40 -0800378 resource->resourcePriv().getScratchKey().isValid()) {
bsalomonc2f35b72015-01-23 07:19:22 -0800379 // We won't purge an existing resource to make room for this one.
bsalomonf320e042015-02-17 15:09:34 -0800380 if (fBudgetedCount < fMaxCount &&
381 fBudgetedBytes + resource->gpuMemorySize() <= fMaxBytes) {
bsalomon3582d3e2015-02-13 14:20:05 -0800382 resource->resourcePriv().makeBudgeted();
bsalomon9f2d1572015-02-17 11:47:40 -0800383 return;
bsalomonc2f35b72015-01-23 07:19:22 -0800384 }
bsalomonc2f35b72015-01-23 07:19:22 -0800385 }
386 } else {
bsalomon9f2d1572015-02-17 11:47:40 -0800387 // Purge the resource immediately if we're over budget
bsalomon8718aaf2015-02-19 07:24:21 -0800388 // Also purge if the resource has neither a valid scratch key nor a unique key.
robertphillipsee843b22016-10-04 05:30:20 -0700389 bool noKey = !resource->resourcePriv().getScratchKey().isValid() &&
390 !resource->getUniqueKey().isValid();
391 if (!this->overBudget() && !noKey) {
bsalomon9f2d1572015-02-17 11:47:40 -0800392 return;
bsalomonc2f35b72015-01-23 07:19:22 -0800393 }
394 }
bsalomondace19e2014-11-17 07:34:06 -0800395
bsalomonf320e042015-02-17 15:09:34 -0800396 SkDEBUGCODE(int beforeCount = this->getResourceCount();)
bsalomon9f2d1572015-02-17 11:47:40 -0800397 resource->cacheAccess().release();
398 // We should at least free this resource, perhaps dependent resources as well.
bsalomonf320e042015-02-17 15:09:34 -0800399 SkASSERT(this->getResourceCount() < beforeCount);
bsalomon71cb0c22014-11-14 12:10:14 -0800400 this->validate();
401}
402
bsalomon0ea80f42015-02-11 10:49:59 -0800403void GrResourceCache::didChangeGpuMemorySize(const GrGpuResource* resource, size_t oldSize) {
bsalomon71cb0c22014-11-14 12:10:14 -0800404 // SkASSERT(!fPurging); GrPathRange increases size during flush. :(
405 SkASSERT(resource);
406 SkASSERT(this->isInCache(resource));
407
bsalomondace19e2014-11-17 07:34:06 -0800408 ptrdiff_t delta = resource->gpuMemorySize() - oldSize;
409
410 fBytes += delta;
bsalomon82b1d622014-11-14 13:59:57 -0800411#if GR_CACHE_STATS
412 fHighWaterBytes = SkTMax(fBytes, fHighWaterBytes);
413#endif
bsalomon5ec26ae2016-02-25 08:33:02 -0800414 if (SkBudgeted::kYes == resource->resourcePriv().isBudgeted()) {
bsalomondace19e2014-11-17 07:34:06 -0800415 fBudgetedBytes += delta;
hendrikw876c3132015-03-04 10:33:49 -0800416 TRACE_COUNTER2(TRACE_DISABLED_BY_DEFAULT("skia.gpu.cache"), "skia budget", "used",
417 fBudgetedBytes, "free", fMaxBytes - fBudgetedBytes);
bsalomondace19e2014-11-17 07:34:06 -0800418#if GR_CACHE_STATS
419 fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes);
420#endif
421 }
bsalomon71cb0c22014-11-14 12:10:14 -0800422
423 this->purgeAsNeeded();
424 this->validate();
425}
426
bsalomon0ea80f42015-02-11 10:49:59 -0800427void GrResourceCache::didChangeBudgetStatus(GrGpuResource* resource) {
bsalomon84c8e622014-11-17 09:33:27 -0800428 SkASSERT(resource);
429 SkASSERT(this->isInCache(resource));
430
431 size_t size = resource->gpuMemorySize();
432
bsalomon5ec26ae2016-02-25 08:33:02 -0800433 if (SkBudgeted::kYes == resource->resourcePriv().isBudgeted()) {
bsalomon84c8e622014-11-17 09:33:27 -0800434 ++fBudgetedCount;
435 fBudgetedBytes += size;
bsalomonafe30052015-01-16 07:32:33 -0800436#if GR_CACHE_STATS
437 fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes);
438 fBudgetedHighWaterCount = SkTMax(fBudgetedCount, fBudgetedHighWaterCount);
439#endif
bsalomon84c8e622014-11-17 09:33:27 -0800440 this->purgeAsNeeded();
441 } else {
442 --fBudgetedCount;
443 fBudgetedBytes -= size;
444 }
hendrikw876c3132015-03-04 10:33:49 -0800445 TRACE_COUNTER2(TRACE_DISABLED_BY_DEFAULT("skia.gpu.cache"), "skia budget", "used",
446 fBudgetedBytes, "free", fMaxBytes - fBudgetedBytes);
bsalomon84c8e622014-11-17 09:33:27 -0800447
448 this->validate();
449}
450
robertphillipsee843b22016-10-04 05:30:20 -0700451void GrResourceCache::purgeAsNeeded() {
bsalomon3f324322015-04-08 11:01:54 -0700452 SkTArray<GrUniqueKeyInvalidatedMessage> invalidKeyMsgs;
453 fInvalidUniqueKeyInbox.poll(&invalidKeyMsgs);
454 if (invalidKeyMsgs.count()) {
455 this->processInvalidUniqueKeys(invalidKeyMsgs);
456 }
bsalomon71cb0c22014-11-14 12:10:14 -0800457
Brian Osman13dddce2017-05-09 13:19:50 -0400458 this->processFreedGpuResources();
459
bsalomone2e87f32016-09-22 12:42:11 -0700460 if (fMaxUnusedFlushes > 0) {
461 // We want to know how many complete flushes have occurred without the resource being used.
462 // If the resource was tagged when fExternalFlushCnt was N then this means it became
463 // purgeable during activity that became the N+1th flush. So when the flush count is N+2
464 // it has sat in the purgeable queue for one entire flush.
465 uint32_t oldestAllowedFlushCnt = fExternalFlushCnt - fMaxUnusedFlushes - 1;
466 // check for underflow
467 if (oldestAllowedFlushCnt < fExternalFlushCnt) {
468 while (fPurgeableQueue.count()) {
469 uint32_t flushWhenResourceBecamePurgeable =
470 fPurgeableQueue.peek()->cacheAccess().flushCntWhenResourceBecamePurgeable();
471 if (oldestAllowedFlushCnt < flushWhenResourceBecamePurgeable) {
472 // Resources were given both LRU timestamps and tagged with a flush cnt when
473 // they first became purgeable. The LRU timestamp won't change again until the
474 // resource is made non-purgeable again. So, at this point all the remaining
475 // resources in the timestamp-sorted queue will have a flush count >= to this
476 // one.
477 break;
478 }
479 GrGpuResource* resource = fPurgeableQueue.peek();
480 SkASSERT(resource->isPurgeable());
481 resource->cacheAccess().release();
bsalomon3f324322015-04-08 11:01:54 -0700482 }
bsalomon3f324322015-04-08 11:01:54 -0700483 }
484 }
485
486 bool stillOverbudget = this->overBudget();
487 while (stillOverbudget && fPurgeableQueue.count()) {
robertphillipsee843b22016-10-04 05:30:20 -0700488 GrGpuResource* resource = fPurgeableQueue.peek();
bsalomon9f2d1572015-02-17 11:47:40 -0800489 SkASSERT(resource->isPurgeable());
490 resource->cacheAccess().release();
bsalomon3f324322015-04-08 11:01:54 -0700491 stillOverbudget = this->overBudget();
bsalomon9f2d1572015-02-17 11:47:40 -0800492 }
bsalomon71cb0c22014-11-14 12:10:14 -0800493
bsalomonb436ed62014-11-17 12:15:56 -0800494 this->validate();
robertphillipsee843b22016-10-04 05:30:20 -0700495
496 if (stillOverbudget) {
497 // Set this so that GrDrawingManager will issue a flush to free up resources with pending
498 // IO that we were unable to purge in this pass.
499 fRequestFlush = true;
500 }
bsalomon71cb0c22014-11-14 12:10:14 -0800501}
502
bsalomon0ea80f42015-02-11 10:49:59 -0800503void GrResourceCache::purgeAllUnlocked() {
bsalomon9f2d1572015-02-17 11:47:40 -0800504 // We could disable maintaining the heap property here, but it would add a lot of complexity.
505 // Moreover, this is rarely called.
506 while (fPurgeableQueue.count()) {
507 GrGpuResource* resource = fPurgeableQueue.peek();
508 SkASSERT(resource->isPurgeable());
509 resource->cacheAccess().release();
510 }
bsalomon71cb0c22014-11-14 12:10:14 -0800511
bsalomonb436ed62014-11-17 12:15:56 -0800512 this->validate();
bsalomon71cb0c22014-11-14 12:10:14 -0800513}
514
Brian Salomon5e150852017-03-22 14:53:13 -0400515void GrResourceCache::purgeResourcesNotUsedSince(GrStdSteadyClock::time_point purgeTime) {
516 while (fPurgeableQueue.count()) {
517 const GrStdSteadyClock::time_point resourceTime =
518 fPurgeableQueue.peek()->cacheAccess().timeWhenResourceBecamePurgeable();
519 if (resourceTime >= purgeTime) {
520 // Resources were given both LRU timestamps and tagged with a frame number when
521 // they first became purgeable. The LRU timestamp won't change again until the
522 // resource is made non-purgeable again. So, at this point all the remaining
523 // resources in the timestamp-sorted queue will have a frame number >= to this
524 // one.
525 break;
526 }
527 GrGpuResource* resource = fPurgeableQueue.peek();
528 SkASSERT(resource->isPurgeable());
529 resource->cacheAccess().release();
530 }
531}
532
bsalomon8718aaf2015-02-19 07:24:21 -0800533void GrResourceCache::processInvalidUniqueKeys(
534 const SkTArray<GrUniqueKeyInvalidatedMessage>& msgs) {
bsalomon23e619c2015-02-06 11:54:28 -0800535 for (int i = 0; i < msgs.count(); ++i) {
bsalomon8718aaf2015-02-19 07:24:21 -0800536 GrGpuResource* resource = this->findAndRefUniqueResource(msgs[i].key());
bsalomon23e619c2015-02-06 11:54:28 -0800537 if (resource) {
bsalomon8718aaf2015-02-19 07:24:21 -0800538 resource->resourcePriv().removeUniqueKey();
bsalomon3f324322015-04-08 11:01:54 -0700539 resource->unref(); // If this resource is now purgeable, the cache will be notified.
bsalomon23e619c2015-02-06 11:54:28 -0800540 }
541 }
542}
543
Brian Osman13dddce2017-05-09 13:19:50 -0400544void GrResourceCache::insertCrossContextGpuResource(GrGpuResource* resource) {
545 resource->ref();
546}
547
548void GrResourceCache::processFreedGpuResources() {
549 SkTArray<GrGpuResourceFreedMessage> msgs;
550 fFreedGpuResourceInbox.poll(&msgs);
551 for (int i = 0; i < msgs.count(); ++i) {
552 if (msgs[i].fOwningUniqueID == fContextUniqueID) {
553 msgs[i].fResource->unref();
554 }
555 }
556}
557
bsalomonf320e042015-02-17 15:09:34 -0800558void GrResourceCache::addToNonpurgeableArray(GrGpuResource* resource) {
559 int index = fNonpurgeableResources.count();
560 *fNonpurgeableResources.append() = resource;
561 *resource->cacheAccess().accessCacheIndex() = index;
562}
563
564void GrResourceCache::removeFromNonpurgeableArray(GrGpuResource* resource) {
565 int* index = resource->cacheAccess().accessCacheIndex();
566 // Fill the whole we will create in the array with the tail object, adjust its index, and
567 // then pop the array
568 GrGpuResource* tail = *(fNonpurgeableResources.end() - 1);
569 SkASSERT(fNonpurgeableResources[*index] == resource);
570 fNonpurgeableResources[*index] = tail;
571 *tail->cacheAccess().accessCacheIndex() = *index;
572 fNonpurgeableResources.pop();
573 SkDEBUGCODE(*index = -1);
574}
575
bsalomonddf30e62015-02-19 11:38:44 -0800576uint32_t GrResourceCache::getNextTimestamp() {
577 // If we wrap then all the existing resources will appear older than any resources that get
578 // a timestamp after the wrap.
579 if (0 == fTimestamp) {
580 int count = this->getResourceCount();
581 if (count) {
582 // Reset all the timestamps. We sort the resources by timestamp and then assign
583 // sequential timestamps beginning with 0. This is O(n*lg(n)) but it should be extremely
584 // rare.
585 SkTDArray<GrGpuResource*> sortedPurgeableResources;
586 sortedPurgeableResources.setReserve(fPurgeableQueue.count());
587
588 while (fPurgeableQueue.count()) {
589 *sortedPurgeableResources.append() = fPurgeableQueue.peek();
590 fPurgeableQueue.pop();
591 }
robertphillipsee843b22016-10-04 05:30:20 -0700592
bsalomone2e87f32016-09-22 12:42:11 -0700593 SkTQSort(fNonpurgeableResources.begin(), fNonpurgeableResources.end() - 1,
594 CompareTimestamp);
bsalomonddf30e62015-02-19 11:38:44 -0800595
596 // Pick resources out of the purgeable and non-purgeable arrays based on lowest
597 // timestamp and assign new timestamps.
598 int currP = 0;
599 int currNP = 0;
600 while (currP < sortedPurgeableResources.count() &&
mtklein56da0252015-11-16 11:16:23 -0800601 currNP < fNonpurgeableResources.count()) {
bsalomonddf30e62015-02-19 11:38:44 -0800602 uint32_t tsP = sortedPurgeableResources[currP]->cacheAccess().timestamp();
603 uint32_t tsNP = fNonpurgeableResources[currNP]->cacheAccess().timestamp();
604 SkASSERT(tsP != tsNP);
605 if (tsP < tsNP) {
606 sortedPurgeableResources[currP++]->cacheAccess().setTimestamp(fTimestamp++);
607 } else {
608 // Correct the index in the nonpurgeable array stored on the resource post-sort.
609 *fNonpurgeableResources[currNP]->cacheAccess().accessCacheIndex() = currNP;
610 fNonpurgeableResources[currNP++]->cacheAccess().setTimestamp(fTimestamp++);
611 }
612 }
613
614 // The above loop ended when we hit the end of one array. Finish the other one.
615 while (currP < sortedPurgeableResources.count()) {
616 sortedPurgeableResources[currP++]->cacheAccess().setTimestamp(fTimestamp++);
617 }
618 while (currNP < fNonpurgeableResources.count()) {
619 *fNonpurgeableResources[currNP]->cacheAccess().accessCacheIndex() = currNP;
620 fNonpurgeableResources[currNP++]->cacheAccess().setTimestamp(fTimestamp++);
621 }
622
623 // Rebuild the queue.
624 for (int i = 0; i < sortedPurgeableResources.count(); ++i) {
625 fPurgeableQueue.insert(sortedPurgeableResources[i]);
626 }
627
628 this->validate();
629 SkASSERT(count == this->getResourceCount());
630
631 // count should be the next timestamp we return.
632 SkASSERT(fTimestamp == SkToU32(count));
mtklein56da0252015-11-16 11:16:23 -0800633 }
bsalomonddf30e62015-02-19 11:38:44 -0800634 }
635 return fTimestamp++;
636}
637
bsalomonb77a9072016-09-07 10:02:04 -0700638void GrResourceCache::notifyFlushOccurred(FlushType type) {
639 switch (type) {
640 case FlushType::kImmediateMode:
641 break;
642 case FlushType::kCacheRequested:
robertphillipsee843b22016-10-04 05:30:20 -0700643 SkASSERT(fRequestFlush);
644 fRequestFlush = false;
bsalomonb77a9072016-09-07 10:02:04 -0700645 break;
robertphillipsee843b22016-10-04 05:30:20 -0700646 case FlushType::kExternal:
bsalomone2e87f32016-09-22 12:42:11 -0700647 ++fExternalFlushCnt;
648 if (0 == fExternalFlushCnt) {
649 // When this wraps just reset all the purgeable resources' last used flush state.
650 for (int i = 0; i < fPurgeableQueue.count(); ++i) {
651 fPurgeableQueue.at(i)->cacheAccess().setFlushCntWhenResourceBecamePurgeable(0);
652 }
bsalomonb77a9072016-09-07 10:02:04 -0700653 }
654 break;
bsalomon3f324322015-04-08 11:01:54 -0700655 }
robertphillipsee843b22016-10-04 05:30:20 -0700656 this->purgeAsNeeded();
bsalomon3f324322015-04-08 11:01:54 -0700657}
658
ericrk0a5fa482015-09-15 14:16:10 -0700659void GrResourceCache::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
660 for (int i = 0; i < fNonpurgeableResources.count(); ++i) {
661 fNonpurgeableResources[i]->dumpMemoryStatistics(traceMemoryDump);
662 }
663 for (int i = 0; i < fPurgeableQueue.count(); ++i) {
664 fPurgeableQueue.at(i)->dumpMemoryStatistics(traceMemoryDump);
665 }
666}
667
bsalomon71cb0c22014-11-14 12:10:14 -0800668#ifdef SK_DEBUG
bsalomon0ea80f42015-02-11 10:49:59 -0800669void GrResourceCache::validate() const {
bsalomonc2f35b72015-01-23 07:19:22 -0800670 // Reduce the frequency of validations for large resource counts.
671 static SkRandom gRandom;
672 int mask = (SkNextPow2(fCount + 1) >> 5) - 1;
673 if (~mask && (gRandom.nextU() & mask)) {
674 return;
675 }
676
bsalomonf320e042015-02-17 15:09:34 -0800677 struct Stats {
678 size_t fBytes;
679 int fBudgetedCount;
680 size_t fBudgetedBytes;
681 int fLocked;
682 int fScratch;
683 int fCouldBeScratch;
684 int fContent;
685 const ScratchMap* fScratchMap;
bsalomon8718aaf2015-02-19 07:24:21 -0800686 const UniqueHash* fUniqueHash;
bsalomon71cb0c22014-11-14 12:10:14 -0800687
bsalomonf320e042015-02-17 15:09:34 -0800688 Stats(const GrResourceCache* cache) {
689 memset(this, 0, sizeof(*this));
690 fScratchMap = &cache->fScratchMap;
bsalomon8718aaf2015-02-19 07:24:21 -0800691 fUniqueHash = &cache->fUniqueHash;
bsalomon71cb0c22014-11-14 12:10:14 -0800692 }
693
bsalomonf320e042015-02-17 15:09:34 -0800694 void update(GrGpuResource* resource) {
695 fBytes += resource->gpuMemorySize();
bsalomondace19e2014-11-17 07:34:06 -0800696
bsalomonf320e042015-02-17 15:09:34 -0800697 if (!resource->isPurgeable()) {
698 ++fLocked;
699 }
bsalomon9f2d1572015-02-17 11:47:40 -0800700
robertphillipsc4ed6842016-05-24 14:17:12 -0700701 const GrScratchKey& scratchKey = resource->resourcePriv().getScratchKey();
702 const GrUniqueKey& uniqueKey = resource->getUniqueKey();
703
bsalomonf320e042015-02-17 15:09:34 -0800704 if (resource->cacheAccess().isScratch()) {
robertphillipsc4ed6842016-05-24 14:17:12 -0700705 SkASSERT(!uniqueKey.isValid());
bsalomonf320e042015-02-17 15:09:34 -0800706 ++fScratch;
robertphillipsc4ed6842016-05-24 14:17:12 -0700707 SkASSERT(fScratchMap->countForKey(scratchKey));
kkinnunen2e6055b2016-04-22 01:48:29 -0700708 SkASSERT(!resource->resourcePriv().refsWrappedObjects());
robertphillipsc4ed6842016-05-24 14:17:12 -0700709 } else if (scratchKey.isValid()) {
bsalomon5ec26ae2016-02-25 08:33:02 -0800710 SkASSERT(SkBudgeted::kNo == resource->resourcePriv().isBudgeted() ||
robertphillipsc4ed6842016-05-24 14:17:12 -0700711 uniqueKey.isValid());
712 if (!uniqueKey.isValid()) {
mtklein4e976072016-08-08 09:06:27 -0700713 ++fCouldBeScratch;
robertphillipsc4ed6842016-05-24 14:17:12 -0700714 SkASSERT(fScratchMap->countForKey(scratchKey));
715 }
kkinnunen2e6055b2016-04-22 01:48:29 -0700716 SkASSERT(!resource->resourcePriv().refsWrappedObjects());
bsalomonf320e042015-02-17 15:09:34 -0800717 }
bsalomon8718aaf2015-02-19 07:24:21 -0800718 if (uniqueKey.isValid()) {
bsalomonf320e042015-02-17 15:09:34 -0800719 ++fContent;
bsalomon8718aaf2015-02-19 07:24:21 -0800720 SkASSERT(fUniqueHash->find(uniqueKey) == resource);
Brian Osman0562eb92017-05-08 11:16:39 -0400721 SkASSERT(SkBudgeted::kYes == resource->resourcePriv().isBudgeted() ||
722 resource->resourcePriv().refsWrappedObjects());
robertphillipsc4ed6842016-05-24 14:17:12 -0700723
724 if (scratchKey.isValid()) {
725 SkASSERT(!fScratchMap->has(resource, scratchKey));
726 }
bsalomonf320e042015-02-17 15:09:34 -0800727 }
728
bsalomon5ec26ae2016-02-25 08:33:02 -0800729 if (SkBudgeted::kYes == resource->resourcePriv().isBudgeted()) {
bsalomonf320e042015-02-17 15:09:34 -0800730 ++fBudgetedCount;
731 fBudgetedBytes += resource->gpuMemorySize();
732 }
bsalomon9f2d1572015-02-17 11:47:40 -0800733 }
bsalomonf320e042015-02-17 15:09:34 -0800734 };
735
robertphillipsc4ed6842016-05-24 14:17:12 -0700736 {
737 ScratchMap::ConstIter iter(&fScratchMap);
738
739 int count = 0;
740 for ( ; !iter.done(); ++iter) {
741 const GrGpuResource* resource = *iter;
742 SkASSERT(resource->resourcePriv().getScratchKey().isValid());
743 SkASSERT(!resource->getUniqueKey().isValid());
744 count++;
745 }
746 SkASSERT(count == fScratchMap.count()); // ensure the iterator is working correctly
747 }
748
bsalomonf320e042015-02-17 15:09:34 -0800749 Stats stats(this);
750
751 for (int i = 0; i < fNonpurgeableResources.count(); ++i) {
bsalomon3f324322015-04-08 11:01:54 -0700752 SkASSERT(!fNonpurgeableResources[i]->isPurgeable() ||
753 fNewlyPurgeableResourceForValidation == fNonpurgeableResources[i]);
bsalomonf320e042015-02-17 15:09:34 -0800754 SkASSERT(*fNonpurgeableResources[i]->cacheAccess().accessCacheIndex() == i);
755 SkASSERT(!fNonpurgeableResources[i]->wasDestroyed());
756 stats.update(fNonpurgeableResources[i]);
bsalomon71cb0c22014-11-14 12:10:14 -0800757 }
bsalomon9f2d1572015-02-17 11:47:40 -0800758 for (int i = 0; i < fPurgeableQueue.count(); ++i) {
759 SkASSERT(fPurgeableQueue.at(i)->isPurgeable());
bsalomonf320e042015-02-17 15:09:34 -0800760 SkASSERT(*fPurgeableQueue.at(i)->cacheAccess().accessCacheIndex() == i);
761 SkASSERT(!fPurgeableQueue.at(i)->wasDestroyed());
762 stats.update(fPurgeableQueue.at(i));
bsalomon9f2d1572015-02-17 11:47:40 -0800763 }
764
bsalomonf320e042015-02-17 15:09:34 -0800765 SkASSERT(fCount == this->getResourceCount());
bsalomondace19e2014-11-17 07:34:06 -0800766 SkASSERT(fBudgetedCount <= fCount);
bsalomonf320e042015-02-17 15:09:34 -0800767 SkASSERT(fBudgetedBytes <= fBytes);
768 SkASSERT(stats.fBytes == fBytes);
769 SkASSERT(stats.fBudgetedBytes == fBudgetedBytes);
770 SkASSERT(stats.fBudgetedCount == fBudgetedCount);
bsalomon71cb0c22014-11-14 12:10:14 -0800771#if GR_CACHE_STATS
bsalomondace19e2014-11-17 07:34:06 -0800772 SkASSERT(fBudgetedHighWaterCount <= fHighWaterCount);
773 SkASSERT(fBudgetedHighWaterBytes <= fHighWaterBytes);
bsalomonf320e042015-02-17 15:09:34 -0800774 SkASSERT(fBytes <= fHighWaterBytes);
775 SkASSERT(fCount <= fHighWaterCount);
776 SkASSERT(fBudgetedBytes <= fBudgetedHighWaterBytes);
777 SkASSERT(fBudgetedCount <= fBudgetedHighWaterCount);
bsalomon71cb0c22014-11-14 12:10:14 -0800778#endif
bsalomon8718aaf2015-02-19 07:24:21 -0800779 SkASSERT(stats.fContent == fUniqueHash.count());
bsalomonf320e042015-02-17 15:09:34 -0800780 SkASSERT(stats.fScratch + stats.fCouldBeScratch == fScratchMap.count());
bsalomon71cb0c22014-11-14 12:10:14 -0800781
bsalomon3f324322015-04-08 11:01:54 -0700782 // This assertion is not currently valid because we can be in recursive notifyCntReachedZero()
bsalomon12299ab2014-11-14 13:33:09 -0800783 // calls. This will be fixed when subresource registration is explicit.
bsalomondace19e2014-11-17 07:34:06 -0800784 // bool overBudget = budgetedBytes > fMaxBytes || budgetedCount > fMaxCount;
bsalomon12299ab2014-11-14 13:33:09 -0800785 // SkASSERT(!overBudget || locked == count || fPurging);
bsalomon71cb0c22014-11-14 12:10:14 -0800786}
bsalomonf320e042015-02-17 15:09:34 -0800787
788bool GrResourceCache::isInCache(const GrGpuResource* resource) const {
789 int index = *resource->cacheAccess().accessCacheIndex();
790 if (index < 0) {
791 return false;
792 }
793 if (index < fPurgeableQueue.count() && fPurgeableQueue.at(index) == resource) {
794 return true;
795 }
796 if (index < fNonpurgeableResources.count() && fNonpurgeableResources[index] == resource) {
797 return true;
798 }
799 SkDEBUGFAIL("Resource index should be -1 or the resource should be in the cache.");
800 return false;
801}
802
bsalomon71cb0c22014-11-14 12:10:14 -0800803#endif