OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2006 The Android Open Source Project | 2 * Copyright 2006 The Android Open Source Project |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkGlyphCache.h" | 8 #include "SkGlyphCache.h" |
9 #include "SkGlyphCache_Globals.h" | 9 #include "SkGlyphCache_Globals.h" |
10 #include "SkGraphics.h" | 10 #include "SkGraphics.h" |
(...skipping 407 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
418 /////////////////////////////////////////////////////////////////////////////// | 418 /////////////////////////////////////////////////////////////////////////////// |
419 | 419 |
420 #include "SkThread.h" | 420 #include "SkThread.h" |
421 | 421 |
422 size_t SkGlyphCache_Globals::setCacheSizeLimit(size_t newLimit) { | 422 size_t SkGlyphCache_Globals::setCacheSizeLimit(size_t newLimit) { |
423 static const size_t minLimit = 256 * 1024; | 423 static const size_t minLimit = 256 * 1024; |
424 if (newLimit < minLimit) { | 424 if (newLimit < minLimit) { |
425 newLimit = minLimit; | 425 newLimit = minLimit; |
426 } | 426 } |
427 | 427 |
428 SkAutoMutexAcquire ac(fMutex); | 428 SkScopedLock<Lock> ac(*fMutex); |
429 | 429 |
430 size_t prevLimit = fCacheSizeLimit; | 430 size_t prevLimit = fCacheSizeLimit; |
431 fCacheSizeLimit = newLimit; | 431 fCacheSizeLimit = newLimit; |
432 this->internalPurge(); | 432 this->internalPurge(); |
433 return prevLimit; | 433 return prevLimit; |
434 } | 434 } |
435 | 435 |
436 int SkGlyphCache_Globals::setCacheCountLimit(int newCount) { | 436 int SkGlyphCache_Globals::setCacheCountLimit(int newCount) { |
437 if (newCount < 0) { | 437 if (newCount < 0) { |
438 newCount = 0; | 438 newCount = 0; |
439 } | 439 } |
440 | 440 |
441 SkAutoMutexAcquire ac(fMutex); | 441 SkScopedLock<Lock> ac(*fMutex); |
442 | 442 |
443 int prevCount = fCacheCountLimit; | 443 int prevCount = fCacheCountLimit; |
444 fCacheCountLimit = newCount; | 444 fCacheCountLimit = newCount; |
445 this->internalPurge(); | 445 this->internalPurge(); |
446 return prevCount; | 446 return prevCount; |
447 } | 447 } |
448 | 448 |
449 void SkGlyphCache_Globals::purgeAll() { | 449 void SkGlyphCache_Globals::purgeAll() { |
450 SkAutoMutexAcquire ac(fMutex); | 450 SkScopedLock<Lock> ac(*fMutex); |
451 this->internalPurge(fTotalMemoryUsed); | 451 this->internalPurge(fTotalMemoryUsed); |
452 } | 452 } |
453 | 453 |
454 /* This guy calls the visitor from within the mutext lock, so the visitor | 454 /* This guy calls the visitor from within the mutext lock, so the visitor |
455 cannot: | 455 cannot: |
456 - take too much time | 456 - take too much time |
457 - try to acquire the mutext again | 457 - try to acquire the mutext again |
458 - call a fontscaler (which might call into the cache) | 458 - call a fontscaler (which might call into the cache) |
459 */ | 459 */ |
460 SkGlyphCache* SkGlyphCache::VisitCache(SkTypeface* typeface, | 460 SkGlyphCache* SkGlyphCache::VisitCache(SkTypeface* typeface, |
461 const SkDescriptor* desc, | 461 const SkDescriptor* desc, |
462 bool (*proc)(const SkGlyphCache*, void*), | 462 bool (*proc)(const SkGlyphCache*, void*), |
463 void* context) { | 463 void* context) { |
464 if (!typeface) { | 464 if (!typeface) { |
465 typeface = SkTypeface::GetDefaultTypeface(); | 465 typeface = SkTypeface::GetDefaultTypeface(); |
466 } | 466 } |
467 SkASSERT(desc); | 467 SkASSERT(desc); |
468 | 468 |
469 SkGlyphCache_Globals& globals = getGlobals(); | 469 SkGlyphCache_Globals& globals = getGlobals(); |
470 SkAutoMutexAcquire ac(globals.fMutex); | |
471 SkGlyphCache* cache; | 470 SkGlyphCache* cache; |
472 bool insideMutex = true; | |
473 | 471 |
474 globals.validate(); | 472 { |
| 473 SkScopedLock<SkGlyphCache_Globals::Lock> ac(*globals.fMutex); |
475 | 474 |
476 for (cache = globals.internalGetHead(); cache != NULL; cache = cache->fNext)
{ | 475 globals.validate(); |
477 if (cache->fDesc->equals(*desc)) { | 476 |
478 globals.internalDetachCache(cache); | 477 for (cache = globals.internalGetHead(); cache != NULL; cache = cache->fN
ext) { |
479 goto FOUND_IT; | 478 if (cache->fDesc->equals(*desc)) { |
| 479 globals.internalDetachCache(cache); |
| 480 if (!proc(cache, context)) { |
| 481 globals.internalAttachCacheToHead(cache); |
| 482 cache = NULL; |
| 483 } |
| 484 return cache; |
| 485 } |
480 } | 486 } |
481 } | 487 } |
482 | 488 |
483 /* Release the mutex now, before we create a new entry (which might have | |
484 side-effects like trying to access the cache/mutex (yikes!) | |
485 */ | |
486 ac.release(); // release the mutex now | |
487 insideMutex = false; // can't use globals anymore | |
488 | |
489 // Check if we can create a scaler-context before creating the glyphcache. | 489 // Check if we can create a scaler-context before creating the glyphcache. |
490 // If not, we may have exhausted OS/font resources, so try purging the | 490 // If not, we may have exhausted OS/font resources, so try purging the |
491 // cache once and try again. | 491 // cache once and try again. |
492 { | 492 { |
493 // pass true the first time, to notice if the scalercontext failed, | 493 // pass true the first time, to notice if the scalercontext failed, |
494 // so we can try the purge. | 494 // so we can try the purge. |
495 SkScalerContext* ctx = typeface->createScalerContext(desc, true); | 495 SkScalerContext* ctx = typeface->createScalerContext(desc, true); |
496 if (!ctx) { | 496 if (!ctx) { |
497 getSharedGlobals().purgeAll(); | 497 getSharedGlobals().purgeAll(); |
498 ctx = typeface->createScalerContext(desc, false); | 498 ctx = typeface->createScalerContext(desc, false); |
499 SkASSERT(ctx); | 499 SkASSERT(ctx); |
500 } | 500 } |
501 cache = SkNEW_ARGS(SkGlyphCache, (typeface, desc, ctx)); | 501 cache = SkNEW_ARGS(SkGlyphCache, (typeface, desc, ctx)); |
502 } | 502 } |
503 | 503 |
504 FOUND_IT: | |
505 | |
506 AutoValidate av(cache); | 504 AutoValidate av(cache); |
507 | 505 |
508 if (!proc(cache, context)) { // need to reattach | 506 if (!proc(cache, context)) { // need to reattach |
509 if (insideMutex) { | 507 globals.attachCacheToHead(cache); |
510 globals.internalAttachCacheToHead(cache); | |
511 } else { | |
512 globals.attachCacheToHead(cache); | |
513 } | |
514 cache = NULL; | 508 cache = NULL; |
515 } | 509 } |
516 return cache; | 510 return cache; |
517 } | 511 } |
518 | 512 |
519 void SkGlyphCache::AttachCache(SkGlyphCache* cache) { | 513 void SkGlyphCache::AttachCache(SkGlyphCache* cache) { |
520 SkASSERT(cache); | 514 SkASSERT(cache); |
521 SkASSERT(cache->fNext == NULL); | 515 SkASSERT(cache->fNext == NULL); |
522 | 516 |
523 getGlobals().attachCacheToHead(cache); | 517 getGlobals().attachCacheToHead(cache); |
524 } | 518 } |
525 | 519 |
526 void SkGlyphCache::Dump() { | 520 void SkGlyphCache::Dump() { |
527 SkGlyphCache_Globals& globals = getGlobals(); | 521 SkGlyphCache_Globals& globals = getGlobals(); |
528 SkAutoMutexAcquire ac(globals.fMutex); | 522 SkScopedLock<SkGlyphCache_Globals::Lock> ac(*globals.fMutex); |
529 SkGlyphCache* cache; | 523 SkGlyphCache* cache; |
530 | 524 |
531 globals.validate(); | 525 globals.validate(); |
532 | 526 |
533 SkDebugf("SkGlyphCache strikes:%d memory:%d\n", | 527 SkDebugf("SkGlyphCache strikes:%d memory:%d\n", |
534 globals.getCacheCountUsed(), (int)globals.getTotalMemoryUsed()); | 528 globals.getCacheCountUsed(), (int)globals.getTotalMemoryUsed()); |
535 | 529 |
536 #ifdef SK_GLYPHCACHE_TRACK_HASH_STATS | 530 #ifdef SK_GLYPHCACHE_TRACK_HASH_STATS |
537 int hitCount = 0; | 531 int hitCount = 0; |
538 int missCount = 0; | 532 int missCount = 0; |
539 #endif | 533 #endif |
540 | 534 |
541 for (cache = globals.internalGetHead(); cache != NULL; cache = cache->fNext)
{ | 535 for (cache = globals.internalGetHead(); cache != NULL; cache = cache->fNext)
{ |
542 #ifdef SK_GLYPHCACHE_TRACK_HASH_STATS | 536 #ifdef SK_GLYPHCACHE_TRACK_HASH_STATS |
543 hitCount += cache->fHashHitCount; | 537 hitCount += cache->fHashHitCount; |
544 missCount += cache->fHashMissCount; | 538 missCount += cache->fHashMissCount; |
545 #endif | 539 #endif |
546 cache->dump(); | 540 cache->dump(); |
547 } | 541 } |
548 #ifdef SK_GLYPHCACHE_TRACK_HASH_STATS | 542 #ifdef SK_GLYPHCACHE_TRACK_HASH_STATS |
549 SkDebugf("Hash hit percent:%2d\n", 100 * hitCount / (hitCount + missCount)); | 543 SkDebugf("Hash hit percent:%2d\n", 100 * hitCount / (hitCount + missCount)); |
550 #endif | 544 #endif |
551 } | 545 } |
552 | 546 |
553 /////////////////////////////////////////////////////////////////////////////// | 547 /////////////////////////////////////////////////////////////////////////////// |
554 | 548 |
555 void SkGlyphCache_Globals::attachCacheToHead(SkGlyphCache* cache) { | 549 void SkGlyphCache_Globals::attachCacheToHead(SkGlyphCache* cache) { |
556 SkAutoMutexAcquire ac(fMutex); | 550 SkScopedLock<Lock> ac(*fMutex); |
557 | 551 |
558 this->validate(); | 552 this->validate(); |
559 cache->validate(); | 553 cache->validate(); |
560 | 554 |
561 this->internalAttachCacheToHead(cache); | 555 this->internalAttachCacheToHead(cache); |
562 this->internalPurge(); | 556 this->internalPurge(); |
563 } | 557 } |
564 | 558 |
565 SkGlyphCache* SkGlyphCache_Globals::internalGetTail() const { | 559 SkGlyphCache* SkGlyphCache_Globals::internalGetTail() const { |
566 SkGlyphCache* cache = fHead; | 560 SkGlyphCache* cache = fHead; |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
727 return tls ? tls->getCacheSizeLimit() : 0; | 721 return tls ? tls->getCacheSizeLimit() : 0; |
728 } | 722 } |
729 | 723 |
730 void SkGraphics::SetTLSFontCacheLimit(size_t bytes) { | 724 void SkGraphics::SetTLSFontCacheLimit(size_t bytes) { |
731 if (0 == bytes) { | 725 if (0 == bytes) { |
732 SkGlyphCache_Globals::DeleteTLS(); | 726 SkGlyphCache_Globals::DeleteTLS(); |
733 } else { | 727 } else { |
734 SkGlyphCache_Globals::GetTLS().setCacheSizeLimit(bytes); | 728 SkGlyphCache_Globals::GetTLS().setCacheSizeLimit(bytes); |
735 } | 729 } |
736 } | 730 } |
OLD | NEW |