blob: 805d359eb4e0061f9a7177ec2b759b5f426959e2 [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
25 * resource instances with the same properties (e.g. multipass rendering that ping pongs
26 * 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 /**
50 * Returns the number of cached resources.
51 */
52 int getResourceCount() const { return fCount; }
bsalomon8b79d232014-11-10 10:19:06 -080053
bsalomon71cb0c22014-11-14 12:10:14 -080054 /**
55 * Returns the number of bytes consumed by cached resources.
56 */
57 size_t getResourceBytes() const { return fBytes; }
58
59 /**
60 * Returns the cached resources count budget.
61 */
62 int getMaxResourceCount() const { return fMaxCount; }
63
64 /**
65 * Returns the number of bytes consumed by cached resources.
66 */
67 size_t getMaxResourceBytes() const { return fMaxBytes; }
68
69 /**
70 * Abandons the backend API resources owned by all GrGpuResource objects and removes them from
71 * the cache.
72 */
bsalomonc8dc1f72014-08-21 13:02:13 -070073 void abandonAll();
74
bsalomon71cb0c22014-11-14 12:10:14 -080075 /**
76 * Releases the backend API resources owned by all GrGpuResource objects and removes them from
77 * the cache.
78 */
bsalomonc8dc1f72014-08-21 13:02:13 -070079 void releaseAll();
80
bsalomon000f8292014-10-15 19:04:14 -070081 enum {
82 /** Preferentially returns scratch resources with no pending IO. */
83 kPreferNoPendingIO_ScratchFlag = 0x1,
84 /** Will not return any resources that match but have pending IO. */
85 kRequireNoPendingIO_ScratchFlag = 0x2,
86 };
bsalomon71cb0c22014-11-14 12:10:14 -080087
88 /**
89 * Find a resource that matches a scratch key.
90 */
bsalomon000f8292014-10-15 19:04:14 -070091 GrGpuResource* findAndRefScratchResource(const GrResourceKey& scratchKey, uint32_t flags = 0);
bsalomon8b79d232014-11-10 10:19:06 -080092
93#ifdef SK_DEBUG
94 // This is not particularly fast and only used for validation, so debug only.
95 int countScratchEntriesForKey(const GrResourceKey& scratchKey) const {
96 SkASSERT(scratchKey.isScratch());
97 return fScratchMap.countForKey(scratchKey);
98 }
99#endif
100
bsalomon71cb0c22014-11-14 12:10:14 -0800101 /**
102 * Find a resource that matches a content key.
103 */
bsalomon8b79d232014-11-10 10:19:06 -0800104 GrGpuResource* findAndRefContentResource(const GrResourceKey& contentKey) {
105 SkASSERT(!contentKey.isScratch());
bsalomon71cb0c22014-11-14 12:10:14 -0800106 GrGpuResource* resource = fContentHash.find(contentKey);
107 if (resource) {
108 resource->ref();
109 this->makeResourceMRU(resource);
110 }
111 return resource;
bsalomon8b79d232014-11-10 10:19:06 -0800112 }
113
bsalomon71cb0c22014-11-14 12:10:14 -0800114 /**
115 * Query whether a content key exists in the cache.
116 */
bsalomon8b79d232014-11-10 10:19:06 -0800117 bool hasContentKey(const GrResourceKey& contentKey) const {
118 SkASSERT(!contentKey.isScratch());
119 return SkToBool(fContentHash.find(contentKey));
120 }
bsalomonbcf0a522014-10-08 08:40:09 -0700121
bsalomon71cb0c22014-11-14 12:10:14 -0800122 /** Purges all resources that don't have external owners. */
123 void purgeAllUnlocked();
124
125 /**
126 * The callback function used by the cache when it is still over budget after a purge. The
127 * passed in 'data' is the same 'data' handed to setOverbudgetCallback.
128 */
129 typedef void (*PFOverBudgetCB)(void* data);
130
131 /**
132 * Set the callback the cache should use when it is still over budget after a purge. The 'data'
133 * provided here will be passed back to the callback. Note that the cache will attempt to purge
134 * any resources newly freed by the callback.
135 */
136 void setOverBudgetCallback(PFOverBudgetCB overBudgetCB, void* data) {
137 fOverBudgetCB = overBudgetCB;
138 fOverBudgetData = data;
139 }
140
141#if GR_GPU_STATS
142 void printStats() const;
143#endif
144
bsalomonc8dc1f72014-08-21 13:02:13 -0700145private:
bsalomon71cb0c22014-11-14 12:10:14 -0800146 ///////////////////////////////////////////////////////////////////////////
147 /// @name Methods accessible via ResourceAccess
148 ////
149 void insertResource(GrGpuResource*);
150 void removeResource(GrGpuResource*);
bsalomon12299ab2014-11-14 13:33:09 -0800151 void notifyPurgable(GrGpuResource*);
bsalomon71cb0c22014-11-14 12:10:14 -0800152 void didChangeGpuMemorySize(const GrGpuResource*, size_t oldSize);
153 bool didSetContentKey(GrGpuResource*);
154 void makeResourceMRU(GrGpuResource*);
155 /// @}
156
157 void purgeAsNeeded() {
158 if (fPurging || (fCount <= fMaxCount && fBytes < fMaxBytes)) {
159 return;
160 }
161 this->internalPurgeAsNeeded();
162 }
163
164 void internalPurgeAsNeeded();
165
bsalomon16961262014-08-26 14:01:07 -0700166#ifdef SK_DEBUG
bsalomon37dd3312014-11-03 08:47:23 -0800167 bool isInCache(const GrGpuResource* r) const { return fResources.isInList(r); }
bsalomon71cb0c22014-11-14 12:10:14 -0800168 void validate() const;
169#else
170 void validate() const {}
bsalomon16961262014-08-26 14:01:07 -0700171#endif
172
bsalomon71cb0c22014-11-14 12:10:14 -0800173 class AutoValidate;
174
bsalomonbcf0a522014-10-08 08:40:09 -0700175 class AvailableForScratchUse;
bsalomon744998e2014-08-28 09:54:34 -0700176
bsalomon744998e2014-08-28 09:54:34 -0700177 struct ScratchMapTraits {
178 static const GrResourceKey& GetKey(const GrGpuResource& r) {
bsalomon453cf402014-11-11 14:15:57 -0800179 return r.cacheAccess().getScratchKey();
bsalomon744998e2014-08-28 09:54:34 -0700180 }
181
182 static uint32_t Hash(const GrResourceKey& key) { return key.getHash(); }
183 };
184 typedef SkTMultiMap<GrGpuResource, GrResourceKey, ScratchMapTraits> ScratchMap;
185
bsalomon8b79d232014-11-10 10:19:06 -0800186 struct ContentHashTraits {
187 static const GrResourceKey& GetKey(const GrGpuResource& r) {
bsalomon453cf402014-11-11 14:15:57 -0800188 return *r.cacheAccess().getContentKey();
bsalomon8b79d232014-11-10 10:19:06 -0800189 }
190
191 static uint32_t Hash(const GrResourceKey& key) { return key.getHash(); }
192 };
193 typedef SkTDynamicHash<GrGpuResource, GrResourceKey, ContentHashTraits> ContentHash;
194
bsalomon71cb0c22014-11-14 12:10:14 -0800195 typedef SkTInternalLList<GrGpuResource> ResourceList;
196
197 ResourceList fResources;
bsalomon744998e2014-08-28 09:54:34 -0700198 // This map holds all resources that can be used as scratch resources.
bsalomon8b79d232014-11-10 10:19:06 -0800199 ScratchMap fScratchMap;
200 // This holds all resources that have content keys.
201 ContentHash fContentHash;
bsalomon71cb0c22014-11-14 12:10:14 -0800202
203 // our budget, used in purgeAsNeeded()
204 int fMaxCount;
205 size_t fMaxBytes;
206
207#if GR_CACHE_STATS
208 int fHighWaterCount;
209 size_t fHighWaterBytes;
210#endif
211
212 // our current stats, related to our budget
213 int fCount;
214 size_t fBytes;
215
216 // prevents recursive purging
217 bool fPurging;
218 bool fNewlyPurgableResourceWhilePurging;
219
220 PFOverBudgetCB fOverBudgetCB;
221 void* fOverBudgetData;
222
bsalomonc8dc1f72014-08-21 13:02:13 -0700223};
224
bsalomon71cb0c22014-11-14 12:10:14 -0800225class GrResourceCache2::ResourceAccess {
226private:
227 ResourceAccess(GrResourceCache2* cache) : fCache(cache) { }
228 ResourceAccess(const ResourceAccess& that) : fCache(that.fCache) { }
229 ResourceAccess& operator=(const ResourceAccess&); // unimpl
230
231 /**
232 * Insert a resource into the cache.
233 */
234 void insertResource(GrGpuResource* resource) { fCache->insertResource(resource); }
235
236 /**
237 * Removes a resource from the cache.
238 */
239 void removeResource(GrGpuResource* resource) { fCache->removeResource(resource); }
240
241 /**
242 * Called by GrGpuResources when they detects that they are newly purgable.
243 */
bsalomon12299ab2014-11-14 13:33:09 -0800244 void notifyPurgable(GrGpuResource* resource) { fCache->notifyPurgable(resource); }
bsalomon71cb0c22014-11-14 12:10:14 -0800245
246 /**
247 * Called by GrGpuResources when their sizes change.
248 */
249 void didChangeGpuMemorySize(const GrGpuResource* resource, size_t oldSize) {
250 fCache->didChangeGpuMemorySize(resource, oldSize);
251 }
252
253 /**
254 * Called by GrGpuResources when their content keys change.
255 *
256 * This currently returns a bool and fails when an existing resource has a key that collides
257 * with the new content key. In the future it will null out the content key for the existing
258 * resource. The failure is a temporary measure taken because duties are split between two
259 * cache objects currently.
260 */
261 bool didSetContentKey(GrGpuResource* resource) { return fCache->didSetContentKey(resource); }
262
263 // No taking addresses of this type.
264 const ResourceAccess* operator&() const;
265 ResourceAccess* operator&();
266
267 GrResourceCache2* fCache;
268
269 friend class GrGpuResource; // To access all the proxy inline methods.
270 friend class GrResourceCache2; // To create this type.
271};
272
273inline GrResourceCache2::ResourceAccess GrResourceCache2::resourceAccess() {
274 return ResourceAccess(this);
275}
276
bsalomonc8dc1f72014-08-21 13:02:13 -0700277#endif