1c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon
2c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon/*
3c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon * Copyright 2014 Google Inc.
4c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon *
5c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon * Use of this source code is governed by a BSD-style license that can be
6c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon * found in the LICENSE file.
7c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon */
8c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon
90ea80f43a1af05b8157a4ef387223bb5b0da35edbsalomon#ifndef GrResourceCache_DEFINED
100ea80f43a1af05b8157a4ef387223bb5b0da35edbsalomon#define GrResourceCache_DEFINED
11c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon
12744998e666073166307d2522847b2536000a7619bsalomon#include "GrGpuResource.h"
139f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon#include "GrGpuResourceCacheAccess.h"
143582d3ee9fffdec715f5e4949a241ab08e6271ecbsalomon#include "GrGpuResourcePriv.h"
15744998e666073166307d2522847b2536000a7619bsalomon#include "GrResourceKey.h"
1623e619cf462b2a8a500f3ca750e099f79601f508bsalomon#include "SkMessageBus.h"
178b79d23f825cd9e0f9e3bf8aaa9e209940b17ef6bsalomon#include "SkRefCnt.h"
1823e619cf462b2a8a500f3ca750e099f79601f508bsalomon#include "SkTArray.h"
199f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon#include "SkTDPQueue.h"
20c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon#include "SkTInternalLList.h"
21744998e666073166307d2522847b2536000a7619bsalomon#include "SkTMultiMap.h"
22c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon
2363926683c583e8497d9d907977e773663cb4bd9erobertphillipsclass GrCaps;
24b9eb4ac0f1c29d6fe10ad7ff81ed8326ac1ea043mtkleinclass SkString;
250a5fa484fd58d27088f8696bdc11c8cc8f2b4866ericrkclass SkTraceMemoryDump;
26b9eb4ac0f1c29d6fe10ad7ff81ed8326ac1ea043mtklein
27c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon/**
2871cb0c241e439b6ed746b90294d0b6916644a644bsalomon * Manages the lifetime of all GrGpuResource instances.
2971cb0c241e439b6ed746b90294d0b6916644a644bsalomon *
3071cb0c241e439b6ed746b90294d0b6916644a644bsalomon * Resources may have optionally have two types of keys:
3171cb0c241e439b6ed746b90294d0b6916644a644bsalomon *      1) A scratch key. This is for resources whose allocations are cached but not their contents.
3271cb0c241e439b6ed746b90294d0b6916644a644bsalomon *         Multiple resources can share the same scratch key. This is so a caller can have two
3384c8e62fad59f0e19b40ac718467f5b7884b431dbsalomon *         resource instances with the same properties (e.g. multipass rendering that ping-pongs
348718aafec239c93485e45bbe8fed19d9a8def079bsalomon *         between two temporary surfaces). The scratch key is set at resource creation time and
3571cb0c241e439b6ed746b90294d0b6916644a644bsalomon *         should never change. Resources need not have a scratch key.
368718aafec239c93485e45bbe8fed19d9a8def079bsalomon *      2) A unique key. This key's meaning is specific to the domain that created the key. Only one
37f99e961f55bb603d099c8cb57d05a2ae52a4e9cabsalomon *         resource may have a given unique key. The unique key can be set, cleared, or changed
38f99e961f55bb603d099c8cb57d05a2ae52a4e9cabsalomon *         anytime after resource creation.
39f99e961f55bb603d099c8cb57d05a2ae52a4e9cabsalomon *
408718aafec239c93485e45bbe8fed19d9a8def079bsalomon * A unique key always takes precedence over a scratch key when a resource has both types of keys.
4171cb0c241e439b6ed746b90294d0b6916644a644bsalomon * If a resource has neither key type then it will be deleted as soon as the last reference to it
428718aafec239c93485e45bbe8fed19d9a8def079bsalomon * is dropped.
433f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon *
443f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon * When proactive purging is enabled, on every flush, the timestamp of that flush is stored in a
453f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon * n-sized ring buffer. When purging occurs each purgeable resource's timestamp is compared to the
463f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon * timestamp of the n-th prior flush. If the resource's last use timestamp is older than the old
473f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon * flush then the resource is proactively purged even when the cache is under budget. By default
483f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon * this feature is disabled, though it can be enabled by calling GrResourceCache::setLimits.
49c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon */
500ea80f43a1af05b8157a4ef387223bb5b0da35edbsalomonclass GrResourceCache {
51c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomonpublic:
5263926683c583e8497d9d907977e773663cb4bd9erobertphillips    GrResourceCache(const GrCaps* caps);
530ea80f43a1af05b8157a4ef387223bb5b0da35edbsalomon    ~GrResourceCache();
54c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon
553f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    // Default maximum number of budgeted resources in the cache.
563f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    static const int    kDefaultMaxCount            = 2 * (1 << 12);
573f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    // Default maximum number of bytes of gpu memory of budgeted resources in the cache.
583f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    static const size_t kDefaultMaxSize             = 96 * (1 << 20);
593f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    // Default number of flushes a budgeted resources can go unused in the cache before it is
603f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    // purged. Large values disable the feature (as the ring buffer of flush timestamps would be
61c03bdfa8e653fbdcb6b9f59ce862e00212e7c419bsalomon    // large). This is currently the default until we decide to enable this feature
62c03bdfa8e653fbdcb6b9f59ce862e00212e7c419bsalomon    // of the cache by default.
639f0337ed4b5b5f7b3a049175365658470061b3cbbsalomon    static const int    kDefaultMaxUnusedFlushes    = 64;
643f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon
6571cb0c241e439b6ed746b90294d0b6916644a644bsalomon    /** Used to access functionality needed by GrGpuResource for lifetime management. */
6671cb0c241e439b6ed746b90294d0b6916644a644bsalomon    class ResourceAccess;
6771cb0c241e439b6ed746b90294d0b6916644a644bsalomon    ResourceAccess resourceAccess();
68407aa584d183c1bf314f5defd1cf0202e8a96c89bsalomon
6971cb0c241e439b6ed746b90294d0b6916644a644bsalomon    /**
703f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon     * Sets the cache limits in terms of number of resources, max gpu memory byte size, and number
713f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon     * of GrContext flushes that a resource can be unused before it is evicted. The latter value is
723f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon     * a suggestion and there is no promise that a resource will be purged immediately after it
733f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon     * hasn't been used in maxUnusedFlushes flushes.
7471cb0c241e439b6ed746b90294d0b6916644a644bsalomon     */
753f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    void setLimits(int count, size_t bytes, int maxUnusedFlushes = kDefaultMaxUnusedFlushes);
7666a450f21a3da174b7eed89a1d5fc8591e8b6ee6bsalomon
7771cb0c241e439b6ed746b90294d0b6916644a644bsalomon    /**
78dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon     * Returns the number of resources.
7971cb0c241e439b6ed746b90294d0b6916644a644bsalomon     */
80f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    int getResourceCount() const {
81f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon        return fPurgeableQueue.count() + fNonpurgeableResources.count();
82f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    }
8371cb0c241e439b6ed746b90294d0b6916644a644bsalomon
8471cb0c241e439b6ed746b90294d0b6916644a644bsalomon    /**
85dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon     * Returns the number of resources that count against the budget.
86dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon     */
87dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon    int getBudgetedResourceCount() const { return fBudgetedCount; }
88dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon
89dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon    /**
90dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon     * Returns the number of bytes consumed by resources.
9171cb0c241e439b6ed746b90294d0b6916644a644bsalomon     */
9271cb0c241e439b6ed746b90294d0b6916644a644bsalomon    size_t getResourceBytes() const { return fBytes; }
9371cb0c241e439b6ed746b90294d0b6916644a644bsalomon
9471cb0c241e439b6ed746b90294d0b6916644a644bsalomon    /**
95dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon     * Returns the number of bytes consumed by budgeted resources.
96dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon     */
97dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon    size_t getBudgetedResourceBytes() const { return fBudgetedBytes; }
98dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon
99dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon    /**
10071cb0c241e439b6ed746b90294d0b6916644a644bsalomon     * Returns the cached resources count budget.
10171cb0c241e439b6ed746b90294d0b6916644a644bsalomon     */
10271cb0c241e439b6ed746b90294d0b6916644a644bsalomon    int getMaxResourceCount() const { return fMaxCount; }
103407aa584d183c1bf314f5defd1cf0202e8a96c89bsalomon
10471cb0c241e439b6ed746b90294d0b6916644a644bsalomon    /**
10571cb0c241e439b6ed746b90294d0b6916644a644bsalomon     * Returns the number of bytes consumed by cached resources.
10671cb0c241e439b6ed746b90294d0b6916644a644bsalomon     */
10771cb0c241e439b6ed746b90294d0b6916644a644bsalomon    size_t getMaxResourceBytes() const { return fMaxBytes; }
10871cb0c241e439b6ed746b90294d0b6916644a644bsalomon
10971cb0c241e439b6ed746b90294d0b6916644a644bsalomon    /**
11071cb0c241e439b6ed746b90294d0b6916644a644bsalomon     * Abandons the backend API resources owned by all GrGpuResource objects and removes them from
11171cb0c241e439b6ed746b90294d0b6916644a644bsalomon     * the cache.
11271cb0c241e439b6ed746b90294d0b6916644a644bsalomon     */
113c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon    void abandonAll();
114c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon
11571cb0c241e439b6ed746b90294d0b6916644a644bsalomon    /**
11671cb0c241e439b6ed746b90294d0b6916644a644bsalomon     * Releases the backend API resources owned by all GrGpuResource objects and removes them from
11771cb0c241e439b6ed746b90294d0b6916644a644bsalomon     * the cache.
11871cb0c241e439b6ed746b90294d0b6916644a644bsalomon     */
119c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon    void releaseAll();
120c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon
121000f829f14a9535a005082731af5de1526284c83bsalomon    enum {
122000f829f14a9535a005082731af5de1526284c83bsalomon        /** Preferentially returns scratch resources with no pending IO. */
123000f829f14a9535a005082731af5de1526284c83bsalomon        kPreferNoPendingIO_ScratchFlag = 0x1,
124000f829f14a9535a005082731af5de1526284c83bsalomon        /** Will not return any resources that match but have pending IO. */
125000f829f14a9535a005082731af5de1526284c83bsalomon        kRequireNoPendingIO_ScratchFlag = 0x2,
126000f829f14a9535a005082731af5de1526284c83bsalomon    };
12771cb0c241e439b6ed746b90294d0b6916644a644bsalomon
12871cb0c241e439b6ed746b90294d0b6916644a644bsalomon    /**
12971cb0c241e439b6ed746b90294d0b6916644a644bsalomon     * Find a resource that matches a scratch key.
13071cb0c241e439b6ed746b90294d0b6916644a644bsalomon     */
1316e83ac778f8f90939abe3aee3ea865428dff592frobertphillips    GrGpuResource* findAndRefScratchResource(const GrScratchKey& scratchKey,
1326e83ac778f8f90939abe3aee3ea865428dff592frobertphillips                                             size_t resourceSize,
1336e83ac778f8f90939abe3aee3ea865428dff592frobertphillips                                             uint32_t flags);
1348b79d23f825cd9e0f9e3bf8aaa9e209940b17ef6bsalomon
1358b79d23f825cd9e0f9e3bf8aaa9e209940b17ef6bsalomon#ifdef SK_DEBUG
1368b79d23f825cd9e0f9e3bf8aaa9e209940b17ef6bsalomon    // This is not particularly fast and only used for validation, so debug only.
1377775c85611c734a2af709b3a9c127939a4296c48bsalomon    int countScratchEntriesForKey(const GrScratchKey& scratchKey) const {
1388b79d23f825cd9e0f9e3bf8aaa9e209940b17ef6bsalomon        return fScratchMap.countForKey(scratchKey);
1398b79d23f825cd9e0f9e3bf8aaa9e209940b17ef6bsalomon    }
1408b79d23f825cd9e0f9e3bf8aaa9e209940b17ef6bsalomon#endif
1418b79d23f825cd9e0f9e3bf8aaa9e209940b17ef6bsalomon
14271cb0c241e439b6ed746b90294d0b6916644a644bsalomon    /**
1438718aafec239c93485e45bbe8fed19d9a8def079bsalomon     * Find a resource that matches a unique key.
14471cb0c241e439b6ed746b90294d0b6916644a644bsalomon     */
1458718aafec239c93485e45bbe8fed19d9a8def079bsalomon    GrGpuResource* findAndRefUniqueResource(const GrUniqueKey& key) {
1468718aafec239c93485e45bbe8fed19d9a8def079bsalomon        GrGpuResource* resource = fUniqueHash.find(key);
14771cb0c241e439b6ed746b90294d0b6916644a644bsalomon        if (resource) {
1489f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon            this->refAndMakeResourceMRU(resource);
14971cb0c241e439b6ed746b90294d0b6916644a644bsalomon        }
15071cb0c241e439b6ed746b90294d0b6916644a644bsalomon        return resource;
1518b79d23f825cd9e0f9e3bf8aaa9e209940b17ef6bsalomon    }
1528b79d23f825cd9e0f9e3bf8aaa9e209940b17ef6bsalomon
15371cb0c241e439b6ed746b90294d0b6916644a644bsalomon    /**
1548718aafec239c93485e45bbe8fed19d9a8def079bsalomon     * Query whether a unique key exists in the cache.
15571cb0c241e439b6ed746b90294d0b6916644a644bsalomon     */
1568718aafec239c93485e45bbe8fed19d9a8def079bsalomon    bool hasUniqueKey(const GrUniqueKey& key) const {
1578718aafec239c93485e45bbe8fed19d9a8def079bsalomon        return SkToBool(fUniqueHash.find(key));
1588b79d23f825cd9e0f9e3bf8aaa9e209940b17ef6bsalomon    }
159bcf0a52d4f4221b158e68a06ba0c4cc4db011060bsalomon
1608718aafec239c93485e45bbe8fed19d9a8def079bsalomon    /** Purges resources to become under budget and processes resources with invalidated unique
16123e619cf462b2a8a500f3ca750e099f79601f508bsalomon        keys. */
1623f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    void purgeAsNeeded();
16323e619cf462b2a8a500f3ca750e099f79601f508bsalomon
16471cb0c241e439b6ed746b90294d0b6916644a644bsalomon    /** Purges all resources that don't have external owners. */
16571cb0c241e439b6ed746b90294d0b6916644a644bsalomon    void purgeAllUnlocked();
16671cb0c241e439b6ed746b90294d0b6916644a644bsalomon
16771cb0c241e439b6ed746b90294d0b6916644a644bsalomon    /**
16871cb0c241e439b6ed746b90294d0b6916644a644bsalomon     * The callback function used by the cache when it is still over budget after a purge. The
16971cb0c241e439b6ed746b90294d0b6916644a644bsalomon     * passed in 'data' is the same 'data' handed to setOverbudgetCallback.
17071cb0c241e439b6ed746b90294d0b6916644a644bsalomon     */
17171cb0c241e439b6ed746b90294d0b6916644a644bsalomon    typedef void (*PFOverBudgetCB)(void* data);
17271cb0c241e439b6ed746b90294d0b6916644a644bsalomon
17371cb0c241e439b6ed746b90294d0b6916644a644bsalomon    /**
17471cb0c241e439b6ed746b90294d0b6916644a644bsalomon     * Set the callback the cache should use when it is still over budget after a purge. The 'data'
17571cb0c241e439b6ed746b90294d0b6916644a644bsalomon     * provided here will be passed back to the callback. Note that the cache will attempt to purge
17671cb0c241e439b6ed746b90294d0b6916644a644bsalomon     * any resources newly freed by the callback.
17771cb0c241e439b6ed746b90294d0b6916644a644bsalomon     */
17871cb0c241e439b6ed746b90294d0b6916644a644bsalomon    void setOverBudgetCallback(PFOverBudgetCB overBudgetCB, void* data) {
17971cb0c241e439b6ed746b90294d0b6916644a644bsalomon        fOverBudgetCB = overBudgetCB;
18071cb0c241e439b6ed746b90294d0b6916644a644bsalomon        fOverBudgetData = data;
18171cb0c241e439b6ed746b90294d0b6916644a644bsalomon    }
1820a5fa484fd58d27088f8696bdc11c8cc8f2b4866ericrk
1833f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    void notifyFlushOccurred();
18471cb0c241e439b6ed746b90294d0b6916644a644bsalomon
18560029a5397f75aae4bdb994f26bd297edc3e433crobertphillips#if GR_CACHE_STATS
18660029a5397f75aae4bdb994f26bd297edc3e433crobertphillips    struct Stats {
18760029a5397f75aae4bdb994f26bd297edc3e433crobertphillips        int fTotal;
18860029a5397f75aae4bdb994f26bd297edc3e433crobertphillips        int fNumPurgeable;
18960029a5397f75aae4bdb994f26bd297edc3e433crobertphillips        int fNumNonPurgeable;
19060029a5397f75aae4bdb994f26bd297edc3e433crobertphillips
19160029a5397f75aae4bdb994f26bd297edc3e433crobertphillips        int fScratch;
19260029a5397f75aae4bdb994f26bd297edc3e433crobertphillips        int fExternal;
19360029a5397f75aae4bdb994f26bd297edc3e433crobertphillips        int fBorrowed;
19460029a5397f75aae4bdb994f26bd297edc3e433crobertphillips        int fAdopted;
19560029a5397f75aae4bdb994f26bd297edc3e433crobertphillips        size_t fUnbudgetedSize;
19660029a5397f75aae4bdb994f26bd297edc3e433crobertphillips
19760029a5397f75aae4bdb994f26bd297edc3e433crobertphillips        Stats() { this->reset(); }
19860029a5397f75aae4bdb994f26bd297edc3e433crobertphillips
19960029a5397f75aae4bdb994f26bd297edc3e433crobertphillips        void reset() {
20060029a5397f75aae4bdb994f26bd297edc3e433crobertphillips            fTotal = 0;
20160029a5397f75aae4bdb994f26bd297edc3e433crobertphillips            fNumPurgeable = 0;
20260029a5397f75aae4bdb994f26bd297edc3e433crobertphillips            fNumNonPurgeable = 0;
20360029a5397f75aae4bdb994f26bd297edc3e433crobertphillips            fScratch = 0;
20460029a5397f75aae4bdb994f26bd297edc3e433crobertphillips            fExternal = 0;
20560029a5397f75aae4bdb994f26bd297edc3e433crobertphillips            fBorrowed = 0;
20660029a5397f75aae4bdb994f26bd297edc3e433crobertphillips            fAdopted = 0;
20760029a5397f75aae4bdb994f26bd297edc3e433crobertphillips            fUnbudgetedSize = 0;
20860029a5397f75aae4bdb994f26bd297edc3e433crobertphillips        }
20960029a5397f75aae4bdb994f26bd297edc3e433crobertphillips
21060029a5397f75aae4bdb994f26bd297edc3e433crobertphillips        void update(GrGpuResource* resource) {
21160029a5397f75aae4bdb994f26bd297edc3e433crobertphillips            if (resource->cacheAccess().isScratch()) {
21260029a5397f75aae4bdb994f26bd297edc3e433crobertphillips                ++fScratch;
21360029a5397f75aae4bdb994f26bd297edc3e433crobertphillips            }
21460029a5397f75aae4bdb994f26bd297edc3e433crobertphillips            if (resource->cacheAccess().isExternal()) {
21560029a5397f75aae4bdb994f26bd297edc3e433crobertphillips                ++fExternal;
21660029a5397f75aae4bdb994f26bd297edc3e433crobertphillips            }
21760029a5397f75aae4bdb994f26bd297edc3e433crobertphillips            if (resource->cacheAccess().isBorrowed()) {
21860029a5397f75aae4bdb994f26bd297edc3e433crobertphillips                ++fBorrowed;
21960029a5397f75aae4bdb994f26bd297edc3e433crobertphillips            }
22060029a5397f75aae4bdb994f26bd297edc3e433crobertphillips            if (resource->cacheAccess().isAdopted()) {
22160029a5397f75aae4bdb994f26bd297edc3e433crobertphillips                ++fAdopted;
22260029a5397f75aae4bdb994f26bd297edc3e433crobertphillips            }
2235ec26ae9bfca635ccc98283aad5deda11519d826bsalomon            if (SkBudgeted::kNo  == resource->resourcePriv().isBudgeted()) {
22460029a5397f75aae4bdb994f26bd297edc3e433crobertphillips                fUnbudgetedSize += resource->gpuMemorySize();
22560029a5397f75aae4bdb994f26bd297edc3e433crobertphillips            }
22660029a5397f75aae4bdb994f26bd297edc3e433crobertphillips        }
22760029a5397f75aae4bdb994f26bd297edc3e433crobertphillips    };
22860029a5397f75aae4bdb994f26bd297edc3e433crobertphillips
22960029a5397f75aae4bdb994f26bd297edc3e433crobertphillips    void getStats(Stats*) const;
23060029a5397f75aae4bdb994f26bd297edc3e433crobertphillips
231b9eb4ac0f1c29d6fe10ad7ff81ed8326ac1ea043mtklein    void dumpStats(SkString*) const;
232dc5685ac3752e90dd68179e9f1675ff6f15ed600joshualitt
233dc5685ac3752e90dd68179e9f1675ff6f15ed600joshualitt    void dumpStatsKeyValuePairs(SkTArray<SkString>* keys, SkTArray<double>* value) const;
23471cb0c241e439b6ed746b90294d0b6916644a644bsalomon#endif
23571cb0c241e439b6ed746b90294d0b6916644a644bsalomon
236ddf30e64fe474847b204d7062fad3341d245062cbsalomon    // This function is for unit testing and is only defined in test tools.
237ddf30e64fe474847b204d7062fad3341d245062cbsalomon    void changeTimestamp(uint32_t newTimestamp);
238ddf30e64fe474847b204d7062fad3341d245062cbsalomon
2390a5fa484fd58d27088f8696bdc11c8cc8f2b4866ericrk    // Enumerates all cached resources and dumps their details to traceMemoryDump.
2400a5fa484fd58d27088f8696bdc11c8cc8f2b4866ericrk    void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const;
2410a5fa484fd58d27088f8696bdc11c8cc8f2b4866ericrk
242c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomonprivate:
24371cb0c241e439b6ed746b90294d0b6916644a644bsalomon    ///////////////////////////////////////////////////////////////////////////
24471cb0c241e439b6ed746b90294d0b6916644a644bsalomon    /// @name Methods accessible via ResourceAccess
24571cb0c241e439b6ed746b90294d0b6916644a644bsalomon    ////
24671cb0c241e439b6ed746b90294d0b6916644a644bsalomon    void insertResource(GrGpuResource*);
24771cb0c241e439b6ed746b90294d0b6916644a644bsalomon    void removeResource(GrGpuResource*);
2483f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    void notifyCntReachedZero(GrGpuResource*, uint32_t flags);
24971cb0c241e439b6ed746b90294d0b6916644a644bsalomon    void didChangeGpuMemorySize(const GrGpuResource*, size_t oldSize);
250f99e961f55bb603d099c8cb57d05a2ae52a4e9cabsalomon    void changeUniqueKey(GrGpuResource*, const GrUniqueKey&);
251f99e961f55bb603d099c8cb57d05a2ae52a4e9cabsalomon    void removeUniqueKey(GrGpuResource*);
25210e23caea3106be125acea10a637789e5a15c728bsalomon    void willRemoveScratchKey(const GrGpuResource*);
25384c8e62fad59f0e19b40ac718467f5b7884b431dbsalomon    void didChangeBudgetStatus(GrGpuResource*);
2549f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon    void refAndMakeResourceMRU(GrGpuResource*);
25571cb0c241e439b6ed746b90294d0b6916644a644bsalomon    /// @}
25671cb0c241e439b6ed746b90294d0b6916644a644bsalomon
2573f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    void resetFlushTimestamps();
2588718aafec239c93485e45bbe8fed19d9a8def079bsalomon    void processInvalidUniqueKeys(const SkTArray<GrUniqueKeyInvalidatedMessage>&);
259f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    void addToNonpurgeableArray(GrGpuResource*);
260f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    void removeFromNonpurgeableArray(GrGpuResource*);
261f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    bool overBudget() const { return fBudgetedBytes > fMaxBytes || fBudgetedCount > fMaxCount; }
26271cb0c241e439b6ed746b90294d0b6916644a644bsalomon
2636e83ac778f8f90939abe3aee3ea865428dff592frobertphillips    bool wouldFit(size_t bytes) {
2646e83ac778f8f90939abe3aee3ea865428dff592frobertphillips        return fBudgetedBytes+bytes <= fMaxBytes && fBudgetedCount+1 <= fMaxCount;
2656e83ac778f8f90939abe3aee3ea865428dff592frobertphillips    }
2666e83ac778f8f90939abe3aee3ea865428dff592frobertphillips
267ddf30e64fe474847b204d7062fad3341d245062cbsalomon    uint32_t getNextTimestamp();
268ddf30e64fe474847b204d7062fad3341d245062cbsalomon
269169612621f00b3fe9f71014079991287d311751absalomon#ifdef SK_DEBUG
270f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    bool isInCache(const GrGpuResource* r) const;
27171cb0c241e439b6ed746b90294d0b6916644a644bsalomon    void validate() const;
27271cb0c241e439b6ed746b90294d0b6916644a644bsalomon#else
27371cb0c241e439b6ed746b90294d0b6916644a644bsalomon    void validate() const {}
274169612621f00b3fe9f71014079991287d311751absalomon#endif
275169612621f00b3fe9f71014079991287d311751absalomon
27671cb0c241e439b6ed746b90294d0b6916644a644bsalomon    class AutoValidate;
27771cb0c241e439b6ed746b90294d0b6916644a644bsalomon
278bcf0a52d4f4221b158e68a06ba0c4cc4db011060bsalomon    class AvailableForScratchUse;
279744998e666073166307d2522847b2536000a7619bsalomon
280744998e666073166307d2522847b2536000a7619bsalomon    struct ScratchMapTraits {
2817775c85611c734a2af709b3a9c127939a4296c48bsalomon        static const GrScratchKey& GetKey(const GrGpuResource& r) {
2823582d3ee9fffdec715f5e4949a241ab08e6271ecbsalomon            return r.resourcePriv().getScratchKey();
283744998e666073166307d2522847b2536000a7619bsalomon        }
284744998e666073166307d2522847b2536000a7619bsalomon
2857775c85611c734a2af709b3a9c127939a4296c48bsalomon        static uint32_t Hash(const GrScratchKey& key) { return key.hash(); }
286744998e666073166307d2522847b2536000a7619bsalomon    };
2877775c85611c734a2af709b3a9c127939a4296c48bsalomon    typedef SkTMultiMap<GrGpuResource, GrScratchKey, ScratchMapTraits> ScratchMap;
288744998e666073166307d2522847b2536000a7619bsalomon
2898718aafec239c93485e45bbe8fed19d9a8def079bsalomon    struct UniqueHashTraits {
2908718aafec239c93485e45bbe8fed19d9a8def079bsalomon        static const GrUniqueKey& GetKey(const GrGpuResource& r) { return r.getUniqueKey(); }
2918b79d23f825cd9e0f9e3bf8aaa9e209940b17ef6bsalomon
2928718aafec239c93485e45bbe8fed19d9a8def079bsalomon        static uint32_t Hash(const GrUniqueKey& key) { return key.hash(); }
2938b79d23f825cd9e0f9e3bf8aaa9e209940b17ef6bsalomon    };
2948718aafec239c93485e45bbe8fed19d9a8def079bsalomon    typedef SkTDynamicHash<GrGpuResource, GrUniqueKey, UniqueHashTraits> UniqueHash;
2958b79d23f825cd9e0f9e3bf8aaa9e209940b17ef6bsalomon
2969f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon    static bool CompareTimestamp(GrGpuResource* const& a, GrGpuResource* const& b) {
2979f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon        return a->cacheAccess().timestamp() < b->cacheAccess().timestamp();
2989f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon    }
2999f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon
3009f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon    static int* AccessResourceIndex(GrGpuResource* const& res) {
3019f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon        return res->cacheAccess().accessCacheIndex();
3029f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon    }
3039f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon
3048718aafec239c93485e45bbe8fed19d9a8def079bsalomon    typedef SkMessageBus<GrUniqueKeyInvalidatedMessage>::Inbox InvalidUniqueKeyInbox;
3059f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon    typedef SkTDPQueue<GrGpuResource*, CompareTimestamp, AccessResourceIndex> PurgeableQueue;
306f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    typedef SkTDArray<GrGpuResource*> ResourceArray;
30723e619cf462b2a8a500f3ca750e099f79601f508bsalomon
3089f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon    // Whenever a resource is added to the cache or the result of a cache lookup, fTimestamp is
3099f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon    // assigned as the resource's timestamp and then incremented. fPurgeableQueue orders the
3109f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon    // purgeable resources by this value, and thus is used to purge resources in LRU order.
3119f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon    uint32_t                            fTimestamp;
3129f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon    PurgeableQueue                      fPurgeableQueue;
313f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    ResourceArray                       fNonpurgeableResources;
3149f2d1571ed1f0ed579e5d7779c46a90e20f30f22bsalomon
315744998e666073166307d2522847b2536000a7619bsalomon    // This map holds all resources that can be used as scratch resources.
3168b79d23f825cd9e0f9e3bf8aaa9e209940b17ef6bsalomon    ScratchMap                          fScratchMap;
3178718aafec239c93485e45bbe8fed19d9a8def079bsalomon    // This holds all resources that have unique keys.
3188718aafec239c93485e45bbe8fed19d9a8def079bsalomon    UniqueHash                          fUniqueHash;
31971cb0c241e439b6ed746b90294d0b6916644a644bsalomon
32071cb0c241e439b6ed746b90294d0b6916644a644bsalomon    // our budget, used in purgeAsNeeded()
32171cb0c241e439b6ed746b90294d0b6916644a644bsalomon    int                                 fMaxCount;
32271cb0c241e439b6ed746b90294d0b6916644a644bsalomon    size_t                              fMaxBytes;
3233f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    int                                 fMaxUnusedFlushes;
32471cb0c241e439b6ed746b90294d0b6916644a644bsalomon
32571cb0c241e439b6ed746b90294d0b6916644a644bsalomon#if GR_CACHE_STATS
32671cb0c241e439b6ed746b90294d0b6916644a644bsalomon    int                                 fHighWaterCount;
32771cb0c241e439b6ed746b90294d0b6916644a644bsalomon    size_t                              fHighWaterBytes;
328dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon    int                                 fBudgetedHighWaterCount;
329dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon    size_t                              fBudgetedHighWaterBytes;
33071cb0c241e439b6ed746b90294d0b6916644a644bsalomon#endif
33171cb0c241e439b6ed746b90294d0b6916644a644bsalomon
332dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon    // our current stats for all resources
333f320e04c50a1c8a861bc1d8f50bf732044ff9843bsalomon    SkDEBUGCODE(int                     fCount;)
33471cb0c241e439b6ed746b90294d0b6916644a644bsalomon    size_t                              fBytes;
33571cb0c241e439b6ed746b90294d0b6916644a644bsalomon
336dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon    // our current stats for resources that count against the budget
337dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon    int                                 fBudgetedCount;
338dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon    size_t                              fBudgetedBytes;
339dace19ec17e85872df3fb35212e1b8bce72018b6bsalomon
34071cb0c241e439b6ed746b90294d0b6916644a644bsalomon    PFOverBudgetCB                      fOverBudgetCB;
34171cb0c241e439b6ed746b90294d0b6916644a644bsalomon    void*                               fOverBudgetData;
34271cb0c241e439b6ed746b90294d0b6916644a644bsalomon
3433f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    // We keep track of the "timestamps" of the last n flushes. If a resource hasn't been used in
3443f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    // that time then we well preemptively purge it to reduce memory usage.
3453f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    uint32_t*                           fFlushTimestamps;
3463f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    int                                 fLastFlushTimestampIndex;
3473f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon
3488718aafec239c93485e45bbe8fed19d9a8def079bsalomon    InvalidUniqueKeyInbox               fInvalidUniqueKeyInbox;
3493f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon
3503f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    // This resource is allowed to be in the nonpurgeable array for the sake of validate() because
3513f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    // we're in the midst of converting it to purgeable status.
3523f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    SkDEBUGCODE(GrGpuResource*          fNewlyPurgeableResourceForValidation;)
35363926683c583e8497d9d907977e773663cb4bd9erobertphillips
35463926683c583e8497d9d907977e773663cb4bd9erobertphillips    bool                                fPreferVRAMUseOverFlushes;
355c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon};
356c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon
3570ea80f43a1af05b8157a4ef387223bb5b0da35edbsalomonclass GrResourceCache::ResourceAccess {
35871cb0c241e439b6ed746b90294d0b6916644a644bsalomonprivate:
3590ea80f43a1af05b8157a4ef387223bb5b0da35edbsalomon    ResourceAccess(GrResourceCache* cache) : fCache(cache) { }
36071cb0c241e439b6ed746b90294d0b6916644a644bsalomon    ResourceAccess(const ResourceAccess& that) : fCache(that.fCache) { }
36171cb0c241e439b6ed746b90294d0b6916644a644bsalomon    ResourceAccess& operator=(const ResourceAccess&); // unimpl
36271cb0c241e439b6ed746b90294d0b6916644a644bsalomon
36371cb0c241e439b6ed746b90294d0b6916644a644bsalomon    /**
36471cb0c241e439b6ed746b90294d0b6916644a644bsalomon     * Insert a resource into the cache.
36571cb0c241e439b6ed746b90294d0b6916644a644bsalomon     */
36671cb0c241e439b6ed746b90294d0b6916644a644bsalomon    void insertResource(GrGpuResource* resource) { fCache->insertResource(resource); }
36771cb0c241e439b6ed746b90294d0b6916644a644bsalomon
36871cb0c241e439b6ed746b90294d0b6916644a644bsalomon    /**
36971cb0c241e439b6ed746b90294d0b6916644a644bsalomon     * Removes a resource from the cache.
37071cb0c241e439b6ed746b90294d0b6916644a644bsalomon     */
37171cb0c241e439b6ed746b90294d0b6916644a644bsalomon    void removeResource(GrGpuResource* resource) { fCache->removeResource(resource); }
37271cb0c241e439b6ed746b90294d0b6916644a644bsalomon
37371cb0c241e439b6ed746b90294d0b6916644a644bsalomon    /**
3743f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon     * Notifications that should be sent to the cache when the ref/io cnt status of resources
3753f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon     * changes.
3763f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon     */
3773f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    enum RefNotificationFlags {
3783f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon        /** All types of refs on the resource have reached zero. */
3793f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon        kAllCntsReachedZero_RefNotificationFlag = 0x1,
3803f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon        /** The normal (not pending IO type) ref cnt has reached zero. */
3813f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon        kRefCntReachedZero_RefNotificationFlag  = 0x2,
3823f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    };
3833f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    /**
3843f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon     * Called by GrGpuResources when they detect that their ref/io cnts have reached zero. When the
3853f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon     * normal ref cnt reaches zero the flags that are set should be:
3863f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon     *     a) kRefCntReachedZero if a pending IO cnt is still non-zero.
3873f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon     *     b) (kRefCntReachedZero | kAllCntsReachedZero) when all pending IO cnts are also zero.
3883f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon     * kAllCntsReachedZero is set by itself if a pending IO cnt is decremented to zero and all the
3893f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon     * the other cnts are already zero.
39071cb0c241e439b6ed746b90294d0b6916644a644bsalomon     */
3913f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    void notifyCntReachedZero(GrGpuResource* resource, uint32_t flags) {
3923f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon        fCache->notifyCntReachedZero(resource, flags);
3933f324321cdd8fde7976d958e2888a1ec4e657e35bsalomon    }
39471cb0c241e439b6ed746b90294d0b6916644a644bsalomon
39571cb0c241e439b6ed746b90294d0b6916644a644bsalomon    /**
39671cb0c241e439b6ed746b90294d0b6916644a644bsalomon     * Called by GrGpuResources when their sizes change.
39771cb0c241e439b6ed746b90294d0b6916644a644bsalomon     */
39871cb0c241e439b6ed746b90294d0b6916644a644bsalomon    void didChangeGpuMemorySize(const GrGpuResource* resource, size_t oldSize) {
39971cb0c241e439b6ed746b90294d0b6916644a644bsalomon        fCache->didChangeGpuMemorySize(resource, oldSize);
40071cb0c241e439b6ed746b90294d0b6916644a644bsalomon    }
40171cb0c241e439b6ed746b90294d0b6916644a644bsalomon
40271cb0c241e439b6ed746b90294d0b6916644a644bsalomon    /**
403f99e961f55bb603d099c8cb57d05a2ae52a4e9cabsalomon     * Called by GrGpuResources to change their unique keys.
40471cb0c241e439b6ed746b90294d0b6916644a644bsalomon     */
405f99e961f55bb603d099c8cb57d05a2ae52a4e9cabsalomon    void changeUniqueKey(GrGpuResource* resource, const GrUniqueKey& newKey) {
406f99e961f55bb603d099c8cb57d05a2ae52a4e9cabsalomon         fCache->changeUniqueKey(resource, newKey);
407f99e961f55bb603d099c8cb57d05a2ae52a4e9cabsalomon    }
40871cb0c241e439b6ed746b90294d0b6916644a644bsalomon
40910e23caea3106be125acea10a637789e5a15c728bsalomon    /**
410f99e961f55bb603d099c8cb57d05a2ae52a4e9cabsalomon     * Called by a GrGpuResource to remove its unique key.
41123e619cf462b2a8a500f3ca750e099f79601f508bsalomon     */
412f99e961f55bb603d099c8cb57d05a2ae52a4e9cabsalomon    void removeUniqueKey(GrGpuResource* resource) { fCache->removeUniqueKey(resource); }
41323e619cf462b2a8a500f3ca750e099f79601f508bsalomon
41423e619cf462b2a8a500f3ca750e099f79601f508bsalomon    /**
41523e619cf462b2a8a500f3ca750e099f79601f508bsalomon     * Called by a GrGpuResource when it removes its scratch key.
41610e23caea3106be125acea10a637789e5a15c728bsalomon     */
41710e23caea3106be125acea10a637789e5a15c728bsalomon    void willRemoveScratchKey(const GrGpuResource* resource) {
41810e23caea3106be125acea10a637789e5a15c728bsalomon        fCache->willRemoveScratchKey(resource);
41910e23caea3106be125acea10a637789e5a15c728bsalomon    }
42084c8e62fad59f0e19b40ac718467f5b7884b431dbsalomon
42184c8e62fad59f0e19b40ac718467f5b7884b431dbsalomon    /**
42284c8e62fad59f0e19b40ac718467f5b7884b431dbsalomon     * Called by GrGpuResources when they change from budgeted to unbudgeted or vice versa.
42384c8e62fad59f0e19b40ac718467f5b7884b431dbsalomon     */
42484c8e62fad59f0e19b40ac718467f5b7884b431dbsalomon    void didChangeBudgetStatus(GrGpuResource* resource) { fCache->didChangeBudgetStatus(resource); }
42584c8e62fad59f0e19b40ac718467f5b7884b431dbsalomon
42671cb0c241e439b6ed746b90294d0b6916644a644bsalomon    // No taking addresses of this type.
42771cb0c241e439b6ed746b90294d0b6916644a644bsalomon    const ResourceAccess* operator&() const;
42871cb0c241e439b6ed746b90294d0b6916644a644bsalomon    ResourceAccess* operator&();
42971cb0c241e439b6ed746b90294d0b6916644a644bsalomon
4300ea80f43a1af05b8157a4ef387223bb5b0da35edbsalomon    GrResourceCache* fCache;
43171cb0c241e439b6ed746b90294d0b6916644a644bsalomon
43271cb0c241e439b6ed746b90294d0b6916644a644bsalomon    friend class GrGpuResource; // To access all the proxy inline methods.
4330ea80f43a1af05b8157a4ef387223bb5b0da35edbsalomon    friend class GrResourceCache; // To create this type.
43471cb0c241e439b6ed746b90294d0b6916644a644bsalomon};
43571cb0c241e439b6ed746b90294d0b6916644a644bsalomon
4360ea80f43a1af05b8157a4ef387223bb5b0da35edbsalomoninline GrResourceCache::ResourceAccess GrResourceCache::resourceAccess() {
43771cb0c241e439b6ed746b90294d0b6916644a644bsalomon    return ResourceAccess(this);
43871cb0c241e439b6ed746b90294d0b6916644a644bsalomon}
43971cb0c241e439b6ed746b90294d0b6916644a644bsalomon
440c8dc1f74b6cdda9a43a638292a608c59c1d72d80bsalomon#endif
441