1c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon/*
2c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon * Copyright 2014 Google Inc.
3c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon *
4c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon * Use of this source code is governed by a BSD-style license that can be
5c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon * found in the LICENSE file.
6c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon */
7c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon
8c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon
90ea80f43a1af05b8157a4ef387223bb5b0da35edbsalomon#include "GrResourceCache.h"
1028a838e532250fcca9673aca6c4616193a5a139drobertphillips
1128a838e532250fcca9673aca6c4616193a5a139drobertphillips#include "GrCaps.h"
123582d3ee9fffdec715f5e4949a241ab08e6271ecbsalomon#include "GrGpuResourceCacheAccess.h"
131afd4cdb0800e2e395b465da24eb71e0e834dafaRobert Phillips#include "GrProxyProvider.h"
14ae7d3f3992708354a3284bb49066737e36a76f40Robert Phillips#include "GrTexture.h"
15ae7d3f3992708354a3284bb49066737e36a76f40Robert Phillips#include "GrTextureProxyCacheAccess.h"
16876c3132d75966829ad58b2f9b2957d50457cc29hendrikw#include "GrTracing.h"
1771cb0c241e439b6ed746b90294d0b6916644a644bsalomon#include "SkGr.h"
1871cb0c241e439b6ed746b90294d0b6916644a644bsalomon#include "SkMessageBus.h"
194e97607d9a1cef66fac16f347c5ca813ec4f9515mtklein#include "SkOpts.h"
20ddf30e64fe474847b204d7062fad3341d245062cbsalomon#include "SkTSort.h"
2171cb0c241e439b6ed746b90294d0b6916644a644bsalomon
228718aafec239c93485e45bbe8fed19d9a8def079bsalomonDECLARE_SKMESSAGEBUS_MESSAGE(GrUniqueKeyInvalidatedMessage);
2371cb0c241e439b6ed746b90294d0b6916644a644bsalomon
2413dddce65fd87a8175a209a49f35615735a2886aBrian OsmanDECLARE_SKMESSAGEBUS_MESSAGE(GrGpuResourceFreedMessage);
2513dddce65fd87a8175a209a49f35615735a2886aBrian Osman
2671cb0c241e439b6ed746b90294d0b6916644a644bsalomon//////////////////////////////////////////////////////////////////////////////
2771cb0c241e439b6ed746b90294d0b6916644a644bsalomon
287775c85611c734a2af709b3a9c127939a4296c48bsalomonGrScratchKey::ResourceType GrScratchKey::GenerateResourceType() {
2924db3b1c35fb935660229da164fc5ad31977387fbsalomon    static int32_t gType = INHERITED::kInvalidDomain + 1;
30fe369ee34bc59a7e87b5d21bb0117e92cf75c103bsalomon
317775c85611c734a2af709b3a9c127939a4296c48bsalomon    int32_t type = sk_atomic_inc(&gType);
329790a7b36b7704f6f490368778bff16302bb7cb6robertphillips    if (type > SK_MaxU16) {
33b4aab9ae6d27c446af8302b79d15b832c816c633Ben Wagner        SK_ABORT("Too many Resource Types");
347775c85611c734a2af709b3a9c127939a4296c48bsalomon    }
35fe369ee34bc59a7e87b5d21bb0117e92cf75c103bsalomon
367775c85611c734a2af709b3a9c127939a4296c48bsalomon    return static_cast<ResourceType>(type);
37fe369ee34bc59a7e87b5d21bb0117e92cf75c103bsalomon}
38fe369ee34bc59a7e87b5d21bb0117e92cf75c103bsalomon
398718aafec239c93485e45bbe8fed19d9a8def079bsalomonGrUniqueKey::Domain GrUniqueKey::GenerateDomain() {
4024db3b1c35fb935660229da164fc5ad31977387fbsalomon    static int32_t gDomain = INHERITED::kInvalidDomain + 1;
4171cb0c241e439b6ed746b90294d0b6916644a644bsalomon
4224db3b1c35fb935660229da164fc5ad31977387fbsalomon    int32_t domain = sk_atomic_inc(&gDomain);
43016dffb7b3f5f94b4777ddc6bd8bcd03becf4e38kkinnunen    if (domain > SK_MaxU16) {
44b4aab9ae6d27c446af8302b79d15b832c816c633Ben Wagner        SK_ABORT("Too many GrUniqueKey Domains");
4571cb0c241e439b6ed746b90294d0b6916644a644bsalomon    }
4624db3b1c35fb935660229da164fc5ad31977387fbsalomon
4724db3b1c35fb935660229da164fc5ad31977387fbsalomon    return static_cast<Domain>(domain);
4824db3b1c35fb935660229da164fc5ad31977387fbsalomon}
493f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon
5024db3b1c35fb935660229da164fc5ad31977387fbsalomonuint32_t GrResourceKeyHash(const uint32_t* data, size_t size) {
514e97607d9a1cef66fac16f347c5ca813ec4f9515mtklein    return SkOpts::hash(data, size);
5271cb0c241e439b6ed746b90294d0b6916644a644bsalomon}
5371cb0c241e439b6ed746b90294d0b6916644a644bsalomon
54fe369ee34bc59a7e87b5d21bb0117e92cf75c103bsalomon//////////////////////////////////////////////////////////////////////////////
55fe369ee34bc59a7e87b5d21bb0117e92cf75c103bsalomon
560ea80f43a1af05b8157a4ef387223bb5b0da35edbsalomonclass GrResourceCache::AutoValidate : ::SkNoncopyable {
5771cb0c241e439b6ed746b90294d0b6916644a644bsalomonpublic:
580ea80f43a1af05b8157a4ef387223bb5b0da35edbsalomon    AutoValidate(GrResourceCache* cache) : fCache(cache) { cache->validate(); }
5971cb0c241e439b6ed746b90294d0b6916644a644bsalomon    ~AutoValidate() { fCache->validate(); }
6071cb0c241e439b6ed746b90294d0b6916644a644bsalomonprivate:
610ea80f43a1af05b8157a4ef387223bb5b0da35edbsalomon    GrResourceCache* fCache;
6271cb0c241e439b6ed746b90294d0b6916644a644bsalomon};
6371cb0c241e439b6ed746b90294d0b6916644a644bsalomon
6471cb0c241e439b6ed746b90294d0b6916644a644bsalomon //////////////////////////////////////////////////////////////////////////////
65ee843b2ae4d75748d8bc323287f0c310fad548a7robertphillips
6671cb0c241e439b6ed746b90294d0b6916644a644bsalomon
6713dddce65fd87a8175a209a49f35615735a2886aBrian OsmanGrResourceCache::GrResourceCache(const GrCaps* caps, uint32_t contextUniqueID)
681afd4cdb0800e2e395b465da24eb71e0e834dafaRobert Phillips    : fProxyProvider(nullptr)
691afd4cdb0800e2e395b465da24eb71e0e834dafaRobert Phillips    , fTimestamp(0)
709f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon    , fMaxCount(kDefaultMaxCount)
7171cb0c241e439b6ed746b90294d0b6916644a644bsalomon    , fMaxBytes(kDefaultMaxSize)
723f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    , fMaxUnusedFlushes(kDefaultMaxUnusedFlushes)
7371cb0c241e439b6ed746b90294d0b6916644a644bsalomon#if GR_CACHE_STATS
7471cb0c241e439b6ed746b90294d0b6916644a644bsalomon    , fHighWaterCount(0)
7571cb0c241e439b6ed746b90294d0b6916644a644bsalomon    , fHighWaterBytes(0)
76dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon    , fBudgetedHighWaterCount(0)
77dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon    , fBudgetedHighWaterBytes(0)
7871cb0c241e439b6ed746b90294d0b6916644a644bsalomon#endif
7971cb0c241e439b6ed746b90294d0b6916644a644bsalomon    , fBytes(0)
80dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon    , fBudgetedCount(0)
81dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon    , fBudgetedBytes(0)
82ee47914ae5661043c20754f46523665a6d31bc73Derek Sollenberger    , fPurgeableBytes(0)
83ee843b2ae4d75748d8bc323287f0c310fad548a7robertphillips    , fRequestFlush(false)
84e2e87f3484e5524dbfd6c01f402136738d1d434bbsalomon    , fExternalFlushCnt(0)
8513dddce65fd87a8175a209a49f35615735a2886aBrian Osman    , fContextUniqueID(contextUniqueID)
8663926683c583e8497d9d907977e773663cb4bd9erobertphillips    , fPreferVRAMUseOverFlushes(caps->preferVRAMUseOverFlushes()) {
87f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    SkDEBUGCODE(fCount = 0;)
8896fcdcc219d2a0d3579719b84b28bede76efba64halcanary    SkDEBUGCODE(fNewlyPurgeableResourceForValidation = nullptr;)
8971cb0c241e439b6ed746b90294d0b6916644a644bsalomon}
9071cb0c241e439b6ed746b90294d0b6916644a644bsalomon
910ea80f43a1af05b8157a4ef387223bb5b0da35edbsalomonGrResourceCache::~GrResourceCache() {
92c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon    this->releaseAll();
93c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon}
94c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon
953f324321cdd8fde7976d958e2888a1ec4e657e35bsalomonvoid GrResourceCache::setLimits(int count, size_t bytes, int maxUnusedFlushes) {
9671cb0c241e439b6ed746b90294d0b6916644a644bsalomon    fMaxCount = count;
9771cb0c241e439b6ed746b90294d0b6916644a644bsalomon    fMaxBytes = bytes;
983f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    fMaxUnusedFlushes = maxUnusedFlushes;
9971cb0c241e439b6ed746b90294d0b6916644a644bsalomon    this->purgeAsNeeded();
10071cb0c241e439b6ed746b90294d0b6916644a644bsalomon}
10171cb0c241e439b6ed746b90294d0b6916644a644bsalomon
1020ea80f43a1af05b8157a4ef387223bb5b0da35edbsalomonvoid GrResourceCache::insertResource(GrGpuResource* resource) {
10349f085dddff10473b6ebf832a974288300224e60bsalomon    SkASSERT(resource);
104169612621f00b3fe9f71014079991287d311751absalomon    SkASSERT(!this->isInCache(resource));
105f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    SkASSERT(!resource->wasDestroyed());
106f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    SkASSERT(!resource->isPurgeable());
107ddf30e64fe474847b204d7062fad3341d245062cbsalomon
108ddf30e64fe474847b204d7062fad3341d245062cbsalomon    // We must set the timestamp before adding to the array in case the timestamp wraps and we wind
109ddf30e64fe474847b204d7062fad3341d245062cbsalomon    // up iterating over all the resources that already have timestamps.
110ddf30e64fe474847b204d7062fad3341d245062cbsalomon    resource->cacheAccess().setTimestamp(this->getNextTimestamp());
111ddf30e64fe474847b204d7062fad3341d245062cbsalomon
112f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    this->addToNonpurgeableArray(resource);
11371cb0c241e439b6ed746b90294d0b6916644a644bsalomon
114dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon    size_t size = resource->gpuMemorySize();
115f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    SkDEBUGCODE(++fCount;)
11684c8e62fad59f0e19b40ac718467f5b7884b431dbsalomon    fBytes += size;
11782b1d620137f35fe48bc635bc74f638c9716710bbsalomon#if GR_CACHE_STATS
118f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    fHighWaterCount = SkTMax(this->getResourceCount(), fHighWaterCount);
11982b1d620137f35fe48bc635bc74f638c9716710bbsalomon    fHighWaterBytes = SkTMax(fBytes, fHighWaterBytes);
12082b1d620137f35fe48bc635bc74f638c9716710bbsalomon#endif
1215ec26ae9bfca635ccc98283aad5deda11519d826bsalomon    if (SkBudgeted::kYes == resource->resourcePriv().isBudgeted()) {
122dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon        ++fBudgetedCount;
123dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon        fBudgetedBytes += size;
12439c08ac3be30f9956cea7c5e4fd9a1d86e993a65Brian Osman        TRACE_COUNTER2("skia.gpu.cache", "skia budget", "used",
125876c3132d75966829ad58b2f9b2957d50457cc29hendrikw                       fBudgetedBytes, "free", fMaxBytes - fBudgetedBytes);
126dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon#if GR_CACHE_STATS
127dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon        fBudgetedHighWaterCount = SkTMax(fBudgetedCount, fBudgetedHighWaterCount);
128dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon        fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes);
129dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon#endif
130dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon    }
131c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips    if (resource->resourcePriv().getScratchKey().isValid() &&
132c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips        !resource->getUniqueKey().isValid()) {
1332e6055b3ea14a04fcde1ac1974a70bf00b1e295bkkinnunen        SkASSERT(!resource->resourcePriv().refsWrappedObjects());
1343582d3ee9fffdec715f5e4949a241ab08e6271ecbsalomon        fScratchMap.insert(resource->resourcePriv().getScratchKey(), resource);
135744998e666073166307d2522847b2536000a7619bsalomon    }
1369f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon
13771cb0c241e439b6ed746b90294d0b6916644a644bsalomon    this->purgeAsNeeded();
138c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon}
139c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon
1400ea80f43a1af05b8157a4ef387223bb5b0da35edbsalomonvoid GrResourceCache::removeResource(GrGpuResource* resource) {
1419f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon    this->validate();
142169612621f00b3fe9f71014079991287d311751absalomon    SkASSERT(this->isInCache(resource));
143dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon
144ee47914ae5661043c20754f46523665a6d31bc73Derek Sollenberger    size_t size = resource->gpuMemorySize();
1459f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon    if (resource->isPurgeable()) {
1469f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon        fPurgeableQueue.remove(resource);
147ee47914ae5661043c20754f46523665a6d31bc73Derek Sollenberger        fPurgeableBytes -= size;
148f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    } else {
149f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon        this->removeFromNonpurgeableArray(resource);
1509f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon    }
1519f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon
152f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    SkDEBUGCODE(--fCount;)
153dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon    fBytes -= size;
1545ec26ae9bfca635ccc98283aad5deda11519d826bsalomon    if (SkBudgeted::kYes == resource->resourcePriv().isBudgeted()) {
155dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon        --fBudgetedCount;
156dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon        fBudgetedBytes -= size;
15739c08ac3be30f9956cea7c5e4fd9a1d86e993a65Brian Osman        TRACE_COUNTER2("skia.gpu.cache", "skia budget", "used",
158876c3132d75966829ad58b2f9b2957d50457cc29hendrikw                       fBudgetedBytes, "free", fMaxBytes - fBudgetedBytes);
159dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon    }
160dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon
161c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips    if (resource->resourcePriv().getScratchKey().isValid() &&
162c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips        !resource->getUniqueKey().isValid()) {
1633582d3ee9fffdec715f5e4949a241ab08e6271ecbsalomon        fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource);
164744998e666073166307d2522847b2536000a7619bsalomon    }
1658718aafec239c93485e45bbe8fed19d9a8def079bsalomon    if (resource->getUniqueKey().isValid()) {
1668718aafec239c93485e45bbe8fed19d9a8def079bsalomon        fUniqueHash.remove(resource->getUniqueKey());
1678b79d23f825cd9e0f9e3bf8aaa9e209940b17ef6bsalomon    }
168b436ed6754452d7acb6c70e70307904c8f4a50e7bsalomon    this->validate();
169c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon}
170c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon
1710ea80f43a1af05b8157a4ef387223bb5b0da35edbsalomonvoid GrResourceCache::abandonAll() {
17271cb0c241e439b6ed746b90294d0b6916644a644bsalomon    AutoValidate av(this);
17371cb0c241e439b6ed746b90294d0b6916644a644bsalomon
174f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    while (fNonpurgeableResources.count()) {
175f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon        GrGpuResource* back = *(fNonpurgeableResources.end() - 1);
176f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon        SkASSERT(!back->wasDestroyed());
177f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon        back->cacheAccess().abandon();
178f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    }
179f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon
180f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    while (fPurgeableQueue.count()) {
181f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon        GrGpuResource* top = fPurgeableQueue.peek();
182f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon        SkASSERT(!top->wasDestroyed());
183f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon        top->cacheAccess().abandon();
184c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon    }
185f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon
186744998e666073166307d2522847b2536000a7619bsalomon    SkASSERT(!fScratchMap.count());
1878718aafec239c93485e45bbe8fed19d9a8def079bsalomon    SkASSERT(!fUniqueHash.count());
188c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon    SkASSERT(!fCount);
189f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    SkASSERT(!this->getResourceCount());
190dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon    SkASSERT(!fBytes);
191dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon    SkASSERT(!fBudgetedCount);
192dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon    SkASSERT(!fBudgetedBytes);
193ee47914ae5661043c20754f46523665a6d31bc73Derek Sollenberger    SkASSERT(!fPurgeableBytes);
194c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon}
195c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon
1960ea80f43a1af05b8157a4ef387223bb5b0da35edbsalomonvoid GrResourceCache::releaseAll() {
19771cb0c241e439b6ed746b90294d0b6916644a644bsalomon    AutoValidate av(this);
19871cb0c241e439b6ed746b90294d0b6916644a644bsalomon
19913dddce65fd87a8175a209a49f35615735a2886aBrian Osman    this->processFreedGpuResources();
20013dddce65fd87a8175a209a49f35615735a2886aBrian Osman
2011afd4cdb0800e2e395b465da24eb71e0e834dafaRobert Phillips    SkASSERT(fProxyProvider); // better have called setProxyProvider
2023ec9573ac3fd8b973fe4feda27c109d47cb5defcRobert Phillips    // We must remove the uniqueKeys from the proxies here. While they possess a uniqueKey
2033ec9573ac3fd8b973fe4feda27c109d47cb5defcRobert Phillips    // they also have a raw pointer back to this class (which is presumably going away)!
2041afd4cdb0800e2e395b465da24eb71e0e834dafaRobert Phillips    fProxyProvider->removeAllUniqueKeys();
20545a6f147b0dc47630e75dcfc8f9c4ce816392553Robert Phillips
206f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    while(fNonpurgeableResources.count()) {
207f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon        GrGpuResource* back = *(fNonpurgeableResources.end() - 1);
208f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon        SkASSERT(!back->wasDestroyed());
209f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon        back->cacheAccess().release();
210c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon    }
211f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon
212f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    while (fPurgeableQueue.count()) {
213f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon        GrGpuResource* top = fPurgeableQueue.peek();
214f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon        SkASSERT(!top->wasDestroyed());
215f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon        top->cacheAccess().release();
216f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    }
217f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon
218744998e666073166307d2522847b2536000a7619bsalomon    SkASSERT(!fScratchMap.count());
2198718aafec239c93485e45bbe8fed19d9a8def079bsalomon    SkASSERT(!fUniqueHash.count());
220c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon    SkASSERT(!fCount);
221f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    SkASSERT(!this->getResourceCount());
222dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon    SkASSERT(!fBytes);
223dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon    SkASSERT(!fBudgetedCount);
224dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon    SkASSERT(!fBudgetedBytes);
225ee47914ae5661043c20754f46523665a6d31bc73Derek Sollenberger    SkASSERT(!fPurgeableBytes);
226c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon}
227bcf0a52d4f4221b158e68a06ba0c4cc4db011060bsalomon
2280ea80f43a1af05b8157a4ef387223bb5b0da35edbsalomonclass GrResourceCache::AvailableForScratchUse {
229bcf0a52d4f4221b158e68a06ba0c4cc4db011060bsalomonpublic:
230000f829f14a9535a005082731af5de1526284c83bsalomon    AvailableForScratchUse(bool rejectPendingIO) : fRejectPendingIO(rejectPendingIO) { }
231bcf0a52d4f4221b158e68a06ba0c4cc4db011060bsalomon
232bcf0a52d4f4221b158e68a06ba0c4cc4db011060bsalomon    bool operator()(const GrGpuResource* resource) const {
233c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips        SkASSERT(!resource->getUniqueKey().isValid() &&
234c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips                 resource->resourcePriv().getScratchKey().isValid());
23512299ab7a1be5f4b99284ecf289d46107ef0a946bsalomon        if (resource->internalHasRef() || !resource->cacheAccess().isScratch()) {
236000f829f14a9535a005082731af5de1526284c83bsalomon            return false;
237bcf0a52d4f4221b158e68a06ba0c4cc4db011060bsalomon        }
238000f829f14a9535a005082731af5de1526284c83bsalomon        return !fRejectPendingIO || !resource->internalHasPendingIO();
239bcf0a52d4f4221b158e68a06ba0c4cc4db011060bsalomon    }
2401e2530babb65a883a01df5ee87147432f6707ce3bsalomon
241bcf0a52d4f4221b158e68a06ba0c4cc4db011060bsalomonprivate:
242000f829f14a9535a005082731af5de1526284c83bsalomon    bool fRejectPendingIO;
243bcf0a52d4f4221b158e68a06ba0c4cc4db011060bsalomon};
244bcf0a52d4f4221b158e68a06ba0c4cc4db011060bsalomon
2450ea80f43a1af05b8157a4ef387223bb5b0da35edbsalomonGrGpuResource* GrResourceCache::findAndRefScratchResource(const GrScratchKey& scratchKey,
2466e83ac778f8f90939abe3aee3ea865428dff592frobertphillips                                                          size_t resourceSize,
2479f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon                                                          uint32_t flags) {
2487775c85611c734a2af709b3a9c127939a4296c48bsalomon    SkASSERT(scratchKey.isValid());
249ee843b2ae4d75748d8bc323287f0c310fad548a7robertphillips
25071cb0c241e439b6ed746b90294d0b6916644a644bsalomon    GrGpuResource* resource;
251000f829f14a9535a005082731af5de1526284c83bsalomon    if (flags & (kPreferNoPendingIO_ScratchFlag | kRequireNoPendingIO_ScratchFlag)) {
25271cb0c241e439b6ed746b90294d0b6916644a644bsalomon        resource = fScratchMap.find(scratchKey, AvailableForScratchUse(true));
253000f829f14a9535a005082731af5de1526284c83bsalomon        if (resource) {
2549f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon            this->refAndMakeResourceMRU(resource);
255b436ed6754452d7acb6c70e70307904c8f4a50e7bsalomon            this->validate();
256b436ed6754452d7acb6c70e70307904c8f4a50e7bsalomon            return resource;
257000f829f14a9535a005082731af5de1526284c83bsalomon        } else if (flags & kRequireNoPendingIO_ScratchFlag) {
25896fcdcc219d2a0d3579719b84b28bede76efba64halcanary            return nullptr;
259000f829f14a9535a005082731af5de1526284c83bsalomon        }
26063926683c583e8497d9d907977e773663cb4bd9erobertphillips        // We would prefer to consume more available VRAM rather than flushing
26163926683c583e8497d9d907977e773663cb4bd9erobertphillips        // immediately, but on ANGLE this can lead to starving of the GPU.
26263926683c583e8497d9d907977e773663cb4bd9erobertphillips        if (fPreferVRAMUseOverFlushes && this->wouldFit(resourceSize)) {
2636e83ac778f8f90939abe3aee3ea865428dff592frobertphillips            // kPrefer is specified, we didn't find a resource without pending io,
26463926683c583e8497d9d907977e773663cb4bd9erobertphillips            // but there is still space in our budget for the resource so force
26563926683c583e8497d9d907977e773663cb4bd9erobertphillips            // the caller to allocate a new resource.
26696fcdcc219d2a0d3579719b84b28bede76efba64halcanary            return nullptr;
2676e83ac778f8f90939abe3aee3ea865428dff592frobertphillips        }
268000f829f14a9535a005082731af5de1526284c83bsalomon    }
26971cb0c241e439b6ed746b90294d0b6916644a644bsalomon    resource = fScratchMap.find(scratchKey, AvailableForScratchUse(false));
27071cb0c241e439b6ed746b90294d0b6916644a644bsalomon    if (resource) {
2719f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon        this->refAndMakeResourceMRU(resource);
272b436ed6754452d7acb6c70e70307904c8f4a50e7bsalomon        this->validate();
27371cb0c241e439b6ed746b90294d0b6916644a644bsalomon    }
27471cb0c241e439b6ed746b90294d0b6916644a644bsalomon    return resource;
275bcf0a52d4f4221b158e68a06ba0c4cc4db011060bsalomon}
2768b79d23f825cd9e0f9e3bf8aaa9e209940b17ef6bsalomon
2770ea80f43a1af05b8157a4ef387223bb5b0da35edbsalomonvoid GrResourceCache::willRemoveScratchKey(const GrGpuResource* resource) {
2783582d3ee9fffdec715f5e4949a241ab08e6271ecbsalomon    SkASSERT(resource->resourcePriv().getScratchKey().isValid());
279c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips    if (!resource->getUniqueKey().isValid()) {
280c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips        fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource);
281c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips    }
28210e23caea3106be125acea10a637789e5a15c728bsalomon}
28310e23caea3106be125acea10a637789e5a15c728bsalomon
284f99e961f55bb603d099c8cb57d05a2ae52a4e9cabsalomonvoid GrResourceCache::removeUniqueKey(GrGpuResource* resource) {
2853f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    // Someone has a ref to this resource in order to have removed the key. When the ref count
2863f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    // reaches zero we will get a ref cnt notification and figure out what to do with it.
287f99e961f55bb603d099c8cb57d05a2ae52a4e9cabsalomon    if (resource->getUniqueKey().isValid()) {
288f99e961f55bb603d099c8cb57d05a2ae52a4e9cabsalomon        SkASSERT(resource == fUniqueHash.find(resource->getUniqueKey()));
289f99e961f55bb603d099c8cb57d05a2ae52a4e9cabsalomon        fUniqueHash.remove(resource->getUniqueKey());
290f99e961f55bb603d099c8cb57d05a2ae52a4e9cabsalomon    }
291f99e961f55bb603d099c8cb57d05a2ae52a4e9cabsalomon    resource->cacheAccess().removeUniqueKey();
292c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips
293c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips    if (resource->resourcePriv().getScratchKey().isValid()) {
294c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips        fScratchMap.insert(resource->resourcePriv().getScratchKey(), resource);
295c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips    }
296c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips
297f99e961f55bb603d099c8cb57d05a2ae52a4e9cabsalomon    this->validate();
29823e619cf462b2a8a500f3ca750e099f79601f508bsalomon}
29923e619cf462b2a8a500f3ca750e099f79601f508bsalomon
300f99e961f55bb603d099c8cb57d05a2ae52a4e9cabsalomonvoid GrResourceCache::changeUniqueKey(GrGpuResource* resource, const GrUniqueKey& newKey) {
3018b79d23f825cd9e0f9e3bf8aaa9e209940b17ef6bsalomon    SkASSERT(resource);
30271cb0c241e439b6ed746b90294d0b6916644a644bsalomon    SkASSERT(this->isInCache(resource));
3038b79d23f825cd9e0f9e3bf8aaa9e209940b17ef6bsalomon
304f99e961f55bb603d099c8cb57d05a2ae52a4e9cabsalomon    // If another resource has the new key, remove its key then install the key on this resource.
305f99e961f55bb603d099c8cb57d05a2ae52a4e9cabsalomon    if (newKey.isValid()) {
3060d53780b8cbf75c0282fb8246a0a3de0026f211bGreg Daniel        if (GrGpuResource* old = fUniqueHash.find(newKey)) {
3070d53780b8cbf75c0282fb8246a0a3de0026f211bGreg Daniel            // If the old resource using the key is purgeable and is unreachable, then remove it.
3080d53780b8cbf75c0282fb8246a0a3de0026f211bGreg Daniel            if (!old->resourcePriv().getScratchKey().isValid() && old->isPurgeable()) {
3090d53780b8cbf75c0282fb8246a0a3de0026f211bGreg Daniel                old->cacheAccess().release();
3100d53780b8cbf75c0282fb8246a0a3de0026f211bGreg Daniel            } else {
3110d53780b8cbf75c0282fb8246a0a3de0026f211bGreg Daniel                this->removeUniqueKey(old);
3120d53780b8cbf75c0282fb8246a0a3de0026f211bGreg Daniel            }
3130d53780b8cbf75c0282fb8246a0a3de0026f211bGreg Daniel        }
3140d53780b8cbf75c0282fb8246a0a3de0026f211bGreg Daniel        SkASSERT(nullptr == fUniqueHash.find(newKey));
3150d53780b8cbf75c0282fb8246a0a3de0026f211bGreg Daniel
316c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips        // Remove the entry for this resource if it already has a unique key.
317c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips        if (resource->getUniqueKey().isValid()) {
318c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips            SkASSERT(resource == fUniqueHash.find(resource->getUniqueKey()));
319c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips            fUniqueHash.remove(resource->getUniqueKey());
320c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips            SkASSERT(nullptr == fUniqueHash.find(resource->getUniqueKey()));
321c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips        } else {
322c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips            // 'resource' didn't have a valid unique key before so it is switching sides. Remove it
323c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips            // from the ScratchMap
324c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips            if (resource->resourcePriv().getScratchKey().isValid()) {
325c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips                fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource);
326c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips            }
327c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips        }
328c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips
329f99e961f55bb603d099c8cb57d05a2ae52a4e9cabsalomon        resource->cacheAccess().setUniqueKey(newKey);
330f99e961f55bb603d099c8cb57d05a2ae52a4e9cabsalomon        fUniqueHash.add(resource);
331f99e961f55bb603d099c8cb57d05a2ae52a4e9cabsalomon    } else {
332c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips        this->removeUniqueKey(resource);
3338b79d23f825cd9e0f9e3bf8aaa9e209940b17ef6bsalomon    }
3348b79d23f825cd9e0f9e3bf8aaa9e209940b17ef6bsalomon
33571cb0c241e439b6ed746b90294d0b6916644a644bsalomon    this->validate();
3368b79d23f825cd9e0f9e3bf8aaa9e209940b17ef6bsalomon}
33771cb0c241e439b6ed746b90294d0b6916644a644bsalomon
3389f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomonvoid GrResourceCache::refAndMakeResourceMRU(GrGpuResource* resource) {
33971cb0c241e439b6ed746b90294d0b6916644a644bsalomon    SkASSERT(resource);
34071cb0c241e439b6ed746b90294d0b6916644a644bsalomon    SkASSERT(this->isInCache(resource));
341ddf30e64fe474847b204d7062fad3341d245062cbsalomon
3429f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon    if (resource->isPurgeable()) {
3439f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon        // It's about to become unpurgeable.
344ee47914ae5661043c20754f46523665a6d31bc73Derek Sollenberger        fPurgeableBytes -= resource->gpuMemorySize();
3459f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon        fPurgeableQueue.remove(resource);
346f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon        this->addToNonpurgeableArray(resource);
3479f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon    }
3489f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon    resource->ref();
349ddf30e64fe474847b204d7062fad3341d245062cbsalomon
350ddf30e64fe474847b204d7062fad3341d245062cbsalomon    resource->cacheAccess().setTimestamp(this->getNextTimestamp());
351f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    this->validate();
35271cb0c241e439b6ed746b90294d0b6916644a644bsalomon}
35371cb0c241e439b6ed746b90294d0b6916644a644bsalomon
3543f324321cdd8fde7976d958e2888a1ec4e657e35bsalomonvoid GrResourceCache::notifyCntReachedZero(GrGpuResource* resource, uint32_t flags) {
35571cb0c241e439b6ed746b90294d0b6916644a644bsalomon    SkASSERT(resource);
3563f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    SkASSERT(!resource->wasDestroyed());
3573f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    SkASSERT(flags);
35871cb0c241e439b6ed746b90294d0b6916644a644bsalomon    SkASSERT(this->isInCache(resource));
3593f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    // This resource should always be in the nonpurgeable array when this function is called. It
3603f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    // will be moved to the queue if it is newly purgeable.
3613f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    SkASSERT(fNonpurgeableResources[*resource->cacheAccess().accessCacheIndex()] == resource);
3623f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon
3633f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    if (SkToBool(ResourceAccess::kRefCntReachedZero_RefNotificationFlag & flags)) {
3643f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon#ifdef SK_DEBUG
3653f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon        // When the timestamp overflows validate() is called. validate() checks that resources in
3663f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon        // the nonpurgeable array are indeed not purgeable. However, the movement from the array to
3673f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon        // the purgeable queue happens just below in this function. So we mark it as an exception.
3683f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon        if (resource->isPurgeable()) {
3693f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon            fNewlyPurgeableResourceForValidation = resource;
3703f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon        }
3713f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon#endif
3723f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon        resource->cacheAccess().setTimestamp(this->getNextTimestamp());
37396fcdcc219d2a0d3579719b84b28bede76efba64halcanary        SkDEBUGCODE(fNewlyPurgeableResourceForValidation = nullptr);
3743f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    }
37571cb0c241e439b6ed746b90294d0b6916644a644bsalomon
3763f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    if (!SkToBool(ResourceAccess::kAllCntsReachedZero_RefNotificationFlag & flags)) {
3773f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon        SkASSERT(!resource->isPurgeable());
3783f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon        return;
3793f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    }
3803f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon
3813f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    SkASSERT(resource->isPurgeable());
382f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    this->removeFromNonpurgeableArray(resource);
3839f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon    fPurgeableQueue.insert(resource);
384e2e87f3484e5524dbfd6c01f402136738d1d434bbsalomon    resource->cacheAccess().setFlushCntWhenResourceBecamePurgeable(fExternalFlushCnt);
3855e150851d0dd5ddb161449b44edf1bf52d18ac5aBrian Salomon    resource->cacheAccess().setTimeWhenResourceBecomePurgeable();
386ee47914ae5661043c20754f46523665a6d31bc73Derek Sollenberger    fPurgeableBytes += resource->gpuMemorySize();
387c2f35b750a57d7dc0b8053a98279631d1ccb9b56bsalomon
3885ec26ae9bfca635ccc98283aad5deda11519d826bsalomon    if (SkBudgeted::kNo == resource->resourcePriv().isBudgeted()) {
389c2f35b750a57d7dc0b8053a98279631d1ccb9b56bsalomon        // Check whether this resource could still be used as a scratch resource.
3902e6055b3ea14a04fcde1ac1974a70bf00b1e295bkkinnunen        if (!resource->resourcePriv().refsWrappedObjects() &&
3919f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon            resource->resourcePriv().getScratchKey().isValid()) {
392c2f35b750a57d7dc0b8053a98279631d1ccb9b56bsalomon            // We won't purge an existing resource to make room for this one.
393f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon            if (fBudgetedCount < fMaxCount &&
394f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon                fBudgetedBytes + resource->gpuMemorySize() <= fMaxBytes) {
3953582d3ee9fffdec715f5e4949a241ab08e6271ecbsalomon                resource->resourcePriv().makeBudgeted();
3969f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon                return;
397c2f35b750a57d7dc0b8053a98279631d1ccb9b56bsalomon            }
398c2f35b750a57d7dc0b8053a98279631d1ccb9b56bsalomon        }
399c2f35b750a57d7dc0b8053a98279631d1ccb9b56bsalomon    } else {
4009f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon        // Purge the resource immediately if we're over budget
4018718aafec239c93485e45bbe8fed19d9a8def079bsalomon        // Also purge if the resource has neither a valid scratch key nor a unique key.
402ee843b2ae4d75748d8bc323287f0c310fad548a7robertphillips        bool noKey = !resource->resourcePriv().getScratchKey().isValid() &&
403ee843b2ae4d75748d8bc323287f0c310fad548a7robertphillips                     !resource->getUniqueKey().isValid();
404ee843b2ae4d75748d8bc323287f0c310fad548a7robertphillips        if (!this->overBudget() && !noKey) {
4059f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon            return;
406c2f35b750a57d7dc0b8053a98279631d1ccb9b56bsalomon        }
407c2f35b750a57d7dc0b8053a98279631d1ccb9b56bsalomon    }
408dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon
409f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    SkDEBUGCODE(int beforeCount = this->getResourceCount();)
4109f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon    resource->cacheAccess().release();
4119f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon    // We should at least free this resource, perhaps dependent resources as well.
412f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    SkASSERT(this->getResourceCount() < beforeCount);
41371cb0c241e439b6ed746b90294d0b6916644a644bsalomon    this->validate();
41471cb0c241e439b6ed746b90294d0b6916644a644bsalomon}
41571cb0c241e439b6ed746b90294d0b6916644a644bsalomon
4160ea80f43a1af05b8157a4ef387223bb5b0da35edbsalomonvoid GrResourceCache::didChangeGpuMemorySize(const GrGpuResource* resource, size_t oldSize) {
41771cb0c241e439b6ed746b90294d0b6916644a644bsalomon    // SkASSERT(!fPurging); GrPathRange increases size during flush. :(
41871cb0c241e439b6ed746b90294d0b6916644a644bsalomon    SkASSERT(resource);
41971cb0c241e439b6ed746b90294d0b6916644a644bsalomon    SkASSERT(this->isInCache(resource));
42071cb0c241e439b6ed746b90294d0b6916644a644bsalomon
421dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon    ptrdiff_t delta = resource->gpuMemorySize() - oldSize;
422dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon
423dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon    fBytes += delta;
42482b1d620137f35fe48bc635bc74f638c9716710bbsalomon#if GR_CACHE_STATS
42582b1d620137f35fe48bc635bc74f638c9716710bbsalomon    fHighWaterBytes = SkTMax(fBytes, fHighWaterBytes);
42682b1d620137f35fe48bc635bc74f638c9716710bbsalomon#endif
4275ec26ae9bfca635ccc98283aad5deda11519d826bsalomon    if (SkBudgeted::kYes == resource->resourcePriv().isBudgeted()) {
428dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon        fBudgetedBytes += delta;
42939c08ac3be30f9956cea7c5e4fd9a1d86e993a65Brian Osman        TRACE_COUNTER2("skia.gpu.cache", "skia budget", "used",
430876c3132d75966829ad58b2f9b2957d50457cc29hendrikw                       fBudgetedBytes, "free", fMaxBytes - fBudgetedBytes);
431dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon#if GR_CACHE_STATS
432dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon        fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes);
433dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon#endif
434dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon    }
43571cb0c241e439b6ed746b90294d0b6916644a644bsalomon
43671cb0c241e439b6ed746b90294d0b6916644a644bsalomon    this->purgeAsNeeded();
43771cb0c241e439b6ed746b90294d0b6916644a644bsalomon    this->validate();
43871cb0c241e439b6ed746b90294d0b6916644a644bsalomon}
43971cb0c241e439b6ed746b90294d0b6916644a644bsalomon
4400ea80f43a1af05b8157a4ef387223bb5b0da35edbsalomonvoid GrResourceCache::didChangeBudgetStatus(GrGpuResource* resource) {
44184c8e62fad59f0e19b40ac718467f5b7884b431dbsalomon    SkASSERT(resource);
44284c8e62fad59f0e19b40ac718467f5b7884b431dbsalomon    SkASSERT(this->isInCache(resource));
44384c8e62fad59f0e19b40ac718467f5b7884b431dbsalomon
44484c8e62fad59f0e19b40ac718467f5b7884b431dbsalomon    size_t size = resource->gpuMemorySize();
44584c8e62fad59f0e19b40ac718467f5b7884b431dbsalomon
4465ec26ae9bfca635ccc98283aad5deda11519d826bsalomon    if (SkBudgeted::kYes == resource->resourcePriv().isBudgeted()) {
44784c8e62fad59f0e19b40ac718467f5b7884b431dbsalomon        ++fBudgetedCount;
44884c8e62fad59f0e19b40ac718467f5b7884b431dbsalomon        fBudgetedBytes += size;
449afe3005be3392e43bc51eb7eb2017eefaed85ad1bsalomon#if GR_CACHE_STATS
450afe3005be3392e43bc51eb7eb2017eefaed85ad1bsalomon        fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes);
451afe3005be3392e43bc51eb7eb2017eefaed85ad1bsalomon        fBudgetedHighWaterCount = SkTMax(fBudgetedCount, fBudgetedHighWaterCount);
452afe3005be3392e43bc51eb7eb2017eefaed85ad1bsalomon#endif
45384c8e62fad59f0e19b40ac718467f5b7884b431dbsalomon        this->purgeAsNeeded();
45484c8e62fad59f0e19b40ac718467f5b7884b431dbsalomon    } else {
45584c8e62fad59f0e19b40ac718467f5b7884b431dbsalomon        --fBudgetedCount;
45684c8e62fad59f0e19b40ac718467f5b7884b431dbsalomon        fBudgetedBytes -= size;
45784c8e62fad59f0e19b40ac718467f5b7884b431dbsalomon    }
45839c08ac3be30f9956cea7c5e4fd9a1d86e993a65Brian Osman    TRACE_COUNTER2("skia.gpu.cache", "skia budget", "used",
459876c3132d75966829ad58b2f9b2957d50457cc29hendrikw                   fBudgetedBytes, "free", fMaxBytes - fBudgetedBytes);
46084c8e62fad59f0e19b40ac718467f5b7884b431dbsalomon
46184c8e62fad59f0e19b40ac718467f5b7884b431dbsalomon    this->validate();
46284c8e62fad59f0e19b40ac718467f5b7884b431dbsalomon}
46384c8e62fad59f0e19b40ac718467f5b7884b431dbsalomon
464ee843b2ae4d75748d8bc323287f0c310fad548a7robertphillipsvoid GrResourceCache::purgeAsNeeded() {
4653f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    SkTArray<GrUniqueKeyInvalidatedMessage> invalidKeyMsgs;
4663f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    fInvalidUniqueKeyInbox.poll(&invalidKeyMsgs);
4673f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    if (invalidKeyMsgs.count()) {
4683f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon        this->processInvalidUniqueKeys(invalidKeyMsgs);
4693f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    }
47071cb0c241e439b6ed746b90294d0b6916644a644bsalomon
47113dddce65fd87a8175a209a49f35615735a2886aBrian Osman    this->processFreedGpuResources();
47213dddce65fd87a8175a209a49f35615735a2886aBrian Osman
473e2e87f3484e5524dbfd6c01f402136738d1d434bbsalomon    if (fMaxUnusedFlushes > 0) {
474e2e87f3484e5524dbfd6c01f402136738d1d434bbsalomon        // We want to know how many complete flushes have occurred without the resource being used.
475e2e87f3484e5524dbfd6c01f402136738d1d434bbsalomon        // If the resource was tagged when fExternalFlushCnt was N then this means it became
476e2e87f3484e5524dbfd6c01f402136738d1d434bbsalomon        // purgeable during activity that became the N+1th flush. So when the flush count is N+2
477e2e87f3484e5524dbfd6c01f402136738d1d434bbsalomon        // it has sat in the purgeable queue for one entire flush.
478e2e87f3484e5524dbfd6c01f402136738d1d434bbsalomon        uint32_t oldestAllowedFlushCnt = fExternalFlushCnt - fMaxUnusedFlushes - 1;
479e2e87f3484e5524dbfd6c01f402136738d1d434bbsalomon        // check for underflow
480e2e87f3484e5524dbfd6c01f402136738d1d434bbsalomon        if (oldestAllowedFlushCnt < fExternalFlushCnt) {
481e2e87f3484e5524dbfd6c01f402136738d1d434bbsalomon            while (fPurgeableQueue.count()) {
482e2e87f3484e5524dbfd6c01f402136738d1d434bbsalomon                uint32_t flushWhenResourceBecamePurgeable =
483e2e87f3484e5524dbfd6c01f402136738d1d434bbsalomon                        fPurgeableQueue.peek()->cacheAccess().flushCntWhenResourceBecamePurgeable();
484e2e87f3484e5524dbfd6c01f402136738d1d434bbsalomon                if (oldestAllowedFlushCnt < flushWhenResourceBecamePurgeable) {
485e2e87f3484e5524dbfd6c01f402136738d1d434bbsalomon                    // Resources were given both LRU timestamps and tagged with a flush cnt when
486e2e87f3484e5524dbfd6c01f402136738d1d434bbsalomon                    // they first became purgeable. The LRU timestamp won't change again until the
487e2e87f3484e5524dbfd6c01f402136738d1d434bbsalomon                    // resource is made non-purgeable again. So, at this point all the remaining
488e2e87f3484e5524dbfd6c01f402136738d1d434bbsalomon                    // resources in the timestamp-sorted queue will have a flush count >= to this
489e2e87f3484e5524dbfd6c01f402136738d1d434bbsalomon                    // one.
490e2e87f3484e5524dbfd6c01f402136738d1d434bbsalomon                    break;
491e2e87f3484e5524dbfd6c01f402136738d1d434bbsalomon                }
492e2e87f3484e5524dbfd6c01f402136738d1d434bbsalomon                GrGpuResource* resource = fPurgeableQueue.peek();
493e2e87f3484e5524dbfd6c01f402136738d1d434bbsalomon                SkASSERT(resource->isPurgeable());
494e2e87f3484e5524dbfd6c01f402136738d1d434bbsalomon                resource->cacheAccess().release();
4953f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon            }
4963f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon        }
4973f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    }
4983f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon
4993f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    bool stillOverbudget = this->overBudget();
5003f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    while (stillOverbudget && fPurgeableQueue.count()) {
501ee843b2ae4d75748d8bc323287f0c310fad548a7robertphillips        GrGpuResource* resource = fPurgeableQueue.peek();
5029f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon        SkASSERT(resource->isPurgeable());
5039f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon        resource->cacheAccess().release();
5043f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon        stillOverbudget = this->overBudget();
5059f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon    }
50671cb0c241e439b6ed746b90294d0b6916644a644bsalomon
507b436ed6754452d7acb6c70e70307904c8f4a50e7bsalomon    this->validate();
508ee843b2ae4d75748d8bc323287f0c310fad548a7robertphillips
509ee843b2ae4d75748d8bc323287f0c310fad548a7robertphillips    if (stillOverbudget) {
510ee843b2ae4d75748d8bc323287f0c310fad548a7robertphillips        // Set this so that GrDrawingManager will issue a flush to free up resources with pending
511ee843b2ae4d75748d8bc323287f0c310fad548a7robertphillips        // IO that we were unable to purge in this pass.
512ee843b2ae4d75748d8bc323287f0c310fad548a7robertphillips        fRequestFlush = true;
513ee843b2ae4d75748d8bc323287f0c310fad548a7robertphillips    }
51471cb0c241e439b6ed746b90294d0b6916644a644bsalomon}
51571cb0c241e439b6ed746b90294d0b6916644a644bsalomon
51647710a52505e9b8d2ae6ef8521f6b7a022542b9eRobert Phillipsvoid GrResourceCache::purgeUnlockedResources(bool scratchResourcesOnly) {
51747710a52505e9b8d2ae6ef8521f6b7a022542b9eRobert Phillips    if (!scratchResourcesOnly) {
51847710a52505e9b8d2ae6ef8521f6b7a022542b9eRobert Phillips        // We could disable maintaining the heap property here, but it would add a lot of
51947710a52505e9b8d2ae6ef8521f6b7a022542b9eRobert Phillips        // complexity. Moreover, this is rarely called.
52047710a52505e9b8d2ae6ef8521f6b7a022542b9eRobert Phillips        while (fPurgeableQueue.count()) {
52147710a52505e9b8d2ae6ef8521f6b7a022542b9eRobert Phillips            GrGpuResource* resource = fPurgeableQueue.peek();
52247710a52505e9b8d2ae6ef8521f6b7a022542b9eRobert Phillips            SkASSERT(resource->isPurgeable());
52347710a52505e9b8d2ae6ef8521f6b7a022542b9eRobert Phillips            resource->cacheAccess().release();
52447710a52505e9b8d2ae6ef8521f6b7a022542b9eRobert Phillips        }
52547710a52505e9b8d2ae6ef8521f6b7a022542b9eRobert Phillips    } else {
52647710a52505e9b8d2ae6ef8521f6b7a022542b9eRobert Phillips        // Sort the queue
52747710a52505e9b8d2ae6ef8521f6b7a022542b9eRobert Phillips        fPurgeableQueue.sort();
52847710a52505e9b8d2ae6ef8521f6b7a022542b9eRobert Phillips
52947710a52505e9b8d2ae6ef8521f6b7a022542b9eRobert Phillips        // Make a list of the scratch resources to delete
53047710a52505e9b8d2ae6ef8521f6b7a022542b9eRobert Phillips        SkTDArray<GrGpuResource*> scratchResources;
53147710a52505e9b8d2ae6ef8521f6b7a022542b9eRobert Phillips        for (int i = 0; i < fPurgeableQueue.count(); i++) {
53247710a52505e9b8d2ae6ef8521f6b7a022542b9eRobert Phillips            GrGpuResource* resource = fPurgeableQueue.at(i);
53347710a52505e9b8d2ae6ef8521f6b7a022542b9eRobert Phillips            SkASSERT(resource->isPurgeable());
53447710a52505e9b8d2ae6ef8521f6b7a022542b9eRobert Phillips            if (!resource->getUniqueKey().isValid()) {
53547710a52505e9b8d2ae6ef8521f6b7a022542b9eRobert Phillips                *scratchResources.append() = resource;
53647710a52505e9b8d2ae6ef8521f6b7a022542b9eRobert Phillips            }
53747710a52505e9b8d2ae6ef8521f6b7a022542b9eRobert Phillips        }
53847710a52505e9b8d2ae6ef8521f6b7a022542b9eRobert Phillips
53947710a52505e9b8d2ae6ef8521f6b7a022542b9eRobert Phillips        // Delete the scratch resources. This must be done as a separate pass
54047710a52505e9b8d2ae6ef8521f6b7a022542b9eRobert Phillips        // to avoid messing up the sorted order of the queue
54147710a52505e9b8d2ae6ef8521f6b7a022542b9eRobert Phillips        for (int i = 0; i < scratchResources.count(); i++) {
54247710a52505e9b8d2ae6ef8521f6b7a022542b9eRobert Phillips            scratchResources.getAt(i)->cacheAccess().release();
54347710a52505e9b8d2ae6ef8521f6b7a022542b9eRobert Phillips        }
5449f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon    }
54571cb0c241e439b6ed746b90294d0b6916644a644bsalomon
546b436ed6754452d7acb6c70e70307904c8f4a50e7bsalomon    this->validate();
54771cb0c241e439b6ed746b90294d0b6916644a644bsalomon}
54871cb0c241e439b6ed746b90294d0b6916644a644bsalomon
5495e150851d0dd5ddb161449b44edf1bf52d18ac5aBrian Salomonvoid GrResourceCache::purgeResourcesNotUsedSince(GrStdSteadyClock::time_point purgeTime) {
5505e150851d0dd5ddb161449b44edf1bf52d18ac5aBrian Salomon    while (fPurgeableQueue.count()) {
5515e150851d0dd5ddb161449b44edf1bf52d18ac5aBrian Salomon        const GrStdSteadyClock::time_point resourceTime =
5525e150851d0dd5ddb161449b44edf1bf52d18ac5aBrian Salomon                fPurgeableQueue.peek()->cacheAccess().timeWhenResourceBecamePurgeable();
5535e150851d0dd5ddb161449b44edf1bf52d18ac5aBrian Salomon        if (resourceTime >= purgeTime) {
5545e150851d0dd5ddb161449b44edf1bf52d18ac5aBrian Salomon            // Resources were given both LRU timestamps and tagged with a frame number when
5555e150851d0dd5ddb161449b44edf1bf52d18ac5aBrian Salomon            // they first became purgeable. The LRU timestamp won't change again until the
5565e150851d0dd5ddb161449b44edf1bf52d18ac5aBrian Salomon            // resource is made non-purgeable again. So, at this point all the remaining
5575e150851d0dd5ddb161449b44edf1bf52d18ac5aBrian Salomon            // resources in the timestamp-sorted queue will have a frame number >= to this
5585e150851d0dd5ddb161449b44edf1bf52d18ac5aBrian Salomon            // one.
5595e150851d0dd5ddb161449b44edf1bf52d18ac5aBrian Salomon            break;
5605e150851d0dd5ddb161449b44edf1bf52d18ac5aBrian Salomon        }
5615e150851d0dd5ddb161449b44edf1bf52d18ac5aBrian Salomon        GrGpuResource* resource = fPurgeableQueue.peek();
5625e150851d0dd5ddb161449b44edf1bf52d18ac5aBrian Salomon        SkASSERT(resource->isPurgeable());
5635e150851d0dd5ddb161449b44edf1bf52d18ac5aBrian Salomon        resource->cacheAccess().release();
5645e150851d0dd5ddb161449b44edf1bf52d18ac5aBrian Salomon    }
5655e150851d0dd5ddb161449b44edf1bf52d18ac5aBrian Salomon}
5665e150851d0dd5ddb161449b44edf1bf52d18ac5aBrian Salomon
5675480a18d8799511034d0da219c72932cd8f25274Derek Sollenbergervoid GrResourceCache::purgeUnlockedResources(size_t bytesToPurge, bool preferScratchResources) {
5685480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger
5695480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger    const size_t tmpByteBudget = SkTMax((size_t)0, fBytes - bytesToPurge);
5705480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger    bool stillOverbudget = tmpByteBudget < fBytes;
5715480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger
5725480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger    if (preferScratchResources && bytesToPurge < fPurgeableBytes) {
5735480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger        // Sort the queue
5745480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger        fPurgeableQueue.sort();
5755480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger
5765480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger        // Make a list of the scratch resources to delete
5775480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger        SkTDArray<GrGpuResource*> scratchResources;
5785480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger        size_t scratchByteCount = 0;
5795480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger        for (int i = 0; i < fPurgeableQueue.count() && stillOverbudget; i++) {
5805480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger            GrGpuResource* resource = fPurgeableQueue.at(i);
5815480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger            SkASSERT(resource->isPurgeable());
5825480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger            if (!resource->getUniqueKey().isValid()) {
5835480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger                *scratchResources.append() = resource;
5845480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger                scratchByteCount += resource->gpuMemorySize();
5855480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger                stillOverbudget = tmpByteBudget < fBytes - scratchByteCount;
5865480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger            }
5875480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger        }
5885480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger
5895480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger        // Delete the scratch resources. This must be done as a separate pass
5905480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger        // to avoid messing up the sorted order of the queue
5915480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger        for (int i = 0; i < scratchResources.count(); i++) {
5925480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger            scratchResources.getAt(i)->cacheAccess().release();
5935480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger        }
5945480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger        stillOverbudget = tmpByteBudget < fBytes;
5955480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger
5965480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger        this->validate();
5975480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger    }
5985480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger
5995480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger    // Purge any remaining resources in LRU order
6005480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger    if (stillOverbudget) {
6015480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger        const size_t cachedByteCount = fMaxBytes;
6025480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger        fMaxBytes = tmpByteBudget;
6035480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger        this->purgeAsNeeded();
6045480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger        fMaxBytes = cachedByteCount;
6055480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger    }
6065480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger}
6075480a18d8799511034d0da219c72932cd8f25274Derek Sollenberger
6088718aafec239c93485e45bbe8fed19d9a8def079bsalomonvoid GrResourceCache::processInvalidUniqueKeys(
6091afd4cdb0800e2e395b465da24eb71e0e834dafaRobert Phillips                                            const SkTArray<GrUniqueKeyInvalidatedMessage>& msgs) {
6101afd4cdb0800e2e395b465da24eb71e0e834dafaRobert Phillips    SkASSERT(fProxyProvider); // better have called setProxyProvider
6111afd4cdb0800e2e395b465da24eb71e0e834dafaRobert Phillips
61223e619cf462b2a8a500f3ca750e099f79601f508bsalomon    for (int i = 0; i < msgs.count(); ++i) {
6131afd4cdb0800e2e395b465da24eb71e0e834dafaRobert Phillips        fProxyProvider->processInvalidProxyUniqueKey(msgs[i].key());
614ae7d3f3992708354a3284bb49066737e36a76f40Robert Phillips
6158718aafec239c93485e45bbe8fed19d9a8def079bsalomon        GrGpuResource* resource = this->findAndRefUniqueResource(msgs[i].key());
61623e619cf462b2a8a500f3ca750e099f79601f508bsalomon        if (resource) {
6178718aafec239c93485e45bbe8fed19d9a8def079bsalomon            resource->resourcePriv().removeUniqueKey();
6183f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon            resource->unref(); // If this resource is now purgeable, the cache will be notified.
61923e619cf462b2a8a500f3ca750e099f79601f508bsalomon        }
62023e619cf462b2a8a500f3ca750e099f79601f508bsalomon    }
62123e619cf462b2a8a500f3ca750e099f79601f508bsalomon}
62223e619cf462b2a8a500f3ca750e099f79601f508bsalomon
62313dddce65fd87a8175a209a49f35615735a2886aBrian Osmanvoid GrResourceCache::insertCrossContextGpuResource(GrGpuResource* resource) {
62413dddce65fd87a8175a209a49f35615735a2886aBrian Osman    resource->ref();
62513dddce65fd87a8175a209a49f35615735a2886aBrian Osman}
62613dddce65fd87a8175a209a49f35615735a2886aBrian Osman
62713dddce65fd87a8175a209a49f35615735a2886aBrian Osmanvoid GrResourceCache::processFreedGpuResources() {
62813dddce65fd87a8175a209a49f35615735a2886aBrian Osman    SkTArray<GrGpuResourceFreedMessage> msgs;
62913dddce65fd87a8175a209a49f35615735a2886aBrian Osman    fFreedGpuResourceInbox.poll(&msgs);
63013dddce65fd87a8175a209a49f35615735a2886aBrian Osman    for (int i = 0; i < msgs.count(); ++i) {
63113dddce65fd87a8175a209a49f35615735a2886aBrian Osman        if (msgs[i].fOwningUniqueID == fContextUniqueID) {
63213dddce65fd87a8175a209a49f35615735a2886aBrian Osman            msgs[i].fResource->unref();
63313dddce65fd87a8175a209a49f35615735a2886aBrian Osman        }
63413dddce65fd87a8175a209a49f35615735a2886aBrian Osman    }
63513dddce65fd87a8175a209a49f35615735a2886aBrian Osman}
63613dddce65fd87a8175a209a49f35615735a2886aBrian Osman
637f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomonvoid GrResourceCache::addToNonpurgeableArray(GrGpuResource* resource) {
638f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    int index = fNonpurgeableResources.count();
639f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    *fNonpurgeableResources.append() = resource;
640f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    *resource->cacheAccess().accessCacheIndex() = index;
641f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon}
642f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon
643f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomonvoid GrResourceCache::removeFromNonpurgeableArray(GrGpuResource* resource) {
644f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    int* index = resource->cacheAccess().accessCacheIndex();
645f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    // Fill the whole we will create in the array with the tail object, adjust its index, and
646f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    // then pop the array
647f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    GrGpuResource* tail = *(fNonpurgeableResources.end() - 1);
648f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    SkASSERT(fNonpurgeableResources[*index] == resource);
649f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    fNonpurgeableResources[*index] = tail;
650f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    *tail->cacheAccess().accessCacheIndex() = *index;
651f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    fNonpurgeableResources.pop();
652f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    SkDEBUGCODE(*index = -1);
653f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon}
654f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon
655ddf30e64fe474847b204d7062fad3341d245062cbsalomonuint32_t GrResourceCache::getNextTimestamp() {
656ddf30e64fe474847b204d7062fad3341d245062cbsalomon    // If we wrap then all the existing resources will appear older than any resources that get
657ddf30e64fe474847b204d7062fad3341d245062cbsalomon    // a timestamp after the wrap.
658ddf30e64fe474847b204d7062fad3341d245062cbsalomon    if (0 == fTimestamp) {
659ddf30e64fe474847b204d7062fad3341d245062cbsalomon        int count = this->getResourceCount();
660ddf30e64fe474847b204d7062fad3341d245062cbsalomon        if (count) {
661ddf30e64fe474847b204d7062fad3341d245062cbsalomon            // Reset all the timestamps. We sort the resources by timestamp and then assign
662ddf30e64fe474847b204d7062fad3341d245062cbsalomon            // sequential timestamps beginning with 0. This is O(n*lg(n)) but it should be extremely
663ddf30e64fe474847b204d7062fad3341d245062cbsalomon            // rare.
664ddf30e64fe474847b204d7062fad3341d245062cbsalomon            SkTDArray<GrGpuResource*> sortedPurgeableResources;
665ddf30e64fe474847b204d7062fad3341d245062cbsalomon            sortedPurgeableResources.setReserve(fPurgeableQueue.count());
666ddf30e64fe474847b204d7062fad3341d245062cbsalomon
667ddf30e64fe474847b204d7062fad3341d245062cbsalomon            while (fPurgeableQueue.count()) {
668ddf30e64fe474847b204d7062fad3341d245062cbsalomon                *sortedPurgeableResources.append() = fPurgeableQueue.peek();
669ddf30e64fe474847b204d7062fad3341d245062cbsalomon                fPurgeableQueue.pop();
670ddf30e64fe474847b204d7062fad3341d245062cbsalomon            }
671ee843b2ae4d75748d8bc323287f0c310fad548a7robertphillips
672e2e87f3484e5524dbfd6c01f402136738d1d434bbsalomon            SkTQSort(fNonpurgeableResources.begin(), fNonpurgeableResources.end() - 1,
673e2e87f3484e5524dbfd6c01f402136738d1d434bbsalomon                     CompareTimestamp);
674ddf30e64fe474847b204d7062fad3341d245062cbsalomon
675ddf30e64fe474847b204d7062fad3341d245062cbsalomon            // Pick resources out of the purgeable and non-purgeable arrays based on lowest
676ddf30e64fe474847b204d7062fad3341d245062cbsalomon            // timestamp and assign new timestamps.
677ddf30e64fe474847b204d7062fad3341d245062cbsalomon            int currP = 0;
678ddf30e64fe474847b204d7062fad3341d245062cbsalomon            int currNP = 0;
679ddf30e64fe474847b204d7062fad3341d245062cbsalomon            while (currP < sortedPurgeableResources.count() &&
68056da02502019cfbb817898e37e320539b9838e2bmtklein                   currNP < fNonpurgeableResources.count()) {
681ddf30e64fe474847b204d7062fad3341d245062cbsalomon                uint32_t tsP = sortedPurgeableResources[currP]->cacheAccess().timestamp();
682ddf30e64fe474847b204d7062fad3341d245062cbsalomon                uint32_t tsNP = fNonpurgeableResources[currNP]->cacheAccess().timestamp();
683ddf30e64fe474847b204d7062fad3341d245062cbsalomon                SkASSERT(tsP != tsNP);
684ddf30e64fe474847b204d7062fad3341d245062cbsalomon                if (tsP < tsNP) {
685ddf30e64fe474847b204d7062fad3341d245062cbsalomon                    sortedPurgeableResources[currP++]->cacheAccess().setTimestamp(fTimestamp++);
686ddf30e64fe474847b204d7062fad3341d245062cbsalomon                } else {
687ddf30e64fe474847b204d7062fad3341d245062cbsalomon                    // Correct the index in the nonpurgeable array stored on the resource post-sort.
688ddf30e64fe474847b204d7062fad3341d245062cbsalomon                    *fNonpurgeableResources[currNP]->cacheAccess().accessCacheIndex() = currNP;
689ddf30e64fe474847b204d7062fad3341d245062cbsalomon                    fNonpurgeableResources[currNP++]->cacheAccess().setTimestamp(fTimestamp++);
690ddf30e64fe474847b204d7062fad3341d245062cbsalomon                }
691ddf30e64fe474847b204d7062fad3341d245062cbsalomon            }
692ddf30e64fe474847b204d7062fad3341d245062cbsalomon
693ddf30e64fe474847b204d7062fad3341d245062cbsalomon            // The above loop ended when we hit the end of one array. Finish the other one.
694ddf30e64fe474847b204d7062fad3341d245062cbsalomon            while (currP < sortedPurgeableResources.count()) {
695ddf30e64fe474847b204d7062fad3341d245062cbsalomon                sortedPurgeableResources[currP++]->cacheAccess().setTimestamp(fTimestamp++);
696ddf30e64fe474847b204d7062fad3341d245062cbsalomon            }
697ddf30e64fe474847b204d7062fad3341d245062cbsalomon            while (currNP < fNonpurgeableResources.count()) {
698ddf30e64fe474847b204d7062fad3341d245062cbsalomon                *fNonpurgeableResources[currNP]->cacheAccess().accessCacheIndex() = currNP;
699ddf30e64fe474847b204d7062fad3341d245062cbsalomon                fNonpurgeableResources[currNP++]->cacheAccess().setTimestamp(fTimestamp++);
700ddf30e64fe474847b204d7062fad3341d245062cbsalomon            }
701ddf30e64fe474847b204d7062fad3341d245062cbsalomon
702ddf30e64fe474847b204d7062fad3341d245062cbsalomon            // Rebuild the queue.
703ddf30e64fe474847b204d7062fad3341d245062cbsalomon            for (int i = 0; i < sortedPurgeableResources.count(); ++i) {
704ddf30e64fe474847b204d7062fad3341d245062cbsalomon                fPurgeableQueue.insert(sortedPurgeableResources[i]);
705ddf30e64fe474847b204d7062fad3341d245062cbsalomon            }
706ddf30e64fe474847b204d7062fad3341d245062cbsalomon
707ddf30e64fe474847b204d7062fad3341d245062cbsalomon            this->validate();
708ddf30e64fe474847b204d7062fad3341d245062cbsalomon            SkASSERT(count == this->getResourceCount());
709ddf30e64fe474847b204d7062fad3341d245062cbsalomon
710ddf30e64fe474847b204d7062fad3341d245062cbsalomon            // count should be the next timestamp we return.
711ddf30e64fe474847b204d7062fad3341d245062cbsalomon            SkASSERT(fTimestamp == SkToU32(count));
71256da02502019cfbb817898e37e320539b9838e2bmtklein        }
713ddf30e64fe474847b204d7062fad3341d245062cbsalomon    }
714ddf30e64fe474847b204d7062fad3341d245062cbsalomon    return fTimestamp++;
715ddf30e64fe474847b204d7062fad3341d245062cbsalomon}
716ddf30e64fe474847b204d7062fad3341d245062cbsalomon
717b77a907c2fb4402b7e70e9fff70eb71482354e67bsalomonvoid GrResourceCache::notifyFlushOccurred(FlushType type) {
718b77a907c2fb4402b7e70e9fff70eb71482354e67bsalomon    switch (type) {
719b77a907c2fb4402b7e70e9fff70eb71482354e67bsalomon        case FlushType::kCacheRequested:
720ee843b2ae4d75748d8bc323287f0c310fad548a7robertphillips            SkASSERT(fRequestFlush);
721ee843b2ae4d75748d8bc323287f0c310fad548a7robertphillips            fRequestFlush = false;
722b77a907c2fb4402b7e70e9fff70eb71482354e67bsalomon            break;
723ee843b2ae4d75748d8bc323287f0c310fad548a7robertphillips        case FlushType::kExternal:
724e2e87f3484e5524dbfd6c01f402136738d1d434bbsalomon            ++fExternalFlushCnt;
725e2e87f3484e5524dbfd6c01f402136738d1d434bbsalomon            if (0 == fExternalFlushCnt) {
726e2e87f3484e5524dbfd6c01f402136738d1d434bbsalomon                // When this wraps just reset all the purgeable resources' last used flush state.
727e2e87f3484e5524dbfd6c01f402136738d1d434bbsalomon                for (int i = 0; i < fPurgeableQueue.count(); ++i) {
728e2e87f3484e5524dbfd6c01f402136738d1d434bbsalomon                    fPurgeableQueue.at(i)->cacheAccess().setFlushCntWhenResourceBecamePurgeable(0);
729e2e87f3484e5524dbfd6c01f402136738d1d434bbsalomon                }
730b77a907c2fb4402b7e70e9fff70eb71482354e67bsalomon            }
731b77a907c2fb4402b7e70e9fff70eb71482354e67bsalomon            break;
7323f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    }
733ee843b2ae4d75748d8bc323287f0c310fad548a7robertphillips    this->purgeAsNeeded();
7343f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon}
7353f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon
7360a5fa484fd58d27088f8696bdc11c8cc8f2b4866ericrkvoid GrResourceCache::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
7370a5fa484fd58d27088f8696bdc11c8cc8f2b4866ericrk    for (int i = 0; i < fNonpurgeableResources.count(); ++i) {
7380a5fa484fd58d27088f8696bdc11c8cc8f2b4866ericrk        fNonpurgeableResources[i]->dumpMemoryStatistics(traceMemoryDump);
7390a5fa484fd58d27088f8696bdc11c8cc8f2b4866ericrk    }
7400a5fa484fd58d27088f8696bdc11c8cc8f2b4866ericrk    for (int i = 0; i < fPurgeableQueue.count(); ++i) {
7410a5fa484fd58d27088f8696bdc11c8cc8f2b4866ericrk        fPurgeableQueue.at(i)->dumpMemoryStatistics(traceMemoryDump);
7420a5fa484fd58d27088f8696bdc11c8cc8f2b4866ericrk    }
7430a5fa484fd58d27088f8696bdc11c8cc8f2b4866ericrk}
7440a5fa484fd58d27088f8696bdc11c8cc8f2b4866ericrk
74571cb0c241e439b6ed746b90294d0b6916644a644bsalomon#ifdef SK_DEBUG
7460ea80f43a1af05b8157a4ef387223bb5b0da35edbsalomonvoid GrResourceCache::validate() const {
747c2f35b750a57d7dc0b8053a98279631d1ccb9b56bsalomon    // Reduce the frequency of validations for large resource counts.
748c2f35b750a57d7dc0b8053a98279631d1ccb9b56bsalomon    static SkRandom gRandom;
749c2f35b750a57d7dc0b8053a98279631d1ccb9b56bsalomon    int mask = (SkNextPow2(fCount + 1) >> 5) - 1;
750c2f35b750a57d7dc0b8053a98279631d1ccb9b56bsalomon    if (~mask && (gRandom.nextU() & mask)) {
751c2f35b750a57d7dc0b8053a98279631d1ccb9b56bsalomon        return;
752c2f35b750a57d7dc0b8053a98279631d1ccb9b56bsalomon    }
753c2f35b750a57d7dc0b8053a98279631d1ccb9b56bsalomon
754f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    struct Stats {
755f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon        size_t fBytes;
756f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon        int fBudgetedCount;
757f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon        size_t fBudgetedBytes;
758f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon        int fLocked;
759f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon        int fScratch;
760f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon        int fCouldBeScratch;
761f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon        int fContent;
762f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon        const ScratchMap* fScratchMap;
7638718aafec239c93485e45bbe8fed19d9a8def079bsalomon        const UniqueHash* fUniqueHash;
764f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon
765f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon        Stats(const GrResourceCache* cache) {
766f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon            memset(this, 0, sizeof(*this));
767f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon            fScratchMap = &cache->fScratchMap;
7688718aafec239c93485e45bbe8fed19d9a8def079bsalomon            fUniqueHash = &cache->fUniqueHash;
76971cb0c241e439b6ed746b90294d0b6916644a644bsalomon        }
77071cb0c241e439b6ed746b90294d0b6916644a644bsalomon
771f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon        void update(GrGpuResource* resource) {
772f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon            fBytes += resource->gpuMemorySize();
773dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon
774f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon            if (!resource->isPurgeable()) {
775f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon                ++fLocked;
776f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon            }
7779f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon
778c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips            const GrScratchKey& scratchKey = resource->resourcePriv().getScratchKey();
779c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips            const GrUniqueKey& uniqueKey = resource->getUniqueKey();
780c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips
781f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon            if (resource->cacheAccess().isScratch()) {
782c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips                SkASSERT(!uniqueKey.isValid());
783f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon                ++fScratch;
784c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips                SkASSERT(fScratchMap->countForKey(scratchKey));
7852e6055b3ea14a04fcde1ac1974a70bf00b1e295bkkinnunen                SkASSERT(!resource->resourcePriv().refsWrappedObjects());
786c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips            } else if (scratchKey.isValid()) {
7875ec26ae9bfca635ccc98283aad5deda11519d826bsalomon                SkASSERT(SkBudgeted::kNo == resource->resourcePriv().isBudgeted() ||
788c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips                         uniqueKey.isValid());
789c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips                if (!uniqueKey.isValid()) {
7904e97607d9a1cef66fac16f347c5ca813ec4f9515mtklein                    ++fCouldBeScratch;
791c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips                    SkASSERT(fScratchMap->countForKey(scratchKey));
792c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips                }
7932e6055b3ea14a04fcde1ac1974a70bf00b1e295bkkinnunen                SkASSERT(!resource->resourcePriv().refsWrappedObjects());
794f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon            }
7958718aafec239c93485e45bbe8fed19d9a8def079bsalomon            if (uniqueKey.isValid()) {
796f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon                ++fContent;
7978718aafec239c93485e45bbe8fed19d9a8def079bsalomon                SkASSERT(fUniqueHash->find(uniqueKey) == resource);
7980562eb9c6c98f07732ca96a1dd4e986f1ca089b8Brian Osman                SkASSERT(SkBudgeted::kYes == resource->resourcePriv().isBudgeted() ||
7990562eb9c6c98f07732ca96a1dd4e986f1ca089b8Brian Osman                         resource->resourcePriv().refsWrappedObjects());
800c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips
801c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips                if (scratchKey.isValid()) {
802c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips                    SkASSERT(!fScratchMap->has(resource, scratchKey));
803c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips                }
804f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon            }
805f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon
8065ec26ae9bfca635ccc98283aad5deda11519d826bsalomon            if (SkBudgeted::kYes == resource->resourcePriv().isBudgeted()) {
807f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon                ++fBudgetedCount;
808f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon                fBudgetedBytes += resource->gpuMemorySize();
809f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon            }
8109f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon        }
811f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    };
8129f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon
813c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips    {
814c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips        ScratchMap::ConstIter iter(&fScratchMap);
815c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips
816c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips        int count = 0;
817c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips        for ( ; !iter.done(); ++iter) {
818c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips            const GrGpuResource* resource = *iter;
819c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips            SkASSERT(resource->resourcePriv().getScratchKey().isValid());
820c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips            SkASSERT(!resource->getUniqueKey().isValid());
821c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips            count++;
822c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips        }
823c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips        SkASSERT(count == fScratchMap.count()); // ensure the iterator is working correctly
824c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips    }
825c4ed68426649dd4ca2c3119cdafdd562d3c3ba28robertphillips
826f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    Stats stats(this);
827ee47914ae5661043c20754f46523665a6d31bc73Derek Sollenberger    size_t purgeableBytes = 0;
828f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon
829f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    for (int i = 0; i < fNonpurgeableResources.count(); ++i) {
8303f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon        SkASSERT(!fNonpurgeableResources[i]->isPurgeable() ||
8313f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon                 fNewlyPurgeableResourceForValidation == fNonpurgeableResources[i]);
832f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon        SkASSERT(*fNonpurgeableResources[i]->cacheAccess().accessCacheIndex() == i);
833f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon        SkASSERT(!fNonpurgeableResources[i]->wasDestroyed());
834f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon        stats.update(fNonpurgeableResources[i]);
835f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    }
8369f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon    for (int i = 0; i < fPurgeableQueue.count(); ++i) {
8379f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon        SkASSERT(fPurgeableQueue.at(i)->isPurgeable());
838f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon        SkASSERT(*fPurgeableQueue.at(i)->cacheAccess().accessCacheIndex() == i);
839f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon        SkASSERT(!fPurgeableQueue.at(i)->wasDestroyed());
840f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon        stats.update(fPurgeableQueue.at(i));
841ee47914ae5661043c20754f46523665a6d31bc73Derek Sollenberger        purgeableBytes += fPurgeableQueue.at(i)->gpuMemorySize();
84271cb0c241e439b6ed746b90294d0b6916644a644bsalomon    }
84371cb0c241e439b6ed746b90294d0b6916644a644bsalomon
844f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    SkASSERT(fCount == this->getResourceCount());
845dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon    SkASSERT(fBudgetedCount <= fCount);
846f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    SkASSERT(fBudgetedBytes <= fBytes);
847f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    SkASSERT(stats.fBytes == fBytes);
848f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    SkASSERT(stats.fBudgetedBytes == fBudgetedBytes);
849f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    SkASSERT(stats.fBudgetedCount == fBudgetedCount);
850ee47914ae5661043c20754f46523665a6d31bc73Derek Sollenberger    SkASSERT(purgeableBytes == fPurgeableBytes);
85171cb0c241e439b6ed746b90294d0b6916644a644bsalomon#if GR_CACHE_STATS
852dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon    SkASSERT(fBudgetedHighWaterCount <= fHighWaterCount);
853dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon    SkASSERT(fBudgetedHighWaterBytes <= fHighWaterBytes);
854f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    SkASSERT(fBytes <= fHighWaterBytes);
855f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    SkASSERT(fCount <= fHighWaterCount);
856f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    SkASSERT(fBudgetedBytes <= fBudgetedHighWaterBytes);
857f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    SkASSERT(fBudgetedCount <= fBudgetedHighWaterCount);
85871cb0c241e439b6ed746b90294d0b6916644a644bsalomon#endif
8598718aafec239c93485e45bbe8fed19d9a8def079bsalomon    SkASSERT(stats.fContent == fUniqueHash.count());
860f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    SkASSERT(stats.fScratch + stats.fCouldBeScratch == fScratchMap.count());
86171cb0c241e439b6ed746b90294d0b6916644a644bsalomon
8623f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    // This assertion is not currently valid because we can be in recursive notifyCntReachedZero()
86312299ab7a1be5f4b99284ecf289d46107ef0a946bsalomon    // calls. This will be fixed when subresource registration is explicit.
864dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon    // bool overBudget = budgetedBytes > fMaxBytes || budgetedCount > fMaxCount;
86512299ab7a1be5f4b99284ecf289d46107ef0a946bsalomon    // SkASSERT(!overBudget || locked == count || fPurging);
86671cb0c241e439b6ed746b90294d0b6916644a644bsalomon}
867f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon
868f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomonbool GrResourceCache::isInCache(const GrGpuResource* resource) const {
869f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    int index = *resource->cacheAccess().accessCacheIndex();
870f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    if (index < 0) {
871f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon        return false;
872f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    }
873f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    if (index < fPurgeableQueue.count() && fPurgeableQueue.at(index) == resource) {
874f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon        return true;
875f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    }
876f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    if (index < fNonpurgeableResources.count() && fNonpurgeableResources[index] == resource) {
877f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon        return true;
878f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    }
879f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    SkDEBUGFAIL("Resource index should be -1 or the resource should be in the cache.");
880f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    return false;
881f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon}
882f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon
88371cb0c241e439b6ed746b90294d0b6916644a644bsalomon#endif
884