blob: 1d32c23abac3fca5deb16c7b986211b029285172 [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"
bsalomon3582d3e2015-02-13 14:20:05 -080010#include "GrGpuResourceCacheAccess.h"
hendrikw876c3132015-03-04 10:33:49 -080011#include "GrTracing.h"
bsalomon7775c852014-12-30 12:50:52 -080012#include "SkChecksum.h"
bsalomon71cb0c22014-11-14 12:10:14 -080013#include "SkGr.h"
14#include "SkMessageBus.h"
bsalomonddf30e62015-02-19 11:38:44 -080015#include "SkTSort.h"
bsalomon71cb0c22014-11-14 12:10:14 -080016
bsalomon8718aaf2015-02-19 07:24:21 -080017DECLARE_SKMESSAGEBUS_MESSAGE(GrUniqueKeyInvalidatedMessage);
bsalomon71cb0c22014-11-14 12:10:14 -080018
19//////////////////////////////////////////////////////////////////////////////
20
bsalomon7775c852014-12-30 12:50:52 -080021GrScratchKey::ResourceType GrScratchKey::GenerateResourceType() {
bsalomon24db3b12015-01-23 04:24:04 -080022 static int32_t gType = INHERITED::kInvalidDomain + 1;
bsalomonfe369ee2014-11-10 11:59:06 -080023
bsalomon7775c852014-12-30 12:50:52 -080024 int32_t type = sk_atomic_inc(&gType);
robertphillips9790a7b2015-01-05 12:29:15 -080025 if (type > SK_MaxU16) {
bsalomon71cb0c22014-11-14 12:10:14 -080026 SkFAIL("Too many Resource Types");
27 }
28
29 return static_cast<ResourceType>(type);
30}
31
bsalomon8718aaf2015-02-19 07:24:21 -080032GrUniqueKey::Domain GrUniqueKey::GenerateDomain() {
bsalomon24db3b12015-01-23 04:24:04 -080033 static int32_t gDomain = INHERITED::kInvalidDomain + 1;
bsalomon7775c852014-12-30 12:50:52 -080034
bsalomon24db3b12015-01-23 04:24:04 -080035 int32_t domain = sk_atomic_inc(&gDomain);
kkinnunen016dffb2015-01-23 06:43:05 -080036 if (domain > SK_MaxU16) {
bsalomon8718aaf2015-02-19 07:24:21 -080037 SkFAIL("Too many GrUniqueKey Domains");
bsalomon7775c852014-12-30 12:50:52 -080038 }
bsalomon24db3b12015-01-23 04:24:04 -080039
40 return static_cast<Domain>(domain);
41}
bsalomon3f324322015-04-08 11:01:54 -070042
bsalomon24db3b12015-01-23 04:24:04 -080043uint32_t GrResourceKeyHash(const uint32_t* data, size_t size) {
mtklein56da0252015-11-16 11:16:23 -080044 return SkChecksum::Murmur3(data, size);
bsalomon7775c852014-12-30 12:50:52 -080045}
46
bsalomonfe369ee2014-11-10 11:59:06 -080047//////////////////////////////////////////////////////////////////////////////
48
bsalomon0ea80f42015-02-11 10:49:59 -080049class GrResourceCache::AutoValidate : ::SkNoncopyable {
bsalomon71cb0c22014-11-14 12:10:14 -080050public:
bsalomon0ea80f42015-02-11 10:49:59 -080051 AutoValidate(GrResourceCache* cache) : fCache(cache) { cache->validate(); }
bsalomon71cb0c22014-11-14 12:10:14 -080052 ~AutoValidate() { fCache->validate(); }
53private:
bsalomon0ea80f42015-02-11 10:49:59 -080054 GrResourceCache* fCache;
bsalomon71cb0c22014-11-14 12:10:14 -080055};
56
57 //////////////////////////////////////////////////////////////////////////////
58
bsalomon71cb0c22014-11-14 12:10:14 -080059
robertphillips63926682015-08-20 09:39:02 -070060GrResourceCache::GrResourceCache(const GrCaps* caps)
bsalomon9f2d1572015-02-17 11:47:40 -080061 : fTimestamp(0)
62 , fMaxCount(kDefaultMaxCount)
bsalomon71cb0c22014-11-14 12:10:14 -080063 , fMaxBytes(kDefaultMaxSize)
bsalomon3f324322015-04-08 11:01:54 -070064 , fMaxUnusedFlushes(kDefaultMaxUnusedFlushes)
bsalomon71cb0c22014-11-14 12:10:14 -080065#if GR_CACHE_STATS
66 , fHighWaterCount(0)
67 , fHighWaterBytes(0)
bsalomondace19e2014-11-17 07:34:06 -080068 , fBudgetedHighWaterCount(0)
69 , fBudgetedHighWaterBytes(0)
bsalomon71cb0c22014-11-14 12:10:14 -080070#endif
bsalomon71cb0c22014-11-14 12:10:14 -080071 , fBytes(0)
bsalomondace19e2014-11-17 07:34:06 -080072 , fBudgetedCount(0)
73 , fBudgetedBytes(0)
halcanary96fcdcc2015-08-27 07:41:13 -070074 , fOverBudgetCB(nullptr)
75 , fOverBudgetData(nullptr)
76 , fFlushTimestamps(nullptr)
robertphillips63926682015-08-20 09:39:02 -070077 , fLastFlushTimestampIndex(0)
78 , fPreferVRAMUseOverFlushes(caps->preferVRAMUseOverFlushes()) {
bsalomonf320e042015-02-17 15:09:34 -080079 SkDEBUGCODE(fCount = 0;)
halcanary96fcdcc2015-08-27 07:41:13 -070080 SkDEBUGCODE(fNewlyPurgeableResourceForValidation = nullptr;)
bsalomon3f324322015-04-08 11:01:54 -070081 this->resetFlushTimestamps();
bsalomon71cb0c22014-11-14 12:10:14 -080082}
83
bsalomon0ea80f42015-02-11 10:49:59 -080084GrResourceCache::~GrResourceCache() {
bsalomonc8dc1f72014-08-21 13:02:13 -070085 this->releaseAll();
halcanary385fe4d2015-08-26 13:07:48 -070086 delete[] fFlushTimestamps;
bsalomonc8dc1f72014-08-21 13:02:13 -070087}
88
bsalomon3f324322015-04-08 11:01:54 -070089void GrResourceCache::setLimits(int count, size_t bytes, int maxUnusedFlushes) {
bsalomon71cb0c22014-11-14 12:10:14 -080090 fMaxCount = count;
91 fMaxBytes = bytes;
bsalomon3f324322015-04-08 11:01:54 -070092 fMaxUnusedFlushes = maxUnusedFlushes;
93 this->resetFlushTimestamps();
bsalomon71cb0c22014-11-14 12:10:14 -080094 this->purgeAsNeeded();
95}
96
bsalomon3f324322015-04-08 11:01:54 -070097void GrResourceCache::resetFlushTimestamps() {
halcanary385fe4d2015-08-26 13:07:48 -070098 delete[] fFlushTimestamps;
bsalomon3f324322015-04-08 11:01:54 -070099
100 // We assume this number is a power of two when wrapping indices into the timestamp array.
101 fMaxUnusedFlushes = SkNextPow2(fMaxUnusedFlushes);
102
103 // Since our implementation is to store the timestamps of the last fMaxUnusedFlushes flush calls
104 // we just turn the feature off if that array would be large.
105 static const int kMaxSupportedTimestampHistory = 128;
106
107 if (fMaxUnusedFlushes > kMaxSupportedTimestampHistory) {
halcanary96fcdcc2015-08-27 07:41:13 -0700108 fFlushTimestamps = nullptr;
bsalomon3f324322015-04-08 11:01:54 -0700109 return;
110 }
111
halcanary385fe4d2015-08-26 13:07:48 -0700112 fFlushTimestamps = new uint32_t[fMaxUnusedFlushes];
bsalomon3f324322015-04-08 11:01:54 -0700113 fLastFlushTimestampIndex = 0;
114 // Set all the historical flush timestamps to initially be at the beginning of time (timestamp
115 // 0).
116 sk_bzero(fFlushTimestamps, fMaxUnusedFlushes * sizeof(uint32_t));
117}
118
bsalomon0ea80f42015-02-11 10:49:59 -0800119void GrResourceCache::insertResource(GrGpuResource* resource) {
bsalomon49f085d2014-09-05 13:34:00 -0700120 SkASSERT(resource);
bsalomon16961262014-08-26 14:01:07 -0700121 SkASSERT(!this->isInCache(resource));
bsalomonf320e042015-02-17 15:09:34 -0800122 SkASSERT(!resource->wasDestroyed());
123 SkASSERT(!resource->isPurgeable());
bsalomonddf30e62015-02-19 11:38:44 -0800124
125 // We must set the timestamp before adding to the array in case the timestamp wraps and we wind
126 // up iterating over all the resources that already have timestamps.
127 resource->cacheAccess().setTimestamp(this->getNextTimestamp());
128
bsalomonf320e042015-02-17 15:09:34 -0800129 this->addToNonpurgeableArray(resource);
bsalomon71cb0c22014-11-14 12:10:14 -0800130
bsalomondace19e2014-11-17 07:34:06 -0800131 size_t size = resource->gpuMemorySize();
bsalomonf320e042015-02-17 15:09:34 -0800132 SkDEBUGCODE(++fCount;)
bsalomon84c8e622014-11-17 09:33:27 -0800133 fBytes += size;
bsalomon82b1d622014-11-14 13:59:57 -0800134#if GR_CACHE_STATS
bsalomonf320e042015-02-17 15:09:34 -0800135 fHighWaterCount = SkTMax(this->getResourceCount(), fHighWaterCount);
bsalomon82b1d622014-11-14 13:59:57 -0800136 fHighWaterBytes = SkTMax(fBytes, fHighWaterBytes);
137#endif
bsalomon5ec26ae2016-02-25 08:33:02 -0800138 if (SkBudgeted::kYes == resource->resourcePriv().isBudgeted()) {
bsalomondace19e2014-11-17 07:34:06 -0800139 ++fBudgetedCount;
140 fBudgetedBytes += size;
hendrikw876c3132015-03-04 10:33:49 -0800141 TRACE_COUNTER2(TRACE_DISABLED_BY_DEFAULT("skia.gpu.cache"), "skia budget", "used",
142 fBudgetedBytes, "free", fMaxBytes - fBudgetedBytes);
bsalomondace19e2014-11-17 07:34:06 -0800143#if GR_CACHE_STATS
144 fBudgetedHighWaterCount = SkTMax(fBudgetedCount, fBudgetedHighWaterCount);
145 fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes);
146#endif
147 }
bsalomon3582d3e2015-02-13 14:20:05 -0800148 if (resource->resourcePriv().getScratchKey().isValid()) {
kkinnunen2e6055b2016-04-22 01:48:29 -0700149 SkASSERT(!resource->resourcePriv().refsWrappedObjects());
bsalomon3582d3e2015-02-13 14:20:05 -0800150 fScratchMap.insert(resource->resourcePriv().getScratchKey(), resource);
bsalomon744998e2014-08-28 09:54:34 -0700151 }
bsalomon9f2d1572015-02-17 11:47:40 -0800152
bsalomon71cb0c22014-11-14 12:10:14 -0800153 this->purgeAsNeeded();
bsalomonc8dc1f72014-08-21 13:02:13 -0700154}
155
bsalomon0ea80f42015-02-11 10:49:59 -0800156void GrResourceCache::removeResource(GrGpuResource* resource) {
bsalomon9f2d1572015-02-17 11:47:40 -0800157 this->validate();
bsalomon16961262014-08-26 14:01:07 -0700158 SkASSERT(this->isInCache(resource));
bsalomondace19e2014-11-17 07:34:06 -0800159
bsalomon9f2d1572015-02-17 11:47:40 -0800160 if (resource->isPurgeable()) {
161 fPurgeableQueue.remove(resource);
bsalomonf320e042015-02-17 15:09:34 -0800162 } else {
163 this->removeFromNonpurgeableArray(resource);
bsalomon9f2d1572015-02-17 11:47:40 -0800164 }
165
bsalomondace19e2014-11-17 07:34:06 -0800166 size_t size = resource->gpuMemorySize();
bsalomonf320e042015-02-17 15:09:34 -0800167 SkDEBUGCODE(--fCount;)
bsalomondace19e2014-11-17 07:34:06 -0800168 fBytes -= size;
bsalomon5ec26ae2016-02-25 08:33:02 -0800169 if (SkBudgeted::kYes == resource->resourcePriv().isBudgeted()) {
bsalomondace19e2014-11-17 07:34:06 -0800170 --fBudgetedCount;
171 fBudgetedBytes -= size;
hendrikw876c3132015-03-04 10:33:49 -0800172 TRACE_COUNTER2(TRACE_DISABLED_BY_DEFAULT("skia.gpu.cache"), "skia budget", "used",
173 fBudgetedBytes, "free", fMaxBytes - fBudgetedBytes);
bsalomondace19e2014-11-17 07:34:06 -0800174 }
175
bsalomon3582d3e2015-02-13 14:20:05 -0800176 if (resource->resourcePriv().getScratchKey().isValid()) {
177 fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource);
bsalomon744998e2014-08-28 09:54:34 -0700178 }
bsalomon8718aaf2015-02-19 07:24:21 -0800179 if (resource->getUniqueKey().isValid()) {
180 fUniqueHash.remove(resource->getUniqueKey());
bsalomon8b79d232014-11-10 10:19:06 -0800181 }
bsalomonb436ed62014-11-17 12:15:56 -0800182 this->validate();
bsalomonc8dc1f72014-08-21 13:02:13 -0700183}
184
bsalomon0ea80f42015-02-11 10:49:59 -0800185void GrResourceCache::abandonAll() {
bsalomon71cb0c22014-11-14 12:10:14 -0800186 AutoValidate av(this);
187
bsalomonf320e042015-02-17 15:09:34 -0800188 while (fNonpurgeableResources.count()) {
189 GrGpuResource* back = *(fNonpurgeableResources.end() - 1);
190 SkASSERT(!back->wasDestroyed());
191 back->cacheAccess().abandon();
bsalomonc8dc1f72014-08-21 13:02:13 -0700192 }
bsalomonf320e042015-02-17 15:09:34 -0800193
194 while (fPurgeableQueue.count()) {
195 GrGpuResource* top = fPurgeableQueue.peek();
196 SkASSERT(!top->wasDestroyed());
197 top->cacheAccess().abandon();
198 }
199
bsalomon744998e2014-08-28 09:54:34 -0700200 SkASSERT(!fScratchMap.count());
bsalomon8718aaf2015-02-19 07:24:21 -0800201 SkASSERT(!fUniqueHash.count());
bsalomonc8dc1f72014-08-21 13:02:13 -0700202 SkASSERT(!fCount);
bsalomonf320e042015-02-17 15:09:34 -0800203 SkASSERT(!this->getResourceCount());
bsalomondace19e2014-11-17 07:34:06 -0800204 SkASSERT(!fBytes);
205 SkASSERT(!fBudgetedCount);
206 SkASSERT(!fBudgetedBytes);
bsalomonc8dc1f72014-08-21 13:02:13 -0700207}
208
bsalomon0ea80f42015-02-11 10:49:59 -0800209void GrResourceCache::releaseAll() {
bsalomon71cb0c22014-11-14 12:10:14 -0800210 AutoValidate av(this);
211
bsalomonf320e042015-02-17 15:09:34 -0800212 while(fNonpurgeableResources.count()) {
213 GrGpuResource* back = *(fNonpurgeableResources.end() - 1);
214 SkASSERT(!back->wasDestroyed());
215 back->cacheAccess().release();
bsalomonc8dc1f72014-08-21 13:02:13 -0700216 }
bsalomonf320e042015-02-17 15:09:34 -0800217
218 while (fPurgeableQueue.count()) {
219 GrGpuResource* top = fPurgeableQueue.peek();
220 SkASSERT(!top->wasDestroyed());
221 top->cacheAccess().release();
222 }
223
bsalomon744998e2014-08-28 09:54:34 -0700224 SkASSERT(!fScratchMap.count());
bsalomon8718aaf2015-02-19 07:24:21 -0800225 SkASSERT(!fUniqueHash.count());
bsalomonc8dc1f72014-08-21 13:02:13 -0700226 SkASSERT(!fCount);
bsalomonf320e042015-02-17 15:09:34 -0800227 SkASSERT(!this->getResourceCount());
bsalomondace19e2014-11-17 07:34:06 -0800228 SkASSERT(!fBytes);
229 SkASSERT(!fBudgetedCount);
230 SkASSERT(!fBudgetedBytes);
bsalomonc8dc1f72014-08-21 13:02:13 -0700231}
bsalomonbcf0a522014-10-08 08:40:09 -0700232
bsalomon0ea80f42015-02-11 10:49:59 -0800233class GrResourceCache::AvailableForScratchUse {
bsalomonbcf0a522014-10-08 08:40:09 -0700234public:
bsalomon000f8292014-10-15 19:04:14 -0700235 AvailableForScratchUse(bool rejectPendingIO) : fRejectPendingIO(rejectPendingIO) { }
bsalomonbcf0a522014-10-08 08:40:09 -0700236
237 bool operator()(const GrGpuResource* resource) const {
bsalomon12299ab2014-11-14 13:33:09 -0800238 if (resource->internalHasRef() || !resource->cacheAccess().isScratch()) {
bsalomon000f8292014-10-15 19:04:14 -0700239 return false;
bsalomonbcf0a522014-10-08 08:40:09 -0700240 }
bsalomon000f8292014-10-15 19:04:14 -0700241 return !fRejectPendingIO || !resource->internalHasPendingIO();
bsalomonbcf0a522014-10-08 08:40:09 -0700242 }
bsalomon1e2530b2014-10-09 09:57:18 -0700243
bsalomonbcf0a522014-10-08 08:40:09 -0700244private:
bsalomon000f8292014-10-15 19:04:14 -0700245 bool fRejectPendingIO;
bsalomonbcf0a522014-10-08 08:40:09 -0700246};
247
bsalomon0ea80f42015-02-11 10:49:59 -0800248GrGpuResource* GrResourceCache::findAndRefScratchResource(const GrScratchKey& scratchKey,
robertphillips6e83ac72015-08-13 05:19:14 -0700249 size_t resourceSize,
bsalomon9f2d1572015-02-17 11:47:40 -0800250 uint32_t flags) {
bsalomon7775c852014-12-30 12:50:52 -0800251 SkASSERT(scratchKey.isValid());
bsalomon000f8292014-10-15 19:04:14 -0700252
bsalomon71cb0c22014-11-14 12:10:14 -0800253 GrGpuResource* resource;
bsalomon000f8292014-10-15 19:04:14 -0700254 if (flags & (kPreferNoPendingIO_ScratchFlag | kRequireNoPendingIO_ScratchFlag)) {
bsalomon71cb0c22014-11-14 12:10:14 -0800255 resource = fScratchMap.find(scratchKey, AvailableForScratchUse(true));
bsalomon000f8292014-10-15 19:04:14 -0700256 if (resource) {
bsalomon9f2d1572015-02-17 11:47:40 -0800257 this->refAndMakeResourceMRU(resource);
bsalomonb436ed62014-11-17 12:15:56 -0800258 this->validate();
259 return resource;
bsalomon000f8292014-10-15 19:04:14 -0700260 } else if (flags & kRequireNoPendingIO_ScratchFlag) {
halcanary96fcdcc2015-08-27 07:41:13 -0700261 return nullptr;
bsalomon000f8292014-10-15 19:04:14 -0700262 }
robertphillips63926682015-08-20 09:39:02 -0700263 // We would prefer to consume more available VRAM rather than flushing
264 // immediately, but on ANGLE this can lead to starving of the GPU.
265 if (fPreferVRAMUseOverFlushes && this->wouldFit(resourceSize)) {
robertphillips6e83ac72015-08-13 05:19:14 -0700266 // kPrefer is specified, we didn't find a resource without pending io,
robertphillips63926682015-08-20 09:39:02 -0700267 // but there is still space in our budget for the resource so force
268 // the caller to allocate a new resource.
halcanary96fcdcc2015-08-27 07:41:13 -0700269 return nullptr;
robertphillips6e83ac72015-08-13 05:19:14 -0700270 }
bsalomon000f8292014-10-15 19:04:14 -0700271 }
bsalomon71cb0c22014-11-14 12:10:14 -0800272 resource = fScratchMap.find(scratchKey, AvailableForScratchUse(false));
273 if (resource) {
bsalomon9f2d1572015-02-17 11:47:40 -0800274 this->refAndMakeResourceMRU(resource);
bsalomonb436ed62014-11-17 12:15:56 -0800275 this->validate();
bsalomon71cb0c22014-11-14 12:10:14 -0800276 }
277 return resource;
bsalomonbcf0a522014-10-08 08:40:09 -0700278}
bsalomon8b79d232014-11-10 10:19:06 -0800279
bsalomon0ea80f42015-02-11 10:49:59 -0800280void GrResourceCache::willRemoveScratchKey(const GrGpuResource* resource) {
bsalomon3582d3e2015-02-13 14:20:05 -0800281 SkASSERT(resource->resourcePriv().getScratchKey().isValid());
282 fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource);
bsalomon10e23ca2014-11-25 05:52:06 -0800283}
284
bsalomonf99e9612015-02-19 08:24:16 -0800285void GrResourceCache::removeUniqueKey(GrGpuResource* resource) {
bsalomon3f324322015-04-08 11:01:54 -0700286 // Someone has a ref to this resource in order to have removed the key. When the ref count
287 // reaches zero we will get a ref cnt notification and figure out what to do with it.
bsalomonf99e9612015-02-19 08:24:16 -0800288 if (resource->getUniqueKey().isValid()) {
289 SkASSERT(resource == fUniqueHash.find(resource->getUniqueKey()));
290 fUniqueHash.remove(resource->getUniqueKey());
291 }
292 resource->cacheAccess().removeUniqueKey();
293 this->validate();
bsalomon23e619c2015-02-06 11:54:28 -0800294}
295
bsalomonf99e9612015-02-19 08:24:16 -0800296void GrResourceCache::changeUniqueKey(GrGpuResource* resource, const GrUniqueKey& newKey) {
bsalomon8b79d232014-11-10 10:19:06 -0800297 SkASSERT(resource);
bsalomon71cb0c22014-11-14 12:10:14 -0800298 SkASSERT(this->isInCache(resource));
bsalomon8b79d232014-11-10 10:19:06 -0800299
bsalomonf99e9612015-02-19 08:24:16 -0800300 // Remove the entry for this resource if it already has a unique key.
301 if (resource->getUniqueKey().isValid()) {
302 SkASSERT(resource == fUniqueHash.find(resource->getUniqueKey()));
303 fUniqueHash.remove(resource->getUniqueKey());
halcanary96fcdcc2015-08-27 07:41:13 -0700304 SkASSERT(nullptr == fUniqueHash.find(resource->getUniqueKey()));
bsalomon8b79d232014-11-10 10:19:06 -0800305 }
306
bsalomonf99e9612015-02-19 08:24:16 -0800307 // If another resource has the new key, remove its key then install the key on this resource.
308 if (newKey.isValid()) {
309 if (GrGpuResource* old = fUniqueHash.find(newKey)) {
310 // If the old resource using the key is purgeable and is unreachable, then remove it.
311 if (!old->resourcePriv().getScratchKey().isValid() && old->isPurgeable()) {
312 // release may call validate() which will assert that resource is in fUniqueHash
313 // if it has a valid key. So in debug reset the key here before we assign it.
314 SkDEBUGCODE(resource->cacheAccess().removeUniqueKey();)
315 old->cacheAccess().release();
316 } else {
317 fUniqueHash.remove(newKey);
318 old->cacheAccess().removeUniqueKey();
319 }
320 }
halcanary96fcdcc2015-08-27 07:41:13 -0700321 SkASSERT(nullptr == fUniqueHash.find(newKey));
bsalomonf99e9612015-02-19 08:24:16 -0800322 resource->cacheAccess().setUniqueKey(newKey);
323 fUniqueHash.add(resource);
324 } else {
325 resource->cacheAccess().removeUniqueKey();
326 }
327
bsalomon71cb0c22014-11-14 12:10:14 -0800328 this->validate();
bsalomon8b79d232014-11-10 10:19:06 -0800329}
bsalomon71cb0c22014-11-14 12:10:14 -0800330
bsalomon9f2d1572015-02-17 11:47:40 -0800331void GrResourceCache::refAndMakeResourceMRU(GrGpuResource* resource) {
bsalomon71cb0c22014-11-14 12:10:14 -0800332 SkASSERT(resource);
333 SkASSERT(this->isInCache(resource));
bsalomonddf30e62015-02-19 11:38:44 -0800334
bsalomon9f2d1572015-02-17 11:47:40 -0800335 if (resource->isPurgeable()) {
336 // It's about to become unpurgeable.
337 fPurgeableQueue.remove(resource);
bsalomonf320e042015-02-17 15:09:34 -0800338 this->addToNonpurgeableArray(resource);
bsalomon9f2d1572015-02-17 11:47:40 -0800339 }
340 resource->ref();
bsalomonddf30e62015-02-19 11:38:44 -0800341
342 resource->cacheAccess().setTimestamp(this->getNextTimestamp());
bsalomonf320e042015-02-17 15:09:34 -0800343 this->validate();
bsalomon71cb0c22014-11-14 12:10:14 -0800344}
345
bsalomon3f324322015-04-08 11:01:54 -0700346void GrResourceCache::notifyCntReachedZero(GrGpuResource* resource, uint32_t flags) {
bsalomon71cb0c22014-11-14 12:10:14 -0800347 SkASSERT(resource);
bsalomon3f324322015-04-08 11:01:54 -0700348 SkASSERT(!resource->wasDestroyed());
349 SkASSERT(flags);
bsalomon71cb0c22014-11-14 12:10:14 -0800350 SkASSERT(this->isInCache(resource));
bsalomon3f324322015-04-08 11:01:54 -0700351 // This resource should always be in the nonpurgeable array when this function is called. It
352 // will be moved to the queue if it is newly purgeable.
353 SkASSERT(fNonpurgeableResources[*resource->cacheAccess().accessCacheIndex()] == resource);
bsalomon71cb0c22014-11-14 12:10:14 -0800354
bsalomon3f324322015-04-08 11:01:54 -0700355 if (SkToBool(ResourceAccess::kRefCntReachedZero_RefNotificationFlag & flags)) {
356#ifdef SK_DEBUG
357 // When the timestamp overflows validate() is called. validate() checks that resources in
358 // the nonpurgeable array are indeed not purgeable. However, the movement from the array to
359 // the purgeable queue happens just below in this function. So we mark it as an exception.
360 if (resource->isPurgeable()) {
361 fNewlyPurgeableResourceForValidation = resource;
362 }
363#endif
364 resource->cacheAccess().setTimestamp(this->getNextTimestamp());
halcanary96fcdcc2015-08-27 07:41:13 -0700365 SkDEBUGCODE(fNewlyPurgeableResourceForValidation = nullptr);
bsalomon3f324322015-04-08 11:01:54 -0700366 }
367
368 if (!SkToBool(ResourceAccess::kAllCntsReachedZero_RefNotificationFlag & flags)) {
369 SkASSERT(!resource->isPurgeable());
370 return;
371 }
372
373 SkASSERT(resource->isPurgeable());
bsalomonf320e042015-02-17 15:09:34 -0800374 this->removeFromNonpurgeableArray(resource);
bsalomon9f2d1572015-02-17 11:47:40 -0800375 fPurgeableQueue.insert(resource);
bsalomon71cb0c22014-11-14 12:10:14 -0800376
bsalomon5ec26ae2016-02-25 08:33:02 -0800377 if (SkBudgeted::kNo == resource->resourcePriv().isBudgeted()) {
bsalomonc2f35b72015-01-23 07:19:22 -0800378 // Check whether this resource could still be used as a scratch resource.
kkinnunen2e6055b2016-04-22 01:48:29 -0700379 if (!resource->resourcePriv().refsWrappedObjects() &&
bsalomon9f2d1572015-02-17 11:47:40 -0800380 resource->resourcePriv().getScratchKey().isValid()) {
bsalomonc2f35b72015-01-23 07:19:22 -0800381 // We won't purge an existing resource to make room for this one.
bsalomonf320e042015-02-17 15:09:34 -0800382 if (fBudgetedCount < fMaxCount &&
383 fBudgetedBytes + resource->gpuMemorySize() <= fMaxBytes) {
bsalomon3582d3e2015-02-13 14:20:05 -0800384 resource->resourcePriv().makeBudgeted();
bsalomon9f2d1572015-02-17 11:47:40 -0800385 return;
bsalomonc2f35b72015-01-23 07:19:22 -0800386 }
bsalomonc2f35b72015-01-23 07:19:22 -0800387 }
388 } else {
bsalomon9f2d1572015-02-17 11:47:40 -0800389 // Purge the resource immediately if we're over budget
bsalomon8718aaf2015-02-19 07:24:21 -0800390 // Also purge if the resource has neither a valid scratch key nor a unique key.
bsalomon3582d3e2015-02-13 14:20:05 -0800391 bool noKey = !resource->resourcePriv().getScratchKey().isValid() &&
bsalomon8718aaf2015-02-19 07:24:21 -0800392 !resource->getUniqueKey().isValid();
bsalomonf320e042015-02-17 15:09:34 -0800393 if (!this->overBudget() && !noKey) {
bsalomon9f2d1572015-02-17 11:47:40 -0800394 return;
bsalomonc2f35b72015-01-23 07:19:22 -0800395 }
396 }
bsalomondace19e2014-11-17 07:34:06 -0800397
bsalomonf320e042015-02-17 15:09:34 -0800398 SkDEBUGCODE(int beforeCount = this->getResourceCount();)
bsalomon9f2d1572015-02-17 11:47:40 -0800399 resource->cacheAccess().release();
400 // We should at least free this resource, perhaps dependent resources as well.
bsalomonf320e042015-02-17 15:09:34 -0800401 SkASSERT(this->getResourceCount() < beforeCount);
bsalomon71cb0c22014-11-14 12:10:14 -0800402 this->validate();
403}
404
bsalomon0ea80f42015-02-11 10:49:59 -0800405void GrResourceCache::didChangeGpuMemorySize(const GrGpuResource* resource, size_t oldSize) {
bsalomon71cb0c22014-11-14 12:10:14 -0800406 // SkASSERT(!fPurging); GrPathRange increases size during flush. :(
407 SkASSERT(resource);
408 SkASSERT(this->isInCache(resource));
409
bsalomondace19e2014-11-17 07:34:06 -0800410 ptrdiff_t delta = resource->gpuMemorySize() - oldSize;
411
412 fBytes += delta;
bsalomon82b1d622014-11-14 13:59:57 -0800413#if GR_CACHE_STATS
414 fHighWaterBytes = SkTMax(fBytes, fHighWaterBytes);
415#endif
bsalomon5ec26ae2016-02-25 08:33:02 -0800416 if (SkBudgeted::kYes == resource->resourcePriv().isBudgeted()) {
bsalomondace19e2014-11-17 07:34:06 -0800417 fBudgetedBytes += delta;
hendrikw876c3132015-03-04 10:33:49 -0800418 TRACE_COUNTER2(TRACE_DISABLED_BY_DEFAULT("skia.gpu.cache"), "skia budget", "used",
419 fBudgetedBytes, "free", fMaxBytes - fBudgetedBytes);
bsalomondace19e2014-11-17 07:34:06 -0800420#if GR_CACHE_STATS
421 fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes);
422#endif
423 }
bsalomon71cb0c22014-11-14 12:10:14 -0800424
425 this->purgeAsNeeded();
426 this->validate();
427}
428
bsalomon0ea80f42015-02-11 10:49:59 -0800429void GrResourceCache::didChangeBudgetStatus(GrGpuResource* resource) {
bsalomon84c8e622014-11-17 09:33:27 -0800430 SkASSERT(resource);
431 SkASSERT(this->isInCache(resource));
432
433 size_t size = resource->gpuMemorySize();
434
bsalomon5ec26ae2016-02-25 08:33:02 -0800435 if (SkBudgeted::kYes == resource->resourcePriv().isBudgeted()) {
bsalomon84c8e622014-11-17 09:33:27 -0800436 ++fBudgetedCount;
437 fBudgetedBytes += size;
bsalomonafe30052015-01-16 07:32:33 -0800438#if GR_CACHE_STATS
439 fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes);
440 fBudgetedHighWaterCount = SkTMax(fBudgetedCount, fBudgetedHighWaterCount);
441#endif
bsalomon84c8e622014-11-17 09:33:27 -0800442 this->purgeAsNeeded();
443 } else {
444 --fBudgetedCount;
445 fBudgetedBytes -= size;
446 }
hendrikw876c3132015-03-04 10:33:49 -0800447 TRACE_COUNTER2(TRACE_DISABLED_BY_DEFAULT("skia.gpu.cache"), "skia budget", "used",
448 fBudgetedBytes, "free", fMaxBytes - fBudgetedBytes);
bsalomon84c8e622014-11-17 09:33:27 -0800449
450 this->validate();
451}
452
bsalomon3f324322015-04-08 11:01:54 -0700453void GrResourceCache::purgeAsNeeded() {
454 SkTArray<GrUniqueKeyInvalidatedMessage> invalidKeyMsgs;
455 fInvalidUniqueKeyInbox.poll(&invalidKeyMsgs);
456 if (invalidKeyMsgs.count()) {
457 this->processInvalidUniqueKeys(invalidKeyMsgs);
458 }
bsalomon71cb0c22014-11-14 12:10:14 -0800459
bsalomon3f324322015-04-08 11:01:54 -0700460 if (fFlushTimestamps) {
461 // Assuming kNumFlushesToDeleteUnusedResource is a power of 2.
462 SkASSERT(SkIsPow2(fMaxUnusedFlushes));
463 int oldestFlushIndex = (fLastFlushTimestampIndex + 1) & (fMaxUnusedFlushes - 1);
464
465 uint32_t oldestAllowedTimestamp = fFlushTimestamps[oldestFlushIndex];
466 while (fPurgeableQueue.count()) {
467 uint32_t oldestResourceTimestamp = fPurgeableQueue.peek()->cacheAccess().timestamp();
468 if (oldestAllowedTimestamp < oldestResourceTimestamp) {
469 break;
470 }
471 GrGpuResource* resource = fPurgeableQueue.peek();
472 SkASSERT(resource->isPurgeable());
473 resource->cacheAccess().release();
474 }
475 }
476
477 bool stillOverbudget = this->overBudget();
478 while (stillOverbudget && fPurgeableQueue.count()) {
bsalomon9f2d1572015-02-17 11:47:40 -0800479 GrGpuResource* resource = fPurgeableQueue.peek();
480 SkASSERT(resource->isPurgeable());
481 resource->cacheAccess().release();
bsalomon3f324322015-04-08 11:01:54 -0700482 stillOverbudget = this->overBudget();
bsalomon9f2d1572015-02-17 11:47:40 -0800483 }
bsalomon71cb0c22014-11-14 12:10:14 -0800484
bsalomonb436ed62014-11-17 12:15:56 -0800485 this->validate();
bsalomon9f2d1572015-02-17 11:47:40 -0800486
487 if (stillOverbudget) {
488 // Despite the purge we're still over budget. Call our over budget callback. If this frees
bsalomon3f324322015-04-08 11:01:54 -0700489 // any resources then we'll get notified and take appropriate action.
bsalomon9f2d1572015-02-17 11:47:40 -0800490 (*fOverBudgetCB)(fOverBudgetData);
491 this->validate();
492 }
bsalomon71cb0c22014-11-14 12:10:14 -0800493}
494
bsalomon0ea80f42015-02-11 10:49:59 -0800495void GrResourceCache::purgeAllUnlocked() {
bsalomon9f2d1572015-02-17 11:47:40 -0800496 // We could disable maintaining the heap property here, but it would add a lot of complexity.
497 // Moreover, this is rarely called.
498 while (fPurgeableQueue.count()) {
499 GrGpuResource* resource = fPurgeableQueue.peek();
500 SkASSERT(resource->isPurgeable());
501 resource->cacheAccess().release();
502 }
bsalomon71cb0c22014-11-14 12:10:14 -0800503
bsalomonb436ed62014-11-17 12:15:56 -0800504 this->validate();
bsalomon71cb0c22014-11-14 12:10:14 -0800505}
506
bsalomon8718aaf2015-02-19 07:24:21 -0800507void GrResourceCache::processInvalidUniqueKeys(
508 const SkTArray<GrUniqueKeyInvalidatedMessage>& msgs) {
bsalomon23e619c2015-02-06 11:54:28 -0800509 for (int i = 0; i < msgs.count(); ++i) {
bsalomon8718aaf2015-02-19 07:24:21 -0800510 GrGpuResource* resource = this->findAndRefUniqueResource(msgs[i].key());
bsalomon23e619c2015-02-06 11:54:28 -0800511 if (resource) {
bsalomon8718aaf2015-02-19 07:24:21 -0800512 resource->resourcePriv().removeUniqueKey();
bsalomon3f324322015-04-08 11:01:54 -0700513 resource->unref(); // If this resource is now purgeable, the cache will be notified.
bsalomon23e619c2015-02-06 11:54:28 -0800514 }
515 }
516}
517
bsalomonf320e042015-02-17 15:09:34 -0800518void GrResourceCache::addToNonpurgeableArray(GrGpuResource* resource) {
519 int index = fNonpurgeableResources.count();
520 *fNonpurgeableResources.append() = resource;
521 *resource->cacheAccess().accessCacheIndex() = index;
522}
523
524void GrResourceCache::removeFromNonpurgeableArray(GrGpuResource* resource) {
525 int* index = resource->cacheAccess().accessCacheIndex();
526 // Fill the whole we will create in the array with the tail object, adjust its index, and
527 // then pop the array
528 GrGpuResource* tail = *(fNonpurgeableResources.end() - 1);
529 SkASSERT(fNonpurgeableResources[*index] == resource);
530 fNonpurgeableResources[*index] = tail;
531 *tail->cacheAccess().accessCacheIndex() = *index;
532 fNonpurgeableResources.pop();
533 SkDEBUGCODE(*index = -1);
534}
535
bsalomonddf30e62015-02-19 11:38:44 -0800536uint32_t GrResourceCache::getNextTimestamp() {
537 // If we wrap then all the existing resources will appear older than any resources that get
538 // a timestamp after the wrap.
539 if (0 == fTimestamp) {
540 int count = this->getResourceCount();
541 if (count) {
542 // Reset all the timestamps. We sort the resources by timestamp and then assign
543 // sequential timestamps beginning with 0. This is O(n*lg(n)) but it should be extremely
544 // rare.
545 SkTDArray<GrGpuResource*> sortedPurgeableResources;
546 sortedPurgeableResources.setReserve(fPurgeableQueue.count());
547
548 while (fPurgeableQueue.count()) {
549 *sortedPurgeableResources.append() = fPurgeableQueue.peek();
550 fPurgeableQueue.pop();
551 }
552
553 struct Less {
554 bool operator()(GrGpuResource* a, GrGpuResource* b) {
555 return CompareTimestamp(a,b);
556 }
557 };
558 Less less;
559 SkTQSort(fNonpurgeableResources.begin(), fNonpurgeableResources.end() - 1, less);
560
561 // Pick resources out of the purgeable and non-purgeable arrays based on lowest
562 // timestamp and assign new timestamps.
563 int currP = 0;
564 int currNP = 0;
565 while (currP < sortedPurgeableResources.count() &&
mtklein56da0252015-11-16 11:16:23 -0800566 currNP < fNonpurgeableResources.count()) {
bsalomonddf30e62015-02-19 11:38:44 -0800567 uint32_t tsP = sortedPurgeableResources[currP]->cacheAccess().timestamp();
568 uint32_t tsNP = fNonpurgeableResources[currNP]->cacheAccess().timestamp();
569 SkASSERT(tsP != tsNP);
570 if (tsP < tsNP) {
571 sortedPurgeableResources[currP++]->cacheAccess().setTimestamp(fTimestamp++);
572 } else {
573 // Correct the index in the nonpurgeable array stored on the resource post-sort.
574 *fNonpurgeableResources[currNP]->cacheAccess().accessCacheIndex() = currNP;
575 fNonpurgeableResources[currNP++]->cacheAccess().setTimestamp(fTimestamp++);
576 }
577 }
578
579 // The above loop ended when we hit the end of one array. Finish the other one.
580 while (currP < sortedPurgeableResources.count()) {
581 sortedPurgeableResources[currP++]->cacheAccess().setTimestamp(fTimestamp++);
582 }
583 while (currNP < fNonpurgeableResources.count()) {
584 *fNonpurgeableResources[currNP]->cacheAccess().accessCacheIndex() = currNP;
585 fNonpurgeableResources[currNP++]->cacheAccess().setTimestamp(fTimestamp++);
586 }
587
588 // Rebuild the queue.
589 for (int i = 0; i < sortedPurgeableResources.count(); ++i) {
590 fPurgeableQueue.insert(sortedPurgeableResources[i]);
591 }
592
593 this->validate();
594 SkASSERT(count == this->getResourceCount());
595
596 // count should be the next timestamp we return.
597 SkASSERT(fTimestamp == SkToU32(count));
mtklein56da0252015-11-16 11:16:23 -0800598
bsalomon3f324322015-04-08 11:01:54 -0700599 // The historical timestamps of flushes are now invalid.
600 this->resetFlushTimestamps();
mtklein56da0252015-11-16 11:16:23 -0800601 }
bsalomonddf30e62015-02-19 11:38:44 -0800602 }
603 return fTimestamp++;
604}
605
bsalomon3f324322015-04-08 11:01:54 -0700606void GrResourceCache::notifyFlushOccurred() {
607 if (fFlushTimestamps) {
608 SkASSERT(SkIsPow2(fMaxUnusedFlushes));
609 fLastFlushTimestampIndex = (fLastFlushTimestampIndex + 1) & (fMaxUnusedFlushes - 1);
610 // get the timestamp before accessing fFlushTimestamps because getNextTimestamp will
611 // reallocate fFlushTimestamps on timestamp overflow.
612 uint32_t timestamp = this->getNextTimestamp();
613 fFlushTimestamps[fLastFlushTimestampIndex] = timestamp;
614 this->purgeAsNeeded();
615 }
616}
617
ericrk0a5fa482015-09-15 14:16:10 -0700618void GrResourceCache::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
619 for (int i = 0; i < fNonpurgeableResources.count(); ++i) {
620 fNonpurgeableResources[i]->dumpMemoryStatistics(traceMemoryDump);
621 }
622 for (int i = 0; i < fPurgeableQueue.count(); ++i) {
623 fPurgeableQueue.at(i)->dumpMemoryStatistics(traceMemoryDump);
624 }
625}
626
bsalomon71cb0c22014-11-14 12:10:14 -0800627#ifdef SK_DEBUG
bsalomon0ea80f42015-02-11 10:49:59 -0800628void GrResourceCache::validate() const {
bsalomonc2f35b72015-01-23 07:19:22 -0800629 // Reduce the frequency of validations for large resource counts.
630 static SkRandom gRandom;
631 int mask = (SkNextPow2(fCount + 1) >> 5) - 1;
632 if (~mask && (gRandom.nextU() & mask)) {
633 return;
634 }
635
bsalomonf320e042015-02-17 15:09:34 -0800636 struct Stats {
637 size_t fBytes;
638 int fBudgetedCount;
639 size_t fBudgetedBytes;
640 int fLocked;
641 int fScratch;
642 int fCouldBeScratch;
643 int fContent;
644 const ScratchMap* fScratchMap;
bsalomon8718aaf2015-02-19 07:24:21 -0800645 const UniqueHash* fUniqueHash;
bsalomon71cb0c22014-11-14 12:10:14 -0800646
bsalomonf320e042015-02-17 15:09:34 -0800647 Stats(const GrResourceCache* cache) {
648 memset(this, 0, sizeof(*this));
649 fScratchMap = &cache->fScratchMap;
bsalomon8718aaf2015-02-19 07:24:21 -0800650 fUniqueHash = &cache->fUniqueHash;
bsalomon71cb0c22014-11-14 12:10:14 -0800651 }
652
bsalomonf320e042015-02-17 15:09:34 -0800653 void update(GrGpuResource* resource) {
654 fBytes += resource->gpuMemorySize();
bsalomondace19e2014-11-17 07:34:06 -0800655
bsalomonf320e042015-02-17 15:09:34 -0800656 if (!resource->isPurgeable()) {
657 ++fLocked;
658 }
bsalomon9f2d1572015-02-17 11:47:40 -0800659
bsalomonf320e042015-02-17 15:09:34 -0800660 if (resource->cacheAccess().isScratch()) {
bsalomon8718aaf2015-02-19 07:24:21 -0800661 SkASSERT(!resource->getUniqueKey().isValid());
bsalomonf320e042015-02-17 15:09:34 -0800662 ++fScratch;
663 SkASSERT(fScratchMap->countForKey(resource->resourcePriv().getScratchKey()));
kkinnunen2e6055b2016-04-22 01:48:29 -0700664 SkASSERT(!resource->resourcePriv().refsWrappedObjects());
bsalomonf320e042015-02-17 15:09:34 -0800665 } else if (resource->resourcePriv().getScratchKey().isValid()) {
bsalomon5ec26ae2016-02-25 08:33:02 -0800666 SkASSERT(SkBudgeted::kNo == resource->resourcePriv().isBudgeted() ||
bsalomon8718aaf2015-02-19 07:24:21 -0800667 resource->getUniqueKey().isValid());
bsalomonf320e042015-02-17 15:09:34 -0800668 ++fCouldBeScratch;
669 SkASSERT(fScratchMap->countForKey(resource->resourcePriv().getScratchKey()));
kkinnunen2e6055b2016-04-22 01:48:29 -0700670 SkASSERT(!resource->resourcePriv().refsWrappedObjects());
bsalomonf320e042015-02-17 15:09:34 -0800671 }
bsalomon8718aaf2015-02-19 07:24:21 -0800672 const GrUniqueKey& uniqueKey = resource->getUniqueKey();
673 if (uniqueKey.isValid()) {
bsalomonf320e042015-02-17 15:09:34 -0800674 ++fContent;
bsalomon8718aaf2015-02-19 07:24:21 -0800675 SkASSERT(fUniqueHash->find(uniqueKey) == resource);
kkinnunen2e6055b2016-04-22 01:48:29 -0700676 SkASSERT(!resource->resourcePriv().refsWrappedObjects());
bsalomon5ec26ae2016-02-25 08:33:02 -0800677 SkASSERT(SkBudgeted::kYes == resource->resourcePriv().isBudgeted());
bsalomonf320e042015-02-17 15:09:34 -0800678 }
679
bsalomon5ec26ae2016-02-25 08:33:02 -0800680 if (SkBudgeted::kYes == resource->resourcePriv().isBudgeted()) {
bsalomonf320e042015-02-17 15:09:34 -0800681 ++fBudgetedCount;
682 fBudgetedBytes += resource->gpuMemorySize();
683 }
bsalomon9f2d1572015-02-17 11:47:40 -0800684 }
bsalomonf320e042015-02-17 15:09:34 -0800685 };
686
687 Stats stats(this);
688
689 for (int i = 0; i < fNonpurgeableResources.count(); ++i) {
bsalomon3f324322015-04-08 11:01:54 -0700690 SkASSERT(!fNonpurgeableResources[i]->isPurgeable() ||
691 fNewlyPurgeableResourceForValidation == fNonpurgeableResources[i]);
bsalomonf320e042015-02-17 15:09:34 -0800692 SkASSERT(*fNonpurgeableResources[i]->cacheAccess().accessCacheIndex() == i);
693 SkASSERT(!fNonpurgeableResources[i]->wasDestroyed());
694 stats.update(fNonpurgeableResources[i]);
bsalomon71cb0c22014-11-14 12:10:14 -0800695 }
bsalomon9f2d1572015-02-17 11:47:40 -0800696 for (int i = 0; i < fPurgeableQueue.count(); ++i) {
697 SkASSERT(fPurgeableQueue.at(i)->isPurgeable());
bsalomonf320e042015-02-17 15:09:34 -0800698 SkASSERT(*fPurgeableQueue.at(i)->cacheAccess().accessCacheIndex() == i);
699 SkASSERT(!fPurgeableQueue.at(i)->wasDestroyed());
700 stats.update(fPurgeableQueue.at(i));
bsalomon9f2d1572015-02-17 11:47:40 -0800701 }
702
bsalomonf320e042015-02-17 15:09:34 -0800703 SkASSERT(fCount == this->getResourceCount());
bsalomondace19e2014-11-17 07:34:06 -0800704 SkASSERT(fBudgetedCount <= fCount);
bsalomonf320e042015-02-17 15:09:34 -0800705 SkASSERT(fBudgetedBytes <= fBytes);
706 SkASSERT(stats.fBytes == fBytes);
707 SkASSERT(stats.fBudgetedBytes == fBudgetedBytes);
708 SkASSERT(stats.fBudgetedCount == fBudgetedCount);
bsalomon71cb0c22014-11-14 12:10:14 -0800709#if GR_CACHE_STATS
bsalomondace19e2014-11-17 07:34:06 -0800710 SkASSERT(fBudgetedHighWaterCount <= fHighWaterCount);
711 SkASSERT(fBudgetedHighWaterBytes <= fHighWaterBytes);
bsalomonf320e042015-02-17 15:09:34 -0800712 SkASSERT(fBytes <= fHighWaterBytes);
713 SkASSERT(fCount <= fHighWaterCount);
714 SkASSERT(fBudgetedBytes <= fBudgetedHighWaterBytes);
715 SkASSERT(fBudgetedCount <= fBudgetedHighWaterCount);
bsalomon71cb0c22014-11-14 12:10:14 -0800716#endif
bsalomon8718aaf2015-02-19 07:24:21 -0800717 SkASSERT(stats.fContent == fUniqueHash.count());
bsalomonf320e042015-02-17 15:09:34 -0800718 SkASSERT(stats.fScratch + stats.fCouldBeScratch == fScratchMap.count());
bsalomon71cb0c22014-11-14 12:10:14 -0800719
bsalomon3f324322015-04-08 11:01:54 -0700720 // This assertion is not currently valid because we can be in recursive notifyCntReachedZero()
bsalomon12299ab2014-11-14 13:33:09 -0800721 // calls. This will be fixed when subresource registration is explicit.
bsalomondace19e2014-11-17 07:34:06 -0800722 // bool overBudget = budgetedBytes > fMaxBytes || budgetedCount > fMaxCount;
bsalomon12299ab2014-11-14 13:33:09 -0800723 // SkASSERT(!overBudget || locked == count || fPurging);
bsalomon71cb0c22014-11-14 12:10:14 -0800724}
bsalomonf320e042015-02-17 15:09:34 -0800725
726bool GrResourceCache::isInCache(const GrGpuResource* resource) const {
727 int index = *resource->cacheAccess().accessCacheIndex();
728 if (index < 0) {
729 return false;
730 }
731 if (index < fPurgeableQueue.count() && fPurgeableQueue.at(index) == resource) {
732 return true;
733 }
734 if (index < fNonpurgeableResources.count() && fNonpurgeableResources[index] == resource) {
735 return true;
736 }
737 SkDEBUGFAIL("Resource index should be -1 or the resource should be in the cache.");
738 return false;
739}
740
bsalomon71cb0c22014-11-14 12:10:14 -0800741#endif