1fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/*
2fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Copyright 2014 Google Inc.
3fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *
4fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Use of this source code is governed by a BSD-style license that can be
5fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * found in the LICENSE file.
6fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */
7fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
8fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "GrResourceCache.h"
10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "GrCaps.h"
12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "GrGpuResourceCacheAccess.h"
13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "GrProxyProvider.h"
14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "GrTexture.h"
15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "GrTextureProxyCacheAccess.h"
16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "GrTracing.h"
17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkGr.h"
18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkMessageBus.h"
19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkOpts.h"
20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkTSort.h"
21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotDECLARE_SKMESSAGEBUS_MESSAGE(GrUniqueKeyInvalidatedMessage);
23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotDECLARE_SKMESSAGEBUS_MESSAGE(GrGpuResourceFreedMessage);
25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//////////////////////////////////////////////////////////////////////////////
27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotGrScratchKey::ResourceType GrScratchKey::GenerateResourceType() {
29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    static int32_t gType = INHERITED::kInvalidDomain + 1;
30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int32_t type = sk_atomic_inc(&gType);
32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (type > SK_MaxU16) {
33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SK_ABORT("Too many Resource Types");
34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return static_cast<ResourceType>(type);
37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotGrUniqueKey::Domain GrUniqueKey::GenerateDomain() {
40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    static int32_t gDomain = INHERITED::kInvalidDomain + 1;
41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int32_t domain = sk_atomic_inc(&gDomain);
43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (domain > SK_MaxU16) {
44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SK_ABORT("Too many GrUniqueKey Domains");
45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return static_cast<Domain>(domain);
48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotuint32_t GrResourceKeyHash(const uint32_t* data, size_t size) {
51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return SkOpts::hash(data, size);
52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//////////////////////////////////////////////////////////////////////////////
55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotclass GrResourceCache::AutoValidate : ::SkNoncopyable {
57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotpublic:
58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    AutoValidate(GrResourceCache* cache) : fCache(cache) { cache->validate(); }
59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    ~AutoValidate() { fCache->validate(); }
60fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotprivate:
61fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    GrResourceCache* fCache;
62fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot};
63fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
64fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot //////////////////////////////////////////////////////////////////////////////
65fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotGrResourceCache::GrResourceCache(const GrCaps* caps, uint32_t contextUniqueID)
68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    : fProxyProvider(nullptr)
69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    , fTimestamp(0)
70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    , fMaxCount(kDefaultMaxCount)
71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    , fMaxBytes(kDefaultMaxSize)
72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    , fMaxUnusedFlushes(kDefaultMaxUnusedFlushes)
73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if GR_CACHE_STATS
74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    , fHighWaterCount(0)
75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    , fHighWaterBytes(0)
76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    , fBudgetedHighWaterCount(0)
77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    , fBudgetedHighWaterBytes(0)
78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    , fBytes(0)
80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    , fBudgetedCount(0)
81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    , fBudgetedBytes(0)
82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    , fPurgeableBytes(0)
83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    , fRequestFlush(false)
84fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    , fExternalFlushCnt(0)
85fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    , fContextUniqueID(contextUniqueID)
86fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    , fPreferVRAMUseOverFlushes(caps->preferVRAMUseOverFlushes()) {
87fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDEBUGCODE(fCount = 0;)
88fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDEBUGCODE(fNewlyPurgeableResourceForValidation = nullptr;)
89fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
90fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
91fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotGrResourceCache::~GrResourceCache() {
92fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->releaseAll();
93fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
94fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
95fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrResourceCache::setLimits(int count, size_t bytes, int maxUnusedFlushes) {
96fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fMaxCount = count;
97fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fMaxBytes = bytes;
98fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fMaxUnusedFlushes = maxUnusedFlushes;
99fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->purgeAsNeeded();
100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrResourceCache::insertResource(GrGpuResource* resource) {
103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(resource);
104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(!this->isInCache(resource));
105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(!resource->wasDestroyed());
106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(!resource->isPurgeable());
107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // We must set the timestamp before adding to the array in case the timestamp wraps and we wind
109fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // up iterating over all the resources that already have timestamps.
110fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    resource->cacheAccess().setTimestamp(this->getNextTimestamp());
111fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
112fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->addToNonpurgeableArray(resource);
113fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
114fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    size_t size = resource->gpuMemorySize();
115fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDEBUGCODE(++fCount;)
116fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fBytes += size;
117fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if GR_CACHE_STATS
118fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fHighWaterCount = SkTMax(this->getResourceCount(), fHighWaterCount);
119fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fHighWaterBytes = SkTMax(fBytes, fHighWaterBytes);
120fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
121fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (SkBudgeted::kYes == resource->resourcePriv().isBudgeted()) {
122fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ++fBudgetedCount;
123fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fBudgetedBytes += size;
124fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        TRACE_COUNTER2("skia.gpu.cache", "skia budget", "used",
125fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                       fBudgetedBytes, "free", fMaxBytes - fBudgetedBytes);
126fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if GR_CACHE_STATS
127fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fBudgetedHighWaterCount = SkTMax(fBudgetedCount, fBudgetedHighWaterCount);
128fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes);
129fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
130fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
131fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (resource->resourcePriv().getScratchKey().isValid() &&
132fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        !resource->getUniqueKey().isValid()) {
133fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(!resource->resourcePriv().refsWrappedObjects());
134fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fScratchMap.insert(resource->resourcePriv().getScratchKey(), resource);
135fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
136fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
137fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->purgeAsNeeded();
138fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
139fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
140fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrResourceCache::removeResource(GrGpuResource* resource) {
141fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->validate();
142fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(this->isInCache(resource));
143fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
144fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    size_t size = resource->gpuMemorySize();
145fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (resource->isPurgeable()) {
146fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fPurgeableQueue.remove(resource);
147fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fPurgeableBytes -= size;
148fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
149fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->removeFromNonpurgeableArray(resource);
150fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
151fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
152fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDEBUGCODE(--fCount;)
153fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fBytes -= size;
154fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (SkBudgeted::kYes == resource->resourcePriv().isBudgeted()) {
155fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        --fBudgetedCount;
156fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fBudgetedBytes -= size;
157fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        TRACE_COUNTER2("skia.gpu.cache", "skia budget", "used",
158fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                       fBudgetedBytes, "free", fMaxBytes - fBudgetedBytes);
159fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
160fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
161fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (resource->resourcePriv().getScratchKey().isValid() &&
162fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        !resource->getUniqueKey().isValid()) {
163fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource);
164fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
165fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (resource->getUniqueKey().isValid()) {
166fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fUniqueHash.remove(resource->getUniqueKey());
167fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
168fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->validate();
169fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
170fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
171fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrResourceCache::abandonAll() {
172fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    AutoValidate av(this);
173fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
174fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    while (fNonpurgeableResources.count()) {
175fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        GrGpuResource* back = *(fNonpurgeableResources.end() - 1);
176fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(!back->wasDestroyed());
177fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        back->cacheAccess().abandon();
178fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
179fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
180fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    while (fPurgeableQueue.count()) {
181fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        GrGpuResource* top = fPurgeableQueue.peek();
182fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(!top->wasDestroyed());
183fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        top->cacheAccess().abandon();
184fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
185fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
186fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(!fScratchMap.count());
187fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(!fUniqueHash.count());
188fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(!fCount);
189fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(!this->getResourceCount());
190fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(!fBytes);
191fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(!fBudgetedCount);
192fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(!fBudgetedBytes);
193fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(!fPurgeableBytes);
194fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
195fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
196fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrResourceCache::releaseAll() {
197fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    AutoValidate av(this);
198fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
199fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->processFreedGpuResources();
200fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
201fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(fProxyProvider); // better have called setProxyProvider
202fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // We must remove the uniqueKeys from the proxies here. While they possess a uniqueKey
203fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // they also have a raw pointer back to this class (which is presumably going away)!
204fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fProxyProvider->removeAllUniqueKeys();
205fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
206fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    while(fNonpurgeableResources.count()) {
207fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        GrGpuResource* back = *(fNonpurgeableResources.end() - 1);
208fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(!back->wasDestroyed());
209fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        back->cacheAccess().release();
210fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
211fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
212fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    while (fPurgeableQueue.count()) {
213fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        GrGpuResource* top = fPurgeableQueue.peek();
214fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(!top->wasDestroyed());
215fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        top->cacheAccess().release();
216fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
217fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
218fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(!fScratchMap.count());
219fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(!fUniqueHash.count());
220fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(!fCount);
221fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(!this->getResourceCount());
222fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(!fBytes);
223fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(!fBudgetedCount);
224fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(!fBudgetedBytes);
225fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(!fPurgeableBytes);
226fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
227fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
228fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotclass GrResourceCache::AvailableForScratchUse {
229fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotpublic:
230fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    AvailableForScratchUse(bool rejectPendingIO) : fRejectPendingIO(rejectPendingIO) { }
231fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
232fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool operator()(const GrGpuResource* resource) const {
233fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(!resource->getUniqueKey().isValid() &&
234fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                 resource->resourcePriv().getScratchKey().isValid());
235fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (resource->internalHasRef() || !resource->cacheAccess().isScratch()) {
236fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return false;
237fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
238fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return !fRejectPendingIO || !resource->internalHasPendingIO();
239fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
240fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
241fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotprivate:
242fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool fRejectPendingIO;
243fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot};
244fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
245fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotGrGpuResource* GrResourceCache::findAndRefScratchResource(const GrScratchKey& scratchKey,
246fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                          size_t resourceSize,
247fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                          uint32_t flags) {
248fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(scratchKey.isValid());
249fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
250fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    GrGpuResource* resource;
251fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (flags & (kPreferNoPendingIO_ScratchFlag | kRequireNoPendingIO_ScratchFlag)) {
252fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        resource = fScratchMap.find(scratchKey, AvailableForScratchUse(true));
253fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (resource) {
254fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->refAndMakeResourceMRU(resource);
255fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->validate();
256fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return resource;
257fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        } else if (flags & kRequireNoPendingIO_ScratchFlag) {
258fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return nullptr;
259fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
260fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // We would prefer to consume more available VRAM rather than flushing
261fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // immediately, but on ANGLE this can lead to starving of the GPU.
262fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (fPreferVRAMUseOverFlushes && this->wouldFit(resourceSize)) {
263fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // kPrefer is specified, we didn't find a resource without pending io,
264fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // but there is still space in our budget for the resource so force
265fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // the caller to allocate a new resource.
266fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return nullptr;
267fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
268fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
269fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    resource = fScratchMap.find(scratchKey, AvailableForScratchUse(false));
270fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (resource) {
271fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->refAndMakeResourceMRU(resource);
272fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->validate();
273fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
274fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return resource;
275fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
276fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
277fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrResourceCache::willRemoveScratchKey(const GrGpuResource* resource) {
278fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(resource->resourcePriv().getScratchKey().isValid());
279fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!resource->getUniqueKey().isValid()) {
280fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource);
281fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
282fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
283fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
284fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrResourceCache::removeUniqueKey(GrGpuResource* resource) {
285fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // Someone has a ref to this resource in order to have removed the key. When the ref count
286fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // reaches zero we will get a ref cnt notification and figure out what to do with it.
287fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (resource->getUniqueKey().isValid()) {
288fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(resource == fUniqueHash.find(resource->getUniqueKey()));
289fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fUniqueHash.remove(resource->getUniqueKey());
290fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
291fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    resource->cacheAccess().removeUniqueKey();
292fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
293fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (resource->resourcePriv().getScratchKey().isValid()) {
294fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fScratchMap.insert(resource->resourcePriv().getScratchKey(), resource);
295fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
296fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
297fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->validate();
298fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
299fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
300fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrResourceCache::changeUniqueKey(GrGpuResource* resource, const GrUniqueKey& newKey) {
301fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(resource);
302fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(this->isInCache(resource));
303fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
304fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // If another resource has the new key, remove its key then install the key on this resource.
305fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (newKey.isValid()) {
306fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (GrGpuResource* old = fUniqueHash.find(newKey)) {
307fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // If the old resource using the key is purgeable and is unreachable, then remove it.
308fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (!old->resourcePriv().getScratchKey().isValid() && old->isPurgeable()) {
309fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                old->cacheAccess().release();
310fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            } else {
311fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                this->removeUniqueKey(old);
312fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
313fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
314fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(nullptr == fUniqueHash.find(newKey));
315fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
316fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Remove the entry for this resource if it already has a unique key.
317fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (resource->getUniqueKey().isValid()) {
318fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(resource == fUniqueHash.find(resource->getUniqueKey()));
319fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fUniqueHash.remove(resource->getUniqueKey());
320fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(nullptr == fUniqueHash.find(resource->getUniqueKey()));
321fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        } else {
322fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // 'resource' didn't have a valid unique key before so it is switching sides. Remove it
323fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // from the ScratchMap
324fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (resource->resourcePriv().getScratchKey().isValid()) {
325fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource);
326fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
327fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
328fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
329fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        resource->cacheAccess().setUniqueKey(newKey);
330fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fUniqueHash.add(resource);
331fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
332fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->removeUniqueKey(resource);
333fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
334fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
335fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->validate();
336fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
337fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
338fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrResourceCache::refAndMakeResourceMRU(GrGpuResource* resource) {
339fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(resource);
340fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(this->isInCache(resource));
341fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
342fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (resource->isPurgeable()) {
343fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // It's about to become unpurgeable.
344fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fPurgeableBytes -= resource->gpuMemorySize();
345fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fPurgeableQueue.remove(resource);
346fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->addToNonpurgeableArray(resource);
347fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
348fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    resource->ref();
349fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
350fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    resource->cacheAccess().setTimestamp(this->getNextTimestamp());
351fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->validate();
352fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
353fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
354fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrResourceCache::notifyCntReachedZero(GrGpuResource* resource, uint32_t flags) {
355fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(resource);
356fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(!resource->wasDestroyed());
357fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(flags);
358fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(this->isInCache(resource));
359fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // This resource should always be in the nonpurgeable array when this function is called. It
360fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // will be moved to the queue if it is newly purgeable.
361fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(fNonpurgeableResources[*resource->cacheAccess().accessCacheIndex()] == resource);
362fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
363fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (SkToBool(ResourceAccess::kRefCntReachedZero_RefNotificationFlag & flags)) {
364fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifdef SK_DEBUG
365fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // When the timestamp overflows validate() is called. validate() checks that resources in
366fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // the nonpurgeable array are indeed not purgeable. However, the movement from the array to
367fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // the purgeable queue happens just below in this function. So we mark it as an exception.
368fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (resource->isPurgeable()) {
369fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fNewlyPurgeableResourceForValidation = resource;
370fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
371fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
372fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        resource->cacheAccess().setTimestamp(this->getNextTimestamp());
373fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDEBUGCODE(fNewlyPurgeableResourceForValidation = nullptr);
374fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
375fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
376fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!SkToBool(ResourceAccess::kAllCntsReachedZero_RefNotificationFlag & flags)) {
377fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(!resource->isPurgeable());
378fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
379fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
380fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
381fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(resource->isPurgeable());
382fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->removeFromNonpurgeableArray(resource);
383fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fPurgeableQueue.insert(resource);
384fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    resource->cacheAccess().setFlushCntWhenResourceBecamePurgeable(fExternalFlushCnt);
385fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    resource->cacheAccess().setTimeWhenResourceBecomePurgeable();
386fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fPurgeableBytes += resource->gpuMemorySize();
387fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
388fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (SkBudgeted::kNo == resource->resourcePriv().isBudgeted()) {
389fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Check whether this resource could still be used as a scratch resource.
390fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!resource->resourcePriv().refsWrappedObjects() &&
391fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            resource->resourcePriv().getScratchKey().isValid()) {
392fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // We won't purge an existing resource to make room for this one.
393fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (fBudgetedCount < fMaxCount &&
394fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                fBudgetedBytes + resource->gpuMemorySize() <= fMaxBytes) {
395fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                resource->resourcePriv().makeBudgeted();
396fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                return;
397fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
398fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
399fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
400fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Purge the resource immediately if we're over budget
401fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Also purge if the resource has neither a valid scratch key nor a unique key.
402fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        bool noKey = !resource->resourcePriv().getScratchKey().isValid() &&
403fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                     !resource->getUniqueKey().isValid();
404fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!this->overBudget() && !noKey) {
405fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return;
406fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
407fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
408fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
409fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDEBUGCODE(int beforeCount = this->getResourceCount();)
410fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    resource->cacheAccess().release();
411fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // We should at least free this resource, perhaps dependent resources as well.
412fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(this->getResourceCount() < beforeCount);
413fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->validate();
414fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
415fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
416fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrResourceCache::didChangeGpuMemorySize(const GrGpuResource* resource, size_t oldSize) {
417fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // SkASSERT(!fPurging); GrPathRange increases size during flush. :(
418fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(resource);
419fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(this->isInCache(resource));
420fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
421fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    ptrdiff_t delta = resource->gpuMemorySize() - oldSize;
422fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
423fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fBytes += delta;
424fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if GR_CACHE_STATS
425fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fHighWaterBytes = SkTMax(fBytes, fHighWaterBytes);
426fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
427fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (SkBudgeted::kYes == resource->resourcePriv().isBudgeted()) {
428fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fBudgetedBytes += delta;
429fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        TRACE_COUNTER2("skia.gpu.cache", "skia budget", "used",
430fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                       fBudgetedBytes, "free", fMaxBytes - fBudgetedBytes);
431fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if GR_CACHE_STATS
432fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes);
433fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
434fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
435fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
436fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->purgeAsNeeded();
437fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->validate();
438fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
439fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
440fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrResourceCache::didChangeBudgetStatus(GrGpuResource* resource) {
441fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(resource);
442fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(this->isInCache(resource));
443fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
444fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    size_t size = resource->gpuMemorySize();
445fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
446fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (SkBudgeted::kYes == resource->resourcePriv().isBudgeted()) {
447fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ++fBudgetedCount;
448fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fBudgetedBytes += size;
449fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if GR_CACHE_STATS
450fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes);
451fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fBudgetedHighWaterCount = SkTMax(fBudgetedCount, fBudgetedHighWaterCount);
452fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
453fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->purgeAsNeeded();
454fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
455fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        --fBudgetedCount;
456fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fBudgetedBytes -= size;
457fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
458fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    TRACE_COUNTER2("skia.gpu.cache", "skia budget", "used",
459fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                   fBudgetedBytes, "free", fMaxBytes - fBudgetedBytes);
460fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
461fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->validate();
462fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
463fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
464fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrResourceCache::purgeAsNeeded() {
465fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkTArray<GrUniqueKeyInvalidatedMessage> invalidKeyMsgs;
466fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fInvalidUniqueKeyInbox.poll(&invalidKeyMsgs);
467fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (invalidKeyMsgs.count()) {
468fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->processInvalidUniqueKeys(invalidKeyMsgs);
469fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
470fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
471fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->processFreedGpuResources();
472fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
473fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fMaxUnusedFlushes > 0) {
474fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // We want to know how many complete flushes have occurred without the resource being used.
475fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // If the resource was tagged when fExternalFlushCnt was N then this means it became
476fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // purgeable during activity that became the N+1th flush. So when the flush count is N+2
477fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // it has sat in the purgeable queue for one entire flush.
478fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        uint32_t oldestAllowedFlushCnt = fExternalFlushCnt - fMaxUnusedFlushes - 1;
479fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // check for underflow
480fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (oldestAllowedFlushCnt < fExternalFlushCnt) {
481fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            while (fPurgeableQueue.count()) {
482fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                uint32_t flushWhenResourceBecamePurgeable =
483fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        fPurgeableQueue.peek()->cacheAccess().flushCntWhenResourceBecamePurgeable();
484fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (oldestAllowedFlushCnt < flushWhenResourceBecamePurgeable) {
485fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    // Resources were given both LRU timestamps and tagged with a flush cnt when
486fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    // they first became purgeable. The LRU timestamp won't change again until the
487fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    // resource is made non-purgeable again. So, at this point all the remaining
488fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    // resources in the timestamp-sorted queue will have a flush count >= to this
489fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    // one.
490fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    break;
491fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
492fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                GrGpuResource* resource = fPurgeableQueue.peek();
493fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkASSERT(resource->isPurgeable());
494fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                resource->cacheAccess().release();
495fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
496fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
497fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
498fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
499fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool stillOverbudget = this->overBudget();
500fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    while (stillOverbudget && fPurgeableQueue.count()) {
501fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        GrGpuResource* resource = fPurgeableQueue.peek();
502fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(resource->isPurgeable());
503fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        resource->cacheAccess().release();
504fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        stillOverbudget = this->overBudget();
505fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
506fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
507fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->validate();
508fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
509fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (stillOverbudget) {
510fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Set this so that GrDrawingManager will issue a flush to free up resources with pending
511fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // IO that we were unable to purge in this pass.
512fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fRequestFlush = true;
513fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
514fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
515fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
516fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrResourceCache::purgeAllUnlocked() {
517fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // We could disable maintaining the heap property here, but it would add a lot of complexity.
518fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // Moreover, this is rarely called.
519fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    while (fPurgeableQueue.count()) {
520fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        GrGpuResource* resource = fPurgeableQueue.peek();
521fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(resource->isPurgeable());
522fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        resource->cacheAccess().release();
523fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
524fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
525fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->validate();
526fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
527fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
528fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrResourceCache::purgeResourcesNotUsedSince(GrStdSteadyClock::time_point purgeTime) {
529fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    while (fPurgeableQueue.count()) {
530fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const GrStdSteadyClock::time_point resourceTime =
531fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                fPurgeableQueue.peek()->cacheAccess().timeWhenResourceBecamePurgeable();
532fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (resourceTime >= purgeTime) {
533fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // Resources were given both LRU timestamps and tagged with a frame number when
534fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // they first became purgeable. The LRU timestamp won't change again until the
535fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // resource is made non-purgeable again. So, at this point all the remaining
536fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // resources in the timestamp-sorted queue will have a frame number >= to this
537fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // one.
538fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
539fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
540fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        GrGpuResource* resource = fPurgeableQueue.peek();
541fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(resource->isPurgeable());
542fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        resource->cacheAccess().release();
543fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
544fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
545fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
546fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrResourceCache::purgeUnlockedResources(size_t bytesToPurge, bool preferScratchResources) {
547fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
548fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const size_t tmpByteBudget = SkTMax((size_t)0, fBytes - bytesToPurge);
549fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool stillOverbudget = tmpByteBudget < fBytes;
550fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
551fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (preferScratchResources && bytesToPurge < fPurgeableBytes) {
552fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Sort the queue
553fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fPurgeableQueue.sort();
554fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
555fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Make a list of the scratch resources to delete
556fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkTDArray<GrGpuResource*> scratchResources;
557fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        size_t scratchByteCount = 0;
558fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (int i = 0; i < fPurgeableQueue.count() && stillOverbudget; i++) {
559fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            GrGpuResource* resource = fPurgeableQueue.at(i);
560fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(resource->isPurgeable());
561fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (!resource->getUniqueKey().isValid()) {
562fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                *scratchResources.append() = resource;
563fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                scratchByteCount += resource->gpuMemorySize();
564fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                stillOverbudget = tmpByteBudget < fBytes - scratchByteCount;
565fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
566fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
567fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
568fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Delete the scratch resources. This must be done as a separate pass
569fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // to avoid messing up the sorted order of the queue
570fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (int i = 0; i < scratchResources.count(); i++) {
571fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            scratchResources.getAt(i)->cacheAccess().release();
572fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
573fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        stillOverbudget = tmpByteBudget < fBytes;
574fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
575fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->validate();
576fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
577fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
578fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // Purge any remaining resources in LRU order
579fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (stillOverbudget) {
580fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const size_t cachedByteCount = fMaxBytes;
581fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fMaxBytes = tmpByteBudget;
582fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->purgeAsNeeded();
583fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fMaxBytes = cachedByteCount;
584fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
585fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
586fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
587fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrResourceCache::processInvalidUniqueKeys(
588fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                            const SkTArray<GrUniqueKeyInvalidatedMessage>& msgs) {
589fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(fProxyProvider); // better have called setProxyProvider
590fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
591fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int i = 0; i < msgs.count(); ++i) {
592fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fProxyProvider->processInvalidProxyUniqueKey(msgs[i].key());
593fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
594fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        GrGpuResource* resource = this->findAndRefUniqueResource(msgs[i].key());
595fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (resource) {
596fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            resource->resourcePriv().removeUniqueKey();
597fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            resource->unref(); // If this resource is now purgeable, the cache will be notified.
598fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
599fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
600fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
601fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
602fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrResourceCache::insertCrossContextGpuResource(GrGpuResource* resource) {
603fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    resource->ref();
604fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
605fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
606fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrResourceCache::processFreedGpuResources() {
607fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkTArray<GrGpuResourceFreedMessage> msgs;
608fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fFreedGpuResourceInbox.poll(&msgs);
609fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int i = 0; i < msgs.count(); ++i) {
610fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (msgs[i].fOwningUniqueID == fContextUniqueID) {
611fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            msgs[i].fResource->unref();
612fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
613fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
614fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
615fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
616fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrResourceCache::addToNonpurgeableArray(GrGpuResource* resource) {
617fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int index = fNonpurgeableResources.count();
618fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    *fNonpurgeableResources.append() = resource;
619fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    *resource->cacheAccess().accessCacheIndex() = index;
620fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
621fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
622fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrResourceCache::removeFromNonpurgeableArray(GrGpuResource* resource) {
623fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int* index = resource->cacheAccess().accessCacheIndex();
624fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // Fill the whole we will create in the array with the tail object, adjust its index, and
625fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // then pop the array
626fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    GrGpuResource* tail = *(fNonpurgeableResources.end() - 1);
627fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(fNonpurgeableResources[*index] == resource);
628fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fNonpurgeableResources[*index] = tail;
629fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    *tail->cacheAccess().accessCacheIndex() = *index;
630fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fNonpurgeableResources.pop();
631fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDEBUGCODE(*index = -1);
632fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
633fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
634fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotuint32_t GrResourceCache::getNextTimestamp() {
635fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // If we wrap then all the existing resources will appear older than any resources that get
636fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // a timestamp after the wrap.
637fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (0 == fTimestamp) {
638fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        int count = this->getResourceCount();
639fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (count) {
640fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // Reset all the timestamps. We sort the resources by timestamp and then assign
641fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // sequential timestamps beginning with 0. This is O(n*lg(n)) but it should be extremely
642fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // rare.
643fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkTDArray<GrGpuResource*> sortedPurgeableResources;
644fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            sortedPurgeableResources.setReserve(fPurgeableQueue.count());
645fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
646fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            while (fPurgeableQueue.count()) {
647fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                *sortedPurgeableResources.append() = fPurgeableQueue.peek();
648fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                fPurgeableQueue.pop();
649fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
650fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
651fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkTQSort(fNonpurgeableResources.begin(), fNonpurgeableResources.end() - 1,
652fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                     CompareTimestamp);
653fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
654fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // Pick resources out of the purgeable and non-purgeable arrays based on lowest
655fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // timestamp and assign new timestamps.
656fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            int currP = 0;
657fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            int currNP = 0;
658fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            while (currP < sortedPurgeableResources.count() &&
659fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                   currNP < fNonpurgeableResources.count()) {
660fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                uint32_t tsP = sortedPurgeableResources[currP]->cacheAccess().timestamp();
661fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                uint32_t tsNP = fNonpurgeableResources[currNP]->cacheAccess().timestamp();
662fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkASSERT(tsP != tsNP);
663fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (tsP < tsNP) {
664fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    sortedPurgeableResources[currP++]->cacheAccess().setTimestamp(fTimestamp++);
665fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                } else {
666fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    // Correct the index in the nonpurgeable array stored on the resource post-sort.
667fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    *fNonpurgeableResources[currNP]->cacheAccess().accessCacheIndex() = currNP;
668fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    fNonpurgeableResources[currNP++]->cacheAccess().setTimestamp(fTimestamp++);
669fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
670fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
671fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
672fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // The above loop ended when we hit the end of one array. Finish the other one.
673fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            while (currP < sortedPurgeableResources.count()) {
674fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                sortedPurgeableResources[currP++]->cacheAccess().setTimestamp(fTimestamp++);
675fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
676fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            while (currNP < fNonpurgeableResources.count()) {
677fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                *fNonpurgeableResources[currNP]->cacheAccess().accessCacheIndex() = currNP;
678fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                fNonpurgeableResources[currNP++]->cacheAccess().setTimestamp(fTimestamp++);
679fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
680fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
681fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // Rebuild the queue.
682fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            for (int i = 0; i < sortedPurgeableResources.count(); ++i) {
683fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                fPurgeableQueue.insert(sortedPurgeableResources[i]);
684fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
685fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
686fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->validate();
687fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(count == this->getResourceCount());
688fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
689fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // count should be the next timestamp we return.
690fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(fTimestamp == SkToU32(count));
691fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
692fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
693fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return fTimestamp++;
694fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
695fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
696fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrResourceCache::notifyFlushOccurred(FlushType type) {
697fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    switch (type) {
698fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case FlushType::kCacheRequested:
699fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(fRequestFlush);
700fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fRequestFlush = false;
701fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
702fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case FlushType::kExternal:
703fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            ++fExternalFlushCnt;
704fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (0 == fExternalFlushCnt) {
705fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                // When this wraps just reset all the purgeable resources' last used flush state.
706fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                for (int i = 0; i < fPurgeableQueue.count(); ++i) {
707fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    fPurgeableQueue.at(i)->cacheAccess().setFlushCntWhenResourceBecamePurgeable(0);
708fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
709fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
710fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
711fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
712fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->purgeAsNeeded();
713fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
714fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
715fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrResourceCache::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
716fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int i = 0; i < fNonpurgeableResources.count(); ++i) {
717fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fNonpurgeableResources[i]->dumpMemoryStatistics(traceMemoryDump);
718fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
719fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int i = 0; i < fPurgeableQueue.count(); ++i) {
720fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fPurgeableQueue.at(i)->dumpMemoryStatistics(traceMemoryDump);
721fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
722fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
723fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
724fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifdef SK_DEBUG
725fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrResourceCache::validate() const {
726fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // Reduce the frequency of validations for large resource counts.
727fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    static SkRandom gRandom;
728fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int mask = (SkNextPow2(fCount + 1) >> 5) - 1;
729fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (~mask && (gRandom.nextU() & mask)) {
730fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
731fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
732fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
733fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    struct Stats {
734fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        size_t fBytes;
735fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        int fBudgetedCount;
736fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        size_t fBudgetedBytes;
737fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        int fLocked;
738fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        int fScratch;
739fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        int fCouldBeScratch;
740fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        int fContent;
741fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const ScratchMap* fScratchMap;
742fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const UniqueHash* fUniqueHash;
743fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
744fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        Stats(const GrResourceCache* cache) {
745fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            memset(this, 0, sizeof(*this));
746fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fScratchMap = &cache->fScratchMap;
747fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fUniqueHash = &cache->fUniqueHash;
748fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
749fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
750fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        void update(GrGpuResource* resource) {
751fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fBytes += resource->gpuMemorySize();
752fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
753fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (!resource->isPurgeable()) {
754fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                ++fLocked;
755fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
756fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
757fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const GrScratchKey& scratchKey = resource->resourcePriv().getScratchKey();
758fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const GrUniqueKey& uniqueKey = resource->getUniqueKey();
759fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
760fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (resource->cacheAccess().isScratch()) {
761fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkASSERT(!uniqueKey.isValid());
762fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                ++fScratch;
763fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkASSERT(fScratchMap->countForKey(scratchKey));
764fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkASSERT(!resource->resourcePriv().refsWrappedObjects());
765fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            } else if (scratchKey.isValid()) {
766fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkASSERT(SkBudgeted::kNo == resource->resourcePriv().isBudgeted() ||
767fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                         uniqueKey.isValid());
768fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (!uniqueKey.isValid()) {
769fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    ++fCouldBeScratch;
770fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    SkASSERT(fScratchMap->countForKey(scratchKey));
771fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
772fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkASSERT(!resource->resourcePriv().refsWrappedObjects());
773fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
774fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (uniqueKey.isValid()) {
775fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                ++fContent;
776fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkASSERT(fUniqueHash->find(uniqueKey) == resource);
777fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkASSERT(SkBudgeted::kYes == resource->resourcePriv().isBudgeted() ||
778fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                         resource->resourcePriv().refsWrappedObjects());
779fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
780fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (scratchKey.isValid()) {
781fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    SkASSERT(!fScratchMap->has(resource, scratchKey));
782fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
783fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
784fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
785fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (SkBudgeted::kYes == resource->resourcePriv().isBudgeted()) {
786fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                ++fBudgetedCount;
787fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                fBudgetedBytes += resource->gpuMemorySize();
788fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
789fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
790fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    };
791fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
792fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    {
793fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ScratchMap::ConstIter iter(&fScratchMap);
794fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
795fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        int count = 0;
796fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for ( ; !iter.done(); ++iter) {
797fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const GrGpuResource* resource = *iter;
798fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(resource->resourcePriv().getScratchKey().isValid());
799fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(!resource->getUniqueKey().isValid());
800fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            count++;
801fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
802fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(count == fScratchMap.count()); // ensure the iterator is working correctly
803fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
804fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
805fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    Stats stats(this);
806fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    size_t purgeableBytes = 0;
807fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
808fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int i = 0; i < fNonpurgeableResources.count(); ++i) {
809fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(!fNonpurgeableResources[i]->isPurgeable() ||
810fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                 fNewlyPurgeableResourceForValidation == fNonpurgeableResources[i]);
811fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(*fNonpurgeableResources[i]->cacheAccess().accessCacheIndex() == i);
812fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(!fNonpurgeableResources[i]->wasDestroyed());
813fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        stats.update(fNonpurgeableResources[i]);
814fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
815fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int i = 0; i < fPurgeableQueue.count(); ++i) {
816fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(fPurgeableQueue.at(i)->isPurgeable());
817fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(*fPurgeableQueue.at(i)->cacheAccess().accessCacheIndex() == i);
818fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(!fPurgeableQueue.at(i)->wasDestroyed());
819fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        stats.update(fPurgeableQueue.at(i));
820fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        purgeableBytes += fPurgeableQueue.at(i)->gpuMemorySize();
821fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
822fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
823fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(fCount == this->getResourceCount());
824fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(fBudgetedCount <= fCount);
825fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(fBudgetedBytes <= fBytes);
826fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(stats.fBytes == fBytes);
827fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(stats.fBudgetedBytes == fBudgetedBytes);
828fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(stats.fBudgetedCount == fBudgetedCount);
829fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(purgeableBytes == fPurgeableBytes);
830fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if GR_CACHE_STATS
831fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(fBudgetedHighWaterCount <= fHighWaterCount);
832fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(fBudgetedHighWaterBytes <= fHighWaterBytes);
833fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(fBytes <= fHighWaterBytes);
834fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(fCount <= fHighWaterCount);
835fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(fBudgetedBytes <= fBudgetedHighWaterBytes);
836fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(fBudgetedCount <= fBudgetedHighWaterCount);
837fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
838fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(stats.fContent == fUniqueHash.count());
839fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(stats.fScratch + stats.fCouldBeScratch == fScratchMap.count());
840fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
841fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // This assertion is not currently valid because we can be in recursive notifyCntReachedZero()
842fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // calls. This will be fixed when subresource registration is explicit.
843fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // bool overBudget = budgetedBytes > fMaxBytes || budgetedCount > fMaxCount;
844fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // SkASSERT(!overBudget || locked == count || fPurging);
845fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
846fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
847fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool GrResourceCache::isInCache(const GrGpuResource* resource) const {
848fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int index = *resource->cacheAccess().accessCacheIndex();
849fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (index < 0) {
850fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return false;
851fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
852fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (index < fPurgeableQueue.count() && fPurgeableQueue.at(index) == resource) {
853fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return true;
854fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
855fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (index < fNonpurgeableResources.count() && fNonpurgeableResources[index] == resource) {
856fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return true;
857fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
858fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDEBUGFAIL("Resource index should be -1 or the resource should be in the cache.");
859fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return false;
860fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
861fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
862fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
863