OLD | NEW |
---|---|
1 | 1 |
2 /* | 2 /* |
3 * Copyright 2010 Google Inc. | 3 * Copyright 2010 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 | 9 |
10 | 10 |
11 #include "GrResourceCache.h" | 11 #include "GrResourceCache.h" |
12 #include "GrCacheable.h" | 12 #include "GrCacheable.h" |
13 | 13 |
14 DECLARE_SKMESSAGEBUS_MESSAGE(GrResourceInvalidatedMessage); | 14 DECLARE_SKMESSAGEBUS_MESSAGE(GrResourceInvalidatedMessage); |
15 | 15 |
16 /////////////////////////////////////////////////////////////////////////////// | |
17 | |
18 void GrCacheable::onResourceSizeChanged() const { | |
19 if (this->isInCache()) | |
20 fCacheEntry->onResourceSizeChanged(); | |
bsalomon
2014/04/28 21:08:33
{ }
Chris Dalton
2014/04/28 22:30:58
Done.
| |
21 } | |
22 | |
23 /////////////////////////////////////////////////////////////////////////////// | |
24 | |
16 GrResourceKey::ResourceType GrResourceKey::GenerateResourceType() { | 25 GrResourceKey::ResourceType GrResourceKey::GenerateResourceType() { |
17 static int32_t gNextType = 0; | 26 static int32_t gNextType = 0; |
18 | 27 |
19 int32_t type = sk_atomic_inc(&gNextType); | 28 int32_t type = sk_atomic_inc(&gNextType); |
20 if (type >= (1 << 8 * sizeof(ResourceType))) { | 29 if (type >= (1 << 8 * sizeof(ResourceType))) { |
21 GrCrash("Too many Resource Types"); | 30 GrCrash("Too many Resource Types"); |
22 } | 31 } |
23 | 32 |
24 return static_cast<ResourceType>(type); | 33 return static_cast<ResourceType>(type); |
25 } | 34 } |
26 | 35 |
27 /////////////////////////////////////////////////////////////////////////////// | 36 /////////////////////////////////////////////////////////////////////////////// |
28 | 37 |
29 GrResourceCacheEntry::GrResourceCacheEntry(const GrResourceKey& key, GrCacheable * resource) | 38 GrResourceCacheEntry::GrResourceCacheEntry(GrResourceCache* resourceCache, |
30 : fKey(key), fResource(resource) { | 39 const GrResourceKey& key, |
40 GrCacheable* resource) | |
41 : fResourceCache(resourceCache), | |
42 fKey(key), | |
43 fResource(resource), | |
44 fCachedSize(resource->gpuMemorySize()), | |
45 fIsExclusive(false) { | |
31 // we assume ownership of the resource, and will unref it when we die | 46 // we assume ownership of the resource, and will unref it when we die |
32 SkASSERT(resource); | 47 SkASSERT(resource); |
33 resource->ref(); | 48 resource->ref(); |
34 } | 49 } |
35 | 50 |
36 GrResourceCacheEntry::~GrResourceCacheEntry() { | 51 GrResourceCacheEntry::~GrResourceCacheEntry() { |
37 fResource->setCacheEntry(NULL); | 52 fResource->setCacheEntry(NULL); |
38 fResource->unref(); | 53 fResource->unref(); |
39 } | 54 } |
40 | 55 |
41 #ifdef SK_DEBUG | 56 #ifdef SK_DEBUG |
42 void GrResourceCacheEntry::validate() const { | 57 void GrResourceCacheEntry::validate() const { |
58 SkASSERT(fResourceCache); | |
43 SkASSERT(fResource); | 59 SkASSERT(fResource); |
44 SkASSERT(fResource->getCacheEntry() == this); | 60 SkASSERT(fResource->getCacheEntry() == this); |
61 SkASSERT(fResource->gpuMemorySize() == fCachedSize); | |
45 fResource->validate(); | 62 fResource->validate(); |
46 } | 63 } |
47 #endif | 64 #endif |
48 | 65 |
66 void GrResourceCacheEntry::onResourceSizeChanged() { | |
67 size_t oldSize = fCachedSize; | |
68 fCachedSize = fResource->gpuMemorySize(); | |
69 if (fCachedSize > oldSize) { | |
70 fResourceCache->onResourceSizeIncreased(this, fCachedSize - oldSize); | |
71 } else if (fCachedSize < oldSize) { | |
72 fResourceCache->onResourceSizeDecreased(this, oldSize - fCachedSize); | |
73 } | |
74 } | |
75 | |
49 /////////////////////////////////////////////////////////////////////////////// | 76 /////////////////////////////////////////////////////////////////////////////// |
50 | 77 |
51 GrResourceCache::GrResourceCache(int maxCount, size_t maxBytes) : | 78 GrResourceCache::GrResourceCache(int maxCount, size_t maxBytes) : |
52 fMaxCount(maxCount), | 79 fMaxCount(maxCount), |
53 fMaxBytes(maxBytes) { | 80 fMaxBytes(maxBytes) { |
54 #if GR_CACHE_STATS | 81 #if GR_CACHE_STATS |
55 fHighWaterEntryCount = 0; | 82 fHighWaterEntryCount = 0; |
56 fHighWaterEntryBytes = 0; | 83 fHighWaterEntryBytes = 0; |
57 fHighWaterClientDetachedCount = 0; | 84 fHighWaterClientDetachedCount = 0; |
58 fHighWaterClientDetachedBytes = 0; | 85 fHighWaterClientDetachedBytes = 0; |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
108 } | 135 } |
109 } | 136 } |
110 | 137 |
111 void GrResourceCache::internalDetach(GrResourceCacheEntry* entry, | 138 void GrResourceCache::internalDetach(GrResourceCacheEntry* entry, |
112 BudgetBehaviors behavior) { | 139 BudgetBehaviors behavior) { |
113 fList.remove(entry); | 140 fList.remove(entry); |
114 | 141 |
115 // update our stats | 142 // update our stats |
116 if (kIgnore_BudgetBehavior == behavior) { | 143 if (kIgnore_BudgetBehavior == behavior) { |
117 fClientDetachedCount += 1; | 144 fClientDetachedCount += 1; |
118 fClientDetachedBytes += entry->resource()->gpuMemorySize(); | 145 fClientDetachedBytes += entry->fCachedSize; |
119 | 146 |
120 #if GR_CACHE_STATS | 147 #if GR_CACHE_STATS |
121 if (fHighWaterClientDetachedCount < fClientDetachedCount) { | 148 if (fHighWaterClientDetachedCount < fClientDetachedCount) { |
122 fHighWaterClientDetachedCount = fClientDetachedCount; | 149 fHighWaterClientDetachedCount = fClientDetachedCount; |
123 } | 150 } |
124 if (fHighWaterClientDetachedBytes < fClientDetachedBytes) { | 151 if (fHighWaterClientDetachedBytes < fClientDetachedBytes) { |
125 fHighWaterClientDetachedBytes = fClientDetachedBytes; | 152 fHighWaterClientDetachedBytes = fClientDetachedBytes; |
126 } | 153 } |
127 #endif | 154 #endif |
128 | 155 |
129 } else { | 156 } else { |
130 SkASSERT(kAccountFor_BudgetBehavior == behavior); | 157 SkASSERT(kAccountFor_BudgetBehavior == behavior); |
131 | 158 |
132 fEntryCount -= 1; | 159 fEntryCount -= 1; |
133 fEntryBytes -= entry->resource()->gpuMemorySize(); | 160 fEntryBytes -= entry->fCachedSize; |
134 } | 161 } |
135 } | 162 } |
136 | 163 |
137 void GrResourceCache::attachToHead(GrResourceCacheEntry* entry, | 164 void GrResourceCache::attachToHead(GrResourceCacheEntry* entry, |
138 BudgetBehaviors behavior) { | 165 BudgetBehaviors behavior) { |
139 fList.addToHead(entry); | 166 fList.addToHead(entry); |
140 | 167 |
141 // update our stats | 168 // update our stats |
142 if (kIgnore_BudgetBehavior == behavior) { | 169 if (kIgnore_BudgetBehavior == behavior) { |
143 fClientDetachedCount -= 1; | 170 fClientDetachedCount -= 1; |
144 fClientDetachedBytes -= entry->resource()->gpuMemorySize(); | 171 fClientDetachedBytes -= entry->fCachedSize; |
145 } else { | 172 } else { |
146 SkASSERT(kAccountFor_BudgetBehavior == behavior); | 173 SkASSERT(kAccountFor_BudgetBehavior == behavior); |
147 | 174 |
148 fEntryCount += 1; | 175 fEntryCount += 1; |
149 fEntryBytes += entry->resource()->gpuMemorySize(); | 176 fEntryBytes += entry->fCachedSize; |
150 | 177 |
151 #if GR_CACHE_STATS | 178 #if GR_CACHE_STATS |
152 if (fHighWaterEntryCount < fEntryCount) { | 179 if (fHighWaterEntryCount < fEntryCount) { |
153 fHighWaterEntryCount = fEntryCount; | 180 fHighWaterEntryCount = fEntryCount; |
154 } | 181 } |
155 if (fHighWaterEntryBytes < fEntryBytes) { | 182 if (fHighWaterEntryBytes < fEntryBytes) { |
156 fHighWaterEntryBytes = fEntryBytes; | 183 fHighWaterEntryBytes = fEntryBytes; |
157 } | 184 } |
158 #endif | 185 #endif |
159 } | 186 } |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
201 GrCacheable* resource, | 228 GrCacheable* resource, |
202 uint32_t ownershipFlags) { | 229 uint32_t ownershipFlags) { |
203 SkASSERT(NULL == resource->getCacheEntry()); | 230 SkASSERT(NULL == resource->getCacheEntry()); |
204 // we don't expect to create new resources during a purge. In theory | 231 // we don't expect to create new resources during a purge. In theory |
205 // this could cause purgeAsNeeded() into an infinite loop (e.g. | 232 // this could cause purgeAsNeeded() into an infinite loop (e.g. |
206 // each resource destroyed creates and locks 2 resources and | 233 // each resource destroyed creates and locks 2 resources and |
207 // unlocks 1 thereby causing a new purge). | 234 // unlocks 1 thereby causing a new purge). |
208 SkASSERT(!fPurging); | 235 SkASSERT(!fPurging); |
209 GrAutoResourceCacheValidate atcv(this); | 236 GrAutoResourceCacheValidate atcv(this); |
210 | 237 |
211 GrResourceCacheEntry* entry = SkNEW_ARGS(GrResourceCacheEntry, (key, resourc e)); | 238 GrResourceCacheEntry* entry = SkNEW_ARGS(GrResourceCacheEntry, (this, key, r esource)); |
212 resource->setCacheEntry(entry); | 239 resource->setCacheEntry(entry); |
213 | 240 |
214 this->attachToHead(entry); | 241 this->attachToHead(entry); |
215 fCache.insert(key, entry); | 242 fCache.insert(key, entry); |
216 | 243 |
217 if (ownershipFlags & kHide_OwnershipFlag) { | 244 if (ownershipFlags & kHide_OwnershipFlag) { |
218 this->makeExclusive(entry); | 245 this->makeExclusive(entry); |
219 } | 246 } |
220 | 247 |
221 } | 248 } |
222 | 249 |
223 void GrResourceCache::makeExclusive(GrResourceCacheEntry* entry) { | 250 void GrResourceCache::makeExclusive(GrResourceCacheEntry* entry) { |
224 GrAutoResourceCacheValidate atcv(this); | 251 GrAutoResourceCacheValidate atcv(this); |
225 | 252 |
253 SkASSERT(!entry->fIsExclusive); | |
254 entry->fIsExclusive = true; | |
255 | |
226 // When scratch textures are detached (to hide them from future finds) they | 256 // When scratch textures are detached (to hide them from future finds) they |
227 // still count against the resource budget | 257 // still count against the resource budget |
228 this->internalDetach(entry, kIgnore_BudgetBehavior); | 258 this->internalDetach(entry, kIgnore_BudgetBehavior); |
229 fCache.remove(entry->key(), entry); | 259 fCache.remove(entry->key(), entry); |
230 | 260 |
231 #ifdef SK_DEBUG | 261 #ifdef SK_DEBUG |
232 fExclusiveList.addToHead(entry); | 262 fExclusiveList.addToHead(entry); |
233 #endif | 263 #endif |
234 } | 264 } |
235 | 265 |
236 void GrResourceCache::removeInvalidResource(GrResourceCacheEntry* entry) { | 266 void GrResourceCache::removeInvalidResource(GrResourceCacheEntry* entry) { |
237 // If the resource went invalid while it was detached then purge it | 267 // If the resource went invalid while it was detached then purge it |
238 // This can happen when a 3D context was lost, | 268 // This can happen when a 3D context was lost, |
239 // the client called GrContext::contextDestroyed() to notify Gr, | 269 // the client called GrContext::contextDestroyed() to notify Gr, |
240 // and then later an SkGpuDevice's destructor releases its backing | 270 // and then later an SkGpuDevice's destructor releases its backing |
241 // texture (which was invalidated at contextDestroyed time). | 271 // texture (which was invalidated at contextDestroyed time). |
242 fClientDetachedCount -= 1; | 272 fClientDetachedCount -= 1; |
243 fEntryCount -= 1; | 273 fEntryCount -= 1; |
244 size_t size = entry->resource()->gpuMemorySize(); | 274 size_t size = entry->fCachedSize; |
275 entry->fResource->setCacheEntry(NULL); | |
276 delete entry; | |
245 fClientDetachedBytes -= size; | 277 fClientDetachedBytes -= size; |
246 fEntryBytes -= size; | 278 fEntryBytes -= size; |
247 } | 279 } |
248 | 280 |
249 void GrResourceCache::makeNonExclusive(GrResourceCacheEntry* entry) { | 281 void GrResourceCache::makeNonExclusive(GrResourceCacheEntry* entry) { |
250 GrAutoResourceCacheValidate atcv(this); | 282 GrAutoResourceCacheValidate atcv(this); |
251 | 283 |
252 #ifdef SK_DEBUG | 284 #ifdef SK_DEBUG |
253 fExclusiveList.remove(entry); | 285 fExclusiveList.remove(entry); |
254 #endif | 286 #endif |
255 | 287 |
256 if (entry->resource()->isValidOnGpu()) { | 288 if (entry->resource()->isValidOnGpu()) { |
257 // Since scratch textures still count against the cache budget even | 289 // Since scratch textures still count against the cache budget even |
258 // when they have been removed from the cache, re-adding them doesn't | 290 // when they have been removed from the cache, re-adding them doesn't |
259 // alter the budget information. | 291 // alter the budget information. |
260 attachToHead(entry, kIgnore_BudgetBehavior); | 292 attachToHead(entry, kIgnore_BudgetBehavior); |
261 fCache.insert(entry->key(), entry); | 293 fCache.insert(entry->key(), entry); |
294 | |
295 SkASSERT(entry->fIsExclusive); | |
296 entry->fIsExclusive = false; | |
262 } else { | 297 } else { |
263 this->removeInvalidResource(entry); | 298 this->removeInvalidResource(entry); |
264 } | 299 } |
265 } | 300 } |
266 | 301 |
302 void GrResourceCache::onResourceSizeIncreased(const GrResourceCacheEntry* entry, size_t amount) { | |
303 fEntryBytes += amount; | |
304 if (entry->fIsExclusive) { | |
305 fClientDetachedBytes += amount; | |
306 } | |
307 this->purgeAsNeeded(); | |
308 } | |
309 | |
310 void GrResourceCache::onResourceSizeDecreased(const GrResourceCacheEntry* entry, size_t amount) { | |
311 fEntryBytes -= amount; | |
312 if (entry->fIsExclusive) { | |
313 fClientDetachedBytes -= amount; | |
314 } | |
315 #ifdef SK_DEBUG | |
316 this->validate(); | |
317 #endif | |
318 } | |
319 | |
267 /** | 320 /** |
268 * Destroying a resource may potentially trigger the unlock of additional | 321 * Destroying a resource may potentially trigger the unlock of additional |
269 * resources which in turn will trigger a nested purge. We block the nested | 322 * resources which in turn will trigger a nested purge. We block the nested |
270 * purge using the fPurging variable. However, the initial purge will keep | 323 * purge using the fPurging variable. However, the initial purge will keep |
271 * looping until either all resources in the cache are unlocked or we've met | 324 * looping until either all resources in the cache are unlocked or we've met |
272 * the budget. There is an assertion in createAndLock to check against a | 325 * the budget. There is an assertion in createAndLock to check against a |
273 * resource's destructor inserting new resources into the cache. If these | 326 * resource's destructor inserting new resources into the cache. If these |
274 * new resources were unlocked before purgeAsNeeded completed it could | 327 * new resources were unlocked before purgeAsNeeded completed it could |
275 * potentially make purgeAsNeeded loop infinitely. | 328 * potentially make purgeAsNeeded loop infinitely. |
276 * | 329 * |
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
483 fEntryBytes, fHighWaterEntryBytes); | 536 fEntryBytes, fHighWaterEntryBytes); |
484 SkDebugf("\t\tDetached Entry Count: current %d high %d\n", | 537 SkDebugf("\t\tDetached Entry Count: current %d high %d\n", |
485 fClientDetachedCount, fHighWaterClientDetachedCount); | 538 fClientDetachedCount, fHighWaterClientDetachedCount); |
486 SkDebugf("\t\tDetached Bytes: current %d high %d\n", | 539 SkDebugf("\t\tDetached Bytes: current %d high %d\n", |
487 fClientDetachedBytes, fHighWaterClientDetachedBytes); | 540 fClientDetachedBytes, fHighWaterClientDetachedBytes); |
488 } | 541 } |
489 | 542 |
490 #endif | 543 #endif |
491 | 544 |
492 /////////////////////////////////////////////////////////////////////////////// | 545 /////////////////////////////////////////////////////////////////////////////// |
OLD | NEW |