gfx/skia/trunk/src/gpu/GrResourceCache.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/skia/trunk/src/gpu/GrResourceCache.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,386 @@
     1.4 +
     1.5 +/*
     1.6 + * Copyright 2011 Google Inc.
     1.7 + *
     1.8 + * Use of this source code is governed by a BSD-style license that can be
     1.9 + * found in the LICENSE file.
    1.10 + */
    1.11 +
    1.12 +
    1.13 +
    1.14 +#ifndef GrResourceCache_DEFINED
    1.15 +#define GrResourceCache_DEFINED
    1.16 +
    1.17 +#include "GrConfig.h"
    1.18 +#include "GrTypes.h"
    1.19 +#include "GrTMultiMap.h"
    1.20 +#include "GrBinHashKey.h"
    1.21 +#include "SkMessageBus.h"
    1.22 +#include "SkTInternalLList.h"
    1.23 +
    1.24 +class GrResource;
    1.25 +class GrResourceEntry;
    1.26 +
    1.27 +class GrResourceKey {
    1.28 +public:
    1.29 +    static GrCacheID::Domain ScratchDomain() {
    1.30 +        static const GrCacheID::Domain gDomain = GrCacheID::GenerateDomain();
    1.31 +        return gDomain;
    1.32 +    }
    1.33 +
    1.34 +    /** Uniquely identifies the GrResource subclass in the key to avoid collisions
    1.35 +        across resource types. */
    1.36 +    typedef uint8_t ResourceType;
    1.37 +
    1.38 +    /** Flags set by the GrResource subclass. */
    1.39 +    typedef uint8_t ResourceFlags;
    1.40 +
    1.41 +    /** Generate a unique ResourceType */
    1.42 +    static ResourceType GenerateResourceType();
    1.43 +
    1.44 +    /** Creates a key for resource */
    1.45 +    GrResourceKey(const GrCacheID& id, ResourceType type, ResourceFlags flags) {
    1.46 +        this->init(id.getDomain(), id.getKey(), type, flags);
    1.47 +    };
    1.48 +
    1.49 +    GrResourceKey(const GrResourceKey& src) {
    1.50 +        fKey = src.fKey;
    1.51 +    }
    1.52 +
    1.53 +    GrResourceKey() {
    1.54 +        fKey.reset();
    1.55 +    }
    1.56 +
    1.57 +    void reset(const GrCacheID& id, ResourceType type, ResourceFlags flags) {
    1.58 +        this->init(id.getDomain(), id.getKey(), type, flags);
    1.59 +    }
    1.60 +
    1.61 +    uint32_t getHash() const {
    1.62 +        return fKey.getHash();
    1.63 +    }
    1.64 +
    1.65 +    bool isScratch() const {
    1.66 +        return ScratchDomain() ==
    1.67 +            *reinterpret_cast<const GrCacheID::Domain*>(fKey.getData() +
    1.68 +                                                        kCacheIDDomainOffset);
    1.69 +    }
    1.70 +
    1.71 +    ResourceType getResourceType() const {
    1.72 +        return *reinterpret_cast<const ResourceType*>(fKey.getData() +
    1.73 +                                                      kResourceTypeOffset);
    1.74 +    }
    1.75 +
    1.76 +    ResourceFlags getResourceFlags() const {
    1.77 +        return *reinterpret_cast<const ResourceFlags*>(fKey.getData() +
    1.78 +                                                       kResourceFlagsOffset);
    1.79 +    }
    1.80 +
    1.81 +    bool operator==(const GrResourceKey& other) const { return fKey == other.fKey; }
    1.82 +
    1.83 +private:
    1.84 +    enum {
    1.85 +        kCacheIDKeyOffset = 0,
    1.86 +        kCacheIDDomainOffset = kCacheIDKeyOffset + sizeof(GrCacheID::Key),
    1.87 +        kResourceTypeOffset = kCacheIDDomainOffset + sizeof(GrCacheID::Domain),
    1.88 +        kResourceFlagsOffset = kResourceTypeOffset + sizeof(ResourceType),
    1.89 +        kPadOffset = kResourceFlagsOffset + sizeof(ResourceFlags),
    1.90 +        kKeySize = SkAlign4(kPadOffset),
    1.91 +        kPadSize = kKeySize - kPadOffset
    1.92 +    };
    1.93 +
    1.94 +    void init(const GrCacheID::Domain domain,
    1.95 +              const GrCacheID::Key& key,
    1.96 +              ResourceType type,
    1.97 +              ResourceFlags flags) {
    1.98 +        union {
    1.99 +            uint8_t  fKey8[kKeySize];
   1.100 +            uint32_t fKey32[kKeySize / 4];
   1.101 +        } keyData;
   1.102 +
   1.103 +        uint8_t* k = keyData.fKey8;
   1.104 +        memcpy(k + kCacheIDKeyOffset, key.fData8, sizeof(GrCacheID::Key));
   1.105 +        memcpy(k + kCacheIDDomainOffset, &domain, sizeof(GrCacheID::Domain));
   1.106 +        memcpy(k + kResourceTypeOffset, &type, sizeof(ResourceType));
   1.107 +        memcpy(k + kResourceFlagsOffset, &flags, sizeof(ResourceFlags));
   1.108 +        memset(k + kPadOffset, 0, kPadSize);
   1.109 +        fKey.setKeyData(keyData.fKey32);
   1.110 +    }
   1.111 +    GrBinHashKey<kKeySize> fKey;
   1.112 +};
   1.113 +
   1.114 +// The cache listens for these messages to purge junk resources proactively.
   1.115 +struct GrResourceInvalidatedMessage {
   1.116 +    GrResourceKey key;
   1.117 +};
   1.118 +
   1.119 +///////////////////////////////////////////////////////////////////////////////
   1.120 +
   1.121 +class GrResourceEntry {
   1.122 +public:
   1.123 +    GrResource* resource() const { return fResource; }
   1.124 +    const GrResourceKey& key() const { return fKey; }
   1.125 +
   1.126 +    static const GrResourceKey& GetKey(const GrResourceEntry& e) { return e.key(); }
   1.127 +    static uint32_t Hash(const GrResourceKey& key) { return key.getHash(); }
   1.128 +    static bool Equal(const GrResourceEntry& a, const GrResourceKey& b) {
   1.129 +        return a.key() == b;
   1.130 +    }
   1.131 +#ifdef SK_DEBUG
   1.132 +    void validate() const;
   1.133 +#else
   1.134 +    void validate() const {}
   1.135 +#endif
   1.136 +
   1.137 +private:
   1.138 +    GrResourceEntry(const GrResourceKey& key, GrResource* resource);
   1.139 +    ~GrResourceEntry();
   1.140 +
   1.141 +    GrResourceKey    fKey;
   1.142 +    GrResource*      fResource;
   1.143 +
   1.144 +    // Linked list for the LRU ordering.
   1.145 +    SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrResourceEntry);
   1.146 +
   1.147 +    friend class GrResourceCache;
   1.148 +};
   1.149 +
   1.150 +///////////////////////////////////////////////////////////////////////////////
   1.151 +
   1.152 +/**
   1.153 + *  Cache of GrResource objects.
   1.154 + *
   1.155 + *  These have a corresponding GrResourceKey, built from 128bits identifying the
   1.156 + *  resource. Multiple resources can map to same GrResourceKey.
   1.157 + *
   1.158 + *  The cache stores the entries in a double-linked list, which is its LRU.
   1.159 + *  When an entry is "locked" (i.e. given to the caller), it is moved to the
   1.160 + *  head of the list. If/when we must purge some of the entries, we walk the
   1.161 + *  list backwards from the tail, since those are the least recently used.
   1.162 + *
   1.163 + *  For fast searches, we maintain a hash map based on the GrResourceKey.
   1.164 + *
   1.165 + *  It is a goal to make the GrResourceCache the central repository and bookkeeper
   1.166 + *  of all resources. It should replace the linked list of GrResources that
   1.167 + *  GrGpu uses to call abandon/release.
   1.168 + */
   1.169 +class GrResourceCache {
   1.170 +public:
   1.171 +    GrResourceCache(int maxCount, size_t maxBytes);
   1.172 +    ~GrResourceCache();
   1.173 +
   1.174 +    /**
   1.175 +     *  Return the current resource cache limits.
   1.176 +     *
   1.177 +     *  @param maxResource If non-null, returns maximum number of resources
   1.178 +     *                     that can be held in the cache.
   1.179 +     *  @param maxBytes    If non-null, returns maximum number of bytes of
   1.180 +     *                     gpu memory that can be held in the cache.
   1.181 +     */
   1.182 +    void getLimits(int* maxResources, size_t* maxBytes) const;
   1.183 +
   1.184 +    /**
   1.185 +     *  Specify the resource cache limits. If the current cache exceeds either
   1.186 +     *  of these, it will be purged (LRU) to keep the cache within these limits.
   1.187 +     *
   1.188 +     *  @param maxResources The maximum number of resources that can be held in
   1.189 +     *                      the cache.
   1.190 +     *  @param maxBytes     The maximum number of bytes of resource memory that
   1.191 +     *                      can be held in the cache.
   1.192 +     */
   1.193 +    void setLimits(int maxResources, size_t maxResourceBytes);
   1.194 +
   1.195 +    /**
   1.196 +     *  The callback function used by the cache when it is still over budget
   1.197 +     *  after a purge. The passed in 'data' is the same 'data' handed to
   1.198 +     *  setOverbudgetCallback. The callback returns true if some resources
   1.199 +     *  have been freed.
   1.200 +     */
   1.201 +    typedef bool (*PFOverbudgetCB)(void* data);
   1.202 +
   1.203 +    /**
   1.204 +     *  Set the callback the cache should use when it is still over budget
   1.205 +     *  after a purge. The 'data' provided here will be passed back to the
   1.206 +     *  callback. Note that the cache will attempt to purge any resources newly
   1.207 +     *  freed by the callback.
   1.208 +     */
   1.209 +    void setOverbudgetCallback(PFOverbudgetCB overbudgetCB, void* data) {
   1.210 +        fOverbudgetCB = overbudgetCB;
   1.211 +        fOverbudgetData = data;
   1.212 +    }
   1.213 +
   1.214 +    /**
   1.215 +     * Returns the number of bytes consumed by cached resources.
   1.216 +     */
   1.217 +    size_t getCachedResourceBytes() const { return fEntryBytes; }
   1.218 +
   1.219 +    // For a found or added resource to be completely exclusive to the caller
   1.220 +    // both the kNoOtherOwners and kHide flags need to be specified
   1.221 +    enum OwnershipFlags {
   1.222 +        kNoOtherOwners_OwnershipFlag = 0x1, // found/added resource has no other owners
   1.223 +        kHide_OwnershipFlag = 0x2  // found/added resource is hidden from future 'find's
   1.224 +    };
   1.225 +
   1.226 +    /**
   1.227 +     *  Search for an entry with the same Key. If found, return it.
   1.228 +     *  If not found, return null.
   1.229 +     *  If ownershipFlags includes kNoOtherOwners and a resource is returned
   1.230 +     *  then that resource has no other refs to it.
   1.231 +     *  If ownershipFlags includes kHide and a resource is returned then that
   1.232 +     *  resource will not be returned from future 'find' calls until it is
   1.233 +     *  'freed' (and recycled) or makeNonExclusive is called.
   1.234 +     *  For a resource to be completely exclusive to a caller both kNoOtherOwners
   1.235 +     *  and kHide must be specified.
   1.236 +     */
   1.237 +    GrResource* find(const GrResourceKey& key,
   1.238 +                     uint32_t ownershipFlags = 0);
   1.239 +
   1.240 +    /**
   1.241 +     *  Add the new resource to the cache (by creating a new cache entry based
   1.242 +     *  on the provided key and resource).
   1.243 +     *
   1.244 +     *  Ownership of the resource is transferred to the resource cache,
   1.245 +     *  which will unref() it when it is purged or deleted.
   1.246 +     *
   1.247 +     *  If ownershipFlags includes kHide, subsequent calls to 'find' will not
   1.248 +     *  return 'resource' until it is 'freed' (and recycled) or makeNonExclusive
   1.249 +     *  is called.
   1.250 +     */
   1.251 +    void addResource(const GrResourceKey& key,
   1.252 +                     GrResource* resource,
   1.253 +                     uint32_t ownershipFlags = 0);
   1.254 +
   1.255 +    /**
   1.256 +     * Determines if the cache contains an entry matching a key. If a matching
   1.257 +     * entry exists but was detached then it will not be found.
   1.258 +     */
   1.259 +    bool hasKey(const GrResourceKey& key) const { return NULL != fCache.find(key); }
   1.260 +
   1.261 +    /**
   1.262 +     * Hide 'entry' so that future searches will not find it. Such
   1.263 +     * hidden entries will not be purged. The entry still counts against
   1.264 +     * the cache's budget and should be made non-exclusive when exclusive access
   1.265 +     * is no longer needed.
   1.266 +     */
   1.267 +    void makeExclusive(GrResourceEntry* entry);
   1.268 +
   1.269 +    /**
   1.270 +     * Restore 'entry' so that it can be found by future searches. 'entry'
   1.271 +     * will also be purgeable (provided its lock count is now 0.)
   1.272 +     */
   1.273 +    void makeNonExclusive(GrResourceEntry* entry);
   1.274 +
   1.275 +    /**
   1.276 +     * Remove a resource from the cache and delete it!
   1.277 +     */
   1.278 +    void deleteResource(GrResourceEntry* entry);
   1.279 +
   1.280 +    /**
   1.281 +     * Removes every resource in the cache that isn't locked.
   1.282 +     */
   1.283 +    void purgeAllUnlocked();
   1.284 +
   1.285 +    /**
   1.286 +     * Allow cache to purge unused resources to obey resource limitations
   1.287 +     * Note: this entry point will be hidden (again) once totally ref-driven
   1.288 +     * cache maintenance is implemented. Note that the overbudget callback
   1.289 +     * will be called if the initial purge doesn't get the cache under
   1.290 +     * its budget.
   1.291 +     *
   1.292 +     * extraCount and extraBytes are added to the current resource allocation
   1.293 +     * to make sure enough room is available for future additions (e.g,
   1.294 +     * 10MB across 10 textures is about to be added).
   1.295 +     */
   1.296 +    void purgeAsNeeded(int extraCount = 0, size_t extraBytes = 0);
   1.297 +
   1.298 +#ifdef SK_DEBUG
   1.299 +    void validate() const;
   1.300 +#else
   1.301 +    void validate() const {}
   1.302 +#endif
   1.303 +
   1.304 +#if GR_CACHE_STATS
   1.305 +    void printStats();
   1.306 +#endif
   1.307 +
   1.308 +private:
   1.309 +    enum BudgetBehaviors {
   1.310 +        kAccountFor_BudgetBehavior,
   1.311 +        kIgnore_BudgetBehavior
   1.312 +    };
   1.313 +
   1.314 +    void internalDetach(GrResourceEntry*, BudgetBehaviors behavior = kAccountFor_BudgetBehavior);
   1.315 +    void attachToHead(GrResourceEntry*, BudgetBehaviors behavior = kAccountFor_BudgetBehavior);
   1.316 +
   1.317 +    void removeInvalidResource(GrResourceEntry* entry);
   1.318 +
   1.319 +    GrTMultiMap<GrResourceEntry,
   1.320 +                GrResourceKey,
   1.321 +                GrResourceEntry::GetKey,
   1.322 +                GrResourceEntry::Hash,
   1.323 +                GrResourceEntry::Equal> fCache;
   1.324 +
   1.325 +    // We're an internal doubly linked list
   1.326 +    typedef SkTInternalLList<GrResourceEntry> EntryList;
   1.327 +    EntryList      fList;
   1.328 +
   1.329 +#ifdef SK_DEBUG
   1.330 +    // These objects cannot be returned by a search
   1.331 +    EntryList      fExclusiveList;
   1.332 +#endif
   1.333 +
   1.334 +    // our budget, used in purgeAsNeeded()
   1.335 +    int            fMaxCount;
   1.336 +    size_t         fMaxBytes;
   1.337 +
   1.338 +    // our current stats, related to our budget
   1.339 +#if GR_CACHE_STATS
   1.340 +    int            fHighWaterEntryCount;
   1.341 +    size_t         fHighWaterEntryBytes;
   1.342 +    int            fHighWaterClientDetachedCount;
   1.343 +    size_t         fHighWaterClientDetachedBytes;
   1.344 +#endif
   1.345 +
   1.346 +    int            fEntryCount;
   1.347 +    size_t         fEntryBytes;
   1.348 +    int            fClientDetachedCount;
   1.349 +    size_t         fClientDetachedBytes;
   1.350 +
   1.351 +    // prevents recursive purging
   1.352 +    bool           fPurging;
   1.353 +
   1.354 +    PFOverbudgetCB fOverbudgetCB;
   1.355 +    void*          fOverbudgetData;
   1.356 +
   1.357 +    void internalPurge(int extraCount, size_t extraBytes);
   1.358 +
   1.359 +    // Listen for messages that a resource has been invalidated and purge cached junk proactively.
   1.360 +    SkMessageBus<GrResourceInvalidatedMessage>::Inbox fInvalidationInbox;
   1.361 +    void purgeInvalidated();
   1.362 +
   1.363 +#ifdef SK_DEBUG
   1.364 +    static size_t countBytes(const SkTInternalLList<GrResourceEntry>& list);
   1.365 +#endif
   1.366 +};
   1.367 +
   1.368 +///////////////////////////////////////////////////////////////////////////////
   1.369 +
   1.370 +#ifdef SK_DEBUG
   1.371 +    class GrAutoResourceCacheValidate {
   1.372 +    public:
   1.373 +        GrAutoResourceCacheValidate(GrResourceCache* cache) : fCache(cache) {
   1.374 +            cache->validate();
   1.375 +        }
   1.376 +        ~GrAutoResourceCacheValidate() {
   1.377 +            fCache->validate();
   1.378 +        }
   1.379 +    private:
   1.380 +        GrResourceCache* fCache;
   1.381 +    };
   1.382 +#else
   1.383 +    class GrAutoResourceCacheValidate {
   1.384 +    public:
   1.385 +        GrAutoResourceCacheValidate(GrResourceCache*) {}
   1.386 +    };
   1.387 +#endif
   1.388 +
   1.389 +#endif

mercurial