blob: e6f59949b0a0895ea31bbdd5e984188aa6680270 [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
bsalomon0ea80f42015-02-11 10:49:59 -08008#include "GrResourceCache.h"
robertphillips28a838e2016-06-23 14:07:00 -07009
10#include "GrCaps.h"
bsalomon3582d3e2015-02-13 14:20:05 -080011#include "GrGpuResourceCacheAccess.h"
Robert Phillips1afd4cd2018-01-08 13:40:32 -050012#include "GrProxyProvider.h"
Robert Phillipsae7d3f32017-09-21 08:26:08 -040013#include "GrTexture.h"
14#include "GrTextureProxyCacheAccess.h"
hendrikw876c3132015-03-04 10:33:49 -080015#include "GrTracing.h"
bsalomon71cb0c22014-11-14 12:10:14 -080016#include "SkGr.h"
17#include "SkMessageBus.h"
mtklein4e976072016-08-08 09:06:27 -070018#include "SkOpts.h"
bsalomonddf30e62015-02-19 11:38:44 -080019#include "SkTSort.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040020#include "SkTo.h"
bsalomon71cb0c22014-11-14 12:10:14 -080021
bsalomon8718aaf2015-02-19 07:24:21 -080022DECLARE_SKMESSAGEBUS_MESSAGE(GrUniqueKeyInvalidatedMessage);
bsalomon71cb0c22014-11-14 12:10:14 -080023
Brian Osman13dddce2017-05-09 13:19:50 -040024DECLARE_SKMESSAGEBUS_MESSAGE(GrGpuResourceFreedMessage);
25
bsalomon71cb0c22014-11-14 12:10:14 -080026//////////////////////////////////////////////////////////////////////////////
27
bsalomon7775c852014-12-30 12:50:52 -080028GrScratchKey::ResourceType GrScratchKey::GenerateResourceType() {
bsalomon24db3b12015-01-23 04:24:04 -080029 static int32_t gType = INHERITED::kInvalidDomain + 1;
bsalomonfe369ee2014-11-10 11:59:06 -080030
bsalomon7775c852014-12-30 12:50:52 -080031 int32_t type = sk_atomic_inc(&gType);
Ben Wagner9bc36fd2018-06-15 14:23:36 -040032 if (type > SkTo<int32_t>(UINT16_MAX)) {
Ben Wagnerb4aab9a2017-08-16 10:53:04 -040033 SK_ABORT("Too many Resource Types");
bsalomon71cb0c22014-11-14 12:10:14 -080034 }
35
36 return static_cast<ResourceType>(type);
37}
38
bsalomon8718aaf2015-02-19 07:24:21 -080039GrUniqueKey::Domain GrUniqueKey::GenerateDomain() {
bsalomon24db3b12015-01-23 04:24:04 -080040 static int32_t gDomain = INHERITED::kInvalidDomain + 1;
bsalomon7775c852014-12-30 12:50:52 -080041
bsalomon24db3b12015-01-23 04:24:04 -080042 int32_t domain = sk_atomic_inc(&gDomain);
Ben Wagner397ee0e2018-06-15 15:13:26 -040043 if (domain > SkTo<int32_t>(UINT16_MAX)) {
Ben Wagnerb4aab9a2017-08-16 10:53:04 -040044 SK_ABORT("Too many GrUniqueKey Domains");
bsalomon7775c852014-12-30 12:50:52 -080045 }
bsalomon24db3b12015-01-23 04:24:04 -080046
47 return static_cast<Domain>(domain);
48}
bsalomon3f324322015-04-08 11:01:54 -070049
bsalomon24db3b12015-01-23 04:24:04 -080050uint32_t GrResourceKeyHash(const uint32_t* data, size_t size) {
mtklein4e976072016-08-08 09:06:27 -070051 return SkOpts::hash(data, size);
bsalomon7775c852014-12-30 12:50:52 -080052}
53
bsalomonfe369ee2014-11-10 11:59:06 -080054//////////////////////////////////////////////////////////////////////////////
55
bsalomon0ea80f42015-02-11 10:49:59 -080056class GrResourceCache::AutoValidate : ::SkNoncopyable {
bsalomon71cb0c22014-11-14 12:10:14 -080057public:
bsalomon0ea80f42015-02-11 10:49:59 -080058 AutoValidate(GrResourceCache* cache) : fCache(cache) { cache->validate(); }
bsalomon71cb0c22014-11-14 12:10:14 -080059 ~AutoValidate() { fCache->validate(); }
60private:
bsalomon0ea80f42015-02-11 10:49:59 -080061 GrResourceCache* fCache;
bsalomon71cb0c22014-11-14 12:10:14 -080062};
63
64 //////////////////////////////////////////////////////////////////////////////
robertphillipsee843b22016-10-04 05:30:20 -070065
Brian Osman13dddce2017-05-09 13:19:50 -040066GrResourceCache::GrResourceCache(const GrCaps* caps, uint32_t contextUniqueID)
Brian Salomon238069b2018-07-11 15:58:57 -040067 : fProxyProvider(nullptr)
68 , fTimestamp(0)
69 , fMaxCount(kDefaultMaxCount)
70 , fMaxBytes(kDefaultMaxSize)
bsalomon71cb0c22014-11-14 12:10:14 -080071#if GR_CACHE_STATS
Brian Salomon238069b2018-07-11 15:58:57 -040072 , fHighWaterCount(0)
73 , fHighWaterBytes(0)
74 , fBudgetedHighWaterCount(0)
75 , fBudgetedHighWaterBytes(0)
bsalomon71cb0c22014-11-14 12:10:14 -080076#endif
Brian Salomon238069b2018-07-11 15:58:57 -040077 , fBytes(0)
78 , fBudgetedCount(0)
79 , fBudgetedBytes(0)
80 , fPurgeableBytes(0)
Brian Salomon238069b2018-07-11 15:58:57 -040081 , fInvalidUniqueKeyInbox(contextUniqueID)
82 , fFreedGpuResourceInbox(contextUniqueID)
83 , fContextUniqueID(contextUniqueID)
84 , fPreferVRAMUseOverFlushes(caps->preferVRAMUseOverFlushes()) {
85 SkASSERT(contextUniqueID != SK_InvalidUniqueID);
bsalomonf320e042015-02-17 15:09:34 -080086 SkDEBUGCODE(fCount = 0;)
halcanary96fcdcc2015-08-27 07:41:13 -070087 SkDEBUGCODE(fNewlyPurgeableResourceForValidation = nullptr;)
bsalomon71cb0c22014-11-14 12:10:14 -080088}
89
bsalomon0ea80f42015-02-11 10:49:59 -080090GrResourceCache::~GrResourceCache() {
bsalomonc8dc1f72014-08-21 13:02:13 -070091 this->releaseAll();
92}
93
Brian Salomon43b882b2018-09-07 16:29:14 -040094void GrResourceCache::setLimits(int count, size_t bytes) {
bsalomon71cb0c22014-11-14 12:10:14 -080095 fMaxCount = count;
96 fMaxBytes = bytes;
97 this->purgeAsNeeded();
98}
99
bsalomon0ea80f42015-02-11 10:49:59 -0800100void GrResourceCache::insertResource(GrGpuResource* resource) {
bsalomon49f085d2014-09-05 13:34:00 -0700101 SkASSERT(resource);
bsalomon16961262014-08-26 14:01:07 -0700102 SkASSERT(!this->isInCache(resource));
bsalomonf320e042015-02-17 15:09:34 -0800103 SkASSERT(!resource->wasDestroyed());
104 SkASSERT(!resource->isPurgeable());
bsalomonddf30e62015-02-19 11:38:44 -0800105
106 // We must set the timestamp before adding to the array in case the timestamp wraps and we wind
107 // up iterating over all the resources that already have timestamps.
108 resource->cacheAccess().setTimestamp(this->getNextTimestamp());
109
bsalomonf320e042015-02-17 15:09:34 -0800110 this->addToNonpurgeableArray(resource);
bsalomon71cb0c22014-11-14 12:10:14 -0800111
bsalomondace19e2014-11-17 07:34:06 -0800112 size_t size = resource->gpuMemorySize();
bsalomonf320e042015-02-17 15:09:34 -0800113 SkDEBUGCODE(++fCount;)
bsalomon84c8e622014-11-17 09:33:27 -0800114 fBytes += size;
bsalomon82b1d622014-11-14 13:59:57 -0800115#if GR_CACHE_STATS
bsalomonf320e042015-02-17 15:09:34 -0800116 fHighWaterCount = SkTMax(this->getResourceCount(), fHighWaterCount);
bsalomon82b1d622014-11-14 13:59:57 -0800117 fHighWaterBytes = SkTMax(fBytes, fHighWaterBytes);
118#endif
bsalomon5ec26ae2016-02-25 08:33:02 -0800119 if (SkBudgeted::kYes == resource->resourcePriv().isBudgeted()) {
bsalomondace19e2014-11-17 07:34:06 -0800120 ++fBudgetedCount;
121 fBudgetedBytes += size;
Brian Osman39c08ac2017-07-26 09:36:09 -0400122 TRACE_COUNTER2("skia.gpu.cache", "skia budget", "used",
hendrikw876c3132015-03-04 10:33:49 -0800123 fBudgetedBytes, "free", fMaxBytes - fBudgetedBytes);
bsalomondace19e2014-11-17 07:34:06 -0800124#if GR_CACHE_STATS
125 fBudgetedHighWaterCount = SkTMax(fBudgetedCount, fBudgetedHighWaterCount);
126 fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes);
127#endif
128 }
robertphillipsc4ed6842016-05-24 14:17:12 -0700129 if (resource->resourcePriv().getScratchKey().isValid() &&
130 !resource->getUniqueKey().isValid()) {
kkinnunen2e6055b2016-04-22 01:48:29 -0700131 SkASSERT(!resource->resourcePriv().refsWrappedObjects());
bsalomon3582d3e2015-02-13 14:20:05 -0800132 fScratchMap.insert(resource->resourcePriv().getScratchKey(), resource);
bsalomon744998e2014-08-28 09:54:34 -0700133 }
bsalomon9f2d1572015-02-17 11:47:40 -0800134
bsalomon71cb0c22014-11-14 12:10:14 -0800135 this->purgeAsNeeded();
bsalomonc8dc1f72014-08-21 13:02:13 -0700136}
137
bsalomon0ea80f42015-02-11 10:49:59 -0800138void GrResourceCache::removeResource(GrGpuResource* resource) {
bsalomon9f2d1572015-02-17 11:47:40 -0800139 this->validate();
bsalomon16961262014-08-26 14:01:07 -0700140 SkASSERT(this->isInCache(resource));
bsalomondace19e2014-11-17 07:34:06 -0800141
Derek Sollenbergeree479142017-05-24 11:41:33 -0400142 size_t size = resource->gpuMemorySize();
bsalomon9f2d1572015-02-17 11:47:40 -0800143 if (resource->isPurgeable()) {
144 fPurgeableQueue.remove(resource);
Derek Sollenbergeree479142017-05-24 11:41:33 -0400145 fPurgeableBytes -= size;
bsalomonf320e042015-02-17 15:09:34 -0800146 } else {
147 this->removeFromNonpurgeableArray(resource);
bsalomon9f2d1572015-02-17 11:47:40 -0800148 }
149
bsalomonf320e042015-02-17 15:09:34 -0800150 SkDEBUGCODE(--fCount;)
bsalomondace19e2014-11-17 07:34:06 -0800151 fBytes -= size;
bsalomon5ec26ae2016-02-25 08:33:02 -0800152 if (SkBudgeted::kYes == resource->resourcePriv().isBudgeted()) {
bsalomondace19e2014-11-17 07:34:06 -0800153 --fBudgetedCount;
154 fBudgetedBytes -= size;
Brian Osman39c08ac2017-07-26 09:36:09 -0400155 TRACE_COUNTER2("skia.gpu.cache", "skia budget", "used",
hendrikw876c3132015-03-04 10:33:49 -0800156 fBudgetedBytes, "free", fMaxBytes - fBudgetedBytes);
bsalomondace19e2014-11-17 07:34:06 -0800157 }
158
robertphillipsc4ed6842016-05-24 14:17:12 -0700159 if (resource->resourcePriv().getScratchKey().isValid() &&
160 !resource->getUniqueKey().isValid()) {
bsalomon3582d3e2015-02-13 14:20:05 -0800161 fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource);
bsalomon744998e2014-08-28 09:54:34 -0700162 }
bsalomon8718aaf2015-02-19 07:24:21 -0800163 if (resource->getUniqueKey().isValid()) {
164 fUniqueHash.remove(resource->getUniqueKey());
bsalomon8b79d232014-11-10 10:19:06 -0800165 }
bsalomonb436ed62014-11-17 12:15:56 -0800166 this->validate();
bsalomonc8dc1f72014-08-21 13:02:13 -0700167}
168
bsalomon0ea80f42015-02-11 10:49:59 -0800169void GrResourceCache::abandonAll() {
bsalomon71cb0c22014-11-14 12:10:14 -0800170 AutoValidate av(this);
171
Greg Danielb2acf0a2018-09-12 09:17:11 -0400172 for (int i = 0; i < fResourcesWaitingForFreeMsg.count(); ++i) {
173 fResourcesWaitingForFreeMsg[i]->abandon();
174 }
175 fResourcesWaitingForFreeMsg.reset();
176
bsalomonf320e042015-02-17 15:09:34 -0800177 while (fNonpurgeableResources.count()) {
178 GrGpuResource* back = *(fNonpurgeableResources.end() - 1);
179 SkASSERT(!back->wasDestroyed());
180 back->cacheAccess().abandon();
bsalomonc8dc1f72014-08-21 13:02:13 -0700181 }
bsalomonf320e042015-02-17 15:09:34 -0800182
183 while (fPurgeableQueue.count()) {
184 GrGpuResource* top = fPurgeableQueue.peek();
185 SkASSERT(!top->wasDestroyed());
186 top->cacheAccess().abandon();
187 }
188
bsalomon744998e2014-08-28 09:54:34 -0700189 SkASSERT(!fScratchMap.count());
bsalomon8718aaf2015-02-19 07:24:21 -0800190 SkASSERT(!fUniqueHash.count());
bsalomonc8dc1f72014-08-21 13:02:13 -0700191 SkASSERT(!fCount);
bsalomonf320e042015-02-17 15:09:34 -0800192 SkASSERT(!this->getResourceCount());
bsalomondace19e2014-11-17 07:34:06 -0800193 SkASSERT(!fBytes);
194 SkASSERT(!fBudgetedCount);
195 SkASSERT(!fBudgetedBytes);
Derek Sollenbergeree479142017-05-24 11:41:33 -0400196 SkASSERT(!fPurgeableBytes);
Greg Danielb2acf0a2018-09-12 09:17:11 -0400197 SkASSERT(!fResourcesWaitingForFreeMsg.count());
bsalomonc8dc1f72014-08-21 13:02:13 -0700198}
199
bsalomon0ea80f42015-02-11 10:49:59 -0800200void GrResourceCache::releaseAll() {
bsalomon71cb0c22014-11-14 12:10:14 -0800201 AutoValidate av(this);
202
Brian Osman13dddce2017-05-09 13:19:50 -0400203 this->processFreedGpuResources();
204
Greg Danielc27eb722018-08-10 09:48:08 -0400205 // We need to make sure to free any resources that were waiting on a free message but never
206 // received one.
207 for (int i = 0; i < fResourcesWaitingForFreeMsg.count(); ++i) {
208 fResourcesWaitingForFreeMsg[i]->unref();
209 }
Greg Danielb2acf0a2018-09-12 09:17:11 -0400210 fResourcesWaitingForFreeMsg.reset();
Greg Danielc27eb722018-08-10 09:48:08 -0400211
Robert Phillips1afd4cd2018-01-08 13:40:32 -0500212 SkASSERT(fProxyProvider); // better have called setProxyProvider
Robert Phillips3ec95732017-09-29 15:10:39 -0400213 // We must remove the uniqueKeys from the proxies here. While they possess a uniqueKey
214 // they also have a raw pointer back to this class (which is presumably going away)!
Robert Phillips1afd4cd2018-01-08 13:40:32 -0500215 fProxyProvider->removeAllUniqueKeys();
Robert Phillips45a6f142017-09-29 09:49:41 -0400216
bsalomonf320e042015-02-17 15:09:34 -0800217 while(fNonpurgeableResources.count()) {
218 GrGpuResource* back = *(fNonpurgeableResources.end() - 1);
219 SkASSERT(!back->wasDestroyed());
220 back->cacheAccess().release();
bsalomonc8dc1f72014-08-21 13:02:13 -0700221 }
bsalomonf320e042015-02-17 15:09:34 -0800222
223 while (fPurgeableQueue.count()) {
224 GrGpuResource* top = fPurgeableQueue.peek();
225 SkASSERT(!top->wasDestroyed());
226 top->cacheAccess().release();
227 }
228
bsalomon744998e2014-08-28 09:54:34 -0700229 SkASSERT(!fScratchMap.count());
bsalomon8718aaf2015-02-19 07:24:21 -0800230 SkASSERT(!fUniqueHash.count());
bsalomonc8dc1f72014-08-21 13:02:13 -0700231 SkASSERT(!fCount);
bsalomonf320e042015-02-17 15:09:34 -0800232 SkASSERT(!this->getResourceCount());
bsalomondace19e2014-11-17 07:34:06 -0800233 SkASSERT(!fBytes);
234 SkASSERT(!fBudgetedCount);
235 SkASSERT(!fBudgetedBytes);
Derek Sollenbergeree479142017-05-24 11:41:33 -0400236 SkASSERT(!fPurgeableBytes);
Greg Danielb2acf0a2018-09-12 09:17:11 -0400237 SkASSERT(!fResourcesWaitingForFreeMsg.count());
bsalomonc8dc1f72014-08-21 13:02:13 -0700238}
bsalomonbcf0a522014-10-08 08:40:09 -0700239
bsalomon0ea80f42015-02-11 10:49:59 -0800240class GrResourceCache::AvailableForScratchUse {
bsalomonbcf0a522014-10-08 08:40:09 -0700241public:
bsalomon000f8292014-10-15 19:04:14 -0700242 AvailableForScratchUse(bool rejectPendingIO) : fRejectPendingIO(rejectPendingIO) { }
bsalomonbcf0a522014-10-08 08:40:09 -0700243
244 bool operator()(const GrGpuResource* resource) const {
robertphillipsc4ed6842016-05-24 14:17:12 -0700245 SkASSERT(!resource->getUniqueKey().isValid() &&
246 resource->resourcePriv().getScratchKey().isValid());
bsalomon12299ab2014-11-14 13:33:09 -0800247 if (resource->internalHasRef() || !resource->cacheAccess().isScratch()) {
bsalomon000f8292014-10-15 19:04:14 -0700248 return false;
bsalomonbcf0a522014-10-08 08:40:09 -0700249 }
bsalomon000f8292014-10-15 19:04:14 -0700250 return !fRejectPendingIO || !resource->internalHasPendingIO();
bsalomonbcf0a522014-10-08 08:40:09 -0700251 }
bsalomon1e2530b2014-10-09 09:57:18 -0700252
bsalomonbcf0a522014-10-08 08:40:09 -0700253private:
bsalomon000f8292014-10-15 19:04:14 -0700254 bool fRejectPendingIO;
bsalomonbcf0a522014-10-08 08:40:09 -0700255};
256
bsalomon0ea80f42015-02-11 10:49:59 -0800257GrGpuResource* GrResourceCache::findAndRefScratchResource(const GrScratchKey& scratchKey,
robertphillips6e83ac72015-08-13 05:19:14 -0700258 size_t resourceSize,
bsalomon9f2d1572015-02-17 11:47:40 -0800259 uint32_t flags) {
bsalomon7775c852014-12-30 12:50:52 -0800260 SkASSERT(scratchKey.isValid());
robertphillipsee843b22016-10-04 05:30:20 -0700261
bsalomon71cb0c22014-11-14 12:10:14 -0800262 GrGpuResource* resource;
bsalomon000f8292014-10-15 19:04:14 -0700263 if (flags & (kPreferNoPendingIO_ScratchFlag | kRequireNoPendingIO_ScratchFlag)) {
bsalomon71cb0c22014-11-14 12:10:14 -0800264 resource = fScratchMap.find(scratchKey, AvailableForScratchUse(true));
bsalomon000f8292014-10-15 19:04:14 -0700265 if (resource) {
bsalomon9f2d1572015-02-17 11:47:40 -0800266 this->refAndMakeResourceMRU(resource);
bsalomonb436ed62014-11-17 12:15:56 -0800267 this->validate();
268 return resource;
bsalomon000f8292014-10-15 19:04:14 -0700269 } else if (flags & kRequireNoPendingIO_ScratchFlag) {
halcanary96fcdcc2015-08-27 07:41:13 -0700270 return nullptr;
bsalomon000f8292014-10-15 19:04:14 -0700271 }
robertphillips63926682015-08-20 09:39:02 -0700272 // We would prefer to consume more available VRAM rather than flushing
273 // immediately, but on ANGLE this can lead to starving of the GPU.
274 if (fPreferVRAMUseOverFlushes && this->wouldFit(resourceSize)) {
robertphillips6e83ac72015-08-13 05:19:14 -0700275 // kPrefer is specified, we didn't find a resource without pending io,
robertphillips63926682015-08-20 09:39:02 -0700276 // but there is still space in our budget for the resource so force
277 // the caller to allocate a new resource.
halcanary96fcdcc2015-08-27 07:41:13 -0700278 return nullptr;
robertphillips6e83ac72015-08-13 05:19:14 -0700279 }
bsalomon000f8292014-10-15 19:04:14 -0700280 }
bsalomon71cb0c22014-11-14 12:10:14 -0800281 resource = fScratchMap.find(scratchKey, AvailableForScratchUse(false));
282 if (resource) {
bsalomon9f2d1572015-02-17 11:47:40 -0800283 this->refAndMakeResourceMRU(resource);
bsalomonb436ed62014-11-17 12:15:56 -0800284 this->validate();
bsalomon71cb0c22014-11-14 12:10:14 -0800285 }
286 return resource;
bsalomonbcf0a522014-10-08 08:40:09 -0700287}
bsalomon8b79d232014-11-10 10:19:06 -0800288
bsalomon0ea80f42015-02-11 10:49:59 -0800289void GrResourceCache::willRemoveScratchKey(const GrGpuResource* resource) {
bsalomon3582d3e2015-02-13 14:20:05 -0800290 SkASSERT(resource->resourcePriv().getScratchKey().isValid());
robertphillipsc4ed6842016-05-24 14:17:12 -0700291 if (!resource->getUniqueKey().isValid()) {
292 fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource);
293 }
bsalomon10e23ca2014-11-25 05:52:06 -0800294}
295
bsalomonf99e9612015-02-19 08:24:16 -0800296void GrResourceCache::removeUniqueKey(GrGpuResource* resource) {
bsalomon3f324322015-04-08 11:01:54 -0700297 // Someone has a ref to this resource in order to have removed the key. When the ref count
298 // reaches zero we will get a ref cnt notification and figure out what to do with it.
bsalomonf99e9612015-02-19 08:24:16 -0800299 if (resource->getUniqueKey().isValid()) {
300 SkASSERT(resource == fUniqueHash.find(resource->getUniqueKey()));
301 fUniqueHash.remove(resource->getUniqueKey());
302 }
303 resource->cacheAccess().removeUniqueKey();
robertphillipsc4ed6842016-05-24 14:17:12 -0700304
305 if (resource->resourcePriv().getScratchKey().isValid()) {
306 fScratchMap.insert(resource->resourcePriv().getScratchKey(), resource);
307 }
308
bsalomonf99e9612015-02-19 08:24:16 -0800309 this->validate();
bsalomon23e619c2015-02-06 11:54:28 -0800310}
311
bsalomonf99e9612015-02-19 08:24:16 -0800312void GrResourceCache::changeUniqueKey(GrGpuResource* resource, const GrUniqueKey& newKey) {
bsalomon8b79d232014-11-10 10:19:06 -0800313 SkASSERT(resource);
bsalomon71cb0c22014-11-14 12:10:14 -0800314 SkASSERT(this->isInCache(resource));
bsalomon8b79d232014-11-10 10:19:06 -0800315
bsalomonf99e9612015-02-19 08:24:16 -0800316 // If another resource has the new key, remove its key then install the key on this resource.
317 if (newKey.isValid()) {
Greg Daniel0d537802017-09-08 11:44:14 -0400318 if (GrGpuResource* old = fUniqueHash.find(newKey)) {
319 // If the old resource using the key is purgeable and is unreachable, then remove it.
320 if (!old->resourcePriv().getScratchKey().isValid() && old->isPurgeable()) {
321 old->cacheAccess().release();
322 } else {
323 this->removeUniqueKey(old);
324 }
325 }
326 SkASSERT(nullptr == fUniqueHash.find(newKey));
327
robertphillipsc4ed6842016-05-24 14:17:12 -0700328 // Remove the entry for this resource if it already has a unique key.
329 if (resource->getUniqueKey().isValid()) {
330 SkASSERT(resource == fUniqueHash.find(resource->getUniqueKey()));
331 fUniqueHash.remove(resource->getUniqueKey());
332 SkASSERT(nullptr == fUniqueHash.find(resource->getUniqueKey()));
333 } else {
334 // 'resource' didn't have a valid unique key before so it is switching sides. Remove it
335 // from the ScratchMap
336 if (resource->resourcePriv().getScratchKey().isValid()) {
337 fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource);
338 }
339 }
340
bsalomonf99e9612015-02-19 08:24:16 -0800341 resource->cacheAccess().setUniqueKey(newKey);
342 fUniqueHash.add(resource);
343 } else {
robertphillipsc4ed6842016-05-24 14:17:12 -0700344 this->removeUniqueKey(resource);
bsalomonf99e9612015-02-19 08:24:16 -0800345 }
346
bsalomon71cb0c22014-11-14 12:10:14 -0800347 this->validate();
bsalomon8b79d232014-11-10 10:19:06 -0800348}
bsalomon71cb0c22014-11-14 12:10:14 -0800349
bsalomon9f2d1572015-02-17 11:47:40 -0800350void GrResourceCache::refAndMakeResourceMRU(GrGpuResource* resource) {
bsalomon71cb0c22014-11-14 12:10:14 -0800351 SkASSERT(resource);
352 SkASSERT(this->isInCache(resource));
bsalomonddf30e62015-02-19 11:38:44 -0800353
bsalomon9f2d1572015-02-17 11:47:40 -0800354 if (resource->isPurgeable()) {
355 // It's about to become unpurgeable.
Derek Sollenbergeree479142017-05-24 11:41:33 -0400356 fPurgeableBytes -= resource->gpuMemorySize();
bsalomon9f2d1572015-02-17 11:47:40 -0800357 fPurgeableQueue.remove(resource);
bsalomonf320e042015-02-17 15:09:34 -0800358 this->addToNonpurgeableArray(resource);
bsalomon9f2d1572015-02-17 11:47:40 -0800359 }
360 resource->ref();
bsalomonddf30e62015-02-19 11:38:44 -0800361
362 resource->cacheAccess().setTimestamp(this->getNextTimestamp());
bsalomonf320e042015-02-17 15:09:34 -0800363 this->validate();
bsalomon71cb0c22014-11-14 12:10:14 -0800364}
365
bsalomon3f324322015-04-08 11:01:54 -0700366void GrResourceCache::notifyCntReachedZero(GrGpuResource* resource, uint32_t flags) {
bsalomon71cb0c22014-11-14 12:10:14 -0800367 SkASSERT(resource);
bsalomon3f324322015-04-08 11:01:54 -0700368 SkASSERT(!resource->wasDestroyed());
369 SkASSERT(flags);
bsalomon71cb0c22014-11-14 12:10:14 -0800370 SkASSERT(this->isInCache(resource));
bsalomon3f324322015-04-08 11:01:54 -0700371 // This resource should always be in the nonpurgeable array when this function is called. It
372 // will be moved to the queue if it is newly purgeable.
373 SkASSERT(fNonpurgeableResources[*resource->cacheAccess().accessCacheIndex()] == resource);
bsalomon71cb0c22014-11-14 12:10:14 -0800374
bsalomon3f324322015-04-08 11:01:54 -0700375 if (SkToBool(ResourceAccess::kRefCntReachedZero_RefNotificationFlag & flags)) {
376#ifdef SK_DEBUG
377 // When the timestamp overflows validate() is called. validate() checks that resources in
378 // the nonpurgeable array are indeed not purgeable. However, the movement from the array to
379 // the purgeable queue happens just below in this function. So we mark it as an exception.
380 if (resource->isPurgeable()) {
381 fNewlyPurgeableResourceForValidation = resource;
382 }
383#endif
384 resource->cacheAccess().setTimestamp(this->getNextTimestamp());
halcanary96fcdcc2015-08-27 07:41:13 -0700385 SkDEBUGCODE(fNewlyPurgeableResourceForValidation = nullptr);
bsalomon3f324322015-04-08 11:01:54 -0700386 }
387
388 if (!SkToBool(ResourceAccess::kAllCntsReachedZero_RefNotificationFlag & flags)) {
389 SkASSERT(!resource->isPurgeable());
390 return;
391 }
392
393 SkASSERT(resource->isPurgeable());
bsalomonf320e042015-02-17 15:09:34 -0800394 this->removeFromNonpurgeableArray(resource);
bsalomon9f2d1572015-02-17 11:47:40 -0800395 fPurgeableQueue.insert(resource);
Brian Salomon5e150852017-03-22 14:53:13 -0400396 resource->cacheAccess().setTimeWhenResourceBecomePurgeable();
Derek Sollenbergeree479142017-05-24 11:41:33 -0400397 fPurgeableBytes += resource->gpuMemorySize();
bsalomon71cb0c22014-11-14 12:10:14 -0800398
Greg Daniel303e83e2018-09-10 14:10:19 -0400399 bool hasUniqueKey = resource->getUniqueKey().isValid();
400
bsalomon5ec26ae2016-02-25 08:33:02 -0800401 if (SkBudgeted::kNo == resource->resourcePriv().isBudgeted()) {
Greg Daniel303e83e2018-09-10 14:10:19 -0400402 // We keep unbudgeted resources with a unique key in the purgable queue of the cache so they
403 // can be reused again by the image connected to the unique key.
404 if (hasUniqueKey) {
405 return;
406 }
bsalomonc2f35b72015-01-23 07:19:22 -0800407 // Check whether this resource could still be used as a scratch resource.
kkinnunen2e6055b2016-04-22 01:48:29 -0700408 if (!resource->resourcePriv().refsWrappedObjects() &&
bsalomon9f2d1572015-02-17 11:47:40 -0800409 resource->resourcePriv().getScratchKey().isValid()) {
bsalomonc2f35b72015-01-23 07:19:22 -0800410 // We won't purge an existing resource to make room for this one.
bsalomonf320e042015-02-17 15:09:34 -0800411 if (fBudgetedCount < fMaxCount &&
412 fBudgetedBytes + resource->gpuMemorySize() <= fMaxBytes) {
bsalomon3582d3e2015-02-13 14:20:05 -0800413 resource->resourcePriv().makeBudgeted();
bsalomon9f2d1572015-02-17 11:47:40 -0800414 return;
bsalomonc2f35b72015-01-23 07:19:22 -0800415 }
bsalomonc2f35b72015-01-23 07:19:22 -0800416 }
417 } else {
bsalomon9f2d1572015-02-17 11:47:40 -0800418 // Purge the resource immediately if we're over budget
bsalomon8718aaf2015-02-19 07:24:21 -0800419 // Also purge if the resource has neither a valid scratch key nor a unique key.
Greg Daniel303e83e2018-09-10 14:10:19 -0400420 bool hasKey = resource->resourcePriv().getScratchKey().isValid() ||
421 hasUniqueKey;
422 if (!this->overBudget() && hasKey) {
bsalomon9f2d1572015-02-17 11:47:40 -0800423 return;
bsalomonc2f35b72015-01-23 07:19:22 -0800424 }
425 }
bsalomondace19e2014-11-17 07:34:06 -0800426
bsalomonf320e042015-02-17 15:09:34 -0800427 SkDEBUGCODE(int beforeCount = this->getResourceCount();)
bsalomon9f2d1572015-02-17 11:47:40 -0800428 resource->cacheAccess().release();
429 // We should at least free this resource, perhaps dependent resources as well.
bsalomonf320e042015-02-17 15:09:34 -0800430 SkASSERT(this->getResourceCount() < beforeCount);
bsalomon71cb0c22014-11-14 12:10:14 -0800431 this->validate();
432}
433
bsalomon0ea80f42015-02-11 10:49:59 -0800434void GrResourceCache::didChangeBudgetStatus(GrGpuResource* resource) {
bsalomon84c8e622014-11-17 09:33:27 -0800435 SkASSERT(resource);
436 SkASSERT(this->isInCache(resource));
437
438 size_t size = resource->gpuMemorySize();
439
bsalomon5ec26ae2016-02-25 08:33:02 -0800440 if (SkBudgeted::kYes == resource->resourcePriv().isBudgeted()) {
bsalomon84c8e622014-11-17 09:33:27 -0800441 ++fBudgetedCount;
442 fBudgetedBytes += size;
bsalomonafe30052015-01-16 07:32:33 -0800443#if GR_CACHE_STATS
444 fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes);
445 fBudgetedHighWaterCount = SkTMax(fBudgetedCount, fBudgetedHighWaterCount);
446#endif
bsalomon84c8e622014-11-17 09:33:27 -0800447 this->purgeAsNeeded();
448 } else {
449 --fBudgetedCount;
450 fBudgetedBytes -= size;
451 }
Brian Osman39c08ac2017-07-26 09:36:09 -0400452 TRACE_COUNTER2("skia.gpu.cache", "skia budget", "used",
hendrikw876c3132015-03-04 10:33:49 -0800453 fBudgetedBytes, "free", fMaxBytes - fBudgetedBytes);
bsalomon84c8e622014-11-17 09:33:27 -0800454
455 this->validate();
456}
457
robertphillipsee843b22016-10-04 05:30:20 -0700458void GrResourceCache::purgeAsNeeded() {
bsalomon3f324322015-04-08 11:01:54 -0700459 SkTArray<GrUniqueKeyInvalidatedMessage> invalidKeyMsgs;
460 fInvalidUniqueKeyInbox.poll(&invalidKeyMsgs);
461 if (invalidKeyMsgs.count()) {
462 this->processInvalidUniqueKeys(invalidKeyMsgs);
463 }
bsalomon71cb0c22014-11-14 12:10:14 -0800464
Brian Osman13dddce2017-05-09 13:19:50 -0400465 this->processFreedGpuResources();
466
bsalomon3f324322015-04-08 11:01:54 -0700467 bool stillOverbudget = this->overBudget();
468 while (stillOverbudget && fPurgeableQueue.count()) {
robertphillipsee843b22016-10-04 05:30:20 -0700469 GrGpuResource* resource = fPurgeableQueue.peek();
bsalomon9f2d1572015-02-17 11:47:40 -0800470 SkASSERT(resource->isPurgeable());
471 resource->cacheAccess().release();
bsalomon3f324322015-04-08 11:01:54 -0700472 stillOverbudget = this->overBudget();
bsalomon9f2d1572015-02-17 11:47:40 -0800473 }
bsalomon71cb0c22014-11-14 12:10:14 -0800474
bsalomonb436ed62014-11-17 12:15:56 -0800475 this->validate();
bsalomon71cb0c22014-11-14 12:10:14 -0800476}
477
Robert Phillips6eba0632018-03-28 12:25:42 -0400478void GrResourceCache::purgeUnlockedResources(bool scratchResourcesOnly) {
479 if (!scratchResourcesOnly) {
480 // We could disable maintaining the heap property here, but it would add a lot of
481 // complexity. Moreover, this is rarely called.
482 while (fPurgeableQueue.count()) {
483 GrGpuResource* resource = fPurgeableQueue.peek();
484 SkASSERT(resource->isPurgeable());
485 resource->cacheAccess().release();
486 }
487 } else {
488 // Sort the queue
489 fPurgeableQueue.sort();
490
491 // Make a list of the scratch resources to delete
492 SkTDArray<GrGpuResource*> scratchResources;
493 for (int i = 0; i < fPurgeableQueue.count(); i++) {
494 GrGpuResource* resource = fPurgeableQueue.at(i);
495 SkASSERT(resource->isPurgeable());
496 if (!resource->getUniqueKey().isValid()) {
497 *scratchResources.append() = resource;
498 }
499 }
500
501 // Delete the scratch resources. This must be done as a separate pass
502 // to avoid messing up the sorted order of the queue
503 for (int i = 0; i < scratchResources.count(); i++) {
504 scratchResources.getAt(i)->cacheAccess().release();
505 }
bsalomon9f2d1572015-02-17 11:47:40 -0800506 }
bsalomon71cb0c22014-11-14 12:10:14 -0800507
bsalomonb436ed62014-11-17 12:15:56 -0800508 this->validate();
bsalomon71cb0c22014-11-14 12:10:14 -0800509}
510
Brian Salomon5e150852017-03-22 14:53:13 -0400511void GrResourceCache::purgeResourcesNotUsedSince(GrStdSteadyClock::time_point purgeTime) {
512 while (fPurgeableQueue.count()) {
513 const GrStdSteadyClock::time_point resourceTime =
514 fPurgeableQueue.peek()->cacheAccess().timeWhenResourceBecamePurgeable();
515 if (resourceTime >= purgeTime) {
516 // Resources were given both LRU timestamps and tagged with a frame number when
517 // they first became purgeable. The LRU timestamp won't change again until the
518 // resource is made non-purgeable again. So, at this point all the remaining
519 // resources in the timestamp-sorted queue will have a frame number >= to this
520 // one.
521 break;
522 }
523 GrGpuResource* resource = fPurgeableQueue.peek();
524 SkASSERT(resource->isPurgeable());
525 resource->cacheAccess().release();
526 }
527}
528
Derek Sollenberger5480a182017-05-25 16:43:59 -0400529void GrResourceCache::purgeUnlockedResources(size_t bytesToPurge, bool preferScratchResources) {
530
531 const size_t tmpByteBudget = SkTMax((size_t)0, fBytes - bytesToPurge);
532 bool stillOverbudget = tmpByteBudget < fBytes;
533
534 if (preferScratchResources && bytesToPurge < fPurgeableBytes) {
535 // Sort the queue
536 fPurgeableQueue.sort();
537
538 // Make a list of the scratch resources to delete
539 SkTDArray<GrGpuResource*> scratchResources;
540 size_t scratchByteCount = 0;
541 for (int i = 0; i < fPurgeableQueue.count() && stillOverbudget; i++) {
542 GrGpuResource* resource = fPurgeableQueue.at(i);
543 SkASSERT(resource->isPurgeable());
544 if (!resource->getUniqueKey().isValid()) {
545 *scratchResources.append() = resource;
546 scratchByteCount += resource->gpuMemorySize();
547 stillOverbudget = tmpByteBudget < fBytes - scratchByteCount;
548 }
549 }
550
551 // Delete the scratch resources. This must be done as a separate pass
552 // to avoid messing up the sorted order of the queue
553 for (int i = 0; i < scratchResources.count(); i++) {
554 scratchResources.getAt(i)->cacheAccess().release();
555 }
556 stillOverbudget = tmpByteBudget < fBytes;
557
558 this->validate();
559 }
560
561 // Purge any remaining resources in LRU order
562 if (stillOverbudget) {
563 const size_t cachedByteCount = fMaxBytes;
564 fMaxBytes = tmpByteBudget;
565 this->purgeAsNeeded();
566 fMaxBytes = cachedByteCount;
567 }
568}
569
bsalomon8718aaf2015-02-19 07:24:21 -0800570void GrResourceCache::processInvalidUniqueKeys(
Robert Phillips1afd4cd2018-01-08 13:40:32 -0500571 const SkTArray<GrUniqueKeyInvalidatedMessage>& msgs) {
572 SkASSERT(fProxyProvider); // better have called setProxyProvider
573
bsalomon23e619c2015-02-06 11:54:28 -0800574 for (int i = 0; i < msgs.count(); ++i) {
Robert Phillips1afd4cd2018-01-08 13:40:32 -0500575 fProxyProvider->processInvalidProxyUniqueKey(msgs[i].key());
Robert Phillipsae7d3f32017-09-21 08:26:08 -0400576
bsalomon8718aaf2015-02-19 07:24:21 -0800577 GrGpuResource* resource = this->findAndRefUniqueResource(msgs[i].key());
bsalomon23e619c2015-02-06 11:54:28 -0800578 if (resource) {
bsalomon8718aaf2015-02-19 07:24:21 -0800579 resource->resourcePriv().removeUniqueKey();
bsalomon3f324322015-04-08 11:01:54 -0700580 resource->unref(); // If this resource is now purgeable, the cache will be notified.
bsalomon23e619c2015-02-06 11:54:28 -0800581 }
582 }
583}
584
Brian Osman13dddce2017-05-09 13:19:50 -0400585void GrResourceCache::insertCrossContextGpuResource(GrGpuResource* resource) {
586 resource->ref();
Greg Danielc27eb722018-08-10 09:48:08 -0400587 SkASSERT(!fResourcesWaitingForFreeMsg.contains(resource));
588 fResourcesWaitingForFreeMsg.push_back(resource);
Brian Osman13dddce2017-05-09 13:19:50 -0400589}
590
591void GrResourceCache::processFreedGpuResources() {
592 SkTArray<GrGpuResourceFreedMessage> msgs;
593 fFreedGpuResourceInbox.poll(&msgs);
594 for (int i = 0; i < msgs.count(); ++i) {
Brian Salomon238069b2018-07-11 15:58:57 -0400595 SkASSERT(msgs[i].fOwningUniqueID == fContextUniqueID);
Greg Danielc27eb722018-08-10 09:48:08 -0400596 int index = fResourcesWaitingForFreeMsg.find(msgs[i].fResource);
Greg Danielb2acf0a2018-09-12 09:17:11 -0400597 // If we called release or abandon on the GrContext we will have already released our ref on
598 // the GrGpuResource. If then the message arrives before the actual GrContext gets destroyed
599 // we will try to process the message when we destroy the GrContext. This protects us from
600 // trying to unref the resource twice.
601 if (index != -1) {
602 fResourcesWaitingForFreeMsg.removeShuffle(index);
603 msgs[i].fResource->unref();
604 }
Brian Osman13dddce2017-05-09 13:19:50 -0400605 }
606}
607
bsalomonf320e042015-02-17 15:09:34 -0800608void GrResourceCache::addToNonpurgeableArray(GrGpuResource* resource) {
609 int index = fNonpurgeableResources.count();
610 *fNonpurgeableResources.append() = resource;
611 *resource->cacheAccess().accessCacheIndex() = index;
612}
613
614void GrResourceCache::removeFromNonpurgeableArray(GrGpuResource* resource) {
615 int* index = resource->cacheAccess().accessCacheIndex();
616 // Fill the whole we will create in the array with the tail object, adjust its index, and
617 // then pop the array
618 GrGpuResource* tail = *(fNonpurgeableResources.end() - 1);
619 SkASSERT(fNonpurgeableResources[*index] == resource);
620 fNonpurgeableResources[*index] = tail;
621 *tail->cacheAccess().accessCacheIndex() = *index;
622 fNonpurgeableResources.pop();
623 SkDEBUGCODE(*index = -1);
624}
625
bsalomonddf30e62015-02-19 11:38:44 -0800626uint32_t GrResourceCache::getNextTimestamp() {
627 // If we wrap then all the existing resources will appear older than any resources that get
628 // a timestamp after the wrap.
629 if (0 == fTimestamp) {
630 int count = this->getResourceCount();
631 if (count) {
632 // Reset all the timestamps. We sort the resources by timestamp and then assign
633 // sequential timestamps beginning with 0. This is O(n*lg(n)) but it should be extremely
634 // rare.
635 SkTDArray<GrGpuResource*> sortedPurgeableResources;
636 sortedPurgeableResources.setReserve(fPurgeableQueue.count());
637
638 while (fPurgeableQueue.count()) {
639 *sortedPurgeableResources.append() = fPurgeableQueue.peek();
640 fPurgeableQueue.pop();
641 }
robertphillipsee843b22016-10-04 05:30:20 -0700642
bsalomone2e87f32016-09-22 12:42:11 -0700643 SkTQSort(fNonpurgeableResources.begin(), fNonpurgeableResources.end() - 1,
644 CompareTimestamp);
bsalomonddf30e62015-02-19 11:38:44 -0800645
646 // Pick resources out of the purgeable and non-purgeable arrays based on lowest
647 // timestamp and assign new timestamps.
648 int currP = 0;
649 int currNP = 0;
650 while (currP < sortedPurgeableResources.count() &&
mtklein56da0252015-11-16 11:16:23 -0800651 currNP < fNonpurgeableResources.count()) {
bsalomonddf30e62015-02-19 11:38:44 -0800652 uint32_t tsP = sortedPurgeableResources[currP]->cacheAccess().timestamp();
653 uint32_t tsNP = fNonpurgeableResources[currNP]->cacheAccess().timestamp();
654 SkASSERT(tsP != tsNP);
655 if (tsP < tsNP) {
656 sortedPurgeableResources[currP++]->cacheAccess().setTimestamp(fTimestamp++);
657 } else {
658 // Correct the index in the nonpurgeable array stored on the resource post-sort.
659 *fNonpurgeableResources[currNP]->cacheAccess().accessCacheIndex() = currNP;
660 fNonpurgeableResources[currNP++]->cacheAccess().setTimestamp(fTimestamp++);
661 }
662 }
663
664 // The above loop ended when we hit the end of one array. Finish the other one.
665 while (currP < sortedPurgeableResources.count()) {
666 sortedPurgeableResources[currP++]->cacheAccess().setTimestamp(fTimestamp++);
667 }
668 while (currNP < fNonpurgeableResources.count()) {
669 *fNonpurgeableResources[currNP]->cacheAccess().accessCacheIndex() = currNP;
670 fNonpurgeableResources[currNP++]->cacheAccess().setTimestamp(fTimestamp++);
671 }
672
673 // Rebuild the queue.
674 for (int i = 0; i < sortedPurgeableResources.count(); ++i) {
675 fPurgeableQueue.insert(sortedPurgeableResources[i]);
676 }
677
678 this->validate();
679 SkASSERT(count == this->getResourceCount());
680
681 // count should be the next timestamp we return.
682 SkASSERT(fTimestamp == SkToU32(count));
mtklein56da0252015-11-16 11:16:23 -0800683 }
bsalomonddf30e62015-02-19 11:38:44 -0800684 }
685 return fTimestamp++;
686}
687
ericrk0a5fa482015-09-15 14:16:10 -0700688void GrResourceCache::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
689 for (int i = 0; i < fNonpurgeableResources.count(); ++i) {
690 fNonpurgeableResources[i]->dumpMemoryStatistics(traceMemoryDump);
691 }
692 for (int i = 0; i < fPurgeableQueue.count(); ++i) {
693 fPurgeableQueue.at(i)->dumpMemoryStatistics(traceMemoryDump);
694 }
695}
696
bsalomon71cb0c22014-11-14 12:10:14 -0800697#ifdef SK_DEBUG
bsalomon0ea80f42015-02-11 10:49:59 -0800698void GrResourceCache::validate() const {
bsalomonc2f35b72015-01-23 07:19:22 -0800699 // Reduce the frequency of validations for large resource counts.
700 static SkRandom gRandom;
701 int mask = (SkNextPow2(fCount + 1) >> 5) - 1;
702 if (~mask && (gRandom.nextU() & mask)) {
703 return;
704 }
705
bsalomonf320e042015-02-17 15:09:34 -0800706 struct Stats {
707 size_t fBytes;
708 int fBudgetedCount;
709 size_t fBudgetedBytes;
710 int fLocked;
711 int fScratch;
712 int fCouldBeScratch;
713 int fContent;
714 const ScratchMap* fScratchMap;
bsalomon8718aaf2015-02-19 07:24:21 -0800715 const UniqueHash* fUniqueHash;
bsalomon71cb0c22014-11-14 12:10:14 -0800716
bsalomonf320e042015-02-17 15:09:34 -0800717 Stats(const GrResourceCache* cache) {
718 memset(this, 0, sizeof(*this));
719 fScratchMap = &cache->fScratchMap;
bsalomon8718aaf2015-02-19 07:24:21 -0800720 fUniqueHash = &cache->fUniqueHash;
bsalomon71cb0c22014-11-14 12:10:14 -0800721 }
722
bsalomonf320e042015-02-17 15:09:34 -0800723 void update(GrGpuResource* resource) {
724 fBytes += resource->gpuMemorySize();
bsalomondace19e2014-11-17 07:34:06 -0800725
bsalomonf320e042015-02-17 15:09:34 -0800726 if (!resource->isPurgeable()) {
727 ++fLocked;
728 }
bsalomon9f2d1572015-02-17 11:47:40 -0800729
robertphillipsc4ed6842016-05-24 14:17:12 -0700730 const GrScratchKey& scratchKey = resource->resourcePriv().getScratchKey();
731 const GrUniqueKey& uniqueKey = resource->getUniqueKey();
732
bsalomonf320e042015-02-17 15:09:34 -0800733 if (resource->cacheAccess().isScratch()) {
robertphillipsc4ed6842016-05-24 14:17:12 -0700734 SkASSERT(!uniqueKey.isValid());
bsalomonf320e042015-02-17 15:09:34 -0800735 ++fScratch;
robertphillipsc4ed6842016-05-24 14:17:12 -0700736 SkASSERT(fScratchMap->countForKey(scratchKey));
kkinnunen2e6055b2016-04-22 01:48:29 -0700737 SkASSERT(!resource->resourcePriv().refsWrappedObjects());
robertphillipsc4ed6842016-05-24 14:17:12 -0700738 } else if (scratchKey.isValid()) {
bsalomon5ec26ae2016-02-25 08:33:02 -0800739 SkASSERT(SkBudgeted::kNo == resource->resourcePriv().isBudgeted() ||
robertphillipsc4ed6842016-05-24 14:17:12 -0700740 uniqueKey.isValid());
741 if (!uniqueKey.isValid()) {
mtklein4e976072016-08-08 09:06:27 -0700742 ++fCouldBeScratch;
robertphillipsc4ed6842016-05-24 14:17:12 -0700743 SkASSERT(fScratchMap->countForKey(scratchKey));
744 }
kkinnunen2e6055b2016-04-22 01:48:29 -0700745 SkASSERT(!resource->resourcePriv().refsWrappedObjects());
bsalomonf320e042015-02-17 15:09:34 -0800746 }
bsalomon8718aaf2015-02-19 07:24:21 -0800747 if (uniqueKey.isValid()) {
bsalomonf320e042015-02-17 15:09:34 -0800748 ++fContent;
bsalomon8718aaf2015-02-19 07:24:21 -0800749 SkASSERT(fUniqueHash->find(uniqueKey) == resource);
Brian Osman0562eb92017-05-08 11:16:39 -0400750 SkASSERT(SkBudgeted::kYes == resource->resourcePriv().isBudgeted() ||
751 resource->resourcePriv().refsWrappedObjects());
robertphillipsc4ed6842016-05-24 14:17:12 -0700752
753 if (scratchKey.isValid()) {
754 SkASSERT(!fScratchMap->has(resource, scratchKey));
755 }
bsalomonf320e042015-02-17 15:09:34 -0800756 }
757
bsalomon5ec26ae2016-02-25 08:33:02 -0800758 if (SkBudgeted::kYes == resource->resourcePriv().isBudgeted()) {
bsalomonf320e042015-02-17 15:09:34 -0800759 ++fBudgetedCount;
760 fBudgetedBytes += resource->gpuMemorySize();
761 }
bsalomon9f2d1572015-02-17 11:47:40 -0800762 }
bsalomonf320e042015-02-17 15:09:34 -0800763 };
764
robertphillipsc4ed6842016-05-24 14:17:12 -0700765 {
766 ScratchMap::ConstIter iter(&fScratchMap);
767
768 int count = 0;
769 for ( ; !iter.done(); ++iter) {
770 const GrGpuResource* resource = *iter;
771 SkASSERT(resource->resourcePriv().getScratchKey().isValid());
772 SkASSERT(!resource->getUniqueKey().isValid());
773 count++;
774 }
775 SkASSERT(count == fScratchMap.count()); // ensure the iterator is working correctly
776 }
777
bsalomonf320e042015-02-17 15:09:34 -0800778 Stats stats(this);
Derek Sollenbergeree479142017-05-24 11:41:33 -0400779 size_t purgeableBytes = 0;
bsalomonf320e042015-02-17 15:09:34 -0800780
781 for (int i = 0; i < fNonpurgeableResources.count(); ++i) {
bsalomon3f324322015-04-08 11:01:54 -0700782 SkASSERT(!fNonpurgeableResources[i]->isPurgeable() ||
783 fNewlyPurgeableResourceForValidation == fNonpurgeableResources[i]);
bsalomonf320e042015-02-17 15:09:34 -0800784 SkASSERT(*fNonpurgeableResources[i]->cacheAccess().accessCacheIndex() == i);
785 SkASSERT(!fNonpurgeableResources[i]->wasDestroyed());
786 stats.update(fNonpurgeableResources[i]);
bsalomon71cb0c22014-11-14 12:10:14 -0800787 }
bsalomon9f2d1572015-02-17 11:47:40 -0800788 for (int i = 0; i < fPurgeableQueue.count(); ++i) {
789 SkASSERT(fPurgeableQueue.at(i)->isPurgeable());
bsalomonf320e042015-02-17 15:09:34 -0800790 SkASSERT(*fPurgeableQueue.at(i)->cacheAccess().accessCacheIndex() == i);
791 SkASSERT(!fPurgeableQueue.at(i)->wasDestroyed());
792 stats.update(fPurgeableQueue.at(i));
Derek Sollenbergeree479142017-05-24 11:41:33 -0400793 purgeableBytes += fPurgeableQueue.at(i)->gpuMemorySize();
bsalomon9f2d1572015-02-17 11:47:40 -0800794 }
795
bsalomonf320e042015-02-17 15:09:34 -0800796 SkASSERT(fCount == this->getResourceCount());
bsalomondace19e2014-11-17 07:34:06 -0800797 SkASSERT(fBudgetedCount <= fCount);
bsalomonf320e042015-02-17 15:09:34 -0800798 SkASSERT(fBudgetedBytes <= fBytes);
799 SkASSERT(stats.fBytes == fBytes);
800 SkASSERT(stats.fBudgetedBytes == fBudgetedBytes);
801 SkASSERT(stats.fBudgetedCount == fBudgetedCount);
Derek Sollenbergeree479142017-05-24 11:41:33 -0400802 SkASSERT(purgeableBytes == fPurgeableBytes);
bsalomon71cb0c22014-11-14 12:10:14 -0800803#if GR_CACHE_STATS
bsalomondace19e2014-11-17 07:34:06 -0800804 SkASSERT(fBudgetedHighWaterCount <= fHighWaterCount);
805 SkASSERT(fBudgetedHighWaterBytes <= fHighWaterBytes);
bsalomonf320e042015-02-17 15:09:34 -0800806 SkASSERT(fBytes <= fHighWaterBytes);
807 SkASSERT(fCount <= fHighWaterCount);
808 SkASSERT(fBudgetedBytes <= fBudgetedHighWaterBytes);
809 SkASSERT(fBudgetedCount <= fBudgetedHighWaterCount);
bsalomon71cb0c22014-11-14 12:10:14 -0800810#endif
bsalomon8718aaf2015-02-19 07:24:21 -0800811 SkASSERT(stats.fContent == fUniqueHash.count());
bsalomonf320e042015-02-17 15:09:34 -0800812 SkASSERT(stats.fScratch + stats.fCouldBeScratch == fScratchMap.count());
bsalomon71cb0c22014-11-14 12:10:14 -0800813
bsalomon3f324322015-04-08 11:01:54 -0700814 // This assertion is not currently valid because we can be in recursive notifyCntReachedZero()
bsalomon12299ab2014-11-14 13:33:09 -0800815 // calls. This will be fixed when subresource registration is explicit.
bsalomondace19e2014-11-17 07:34:06 -0800816 // bool overBudget = budgetedBytes > fMaxBytes || budgetedCount > fMaxCount;
bsalomon12299ab2014-11-14 13:33:09 -0800817 // SkASSERT(!overBudget || locked == count || fPurging);
bsalomon71cb0c22014-11-14 12:10:14 -0800818}
bsalomonf320e042015-02-17 15:09:34 -0800819
820bool GrResourceCache::isInCache(const GrGpuResource* resource) const {
821 int index = *resource->cacheAccess().accessCacheIndex();
822 if (index < 0) {
823 return false;
824 }
825 if (index < fPurgeableQueue.count() && fPurgeableQueue.at(index) == resource) {
826 return true;
827 }
828 if (index < fNonpurgeableResources.count() && fNonpurgeableResources[index] == resource) {
829 return true;
830 }
831 SkDEBUGFAIL("Resource index should be -1 or the resource should be in the cache.");
832 return false;
833}
834
bsalomon71cb0c22014-11-14 12:10:14 -0800835#endif