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 | 9 |
10 #include "GrResourceCache.h" | 10 #include "GrResourceCache.h" |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
51 private: | 51 private: |
52 GrResourceCache* fCache; | 52 GrResourceCache* fCache; |
53 }; | 53 }; |
54 | 54 |
55 ////////////////////////////////////////////////////////////////////////////// | 55 ////////////////////////////////////////////////////////////////////////////// |
56 | 56 |
57 static const int kDefaultMaxCount = 2 * (1 << 10); | 57 static const int kDefaultMaxCount = 2 * (1 << 10); |
58 static const size_t kDefaultMaxSize = 96 * (1 << 20); | 58 static const size_t kDefaultMaxSize = 96 * (1 << 20); |
59 | 59 |
60 GrResourceCache::GrResourceCache() | 60 GrResourceCache::GrResourceCache() |
61 : fMaxCount(kDefaultMaxCount) | 61 : fTimestamp(0) |
| 62 , fMaxCount(kDefaultMaxCount) |
62 , fMaxBytes(kDefaultMaxSize) | 63 , fMaxBytes(kDefaultMaxSize) |
63 #if GR_CACHE_STATS | 64 #if GR_CACHE_STATS |
64 , fHighWaterCount(0) | 65 , fHighWaterCount(0) |
65 , fHighWaterBytes(0) | 66 , fHighWaterBytes(0) |
66 , fBudgetedHighWaterCount(0) | 67 , fBudgetedHighWaterCount(0) |
67 , fBudgetedHighWaterBytes(0) | 68 , fBudgetedHighWaterBytes(0) |
68 #endif | 69 #endif |
69 , fCount(0) | 70 , fCount(0) |
70 , fBytes(0) | 71 , fBytes(0) |
71 , fBudgetedCount(0) | 72 , fBudgetedCount(0) |
72 , fBudgetedBytes(0) | 73 , fBudgetedBytes(0) |
73 , fPurging(false) | |
74 , fNewlyPurgeableResourceWhilePurging(false) | |
75 , fOverBudgetCB(NULL) | 74 , fOverBudgetCB(NULL) |
76 , fOverBudgetData(NULL) { | 75 , fOverBudgetData(NULL) { |
77 } | 76 } |
78 | 77 |
79 GrResourceCache::~GrResourceCache() { | 78 GrResourceCache::~GrResourceCache() { |
80 this->releaseAll(); | 79 this->releaseAll(); |
81 } | 80 } |
82 | 81 |
83 void GrResourceCache::setLimits(int count, size_t bytes) { | 82 void GrResourceCache::setLimits(int count, size_t bytes) { |
84 fMaxCount = count; | 83 fMaxCount = count; |
85 fMaxBytes = bytes; | 84 fMaxBytes = bytes; |
86 this->purgeAsNeeded(); | 85 this->purgeAsNeeded(); |
87 } | 86 } |
88 | 87 |
89 void GrResourceCache::insertResource(GrGpuResource* resource) { | 88 void GrResourceCache::insertResource(GrGpuResource* resource) { |
90 SkASSERT(resource); | 89 SkASSERT(resource); |
91 SkASSERT(!resource->wasDestroyed()); | 90 SkASSERT(!resource->wasDestroyed()); |
92 SkASSERT(!this->isInCache(resource)); | 91 SkASSERT(!this->isInCache(resource)); |
93 SkASSERT(!fPurging); | |
94 fResources.addToHead(resource); | 92 fResources.addToHead(resource); |
95 | 93 |
96 size_t size = resource->gpuMemorySize(); | 94 size_t size = resource->gpuMemorySize(); |
97 ++fCount; | 95 ++fCount; |
98 fBytes += size; | 96 fBytes += size; |
99 #if GR_CACHE_STATS | 97 #if GR_CACHE_STATS |
100 fHighWaterCount = SkTMax(fCount, fHighWaterCount); | 98 fHighWaterCount = SkTMax(fCount, fHighWaterCount); |
101 fHighWaterBytes = SkTMax(fBytes, fHighWaterBytes); | 99 fHighWaterBytes = SkTMax(fBytes, fHighWaterBytes); |
102 #endif | 100 #endif |
103 if (resource->resourcePriv().isBudgeted()) { | 101 if (resource->resourcePriv().isBudgeted()) { |
104 ++fBudgetedCount; | 102 ++fBudgetedCount; |
105 fBudgetedBytes += size; | 103 fBudgetedBytes += size; |
106 #if GR_CACHE_STATS | 104 #if GR_CACHE_STATS |
107 fBudgetedHighWaterCount = SkTMax(fBudgetedCount, fBudgetedHighWaterCount
); | 105 fBudgetedHighWaterCount = SkTMax(fBudgetedCount, fBudgetedHighWaterCount
); |
108 fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes
); | 106 fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes
); |
109 #endif | 107 #endif |
110 } | 108 } |
111 if (resource->resourcePriv().getScratchKey().isValid()) { | 109 if (resource->resourcePriv().getScratchKey().isValid()) { |
112 SkASSERT(!resource->cacheAccess().isWrapped()); | 110 SkASSERT(!resource->cacheAccess().isWrapped()); |
113 fScratchMap.insert(resource->resourcePriv().getScratchKey(), resource); | 111 fScratchMap.insert(resource->resourcePriv().getScratchKey(), resource); |
114 } | 112 } |
115 | 113 |
| 114 resource->cacheAccess().setTimestamp(fTimestamp++); |
| 115 |
116 this->purgeAsNeeded(); | 116 this->purgeAsNeeded(); |
117 } | 117 } |
118 | 118 |
119 void GrResourceCache::removeResource(GrGpuResource* resource) { | 119 void GrResourceCache::removeResource(GrGpuResource* resource) { |
| 120 this->validate(); |
120 SkASSERT(this->isInCache(resource)); | 121 SkASSERT(this->isInCache(resource)); |
121 | 122 |
| 123 if (resource->isPurgeable()) { |
| 124 fPurgeableQueue.remove(resource); |
| 125 } |
| 126 |
122 size_t size = resource->gpuMemorySize(); | 127 size_t size = resource->gpuMemorySize(); |
123 --fCount; | 128 --fCount; |
124 fBytes -= size; | 129 fBytes -= size; |
125 if (resource->resourcePriv().isBudgeted()) { | 130 if (resource->resourcePriv().isBudgeted()) { |
126 --fBudgetedCount; | 131 --fBudgetedCount; |
127 fBudgetedBytes -= size; | 132 fBudgetedBytes -= size; |
128 } | 133 } |
129 | 134 |
130 fResources.remove(resource); | 135 fResources.remove(resource); |
131 if (resource->resourcePriv().getScratchKey().isValid()) { | 136 if (resource->resourcePriv().getScratchKey().isValid()) { |
132 fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource); | 137 fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource); |
133 } | 138 } |
134 if (resource->getContentKey().isValid()) { | 139 if (resource->getContentKey().isValid()) { |
135 fContentHash.remove(resource->getContentKey()); | 140 fContentHash.remove(resource->getContentKey()); |
136 } | 141 } |
137 this->validate(); | 142 this->validate(); |
138 } | 143 } |
139 | 144 |
140 void GrResourceCache::abandonAll() { | 145 void GrResourceCache::abandonAll() { |
141 AutoValidate av(this); | 146 AutoValidate av(this); |
142 | 147 |
143 SkASSERT(!fPurging); | |
144 while (GrGpuResource* head = fResources.head()) { | 148 while (GrGpuResource* head = fResources.head()) { |
145 SkASSERT(!head->wasDestroyed()); | 149 SkASSERT(!head->wasDestroyed()); |
146 head->cacheAccess().abandon(); | 150 head->cacheAccess().abandon(); |
147 // abandon should have already removed this from the list. | 151 // abandon should have already removed this from the list. |
148 SkASSERT(head != fResources.head()); | 152 SkASSERT(head != fResources.head()); |
149 } | 153 } |
150 SkASSERT(!fScratchMap.count()); | 154 SkASSERT(!fScratchMap.count()); |
151 SkASSERT(!fContentHash.count()); | 155 SkASSERT(!fContentHash.count()); |
152 SkASSERT(!fCount); | 156 SkASSERT(!fCount); |
153 SkASSERT(!fBytes); | 157 SkASSERT(!fBytes); |
154 SkASSERT(!fBudgetedCount); | 158 SkASSERT(!fBudgetedCount); |
155 SkASSERT(!fBudgetedBytes); | 159 SkASSERT(!fBudgetedBytes); |
156 } | 160 } |
157 | 161 |
158 void GrResourceCache::releaseAll() { | 162 void GrResourceCache::releaseAll() { |
159 AutoValidate av(this); | 163 AutoValidate av(this); |
160 | 164 |
161 SkASSERT(!fPurging); | |
162 while (GrGpuResource* head = fResources.head()) { | 165 while (GrGpuResource* head = fResources.head()) { |
163 SkASSERT(!head->wasDestroyed()); | 166 SkASSERT(!head->wasDestroyed()); |
164 head->cacheAccess().release(); | 167 head->cacheAccess().release(); |
165 // release should have already removed this from the list. | 168 // release should have already removed this from the list. |
166 SkASSERT(head != fResources.head()); | 169 SkASSERT(head != fResources.head()); |
167 } | 170 } |
168 SkASSERT(!fScratchMap.count()); | 171 SkASSERT(!fScratchMap.count()); |
169 SkASSERT(!fCount); | 172 SkASSERT(!fCount); |
170 SkASSERT(!fBytes); | 173 SkASSERT(!fBytes); |
171 SkASSERT(!fBudgetedCount); | 174 SkASSERT(!fBudgetedCount); |
172 SkASSERT(!fBudgetedBytes); | 175 SkASSERT(!fBudgetedBytes); |
173 } | 176 } |
174 | 177 |
175 class GrResourceCache::AvailableForScratchUse { | 178 class GrResourceCache::AvailableForScratchUse { |
176 public: | 179 public: |
177 AvailableForScratchUse(bool rejectPendingIO) : fRejectPendingIO(rejectPendin
gIO) { } | 180 AvailableForScratchUse(bool rejectPendingIO) : fRejectPendingIO(rejectPendin
gIO) { } |
178 | 181 |
179 bool operator()(const GrGpuResource* resource) const { | 182 bool operator()(const GrGpuResource* resource) const { |
180 if (resource->internalHasRef() || !resource->cacheAccess().isScratch())
{ | 183 if (resource->internalHasRef() || !resource->cacheAccess().isScratch())
{ |
181 return false; | 184 return false; |
182 } | 185 } |
183 return !fRejectPendingIO || !resource->internalHasPendingIO(); | 186 return !fRejectPendingIO || !resource->internalHasPendingIO(); |
184 } | 187 } |
185 | 188 |
186 private: | 189 private: |
187 bool fRejectPendingIO; | 190 bool fRejectPendingIO; |
188 }; | 191 }; |
189 | 192 |
190 GrGpuResource* GrResourceCache::findAndRefScratchResource(const GrScratchKey& sc
ratchKey, | 193 GrGpuResource* GrResourceCache::findAndRefScratchResource(const GrScratchKey& sc
ratchKey, |
191 uint32_t flags) { | 194 uint32_t flags) { |
192 SkASSERT(!fPurging); | |
193 SkASSERT(scratchKey.isValid()); | 195 SkASSERT(scratchKey.isValid()); |
194 | 196 |
195 GrGpuResource* resource; | 197 GrGpuResource* resource; |
196 if (flags & (kPreferNoPendingIO_ScratchFlag | kRequireNoPendingIO_ScratchFla
g)) { | 198 if (flags & (kPreferNoPendingIO_ScratchFlag | kRequireNoPendingIO_ScratchFla
g)) { |
197 resource = fScratchMap.find(scratchKey, AvailableForScratchUse(true)); | 199 resource = fScratchMap.find(scratchKey, AvailableForScratchUse(true)); |
198 if (resource) { | 200 if (resource) { |
199 resource->ref(); | 201 this->refAndMakeResourceMRU(resource); |
200 this->makeResourceMRU(resource); | |
201 this->validate(); | 202 this->validate(); |
202 return resource; | 203 return resource; |
203 } else if (flags & kRequireNoPendingIO_ScratchFlag) { | 204 } else if (flags & kRequireNoPendingIO_ScratchFlag) { |
204 return NULL; | 205 return NULL; |
205 } | 206 } |
206 // TODO: fail here when kPrefer is specified, we didn't find a resource
without pending io, | 207 // TODO: fail here when kPrefer is specified, we didn't find a resource
without pending io, |
207 // but there is still space in our budget for the resource. | 208 // but there is still space in our budget for the resource. |
208 } | 209 } |
209 resource = fScratchMap.find(scratchKey, AvailableForScratchUse(false)); | 210 resource = fScratchMap.find(scratchKey, AvailableForScratchUse(false)); |
210 if (resource) { | 211 if (resource) { |
211 resource->ref(); | 212 this->refAndMakeResourceMRU(resource); |
212 this->makeResourceMRU(resource); | |
213 this->validate(); | 213 this->validate(); |
214 } | 214 } |
215 return resource; | 215 return resource; |
216 } | 216 } |
217 | 217 |
218 void GrResourceCache::willRemoveScratchKey(const GrGpuResource* resource) { | 218 void GrResourceCache::willRemoveScratchKey(const GrGpuResource* resource) { |
219 SkASSERT(resource->resourcePriv().getScratchKey().isValid()); | 219 SkASSERT(resource->resourcePriv().getScratchKey().isValid()); |
220 fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource); | 220 fScratchMap.remove(resource->resourcePriv().getScratchKey(), resource); |
221 } | 221 } |
222 | 222 |
223 void GrResourceCache::willRemoveContentKey(const GrGpuResource* resource) { | 223 void GrResourceCache::willRemoveContentKey(const GrGpuResource* resource) { |
224 // Someone has a ref to this resource in order to invalidate it. When the re
f count reaches | 224 // Someone has a ref to this resource in order to invalidate it. When the re
f count reaches |
225 // zero we will get a notifyPurgable() and figure out what to do with it. | 225 // zero we will get a notifyPurgable() and figure out what to do with it. |
226 SkASSERT(resource->getContentKey().isValid()); | 226 SkASSERT(resource->getContentKey().isValid()); |
227 fContentHash.remove(resource->getContentKey()); | 227 fContentHash.remove(resource->getContentKey()); |
228 } | 228 } |
229 | 229 |
230 bool GrResourceCache::didSetContentKey(GrGpuResource* resource) { | 230 bool GrResourceCache::didSetContentKey(GrGpuResource* resource) { |
231 SkASSERT(!fPurging); | |
232 SkASSERT(resource); | 231 SkASSERT(resource); |
233 SkASSERT(this->isInCache(resource)); | 232 SkASSERT(this->isInCache(resource)); |
234 SkASSERT(resource->getContentKey().isValid()); | 233 SkASSERT(resource->getContentKey().isValid()); |
235 | 234 |
236 GrGpuResource* res = fContentHash.find(resource->getContentKey()); | 235 GrGpuResource* res = fContentHash.find(resource->getContentKey()); |
237 if (NULL != res) { | 236 if (NULL != res) { |
238 return false; | 237 return false; |
239 } | 238 } |
240 | 239 |
241 fContentHash.add(resource); | 240 fContentHash.add(resource); |
242 this->validate(); | 241 this->validate(); |
243 return true; | 242 return true; |
244 } | 243 } |
245 | 244 |
246 void GrResourceCache::makeResourceMRU(GrGpuResource* resource) { | 245 void GrResourceCache::refAndMakeResourceMRU(GrGpuResource* resource) { |
247 SkASSERT(!fPurging); | |
248 SkASSERT(resource); | 246 SkASSERT(resource); |
249 SkASSERT(this->isInCache(resource)); | 247 SkASSERT(this->isInCache(resource)); |
250 fResources.remove(resource); | 248 if (resource->isPurgeable()) { |
251 fResources.addToHead(resource); | 249 // It's about to become unpurgeable. |
| 250 fPurgeableQueue.remove(resource); |
| 251 } |
| 252 resource->ref(); |
| 253 resource->cacheAccess().setTimestamp(fTimestamp++); |
| 254 SkASSERT(!resource->isPurgeable()); |
252 } | 255 } |
253 | 256 |
254 void GrResourceCache::notifyPurgeable(GrGpuResource* resource) { | 257 void GrResourceCache::notifyPurgeable(GrGpuResource* resource) { |
255 SkASSERT(resource); | 258 SkASSERT(resource); |
256 SkASSERT(this->isInCache(resource)); | 259 SkASSERT(this->isInCache(resource)); |
257 SkASSERT(resource->isPurgeable()); | 260 SkASSERT(resource->isPurgeable()); |
258 | 261 |
259 // We can't purge if in the middle of purging because purge is iterating. In
stead record | 262 SkASSERT(-1 == *resource->cacheAccess().accessCacheIndex()); |
260 // that additional resources became purgeable. | 263 fPurgeableQueue.insert(resource); |
261 if (fPurging) { | |
262 fNewlyPurgeableResourceWhilePurging = true; | |
263 return; | |
264 } | |
265 | 264 |
266 bool release = false; | 265 if (!resource->resourcePriv().isBudgeted()) { |
267 | |
268 if (resource->cacheAccess().isWrapped()) { | |
269 release = true; | |
270 } else if (!resource->resourcePriv().isBudgeted()) { | |
271 // Check whether this resource could still be used as a scratch resource
. | 266 // Check whether this resource could still be used as a scratch resource
. |
272 if (resource->resourcePriv().getScratchKey().isValid()) { | 267 if (!resource->cacheAccess().isWrapped() && |
| 268 resource->resourcePriv().getScratchKey().isValid()) { |
273 // We won't purge an existing resource to make room for this one. | 269 // We won't purge an existing resource to make room for this one. |
274 bool underBudget = fBudgetedCount < fMaxCount && | 270 bool underBudget = fBudgetedCount < fMaxCount && |
275 fBudgetedBytes + resource->gpuMemorySize() <= fMa
xBytes; | 271 fBudgetedBytes + resource->gpuMemorySize() <= fMa
xBytes; |
276 if (underBudget) { | 272 if (underBudget) { |
277 resource->resourcePriv().makeBudgeted(); | 273 resource->resourcePriv().makeBudgeted(); |
278 } else { | 274 return; |
279 release = true; | |
280 } | 275 } |
281 } else { | |
282 release = true; | |
283 } | 276 } |
284 } else { | 277 } else { |
285 // Purge the resource if we're over budget | 278 // Purge the resource immediately if we're over budget |
286 bool overBudget = fBudgetedCount > fMaxCount || fBudgetedBytes > fMaxByt
es; | 279 bool overBudget = fBudgetedCount > fMaxCount || fBudgetedBytes > fMaxByt
es; |
287 | 280 |
288 // Also purge if the resource has neither a valid scratch key nor a cont
ent key. | 281 // Also purge if the resource has neither a valid scratch key nor a cont
ent key. |
289 bool noKey = !resource->resourcePriv().getScratchKey().isValid() && | 282 bool noKey = !resource->resourcePriv().getScratchKey().isValid() && |
290 !resource->getContentKey().isValid(); | 283 !resource->getContentKey().isValid(); |
291 if (overBudget || noKey) { | 284 if (!overBudget && !noKey) { |
292 release = true; | 285 return; |
293 } | 286 } |
294 } | 287 } |
295 | 288 |
296 if (release) { | 289 SkDEBUGCODE(int beforeCount = fCount;) |
297 SkDEBUGCODE(int beforeCount = fCount;) | 290 resource->cacheAccess().release(); |
298 resource->cacheAccess().release(); | 291 // We should at least free this resource, perhaps dependent resources as wel
l. |
299 // We should at least free this resource, perhaps dependent resources as
well. | 292 SkASSERT(fCount < beforeCount); |
300 SkASSERT(fCount < beforeCount); | |
301 } | |
302 this->validate(); | 293 this->validate(); |
303 } | 294 } |
304 | 295 |
305 void GrResourceCache::didChangeGpuMemorySize(const GrGpuResource* resource, size
_t oldSize) { | 296 void GrResourceCache::didChangeGpuMemorySize(const GrGpuResource* resource, size
_t oldSize) { |
306 // SkASSERT(!fPurging); GrPathRange increases size during flush. :( | 297 // SkASSERT(!fPurging); GrPathRange increases size during flush. :( |
307 SkASSERT(resource); | 298 SkASSERT(resource); |
308 SkASSERT(this->isInCache(resource)); | 299 SkASSERT(this->isInCache(resource)); |
309 | 300 |
310 ptrdiff_t delta = resource->gpuMemorySize() - oldSize; | 301 ptrdiff_t delta = resource->gpuMemorySize() - oldSize; |
311 | 302 |
312 fBytes += delta; | 303 fBytes += delta; |
313 #if GR_CACHE_STATS | 304 #if GR_CACHE_STATS |
314 fHighWaterBytes = SkTMax(fBytes, fHighWaterBytes); | 305 fHighWaterBytes = SkTMax(fBytes, fHighWaterBytes); |
315 #endif | 306 #endif |
316 if (resource->resourcePriv().isBudgeted()) { | 307 if (resource->resourcePriv().isBudgeted()) { |
317 fBudgetedBytes += delta; | 308 fBudgetedBytes += delta; |
318 #if GR_CACHE_STATS | 309 #if GR_CACHE_STATS |
319 fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes
); | 310 fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes
); |
320 #endif | 311 #endif |
321 } | 312 } |
322 | 313 |
323 this->purgeAsNeeded(); | 314 this->purgeAsNeeded(); |
324 this->validate(); | 315 this->validate(); |
325 } | 316 } |
326 | 317 |
327 void GrResourceCache::didChangeBudgetStatus(GrGpuResource* resource) { | 318 void GrResourceCache::didChangeBudgetStatus(GrGpuResource* resource) { |
328 SkASSERT(!fPurging); | |
329 SkASSERT(resource); | 319 SkASSERT(resource); |
330 SkASSERT(this->isInCache(resource)); | 320 SkASSERT(this->isInCache(resource)); |
331 | 321 |
332 size_t size = resource->gpuMemorySize(); | 322 size_t size = resource->gpuMemorySize(); |
333 | 323 |
334 if (resource->resourcePriv().isBudgeted()) { | 324 if (resource->resourcePriv().isBudgeted()) { |
335 ++fBudgetedCount; | 325 ++fBudgetedCount; |
336 fBudgetedBytes += size; | 326 fBudgetedBytes += size; |
337 #if GR_CACHE_STATS | 327 #if GR_CACHE_STATS |
338 fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes
); | 328 fBudgetedHighWaterBytes = SkTMax(fBudgetedBytes, fBudgetedHighWaterBytes
); |
339 fBudgetedHighWaterCount = SkTMax(fBudgetedCount, fBudgetedHighWaterCount
); | 329 fBudgetedHighWaterCount = SkTMax(fBudgetedCount, fBudgetedHighWaterCount
); |
340 #endif | 330 #endif |
341 this->purgeAsNeeded(); | 331 this->purgeAsNeeded(); |
342 } else { | 332 } else { |
343 --fBudgetedCount; | 333 --fBudgetedCount; |
344 fBudgetedBytes -= size; | 334 fBudgetedBytes -= size; |
345 } | 335 } |
346 | 336 |
347 this->validate(); | 337 this->validate(); |
348 } | 338 } |
349 | 339 |
350 void GrResourceCache::internalPurgeAsNeeded() { | 340 void GrResourceCache::internalPurgeAsNeeded() { |
351 SkASSERT(!fPurging); | |
352 SkASSERT(!fNewlyPurgeableResourceWhilePurging); | |
353 SkASSERT(fBudgetedCount > fMaxCount || fBudgetedBytes > fMaxBytes); | 341 SkASSERT(fBudgetedCount > fMaxCount || fBudgetedBytes > fMaxBytes); |
354 | 342 |
355 fPurging = true; | 343 bool stillOverbudget = true; |
| 344 while (fPurgeableQueue.count()) { |
| 345 GrGpuResource* resource = fPurgeableQueue.peek(); |
| 346 SkASSERT(resource->isPurgeable()); |
| 347 resource->cacheAccess().release(); |
| 348 if (fBudgetedCount <= fMaxCount && fBudgetedBytes <= fMaxBytes) { |
| 349 stillOverbudget = false; |
| 350 break; |
| 351 } |
| 352 } |
356 | 353 |
357 bool overBudget = true; | 354 this->validate(); |
358 do { | |
359 fNewlyPurgeableResourceWhilePurging = false; | |
360 ResourceList::Iter resourceIter; | |
361 GrGpuResource* resource = resourceIter.init(fResources, | |
362 ResourceList::Iter::kTail_It
erStart); | |
363 | 355 |
364 while (resource) { | 356 if (stillOverbudget) { |
365 GrGpuResource* prev = resourceIter.prev(); | 357 // Despite the purge we're still over budget. Call our over budget callb
ack. If this frees |
366 if (resource->isPurgeable()) { | 358 // any resources then we'll get notifyPurgeable() calls and take appropr
iate action. |
367 resource->cacheAccess().release(); | 359 (*fOverBudgetCB)(fOverBudgetData); |
368 } | 360 this->validate(); |
369 resource = prev; | 361 } |
370 if (fBudgetedCount <= fMaxCount && fBudgetedBytes <= fMaxBytes) { | 362 } |
371 overBudget = false; | |
372 resource = NULL; | |
373 } | |
374 } | |
375 | 363 |
376 if (!fNewlyPurgeableResourceWhilePurging && overBudget && fOverBudgetCB)
{ | 364 void GrResourceCache::purgeAllUnlocked() { |
377 // Despite the purge we're still over budget. Call our over budget c
allback. | 365 // We could disable maintaining the heap property here, but it would add a l
ot of complexity. |
378 (*fOverBudgetCB)(fOverBudgetData); | 366 // Moreover, this is rarely called. |
379 } | 367 while (fPurgeableQueue.count()) { |
380 } while (overBudget && fNewlyPurgeableResourceWhilePurging); | 368 GrGpuResource* resource = fPurgeableQueue.peek(); |
| 369 SkASSERT(resource->isPurgeable()); |
| 370 resource->cacheAccess().release(); |
| 371 } |
381 | 372 |
382 fNewlyPurgeableResourceWhilePurging = false; | |
383 fPurging = false; | |
384 this->validate(); | 373 this->validate(); |
385 } | 374 } |
386 | 375 |
387 void GrResourceCache::purgeAllUnlocked() { | |
388 SkASSERT(!fPurging); | |
389 SkASSERT(!fNewlyPurgeableResourceWhilePurging); | |
390 | |
391 fPurging = true; | |
392 | |
393 do { | |
394 fNewlyPurgeableResourceWhilePurging = false; | |
395 ResourceList::Iter resourceIter; | |
396 GrGpuResource* resource = | |
397 resourceIter.init(fResources, ResourceList::Iter::kTail_IterStart); | |
398 | |
399 while (resource) { | |
400 GrGpuResource* prev = resourceIter.prev(); | |
401 if (resource->isPurgeable()) { | |
402 resource->cacheAccess().release(); | |
403 } | |
404 resource = prev; | |
405 } | |
406 | |
407 if (!fNewlyPurgeableResourceWhilePurging && fCount && fOverBudgetCB) { | |
408 (*fOverBudgetCB)(fOverBudgetData); | |
409 } | |
410 } while (fNewlyPurgeableResourceWhilePurging); | |
411 fPurging = false; | |
412 this->validate(); | |
413 } | |
414 | |
415 void GrResourceCache::processInvalidContentKeys( | 376 void GrResourceCache::processInvalidContentKeys( |
416 const SkTArray<GrContentKeyInvalidatedMessage>& msgs) { | 377 const SkTArray<GrContentKeyInvalidatedMessage>& msgs) { |
417 for (int i = 0; i < msgs.count(); ++i) { | 378 for (int i = 0; i < msgs.count(); ++i) { |
418 GrGpuResource* resource = this->findAndRefContentResource(msgs[i].key())
; | 379 GrGpuResource* resource = this->findAndRefContentResource(msgs[i].key())
; |
419 if (resource) { | 380 if (resource) { |
420 resource->resourcePriv().removeContentKey(); | 381 resource->resourcePriv().removeContentKey(); |
421 resource->unref(); // will call notifyPurgeable, if it is indeed now
purgeable. | 382 resource->unref(); // will call notifyPurgeable, if it is indeed now
purgeable. |
422 } | 383 } |
423 } | 384 } |
424 } | 385 } |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
468 ++content; | 429 ++content; |
469 SkASSERT(fContentHash.find(contentKey) == resource); | 430 SkASSERT(fContentHash.find(contentKey) == resource); |
470 SkASSERT(!resource->cacheAccess().isWrapped()); | 431 SkASSERT(!resource->cacheAccess().isWrapped()); |
471 SkASSERT(resource->resourcePriv().isBudgeted()); | 432 SkASSERT(resource->resourcePriv().isBudgeted()); |
472 } | 433 } |
473 | 434 |
474 if (resource->resourcePriv().isBudgeted()) { | 435 if (resource->resourcePriv().isBudgeted()) { |
475 ++budgetedCount; | 436 ++budgetedCount; |
476 budgetedBytes += resource->gpuMemorySize(); | 437 budgetedBytes += resource->gpuMemorySize(); |
477 } | 438 } |
| 439 |
| 440 if (!resource->isPurgeable()) { |
| 441 SkASSERT(-1 == *resource->cacheAccess().accessCacheIndex()); |
| 442 } |
478 } | 443 } |
479 | 444 |
| 445 for (int i = 0; i < fPurgeableQueue.count(); ++i) { |
| 446 SkASSERT(fPurgeableQueue.at(i)->isPurgeable()); |
| 447 } |
| 448 |
| 449 SkASSERT(fCount - locked == fPurgeableQueue.count()); |
480 SkASSERT(fBudgetedCount <= fCount); | 450 SkASSERT(fBudgetedCount <= fCount); |
481 SkASSERT(fBudgetedBytes <= fBudgetedBytes); | 451 SkASSERT(fBudgetedBytes <= fBudgetedBytes); |
482 SkASSERT(bytes == fBytes); | 452 SkASSERT(bytes == fBytes); |
483 SkASSERT(count == fCount); | 453 SkASSERT(count == fCount); |
484 SkASSERT(budgetedBytes == fBudgetedBytes); | 454 SkASSERT(budgetedBytes == fBudgetedBytes); |
485 SkASSERT(budgetedCount == fBudgetedCount); | 455 SkASSERT(budgetedCount == fBudgetedCount); |
486 #if GR_CACHE_STATS | 456 #if GR_CACHE_STATS |
487 SkASSERT(fBudgetedHighWaterCount <= fHighWaterCount); | 457 SkASSERT(fBudgetedHighWaterCount <= fHighWaterCount); |
488 SkASSERT(fBudgetedHighWaterBytes <= fHighWaterBytes); | 458 SkASSERT(fBudgetedHighWaterBytes <= fHighWaterBytes); |
489 SkASSERT(bytes <= fHighWaterBytes); | 459 SkASSERT(bytes <= fHighWaterBytes); |
490 SkASSERT(count <= fHighWaterCount); | 460 SkASSERT(count <= fHighWaterCount); |
491 SkASSERT(budgetedBytes <= fBudgetedHighWaterBytes); | 461 SkASSERT(budgetedBytes <= fBudgetedHighWaterBytes); |
492 SkASSERT(budgetedCount <= fBudgetedHighWaterCount); | 462 SkASSERT(budgetedCount <= fBudgetedHighWaterCount); |
493 #endif | 463 #endif |
494 SkASSERT(content == fContentHash.count()); | 464 SkASSERT(content == fContentHash.count()); |
495 SkASSERT(scratch + couldBeScratch == fScratchMap.count()); | 465 SkASSERT(scratch + couldBeScratch == fScratchMap.count()); |
496 | 466 |
497 // This assertion is not currently valid because we can be in recursive noti
fyIsPurgeable() | 467 // This assertion is not currently valid because we can be in recursive noti
fyIsPurgeable() |
498 // calls. This will be fixed when subresource registration is explicit. | 468 // calls. This will be fixed when subresource registration is explicit. |
499 // bool overBudget = budgetedBytes > fMaxBytes || budgetedCount > fMaxCount; | 469 // bool overBudget = budgetedBytes > fMaxBytes || budgetedCount > fMaxCount; |
500 // SkASSERT(!overBudget || locked == count || fPurging); | 470 // SkASSERT(!overBudget || locked == count || fPurging); |
501 } | 471 } |
502 #endif | 472 #endif |
OLD | NEW |