1ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2010 Google Inc.
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
7ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com */
8ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
9ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
10ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
1150398bf7f1953e640e5529616e710cf540799731bsalomon@google.com#include "GrResourceCache.h"
126d3fe022d68fd6dd32c0fab30e24fa5a4f048946bsalomon#include "GrGpuResource.h"
13ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
14c665804300096c2e7617379835bb83d715538788commit-bot@chromium.orgDECLARE_SKMESSAGEBUS_MESSAGE(GrResourceInvalidatedMessage);
150797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com
1611c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org///////////////////////////////////////////////////////////////////////////////
1711c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org
186d3fe022d68fd6dd32c0fab30e24fa5a4f048946bsalomonvoid GrGpuResource::didChangeGpuMemorySize() const {
1911c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org    if (this->isInCache()) {
2011c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org        fCacheEntry->didChangeResourceSize();
2111c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org    }
2211c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org}
2311c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org
2411c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org///////////////////////////////////////////////////////////////////////////////
2511c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org
260797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.comGrResourceKey::ResourceType GrResourceKey::GenerateResourceType() {
270797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com    static int32_t gNextType = 0;
280797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com
290797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com    int32_t type = sk_atomic_inc(&gNextType);
300797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com    if (type >= (1 << 8 * sizeof(ResourceType))) {
3188cb22b6b4816c7a9ca6c5b795965b4606f9eb7bcommit-bot@chromium.org        SkFAIL("Too many Resource Types");
320797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com    }
330797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com
340797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com    return static_cast<ResourceType>(type);
350797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com}
360797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com
370797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com///////////////////////////////////////////////////////////////////////////////
380797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com
3911c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.orgGrResourceCacheEntry::GrResourceCacheEntry(GrResourceCache* resourceCache,
4011c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org                                           const GrResourceKey& key,
416d3fe022d68fd6dd32c0fab30e24fa5a4f048946bsalomon                                           GrGpuResource* resource)
4211c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org        : fResourceCache(resourceCache),
4311c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org          fKey(key),
4411c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org          fResource(resource),
4511c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org          fCachedSize(resource->gpuMemorySize()),
4611c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org          fIsExclusive(false) {
4750398bf7f1953e640e5529616e710cf540799731bsalomon@google.com    // we assume ownership of the resource, and will unref it when we die
48f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(resource);
496c778164a743f8760dca251524d51848548b436fskia.committer@gmail.com    resource->ref();
50ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com}
51ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
52089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.orgGrResourceCacheEntry::~GrResourceCacheEntry() {
53521eaf8cc73cebebeaf54338c51c22922ac70951robertphillips@google.com    fResource->setCacheEntry(NULL);
5450398bf7f1953e640e5529616e710cf540799731bsalomon@google.com    fResource->unref();
55ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com}
56ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
57515dcd36032997ce335daa0163c6d67e851bcad1commit-bot@chromium.org#ifdef SK_DEBUG
58089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.orgvoid GrResourceCacheEntry::validate() const {
5911c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org    SkASSERT(fResourceCache);
60f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(fResource);
61f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(fResource->getCacheEntry() == this);
6211c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org    SkASSERT(fResource->gpuMemorySize() == fCachedSize);
6350398bf7f1953e640e5529616e710cf540799731bsalomon@google.com    fResource->validate();
64ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com}
65ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com#endif
66ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
6711c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.orgvoid GrResourceCacheEntry::didChangeResourceSize() {
6811c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org    size_t oldSize = fCachedSize;
6911c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org    fCachedSize = fResource->gpuMemorySize();
7011c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org    if (fCachedSize > oldSize) {
7111c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org        fResourceCache->didIncreaseResourceSize(this, fCachedSize - oldSize);
7211c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org    } else if (fCachedSize < oldSize) {
7311c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org        fResourceCache->didDecreaseResourceSize(this, oldSize - fCachedSize);
7411c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org    }
7511c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org}
7611c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org
77ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com///////////////////////////////////////////////////////////////////////////////
78ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
7907fc0d178e20f74a88dd78384f817b53204e625fbsalomon@google.comGrResourceCache::GrResourceCache(int maxCount, size_t maxBytes) :
8007fc0d178e20f74a88dd78384f817b53204e625fbsalomon@google.com        fMaxCount(maxCount),
8107fc0d178e20f74a88dd78384f817b53204e625fbsalomon@google.com        fMaxBytes(maxBytes) {
825955202c805c7ef1448103cbf666972ea9d1ded1robertphillips@google.com#if GR_CACHE_STATS
835f9f2f574fe9b195f5f3e40edeb2e28b673511fdrobertphillips@google.com    fHighWaterEntryCount          = 0;
845f9f2f574fe9b195f5f3e40edeb2e28b673511fdrobertphillips@google.com    fHighWaterEntryBytes          = 0;
855f9f2f574fe9b195f5f3e40edeb2e28b673511fdrobertphillips@google.com    fHighWaterClientDetachedCount = 0;
865f9f2f574fe9b195f5f3e40edeb2e28b673511fdrobertphillips@google.com    fHighWaterClientDetachedBytes = 0;
875f9f2f574fe9b195f5f3e40edeb2e28b673511fdrobertphillips@google.com#endif
885f9f2f574fe9b195f5f3e40edeb2e28b673511fdrobertphillips@google.com
895f9f2f574fe9b195f5f3e40edeb2e28b673511fdrobertphillips@google.com    fEntryCount                   = 0;
905f9f2f574fe9b195f5f3e40edeb2e28b673511fdrobertphillips@google.com    fEntryBytes                   = 0;
915f9f2f574fe9b195f5f3e40edeb2e28b673511fdrobertphillips@google.com    fClientDetachedCount          = 0;
925f9f2f574fe9b195f5f3e40edeb2e28b673511fdrobertphillips@google.com    fClientDetachedBytes          = 0;
93ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
94cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org    fPurging                      = false;
95cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org
96cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org    fOverbudgetCB                 = NULL;
97cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org    fOverbudgetData               = NULL;
98ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com}
99ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
10050398bf7f1953e640e5529616e710cf540799731bsalomon@google.comGrResourceCache::~GrResourceCache() {
10150398bf7f1953e640e5529616e710cf540799731bsalomon@google.com    GrAutoResourceCacheValidate atcv(this);
10201804b44f9e4c468ef94aa3fe609a0a1b65fde3dreed@google.com
103a292112154f803feb9f5cc002bbfab559f7cb633bsalomon@google.com    EntryList::Iter iter;
104a292112154f803feb9f5cc002bbfab559f7cb633bsalomon@google.com
105a292112154f803feb9f5cc002bbfab559f7cb633bsalomon@google.com    // Unlike the removeAll, here we really remove everything, including locked resources.
106089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.org    while (GrResourceCacheEntry* entry = fList.head()) {
107a292112154f803feb9f5cc002bbfab559f7cb633bsalomon@google.com        GrAutoResourceCacheValidate atcv(this);
108a292112154f803feb9f5cc002bbfab559f7cb633bsalomon@google.com
109a292112154f803feb9f5cc002bbfab559f7cb633bsalomon@google.com        // remove from our cache
110a292112154f803feb9f5cc002bbfab559f7cb633bsalomon@google.com        fCache.remove(entry->fKey, entry);
111a292112154f803feb9f5cc002bbfab559f7cb633bsalomon@google.com
112a292112154f803feb9f5cc002bbfab559f7cb633bsalomon@google.com        // remove from our llist
113209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com        this->internalDetach(entry);
114a292112154f803feb9f5cc002bbfab559f7cb633bsalomon@google.com
115a292112154f803feb9f5cc002bbfab559f7cb633bsalomon@google.com        delete entry;
116a292112154f803feb9f5cc002bbfab559f7cb633bsalomon@google.com    }
117ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com}
118ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
11907fc0d178e20f74a88dd78384f817b53204e625fbsalomon@google.comvoid GrResourceCache::getLimits(int* maxResources, size_t* maxResourceBytes) const{
12049f085dddff10473b6ebf832a974288300224e60bsalomon    if (maxResources) {
12107fc0d178e20f74a88dd78384f817b53204e625fbsalomon@google.com        *maxResources = fMaxCount;
12207fc0d178e20f74a88dd78384f817b53204e625fbsalomon@google.com    }
12349f085dddff10473b6ebf832a974288300224e60bsalomon    if (maxResourceBytes) {
12407fc0d178e20f74a88dd78384f817b53204e625fbsalomon@google.com        *maxResourceBytes = fMaxBytes;
12507fc0d178e20f74a88dd78384f817b53204e625fbsalomon@google.com    }
12607fc0d178e20f74a88dd78384f817b53204e625fbsalomon@google.com}
12707fc0d178e20f74a88dd78384f817b53204e625fbsalomon@google.com
12807fc0d178e20f74a88dd78384f817b53204e625fbsalomon@google.comvoid GrResourceCache::setLimits(int maxResources, size_t maxResourceBytes) {
12907fc0d178e20f74a88dd78384f817b53204e625fbsalomon@google.com    bool smaller = (maxResources < fMaxCount) || (maxResourceBytes < fMaxBytes);
13001804b44f9e4c468ef94aa3fe609a0a1b65fde3dreed@google.com
13107fc0d178e20f74a88dd78384f817b53204e625fbsalomon@google.com    fMaxCount = maxResources;
13250398bf7f1953e640e5529616e710cf540799731bsalomon@google.com    fMaxBytes = maxResourceBytes;
13301804b44f9e4c468ef94aa3fe609a0a1b65fde3dreed@google.com
13401804b44f9e4c468ef94aa3fe609a0a1b65fde3dreed@google.com    if (smaller) {
13501804b44f9e4c468ef94aa3fe609a0a1b65fde3dreed@google.com        this->purgeAsNeeded();
13601804b44f9e4c468ef94aa3fe609a0a1b65fde3dreed@google.com    }
13701804b44f9e4c468ef94aa3fe609a0a1b65fde3dreed@google.com}
13801804b44f9e4c468ef94aa3fe609a0a1b65fde3dreed@google.com
139089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.orgvoid GrResourceCache::internalDetach(GrResourceCacheEntry* entry,
140209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com                                     BudgetBehaviors behavior) {
141521eaf8cc73cebebeaf54338c51c22922ac70951robertphillips@google.com    fList.remove(entry);
142ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
143ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    // update our stats
144209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com    if (kIgnore_BudgetBehavior == behavior) {
145ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        fClientDetachedCount += 1;
14611c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org        fClientDetachedBytes += entry->fCachedSize;
1475f9f2f574fe9b195f5f3e40edeb2e28b673511fdrobertphillips@google.com
1485955202c805c7ef1448103cbf666972ea9d1ded1robertphillips@google.com#if GR_CACHE_STATS
1495f9f2f574fe9b195f5f3e40edeb2e28b673511fdrobertphillips@google.com        if (fHighWaterClientDetachedCount < fClientDetachedCount) {
1505f9f2f574fe9b195f5f3e40edeb2e28b673511fdrobertphillips@google.com            fHighWaterClientDetachedCount = fClientDetachedCount;
1515f9f2f574fe9b195f5f3e40edeb2e28b673511fdrobertphillips@google.com        }
1525f9f2f574fe9b195f5f3e40edeb2e28b673511fdrobertphillips@google.com        if (fHighWaterClientDetachedBytes < fClientDetachedBytes) {
1535f9f2f574fe9b195f5f3e40edeb2e28b673511fdrobertphillips@google.com            fHighWaterClientDetachedBytes = fClientDetachedBytes;
1545f9f2f574fe9b195f5f3e40edeb2e28b673511fdrobertphillips@google.com        }
1555f9f2f574fe9b195f5f3e40edeb2e28b673511fdrobertphillips@google.com#endif
1565f9f2f574fe9b195f5f3e40edeb2e28b673511fdrobertphillips@google.com
157ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    } else {
158f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org        SkASSERT(kAccountFor_BudgetBehavior == behavior);
159209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com
160ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        fEntryCount -= 1;
16111c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org        fEntryBytes -= entry->fCachedSize;
162ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    }
163ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com}
164ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
165089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.orgvoid GrResourceCache::attachToHead(GrResourceCacheEntry* entry,
166209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com                                   BudgetBehaviors behavior) {
167521eaf8cc73cebebeaf54338c51c22922ac70951robertphillips@google.com    fList.addToHead(entry);
168521eaf8cc73cebebeaf54338c51c22922ac70951robertphillips@google.com
169ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    // update our stats
170209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com    if (kIgnore_BudgetBehavior == behavior) {
171ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        fClientDetachedCount -= 1;
17211c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org        fClientDetachedBytes -= entry->fCachedSize;
173ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    } else {
174f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org        SkASSERT(kAccountFor_BudgetBehavior == behavior);
175209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com
176ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        fEntryCount += 1;
17711c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org        fEntryBytes += entry->fCachedSize;
1785f9f2f574fe9b195f5f3e40edeb2e28b673511fdrobertphillips@google.com
1795955202c805c7ef1448103cbf666972ea9d1ded1robertphillips@google.com#if GR_CACHE_STATS
1805f9f2f574fe9b195f5f3e40edeb2e28b673511fdrobertphillips@google.com        if (fHighWaterEntryCount < fEntryCount) {
1815f9f2f574fe9b195f5f3e40edeb2e28b673511fdrobertphillips@google.com            fHighWaterEntryCount = fEntryCount;
1825f9f2f574fe9b195f5f3e40edeb2e28b673511fdrobertphillips@google.com        }
1835f9f2f574fe9b195f5f3e40edeb2e28b673511fdrobertphillips@google.com        if (fHighWaterEntryBytes < fEntryBytes) {
1845f9f2f574fe9b195f5f3e40edeb2e28b673511fdrobertphillips@google.com            fHighWaterEntryBytes = fEntryBytes;
1855f9f2f574fe9b195f5f3e40edeb2e28b673511fdrobertphillips@google.com        }
1865f9f2f574fe9b195f5f3e40edeb2e28b673511fdrobertphillips@google.com#endif
187ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    }
188ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com}
189ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
190209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com// This functor just searches for an entry with only a single ref (from
191209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com// the texture cache itself). Presumably in this situation no one else
192209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com// is relying on the texture.
193209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.comclass GrTFindUnreffedFunctor {
194209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.compublic:
195089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.org    bool operator()(const GrResourceCacheEntry* entry) const {
196f64c6842c15e1ba126639be7578e4642cb396987bungeman@google.com        return entry->resource()->unique();
197209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com    }
198209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com};
199209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com
2006d3fe022d68fd6dd32c0fab30e24fa5a4f048946bsalomonGrGpuResource* GrResourceCache::find(const GrResourceKey& key, uint32_t ownershipFlags) {
201a9b0623eac4a473517c15418dbdc1e331ee752d2robertphillips@google.com    GrAutoResourceCacheValidate atcv(this);
202a9b0623eac4a473517c15418dbdc1e331ee752d2robertphillips@google.com
203089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.org    GrResourceCacheEntry* entry = NULL;
204209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com
205209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com    if (ownershipFlags & kNoOtherOwners_OwnershipFlag) {
206209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com        GrTFindUnreffedFunctor functor;
207209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com
208209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com        entry = fCache.find<GrTFindUnreffedFunctor>(key, functor);
209209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com    } else {
210209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com        entry = fCache.find(key);
211209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com    }
212209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com
213a9b0623eac4a473517c15418dbdc1e331ee752d2robertphillips@google.com    if (NULL == entry) {
214a9b0623eac4a473517c15418dbdc1e331ee752d2robertphillips@google.com        return NULL;
215a9b0623eac4a473517c15418dbdc1e331ee752d2robertphillips@google.com    }
216a9b0623eac4a473517c15418dbdc1e331ee752d2robertphillips@google.com
217209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com    if (ownershipFlags & kHide_OwnershipFlag) {
218209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com        this->makeExclusive(entry);
219209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com    } else {
220209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com        // Make this resource MRU
221209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com        this->internalDetach(entry);
222209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com        this->attachToHead(entry);
223209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com    }
224d07cb0c0370de521169500c26b8d534a001cf580robertphillips@google.com
2251f47f4f7325971dd53991e2bb02da94fa7c6d962robertphillips@google.com    return entry->fResource;
226ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com}
227ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
228f3dc199c0b18e35ac8de4075ecbede7a484f1b0dskia.committer@gmail.comvoid GrResourceCache::addResource(const GrResourceKey& key,
2296d3fe022d68fd6dd32c0fab30e24fa5a4f048946bsalomon                                  GrGpuResource* resource,
230209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com                                  uint32_t ownershipFlags) {
231f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(NULL == resource->getCacheEntry());
232a5a1da81d0bed4a65e9d8956e2e2b2b226d4b05dbsalomon@google.com    // we don't expect to create new resources during a purge. In theory
233a5a1da81d0bed4a65e9d8956e2e2b2b226d4b05dbsalomon@google.com    // this could cause purgeAsNeeded() into an infinite loop (e.g.
234a5a1da81d0bed4a65e9d8956e2e2b2b226d4b05dbsalomon@google.com    // each resource destroyed creates and locks 2 resources and
235a5a1da81d0bed4a65e9d8956e2e2b2b226d4b05dbsalomon@google.com    // unlocks 1 thereby causing a new purge).
236f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(!fPurging);
23750398bf7f1953e640e5529616e710cf540799731bsalomon@google.com    GrAutoResourceCacheValidate atcv(this);
238ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
23911c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org    GrResourceCacheEntry* entry = SkNEW_ARGS(GrResourceCacheEntry, (this, key, resource));
2401f47f4f7325971dd53991e2bb02da94fa7c6d962robertphillips@google.com    resource->setCacheEntry(entry);
2411f47f4f7325971dd53991e2bb02da94fa7c6d962robertphillips@google.com
242209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com    this->attachToHead(entry);
243ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    fCache.insert(key, entry);
244ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
245209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com    if (ownershipFlags & kHide_OwnershipFlag) {
246209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com        this->makeExclusive(entry);
247209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com    }
248209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com
249ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com}
250ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
251089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.orgvoid GrResourceCache::makeExclusive(GrResourceCacheEntry* entry) {
252e9a98942b4cfb179d2c726806a729f8d939cca9fbsalomon@google.com    GrAutoResourceCacheValidate atcv(this);
253521eaf8cc73cebebeaf54338c51c22922ac70951robertphillips@google.com
25411c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org    SkASSERT(!entry->fIsExclusive);
25511c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org    entry->fIsExclusive = true;
25611c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org
257209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com    // When scratch textures are detached (to hide them from future finds) they
258209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com    // still count against the resource budget
259209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com    this->internalDetach(entry, kIgnore_BudgetBehavior);
260a9b0623eac4a473517c15418dbdc1e331ee752d2robertphillips@google.com    fCache.remove(entry->key(), entry);
261521eaf8cc73cebebeaf54338c51c22922ac70951robertphillips@google.com
262515dcd36032997ce335daa0163c6d67e851bcad1commit-bot@chromium.org#ifdef SK_DEBUG
263521eaf8cc73cebebeaf54338c51c22922ac70951robertphillips@google.com    fExclusiveList.addToHead(entry);
264521eaf8cc73cebebeaf54338c51c22922ac70951robertphillips@google.com#endif
265ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com}
266ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
267089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.orgvoid GrResourceCache::removeInvalidResource(GrResourceCacheEntry* entry) {
268521eaf8cc73cebebeaf54338c51c22922ac70951robertphillips@google.com    // If the resource went invalid while it was detached then purge it
269521eaf8cc73cebebeaf54338c51c22922ac70951robertphillips@google.com    // This can happen when a 3D context was lost,
270c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon    // the client called GrContext::abandonContext() to notify Gr,
271521eaf8cc73cebebeaf54338c51c22922ac70951robertphillips@google.com    // and then later an SkGpuDevice's destructor releases its backing
272521eaf8cc73cebebeaf54338c51c22922ac70951robertphillips@google.com    // texture (which was invalidated at contextDestroyed time).
27311c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org    // TODO: Safely delete the GrResourceCacheEntry as well.
274521eaf8cc73cebebeaf54338c51c22922ac70951robertphillips@google.com    fClientDetachedCount -= 1;
275521eaf8cc73cebebeaf54338c51c22922ac70951robertphillips@google.com    fEntryCount -= 1;
27611c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org    fClientDetachedBytes -= entry->fCachedSize;
27711c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org    fEntryBytes -= entry->fCachedSize;
27811c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org    entry->fCachedSize = 0;
27915c0fea699b25343fe6f49668a5632866e1a0306robertphillips@google.com}
28015c0fea699b25343fe6f49668a5632866e1a0306robertphillips@google.com
281089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.orgvoid GrResourceCache::makeNonExclusive(GrResourceCacheEntry* entry) {
2826087975e5d9aed5b975831ade25daadedd485d2fbsalomon@google.com    GrAutoResourceCacheValidate atcv(this);
283521eaf8cc73cebebeaf54338c51c22922ac70951robertphillips@google.com
284515dcd36032997ce335daa0163c6d67e851bcad1commit-bot@chromium.org#ifdef SK_DEBUG
285521eaf8cc73cebebeaf54338c51c22922ac70951robertphillips@google.com    fExclusiveList.remove(entry);
286521eaf8cc73cebebeaf54338c51c22922ac70951robertphillips@google.com#endif
287521eaf8cc73cebebeaf54338c51c22922ac70951robertphillips@google.com
288c44be0e9e4cee5402909c06370a630eee188a8f3bsalomon    if (!entry->resource()->wasDestroyed()) {
289f3dc199c0b18e35ac8de4075ecbede7a484f1b0dskia.committer@gmail.com        // Since scratch textures still count against the cache budget even
290f3dc199c0b18e35ac8de4075ecbede7a484f1b0dskia.committer@gmail.com        // when they have been removed from the cache, re-adding them doesn't
291209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com        // alter the budget information.
292209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com        attachToHead(entry, kIgnore_BudgetBehavior);
2936087975e5d9aed5b975831ade25daadedd485d2fbsalomon@google.com        fCache.insert(entry->key(), entry);
29411c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org
29511c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org        SkASSERT(entry->fIsExclusive);
29611c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org        entry->fIsExclusive = false;
2976087975e5d9aed5b975831ade25daadedd485d2fbsalomon@google.com    } else {
298521eaf8cc73cebebeaf54338c51c22922ac70951robertphillips@google.com        this->removeInvalidResource(entry);
2996087975e5d9aed5b975831ade25daadedd485d2fbsalomon@google.com    }
300ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com}
301ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
30211c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.orgvoid GrResourceCache::didIncreaseResourceSize(const GrResourceCacheEntry* entry, size_t amountInc) {
30311c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org    fEntryBytes += amountInc;
30411c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org    if (entry->fIsExclusive) {
30511c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org        fClientDetachedBytes += amountInc;
30611c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org    }
30711c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org    this->purgeAsNeeded();
30811c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org}
30911c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org
31011c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.orgvoid GrResourceCache::didDecreaseResourceSize(const GrResourceCacheEntry* entry, size_t amountDec) {
31111c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org    fEntryBytes -= amountDec;
31211c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org    if (entry->fIsExclusive) {
31311c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org        fClientDetachedBytes -= amountDec;
31411c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org    }
31511c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org#ifdef SK_DEBUG
31611c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org    this->validate();
31711c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org#endif
31811c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org}
31911c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org
320a5a1da81d0bed4a65e9d8956e2e2b2b226d4b05dbsalomon@google.com/**
321fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com * Destroying a resource may potentially trigger the unlock of additional
322a5a1da81d0bed4a65e9d8956e2e2b2b226d4b05dbsalomon@google.com * resources which in turn will trigger a nested purge. We block the nested
323a5a1da81d0bed4a65e9d8956e2e2b2b226d4b05dbsalomon@google.com * purge using the fPurging variable. However, the initial purge will keep
324a5a1da81d0bed4a65e9d8956e2e2b2b226d4b05dbsalomon@google.com * looping until either all resources in the cache are unlocked or we've met
325a5a1da81d0bed4a65e9d8956e2e2b2b226d4b05dbsalomon@google.com * the budget. There is an assertion in createAndLock to check against a
326a5a1da81d0bed4a65e9d8956e2e2b2b226d4b05dbsalomon@google.com * resource's destructor inserting new resources into the cache. If these
327a5a1da81d0bed4a65e9d8956e2e2b2b226d4b05dbsalomon@google.com * new resources were unlocked before purgeAsNeeded completed it could
328a5a1da81d0bed4a65e9d8956e2e2b2b226d4b05dbsalomon@google.com * potentially make purgeAsNeeded loop infinitely.
32941d2532931a2e85b56ae112047d57927cb09ef6frobertphillips@google.com *
33041d2532931a2e85b56ae112047d57927cb09ef6frobertphillips@google.com * extraCount and extraBytes are added to the current resource totals to account
33141d2532931a2e85b56ae112047d57927cb09ef6frobertphillips@google.com * for incoming resources (e.g., GrContext is about to add 10MB split between
33241d2532931a2e85b56ae112047d57927cb09ef6frobertphillips@google.com * 10 textures).
333a5a1da81d0bed4a65e9d8956e2e2b2b226d4b05dbsalomon@google.com */
33441d2532931a2e85b56ae112047d57927cb09ef6frobertphillips@google.comvoid GrResourceCache::purgeAsNeeded(int extraCount, size_t extraBytes) {
335cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org    if (fPurging) {
336cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org        return;
337cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org    }
338cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org
339cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org    fPurging = true;
340cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org
34150a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    this->purgeInvalidated();
34250a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org
34341d2532931a2e85b56ae112047d57927cb09ef6frobertphillips@google.com    this->internalPurge(extraCount, extraBytes);
344a79919883e275e7a5e00afc50be10cc721f6ba1dskia.committer@gmail.com    if (((fEntryCount+extraCount) > fMaxCount ||
34541d2532931a2e85b56ae112047d57927cb09ef6frobertphillips@google.com        (fEntryBytes+extraBytes) > fMaxBytes) &&
34649f085dddff10473b6ebf832a974288300224e60bsalomon        fOverbudgetCB) {
347cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org        // Despite the purge we're still over budget. See if Ganesh can
348cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org        // release some resources and purge again.
349cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org        if ((*fOverbudgetCB)(fOverbudgetData)) {
35041d2532931a2e85b56ae112047d57927cb09ef6frobertphillips@google.com            this->internalPurge(extraCount, extraBytes);
351cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org        }
352ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    }
353cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org
354cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org    fPurging = false;
355cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org}
356cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org
35750a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.orgvoid GrResourceCache::purgeInvalidated() {
35850a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    SkTDArray<GrResourceInvalidatedMessage> invalidated;
35950a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    fInvalidationInbox.poll(&invalidated);
36050a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org
36150a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    for (int i = 0; i < invalidated.count(); i++) {
36250a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org        // We're somewhat missing an opportunity here.  We could use the
36350a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org        // default find functor that gives us back resources whether we own
36450a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org        // them exclusively or not, and when they're not exclusively owned mark
36550a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org        // them for purging later when they do become exclusively owned.
36650a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org        //
36750a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org        // This is complicated and confusing.  May try this in the future.  For
36850a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org        // now, these resources are just LRU'd as if we never got the message.
369089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.org        while (GrResourceCacheEntry* entry = fCache.find(invalidated[i].key, GrTFindUnreffedFunctor())) {
37050a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org            this->deleteResource(entry);
37150a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org        }
37250a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    }
37350a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org}
37450a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org
375089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.orgvoid GrResourceCache::deleteResource(GrResourceCacheEntry* entry) {
376dcabb05113a732636691abc16d643a091336aea5bsalomon    SkASSERT(entry->fResource->unique());
377e4eaea2d126d58d8ce4034a1ce921404e83fe3f4robertphillips@google.com
378e4eaea2d126d58d8ce4034a1ce921404e83fe3f4robertphillips@google.com    // remove from our cache
379e4eaea2d126d58d8ce4034a1ce921404e83fe3f4robertphillips@google.com    fCache.remove(entry->key(), entry);
380e4eaea2d126d58d8ce4034a1ce921404e83fe3f4robertphillips@google.com
381e4eaea2d126d58d8ce4034a1ce921404e83fe3f4robertphillips@google.com    // remove from our llist
382e4eaea2d126d58d8ce4034a1ce921404e83fe3f4robertphillips@google.com    this->internalDetach(entry);
383e4eaea2d126d58d8ce4034a1ce921404e83fe3f4robertphillips@google.com    delete entry;
384e4eaea2d126d58d8ce4034a1ce921404e83fe3f4robertphillips@google.com}
385e4eaea2d126d58d8ce4034a1ce921404e83fe3f4robertphillips@google.com
38641d2532931a2e85b56ae112047d57927cb09ef6frobertphillips@google.comvoid GrResourceCache::internalPurge(int extraCount, size_t extraBytes) {
387cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org    SkASSERT(fPurging);
388cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org
389cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org    bool withinBudget = false;
390cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org    bool changed = false;
391cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org
392cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org    // The purging process is repeated several times since one pass
393cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org    // may free up other resources
394cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org    do {
395cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org        EntryList::Iter iter;
396cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org
397cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org        changed = false;
398cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org
399cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org        // Note: the following code relies on the fact that the
400cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org        // doubly linked list doesn't invalidate its data/pointers
401cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org        // outside of the specific area where a deletion occurs (e.g.,
402cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org        // in internalDetach)
403089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.org        GrResourceCacheEntry* entry = iter.init(fList, EntryList::Iter::kTail_IterStart);
404cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org
40549f085dddff10473b6ebf832a974288300224e60bsalomon        while (entry) {
406cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org            GrAutoResourceCacheValidate atcv(this);
407cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org
408a79919883e275e7a5e00afc50be10cc721f6ba1dskia.committer@gmail.com            if ((fEntryCount+extraCount) <= fMaxCount &&
40941d2532931a2e85b56ae112047d57927cb09ef6frobertphillips@google.com                (fEntryBytes+extraBytes) <= fMaxBytes) {
410cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org                withinBudget = true;
411cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org                break;
412cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org            }
413cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org
414089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.org            GrResourceCacheEntry* prev = iter.prev();
415f64c6842c15e1ba126639be7578e4642cb396987bungeman@google.com            if (entry->fResource->unique()) {
416cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org                changed = true;
417e4eaea2d126d58d8ce4034a1ce921404e83fe3f4robertphillips@google.com                this->deleteResource(entry);
418cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org            }
419cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org            entry = prev;
420cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org        }
421cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org    } while (!withinBudget && changed);
422ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com}
423ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
424a292112154f803feb9f5cc002bbfab559f7cb633bsalomon@google.comvoid GrResourceCache::purgeAllUnlocked() {
425e9a98942b4cfb179d2c726806a729f8d939cca9fbsalomon@google.com    GrAutoResourceCacheValidate atcv(this);
42601804b44f9e4c468ef94aa3fe609a0a1b65fde3dreed@google.com
427089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.org    // we can have one GrCacheable holding a lock on another
428e9a98942b4cfb179d2c726806a729f8d939cca9fbsalomon@google.com    // so we don't want to just do a simple loop kicking each
429e9a98942b4cfb179d2c726806a729f8d939cca9fbsalomon@google.com    // entry out. Instead change the budget and purge.
430ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
431adacc7067ad617cdc7bbef39192ca80f4b4d27f9robertphillips@google.com    size_t savedMaxBytes = fMaxBytes;
43207fc0d178e20f74a88dd78384f817b53204e625fbsalomon@google.com    int savedMaxCount = fMaxCount;
43307fc0d178e20f74a88dd78384f817b53204e625fbsalomon@google.com    fMaxBytes = (size_t) -1;
43407fc0d178e20f74a88dd78384f817b53204e625fbsalomon@google.com    fMaxCount = 0;
435e9a98942b4cfb179d2c726806a729f8d939cca9fbsalomon@google.com    this->purgeAsNeeded();
436e9a98942b4cfb179d2c726806a729f8d939cca9fbsalomon@google.com
437515dcd36032997ce335daa0163c6d67e851bcad1commit-bot@chromium.org#ifdef SK_DEBUG
438f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(fExclusiveList.countEntries() == fClientDetachedCount);
439f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(countBytes(fExclusiveList) == fClientDetachedBytes);
4400ec107f396a566bac2a7787b982a76c9c27c0d2ftwiz@google.com    if (!fCache.count()) {
4410ec107f396a566bac2a7787b982a76c9c27c0d2ftwiz@google.com        // Items may have been detached from the cache (such as the backing
4420ec107f396a566bac2a7787b982a76c9c27c0d2ftwiz@google.com        // texture for an SkGpuDevice). The above purge would not have removed
4430ec107f396a566bac2a7787b982a76c9c27c0d2ftwiz@google.com        // them.
444f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org        SkASSERT(fEntryCount == fClientDetachedCount);
445f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org        SkASSERT(fEntryBytes == fClientDetachedBytes);
446f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org        SkASSERT(fList.isEmpty());
4470ec107f396a566bac2a7787b982a76c9c27c0d2ftwiz@google.com    }
4480ec107f396a566bac2a7787b982a76c9c27c0d2ftwiz@google.com#endif
449e9a98942b4cfb179d2c726806a729f8d939cca9fbsalomon@google.com
450e9a98942b4cfb179d2c726806a729f8d939cca9fbsalomon@google.com    fMaxBytes = savedMaxBytes;
45107fc0d178e20f74a88dd78384f817b53204e625fbsalomon@google.com    fMaxCount = savedMaxCount;
452ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com}
453ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
454ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com///////////////////////////////////////////////////////////////////////////////
455ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
456515dcd36032997ce335daa0163c6d67e851bcad1commit-bot@chromium.org#ifdef SK_DEBUG
457a292112154f803feb9f5cc002bbfab559f7cb633bsalomon@google.comsize_t GrResourceCache::countBytes(const EntryList& list) {
4582ea0a231a82b00e14c57806f6ae4664361d2ed16robertphillips@google.com    size_t bytes = 0;
4592ea0a231a82b00e14c57806f6ae4664361d2ed16robertphillips@google.com
460a292112154f803feb9f5cc002bbfab559f7cb633bsalomon@google.com    EntryList::Iter iter;
461fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
462089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.org    const GrResourceCacheEntry* entry = iter.init(const_cast<EntryList&>(list),
463089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.org                                                  EntryList::Iter::kTail_IterStart);
4642ea0a231a82b00e14c57806f6ae4664361d2ed16robertphillips@google.com
46549f085dddff10473b6ebf832a974288300224e60bsalomon    for ( ; entry; entry = iter.prev()) {
466089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.org        bytes += entry->resource()->gpuMemorySize();
467ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    }
4682ea0a231a82b00e14c57806f6ae4664361d2ed16robertphillips@google.com    return bytes;
469ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com}
470ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
471b89a643b6992d478c0b8bda3abc53f37a87dbd22reed@google.comstatic bool both_zero_or_nonzero(int count, size_t bytes) {
472b89a643b6992d478c0b8bda3abc53f37a87dbd22reed@google.com    return (count == 0 && bytes == 0) || (count > 0 && bytes > 0);
473b89a643b6992d478c0b8bda3abc53f37a87dbd22reed@google.com}
474b89a643b6992d478c0b8bda3abc53f37a87dbd22reed@google.com
47550398bf7f1953e640e5529616e710cf540799731bsalomon@google.comvoid GrResourceCache::validate() const {
4762ea0a231a82b00e14c57806f6ae4664361d2ed16robertphillips@google.com    fList.validate();
4772ea0a231a82b00e14c57806f6ae4664361d2ed16robertphillips@google.com    fExclusiveList.validate();
478f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(both_zero_or_nonzero(fEntryCount, fEntryBytes));
479f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(both_zero_or_nonzero(fClientDetachedCount, fClientDetachedBytes));
480f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(fClientDetachedBytes <= fEntryBytes);
481f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(fClientDetachedCount <= fEntryCount);
482f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT((fEntryCount - fClientDetachedCount) == fCache.count());
48301804b44f9e4c468ef94aa3fe609a0a1b65fde3dreed@google.com
484a292112154f803feb9f5cc002bbfab559f7cb633bsalomon@google.com    EntryList::Iter iter;
485fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
4869fbcad0f00d7098574cf3394a812c9d845c9cc5brobertphillips@google.com    // check that the exclusively held entries are okay
487089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.org    const GrResourceCacheEntry* entry = iter.init(const_cast<EntryList&>(fExclusiveList),
488089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.org                                                  EntryList::Iter::kHead_IterStart);
4892ea0a231a82b00e14c57806f6ae4664361d2ed16robertphillips@google.com
49049f085dddff10473b6ebf832a974288300224e60bsalomon    for ( ; entry; entry = iter.next()) {
491ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        entry->validate();
492d07cb0c0370de521169500c26b8d534a001cf580robertphillips@google.com    }
493d07cb0c0370de521169500c26b8d534a001cf580robertphillips@google.com
4949fbcad0f00d7098574cf3394a812c9d845c9cc5brobertphillips@google.com    // check that the shareable entries are okay
495d07cb0c0370de521169500c26b8d534a001cf580robertphillips@google.com    entry = iter.init(const_cast<EntryList&>(fList), EntryList::Iter::kHead_IterStart);
496d07cb0c0370de521169500c26b8d534a001cf580robertphillips@google.com
497d07cb0c0370de521169500c26b8d534a001cf580robertphillips@google.com    int count = 0;
49849f085dddff10473b6ebf832a974288300224e60bsalomon    for ( ; entry; entry = iter.next()) {
499d07cb0c0370de521169500c26b8d534a001cf580robertphillips@google.com        entry->validate();
500f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org        SkASSERT(fCache.find(entry->key()));
501ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        count += 1;
502ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    }
503f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(count == fEntryCount - fClientDetachedCount);
504521eaf8cc73cebebeaf54338c51c22922ac70951robertphillips@google.com
5052ea0a231a82b00e14c57806f6ae4664361d2ed16robertphillips@google.com    size_t bytes = countBytes(fList);
506f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(bytes == fEntryBytes  - fClientDetachedBytes);
507521eaf8cc73cebebeaf54338c51c22922ac70951robertphillips@google.com
5082ea0a231a82b00e14c57806f6ae4664361d2ed16robertphillips@google.com    bytes = countBytes(fExclusiveList);
509f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(bytes == fClientDetachedBytes);
510521eaf8cc73cebebeaf54338c51c22922ac70951robertphillips@google.com
511f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(fList.countEntries() == fEntryCount - fClientDetachedCount);
512521eaf8cc73cebebeaf54338c51c22922ac70951robertphillips@google.com
513f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org    SkASSERT(fExclusiveList.countEntries() == fClientDetachedCount);
514ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com}
515515dcd36032997ce335daa0163c6d67e851bcad1commit-bot@chromium.org#endif // SK_DEBUG
5165955202c805c7ef1448103cbf666972ea9d1ded1robertphillips@google.com
5175955202c805c7ef1448103cbf666972ea9d1ded1robertphillips@google.com#if GR_CACHE_STATS
5185f9f2f574fe9b195f5f3e40edeb2e28b673511fdrobertphillips@google.com
5199fbcad0f00d7098574cf3394a812c9d845c9cc5brobertphillips@google.comvoid GrResourceCache::printStats() {
5209fbcad0f00d7098574cf3394a812c9d845c9cc5brobertphillips@google.com    int locked = 0;
5219fbcad0f00d7098574cf3394a812c9d845c9cc5brobertphillips@google.com
5229fbcad0f00d7098574cf3394a812c9d845c9cc5brobertphillips@google.com    EntryList::Iter iter;
5239fbcad0f00d7098574cf3394a812c9d845c9cc5brobertphillips@google.com
524089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.org    GrResourceCacheEntry* entry = iter.init(fList, EntryList::Iter::kTail_IterStart);
5259fbcad0f00d7098574cf3394a812c9d845c9cc5brobertphillips@google.com
52649f085dddff10473b6ebf832a974288300224e60bsalomon    for ( ; entry; entry = iter.prev()) {
5279fbcad0f00d7098574cf3394a812c9d845c9cc5brobertphillips@google.com        if (entry->fResource->getRefCnt() > 1) {
5289fbcad0f00d7098574cf3394a812c9d845c9cc5brobertphillips@google.com            ++locked;
5299fbcad0f00d7098574cf3394a812c9d845c9cc5brobertphillips@google.com        }
5309fbcad0f00d7098574cf3394a812c9d845c9cc5brobertphillips@google.com    }
5319fbcad0f00d7098574cf3394a812c9d845c9cc5brobertphillips@google.com
5325f9f2f574fe9b195f5f3e40edeb2e28b673511fdrobertphillips@google.com    SkDebugf("Budget: %d items %d bytes\n", fMaxCount, fMaxBytes);
5339fbcad0f00d7098574cf3394a812c9d845c9cc5brobertphillips@google.com    SkDebugf("\t\tEntry Count: current %d (%d locked) high %d\n",
5349fbcad0f00d7098574cf3394a812c9d845c9cc5brobertphillips@google.com                fEntryCount, locked, fHighWaterEntryCount);
5355f9f2f574fe9b195f5f3e40edeb2e28b673511fdrobertphillips@google.com    SkDebugf("\t\tEntry Bytes: current %d high %d\n",
5365f9f2f574fe9b195f5f3e40edeb2e28b673511fdrobertphillips@google.com                fEntryBytes, fHighWaterEntryBytes);
5375f9f2f574fe9b195f5f3e40edeb2e28b673511fdrobertphillips@google.com    SkDebugf("\t\tDetached Entry Count: current %d high %d\n",
5385f9f2f574fe9b195f5f3e40edeb2e28b673511fdrobertphillips@google.com                fClientDetachedCount, fHighWaterClientDetachedCount);
5395f9f2f574fe9b195f5f3e40edeb2e28b673511fdrobertphillips@google.com    SkDebugf("\t\tDetached Bytes: current %d high %d\n",
5405f9f2f574fe9b195f5f3e40edeb2e28b673511fdrobertphillips@google.com                fClientDetachedBytes, fHighWaterClientDetachedBytes);
5415f9f2f574fe9b195f5f3e40edeb2e28b673511fdrobertphillips@google.com}
5425f9f2f574fe9b195f5f3e40edeb2e28b673511fdrobertphillips@google.com
543ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com#endif
544521eaf8cc73cebebeaf54338c51c22922ac70951robertphillips@google.com
545521eaf8cc73cebebeaf54338c51c22922ac70951robertphillips@google.com///////////////////////////////////////////////////////////////////////////////
546