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 "GrResourceCache2.h" | 10 #include "GrResourceCache2.h" |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
65 , fHighWaterCount(0) | 65 , fHighWaterCount(0) |
66 , fHighWaterBytes(0) | 66 , fHighWaterBytes(0) |
67 , fBudgetedHighWaterCount(0) | 67 , fBudgetedHighWaterCount(0) |
68 , fBudgetedHighWaterBytes(0) | 68 , fBudgetedHighWaterBytes(0) |
69 #endif | 69 #endif |
70 , fCount(0) | 70 , fCount(0) |
71 , fBytes(0) | 71 , fBytes(0) |
72 , fBudgetedCount(0) | 72 , fBudgetedCount(0) |
73 , fBudgetedBytes(0) | 73 , fBudgetedBytes(0) |
74 , fPurging(false) | 74 , fPurging(false) |
75 , fNewlyPurgableResourceWhilePurging(false) | 75 , fNewlyPurgeableResourceWhilePurging(false) |
76 , fOverBudgetCB(NULL) | 76 , fOverBudgetCB(NULL) |
77 , fOverBudgetData(NULL) { | 77 , fOverBudgetData(NULL) { |
78 } | 78 } |
79 | 79 |
80 GrResourceCache2::~GrResourceCache2() { | 80 GrResourceCache2::~GrResourceCache2() { |
81 this->releaseAll(); | 81 this->releaseAll(); |
82 } | 82 } |
83 | 83 |
84 void GrResourceCache2::setLimits(int count, size_t bytes) { | 84 void GrResourceCache2::setLimits(int count, size_t bytes) { |
85 fMaxCount = count; | 85 fMaxCount = count; |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
238 } | 238 } |
239 | 239 |
240 void GrResourceCache2::makeResourceMRU(GrGpuResource* resource) { | 240 void GrResourceCache2::makeResourceMRU(GrGpuResource* resource) { |
241 SkASSERT(!fPurging); | 241 SkASSERT(!fPurging); |
242 SkASSERT(resource); | 242 SkASSERT(resource); |
243 SkASSERT(this->isInCache(resource)); | 243 SkASSERT(this->isInCache(resource)); |
244 fResources.remove(resource); | 244 fResources.remove(resource); |
245 fResources.addToHead(resource); | 245 fResources.addToHead(resource); |
246 } | 246 } |
247 | 247 |
248 void GrResourceCache2::notifyPurgable(GrGpuResource* resource) { | 248 void GrResourceCache2::notifyPurgeable(GrGpuResource* resource) { |
249 SkASSERT(resource); | 249 SkASSERT(resource); |
250 SkASSERT(this->isInCache(resource)); | 250 SkASSERT(this->isInCache(resource)); |
251 SkASSERT(resource->isPurgable()); | 251 SkASSERT(resource->isPurgeable()); |
252 | 252 |
253 // We can't purge if in the middle of purging because purge is iterating. In
stead record | 253 // We can't purge if in the middle of purging because purge is iterating. In
stead record |
254 // that additional resources became purgable. | 254 // that additional resources became purgeable. |
255 if (fPurging) { | 255 if (fPurging) { |
256 fNewlyPurgableResourceWhilePurging = true; | 256 fNewlyPurgeableResourceWhilePurging = true; |
257 return; | 257 return; |
258 } | 258 } |
259 | 259 |
260 bool release = false; | 260 bool release = false; |
261 | 261 |
262 if (resource->cacheAccess().isWrapped()) { | 262 if (resource->cacheAccess().isWrapped()) { |
263 release = true; | 263 release = true; |
264 } else if (!resource->cacheAccess().isBudgeted()) { | 264 } else if (!resource->cacheAccess().isBudgeted()) { |
265 // Check whether this resource could still be used as a scratch resource
. | 265 // Check whether this resource could still be used as a scratch resource
. |
266 if (resource->cacheAccess().getScratchKey().isValid()) { | 266 if (resource->cacheAccess().getScratchKey().isValid()) { |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
336 } else { | 336 } else { |
337 --fBudgetedCount; | 337 --fBudgetedCount; |
338 fBudgetedBytes -= size; | 338 fBudgetedBytes -= size; |
339 } | 339 } |
340 | 340 |
341 this->validate(); | 341 this->validate(); |
342 } | 342 } |
343 | 343 |
344 void GrResourceCache2::internalPurgeAsNeeded() { | 344 void GrResourceCache2::internalPurgeAsNeeded() { |
345 SkASSERT(!fPurging); | 345 SkASSERT(!fPurging); |
346 SkASSERT(!fNewlyPurgableResourceWhilePurging); | 346 SkASSERT(!fNewlyPurgeableResourceWhilePurging); |
347 SkASSERT(fBudgetedCount > fMaxCount || fBudgetedBytes > fMaxBytes); | 347 SkASSERT(fBudgetedCount > fMaxCount || fBudgetedBytes > fMaxBytes); |
348 | 348 |
349 fPurging = true; | 349 fPurging = true; |
350 | 350 |
351 bool overBudget = true; | 351 bool overBudget = true; |
352 do { | 352 do { |
353 fNewlyPurgableResourceWhilePurging = false; | 353 fNewlyPurgeableResourceWhilePurging = false; |
354 ResourceList::Iter resourceIter; | 354 ResourceList::Iter resourceIter; |
355 GrGpuResource* resource = resourceIter.init(fResources, | 355 GrGpuResource* resource = resourceIter.init(fResources, |
356 ResourceList::Iter::kTail_It
erStart); | 356 ResourceList::Iter::kTail_It
erStart); |
357 | 357 |
358 while (resource) { | 358 while (resource) { |
359 GrGpuResource* prev = resourceIter.prev(); | 359 GrGpuResource* prev = resourceIter.prev(); |
360 if (resource->isPurgable()) { | 360 if (resource->isPurgeable()) { |
361 resource->cacheAccess().release(); | 361 resource->cacheAccess().release(); |
362 } | 362 } |
363 resource = prev; | 363 resource = prev; |
364 if (fBudgetedCount <= fMaxCount && fBudgetedBytes <= fMaxBytes) { | 364 if (fBudgetedCount <= fMaxCount && fBudgetedBytes <= fMaxBytes) { |
365 overBudget = false; | 365 overBudget = false; |
366 resource = NULL; | 366 resource = NULL; |
367 } | 367 } |
368 } | 368 } |
369 | 369 |
370 if (!fNewlyPurgableResourceWhilePurging && overBudget && fOverBudgetCB)
{ | 370 if (!fNewlyPurgeableResourceWhilePurging && overBudget && fOverBudgetCB)
{ |
371 // Despite the purge we're still over budget. Call our over budget c
allback. | 371 // Despite the purge we're still over budget. Call our over budget c
allback. |
372 (*fOverBudgetCB)(fOverBudgetData); | 372 (*fOverBudgetCB)(fOverBudgetData); |
373 } | 373 } |
374 } while (overBudget && fNewlyPurgableResourceWhilePurging); | 374 } while (overBudget && fNewlyPurgeableResourceWhilePurging); |
375 | 375 |
376 fNewlyPurgableResourceWhilePurging = false; | 376 fNewlyPurgeableResourceWhilePurging = false; |
377 fPurging = false; | 377 fPurging = false; |
378 this->validate(); | 378 this->validate(); |
379 } | 379 } |
380 | 380 |
381 void GrResourceCache2::purgeAllUnlocked() { | 381 void GrResourceCache2::purgeAllUnlocked() { |
382 SkASSERT(!fPurging); | 382 SkASSERT(!fPurging); |
383 SkASSERT(!fNewlyPurgableResourceWhilePurging); | 383 SkASSERT(!fNewlyPurgeableResourceWhilePurging); |
384 | 384 |
385 fPurging = true; | 385 fPurging = true; |
386 | 386 |
387 do { | 387 do { |
388 fNewlyPurgableResourceWhilePurging = false; | 388 fNewlyPurgeableResourceWhilePurging = false; |
389 ResourceList::Iter resourceIter; | 389 ResourceList::Iter resourceIter; |
390 GrGpuResource* resource = | 390 GrGpuResource* resource = |
391 resourceIter.init(fResources, ResourceList::Iter::kTail_IterStart); | 391 resourceIter.init(fResources, ResourceList::Iter::kTail_IterStart); |
392 | 392 |
393 while (resource) { | 393 while (resource) { |
394 GrGpuResource* prev = resourceIter.prev(); | 394 GrGpuResource* prev = resourceIter.prev(); |
395 if (resource->isPurgable()) { | 395 if (resource->isPurgeable()) { |
396 resource->cacheAccess().release(); | 396 resource->cacheAccess().release(); |
397 } | 397 } |
398 resource = prev; | 398 resource = prev; |
399 } | 399 } |
400 | 400 |
401 if (!fNewlyPurgableResourceWhilePurging && fCount && fOverBudgetCB) { | 401 if (!fNewlyPurgeableResourceWhilePurging && fCount && fOverBudgetCB) { |
402 (*fOverBudgetCB)(fOverBudgetData); | 402 (*fOverBudgetCB)(fOverBudgetData); |
403 } | 403 } |
404 } while (fNewlyPurgableResourceWhilePurging); | 404 } while (fNewlyPurgeableResourceWhilePurging); |
405 fPurging = false; | 405 fPurging = false; |
406 this->validate(); | 406 this->validate(); |
407 } | 407 } |
408 | 408 |
409 #ifdef SK_DEBUG | 409 #ifdef SK_DEBUG |
410 void GrResourceCache2::validate() const { | 410 void GrResourceCache2::validate() const { |
411 // Reduce the frequency of validations for large resource counts. | 411 // Reduce the frequency of validations for large resource counts. |
412 static SkRandom gRandom; | 412 static SkRandom gRandom; |
413 int mask = (SkNextPow2(fCount + 1) >> 5) - 1; | 413 int mask = (SkNextPow2(fCount + 1) >> 5) - 1; |
414 if (~mask && (gRandom.nextU() & mask)) { | 414 if (~mask && (gRandom.nextU() & mask)) { |
415 return; | 415 return; |
416 } | 416 } |
417 | 417 |
418 size_t bytes = 0; | 418 size_t bytes = 0; |
419 int count = 0; | 419 int count = 0; |
420 int budgetedCount = 0; | 420 int budgetedCount = 0; |
421 size_t budgetedBytes = 0; | 421 size_t budgetedBytes = 0; |
422 int locked = 0; | 422 int locked = 0; |
423 int scratch = 0; | 423 int scratch = 0; |
424 int couldBeScratch = 0; | 424 int couldBeScratch = 0; |
425 int content = 0; | 425 int content = 0; |
426 | 426 |
427 ResourceList::Iter iter; | 427 ResourceList::Iter iter; |
428 GrGpuResource* resource = iter.init(fResources, ResourceList::Iter::kHead_It
erStart); | 428 GrGpuResource* resource = iter.init(fResources, ResourceList::Iter::kHead_It
erStart); |
429 for ( ; resource; resource = iter.next()) { | 429 for ( ; resource; resource = iter.next()) { |
430 bytes += resource->gpuMemorySize(); | 430 bytes += resource->gpuMemorySize(); |
431 ++count; | 431 ++count; |
432 | 432 |
433 if (!resource->isPurgable()) { | 433 if (!resource->isPurgeable()) { |
434 ++locked; | 434 ++locked; |
435 } | 435 } |
436 | 436 |
437 if (resource->cacheAccess().isScratch()) { | 437 if (resource->cacheAccess().isScratch()) { |
438 SkASSERT(!resource->cacheAccess().getContentKey().isValid()); | 438 SkASSERT(!resource->cacheAccess().getContentKey().isValid()); |
439 ++scratch; | 439 ++scratch; |
440 SkASSERT(fScratchMap.countForKey(resource->cacheAccess().getScratchK
ey())); | 440 SkASSERT(fScratchMap.countForKey(resource->cacheAccess().getScratchK
ey())); |
441 SkASSERT(!resource->cacheAccess().isWrapped()); | 441 SkASSERT(!resource->cacheAccess().isWrapped()); |
442 } else if (resource->cacheAccess().getScratchKey().isValid()) { | 442 } else if (resource->cacheAccess().getScratchKey().isValid()) { |
443 SkASSERT(!resource->cacheAccess().isBudgeted() || | 443 SkASSERT(!resource->cacheAccess().isBudgeted() || |
(...skipping 26 matching lines...) Expand all Loading... |
470 SkASSERT(fBudgetedHighWaterCount <= fHighWaterCount); | 470 SkASSERT(fBudgetedHighWaterCount <= fHighWaterCount); |
471 SkASSERT(fBudgetedHighWaterBytes <= fHighWaterBytes); | 471 SkASSERT(fBudgetedHighWaterBytes <= fHighWaterBytes); |
472 SkASSERT(bytes <= fHighWaterBytes); | 472 SkASSERT(bytes <= fHighWaterBytes); |
473 SkASSERT(count <= fHighWaterCount); | 473 SkASSERT(count <= fHighWaterCount); |
474 SkASSERT(budgetedBytes <= fBudgetedHighWaterBytes); | 474 SkASSERT(budgetedBytes <= fBudgetedHighWaterBytes); |
475 SkASSERT(budgetedCount <= fBudgetedHighWaterCount); | 475 SkASSERT(budgetedCount <= fBudgetedHighWaterCount); |
476 #endif | 476 #endif |
477 SkASSERT(content == fContentHash.count()); | 477 SkASSERT(content == fContentHash.count()); |
478 SkASSERT(scratch + couldBeScratch == fScratchMap.count()); | 478 SkASSERT(scratch + couldBeScratch == fScratchMap.count()); |
479 | 479 |
480 // This assertion is not currently valid because we can be in recursive noti
fyIsPurgable() | 480 // This assertion is not currently valid because we can be in recursive noti
fyIsPurgeable() |
481 // calls. This will be fixed when subresource registration is explicit. | 481 // calls. This will be fixed when subresource registration is explicit. |
482 // bool overBudget = budgetedBytes > fMaxBytes || budgetedCount > fMaxCount; | 482 // bool overBudget = budgetedBytes > fMaxBytes || budgetedCount > fMaxCount; |
483 // SkASSERT(!overBudget || locked == count || fPurging); | 483 // SkASSERT(!overBudget || locked == count || fPurging); |
484 } | 484 } |
485 #endif | 485 #endif |
486 | 486 |
487 #if GR_CACHE_STATS | 487 #if GR_CACHE_STATS |
488 void GrResourceCache2::printStats() const { | 488 void GrResourceCache2::printStats() const { |
489 this->validate(); | 489 this->validate(); |
490 | 490 |
491 int locked = 0; | 491 int locked = 0; |
492 int scratch = 0; | 492 int scratch = 0; |
493 int wrapped = 0; | 493 int wrapped = 0; |
494 size_t unbudgetedSize = 0; | 494 size_t unbudgetedSize = 0; |
495 | 495 |
496 ResourceList::Iter iter; | 496 ResourceList::Iter iter; |
497 GrGpuResource* resource = iter.init(fResources, ResourceList::Iter::kHead_It
erStart); | 497 GrGpuResource* resource = iter.init(fResources, ResourceList::Iter::kHead_It
erStart); |
498 | 498 |
499 for ( ; resource; resource = iter.next()) { | 499 for ( ; resource; resource = iter.next()) { |
500 if (!resource->isPurgable()) { | 500 if (!resource->isPurgeable()) { |
501 ++locked; | 501 ++locked; |
502 } | 502 } |
503 if (resource->cacheAccess().isScratch()) { | 503 if (resource->cacheAccess().isScratch()) { |
504 ++scratch; | 504 ++scratch; |
505 } | 505 } |
506 if (resource->cacheAccess().isWrapped()) { | 506 if (resource->cacheAccess().isWrapped()) { |
507 ++wrapped; | 507 ++wrapped; |
508 } | 508 } |
509 if (!resource->cacheAccess().isBudgeted()) { | 509 if (!resource->cacheAccess().isBudgeted()) { |
510 unbudgetedSize += resource->gpuMemorySize(); | 510 unbudgetedSize += resource->gpuMemorySize(); |
511 } | 511 } |
512 } | 512 } |
513 | 513 |
514 float countUtilization = (100.f * fBudgetedCount) / fMaxCount; | 514 float countUtilization = (100.f * fBudgetedCount) / fMaxCount; |
515 float byteUtilization = (100.f * fBudgetedBytes) / fMaxBytes; | 515 float byteUtilization = (100.f * fBudgetedBytes) / fMaxBytes; |
516 | 516 |
517 SkDebugf("Budget: %d items %d bytes\n", fMaxCount, fMaxBytes); | 517 SkDebugf("Budget: %d items %d bytes\n", fMaxCount, fMaxBytes); |
518 SkDebugf("\t\tEntry Count: current %d" | 518 SkDebugf("\t\tEntry Count: current %d" |
519 " (%d budgeted, %d wrapped, %d locked, %d scratch %.2g%% full), hig
h %d\n", | 519 " (%d budgeted, %d wrapped, %d locked, %d scratch %.2g%% full), hig
h %d\n", |
520 fCount, fBudgetedCount, wrapped, locked, scratch, countUtilization, fHig
hWaterCount); | 520 fCount, fBudgetedCount, wrapped, locked, scratch, countUtilization, fHig
hWaterCount); |
521 SkDebugf("\t\tEntry Bytes: current %d (budgeted %d, %.2g%% full, %d unbudget
ed) high %d\n", | 521 SkDebugf("\t\tEntry Bytes: current %d (budgeted %d, %.2g%% full, %d unbudget
ed) high %d\n", |
522 fBytes, fBudgetedBytes, byteUtilization, unbudgetedSize, fHighWa
terBytes); | 522 fBytes, fBudgetedBytes, byteUtilization, unbudgetedSize, fHighWa
terBytes); |
523 } | 523 } |
524 | 524 |
525 #endif | 525 #endif |
OLD | NEW |