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::didChangeGpuMemorySize() const { |
| 19 if (this->isInCache()) { |
| 20 fCacheEntry->didChangeResourceSize(); |
| 21 } |
| 22 } |
| 23 |
| 24 /////////////////////////////////////////////////////////////////////////////// |
| 25 |
16 GrResourceKey::ResourceType GrResourceKey::GenerateResourceType() { | 26 GrResourceKey::ResourceType GrResourceKey::GenerateResourceType() { |
17 static int32_t gNextType = 0; | 27 static int32_t gNextType = 0; |
18 | 28 |
19 int32_t type = sk_atomic_inc(&gNextType); | 29 int32_t type = sk_atomic_inc(&gNextType); |
20 if (type >= (1 << 8 * sizeof(ResourceType))) { | 30 if (type >= (1 << 8 * sizeof(ResourceType))) { |
21 SkFAIL("Too many Resource Types"); | 31 SkFAIL("Too many Resource Types"); |
22 } | 32 } |
23 | 33 |
24 return static_cast<ResourceType>(type); | 34 return static_cast<ResourceType>(type); |
25 } | 35 } |
26 | 36 |
27 /////////////////////////////////////////////////////////////////////////////// | 37 /////////////////////////////////////////////////////////////////////////////// |
28 | 38 |
29 GrResourceCacheEntry::GrResourceCacheEntry(const GrResourceKey& key, GrCacheable
* resource) | 39 GrResourceCacheEntry::GrResourceCacheEntry(GrResourceCache* resourceCache, |
30 : fKey(key), fResource(resource) { | 40 const GrResourceKey& key, |
| 41 GrCacheable* resource) |
| 42 : fResourceCache(resourceCache), |
| 43 fKey(key), |
| 44 fResource(resource), |
| 45 fCachedSize(resource->gpuMemorySize()), |
| 46 fIsExclusive(false) { |
31 // we assume ownership of the resource, and will unref it when we die | 47 // we assume ownership of the resource, and will unref it when we die |
32 SkASSERT(resource); | 48 SkASSERT(resource); |
33 resource->ref(); | 49 resource->ref(); |
34 } | 50 } |
35 | 51 |
36 GrResourceCacheEntry::~GrResourceCacheEntry() { | 52 GrResourceCacheEntry::~GrResourceCacheEntry() { |
37 fResource->setCacheEntry(NULL); | 53 fResource->setCacheEntry(NULL); |
38 fResource->unref(); | 54 fResource->unref(); |
39 } | 55 } |
40 | 56 |
41 #ifdef SK_DEBUG | 57 #ifdef SK_DEBUG |
42 void GrResourceCacheEntry::validate() const { | 58 void GrResourceCacheEntry::validate() const { |
| 59 SkASSERT(fResourceCache); |
43 SkASSERT(fResource); | 60 SkASSERT(fResource); |
44 SkASSERT(fResource->getCacheEntry() == this); | 61 SkASSERT(fResource->getCacheEntry() == this); |
| 62 SkASSERT(fResource->gpuMemorySize() == fCachedSize); |
45 fResource->validate(); | 63 fResource->validate(); |
46 } | 64 } |
47 #endif | 65 #endif |
48 | 66 |
| 67 void GrResourceCacheEntry::didChangeResourceSize() { |
| 68 size_t oldSize = fCachedSize; |
| 69 fCachedSize = fResource->gpuMemorySize(); |
| 70 if (fCachedSize > oldSize) { |
| 71 fResourceCache->didIncreaseResourceSize(this, fCachedSize - oldSize); |
| 72 } else if (fCachedSize < oldSize) { |
| 73 fResourceCache->didDecreaseResourceSize(this, oldSize - fCachedSize); |
| 74 } |
| 75 } |
| 76 |
49 /////////////////////////////////////////////////////////////////////////////// | 77 /////////////////////////////////////////////////////////////////////////////// |
50 | 78 |
51 GrResourceCache::GrResourceCache(int maxCount, size_t maxBytes) : | 79 GrResourceCache::GrResourceCache(int maxCount, size_t maxBytes) : |
52 fMaxCount(maxCount), | 80 fMaxCount(maxCount), |
53 fMaxBytes(maxBytes) { | 81 fMaxBytes(maxBytes) { |
54 #if GR_CACHE_STATS | 82 #if GR_CACHE_STATS |
55 fHighWaterEntryCount = 0; | 83 fHighWaterEntryCount = 0; |
56 fHighWaterEntryBytes = 0; | 84 fHighWaterEntryBytes = 0; |
57 fHighWaterClientDetachedCount = 0; | 85 fHighWaterClientDetachedCount = 0; |
58 fHighWaterClientDetachedBytes = 0; | 86 fHighWaterClientDetachedBytes = 0; |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
108 } | 136 } |
109 } | 137 } |
110 | 138 |
111 void GrResourceCache::internalDetach(GrResourceCacheEntry* entry, | 139 void GrResourceCache::internalDetach(GrResourceCacheEntry* entry, |
112 BudgetBehaviors behavior) { | 140 BudgetBehaviors behavior) { |
113 fList.remove(entry); | 141 fList.remove(entry); |
114 | 142 |
115 // update our stats | 143 // update our stats |
116 if (kIgnore_BudgetBehavior == behavior) { | 144 if (kIgnore_BudgetBehavior == behavior) { |
117 fClientDetachedCount += 1; | 145 fClientDetachedCount += 1; |
118 fClientDetachedBytes += entry->resource()->gpuMemorySize(); | 146 fClientDetachedBytes += entry->fCachedSize; |
119 | 147 |
120 #if GR_CACHE_STATS | 148 #if GR_CACHE_STATS |
121 if (fHighWaterClientDetachedCount < fClientDetachedCount) { | 149 if (fHighWaterClientDetachedCount < fClientDetachedCount) { |
122 fHighWaterClientDetachedCount = fClientDetachedCount; | 150 fHighWaterClientDetachedCount = fClientDetachedCount; |
123 } | 151 } |
124 if (fHighWaterClientDetachedBytes < fClientDetachedBytes) { | 152 if (fHighWaterClientDetachedBytes < fClientDetachedBytes) { |
125 fHighWaterClientDetachedBytes = fClientDetachedBytes; | 153 fHighWaterClientDetachedBytes = fClientDetachedBytes; |
126 } | 154 } |
127 #endif | 155 #endif |
128 | 156 |
129 } else { | 157 } else { |
130 SkASSERT(kAccountFor_BudgetBehavior == behavior); | 158 SkASSERT(kAccountFor_BudgetBehavior == behavior); |
131 | 159 |
132 fEntryCount -= 1; | 160 fEntryCount -= 1; |
133 fEntryBytes -= entry->resource()->gpuMemorySize(); | 161 fEntryBytes -= entry->fCachedSize; |
134 } | 162 } |
135 } | 163 } |
136 | 164 |
137 void GrResourceCache::attachToHead(GrResourceCacheEntry* entry, | 165 void GrResourceCache::attachToHead(GrResourceCacheEntry* entry, |
138 BudgetBehaviors behavior) { | 166 BudgetBehaviors behavior) { |
139 fList.addToHead(entry); | 167 fList.addToHead(entry); |
140 | 168 |
141 // update our stats | 169 // update our stats |
142 if (kIgnore_BudgetBehavior == behavior) { | 170 if (kIgnore_BudgetBehavior == behavior) { |
143 fClientDetachedCount -= 1; | 171 fClientDetachedCount -= 1; |
144 fClientDetachedBytes -= entry->resource()->gpuMemorySize(); | 172 fClientDetachedBytes -= entry->fCachedSize; |
145 } else { | 173 } else { |
146 SkASSERT(kAccountFor_BudgetBehavior == behavior); | 174 SkASSERT(kAccountFor_BudgetBehavior == behavior); |
147 | 175 |
148 fEntryCount += 1; | 176 fEntryCount += 1; |
149 fEntryBytes += entry->resource()->gpuMemorySize(); | 177 fEntryBytes += entry->fCachedSize; |
150 | 178 |
151 #if GR_CACHE_STATS | 179 #if GR_CACHE_STATS |
152 if (fHighWaterEntryCount < fEntryCount) { | 180 if (fHighWaterEntryCount < fEntryCount) { |
153 fHighWaterEntryCount = fEntryCount; | 181 fHighWaterEntryCount = fEntryCount; |
154 } | 182 } |
155 if (fHighWaterEntryBytes < fEntryBytes) { | 183 if (fHighWaterEntryBytes < fEntryBytes) { |
156 fHighWaterEntryBytes = fEntryBytes; | 184 fHighWaterEntryBytes = fEntryBytes; |
157 } | 185 } |
158 #endif | 186 #endif |
159 } | 187 } |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
201 GrCacheable* resource, | 229 GrCacheable* resource, |
202 uint32_t ownershipFlags) { | 230 uint32_t ownershipFlags) { |
203 SkASSERT(NULL == resource->getCacheEntry()); | 231 SkASSERT(NULL == resource->getCacheEntry()); |
204 // we don't expect to create new resources during a purge. In theory | 232 // we don't expect to create new resources during a purge. In theory |
205 // this could cause purgeAsNeeded() into an infinite loop (e.g. | 233 // this could cause purgeAsNeeded() into an infinite loop (e.g. |
206 // each resource destroyed creates and locks 2 resources and | 234 // each resource destroyed creates and locks 2 resources and |
207 // unlocks 1 thereby causing a new purge). | 235 // unlocks 1 thereby causing a new purge). |
208 SkASSERT(!fPurging); | 236 SkASSERT(!fPurging); |
209 GrAutoResourceCacheValidate atcv(this); | 237 GrAutoResourceCacheValidate atcv(this); |
210 | 238 |
211 GrResourceCacheEntry* entry = SkNEW_ARGS(GrResourceCacheEntry, (key, resourc
e)); | 239 GrResourceCacheEntry* entry = SkNEW_ARGS(GrResourceCacheEntry, (this, key, r
esource)); |
212 resource->setCacheEntry(entry); | 240 resource->setCacheEntry(entry); |
213 | 241 |
214 this->attachToHead(entry); | 242 this->attachToHead(entry); |
215 fCache.insert(key, entry); | 243 fCache.insert(key, entry); |
216 | 244 |
217 if (ownershipFlags & kHide_OwnershipFlag) { | 245 if (ownershipFlags & kHide_OwnershipFlag) { |
218 this->makeExclusive(entry); | 246 this->makeExclusive(entry); |
219 } | 247 } |
220 | 248 |
221 } | 249 } |
222 | 250 |
223 void GrResourceCache::makeExclusive(GrResourceCacheEntry* entry) { | 251 void GrResourceCache::makeExclusive(GrResourceCacheEntry* entry) { |
224 GrAutoResourceCacheValidate atcv(this); | 252 GrAutoResourceCacheValidate atcv(this); |
225 | 253 |
| 254 SkASSERT(!entry->fIsExclusive); |
| 255 entry->fIsExclusive = true; |
| 256 |
226 // When scratch textures are detached (to hide them from future finds) they | 257 // When scratch textures are detached (to hide them from future finds) they |
227 // still count against the resource budget | 258 // still count against the resource budget |
228 this->internalDetach(entry, kIgnore_BudgetBehavior); | 259 this->internalDetach(entry, kIgnore_BudgetBehavior); |
229 fCache.remove(entry->key(), entry); | 260 fCache.remove(entry->key(), entry); |
230 | 261 |
231 #ifdef SK_DEBUG | 262 #ifdef SK_DEBUG |
232 fExclusiveList.addToHead(entry); | 263 fExclusiveList.addToHead(entry); |
233 #endif | 264 #endif |
234 } | 265 } |
235 | 266 |
236 void GrResourceCache::removeInvalidResource(GrResourceCacheEntry* entry) { | 267 void GrResourceCache::removeInvalidResource(GrResourceCacheEntry* entry) { |
237 // If the resource went invalid while it was detached then purge it | 268 // If the resource went invalid while it was detached then purge it |
238 // This can happen when a 3D context was lost, | 269 // This can happen when a 3D context was lost, |
239 // the client called GrContext::contextDestroyed() to notify Gr, | 270 // the client called GrContext::contextDestroyed() to notify Gr, |
240 // and then later an SkGpuDevice's destructor releases its backing | 271 // and then later an SkGpuDevice's destructor releases its backing |
241 // texture (which was invalidated at contextDestroyed time). | 272 // texture (which was invalidated at contextDestroyed time). |
| 273 // TODO: Safely delete the GrResourceCacheEntry as well. |
242 fClientDetachedCount -= 1; | 274 fClientDetachedCount -= 1; |
243 fEntryCount -= 1; | 275 fEntryCount -= 1; |
244 size_t size = entry->resource()->gpuMemorySize(); | 276 fClientDetachedBytes -= entry->fCachedSize; |
245 fClientDetachedBytes -= size; | 277 fEntryBytes -= entry->fCachedSize; |
246 fEntryBytes -= size; | 278 entry->fCachedSize = 0; |
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::didIncreaseResourceSize(const GrResourceCacheEntry* entry,
size_t amountInc) { |
| 303 fEntryBytes += amountInc; |
| 304 if (entry->fIsExclusive) { |
| 305 fClientDetachedBytes += amountInc; |
| 306 } |
| 307 this->purgeAsNeeded(); |
| 308 } |
| 309 |
| 310 void GrResourceCache::didDecreaseResourceSize(const GrResourceCacheEntry* entry,
size_t amountDec) { |
| 311 fEntryBytes -= amountDec; |
| 312 if (entry->fIsExclusive) { |
| 313 fClientDetachedBytes -= amountDec; |
| 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 |