1ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2011 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#ifndef GrResourceCache_DEFINED
1250398bf7f1953e640e5529616e710cf540799731bsalomon@google.com#define GrResourceCache_DEFINED
13ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
145955202c805c7ef1448103cbf666972ea9d1ded1robertphillips@google.com#include "GrConfig.h"
15ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com#include "GrTypes.h"
16bd58febffb103ea830bf027c5a95313548f7ea8ecommit-bot@chromium.org#include "GrTMultiMap.h"
170797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com#include "GrBinHashKey.h"
1850a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org#include "SkMessageBus.h"
1942619d8df206b0bcd36d952909d972b8961e75debsalomon@google.com#include "SkTInternalLList.h"
20ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
21089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.orgclass GrCacheable;
2211c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.orgclass GrResourceCache;
23089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.orgclass GrResourceCacheEntry;
24ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
2550398bf7f1953e640e5529616e710cf540799731bsalomon@google.comclass GrResourceKey {
26ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.compublic:
270797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com    static GrCacheID::Domain ScratchDomain() {
280797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com        static const GrCacheID::Domain gDomain = GrCacheID::GenerateDomain();
290797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com        return gDomain;
3050398bf7f1953e640e5529616e710cf540799731bsalomon@google.com    }
3150398bf7f1953e640e5529616e710cf540799731bsalomon@google.com
32089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.org    /** Uniquely identifies the GrCacheable subclass in the key to avoid collisions
330797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com        across resource types. */
340797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com    typedef uint8_t ResourceType;
350797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com
36089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.org    /** Flags set by the GrCacheable subclass. */
370797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com    typedef uint8_t ResourceFlags;
380797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com
390797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com    /** Generate a unique ResourceType */
400797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com    static ResourceType GenerateResourceType();
410797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com
420797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com    /** Creates a key for resource */
430797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com    GrResourceKey(const GrCacheID& id, ResourceType type, ResourceFlags flags) {
440797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com        this->init(id.getDomain(), id.getKey(), type, flags);
450797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com    };
46ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
470b6ad2297fbf43466950690102c1c9c150f2a972bsalomon@google.com    GrResourceKey(const GrResourceKey& src) {
480797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com        fKey = src.fKey;
49ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    }
50ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
510797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com    GrResourceKey() {
52d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com        fKey.reset();
530797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com    }
54ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
550797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com    void reset(const GrCacheID& id, ResourceType type, ResourceFlags flags) {
560797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com        this->init(id.getDomain(), id.getKey(), type, flags);
57ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    }
5801804b44f9e4c468ef94aa3fe609a0a1b65fde3dreed@google.com
59bd58febffb103ea830bf027c5a95313548f7ea8ecommit-bot@chromium.org    uint32_t getHash() const {
60bd58febffb103ea830bf027c5a95313548f7ea8ecommit-bot@chromium.org        return fKey.getHash();
61ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    }
62fea37b5e532dfe776269253afb9951e763c3b205bsalomon@google.com
630797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com    bool isScratch() const {
640797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com        return ScratchDomain() ==
65d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com            *reinterpret_cast<const GrCacheID::Domain*>(fKey.getData() +
660797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com                                                        kCacheIDDomainOffset);
67ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    }
684b86e3428b115202e82d49a0914ea8ab6dc25940bsalomon@google.com
690797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com    ResourceType getResourceType() const {
70d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com        return *reinterpret_cast<const ResourceType*>(fKey.getData() +
710797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com                                                      kResourceTypeOffset);
72ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    }
734b86e3428b115202e82d49a0914ea8ab6dc25940bsalomon@google.com
740797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com    ResourceFlags getResourceFlags() const {
75d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com        return *reinterpret_cast<const ResourceFlags*>(fKey.getData() +
760797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com                                                       kResourceFlagsOffset);
77ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    }
780797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com
79d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com    bool operator==(const GrResourceKey& other) const { return fKey == other.fKey; }
80ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
810797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.comprivate:
820797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com    enum {
830797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com        kCacheIDKeyOffset = 0,
840797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com        kCacheIDDomainOffset = kCacheIDKeyOffset + sizeof(GrCacheID::Key),
850797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com        kResourceTypeOffset = kCacheIDDomainOffset + sizeof(GrCacheID::Domain),
860797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com        kResourceFlagsOffset = kResourceTypeOffset + sizeof(ResourceType),
870797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com        kPadOffset = kResourceFlagsOffset + sizeof(ResourceFlags),
880797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com        kKeySize = SkAlign4(kPadOffset),
890797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com        kPadSize = kKeySize - kPadOffset
900797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com    };
914b86e3428b115202e82d49a0914ea8ab6dc25940bsalomon@google.com
920797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com    void init(const GrCacheID::Domain domain,
930797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com              const GrCacheID::Key& key,
940797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com              ResourceType type,
950797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com              ResourceFlags flags) {
960797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com        union {
970797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com            uint8_t  fKey8[kKeySize];
980797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com            uint32_t fKey32[kKeySize / 4];
990797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com        } keyData;
1002859eb74f9c87471b2429cd12b84144b97157efbskia.committer@gmail.com
1010797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com        uint8_t* k = keyData.fKey8;
1020797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com        memcpy(k + kCacheIDKeyOffset, key.fData8, sizeof(GrCacheID::Key));
1030797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com        memcpy(k + kCacheIDDomainOffset, &domain, sizeof(GrCacheID::Domain));
1040797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com        memcpy(k + kResourceTypeOffset, &type, sizeof(ResourceType));
1050797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com        memcpy(k + kResourceFlagsOffset, &flags, sizeof(ResourceFlags));
1060797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com        memset(k + kPadOffset, 0, kPadSize);
107d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com        fKey.setKeyData(keyData.fKey32);
1080797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com    }
109d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com    GrBinHashKey<kKeySize> fKey;
1100797c2cceadd7dfc2e7f9efa30b611d18efcdcddbsalomon@google.com};
1110b6ad2297fbf43466950690102c1c9c150f2a972bsalomon@google.com
11250a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org// The cache listens for these messages to purge junk resources proactively.
11350a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.orgstruct GrResourceInvalidatedMessage {
11450a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    GrResourceKey key;
11550a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org};
11650a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org
117ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com///////////////////////////////////////////////////////////////////////////////
118ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
119089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.orgclass GrResourceCacheEntry {
120ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.compublic:
121089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.org    GrCacheable* resource() const { return fResource; }
12250398bf7f1953e640e5529616e710cf540799731bsalomon@google.com    const GrResourceKey& key() const { return fKey; }
123ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
124089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.org    static const GrResourceKey& GetKey(const GrResourceCacheEntry& e) { return e.key(); }
125bd58febffb103ea830bf027c5a95313548f7ea8ecommit-bot@chromium.org    static uint32_t Hash(const GrResourceKey& key) { return key.getHash(); }
126515dcd36032997ce335daa0163c6d67e851bcad1commit-bot@chromium.org#ifdef SK_DEBUG
127ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    void validate() const;
128ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com#else
129ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    void validate() const {}
130ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com#endif
131ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
13211c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org    /**
13311c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org     *  Update the cached size for this entry and inform the resource cache that
13411c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org     *  it has changed. Usually invoked from GrCacheable::didChangeGpuMemorySize,
13511c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org     *  not directly from here.
13611c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org     */
13711c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org    void didChangeResourceSize();
13811c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org
139ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.comprivate:
14011c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org    GrResourceCacheEntry(GrResourceCache* resourceCache,
14111c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org                         const GrResourceKey& key,
14211c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org                         GrCacheable* resource);
143089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.org    ~GrResourceCacheEntry();
144ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
14511c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org    GrResourceCache* fResourceCache;
14650398bf7f1953e640e5529616e710cf540799731bsalomon@google.com    GrResourceKey    fKey;
147089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.org    GrCacheable*     fResource;
14811c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org    size_t           fCachedSize;
14911c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org    bool             fIsExclusive;
150ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
151bd58febffb103ea830bf027c5a95313548f7ea8ecommit-bot@chromium.org    // Linked list for the LRU ordering.
152089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.org    SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrResourceCacheEntry);
153ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
15450398bf7f1953e640e5529616e710cf540799731bsalomon@google.com    friend class GrResourceCache;
155ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com};
156ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
157ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com///////////////////////////////////////////////////////////////////////////////
158ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
159ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com/**
160089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.org *  Cache of GrCacheable objects.
161ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com *
16250398bf7f1953e640e5529616e710cf540799731bsalomon@google.com *  These have a corresponding GrResourceKey, built from 128bits identifying the
163bd58febffb103ea830bf027c5a95313548f7ea8ecommit-bot@chromium.org *  resource. Multiple resources can map to same GrResourceKey.
164ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com *
165ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com *  The cache stores the entries in a double-linked list, which is its LRU.
166ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com *  When an entry is "locked" (i.e. given to the caller), it is moved to the
167ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com *  head of the list. If/when we must purge some of the entries, we walk the
168ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com *  list backwards from the tail, since those are the least recently used.
169ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com *
170bd58febffb103ea830bf027c5a95313548f7ea8ecommit-bot@chromium.org *  For fast searches, we maintain a hash map based on the GrResourceKey.
17176202b8dc39652b2832b279fc4cb798a0ea03ed3bsalomon@google.com *
17276202b8dc39652b2832b279fc4cb798a0ea03ed3bsalomon@google.com *  It is a goal to make the GrResourceCache the central repository and bookkeeper
173089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.org *  of all resources. It should replace the linked list of GrGpuObjects that
17476202b8dc39652b2832b279fc4cb798a0ea03ed3bsalomon@google.com *  GrGpu uses to call abandon/release.
175ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com */
17650398bf7f1953e640e5529616e710cf540799731bsalomon@google.comclass GrResourceCache {
177ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.compublic:
17807fc0d178e20f74a88dd78384f817b53204e625fbsalomon@google.com    GrResourceCache(int maxCount, size_t maxBytes);
17950398bf7f1953e640e5529616e710cf540799731bsalomon@google.com    ~GrResourceCache();
180ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
181ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    /**
18207fc0d178e20f74a88dd78384f817b53204e625fbsalomon@google.com     *  Return the current resource cache limits.
18307fc0d178e20f74a88dd78384f817b53204e625fbsalomon@google.com     *
184fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com     *  @param maxResource If non-null, returns maximum number of resources
18507fc0d178e20f74a88dd78384f817b53204e625fbsalomon@google.com     *                     that can be held in the cache.
18607fc0d178e20f74a88dd78384f817b53204e625fbsalomon@google.com     *  @param maxBytes    If non-null, returns maximum number of bytes of
187e4eaea2d126d58d8ce4034a1ce921404e83fe3f4robertphillips@google.com     *                     gpu memory that can be held in the cache.
18801804b44f9e4c468ef94aa3fe609a0a1b65fde3dreed@google.com     */
18907fc0d178e20f74a88dd78384f817b53204e625fbsalomon@google.com    void getLimits(int* maxResources, size_t* maxBytes) const;
19001804b44f9e4c468ef94aa3fe609a0a1b65fde3dreed@google.com
19101804b44f9e4c468ef94aa3fe609a0a1b65fde3dreed@google.com    /**
19207fc0d178e20f74a88dd78384f817b53204e625fbsalomon@google.com     *  Specify the resource cache limits. If the current cache exceeds either
19307fc0d178e20f74a88dd78384f817b53204e625fbsalomon@google.com     *  of these, it will be purged (LRU) to keep the cache within these limits.
19401804b44f9e4c468ef94aa3fe609a0a1b65fde3dreed@google.com     *
19507fc0d178e20f74a88dd78384f817b53204e625fbsalomon@google.com     *  @param maxResources The maximum number of resources that can be held in
19607fc0d178e20f74a88dd78384f817b53204e625fbsalomon@google.com     *                      the cache.
19707fc0d178e20f74a88dd78384f817b53204e625fbsalomon@google.com     *  @param maxBytes     The maximum number of bytes of resource memory that
19807fc0d178e20f74a88dd78384f817b53204e625fbsalomon@google.com     *                      can be held in the cache.
19901804b44f9e4c468ef94aa3fe609a0a1b65fde3dreed@google.com     */
200e4eaea2d126d58d8ce4034a1ce921404e83fe3f4robertphillips@google.com    void setLimits(int maxResources, size_t maxResourceBytes);
20101804b44f9e4c468ef94aa3fe609a0a1b65fde3dreed@google.com
20201804b44f9e4c468ef94aa3fe609a0a1b65fde3dreed@google.com    /**
203cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org     *  The callback function used by the cache when it is still over budget
204de2e4e8a6422c7d8b5847f038f5c6360b187f7a2skia.committer@gmail.com     *  after a purge. The passed in 'data' is the same 'data' handed to
205cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org     *  setOverbudgetCallback. The callback returns true if some resources
206cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org     *  have been freed.
207cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org     */
208cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org    typedef bool (*PFOverbudgetCB)(void* data);
209cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org
210cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org    /**
211cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org     *  Set the callback the cache should use when it is still over budget
212de2e4e8a6422c7d8b5847f038f5c6360b187f7a2skia.committer@gmail.com     *  after a purge. The 'data' provided here will be passed back to the
2131f3c73825b8a1752abc6b74fbce978a430de6473skia.committer@gmail.com     *  callback. Note that the cache will attempt to purge any resources newly
214e4eaea2d126d58d8ce4034a1ce921404e83fe3f4robertphillips@google.com     *  freed by the callback.
215cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org     */
216cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org    void setOverbudgetCallback(PFOverbudgetCB overbudgetCB, void* data) {
217cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org        fOverbudgetCB = overbudgetCB;
218cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org        fOverbudgetData = data;
219cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org    }
220cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org
221cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org    /**
22205e70247c31ae927074ef27ea9893634a8dda543twiz@google.com     * Returns the number of bytes consumed by cached resources.
22305e70247c31ae927074ef27ea9893634a8dda543twiz@google.com     */
22405e70247c31ae927074ef27ea9893634a8dda543twiz@google.com    size_t getCachedResourceBytes() const { return fEntryBytes; }
22505e70247c31ae927074ef27ea9893634a8dda543twiz@google.com
226d8a57af725e8fa8905207df3cf7465be50598752commit-bot@chromium.org    /**
227d8a57af725e8fa8905207df3cf7465be50598752commit-bot@chromium.org     * Returns the number of cached resources.
228d8a57af725e8fa8905207df3cf7465be50598752commit-bot@chromium.org     */
229d8a57af725e8fa8905207df3cf7465be50598752commit-bot@chromium.org    int getCachedResourceCount() const { return fEntryCount; }
230d8a57af725e8fa8905207df3cf7465be50598752commit-bot@chromium.org
231209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com    // For a found or added resource to be completely exclusive to the caller
232209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com    // both the kNoOtherOwners and kHide flags need to be specified
233209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com    enum OwnershipFlags {
234209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com        kNoOtherOwners_OwnershipFlag = 0x1, // found/added resource has no other owners
235209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com        kHide_OwnershipFlag = 0x2  // found/added resource is hidden from future 'find's
236209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com    };
237209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com
23805e70247c31ae927074ef27ea9893634a8dda543twiz@google.com    /**
239a9b0623eac4a473517c15418dbdc1e331ee752d2robertphillips@google.com     *  Search for an entry with the same Key. If found, return it.
240a9b0623eac4a473517c15418dbdc1e331ee752d2robertphillips@google.com     *  If not found, return null.
241f3dc199c0b18e35ac8de4075ecbede7a484f1b0dskia.committer@gmail.com     *  If ownershipFlags includes kNoOtherOwners and a resource is returned
242209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com     *  then that resource has no other refs to it.
243209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com     *  If ownershipFlags includes kHide and a resource is returned then that
244209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com     *  resource will not be returned from future 'find' calls until it is
245209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com     *  'freed' (and recycled) or makeNonExclusive is called.
246209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com     *  For a resource to be completely exclusive to a caller both kNoOtherOwners
247209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com     *  and kHide must be specified.
248a9b0623eac4a473517c15418dbdc1e331ee752d2robertphillips@google.com     */
249089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.org    GrCacheable* find(const GrResourceKey& key,
250089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.org                      uint32_t ownershipFlags = 0);
251a9b0623eac4a473517c15418dbdc1e331ee752d2robertphillips@google.com
252a9b0623eac4a473517c15418dbdc1e331ee752d2robertphillips@google.com    /**
253f3dc199c0b18e35ac8de4075ecbede7a484f1b0dskia.committer@gmail.com     *  Add the new resource to the cache (by creating a new cache entry based
254f3dc199c0b18e35ac8de4075ecbede7a484f1b0dskia.committer@gmail.com     *  on the provided key and resource).
255ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com     *
256fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com     *  Ownership of the resource is transferred to the resource cache,
25715c0fea699b25343fe6f49668a5632866e1a0306robertphillips@google.com     *  which will unref() it when it is purged or deleted.
258209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com     *
259209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com     *  If ownershipFlags includes kHide, subsequent calls to 'find' will not
260f3dc199c0b18e35ac8de4075ecbede7a484f1b0dskia.committer@gmail.com     *  return 'resource' until it is 'freed' (and recycled) or makeNonExclusive
261209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com     *  is called.
262ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com     */
263f3dc199c0b18e35ac8de4075ecbede7a484f1b0dskia.committer@gmail.com    void addResource(const GrResourceKey& key,
264089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.org                     GrCacheable* resource,
265209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com                     uint32_t ownershipFlags = 0);
26601804b44f9e4c468ef94aa3fe609a0a1b65fde3dreed@google.com
267ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    /**
268fb30951cd9346a7a2d36e7d5f81f9e7ee792b669bsalomon@google.com     * Determines if the cache contains an entry matching a key. If a matching
269fb30951cd9346a7a2d36e7d5f81f9e7ee792b669bsalomon@google.com     * entry exists but was detached then it will not be found.
270fb30951cd9346a7a2d36e7d5f81f9e7ee792b669bsalomon@google.com     */
271e4eaea2d126d58d8ce4034a1ce921404e83fe3f4robertphillips@google.com    bool hasKey(const GrResourceKey& key) const { return NULL != fCache.find(key); }
272fb30951cd9346a7a2d36e7d5f81f9e7ee792b669bsalomon@google.com
273fb30951cd9346a7a2d36e7d5f81f9e7ee792b669bsalomon@google.com    /**
274521eaf8cc73cebebeaf54338c51c22922ac70951robertphillips@google.com     * Hide 'entry' so that future searches will not find it. Such
275521eaf8cc73cebebeaf54338c51c22922ac70951robertphillips@google.com     * hidden entries will not be purged. The entry still counts against
276521eaf8cc73cebebeaf54338c51c22922ac70951robertphillips@google.com     * the cache's budget and should be made non-exclusive when exclusive access
277521eaf8cc73cebebeaf54338c51c22922ac70951robertphillips@google.com     * is no longer needed.
278ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com     */
279089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.org    void makeExclusive(GrResourceCacheEntry* entry);
28015c0fea699b25343fe6f49668a5632866e1a0306robertphillips@google.com
281ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    /**
282521eaf8cc73cebebeaf54338c51c22922ac70951robertphillips@google.com     * Restore 'entry' so that it can be found by future searches. 'entry'
283521eaf8cc73cebebeaf54338c51c22922ac70951robertphillips@google.com     * will also be purgeable (provided its lock count is now 0.)
284ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com     */
285089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.org    void makeNonExclusive(GrResourceCacheEntry* entry);
286ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
287ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    /**
28811c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org     * Notify the cache that the size of a resource has changed.
28911c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org     */
29011c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org    void didIncreaseResourceSize(const GrResourceCacheEntry*, size_t amountInc);
29111c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org    void didDecreaseResourceSize(const GrResourceCacheEntry*, size_t amountDec);
29211c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org
29311c6b39cfa24f812ceb115589f51a60a56ef14fecommit-bot@chromium.org    /**
294e4eaea2d126d58d8ce4034a1ce921404e83fe3f4robertphillips@google.com     * Remove a resource from the cache and delete it!
295e4eaea2d126d58d8ce4034a1ce921404e83fe3f4robertphillips@google.com     */
296089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.org    void deleteResource(GrResourceCacheEntry* entry);
297e4eaea2d126d58d8ce4034a1ce921404e83fe3f4robertphillips@google.com
298e4eaea2d126d58d8ce4034a1ce921404e83fe3f4robertphillips@google.com    /**
299a292112154f803feb9f5cc002bbfab559f7cb633bsalomon@google.com     * Removes every resource in the cache that isn't locked.
300a292112154f803feb9f5cc002bbfab559f7cb633bsalomon@google.com     */
301a292112154f803feb9f5cc002bbfab559f7cb633bsalomon@google.com    void purgeAllUnlocked();
302ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
30350a035ddbb068446645b0978f4c092dec87a1a02robertphillips@google.com    /**
30450a035ddbb068446645b0978f4c092dec87a1a02robertphillips@google.com     * Allow cache to purge unused resources to obey resource limitations
3059fbcad0f00d7098574cf3394a812c9d845c9cc5brobertphillips@google.com     * Note: this entry point will be hidden (again) once totally ref-driven
306e4eaea2d126d58d8ce4034a1ce921404e83fe3f4robertphillips@google.com     * cache maintenance is implemented. Note that the overbudget callback
307e4eaea2d126d58d8ce4034a1ce921404e83fe3f4robertphillips@google.com     * will be called if the initial purge doesn't get the cache under
308e4eaea2d126d58d8ce4034a1ce921404e83fe3f4robertphillips@google.com     * its budget.
30941d2532931a2e85b56ae112047d57927cb09ef6frobertphillips@google.com     *
31041d2532931a2e85b56ae112047d57927cb09ef6frobertphillips@google.com     * extraCount and extraBytes are added to the current resource allocation
31141d2532931a2e85b56ae112047d57927cb09ef6frobertphillips@google.com     * to make sure enough room is available for future additions (e.g,
31241d2532931a2e85b56ae112047d57927cb09ef6frobertphillips@google.com     * 10MB across 10 textures is about to be added).
31350a035ddbb068446645b0978f4c092dec87a1a02robertphillips@google.com     */
31441d2532931a2e85b56ae112047d57927cb09ef6frobertphillips@google.com    void purgeAsNeeded(int extraCount = 0, size_t extraBytes = 0);
31550a035ddbb068446645b0978f4c092dec87a1a02robertphillips@google.com
316515dcd36032997ce335daa0163c6d67e851bcad1commit-bot@chromium.org#ifdef SK_DEBUG
317ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    void validate() const;
318ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com#else
319ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    void validate() const {}
320ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com#endif
321ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
3225955202c805c7ef1448103cbf666972ea9d1ded1robertphillips@google.com#if GR_CACHE_STATS
3239fbcad0f00d7098574cf3394a812c9d845c9cc5brobertphillips@google.com    void printStats();
3245955202c805c7ef1448103cbf666972ea9d1ded1robertphillips@google.com#endif
3255955202c805c7ef1448103cbf666972ea9d1ded1robertphillips@google.com
326ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.comprivate:
327209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com    enum BudgetBehaviors {
328209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com        kAccountFor_BudgetBehavior,
329209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com        kIgnore_BudgetBehavior
330209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com    };
331209a1143a1a26935578d45c7f86dc6f9aa2eb1a6robertphillips@google.com
332089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.org    void internalDetach(GrResourceCacheEntry*, BudgetBehaviors behavior = kAccountFor_BudgetBehavior);
333089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.org    void attachToHead(GrResourceCacheEntry*, BudgetBehaviors behavior = kAccountFor_BudgetBehavior);
334ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
335089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.org    void removeInvalidResource(GrResourceCacheEntry* entry);
336521eaf8cc73cebebeaf54338c51c22922ac70951robertphillips@google.com
337089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.org    GrTMultiMap<GrResourceCacheEntry, GrResourceKey> fCache;
338ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
33942619d8df206b0bcd36d952909d972b8961e75debsalomon@google.com    // We're an internal doubly linked list
340089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.org    typedef SkTInternalLList<GrResourceCacheEntry> EntryList;
341e4eaea2d126d58d8ce4034a1ce921404e83fe3f4robertphillips@google.com    EntryList      fList;
342521eaf8cc73cebebeaf54338c51c22922ac70951robertphillips@google.com
343515dcd36032997ce335daa0163c6d67e851bcad1commit-bot@chromium.org#ifdef SK_DEBUG
344521eaf8cc73cebebeaf54338c51c22922ac70951robertphillips@google.com    // These objects cannot be returned by a search
345e4eaea2d126d58d8ce4034a1ce921404e83fe3f4robertphillips@google.com    EntryList      fExclusiveList;
346521eaf8cc73cebebeaf54338c51c22922ac70951robertphillips@google.com#endif
347ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
348ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    // our budget, used in purgeAsNeeded()
349e4eaea2d126d58d8ce4034a1ce921404e83fe3f4robertphillips@google.com    int            fMaxCount;
350e4eaea2d126d58d8ce4034a1ce921404e83fe3f4robertphillips@google.com    size_t         fMaxBytes;
351ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
352ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    // our current stats, related to our budget
3535955202c805c7ef1448103cbf666972ea9d1ded1robertphillips@google.com#if GR_CACHE_STATS
354e4eaea2d126d58d8ce4034a1ce921404e83fe3f4robertphillips@google.com    int            fHighWaterEntryCount;
355e4eaea2d126d58d8ce4034a1ce921404e83fe3f4robertphillips@google.com    size_t         fHighWaterEntryBytes;
356e4eaea2d126d58d8ce4034a1ce921404e83fe3f4robertphillips@google.com    int            fHighWaterClientDetachedCount;
357e4eaea2d126d58d8ce4034a1ce921404e83fe3f4robertphillips@google.com    size_t         fHighWaterClientDetachedBytes;
3585f9f2f574fe9b195f5f3e40edeb2e28b673511fdrobertphillips@google.com#endif
3595f9f2f574fe9b195f5f3e40edeb2e28b673511fdrobertphillips@google.com
360e4eaea2d126d58d8ce4034a1ce921404e83fe3f4robertphillips@google.com    int            fEntryCount;
361e4eaea2d126d58d8ce4034a1ce921404e83fe3f4robertphillips@google.com    size_t         fEntryBytes;
362e4eaea2d126d58d8ce4034a1ce921404e83fe3f4robertphillips@google.com    int            fClientDetachedCount;
363e4eaea2d126d58d8ce4034a1ce921404e83fe3f4robertphillips@google.com    size_t         fClientDetachedBytes;
364386319eebb806f62a60b16826750f364edc94ce5robertphillips@google.com
365a5a1da81d0bed4a65e9d8956e2e2b2b226d4b05dbsalomon@google.com    // prevents recursive purging
366cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org    bool           fPurging;
367cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org
368cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org    PFOverbudgetCB fOverbudgetCB;
369cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org    void*          fOverbudgetData;
370cae27fed5e45e8899e56ece22b27e8958ffc0162commit-bot@chromium.org
37141d2532931a2e85b56ae112047d57927cb09ef6frobertphillips@google.com    void internalPurge(int extraCount, size_t extraBytes);
37215c0fea699b25343fe6f49668a5632866e1a0306robertphillips@google.com
37350a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    // Listen for messages that a resource has been invalidated and purge cached junk proactively.
37450a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    SkMessageBus<GrResourceInvalidatedMessage>::Inbox fInvalidationInbox;
37550a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org    void purgeInvalidated();
37650a3043194cf278a74ff51c33c6cdb52cbe1f8f9commit-bot@chromium.org
377515dcd36032997ce335daa0163c6d67e851bcad1commit-bot@chromium.org#ifdef SK_DEBUG
378089a780c3355129eefc942246534bc1f126b8ccbcommit-bot@chromium.org    static size_t countBytes(const SkTInternalLList<GrResourceCacheEntry>& list);
3792ea0a231a82b00e14c57806f6ae4664361d2ed16robertphillips@google.com#endif
380ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com};
381ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
382ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com///////////////////////////////////////////////////////////////////////////////
383ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
384515dcd36032997ce335daa0163c6d67e851bcad1commit-bot@chromium.org#ifdef SK_DEBUG
38550398bf7f1953e640e5529616e710cf540799731bsalomon@google.com    class GrAutoResourceCacheValidate {
386ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    public:
38750398bf7f1953e640e5529616e710cf540799731bsalomon@google.com        GrAutoResourceCacheValidate(GrResourceCache* cache) : fCache(cache) {
388ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com            cache->validate();
389ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        }
39050398bf7f1953e640e5529616e710cf540799731bsalomon@google.com        ~GrAutoResourceCacheValidate() {
391ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com            fCache->validate();
392ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com        }
393ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    private:
39450398bf7f1953e640e5529616e710cf540799731bsalomon@google.com        GrResourceCache* fCache;
395ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    };
396ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com#else
39750398bf7f1953e640e5529616e710cf540799731bsalomon@google.com    class GrAutoResourceCacheValidate {
398ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    public:
39950398bf7f1953e640e5529616e710cf540799731bsalomon@google.com        GrAutoResourceCacheValidate(GrResourceCache*) {}
400ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com    };
401ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com#endif
402ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
403ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com#endif
404