blob: 5733cff66460bc476fe24560c7528141122b51c7 [file] [log] [blame]
bsalomonc8dc1f72014-08-21 13:02:13 -07001
2/*
3 * Copyright 2014 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9#ifndef GrResourceCache2_DEFINED
10#define GrResourceCache2_DEFINED
11
bsalomon744998e2014-08-28 09:54:34 -070012#include "GrGpuResource.h"
bsalomon453cf402014-11-11 14:15:57 -080013#include "GrGpuResourceCacheAccess.h"
bsalomon744998e2014-08-28 09:54:34 -070014#include "GrResourceKey.h"
bsalomon8b79d232014-11-10 10:19:06 -080015#include "SkRefCnt.h"
bsalomonc8dc1f72014-08-21 13:02:13 -070016#include "SkTInternalLList.h"
bsalomon744998e2014-08-28 09:54:34 -070017#include "SkTMultiMap.h"
bsalomonc8dc1f72014-08-21 13:02:13 -070018
19/**
bsalomon71cb0c22014-11-14 12:10:14 -080020 * Manages the lifetime of all GrGpuResource instances.
21 *
22 * Resources may have optionally have two types of keys:
23 * 1) A scratch key. This is for resources whose allocations are cached but not their contents.
24 * Multiple resources can share the same scratch key. This is so a caller can have two
bsalomon84c8e622014-11-17 09:33:27 -080025 * resource instances with the same properties (e.g. multipass rendering that ping-pongs
bsalomon71cb0c22014-11-14 12:10:14 -080026 * between two temporary surfaces. The scratch key is set at resource creation time and
27 * should never change. Resources need not have a scratch key.
28 * 2) A content key. This key represents the contents of the resource rather than just its
29 * allocation properties. They may not collide. The content key can be set after resource
30 * creation. Currently it may only be set once and cannot be cleared. This restriction will
31 * be removed.
32 * If a resource has neither key type then it will be deleted as soon as the last reference to it
33 * is dropped. If a key has both keys the content key takes precedence.
bsalomonc8dc1f72014-08-21 13:02:13 -070034 */
35class GrResourceCache2 {
36public:
bsalomon71cb0c22014-11-14 12:10:14 -080037 GrResourceCache2();
bsalomonc8dc1f72014-08-21 13:02:13 -070038 ~GrResourceCache2();
39
bsalomon71cb0c22014-11-14 12:10:14 -080040 /** Used to access functionality needed by GrGpuResource for lifetime management. */
41 class ResourceAccess;
42 ResourceAccess resourceAccess();
bsalomonc8dc1f72014-08-21 13:02:13 -070043
bsalomon71cb0c22014-11-14 12:10:14 -080044 /**
45 * Sets the cache limits in terms of number of resources and max gpu memory byte size.
46 */
47 void setLimits(int count, size_t bytes);
bsalomonc8dc1f72014-08-21 13:02:13 -070048
bsalomon71cb0c22014-11-14 12:10:14 -080049 /**
bsalomondace19e2014-11-17 07:34:06 -080050 * Returns the number of resources.
bsalomon71cb0c22014-11-14 12:10:14 -080051 */
52 int getResourceCount() const { return fCount; }
bsalomon8b79d232014-11-10 10:19:06 -080053
bsalomon71cb0c22014-11-14 12:10:14 -080054 /**
bsalomondace19e2014-11-17 07:34:06 -080055 * Returns the number of resources that count against the budget.
56 */
57 int getBudgetedResourceCount() const { return fBudgetedCount; }
58
59 /**
60 * Returns the number of bytes consumed by resources.
bsalomon71cb0c22014-11-14 12:10:14 -080061 */
62 size_t getResourceBytes() const { return fBytes; }
63
64 /**
bsalomondace19e2014-11-17 07:34:06 -080065 * Returns the number of bytes consumed by budgeted resources.
66 */
67 size_t getBudgetedResourceBytes() const { return fBudgetedBytes; }
68
69 /**
bsalomon71cb0c22014-11-14 12:10:14 -080070 * Returns the cached resources count budget.
71 */
72 int getMaxResourceCount() const { return fMaxCount; }
73
74 /**
75 * Returns the number of bytes consumed by cached resources.
76 */
77 size_t getMaxResourceBytes() const { return fMaxBytes; }
78
79 /**
80 * Abandons the backend API resources owned by all GrGpuResource objects and removes them from
81 * the cache.
82 */
bsalomonc8dc1f72014-08-21 13:02:13 -070083 void abandonAll();
84
bsalomon71cb0c22014-11-14 12:10:14 -080085 /**
86 * Releases the backend API resources owned by all GrGpuResource objects and removes them from
87 * the cache.
88 */
bsalomonc8dc1f72014-08-21 13:02:13 -070089 void releaseAll();
90
bsalomon000f8292014-10-15 19:04:14 -070091 enum {
92 /** Preferentially returns scratch resources with no pending IO. */
93 kPreferNoPendingIO_ScratchFlag = 0x1,
94 /** Will not return any resources that match but have pending IO. */
95 kRequireNoPendingIO_ScratchFlag = 0x2,
96 };
bsalomon71cb0c22014-11-14 12:10:14 -080097
98 /**
99 * Find a resource that matches a scratch key.
100 */
bsalomon7775c852014-12-30 12:50:52 -0800101 GrGpuResource* findAndRefScratchResource(const GrScratchKey& scratchKey, uint32_t flags = 0);
bsalomon8b79d232014-11-10 10:19:06 -0800102
103#ifdef SK_DEBUG
104 // This is not particularly fast and only used for validation, so debug only.
bsalomon7775c852014-12-30 12:50:52 -0800105 int countScratchEntriesForKey(const GrScratchKey& scratchKey) const {
bsalomon8b79d232014-11-10 10:19:06 -0800106 return fScratchMap.countForKey(scratchKey);
107 }
108#endif
109
bsalomon71cb0c22014-11-14 12:10:14 -0800110 /**
111 * Find a resource that matches a content key.
112 */
bsalomon8b79d232014-11-10 10:19:06 -0800113 GrGpuResource* findAndRefContentResource(const GrResourceKey& contentKey) {
bsalomon71cb0c22014-11-14 12:10:14 -0800114 GrGpuResource* resource = fContentHash.find(contentKey);
115 if (resource) {
116 resource->ref();
117 this->makeResourceMRU(resource);
118 }
119 return resource;
bsalomon8b79d232014-11-10 10:19:06 -0800120 }
121
bsalomon71cb0c22014-11-14 12:10:14 -0800122 /**
123 * Query whether a content key exists in the cache.
124 */
bsalomon8b79d232014-11-10 10:19:06 -0800125 bool hasContentKey(const GrResourceKey& contentKey) const {
bsalomon8b79d232014-11-10 10:19:06 -0800126 return SkToBool(fContentHash.find(contentKey));
127 }
bsalomonbcf0a522014-10-08 08:40:09 -0700128
bsalomon71cb0c22014-11-14 12:10:14 -0800129 /** Purges all resources that don't have external owners. */
130 void purgeAllUnlocked();
131
132 /**
133 * The callback function used by the cache when it is still over budget after a purge. The
134 * passed in 'data' is the same 'data' handed to setOverbudgetCallback.
135 */
136 typedef void (*PFOverBudgetCB)(void* data);
137
138 /**
139 * Set the callback the cache should use when it is still over budget after a purge. The 'data'
140 * provided here will be passed back to the callback. Note that the cache will attempt to purge
141 * any resources newly freed by the callback.
142 */
143 void setOverBudgetCallback(PFOverBudgetCB overBudgetCB, void* data) {
144 fOverBudgetCB = overBudgetCB;
145 fOverBudgetData = data;
146 }
147
148#if GR_GPU_STATS
149 void printStats() const;
150#endif
151
bsalomonc8dc1f72014-08-21 13:02:13 -0700152private:
bsalomon71cb0c22014-11-14 12:10:14 -0800153 ///////////////////////////////////////////////////////////////////////////
154 /// @name Methods accessible via ResourceAccess
155 ////
156 void insertResource(GrGpuResource*);
157 void removeResource(GrGpuResource*);
bsalomon12299ab2014-11-14 13:33:09 -0800158 void notifyPurgable(GrGpuResource*);
bsalomon71cb0c22014-11-14 12:10:14 -0800159 void didChangeGpuMemorySize(const GrGpuResource*, size_t oldSize);
160 bool didSetContentKey(GrGpuResource*);
bsalomon10e23ca2014-11-25 05:52:06 -0800161 void willRemoveScratchKey(const GrGpuResource*);
bsalomon84c8e622014-11-17 09:33:27 -0800162 void didChangeBudgetStatus(GrGpuResource*);
bsalomon71cb0c22014-11-14 12:10:14 -0800163 void makeResourceMRU(GrGpuResource*);
164 /// @}
165
166 void purgeAsNeeded() {
bsalomon1dbd8162014-11-26 06:06:02 -0800167 if (fPurging || (fBudgetedCount <= fMaxCount && fBudgetedBytes <= fMaxBytes)) {
bsalomon71cb0c22014-11-14 12:10:14 -0800168 return;
169 }
170 this->internalPurgeAsNeeded();
171 }
172
173 void internalPurgeAsNeeded();
174
bsalomon16961262014-08-26 14:01:07 -0700175#ifdef SK_DEBUG
bsalomon37dd3312014-11-03 08:47:23 -0800176 bool isInCache(const GrGpuResource* r) const { return fResources.isInList(r); }
bsalomon71cb0c22014-11-14 12:10:14 -0800177 void validate() const;
178#else
179 void validate() const {}
bsalomon16961262014-08-26 14:01:07 -0700180#endif
181
bsalomon71cb0c22014-11-14 12:10:14 -0800182 class AutoValidate;
183
bsalomonbcf0a522014-10-08 08:40:09 -0700184 class AvailableForScratchUse;
bsalomon744998e2014-08-28 09:54:34 -0700185
bsalomon744998e2014-08-28 09:54:34 -0700186 struct ScratchMapTraits {
bsalomon7775c852014-12-30 12:50:52 -0800187 static const GrScratchKey& GetKey(const GrGpuResource& r) {
bsalomon453cf402014-11-11 14:15:57 -0800188 return r.cacheAccess().getScratchKey();
bsalomon744998e2014-08-28 09:54:34 -0700189 }
190
bsalomon7775c852014-12-30 12:50:52 -0800191 static uint32_t Hash(const GrScratchKey& key) { return key.hash(); }
bsalomon744998e2014-08-28 09:54:34 -0700192 };
bsalomon7775c852014-12-30 12:50:52 -0800193 typedef SkTMultiMap<GrGpuResource, GrScratchKey, ScratchMapTraits> ScratchMap;
bsalomon744998e2014-08-28 09:54:34 -0700194
bsalomon8b79d232014-11-10 10:19:06 -0800195 struct ContentHashTraits {
196 static const GrResourceKey& GetKey(const GrGpuResource& r) {
bsalomon453cf402014-11-11 14:15:57 -0800197 return *r.cacheAccess().getContentKey();
bsalomon8b79d232014-11-10 10:19:06 -0800198 }
199
200 static uint32_t Hash(const GrResourceKey& key) { return key.getHash(); }
201 };
202 typedef SkTDynamicHash<GrGpuResource, GrResourceKey, ContentHashTraits> ContentHash;
203
bsalomon71cb0c22014-11-14 12:10:14 -0800204 typedef SkTInternalLList<GrGpuResource> ResourceList;
205
206 ResourceList fResources;
bsalomon744998e2014-08-28 09:54:34 -0700207 // This map holds all resources that can be used as scratch resources.
bsalomon8b79d232014-11-10 10:19:06 -0800208 ScratchMap fScratchMap;
209 // This holds all resources that have content keys.
210 ContentHash fContentHash;
bsalomon71cb0c22014-11-14 12:10:14 -0800211
212 // our budget, used in purgeAsNeeded()
213 int fMaxCount;
214 size_t fMaxBytes;
215
216#if GR_CACHE_STATS
217 int fHighWaterCount;
218 size_t fHighWaterBytes;
bsalomondace19e2014-11-17 07:34:06 -0800219 int fBudgetedHighWaterCount;
220 size_t fBudgetedHighWaterBytes;
bsalomon71cb0c22014-11-14 12:10:14 -0800221#endif
222
bsalomondace19e2014-11-17 07:34:06 -0800223 // our current stats for all resources
bsalomon71cb0c22014-11-14 12:10:14 -0800224 int fCount;
225 size_t fBytes;
226
bsalomondace19e2014-11-17 07:34:06 -0800227 // our current stats for resources that count against the budget
228 int fBudgetedCount;
229 size_t fBudgetedBytes;
230
bsalomon71cb0c22014-11-14 12:10:14 -0800231 // prevents recursive purging
232 bool fPurging;
233 bool fNewlyPurgableResourceWhilePurging;
234
235 PFOverBudgetCB fOverBudgetCB;
236 void* fOverBudgetData;
237
bsalomonc8dc1f72014-08-21 13:02:13 -0700238};
239
bsalomon71cb0c22014-11-14 12:10:14 -0800240class GrResourceCache2::ResourceAccess {
241private:
242 ResourceAccess(GrResourceCache2* cache) : fCache(cache) { }
243 ResourceAccess(const ResourceAccess& that) : fCache(that.fCache) { }
244 ResourceAccess& operator=(const ResourceAccess&); // unimpl
245
246 /**
247 * Insert a resource into the cache.
248 */
249 void insertResource(GrGpuResource* resource) { fCache->insertResource(resource); }
250
251 /**
252 * Removes a resource from the cache.
253 */
254 void removeResource(GrGpuResource* resource) { fCache->removeResource(resource); }
255
256 /**
257 * Called by GrGpuResources when they detects that they are newly purgable.
258 */
bsalomon12299ab2014-11-14 13:33:09 -0800259 void notifyPurgable(GrGpuResource* resource) { fCache->notifyPurgable(resource); }
bsalomon71cb0c22014-11-14 12:10:14 -0800260
261 /**
262 * Called by GrGpuResources when their sizes change.
263 */
264 void didChangeGpuMemorySize(const GrGpuResource* resource, size_t oldSize) {
265 fCache->didChangeGpuMemorySize(resource, oldSize);
266 }
267
268 /**
269 * Called by GrGpuResources when their content keys change.
270 *
271 * This currently returns a bool and fails when an existing resource has a key that collides
272 * with the new content key. In the future it will null out the content key for the existing
273 * resource. The failure is a temporary measure taken because duties are split between two
274 * cache objects currently.
275 */
276 bool didSetContentKey(GrGpuResource* resource) { return fCache->didSetContentKey(resource); }
277
bsalomon10e23ca2014-11-25 05:52:06 -0800278 /**
279 * Called by GrGpuResources when the remove their scratch key.
280 */
281 void willRemoveScratchKey(const GrGpuResource* resource) {
282 fCache->willRemoveScratchKey(resource);
283 }
bsalomon84c8e622014-11-17 09:33:27 -0800284
285 /**
286 * Called by GrGpuResources when they change from budgeted to unbudgeted or vice versa.
287 */
288 void didChangeBudgetStatus(GrGpuResource* resource) { fCache->didChangeBudgetStatus(resource); }
289
bsalomon71cb0c22014-11-14 12:10:14 -0800290 // No taking addresses of this type.
291 const ResourceAccess* operator&() const;
292 ResourceAccess* operator&();
293
294 GrResourceCache2* fCache;
295
296 friend class GrGpuResource; // To access all the proxy inline methods.
297 friend class GrResourceCache2; // To create this type.
298};
299
300inline GrResourceCache2::ResourceAccess GrResourceCache2::resourceAccess() {
301 return ResourceAccess(this);
302}
303
bsalomonc8dc1f72014-08-21 13:02:13 -0700304#endif