Index: src/gpu/GrResourceCache.h |
diff --git a/src/gpu/GrResourceCache.h b/src/gpu/GrResourceCache.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..80e4b3f1e40d0e499f7d67def7a8b7c2ce1f7c8c |
--- /dev/null |
+++ b/src/gpu/GrResourceCache.h |
@@ -0,0 +1,251 @@ |
+ |
+/* |
+ * Copyright 2011 Google Inc. |
+ * |
+ * Use of this source code is governed by a BSD-style license that can be |
+ * found in the LICENSE file. |
+ */ |
+ |
+#ifndef GrResourceCache_DEFINED |
+#define GrResourceCache_DEFINED |
+ |
+#include "GrDrawTargetCaps.h" |
+#include "GrResourceKey.h" |
+#include "SkTMultiMap.h" |
+#include "SkMessageBus.h" |
+#include "SkTInternalLList.h" |
+ |
+class GrGpuResource; |
+class GrResourceCache; |
+class GrResourceCacheEntry; |
+ |
+ |
+// The cache listens for these messages to purge junk resources proactively. |
+struct GrResourceInvalidatedMessage { |
+ GrResourceKey key; |
+}; |
+ |
+/////////////////////////////////////////////////////////////////////////////// |
+ |
+class GrResourceCacheEntry { |
+public: |
+ GrGpuResource* resource() const { return fResource; } |
+ |
+ static uint32_t Hash(const GrGpuResource* resource) { |
+ return static_cast<uint32_t>(reinterpret_cast<intptr_t>(resource)); |
+ } |
+#ifdef SK_DEBUG |
+ void validate() const; |
+#else |
+ void validate() const {} |
+#endif |
+ |
+ /** |
+ * Update the cached size for this entry and inform the resource cache that |
+ * it has changed. Usually invoked from GrGpuResource::didChangeGpuMemorySize, |
+ * not directly from here. |
+ */ |
+ void didChangeResourceSize(); |
+ |
+private: |
+ GrResourceCacheEntry(GrResourceCache*, GrGpuResource*); |
+ ~GrResourceCacheEntry(); |
+ |
+ GrResourceCache* fResourceCache; |
+ GrGpuResource* fResource; |
+ size_t fCachedSize; |
+ |
+ // Linked list for the LRU ordering. |
+ SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrResourceCacheEntry); |
+ |
+ friend class GrResourceCache; |
+ friend class GrContext; |
+}; |
+ |
+/////////////////////////////////////////////////////////////////////////////// |
+ |
+/** |
+ * Cache of GrGpuResource objects. |
+ * |
+ * These have a corresponding GrResourceKey, built from 128bits identifying the |
+ * resource. Multiple resources can map to same GrResourceKey. |
+ * |
+ * The cache stores the entries in a double-linked list, which is its LRU. |
+ * When an entry is "locked" (i.e. given to the caller), it is moved to the |
+ * head of the list. If/when we must purge some of the entries, we walk the |
+ * list backwards from the tail, since those are the least recently used. |
+ * |
+ * For fast searches, we maintain a hash map based on the GrResourceKey. |
+ * |
+ * It is a goal to make the GrResourceCache the central repository and bookkeeper |
+ * of all resources. It should replace the linked list of GrGpuResources that |
+ * GrGpu uses to call abandon/release. |
+ */ |
+class GrResourceCache { |
+public: |
+ GrResourceCache(const GrDrawTargetCaps*, int maxCount, size_t maxBytes); |
+ ~GrResourceCache(); |
+ |
+ /** |
+ * Return the current resource cache limits. |
+ * |
+ * @param maxResource If non-null, returns maximum number of resources |
+ * that can be held in the cache. |
+ * @param maxBytes If non-null, returns maximum number of bytes of |
+ * gpu memory that can be held in the cache. |
+ */ |
+ void getLimits(int* maxResources, size_t* maxBytes) const; |
+ |
+ /** |
+ * Specify the resource cache limits. If the current cache exceeds either |
+ * of these, it will be purged (LRU) to keep the cache within these limits. |
+ * |
+ * @param maxResources The maximum number of resources that can be held in |
+ * the cache. |
+ * @param maxBytes The maximum number of bytes of resource memory that |
+ * can be held in the cache. |
+ */ |
+ void setLimits(int maxResources, size_t maxResourceBytes); |
+ |
+ /** |
+ * The callback function used by the cache when it is still over budget |
+ * after a purge. The passed in 'data' is the same 'data' handed to |
+ * setOverbudgetCallback. The callback returns true if some resources |
+ * have been freed. |
+ */ |
+ typedef bool (*PFOverbudgetCB)(void* data); |
+ |
+ /** |
+ * Set the callback the cache should use when it is still over budget |
+ * after a purge. The 'data' provided here will be passed back to the |
+ * callback. Note that the cache will attempt to purge any resources newly |
+ * freed by the callback. |
+ */ |
+ void setOverbudgetCallback(PFOverbudgetCB overbudgetCB, void* data) { |
+ fOverbudgetCB = overbudgetCB; |
+ fOverbudgetData = data; |
+ } |
+ |
+ /** |
+ * Returns the number of bytes consumed by cached resources. |
+ */ |
+ size_t getCachedResourceBytes() const { return fEntryBytes; } |
+ |
+ /** |
+ * Returns the number of cached resources. |
+ */ |
+ int getCachedResourceCount() const { return fEntryCount; } |
+ |
+ void makeResourceMRU(GrGpuResource*); |
+ |
+ /** Called by GrGpuResources when they detects that they are newly purgable. */ |
+ void notifyPurgable(const GrGpuResource*); |
+ |
+ /** |
+ * Add the new resource to the cache (by creating a new cache entry based |
+ * on the provided key and resource). |
+ * |
+ * Ownership of the resource is transferred to the resource cache, |
+ * which will unref() it when it is purged or deleted. |
+ * |
+ * This can fail if the key is already taken, or the resource is already in |
+ * the cache. |
+ */ |
+ bool addResource(const GrResourceKey& key, GrGpuResource* resource); |
+ |
+ /** |
+ * Notify the cache that the size of a resource has changed. |
+ */ |
+ void didIncreaseResourceSize(const GrResourceCacheEntry*, size_t amountInc); |
+ void didDecreaseResourceSize(const GrResourceCacheEntry*, size_t amountDec); |
+ |
+ /** |
+ * Remove a resource from the cache and delete it! |
+ */ |
+ void deleteResource(GrResourceCacheEntry* entry); |
+ |
+ /** |
+ * Removes every resource in the cache that isn't locked. |
+ */ |
+ void purgeAllUnlocked(); |
+ |
+ /** |
+ * Allow cache to purge unused resources to obey resource limitations |
+ * Note: this entry point will be hidden (again) once totally ref-driven |
+ * cache maintenance is implemented. Note that the overbudget callback |
+ * will be called if the initial purge doesn't get the cache under |
+ * its budget. |
+ * |
+ * extraCount and extraBytes are added to the current resource allocation |
+ * to make sure enough room is available for future additions (e.g, |
+ * 10MB across 10 textures is about to be added). |
+ */ |
+ void purgeAsNeeded(int extraCount = 0, size_t extraBytes = 0); |
+ |
+#ifdef SK_DEBUG |
+ void validate() const; |
+#else |
+ void validate() const {} |
+#endif |
+ |
+#if GR_CACHE_STATS |
+ void printStats(); |
+#endif |
+ |
+private: |
+ void internalDetach(GrResourceCacheEntry*); |
+ void attachToHead(GrResourceCacheEntry*); |
+ void purgeInvalidated(); |
+ void internalPurge(int extraCount, size_t extraBytes); |
+#ifdef SK_DEBUG |
+ static size_t countBytes(const SkTInternalLList<GrResourceCacheEntry>& list); |
+#endif |
+ |
+ // We're an internal doubly linked list |
+ typedef SkTInternalLList<GrResourceCacheEntry> EntryList; |
+ EntryList fList; |
+ |
+ // our budget, used in purgeAsNeeded() |
+ int fMaxCount; |
+ size_t fMaxBytes; |
+ |
+ // our current stats, related to our budget |
+#if GR_CACHE_STATS |
+ int fHighWaterEntryCount; |
+ size_t fHighWaterEntryBytes; |
+#endif |
+ |
+ int fEntryCount; |
+ size_t fEntryBytes; |
+ |
+ // prevents recursive purging |
+ bool fPurging; |
+ |
+ PFOverbudgetCB fOverbudgetCB; |
+ void* fOverbudgetData; |
+ |
+ SkAutoTUnref<const GrDrawTargetCaps> fCaps; |
+}; |
+ |
+/////////////////////////////////////////////////////////////////////////////// |
+ |
+#ifdef SK_DEBUG |
+ class GrAutoResourceCacheValidate { |
+ public: |
+ GrAutoResourceCacheValidate(GrResourceCache* cache) : fCache(cache) { |
+ cache->validate(); |
+ } |
+ ~GrAutoResourceCacheValidate() { |
+ fCache->validate(); |
+ } |
+ private: |
+ GrResourceCache* fCache; |
+ }; |
+#else |
+ class GrAutoResourceCacheValidate { |
+ public: |
+ GrAutoResourceCacheValidate(GrResourceCache*) {} |
+ }; |
+#endif |
+ |
+#endif |