OLD | NEW |
1 | 1 |
2 /* | 2 /* |
3 * Copyright 2006 The Android Open Source Project | 3 * Copyright 2006 The Android Open Source Project |
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 "SkGlyphCache.h" | 10 #include "SkGlyphCache.h" |
11 #include "SkGraphics.h" | 11 #include "SkGraphics.h" |
12 #include "SkPaint.h" | 12 #include "SkPaint.h" |
13 #include "SkPath.h" | 13 #include "SkPath.h" |
14 #include "SkTemplates.h" | 14 #include "SkTemplates.h" |
15 #include "SkTLS.h" | 15 #include "SkTLS.h" |
16 #include "SkTypeface.h" | 16 #include "SkTypeface.h" |
17 | 17 |
18 //#define SPEW_PURGE_STATUS | 18 //#define SPEW_PURGE_STATUS |
19 //#define USE_CACHE_HASH | |
20 //#define RECORD_HASH_EFFICIENCY | 19 //#define RECORD_HASH_EFFICIENCY |
21 | 20 |
22 bool gSkSuppressFontCachePurgeSpew; | 21 bool gSkSuppressFontCachePurgeSpew; |
23 | 22 |
24 /////////////////////////////////////////////////////////////////////////////// | 23 /////////////////////////////////////////////////////////////////////////////// |
25 | 24 |
26 #ifdef RECORD_HASH_EFFICIENCY | 25 #ifdef RECORD_HASH_EFFICIENCY |
27 static uint32_t gHashSuccess; | 26 static uint32_t gHashSuccess; |
28 static uint32_t gHashCollision; | 27 static uint32_t gHashCollision; |
29 | 28 |
(...skipping 365 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
395 } | 394 } |
396 } | 395 } |
397 | 396 |
398 /////////////////////////////////////////////////////////////////////////////// | 397 /////////////////////////////////////////////////////////////////////////////// |
399 /////////////////////////////////////////////////////////////////////////////// | 398 /////////////////////////////////////////////////////////////////////////////// |
400 | 399 |
401 #ifndef SK_DEFAULT_FONT_CACHE_LIMIT | 400 #ifndef SK_DEFAULT_FONT_CACHE_LIMIT |
402 #define SK_DEFAULT_FONT_CACHE_LIMIT (2 * 1024 * 1024) | 401 #define SK_DEFAULT_FONT_CACHE_LIMIT (2 * 1024 * 1024) |
403 #endif | 402 #endif |
404 | 403 |
405 #ifdef USE_CACHE_HASH | |
406 #define HASH_BITCOUNT 6 | |
407 #define HASH_COUNT (1 << HASH_BITCOUNT) | |
408 #define HASH_MASK (HASH_COUNT - 1) | |
409 | |
410 static unsigned desc_to_hashindex(const SkDescriptor* desc) | |
411 { | |
412 SkASSERT(HASH_MASK < 256); // since our munging reduces to 8 bits | |
413 | |
414 uint32_t n = *(const uint32_t*)desc; //desc->getChecksum(); | |
415 SkASSERT(n == desc->getChecksum()); | |
416 | |
417 // don't trust that the low bits of checksum vary enough, so... | |
418 n ^= (n >> 24) ^ (n >> 16) ^ (n >> 8) ^ (n >> 30); | |
419 | |
420 return n & HASH_MASK; | |
421 } | |
422 #endif | |
423 | |
424 #include "SkThread.h" | 404 #include "SkThread.h" |
425 | 405 |
426 class SkGlyphCache_Globals { | 406 class SkGlyphCache_Globals { |
427 public: | 407 public: |
428 enum UseMutex { | 408 enum UseMutex { |
429 kNo_UseMutex, // thread-local cache | 409 kNo_UseMutex, // thread-local cache |
430 kYes_UseMutex // shared cache | 410 kYes_UseMutex // shared cache |
431 }; | 411 }; |
432 | 412 |
433 SkGlyphCache_Globals(UseMutex um) { | 413 SkGlyphCache_Globals(UseMutex um) { |
434 fHead = NULL; | 414 fHead = NULL; |
435 fTotalMemoryUsed = 0; | 415 fTotalMemoryUsed = 0; |
436 fFontCacheLimit = SK_DEFAULT_FONT_CACHE_LIMIT; | 416 fFontCacheLimit = SK_DEFAULT_FONT_CACHE_LIMIT; |
437 fMutex = (kYes_UseMutex == um) ? SkNEW(SkMutex) : NULL; | 417 fMutex = (kYes_UseMutex == um) ? SkNEW(SkMutex) : NULL; |
438 | |
439 #ifdef USE_CACHE_HASH | |
440 sk_bzero(fHash, sizeof(fHash)); | |
441 #endif | |
442 } | 418 } |
443 | 419 |
444 ~SkGlyphCache_Globals() { | 420 ~SkGlyphCache_Globals() { |
445 SkGlyphCache* cache = fHead; | 421 SkGlyphCache* cache = fHead; |
446 while (cache) { | 422 while (cache) { |
447 SkGlyphCache* next = cache->fNext; | 423 SkGlyphCache* next = cache->fNext; |
448 SkDELETE(cache); | 424 SkDELETE(cache); |
449 cache = next; | 425 cache = next; |
450 } | 426 } |
451 | 427 |
452 SkDELETE(fMutex); | 428 SkDELETE(fMutex); |
453 } | 429 } |
454 | 430 |
455 SkMutex* fMutex; | 431 SkMutex* fMutex; |
456 SkGlyphCache* fHead; | 432 SkGlyphCache* fHead; |
457 size_t fTotalMemoryUsed; | 433 size_t fTotalMemoryUsed; |
458 #ifdef USE_CACHE_HASH | |
459 SkGlyphCache* fHash[HASH_COUNT]; | |
460 #endif | |
461 | 434 |
462 #ifdef SK_DEBUG | 435 #ifdef SK_DEBUG |
463 void validate() const; | 436 void validate() const; |
464 #else | 437 #else |
465 void validate() const {} | 438 void validate() const {} |
466 #endif | 439 #endif |
467 | 440 |
468 size_t getFontCacheLimit() const { return fFontCacheLimit; } | 441 size_t getFontCacheLimit() const { return fFontCacheLimit; } |
469 size_t setFontCacheLimit(size_t limit); | 442 size_t setFontCacheLimit(size_t limit); |
470 void purgeAll(); // does not change budget | 443 void purgeAll(); // does not change budget |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
560 } | 533 } |
561 SkASSERT(desc); | 534 SkASSERT(desc); |
562 | 535 |
563 SkGlyphCache_Globals& globals = getGlobals(); | 536 SkGlyphCache_Globals& globals = getGlobals(); |
564 SkAutoMutexAcquire ac(globals.fMutex); | 537 SkAutoMutexAcquire ac(globals.fMutex); |
565 SkGlyphCache* cache; | 538 SkGlyphCache* cache; |
566 bool insideMutex = true; | 539 bool insideMutex = true; |
567 | 540 |
568 globals.validate(); | 541 globals.validate(); |
569 | 542 |
570 #ifdef USE_CACHE_HASH | |
571 SkGlyphCache** hash = globals.fHash; | |
572 unsigned index = desc_to_hashindex(desc); | |
573 cache = hash[index]; | |
574 if (cache && *cache->fDesc == *desc) { | |
575 cache->detach(&globals.fHead); | |
576 goto FOUND_IT; | |
577 } | |
578 #endif | |
579 | |
580 for (cache = globals.fHead; cache != NULL; cache = cache->fNext) { | 543 for (cache = globals.fHead; cache != NULL; cache = cache->fNext) { |
581 if (cache->fDesc->equals(*desc)) { | 544 if (cache->fDesc->equals(*desc)) { |
582 cache->detach(&globals.fHead); | 545 cache->detach(&globals.fHead); |
583 goto FOUND_IT; | 546 goto FOUND_IT; |
584 } | 547 } |
585 } | 548 } |
586 | 549 |
587 /* Release the mutex now, before we create a new entry (which might have | 550 /* Release the mutex now, before we create a new entry (which might have |
588 side-effects like trying to access the cache/mutex (yikes!) | 551 side-effects like trying to access the cache/mutex (yikes!) |
589 */ | 552 */ |
(...skipping 16 matching lines...) Expand all Loading... |
606 } | 569 } |
607 | 570 |
608 FOUND_IT: | 571 FOUND_IT: |
609 | 572 |
610 AutoValidate av(cache); | 573 AutoValidate av(cache); |
611 | 574 |
612 if (proc(cache, context)) { // stay detached | 575 if (proc(cache, context)) { // stay detached |
613 if (insideMutex) { | 576 if (insideMutex) { |
614 SkASSERT(globals.fTotalMemoryUsed >= cache->fMemoryUsed); | 577 SkASSERT(globals.fTotalMemoryUsed >= cache->fMemoryUsed); |
615 globals.fTotalMemoryUsed -= cache->fMemoryUsed; | 578 globals.fTotalMemoryUsed -= cache->fMemoryUsed; |
616 #ifdef USE_CACHE_HASH | |
617 hash[index] = NULL; | |
618 #endif | |
619 } | 579 } |
620 } else { // reattach | 580 } else { // reattach |
621 if (insideMutex) { | 581 if (insideMutex) { |
622 cache->attachToHead(&globals.fHead); | 582 cache->attachToHead(&globals.fHead); |
623 #ifdef USE_CACHE_HASH | |
624 hash[index] = cache; | |
625 #endif | |
626 } else { | 583 } else { |
627 AttachCache(cache); | 584 AttachCache(cache); |
628 } | 585 } |
629 cache = NULL; | 586 cache = NULL; |
630 } | 587 } |
631 return cache; | 588 return cache; |
632 } | 589 } |
633 | 590 |
634 void SkGlyphCache::AttachCache(SkGlyphCache* cache) { | 591 void SkGlyphCache::AttachCache(SkGlyphCache* cache) { |
635 SkASSERT(cache); | 592 SkASSERT(cache); |
(...skipping 10 matching lines...) Expand all Loading... |
646 size_t allocated = globals.fTotalMemoryUsed + cache->fMemoryUsed; | 603 size_t allocated = globals.fTotalMemoryUsed + cache->fMemoryUsed; |
647 size_t budgeted = globals.getFontCacheLimit(); | 604 size_t budgeted = globals.getFontCacheLimit(); |
648 if (allocated > budgeted) { | 605 if (allocated > budgeted) { |
649 (void)InternalFreeCache(&globals, allocated - budgeted); | 606 (void)InternalFreeCache(&globals, allocated - budgeted); |
650 } | 607 } |
651 } | 608 } |
652 | 609 |
653 cache->attachToHead(&globals.fHead); | 610 cache->attachToHead(&globals.fHead); |
654 globals.fTotalMemoryUsed += cache->fMemoryUsed; | 611 globals.fTotalMemoryUsed += cache->fMemoryUsed; |
655 | 612 |
656 #ifdef USE_CACHE_HASH | |
657 unsigned index = desc_to_hashindex(cache->fDesc); | |
658 SkASSERT(globals.fHash[index] != cache); | |
659 globals.fHash[index] = cache; | |
660 #endif | |
661 | |
662 globals.validate(); | 613 globals.validate(); |
663 } | 614 } |
664 | 615 |
665 /////////////////////////////////////////////////////////////////////////////// | 616 /////////////////////////////////////////////////////////////////////////////// |
666 | 617 |
667 SkGlyphCache* SkGlyphCache::FindTail(SkGlyphCache* cache) { | 618 SkGlyphCache* SkGlyphCache::FindTail(SkGlyphCache* cache) { |
668 if (cache) { | 619 if (cache) { |
669 while (cache->fNext) { | 620 while (cache->fNext) { |
670 cache = cache->fNext; | 621 cache = cache->fNext; |
671 } | 622 } |
(...skipping 28 matching lines...) Expand all Loading... |
700 // don't do any "small" purges | 651 // don't do any "small" purges |
701 size_t minToPurge = globals->fTotalMemoryUsed >> 2; | 652 size_t minToPurge = globals->fTotalMemoryUsed >> 2; |
702 if (bytesNeeded < minToPurge) | 653 if (bytesNeeded < minToPurge) |
703 bytesNeeded = minToPurge; | 654 bytesNeeded = minToPurge; |
704 | 655 |
705 SkGlyphCache* cache = FindTail(globals->fHead); | 656 SkGlyphCache* cache = FindTail(globals->fHead); |
706 while (cache != NULL && bytesFreed < bytesNeeded) { | 657 while (cache != NULL && bytesFreed < bytesNeeded) { |
707 SkGlyphCache* prev = cache->fPrev; | 658 SkGlyphCache* prev = cache->fPrev; |
708 bytesFreed += cache->fMemoryUsed; | 659 bytesFreed += cache->fMemoryUsed; |
709 | 660 |
710 #ifdef USE_CACHE_HASH | |
711 unsigned index = desc_to_hashindex(cache->fDesc); | |
712 if (cache == globals->fHash[index]) { | |
713 globals->fHash[index] = NULL; | |
714 } | |
715 #endif | |
716 | |
717 cache->detach(&globals->fHead); | 661 cache->detach(&globals->fHead); |
718 SkDELETE(cache); | 662 SkDELETE(cache); |
719 cache = prev; | 663 cache = prev; |
720 count += 1; | 664 count += 1; |
721 } | 665 } |
722 | 666 |
723 SkASSERT(bytesFreed <= globals->fTotalMemoryUsed); | 667 SkASSERT(bytesFreed <= globals->fTotalMemoryUsed); |
724 globals->fTotalMemoryUsed -= bytesFreed; | 668 globals->fTotalMemoryUsed -= bytesFreed; |
725 globals->validate(); | 669 globals->validate(); |
726 | 670 |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
779 return tls ? tls->getFontCacheLimit() : 0; | 723 return tls ? tls->getFontCacheLimit() : 0; |
780 } | 724 } |
781 | 725 |
782 void SkGraphics::SetTLSFontCacheLimit(size_t bytes) { | 726 void SkGraphics::SetTLSFontCacheLimit(size_t bytes) { |
783 if (0 == bytes) { | 727 if (0 == bytes) { |
784 SkGlyphCache_Globals::DeleteTLS(); | 728 SkGlyphCache_Globals::DeleteTLS(); |
785 } else { | 729 } else { |
786 SkGlyphCache_Globals::GetTLS().setFontCacheLimit(bytes); | 730 SkGlyphCache_Globals::GetTLS().setFontCacheLimit(bytes); |
787 } | 731 } |
788 } | 732 } |
OLD | NEW |