| 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 |