OLD | NEW |
| (Empty) |
1 | |
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 | |
12 #include "GrGpuResource.h" | |
13 #include "GrGpuResourceCacheAccess.h" | |
14 #include "GrResourceKey.h" | |
15 #include "SkMessageBus.h" | |
16 #include "SkRefCnt.h" | |
17 #include "SkTArray.h" | |
18 #include "SkTInternalLList.h" | |
19 #include "SkTMultiMap.h" | |
20 | |
21 class SkString; | |
22 | |
23 /** | |
24 * Manages the lifetime of all GrGpuResource instances. | |
25 * | |
26 * Resources may have optionally have two types of keys: | |
27 * 1) A scratch key. This is for resources whose allocations are cached but
not their contents. | |
28 * Multiple resources can share the same scratch key. This is so a calle
r can have two | |
29 * resource instances with the same properties (e.g. multipass rendering
that ping-pongs | |
30 * between two temporary surfaces. The scratch key is set at resource cr
eation time and | |
31 * should never change. Resources need not have a scratch key. | |
32 * 2) A content key. This key represents the contents of the resource rathe
r than just its | |
33 * allocation properties. They may not collide. The content key can be s
et after resource | |
34 * creation. Currently it may only be set once and cannot be cleared. Th
is restriction will | |
35 * be removed. | |
36 * If a resource has neither key type then it will be deleted as soon as the las
t reference to it | |
37 * is dropped. If a key has both keys the content key takes precedence. | |
38 */ | |
39 class GrResourceCache2 { | |
40 public: | |
41 GrResourceCache2(); | |
42 ~GrResourceCache2(); | |
43 | |
44 /** Used to access functionality needed by GrGpuResource for lifetime manage
ment. */ | |
45 class ResourceAccess; | |
46 ResourceAccess resourceAccess(); | |
47 | |
48 /** | |
49 * Sets the cache limits in terms of number of resources and max gpu memory
byte size. | |
50 */ | |
51 void setLimits(int count, size_t bytes); | |
52 | |
53 /** | |
54 * Returns the number of resources. | |
55 */ | |
56 int getResourceCount() const { return fCount; } | |
57 | |
58 /** | |
59 * Returns the number of resources that count against the budget. | |
60 */ | |
61 int getBudgetedResourceCount() const { return fBudgetedCount; } | |
62 | |
63 /** | |
64 * Returns the number of bytes consumed by resources. | |
65 */ | |
66 size_t getResourceBytes() const { return fBytes; } | |
67 | |
68 /** | |
69 * Returns the number of bytes consumed by budgeted resources. | |
70 */ | |
71 size_t getBudgetedResourceBytes() const { return fBudgetedBytes; } | |
72 | |
73 /** | |
74 * Returns the cached resources count budget. | |
75 */ | |
76 int getMaxResourceCount() const { return fMaxCount; } | |
77 | |
78 /** | |
79 * Returns the number of bytes consumed by cached resources. | |
80 */ | |
81 size_t getMaxResourceBytes() const { return fMaxBytes; } | |
82 | |
83 /** | |
84 * Abandons the backend API resources owned by all GrGpuResource objects and
removes them from | |
85 * the cache. | |
86 */ | |
87 void abandonAll(); | |
88 | |
89 /** | |
90 * Releases the backend API resources owned by all GrGpuResource objects and
removes them from | |
91 * the cache. | |
92 */ | |
93 void releaseAll(); | |
94 | |
95 enum { | |
96 /** Preferentially returns scratch resources with no pending IO. */ | |
97 kPreferNoPendingIO_ScratchFlag = 0x1, | |
98 /** Will not return any resources that match but have pending IO. */ | |
99 kRequireNoPendingIO_ScratchFlag = 0x2, | |
100 }; | |
101 | |
102 /** | |
103 * Find a resource that matches a scratch key. | |
104 */ | |
105 GrGpuResource* findAndRefScratchResource(const GrScratchKey& scratchKey, uin
t32_t flags = 0); | |
106 | |
107 #ifdef SK_DEBUG | |
108 // This is not particularly fast and only used for validation, so debug only
. | |
109 int countScratchEntriesForKey(const GrScratchKey& scratchKey) const { | |
110 return fScratchMap.countForKey(scratchKey); | |
111 } | |
112 #endif | |
113 | |
114 /** | |
115 * Find a resource that matches a content key. | |
116 */ | |
117 GrGpuResource* findAndRefContentResource(const GrContentKey& contentKey) { | |
118 GrGpuResource* resource = fContentHash.find(contentKey); | |
119 if (resource) { | |
120 resource->ref(); | |
121 this->makeResourceMRU(resource); | |
122 } | |
123 return resource; | |
124 } | |
125 | |
126 /** | |
127 * Query whether a content key exists in the cache. | |
128 */ | |
129 bool hasContentKey(const GrContentKey& contentKey) const { | |
130 return SkToBool(fContentHash.find(contentKey)); | |
131 } | |
132 | |
133 /** Purges resources to become under budget and processes resources with inv
alidated content | |
134 keys. */ | |
135 void purgeAsNeeded() { | |
136 SkTArray<GrContentKeyInvalidatedMessage> invalidKeyMsgs; | |
137 fInvalidContentKeyInbox.poll(&invalidKeyMsgs); | |
138 if (invalidKeyMsgs.count()) { | |
139 this->processInvalidContentKeys(invalidKeyMsgs); | |
140 } | |
141 if (fPurging || (fBudgetedCount <= fMaxCount && fBudgetedBytes <= fMaxBy
tes)) { | |
142 return; | |
143 } | |
144 this->internalPurgeAsNeeded(); | |
145 } | |
146 | |
147 /** Purges all resources that don't have external owners. */ | |
148 void purgeAllUnlocked(); | |
149 | |
150 /** | |
151 * The callback function used by the cache when it is still over budget afte
r a purge. The | |
152 * passed in 'data' is the same 'data' handed to setOverbudgetCallback. | |
153 */ | |
154 typedef void (*PFOverBudgetCB)(void* data); | |
155 | |
156 /** | |
157 * Set the callback the cache should use when it is still over budget after
a purge. The 'data' | |
158 * provided here will be passed back to the callback. Note that the cache wi
ll attempt to purge | |
159 * any resources newly freed by the callback. | |
160 */ | |
161 void setOverBudgetCallback(PFOverBudgetCB overBudgetCB, void* data) { | |
162 fOverBudgetCB = overBudgetCB; | |
163 fOverBudgetData = data; | |
164 } | |
165 | |
166 #if GR_GPU_STATS | |
167 void dumpStats(SkString*) const; | |
168 #endif | |
169 | |
170 private: | |
171 /////////////////////////////////////////////////////////////////////////// | |
172 /// @name Methods accessible via ResourceAccess | |
173 //// | |
174 void insertResource(GrGpuResource*); | |
175 void removeResource(GrGpuResource*); | |
176 void notifyPurgeable(GrGpuResource*); | |
177 void didChangeGpuMemorySize(const GrGpuResource*, size_t oldSize); | |
178 bool didSetContentKey(GrGpuResource*); | |
179 void willRemoveScratchKey(const GrGpuResource*); | |
180 void willRemoveContentKey(const GrGpuResource*); | |
181 void didChangeBudgetStatus(GrGpuResource*); | |
182 void makeResourceMRU(GrGpuResource*); | |
183 /// @} | |
184 | |
185 void internalPurgeAsNeeded(); | |
186 void processInvalidContentKeys(const SkTArray<GrContentKeyInvalidatedMessage
>&); | |
187 | |
188 #ifdef SK_DEBUG | |
189 bool isInCache(const GrGpuResource* r) const { return fResources.isInList(r)
; } | |
190 void validate() const; | |
191 #else | |
192 void validate() const {} | |
193 #endif | |
194 | |
195 class AutoValidate; | |
196 | |
197 class AvailableForScratchUse; | |
198 | |
199 struct ScratchMapTraits { | |
200 static const GrScratchKey& GetKey(const GrGpuResource& r) { | |
201 return r.cacheAccess().getScratchKey(); | |
202 } | |
203 | |
204 static uint32_t Hash(const GrScratchKey& key) { return key.hash(); } | |
205 }; | |
206 typedef SkTMultiMap<GrGpuResource, GrScratchKey, ScratchMapTraits> ScratchMa
p; | |
207 | |
208 struct ContentHashTraits { | |
209 static const GrContentKey& GetKey(const GrGpuResource& r) { | |
210 return r.getContentKey(); | |
211 } | |
212 | |
213 static uint32_t Hash(const GrContentKey& key) { return key.hash(); } | |
214 }; | |
215 typedef SkTDynamicHash<GrGpuResource, GrContentKey, ContentHashTraits> Conte
ntHash; | |
216 | |
217 typedef SkTInternalLList<GrGpuResource> ResourceList; | |
218 | |
219 typedef SkMessageBus<GrContentKeyInvalidatedMessage>::Inbox InvalidContentKe
yInbox; | |
220 | |
221 ResourceList fResources; | |
222 // This map holds all resources that can be used as scratch resources. | |
223 ScratchMap fScratchMap; | |
224 // This holds all resources that have content keys. | |
225 ContentHash fContentHash; | |
226 | |
227 // our budget, used in purgeAsNeeded() | |
228 int fMaxCount; | |
229 size_t fMaxBytes; | |
230 | |
231 #if GR_CACHE_STATS | |
232 int fHighWaterCount; | |
233 size_t fHighWaterBytes; | |
234 int fBudgetedHighWaterCount; | |
235 size_t fBudgetedHighWaterBytes; | |
236 #endif | |
237 | |
238 // our current stats for all resources | |
239 int fCount; | |
240 size_t fBytes; | |
241 | |
242 // our current stats for resources that count against the budget | |
243 int fBudgetedCount; | |
244 size_t fBudgetedBytes; | |
245 | |
246 // prevents recursive purging | |
247 bool fPurging; | |
248 bool fNewlyPurgeableResourceWhilePurging; | |
249 | |
250 PFOverBudgetCB fOverBudgetCB; | |
251 void* fOverBudgetData; | |
252 | |
253 InvalidContentKeyInbox fInvalidContentKeyInbox; | |
254 | |
255 }; | |
256 | |
257 class GrResourceCache2::ResourceAccess { | |
258 private: | |
259 ResourceAccess(GrResourceCache2* cache) : fCache(cache) { } | |
260 ResourceAccess(const ResourceAccess& that) : fCache(that.fCache) { } | |
261 ResourceAccess& operator=(const ResourceAccess&); // unimpl | |
262 | |
263 /** | |
264 * Insert a resource into the cache. | |
265 */ | |
266 void insertResource(GrGpuResource* resource) { fCache->insertResource(resour
ce); } | |
267 | |
268 /** | |
269 * Removes a resource from the cache. | |
270 */ | |
271 void removeResource(GrGpuResource* resource) { fCache->removeResource(resour
ce); } | |
272 | |
273 /** | |
274 * Called by GrGpuResources when they detects that they are newly purgeable. | |
275 */ | |
276 void notifyPurgeable(GrGpuResource* resource) { fCache->notifyPurgeable(reso
urce); } | |
277 | |
278 /** | |
279 * Called by GrGpuResources when their sizes change. | |
280 */ | |
281 void didChangeGpuMemorySize(const GrGpuResource* resource, size_t oldSize) { | |
282 fCache->didChangeGpuMemorySize(resource, oldSize); | |
283 } | |
284 | |
285 /** | |
286 * Called by GrGpuResources when their content keys change. | |
287 * | |
288 * This currently returns a bool and fails when an existing resource has a k
ey that collides | |
289 * with the new content key. In the future it will null out the content key
for the existing | |
290 * resource. The failure is a temporary measure taken because duties are spl
it between two | |
291 * cache objects currently. | |
292 */ | |
293 bool didSetContentKey(GrGpuResource* resource) { return fCache->didSetConten
tKey(resource); } | |
294 | |
295 /** | |
296 * Called by a GrGpuResource when it removes its content key. | |
297 */ | |
298 void willRemoveContentKey(GrGpuResource* resource) { | |
299 return fCache->willRemoveContentKey(resource); | |
300 } | |
301 | |
302 /** | |
303 * Called by a GrGpuResource when it removes its scratch key. | |
304 */ | |
305 void willRemoveScratchKey(const GrGpuResource* resource) { | |
306 fCache->willRemoveScratchKey(resource); | |
307 } | |
308 | |
309 /** | |
310 * Called by GrGpuResources when they change from budgeted to unbudgeted or
vice versa. | |
311 */ | |
312 void didChangeBudgetStatus(GrGpuResource* resource) { fCache->didChangeBudge
tStatus(resource); } | |
313 | |
314 // No taking addresses of this type. | |
315 const ResourceAccess* operator&() const; | |
316 ResourceAccess* operator&(); | |
317 | |
318 GrResourceCache2* fCache; | |
319 | |
320 friend class GrGpuResource; // To access all the proxy inline methods. | |
321 friend class GrResourceCache2; // To create this type. | |
322 }; | |
323 | |
324 inline GrResourceCache2::ResourceAccess GrResourceCache2::resourceAccess() { | |
325 return ResourceAccess(this); | |
326 } | |
327 | |
328 #endif | |
OLD | NEW |