OLD | NEW |
1 | 1 |
2 /* | 2 /* |
3 * Copyright 2014 Google Inc. | 3 * Copyright 2014 Google Inc. |
4 * | 4 * |
5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
7 */ | 7 */ |
8 | 8 |
9 #ifndef GrResourceCache_DEFINED | 9 #ifndef GrResourceCache_DEFINED |
10 #define GrResourceCache_DEFINED | 10 #define GrResourceCache_DEFINED |
(...skipping 20 matching lines...) Expand all Loading... |
31 * resource instances with the same properties (e.g. multipass rendering
that ping-pongs | 31 * resource instances with the same properties (e.g. multipass rendering
that ping-pongs |
32 * between two temporary surfaces). The scratch key is set at resource c
reation time and | 32 * between two temporary surfaces). The scratch key is set at resource c
reation time and |
33 * should never change. Resources need not have a scratch key. | 33 * should never change. Resources need not have a scratch key. |
34 * 2) A unique key. This key's meaning is specific to the domain that creat
ed the key. Only one | 34 * 2) A unique key. This key's meaning is specific to the domain that creat
ed the key. Only one |
35 * resource may have a given unique key. The unique key can be set, clea
red, or changed | 35 * resource may have a given unique key. The unique key can be set, clea
red, or changed |
36 * anytime after resource creation. | 36 * anytime after resource creation. |
37 * | 37 * |
38 * A unique key always takes precedence over a scratch key when a resource has b
oth types of keys. | 38 * A unique key always takes precedence over a scratch key when a resource has b
oth types of keys. |
39 * If a resource has neither key type then it will be deleted as soon as the las
t reference to it | 39 * If a resource has neither key type then it will be deleted as soon as the las
t reference to it |
40 * is dropped. | 40 * is dropped. |
| 41 * |
| 42 * When proactive purging is enabled, on every flush, the timestamp of that flus
h is stored in a |
| 43 * n-sized ring buffer. When purging occurs each purgeable resource's timestamp
is compared to the |
| 44 * timestamp of the n-th prior flush. If the resource's last use timestamp is ol
der than the old |
| 45 * flush then the resource is proactively purged even when the cache is under bu
dget. By default |
| 46 * this feature is disabled, though it can be enabled by calling GrResourceCache
::setLimits. |
41 */ | 47 */ |
42 class GrResourceCache { | 48 class GrResourceCache { |
43 public: | 49 public: |
44 GrResourceCache(); | 50 GrResourceCache(); |
45 ~GrResourceCache(); | 51 ~GrResourceCache(); |
46 | 52 |
| 53 // Default maximum number of budgeted resources in the cache. |
| 54 static const int kDefaultMaxCount = 2 * (1 << 12); |
| 55 // Default maximum number of bytes of gpu memory of budgeted resources in th
e cache. |
| 56 static const size_t kDefaultMaxSize = 96 * (1 << 20); |
| 57 // Default number of flushes a budgeted resources can go unused in the cache
before it is |
| 58 // purged. Large values disable the feature (as the ring buffer of flush tim
estamps would be |
| 59 // large). This is currently the default until we decide to enable this feat
ure |
| 60 // of the cache by default. |
| 61 static const int kDefaultMaxUnusedFlushes = 1024; |
| 62 |
47 /** Used to access functionality needed by GrGpuResource for lifetime manage
ment. */ | 63 /** Used to access functionality needed by GrGpuResource for lifetime manage
ment. */ |
48 class ResourceAccess; | 64 class ResourceAccess; |
49 ResourceAccess resourceAccess(); | 65 ResourceAccess resourceAccess(); |
50 | 66 |
51 /** | 67 /** |
52 * Sets the cache limits in terms of number of resources and max gpu memory
byte size. | 68 * Sets the cache limits in terms of number of resources, max gpu memory byt
e size, and number |
| 69 * of GrContext flushes that a resource can be unused before it is evicted.
The latter value is |
| 70 * a suggestion and there is no promise that a resource will be purged immed
iately after it |
| 71 * hasn't been used in maxUnusedFlushes flushes. |
53 */ | 72 */ |
54 void setLimits(int count, size_t bytes); | 73 void setLimits(int count, size_t bytes, int maxUnusedFlushes = kDefaultMaxUn
usedFlushes); |
55 | 74 |
56 /** | 75 /** |
57 * Returns the number of resources. | 76 * Returns the number of resources. |
58 */ | 77 */ |
59 int getResourceCount() const { | 78 int getResourceCount() const { |
60 return fPurgeableQueue.count() + fNonpurgeableResources.count(); | 79 return fPurgeableQueue.count() + fNonpurgeableResources.count(); |
61 } | 80 } |
62 | 81 |
63 /** | 82 /** |
64 * Returns the number of resources that count against the budget. | 83 * Returns the number of resources that count against the budget. |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
129 | 148 |
130 /** | 149 /** |
131 * Query whether a unique key exists in the cache. | 150 * Query whether a unique key exists in the cache. |
132 */ | 151 */ |
133 bool hasUniqueKey(const GrUniqueKey& key) const { | 152 bool hasUniqueKey(const GrUniqueKey& key) const { |
134 return SkToBool(fUniqueHash.find(key)); | 153 return SkToBool(fUniqueHash.find(key)); |
135 } | 154 } |
136 | 155 |
137 /** Purges resources to become under budget and processes resources with inv
alidated unique | 156 /** Purges resources to become under budget and processes resources with inv
alidated unique |
138 keys. */ | 157 keys. */ |
139 void purgeAsNeeded() { | 158 void purgeAsNeeded(); |
140 SkTArray<GrUniqueKeyInvalidatedMessage> invalidKeyMsgs; | |
141 fInvalidUniqueKeyInbox.poll(&invalidKeyMsgs); | |
142 if (invalidKeyMsgs.count()) { | |
143 this->processInvalidUniqueKeys(invalidKeyMsgs); | |
144 } | |
145 if (fBudgetedCount <= fMaxCount && fBudgetedBytes <= fMaxBytes) { | |
146 return; | |
147 } | |
148 this->internalPurgeAsNeeded(); | |
149 } | |
150 | 159 |
151 /** Purges all resources that don't have external owners. */ | 160 /** Purges all resources that don't have external owners. */ |
152 void purgeAllUnlocked(); | 161 void purgeAllUnlocked(); |
153 | 162 |
154 /** | 163 /** |
155 * The callback function used by the cache when it is still over budget afte
r a purge. The | 164 * The callback function used by the cache when it is still over budget afte
r a purge. The |
156 * passed in 'data' is the same 'data' handed to setOverbudgetCallback. | 165 * passed in 'data' is the same 'data' handed to setOverbudgetCallback. |
157 */ | 166 */ |
158 typedef void (*PFOverBudgetCB)(void* data); | 167 typedef void (*PFOverBudgetCB)(void* data); |
159 | 168 |
160 /** | 169 /** |
161 * Set the callback the cache should use when it is still over budget after
a purge. The 'data' | 170 * Set the callback the cache should use when it is still over budget after
a purge. The 'data' |
162 * provided here will be passed back to the callback. Note that the cache wi
ll attempt to purge | 171 * provided here will be passed back to the callback. Note that the cache wi
ll attempt to purge |
163 * any resources newly freed by the callback. | 172 * any resources newly freed by the callback. |
164 */ | 173 */ |
165 void setOverBudgetCallback(PFOverBudgetCB overBudgetCB, void* data) { | 174 void setOverBudgetCallback(PFOverBudgetCB overBudgetCB, void* data) { |
166 fOverBudgetCB = overBudgetCB; | 175 fOverBudgetCB = overBudgetCB; |
167 fOverBudgetData = data; | 176 fOverBudgetData = data; |
168 } | 177 } |
| 178 |
| 179 void notifyFlushOccurred(); |
169 | 180 |
170 #if GR_GPU_STATS | 181 #if GR_GPU_STATS |
171 void dumpStats(SkString*) const; | 182 void dumpStats(SkString*) const; |
172 #endif | 183 #endif |
173 | 184 |
174 // This function is for unit testing and is only defined in test tools. | 185 // This function is for unit testing and is only defined in test tools. |
175 void changeTimestamp(uint32_t newTimestamp); | 186 void changeTimestamp(uint32_t newTimestamp); |
176 | 187 |
177 private: | 188 private: |
178 /////////////////////////////////////////////////////////////////////////// | 189 /////////////////////////////////////////////////////////////////////////// |
179 /// @name Methods accessible via ResourceAccess | 190 /// @name Methods accessible via ResourceAccess |
180 //// | 191 //// |
181 void insertResource(GrGpuResource*); | 192 void insertResource(GrGpuResource*); |
182 void removeResource(GrGpuResource*); | 193 void removeResource(GrGpuResource*); |
183 void notifyPurgeable(GrGpuResource*); | 194 void notifyCntReachedZero(GrGpuResource*, uint32_t flags); |
184 void didChangeGpuMemorySize(const GrGpuResource*, size_t oldSize); | 195 void didChangeGpuMemorySize(const GrGpuResource*, size_t oldSize); |
185 void changeUniqueKey(GrGpuResource*, const GrUniqueKey&); | 196 void changeUniqueKey(GrGpuResource*, const GrUniqueKey&); |
186 void removeUniqueKey(GrGpuResource*); | 197 void removeUniqueKey(GrGpuResource*); |
187 void willRemoveScratchKey(const GrGpuResource*); | 198 void willRemoveScratchKey(const GrGpuResource*); |
188 void didChangeBudgetStatus(GrGpuResource*); | 199 void didChangeBudgetStatus(GrGpuResource*); |
189 void refAndMakeResourceMRU(GrGpuResource*); | 200 void refAndMakeResourceMRU(GrGpuResource*); |
190 /// @} | 201 /// @} |
191 | 202 |
192 void internalPurgeAsNeeded(); | 203 void resetFlushTimestamps(); |
193 void processInvalidUniqueKeys(const SkTArray<GrUniqueKeyInvalidatedMessage>&
); | 204 void processInvalidUniqueKeys(const SkTArray<GrUniqueKeyInvalidatedMessage>&
); |
194 void addToNonpurgeableArray(GrGpuResource*); | 205 void addToNonpurgeableArray(GrGpuResource*); |
195 void removeFromNonpurgeableArray(GrGpuResource*); | 206 void removeFromNonpurgeableArray(GrGpuResource*); |
196 bool overBudget() const { return fBudgetedBytes > fMaxBytes || fBudgetedCoun
t > fMaxCount; } | 207 bool overBudget() const { return fBudgetedBytes > fMaxBytes || fBudgetedCoun
t > fMaxCount; } |
197 | 208 |
198 uint32_t getNextTimestamp(); | 209 uint32_t getNextTimestamp(); |
199 | 210 |
200 #ifdef SK_DEBUG | 211 #ifdef SK_DEBUG |
201 bool isInCache(const GrGpuResource* r) const; | 212 bool isInCache(const GrGpuResource* r) const; |
202 void validate() const; | 213 void validate() const; |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
244 ResourceArray fNonpurgeableResources; | 255 ResourceArray fNonpurgeableResources; |
245 | 256 |
246 // This map holds all resources that can be used as scratch resources. | 257 // This map holds all resources that can be used as scratch resources. |
247 ScratchMap fScratchMap; | 258 ScratchMap fScratchMap; |
248 // This holds all resources that have unique keys. | 259 // This holds all resources that have unique keys. |
249 UniqueHash fUniqueHash; | 260 UniqueHash fUniqueHash; |
250 | 261 |
251 // our budget, used in purgeAsNeeded() | 262 // our budget, used in purgeAsNeeded() |
252 int fMaxCount; | 263 int fMaxCount; |
253 size_t fMaxBytes; | 264 size_t fMaxBytes; |
| 265 int fMaxUnusedFlushes; |
254 | 266 |
255 #if GR_CACHE_STATS | 267 #if GR_CACHE_STATS |
256 int fHighWaterCount; | 268 int fHighWaterCount; |
257 size_t fHighWaterBytes; | 269 size_t fHighWaterBytes; |
258 int fBudgetedHighWaterCount; | 270 int fBudgetedHighWaterCount; |
259 size_t fBudgetedHighWaterBytes; | 271 size_t fBudgetedHighWaterBytes; |
260 #endif | 272 #endif |
261 | 273 |
262 // our current stats for all resources | 274 // our current stats for all resources |
263 SkDEBUGCODE(int fCount;) | 275 SkDEBUGCODE(int fCount;) |
264 size_t fBytes; | 276 size_t fBytes; |
265 | 277 |
266 // our current stats for resources that count against the budget | 278 // our current stats for resources that count against the budget |
267 int fBudgetedCount; | 279 int fBudgetedCount; |
268 size_t fBudgetedBytes; | 280 size_t fBudgetedBytes; |
269 | 281 |
270 PFOverBudgetCB fOverBudgetCB; | 282 PFOverBudgetCB fOverBudgetCB; |
271 void* fOverBudgetData; | 283 void* fOverBudgetData; |
272 | 284 |
| 285 // We keep track of the "timestamps" of the last n flushes. If a resource ha
sn't been used in |
| 286 // that time then we well preemptively purge it to reduce memory usage. |
| 287 uint32_t* fFlushTimestamps; |
| 288 int fLastFlushTimestampIndex; |
| 289 |
273 InvalidUniqueKeyInbox fInvalidUniqueKeyInbox; | 290 InvalidUniqueKeyInbox fInvalidUniqueKeyInbox; |
| 291 |
| 292 // This resource is allowed to be in the nonpurgeable array for the sake of
validate() because |
| 293 // we're in the midst of converting it to purgeable status. |
| 294 SkDEBUGCODE(GrGpuResource* fNewlyPurgeableResourceForValidation;) |
274 }; | 295 }; |
275 | 296 |
276 class GrResourceCache::ResourceAccess { | 297 class GrResourceCache::ResourceAccess { |
277 private: | 298 private: |
278 ResourceAccess(GrResourceCache* cache) : fCache(cache) { } | 299 ResourceAccess(GrResourceCache* cache) : fCache(cache) { } |
279 ResourceAccess(const ResourceAccess& that) : fCache(that.fCache) { } | 300 ResourceAccess(const ResourceAccess& that) : fCache(that.fCache) { } |
280 ResourceAccess& operator=(const ResourceAccess&); // unimpl | 301 ResourceAccess& operator=(const ResourceAccess&); // unimpl |
281 | 302 |
282 /** | 303 /** |
283 * Insert a resource into the cache. | 304 * Insert a resource into the cache. |
284 */ | 305 */ |
285 void insertResource(GrGpuResource* resource) { fCache->insertResource(resour
ce); } | 306 void insertResource(GrGpuResource* resource) { fCache->insertResource(resour
ce); } |
286 | 307 |
287 /** | 308 /** |
288 * Removes a resource from the cache. | 309 * Removes a resource from the cache. |
289 */ | 310 */ |
290 void removeResource(GrGpuResource* resource) { fCache->removeResource(resour
ce); } | 311 void removeResource(GrGpuResource* resource) { fCache->removeResource(resour
ce); } |
291 | 312 |
292 /** | 313 /** |
293 * Called by GrGpuResources when they detects that they are newly purgeable. | 314 * Notifications that should be sent to the cache when the ref/io cnt status
of resources |
| 315 * changes. |
294 */ | 316 */ |
295 void notifyPurgeable(GrGpuResource* resource) { fCache->notifyPurgeable(reso
urce); } | 317 enum RefNotificationFlags { |
| 318 /** All types of refs on the resource have reached zero. */ |
| 319 kAllCntsReachedZero_RefNotificationFlag = 0x1, |
| 320 /** The normal (not pending IO type) ref cnt has reached zero. */ |
| 321 kRefCntReachedZero_RefNotificationFlag = 0x2, |
| 322 }; |
| 323 /** |
| 324 * Called by GrGpuResources when they detect that their ref/io cnts have rea
ched zero. When the |
| 325 * normal ref cnt reaches zero the flags that are set should be: |
| 326 * a) kRefCntReachedZero if a pending IO cnt is still non-zero. |
| 327 * b) (kRefCntReachedZero | kAllCntsReachedZero) when all pending IO cnt
s are also zero. |
| 328 * kAllCntsReachedZero is set by itself if a pending IO cnt is decremented t
o zero and all the |
| 329 * the other cnts are already zero. |
| 330 */ |
| 331 void notifyCntReachedZero(GrGpuResource* resource, uint32_t flags) { |
| 332 fCache->notifyCntReachedZero(resource, flags); |
| 333 } |
296 | 334 |
297 /** | 335 /** |
298 * Called by GrGpuResources when their sizes change. | 336 * Called by GrGpuResources when their sizes change. |
299 */ | 337 */ |
300 void didChangeGpuMemorySize(const GrGpuResource* resource, size_t oldSize) { | 338 void didChangeGpuMemorySize(const GrGpuResource* resource, size_t oldSize) { |
301 fCache->didChangeGpuMemorySize(resource, oldSize); | 339 fCache->didChangeGpuMemorySize(resource, oldSize); |
302 } | 340 } |
303 | 341 |
304 /** | 342 /** |
305 * Called by GrGpuResources to change their unique keys. | 343 * Called by GrGpuResources to change their unique keys. |
(...skipping 27 matching lines...) Expand all Loading... |
333 | 371 |
334 friend class GrGpuResource; // To access all the proxy inline methods. | 372 friend class GrGpuResource; // To access all the proxy inline methods. |
335 friend class GrResourceCache; // To create this type. | 373 friend class GrResourceCache; // To create this type. |
336 }; | 374 }; |
337 | 375 |
338 inline GrResourceCache::ResourceAccess GrResourceCache::resourceAccess() { | 376 inline GrResourceCache::ResourceAccess GrResourceCache::resourceAccess() { |
339 return ResourceAccess(this); | 377 return ResourceAccess(this); |
340 } | 378 } |
341 | 379 |
342 #endif | 380 #endif |
OLD | NEW |