blob: f6170c01b6597d7348d4cfc0e1049a611cfe5100 [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) {
Ben Wagnerb4aab9a2017-08-16 10:53:04 -040030 SK_ABORT("Too many Resource Types");
bsalomon71cb0c22014-11-14 12:10:14 -080031 }
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) {
Ben Wagnerb4aab9a2017-08-16 10:53:04 -040041 SK_ABORT("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)
Derek Sollenbergeree479142017-05-24 11:41:33 -040078 , fPurgeableBytes(0)
robertphillipsee843b22016-10-04 05:30:20 -070079 , fRequestFlush(false)
bsalomone2e87f32016-09-22 12:42:11 -070080 , fExternalFlushCnt(0)
Brian Osman13dddce2017-05-09 13:19:50 -040081 , fContextUniqueID(contextUniqueID)
robertphillips63926682015-08-20 09:39:02 -070082 , fPreferVRAMUseOverFlushes(caps->preferVRAMUseOverFlushes()) {
bsalomonf320e042015-02-17 15:09:34 -080083 SkDEBUGCODE(fCount = 0;)
halcanary96fcdcc2015-08-27 07:41:13 -070084 SkDEBUGCODE(fNewlyPurgeableResourceForValidation = nullptr;)
bsalomon71cb0c22014-11-14 12:10:14 -080085}
86
bsalomon0ea80f42015-02-11 10:49:59 -080087GrResourceCache::~GrResourceCache() {
bsalomonc8dc1f72014-08-21 13:02:13 -070088 this->releaseAll();
89}
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;
bsalomon71cb0c22014-11-14 12:10:14 -080095 this->purgeAsNeeded();
96}
97
bsalomon0ea80f42015-02-11 10:49:59 -080098void GrResourceCache::insertResource(GrGpuResource* resource) {
bsalomon49f085d2014-09-05 13:34:00 -070099 SkASSERT(resource);
bsalomon16961262014-08-26 14:01:07 -0700100 SkASSERT(!this->isInCache(resource));
bsalomonf320e042015-02-17 15:09:34 -0800101 SkASSERT(!resource->wasDestroyed());
102 SkASSERT(!resource->isPurgeable());
bsalomonddf30e62015-02-19 11:38:44 -0800103
104 // We must set the timestamp before adding to the array in case the timestamp wraps and we wind
105 // up iterating over all the resources that already have timestamps.
106 resource->cacheAccess().setTimestamp(this->getNextTimestamp());
107
bsalomonf320e042015-02-17 15:09:34 -0800108 this->addToNonpurgeableArray(resource);
bsalomon71cb0c22014-11-14 12:10:14 -0800109
bsalomondace19e2014-11-17 07:34:06 -0800110 size_t size = resource->gpuMemorySize();
bsalomonf320e042015-02-17 15:09:34 -0800111 SkDEBUGCODE(++fCount;)
bsalomon84c8e622014-11-17 09:33:27 -0800112 fBytes += size;
bsalomon82b1d622014-11-14 13:59:57 -0800113#if GR_CACHE_STATS
bsalomonf320e042015-02-17 15:09:34 -0800114 fHighWaterCount = SkTMax(this->getResourceCount(), fHighWaterCount);
bsalomon82b1d622014-11-14 13:59:57 -0800115 fHighWaterBytes = SkTMax(fBytes, fHighWaterBytes);
116#endif
bsalomon5ec26ae2016-02-25 08:33:02 -0800117 if (SkBudgeted::kYes == resource->resourcePriv().isBudgeted()) {
bsalomondace19e2014-11-17 07:34:06 -0800118 ++fBudgetedCount;
119 fBudgetedBytes += size;
Brian Osman39c08ac2017-07-26 09:36:09 -0400120 TRACE_COUNTER2("skia.gpu.cache", "skia budget", "used",
hendrikw876c3132015-03-04 10:33:49 -0800121 fBudgetedBytes, "free", fMaxBytes - fBudgetedBytes);
bsalomondace19e2014-11-17 07:34:06 -0800122#if GR_CACHE_STATS
123 fBudgetedHighWaterCount = SkTMax(fBudgetedCount, fBudgetedHighWaterCount);
124 fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes);
125#endif
126 }
robertphillipsc4ed6842016-05-24 14:17:12 -0700127 if (resource->resourcePriv().getScratchKey().isValid() &&
128 !resource->getUniqueKey().isValid()) {
kkinnunen2e6055b2016-04-22 01:48:29 -0700129 SkASSERT(!resource->resourcePriv().refsWrappedObjects());
bsalomon3582d3e2015-02-13 14:20:05 -0800130 fScratchMap.insert(resource->resourcePriv().getScratchKey(), resource);
bsalomon744998e2014-08-28 09:54:34 -0700131 }
bsalomon9f2d1572015-02-17 11:47:40 -0800132
bsalomon71cb0c22014-11-14 12:10:14 -0800133 this->purgeAsNeeded();
bsalomonc8dc1f72014-08-21 13:02:13 -0700134}
135
bsalomon0ea80f42015-02-11 10:49:59 -0800136void GrResourceCache::removeResource(GrGpuResource* resource) {
bsalomon9f2d1572015-02-17 11:47:40 -0800137 this->validate();
bsalomon16961262014-08-26 14:01:07 -0700138 SkASSERT(this->isInCache(resource));
bsalomondace19e2014-11-17 07:34:06 -0800139
Derek Sollenbergeree479142017-05-24 11:41:33 -0400140 size_t size = resource->gpuMemorySize();
bsalomon9f2d1572015-02-17 11:47:40 -0800141 if (resource->isPurgeable()) {
142 fPurgeableQueue.remove(resource);
Derek Sollenbergeree479142017-05-24 11:41:33 -0400143 fPurgeableBytes -= size;
bsalomonf320e042015-02-17 15:09:34 -0800144 } else {
145 this->removeFromNonpurgeableArray(resource);
bsalomon9f2d1572015-02-17 11:47:40 -0800146 }
147
bsalomonf320e042015-02-17 15:09:34 -0800148 SkDEBUGCODE(--fCount;)
bsalomondace19e2014-11-17 07:34:06 -0800149 fBytes -= size;
bsalomon5ec26ae2016-02-25 08:33:02 -0800150 if (SkBudgeted::kYes == resource->resourcePriv().isBudgeted()) {
bsalomondace19e2014-11-17 07:34:06 -0800151 --fBudgetedCount;
152 fBudgetedBytes -= size;
Brian Osman39c08ac2017-07-26 09:36:09 -0400153 TRACE_COUNTER2("skia.gpu.cache", "skia budget", "used",
hendrikw876c3132015-03-04 10:33:49 -0800154 fBudgetedBytes, "free", fMaxBytes - fBudgetedBytes);
bsalomondace19e2014-11-17 07:34:06 -0800155 }
156
robertphillipsc4ed6842016-05-24 14:17:12 -0700157 if (resource->resourcePriv().getScratchKey().isValid() &&
158 !resource->getUniqueKey().isValid()) {
bsalomon3582d3e2015-02-13 14:20:05 -0800159 fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource);
bsalomon744998e2014-08-28 09:54:34 -0700160 }
bsalomon8718aaf2015-02-19 07:24:21 -0800161 if (resource->getUniqueKey().isValid()) {
162 fUniqueHash.remove(resource->getUniqueKey());
bsalomon8b79d232014-11-10 10:19:06 -0800163 }
bsalomonb436ed62014-11-17 12:15:56 -0800164 this->validate();
bsalomonc8dc1f72014-08-21 13:02:13 -0700165}
166
bsalomon0ea80f42015-02-11 10:49:59 -0800167void GrResourceCache::abandonAll() {
bsalomon71cb0c22014-11-14 12:10:14 -0800168 AutoValidate av(this);
169
bsalomonf320e042015-02-17 15:09:34 -0800170 while (fNonpurgeableResources.count()) {
171 GrGpuResource* back = *(fNonpurgeableResources.end() - 1);
172 SkASSERT(!back->wasDestroyed());
173 back->cacheAccess().abandon();
bsalomonc8dc1f72014-08-21 13:02:13 -0700174 }
bsalomonf320e042015-02-17 15:09:34 -0800175
176 while (fPurgeableQueue.count()) {
177 GrGpuResource* top = fPurgeableQueue.peek();
178 SkASSERT(!top->wasDestroyed());
179 top->cacheAccess().abandon();
180 }
181
bsalomon744998e2014-08-28 09:54:34 -0700182 SkASSERT(!fScratchMap.count());
bsalomon8718aaf2015-02-19 07:24:21 -0800183 SkASSERT(!fUniqueHash.count());
bsalomonc8dc1f72014-08-21 13:02:13 -0700184 SkASSERT(!fCount);
bsalomonf320e042015-02-17 15:09:34 -0800185 SkASSERT(!this->getResourceCount());
bsalomondace19e2014-11-17 07:34:06 -0800186 SkASSERT(!fBytes);
187 SkASSERT(!fBudgetedCount);
188 SkASSERT(!fBudgetedBytes);
Derek Sollenbergeree479142017-05-24 11:41:33 -0400189 SkASSERT(!fPurgeableBytes);
bsalomonc8dc1f72014-08-21 13:02:13 -0700190}
191
bsalomon0ea80f42015-02-11 10:49:59 -0800192void GrResourceCache::releaseAll() {
bsalomon71cb0c22014-11-14 12:10:14 -0800193 AutoValidate av(this);
194
Brian Osman13dddce2017-05-09 13:19:50 -0400195 this->processFreedGpuResources();
196
bsalomonf320e042015-02-17 15:09:34 -0800197 while(fNonpurgeableResources.count()) {
198 GrGpuResource* back = *(fNonpurgeableResources.end() - 1);
199 SkASSERT(!back->wasDestroyed());
200 back->cacheAccess().release();
bsalomonc8dc1f72014-08-21 13:02:13 -0700201 }
bsalomonf320e042015-02-17 15:09:34 -0800202
203 while (fPurgeableQueue.count()) {
204 GrGpuResource* top = fPurgeableQueue.peek();
205 SkASSERT(!top->wasDestroyed());
206 top->cacheAccess().release();
207 }
208
bsalomon744998e2014-08-28 09:54:34 -0700209 SkASSERT(!fScratchMap.count());
bsalomon8718aaf2015-02-19 07:24:21 -0800210 SkASSERT(!fUniqueHash.count());
bsalomonc8dc1f72014-08-21 13:02:13 -0700211 SkASSERT(!fCount);
bsalomonf320e042015-02-17 15:09:34 -0800212 SkASSERT(!this->getResourceCount());
bsalomondace19e2014-11-17 07:34:06 -0800213 SkASSERT(!fBytes);
214 SkASSERT(!fBudgetedCount);
215 SkASSERT(!fBudgetedBytes);
Derek Sollenbergeree479142017-05-24 11:41:33 -0400216 SkASSERT(!fPurgeableBytes);
bsalomonc8dc1f72014-08-21 13:02:13 -0700217}
bsalomonbcf0a522014-10-08 08:40:09 -0700218
bsalomon0ea80f42015-02-11 10:49:59 -0800219class GrResourceCache::AvailableForScratchUse {
bsalomonbcf0a522014-10-08 08:40:09 -0700220public:
bsalomon000f8292014-10-15 19:04:14 -0700221 AvailableForScratchUse(bool rejectPendingIO) : fRejectPendingIO(rejectPendingIO) { }
bsalomonbcf0a522014-10-08 08:40:09 -0700222
223 bool operator()(const GrGpuResource* resource) const {
robertphillipsc4ed6842016-05-24 14:17:12 -0700224 SkASSERT(!resource->getUniqueKey().isValid() &&
225 resource->resourcePriv().getScratchKey().isValid());
bsalomon12299ab2014-11-14 13:33:09 -0800226 if (resource->internalHasRef() || !resource->cacheAccess().isScratch()) {
bsalomon000f8292014-10-15 19:04:14 -0700227 return false;
bsalomonbcf0a522014-10-08 08:40:09 -0700228 }
bsalomon000f8292014-10-15 19:04:14 -0700229 return !fRejectPendingIO || !resource->internalHasPendingIO();
bsalomonbcf0a522014-10-08 08:40:09 -0700230 }
bsalomon1e2530b2014-10-09 09:57:18 -0700231
bsalomonbcf0a522014-10-08 08:40:09 -0700232private:
bsalomon000f8292014-10-15 19:04:14 -0700233 bool fRejectPendingIO;
bsalomonbcf0a522014-10-08 08:40:09 -0700234};
235
bsalomon0ea80f42015-02-11 10:49:59 -0800236GrGpuResource* GrResourceCache::findAndRefScratchResource(const GrScratchKey& scratchKey,
robertphillips6e83ac72015-08-13 05:19:14 -0700237 size_t resourceSize,
bsalomon9f2d1572015-02-17 11:47:40 -0800238 uint32_t flags) {
bsalomon7775c852014-12-30 12:50:52 -0800239 SkASSERT(scratchKey.isValid());
robertphillipsee843b22016-10-04 05:30:20 -0700240
bsalomon71cb0c22014-11-14 12:10:14 -0800241 GrGpuResource* resource;
bsalomon000f8292014-10-15 19:04:14 -0700242 if (flags & (kPreferNoPendingIO_ScratchFlag | kRequireNoPendingIO_ScratchFlag)) {
bsalomon71cb0c22014-11-14 12:10:14 -0800243 resource = fScratchMap.find(scratchKey, AvailableForScratchUse(true));
bsalomon000f8292014-10-15 19:04:14 -0700244 if (resource) {
bsalomon9f2d1572015-02-17 11:47:40 -0800245 this->refAndMakeResourceMRU(resource);
bsalomonb436ed62014-11-17 12:15:56 -0800246 this->validate();
247 return resource;
bsalomon000f8292014-10-15 19:04:14 -0700248 } else if (flags & kRequireNoPendingIO_ScratchFlag) {
halcanary96fcdcc2015-08-27 07:41:13 -0700249 return nullptr;
bsalomon000f8292014-10-15 19:04:14 -0700250 }
robertphillips63926682015-08-20 09:39:02 -0700251 // We would prefer to consume more available VRAM rather than flushing
252 // immediately, but on ANGLE this can lead to starving of the GPU.
253 if (fPreferVRAMUseOverFlushes && this->wouldFit(resourceSize)) {
robertphillips6e83ac72015-08-13 05:19:14 -0700254 // kPrefer is specified, we didn't find a resource without pending io,
robertphillips63926682015-08-20 09:39:02 -0700255 // but there is still space in our budget for the resource so force
256 // the caller to allocate a new resource.
halcanary96fcdcc2015-08-27 07:41:13 -0700257 return nullptr;
robertphillips6e83ac72015-08-13 05:19:14 -0700258 }
bsalomon000f8292014-10-15 19:04:14 -0700259 }
bsalomon71cb0c22014-11-14 12:10:14 -0800260 resource = fScratchMap.find(scratchKey, AvailableForScratchUse(false));
261 if (resource) {
bsalomon9f2d1572015-02-17 11:47:40 -0800262 this->refAndMakeResourceMRU(resource);
bsalomonb436ed62014-11-17 12:15:56 -0800263 this->validate();
bsalomon71cb0c22014-11-14 12:10:14 -0800264 }
265 return resource;
bsalomonbcf0a522014-10-08 08:40:09 -0700266}
bsalomon8b79d232014-11-10 10:19:06 -0800267
bsalomon0ea80f42015-02-11 10:49:59 -0800268void GrResourceCache::willRemoveScratchKey(const GrGpuResource* resource) {
bsalomon3582d3e2015-02-13 14:20:05 -0800269 SkASSERT(resource->resourcePriv().getScratchKey().isValid());
robertphillipsc4ed6842016-05-24 14:17:12 -0700270 if (!resource->getUniqueKey().isValid()) {
271 fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource);
272 }
bsalomon10e23ca2014-11-25 05:52:06 -0800273}
274
bsalomonf99e9612015-02-19 08:24:16 -0800275void GrResourceCache::removeUniqueKey(GrGpuResource* resource) {
bsalomon3f324322015-04-08 11:01:54 -0700276 // Someone has a ref to this resource in order to have removed the key. When the ref count
277 // reaches zero we will get a ref cnt notification and figure out what to do with it.
bsalomonf99e9612015-02-19 08:24:16 -0800278 if (resource->getUniqueKey().isValid()) {
279 SkASSERT(resource == fUniqueHash.find(resource->getUniqueKey()));
280 fUniqueHash.remove(resource->getUniqueKey());
281 }
282 resource->cacheAccess().removeUniqueKey();
robertphillipsc4ed6842016-05-24 14:17:12 -0700283
284 if (resource->resourcePriv().getScratchKey().isValid()) {
285 fScratchMap.insert(resource->resourcePriv().getScratchKey(), resource);
286 }
287
bsalomonf99e9612015-02-19 08:24:16 -0800288 this->validate();
bsalomon23e619c2015-02-06 11:54:28 -0800289}
290
bsalomonf99e9612015-02-19 08:24:16 -0800291void GrResourceCache::changeUniqueKey(GrGpuResource* resource, const GrUniqueKey& newKey) {
bsalomon8b79d232014-11-10 10:19:06 -0800292 SkASSERT(resource);
bsalomon71cb0c22014-11-14 12:10:14 -0800293 SkASSERT(this->isInCache(resource));
bsalomon8b79d232014-11-10 10:19:06 -0800294
bsalomonf99e9612015-02-19 08:24:16 -0800295 // If another resource has the new key, remove its key then install the key on this resource.
296 if (newKey.isValid()) {
Greg Daniel0d537802017-09-08 11:44:14 -0400297 if (GrGpuResource* old = fUniqueHash.find(newKey)) {
298 // If the old resource using the key is purgeable and is unreachable, then remove it.
299 if (!old->resourcePriv().getScratchKey().isValid() && old->isPurgeable()) {
300 old->cacheAccess().release();
301 } else {
302 this->removeUniqueKey(old);
303 }
304 }
305 SkASSERT(nullptr == fUniqueHash.find(newKey));
306
robertphillipsc4ed6842016-05-24 14:17:12 -0700307 // Remove the entry for this resource if it already has a unique key.
308 if (resource->getUniqueKey().isValid()) {
309 SkASSERT(resource == fUniqueHash.find(resource->getUniqueKey()));
310 fUniqueHash.remove(resource->getUniqueKey());
311 SkASSERT(nullptr == fUniqueHash.find(resource->getUniqueKey()));
312 } else {
313 // 'resource' didn't have a valid unique key before so it is switching sides. Remove it
314 // from the ScratchMap
315 if (resource->resourcePriv().getScratchKey().isValid()) {
316 fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource);
317 }
318 }
319
bsalomonf99e9612015-02-19 08:24:16 -0800320 resource->cacheAccess().setUniqueKey(newKey);
321 fUniqueHash.add(resource);
322 } else {
robertphillipsc4ed6842016-05-24 14:17:12 -0700323 this->removeUniqueKey(resource);
bsalomonf99e9612015-02-19 08:24:16 -0800324 }
325
bsalomon71cb0c22014-11-14 12:10:14 -0800326 this->validate();
bsalomon8b79d232014-11-10 10:19:06 -0800327}
bsalomon71cb0c22014-11-14 12:10:14 -0800328
bsalomon9f2d1572015-02-17 11:47:40 -0800329void GrResourceCache::refAndMakeResourceMRU(GrGpuResource* resource) {
bsalomon71cb0c22014-11-14 12:10:14 -0800330 SkASSERT(resource);
331 SkASSERT(this->isInCache(resource));
bsalomonddf30e62015-02-19 11:38:44 -0800332
bsalomon9f2d1572015-02-17 11:47:40 -0800333 if (resource->isPurgeable()) {
334 // It's about to become unpurgeable.
Derek Sollenbergeree479142017-05-24 11:41:33 -0400335 fPurgeableBytes -= resource->gpuMemorySize();
bsalomon9f2d1572015-02-17 11:47:40 -0800336 fPurgeableQueue.remove(resource);
bsalomonf320e042015-02-17 15:09:34 -0800337 this->addToNonpurgeableArray(resource);
bsalomon9f2d1572015-02-17 11:47:40 -0800338 }
339 resource->ref();
bsalomonddf30e62015-02-19 11:38:44 -0800340
341 resource->cacheAccess().setTimestamp(this->getNextTimestamp());
bsalomonf320e042015-02-17 15:09:34 -0800342 this->validate();
bsalomon71cb0c22014-11-14 12:10:14 -0800343}
344
bsalomon3f324322015-04-08 11:01:54 -0700345void GrResourceCache::notifyCntReachedZero(GrGpuResource* resource, uint32_t flags) {
bsalomon71cb0c22014-11-14 12:10:14 -0800346 SkASSERT(resource);
bsalomon3f324322015-04-08 11:01:54 -0700347 SkASSERT(!resource->wasDestroyed());
348 SkASSERT(flags);
bsalomon71cb0c22014-11-14 12:10:14 -0800349 SkASSERT(this->isInCache(resource));
bsalomon3f324322015-04-08 11:01:54 -0700350 // This resource should always be in the nonpurgeable array when this function is called. It
351 // will be moved to the queue if it is newly purgeable.
352 SkASSERT(fNonpurgeableResources[*resource->cacheAccess().accessCacheIndex()] == resource);
bsalomon71cb0c22014-11-14 12:10:14 -0800353
bsalomon3f324322015-04-08 11:01:54 -0700354 if (SkToBool(ResourceAccess::kRefCntReachedZero_RefNotificationFlag & flags)) {
355#ifdef SK_DEBUG
356 // When the timestamp overflows validate() is called. validate() checks that resources in
357 // the nonpurgeable array are indeed not purgeable. However, the movement from the array to
358 // the purgeable queue happens just below in this function. So we mark it as an exception.
359 if (resource->isPurgeable()) {
360 fNewlyPurgeableResourceForValidation = resource;
361 }
362#endif
363 resource->cacheAccess().setTimestamp(this->getNextTimestamp());
halcanary96fcdcc2015-08-27 07:41:13 -0700364 SkDEBUGCODE(fNewlyPurgeableResourceForValidation = nullptr);
bsalomon3f324322015-04-08 11:01:54 -0700365 }
366
367 if (!SkToBool(ResourceAccess::kAllCntsReachedZero_RefNotificationFlag & flags)) {
368 SkASSERT(!resource->isPurgeable());
369 return;
370 }
371
372 SkASSERT(resource->isPurgeable());
bsalomonf320e042015-02-17 15:09:34 -0800373 this->removeFromNonpurgeableArray(resource);
bsalomon9f2d1572015-02-17 11:47:40 -0800374 fPurgeableQueue.insert(resource);
bsalomone2e87f32016-09-22 12:42:11 -0700375 resource->cacheAccess().setFlushCntWhenResourceBecamePurgeable(fExternalFlushCnt);
Brian Salomon5e150852017-03-22 14:53:13 -0400376 resource->cacheAccess().setTimeWhenResourceBecomePurgeable();
Derek Sollenbergeree479142017-05-24 11:41:33 -0400377 fPurgeableBytes += resource->gpuMemorySize();
bsalomon71cb0c22014-11-14 12:10:14 -0800378
bsalomon5ec26ae2016-02-25 08:33:02 -0800379 if (SkBudgeted::kNo == resource->resourcePriv().isBudgeted()) {
bsalomonc2f35b72015-01-23 07:19:22 -0800380 // Check whether this resource could still be used as a scratch resource.
kkinnunen2e6055b2016-04-22 01:48:29 -0700381 if (!resource->resourcePriv().refsWrappedObjects() &&
bsalomon9f2d1572015-02-17 11:47:40 -0800382 resource->resourcePriv().getScratchKey().isValid()) {
bsalomonc2f35b72015-01-23 07:19:22 -0800383 // We won't purge an existing resource to make room for this one.
bsalomonf320e042015-02-17 15:09:34 -0800384 if (fBudgetedCount < fMaxCount &&
385 fBudgetedBytes + resource->gpuMemorySize() <= fMaxBytes) {
bsalomon3582d3e2015-02-13 14:20:05 -0800386 resource->resourcePriv().makeBudgeted();
bsalomon9f2d1572015-02-17 11:47:40 -0800387 return;
bsalomonc2f35b72015-01-23 07:19:22 -0800388 }
bsalomonc2f35b72015-01-23 07:19:22 -0800389 }
390 } else {
bsalomon9f2d1572015-02-17 11:47:40 -0800391 // Purge the resource immediately if we're over budget
bsalomon8718aaf2015-02-19 07:24:21 -0800392 // Also purge if the resource has neither a valid scratch key nor a unique key.
robertphillipsee843b22016-10-04 05:30:20 -0700393 bool noKey = !resource->resourcePriv().getScratchKey().isValid() &&
394 !resource->getUniqueKey().isValid();
395 if (!this->overBudget() && !noKey) {
bsalomon9f2d1572015-02-17 11:47:40 -0800396 return;
bsalomonc2f35b72015-01-23 07:19:22 -0800397 }
398 }
bsalomondace19e2014-11-17 07:34:06 -0800399
bsalomonf320e042015-02-17 15:09:34 -0800400 SkDEBUGCODE(int beforeCount = this->getResourceCount();)
bsalomon9f2d1572015-02-17 11:47:40 -0800401 resource->cacheAccess().release();
402 // We should at least free this resource, perhaps dependent resources as well.
bsalomonf320e042015-02-17 15:09:34 -0800403 SkASSERT(this->getResourceCount() < beforeCount);
bsalomon71cb0c22014-11-14 12:10:14 -0800404 this->validate();
405}
406
bsalomon0ea80f42015-02-11 10:49:59 -0800407void GrResourceCache::didChangeGpuMemorySize(const GrGpuResource* resource, size_t oldSize) {
bsalomon71cb0c22014-11-14 12:10:14 -0800408 // SkASSERT(!fPurging); GrPathRange increases size during flush. :(
409 SkASSERT(resource);
410 SkASSERT(this->isInCache(resource));
411
bsalomondace19e2014-11-17 07:34:06 -0800412 ptrdiff_t delta = resource->gpuMemorySize() - oldSize;
413
414 fBytes += delta;
bsalomon82b1d622014-11-14 13:59:57 -0800415#if GR_CACHE_STATS
416 fHighWaterBytes = SkTMax(fBytes, fHighWaterBytes);
417#endif
bsalomon5ec26ae2016-02-25 08:33:02 -0800418 if (SkBudgeted::kYes == resource->resourcePriv().isBudgeted()) {
bsalomondace19e2014-11-17 07:34:06 -0800419 fBudgetedBytes += delta;
Brian Osman39c08ac2017-07-26 09:36:09 -0400420 TRACE_COUNTER2("skia.gpu.cache", "skia budget", "used",
hendrikw876c3132015-03-04 10:33:49 -0800421 fBudgetedBytes, "free", fMaxBytes - fBudgetedBytes);
bsalomondace19e2014-11-17 07:34:06 -0800422#if GR_CACHE_STATS
423 fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes);
424#endif
425 }
bsalomon71cb0c22014-11-14 12:10:14 -0800426
427 this->purgeAsNeeded();
428 this->validate();
429}
430
bsalomon0ea80f42015-02-11 10:49:59 -0800431void GrResourceCache::didChangeBudgetStatus(GrGpuResource* resource) {
bsalomon84c8e622014-11-17 09:33:27 -0800432 SkASSERT(resource);
433 SkASSERT(this->isInCache(resource));
434
435 size_t size = resource->gpuMemorySize();
436
bsalomon5ec26ae2016-02-25 08:33:02 -0800437 if (SkBudgeted::kYes == resource->resourcePriv().isBudgeted()) {
bsalomon84c8e622014-11-17 09:33:27 -0800438 ++fBudgetedCount;
439 fBudgetedBytes += size;
bsalomonafe30052015-01-16 07:32:33 -0800440#if GR_CACHE_STATS
441 fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes);
442 fBudgetedHighWaterCount = SkTMax(fBudgetedCount, fBudgetedHighWaterCount);
443#endif
bsalomon84c8e622014-11-17 09:33:27 -0800444 this->purgeAsNeeded();
445 } else {
446 --fBudgetedCount;
447 fBudgetedBytes -= size;
448 }
Brian Osman39c08ac2017-07-26 09:36:09 -0400449 TRACE_COUNTER2("skia.gpu.cache", "skia budget", "used",
hendrikw876c3132015-03-04 10:33:49 -0800450 fBudgetedBytes, "free", fMaxBytes - fBudgetedBytes);
bsalomon84c8e622014-11-17 09:33:27 -0800451
452 this->validate();
453}
454
robertphillipsee843b22016-10-04 05:30:20 -0700455void GrResourceCache::purgeAsNeeded() {
bsalomon3f324322015-04-08 11:01:54 -0700456 SkTArray<GrUniqueKeyInvalidatedMessage> invalidKeyMsgs;
457 fInvalidUniqueKeyInbox.poll(&invalidKeyMsgs);
458 if (invalidKeyMsgs.count()) {
459 this->processInvalidUniqueKeys(invalidKeyMsgs);
460 }
bsalomon71cb0c22014-11-14 12:10:14 -0800461
Brian Osman13dddce2017-05-09 13:19:50 -0400462 this->processFreedGpuResources();
463
bsalomone2e87f32016-09-22 12:42:11 -0700464 if (fMaxUnusedFlushes > 0) {
465 // We want to know how many complete flushes have occurred without the resource being used.
466 // If the resource was tagged when fExternalFlushCnt was N then this means it became
467 // purgeable during activity that became the N+1th flush. So when the flush count is N+2
468 // it has sat in the purgeable queue for one entire flush.
469 uint32_t oldestAllowedFlushCnt = fExternalFlushCnt - fMaxUnusedFlushes - 1;
470 // check for underflow
471 if (oldestAllowedFlushCnt < fExternalFlushCnt) {
472 while (fPurgeableQueue.count()) {
473 uint32_t flushWhenResourceBecamePurgeable =
474 fPurgeableQueue.peek()->cacheAccess().flushCntWhenResourceBecamePurgeable();
475 if (oldestAllowedFlushCnt < flushWhenResourceBecamePurgeable) {
476 // Resources were given both LRU timestamps and tagged with a flush cnt when
477 // they first became purgeable. The LRU timestamp won't change again until the
478 // resource is made non-purgeable again. So, at this point all the remaining
479 // resources in the timestamp-sorted queue will have a flush count >= to this
480 // one.
481 break;
482 }
483 GrGpuResource* resource = fPurgeableQueue.peek();
484 SkASSERT(resource->isPurgeable());
485 resource->cacheAccess().release();
bsalomon3f324322015-04-08 11:01:54 -0700486 }
bsalomon3f324322015-04-08 11:01:54 -0700487 }
488 }
489
490 bool stillOverbudget = this->overBudget();
491 while (stillOverbudget && fPurgeableQueue.count()) {
robertphillipsee843b22016-10-04 05:30:20 -0700492 GrGpuResource* resource = fPurgeableQueue.peek();
bsalomon9f2d1572015-02-17 11:47:40 -0800493 SkASSERT(resource->isPurgeable());
494 resource->cacheAccess().release();
bsalomon3f324322015-04-08 11:01:54 -0700495 stillOverbudget = this->overBudget();
bsalomon9f2d1572015-02-17 11:47:40 -0800496 }
bsalomon71cb0c22014-11-14 12:10:14 -0800497
bsalomonb436ed62014-11-17 12:15:56 -0800498 this->validate();
robertphillipsee843b22016-10-04 05:30:20 -0700499
500 if (stillOverbudget) {
501 // Set this so that GrDrawingManager will issue a flush to free up resources with pending
502 // IO that we were unable to purge in this pass.
503 fRequestFlush = true;
504 }
bsalomon71cb0c22014-11-14 12:10:14 -0800505}
506
bsalomon0ea80f42015-02-11 10:49:59 -0800507void GrResourceCache::purgeAllUnlocked() {
bsalomon9f2d1572015-02-17 11:47:40 -0800508 // We could disable maintaining the heap property here, but it would add a lot of complexity.
509 // Moreover, this is rarely called.
510 while (fPurgeableQueue.count()) {
511 GrGpuResource* resource = fPurgeableQueue.peek();
512 SkASSERT(resource->isPurgeable());
513 resource->cacheAccess().release();
514 }
bsalomon71cb0c22014-11-14 12:10:14 -0800515
bsalomonb436ed62014-11-17 12:15:56 -0800516 this->validate();
bsalomon71cb0c22014-11-14 12:10:14 -0800517}
518
Brian Salomon5e150852017-03-22 14:53:13 -0400519void GrResourceCache::purgeResourcesNotUsedSince(GrStdSteadyClock::time_point purgeTime) {
520 while (fPurgeableQueue.count()) {
521 const GrStdSteadyClock::time_point resourceTime =
522 fPurgeableQueue.peek()->cacheAccess().timeWhenResourceBecamePurgeable();
523 if (resourceTime >= purgeTime) {
524 // Resources were given both LRU timestamps and tagged with a frame number when
525 // they first became purgeable. The LRU timestamp won't change again until the
526 // resource is made non-purgeable again. So, at this point all the remaining
527 // resources in the timestamp-sorted queue will have a frame number >= to this
528 // one.
529 break;
530 }
531 GrGpuResource* resource = fPurgeableQueue.peek();
532 SkASSERT(resource->isPurgeable());
533 resource->cacheAccess().release();
534 }
535}
536
Derek Sollenberger5480a182017-05-25 16:43:59 -0400537void GrResourceCache::purgeUnlockedResources(size_t bytesToPurge, bool preferScratchResources) {
538
539 const size_t tmpByteBudget = SkTMax((size_t)0, fBytes - bytesToPurge);
540 bool stillOverbudget = tmpByteBudget < fBytes;
541
542 if (preferScratchResources && bytesToPurge < fPurgeableBytes) {
543 // Sort the queue
544 fPurgeableQueue.sort();
545
546 // Make a list of the scratch resources to delete
547 SkTDArray<GrGpuResource*> scratchResources;
548 size_t scratchByteCount = 0;
549 for (int i = 0; i < fPurgeableQueue.count() && stillOverbudget; i++) {
550 GrGpuResource* resource = fPurgeableQueue.at(i);
551 SkASSERT(resource->isPurgeable());
552 if (!resource->getUniqueKey().isValid()) {
553 *scratchResources.append() = resource;
554 scratchByteCount += resource->gpuMemorySize();
555 stillOverbudget = tmpByteBudget < fBytes - scratchByteCount;
556 }
557 }
558
559 // Delete the scratch resources. This must be done as a separate pass
560 // to avoid messing up the sorted order of the queue
561 for (int i = 0; i < scratchResources.count(); i++) {
562 scratchResources.getAt(i)->cacheAccess().release();
563 }
564 stillOverbudget = tmpByteBudget < fBytes;
565
566 this->validate();
567 }
568
569 // Purge any remaining resources in LRU order
570 if (stillOverbudget) {
571 const size_t cachedByteCount = fMaxBytes;
572 fMaxBytes = tmpByteBudget;
573 this->purgeAsNeeded();
574 fMaxBytes = cachedByteCount;
575 }
576}
577
bsalomon8718aaf2015-02-19 07:24:21 -0800578void GrResourceCache::processInvalidUniqueKeys(
579 const SkTArray<GrUniqueKeyInvalidatedMessage>& msgs) {
bsalomon23e619c2015-02-06 11:54:28 -0800580 for (int i = 0; i < msgs.count(); ++i) {
bsalomon8718aaf2015-02-19 07:24:21 -0800581 GrGpuResource* resource = this->findAndRefUniqueResource(msgs[i].key());
bsalomon23e619c2015-02-06 11:54:28 -0800582 if (resource) {
bsalomon8718aaf2015-02-19 07:24:21 -0800583 resource->resourcePriv().removeUniqueKey();
bsalomon3f324322015-04-08 11:01:54 -0700584 resource->unref(); // If this resource is now purgeable, the cache will be notified.
bsalomon23e619c2015-02-06 11:54:28 -0800585 }
586 }
587}
588
Brian Osman13dddce2017-05-09 13:19:50 -0400589void GrResourceCache::insertCrossContextGpuResource(GrGpuResource* resource) {
590 resource->ref();
591}
592
593void GrResourceCache::processFreedGpuResources() {
594 SkTArray<GrGpuResourceFreedMessage> msgs;
595 fFreedGpuResourceInbox.poll(&msgs);
596 for (int i = 0; i < msgs.count(); ++i) {
597 if (msgs[i].fOwningUniqueID == fContextUniqueID) {
598 msgs[i].fResource->unref();
599 }
600 }
601}
602
bsalomonf320e042015-02-17 15:09:34 -0800603void GrResourceCache::addToNonpurgeableArray(GrGpuResource* resource) {
604 int index = fNonpurgeableResources.count();
605 *fNonpurgeableResources.append() = resource;
606 *resource->cacheAccess().accessCacheIndex() = index;
607}
608
609void GrResourceCache::removeFromNonpurgeableArray(GrGpuResource* resource) {
610 int* index = resource->cacheAccess().accessCacheIndex();
611 // Fill the whole we will create in the array with the tail object, adjust its index, and
612 // then pop the array
613 GrGpuResource* tail = *(fNonpurgeableResources.end() - 1);
614 SkASSERT(fNonpurgeableResources[*index] == resource);
615 fNonpurgeableResources[*index] = tail;
616 *tail->cacheAccess().accessCacheIndex() = *index;
617 fNonpurgeableResources.pop();
618 SkDEBUGCODE(*index = -1);
619}
620
bsalomonddf30e62015-02-19 11:38:44 -0800621uint32_t GrResourceCache::getNextTimestamp() {
622 // If we wrap then all the existing resources will appear older than any resources that get
623 // a timestamp after the wrap.
624 if (0 == fTimestamp) {
625 int count = this->getResourceCount();
626 if (count) {
627 // Reset all the timestamps. We sort the resources by timestamp and then assign
628 // sequential timestamps beginning with 0. This is O(n*lg(n)) but it should be extremely
629 // rare.
630 SkTDArray<GrGpuResource*> sortedPurgeableResources;
631 sortedPurgeableResources.setReserve(fPurgeableQueue.count());
632
633 while (fPurgeableQueue.count()) {
634 *sortedPurgeableResources.append() = fPurgeableQueue.peek();
635 fPurgeableQueue.pop();
636 }
robertphillipsee843b22016-10-04 05:30:20 -0700637
bsalomone2e87f32016-09-22 12:42:11 -0700638 SkTQSort(fNonpurgeableResources.begin(), fNonpurgeableResources.end() - 1,
639 CompareTimestamp);
bsalomonddf30e62015-02-19 11:38:44 -0800640
641 // Pick resources out of the purgeable and non-purgeable arrays based on lowest
642 // timestamp and assign new timestamps.
643 int currP = 0;
644 int currNP = 0;
645 while (currP < sortedPurgeableResources.count() &&
mtklein56da0252015-11-16 11:16:23 -0800646 currNP < fNonpurgeableResources.count()) {
bsalomonddf30e62015-02-19 11:38:44 -0800647 uint32_t tsP = sortedPurgeableResources[currP]->cacheAccess().timestamp();
648 uint32_t tsNP = fNonpurgeableResources[currNP]->cacheAccess().timestamp();
649 SkASSERT(tsP != tsNP);
650 if (tsP < tsNP) {
651 sortedPurgeableResources[currP++]->cacheAccess().setTimestamp(fTimestamp++);
652 } else {
653 // Correct the index in the nonpurgeable array stored on the resource post-sort.
654 *fNonpurgeableResources[currNP]->cacheAccess().accessCacheIndex() = currNP;
655 fNonpurgeableResources[currNP++]->cacheAccess().setTimestamp(fTimestamp++);
656 }
657 }
658
659 // The above loop ended when we hit the end of one array. Finish the other one.
660 while (currP < sortedPurgeableResources.count()) {
661 sortedPurgeableResources[currP++]->cacheAccess().setTimestamp(fTimestamp++);
662 }
663 while (currNP < fNonpurgeableResources.count()) {
664 *fNonpurgeableResources[currNP]->cacheAccess().accessCacheIndex() = currNP;
665 fNonpurgeableResources[currNP++]->cacheAccess().setTimestamp(fTimestamp++);
666 }
667
668 // Rebuild the queue.
669 for (int i = 0; i < sortedPurgeableResources.count(); ++i) {
670 fPurgeableQueue.insert(sortedPurgeableResources[i]);
671 }
672
673 this->validate();
674 SkASSERT(count == this->getResourceCount());
675
676 // count should be the next timestamp we return.
677 SkASSERT(fTimestamp == SkToU32(count));
mtklein56da0252015-11-16 11:16:23 -0800678 }
bsalomonddf30e62015-02-19 11:38:44 -0800679 }
680 return fTimestamp++;
681}
682
bsalomonb77a9072016-09-07 10:02:04 -0700683void GrResourceCache::notifyFlushOccurred(FlushType type) {
684 switch (type) {
bsalomonb77a9072016-09-07 10:02:04 -0700685 case FlushType::kCacheRequested:
robertphillipsee843b22016-10-04 05:30:20 -0700686 SkASSERT(fRequestFlush);
687 fRequestFlush = false;
bsalomonb77a9072016-09-07 10:02:04 -0700688 break;
robertphillipsee843b22016-10-04 05:30:20 -0700689 case FlushType::kExternal:
bsalomone2e87f32016-09-22 12:42:11 -0700690 ++fExternalFlushCnt;
691 if (0 == fExternalFlushCnt) {
692 // When this wraps just reset all the purgeable resources' last used flush state.
693 for (int i = 0; i < fPurgeableQueue.count(); ++i) {
694 fPurgeableQueue.at(i)->cacheAccess().setFlushCntWhenResourceBecamePurgeable(0);
695 }
bsalomonb77a9072016-09-07 10:02:04 -0700696 }
697 break;
bsalomon3f324322015-04-08 11:01:54 -0700698 }
robertphillipsee843b22016-10-04 05:30:20 -0700699 this->purgeAsNeeded();
bsalomon3f324322015-04-08 11:01:54 -0700700}
701
ericrk0a5fa482015-09-15 14:16:10 -0700702void GrResourceCache::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
703 for (int i = 0; i < fNonpurgeableResources.count(); ++i) {
704 fNonpurgeableResources[i]->dumpMemoryStatistics(traceMemoryDump);
705 }
706 for (int i = 0; i < fPurgeableQueue.count(); ++i) {
707 fPurgeableQueue.at(i)->dumpMemoryStatistics(traceMemoryDump);
708 }
709}
710
bsalomon71cb0c22014-11-14 12:10:14 -0800711#ifdef SK_DEBUG
bsalomon0ea80f42015-02-11 10:49:59 -0800712void GrResourceCache::validate() const {
bsalomonc2f35b72015-01-23 07:19:22 -0800713 // Reduce the frequency of validations for large resource counts.
714 static SkRandom gRandom;
715 int mask = (SkNextPow2(fCount + 1) >> 5) - 1;
716 if (~mask && (gRandom.nextU() & mask)) {
717 return;
718 }
719
bsalomonf320e042015-02-17 15:09:34 -0800720 struct Stats {
721 size_t fBytes;
722 int fBudgetedCount;
723 size_t fBudgetedBytes;
724 int fLocked;
725 int fScratch;
726 int fCouldBeScratch;
727 int fContent;
728 const ScratchMap* fScratchMap;
bsalomon8718aaf2015-02-19 07:24:21 -0800729 const UniqueHash* fUniqueHash;
bsalomon71cb0c22014-11-14 12:10:14 -0800730
bsalomonf320e042015-02-17 15:09:34 -0800731 Stats(const GrResourceCache* cache) {
732 memset(this, 0, sizeof(*this));
733 fScratchMap = &cache->fScratchMap;
bsalomon8718aaf2015-02-19 07:24:21 -0800734 fUniqueHash = &cache->fUniqueHash;
bsalomon71cb0c22014-11-14 12:10:14 -0800735 }
736
bsalomonf320e042015-02-17 15:09:34 -0800737 void update(GrGpuResource* resource) {
738 fBytes += resource->gpuMemorySize();
bsalomondace19e2014-11-17 07:34:06 -0800739
bsalomonf320e042015-02-17 15:09:34 -0800740 if (!resource->isPurgeable()) {
741 ++fLocked;
742 }
bsalomon9f2d1572015-02-17 11:47:40 -0800743
robertphillipsc4ed6842016-05-24 14:17:12 -0700744 const GrScratchKey& scratchKey = resource->resourcePriv().getScratchKey();
745 const GrUniqueKey& uniqueKey = resource->getUniqueKey();
746
bsalomonf320e042015-02-17 15:09:34 -0800747 if (resource->cacheAccess().isScratch()) {
robertphillipsc4ed6842016-05-24 14:17:12 -0700748 SkASSERT(!uniqueKey.isValid());
bsalomonf320e042015-02-17 15:09:34 -0800749 ++fScratch;
robertphillipsc4ed6842016-05-24 14:17:12 -0700750 SkASSERT(fScratchMap->countForKey(scratchKey));
kkinnunen2e6055b2016-04-22 01:48:29 -0700751 SkASSERT(!resource->resourcePriv().refsWrappedObjects());
robertphillipsc4ed6842016-05-24 14:17:12 -0700752 } else if (scratchKey.isValid()) {
bsalomon5ec26ae2016-02-25 08:33:02 -0800753 SkASSERT(SkBudgeted::kNo == resource->resourcePriv().isBudgeted() ||
robertphillipsc4ed6842016-05-24 14:17:12 -0700754 uniqueKey.isValid());
755 if (!uniqueKey.isValid()) {
mtklein4e976072016-08-08 09:06:27 -0700756 ++fCouldBeScratch;
robertphillipsc4ed6842016-05-24 14:17:12 -0700757 SkASSERT(fScratchMap->countForKey(scratchKey));
758 }
kkinnunen2e6055b2016-04-22 01:48:29 -0700759 SkASSERT(!resource->resourcePriv().refsWrappedObjects());
bsalomonf320e042015-02-17 15:09:34 -0800760 }
bsalomon8718aaf2015-02-19 07:24:21 -0800761 if (uniqueKey.isValid()) {
bsalomonf320e042015-02-17 15:09:34 -0800762 ++fContent;
bsalomon8718aaf2015-02-19 07:24:21 -0800763 SkASSERT(fUniqueHash->find(uniqueKey) == resource);
Brian Osman0562eb92017-05-08 11:16:39 -0400764 SkASSERT(SkBudgeted::kYes == resource->resourcePriv().isBudgeted() ||
765 resource->resourcePriv().refsWrappedObjects());
robertphillipsc4ed6842016-05-24 14:17:12 -0700766
767 if (scratchKey.isValid()) {
768 SkASSERT(!fScratchMap->has(resource, scratchKey));
769 }
bsalomonf320e042015-02-17 15:09:34 -0800770 }
771
bsalomon5ec26ae2016-02-25 08:33:02 -0800772 if (SkBudgeted::kYes == resource->resourcePriv().isBudgeted()) {
bsalomonf320e042015-02-17 15:09:34 -0800773 ++fBudgetedCount;
774 fBudgetedBytes += resource->gpuMemorySize();
775 }
bsalomon9f2d1572015-02-17 11:47:40 -0800776 }
bsalomonf320e042015-02-17 15:09:34 -0800777 };
778
robertphillipsc4ed6842016-05-24 14:17:12 -0700779 {
780 ScratchMap::ConstIter iter(&fScratchMap);
781
782 int count = 0;
783 for ( ; !iter.done(); ++iter) {
784 const GrGpuResource* resource = *iter;
785 SkASSERT(resource->resourcePriv().getScratchKey().isValid());
786 SkASSERT(!resource->getUniqueKey().isValid());
787 count++;
788 }
789 SkASSERT(count == fScratchMap.count()); // ensure the iterator is working correctly
790 }
791
bsalomonf320e042015-02-17 15:09:34 -0800792 Stats stats(this);
Derek Sollenbergeree479142017-05-24 11:41:33 -0400793 size_t purgeableBytes = 0;
bsalomonf320e042015-02-17 15:09:34 -0800794
795 for (int i = 0; i < fNonpurgeableResources.count(); ++i) {
bsalomon3f324322015-04-08 11:01:54 -0700796 SkASSERT(!fNonpurgeableResources[i]->isPurgeable() ||
797 fNewlyPurgeableResourceForValidation == fNonpurgeableResources[i]);
bsalomonf320e042015-02-17 15:09:34 -0800798 SkASSERT(*fNonpurgeableResources[i]->cacheAccess().accessCacheIndex() == i);
799 SkASSERT(!fNonpurgeableResources[i]->wasDestroyed());
800 stats.update(fNonpurgeableResources[i]);
bsalomon71cb0c22014-11-14 12:10:14 -0800801 }
bsalomon9f2d1572015-02-17 11:47:40 -0800802 for (int i = 0; i < fPurgeableQueue.count(); ++i) {
803 SkASSERT(fPurgeableQueue.at(i)->isPurgeable());
bsalomonf320e042015-02-17 15:09:34 -0800804 SkASSERT(*fPurgeableQueue.at(i)->cacheAccess().accessCacheIndex() == i);
805 SkASSERT(!fPurgeableQueue.at(i)->wasDestroyed());
806 stats.update(fPurgeableQueue.at(i));
Derek Sollenbergeree479142017-05-24 11:41:33 -0400807 purgeableBytes += fPurgeableQueue.at(i)->gpuMemorySize();
bsalomon9f2d1572015-02-17 11:47:40 -0800808 }
809
bsalomonf320e042015-02-17 15:09:34 -0800810 SkASSERT(fCount == this->getResourceCount());
bsalomondace19e2014-11-17 07:34:06 -0800811 SkASSERT(fBudgetedCount <= fCount);
bsalomonf320e042015-02-17 15:09:34 -0800812 SkASSERT(fBudgetedBytes <= fBytes);
813 SkASSERT(stats.fBytes == fBytes);
814 SkASSERT(stats.fBudgetedBytes == fBudgetedBytes);
815 SkASSERT(stats.fBudgetedCount == fBudgetedCount);
Derek Sollenbergeree479142017-05-24 11:41:33 -0400816 SkASSERT(purgeableBytes == fPurgeableBytes);
bsalomon71cb0c22014-11-14 12:10:14 -0800817#if GR_CACHE_STATS
bsalomondace19e2014-11-17 07:34:06 -0800818 SkASSERT(fBudgetedHighWaterCount <= fHighWaterCount);
819 SkASSERT(fBudgetedHighWaterBytes <= fHighWaterBytes);
bsalomonf320e042015-02-17 15:09:34 -0800820 SkASSERT(fBytes <= fHighWaterBytes);
821 SkASSERT(fCount <= fHighWaterCount);
822 SkASSERT(fBudgetedBytes <= fBudgetedHighWaterBytes);
823 SkASSERT(fBudgetedCount <= fBudgetedHighWaterCount);
bsalomon71cb0c22014-11-14 12:10:14 -0800824#endif
bsalomon8718aaf2015-02-19 07:24:21 -0800825 SkASSERT(stats.fContent == fUniqueHash.count());
bsalomonf320e042015-02-17 15:09:34 -0800826 SkASSERT(stats.fScratch + stats.fCouldBeScratch == fScratchMap.count());
bsalomon71cb0c22014-11-14 12:10:14 -0800827
bsalomon3f324322015-04-08 11:01:54 -0700828 // This assertion is not currently valid because we can be in recursive notifyCntReachedZero()
bsalomon12299ab2014-11-14 13:33:09 -0800829 // calls. This will be fixed when subresource registration is explicit.
bsalomondace19e2014-11-17 07:34:06 -0800830 // bool overBudget = budgetedBytes > fMaxBytes || budgetedCount > fMaxCount;
bsalomon12299ab2014-11-14 13:33:09 -0800831 // SkASSERT(!overBudget || locked == count || fPurging);
bsalomon71cb0c22014-11-14 12:10:14 -0800832}
bsalomonf320e042015-02-17 15:09:34 -0800833
834bool GrResourceCache::isInCache(const GrGpuResource* resource) const {
835 int index = *resource->cacheAccess().accessCacheIndex();
836 if (index < 0) {
837 return false;
838 }
839 if (index < fPurgeableQueue.count() && fPurgeableQueue.at(index) == resource) {
840 return true;
841 }
842 if (index < fNonpurgeableResources.count() && fNonpurgeableResources[index] == resource) {
843 return true;
844 }
845 SkDEBUGFAIL("Resource index should be -1 or the resource should be in the cache.");
846 return false;
847}
848
bsalomon71cb0c22014-11-14 12:10:14 -0800849#endif