| OLD | NEW |
| 1 | |
| 2 /* | 1 /* |
| 3 * Copyright 2006 The Android Open Source Project | 2 * Copyright 2006 The Android Open Source Project |
| 4 * | 3 * |
| 5 * 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 |
| 6 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 7 */ | 6 */ |
| 8 | 7 |
| 9 | |
| 10 #include "SkGlyphCache.h" | 8 #include "SkGlyphCache.h" |
| 11 #include "SkGlyphCache_Globals.h" | 9 #include "SkGlyphCache_Globals.h" |
| 12 #include "SkGraphics.h" | 10 #include "SkGraphics.h" |
| 13 #include "SkLazyPtr.h" | 11 #include "SkLazyPtr.h" |
| 14 #include "SkPaint.h" | 12 #include "SkPaint.h" |
| 15 #include "SkPath.h" | 13 #include "SkPath.h" |
| 16 #include "SkTemplates.h" | 14 #include "SkTemplates.h" |
| 17 #include "SkTLS.h" | 15 #include "SkTLS.h" |
| 18 #include "SkTypeface.h" | 16 #include "SkTypeface.h" |
| 19 | 17 |
| 20 //#define SPEW_PURGE_STATUS | 18 //#define SPEW_PURGE_STATUS |
| 21 //#define RECORD_HASH_EFFICIENCY | |
| 22 | 19 |
| 23 namespace { | 20 namespace { |
| 24 | 21 |
| 25 SkGlyphCache_Globals* create_globals() { | 22 SkGlyphCache_Globals* create_globals() { |
| 26 return SkNEW_ARGS(SkGlyphCache_Globals, (SkGlyphCache_Globals::kYes_UseMutex
)); | 23 return SkNEW_ARGS(SkGlyphCache_Globals, (SkGlyphCache_Globals::kYes_UseMutex
)); |
| 27 } | 24 } |
| 28 | 25 |
| 29 } // namespace | 26 } // namespace |
| 30 | 27 |
| 31 SK_DECLARE_STATIC_LAZY_PTR(SkGlyphCache_Globals, globals, create_globals); | 28 SK_DECLARE_STATIC_LAZY_PTR(SkGlyphCache_Globals, globals, create_globals); |
| 32 | 29 |
| 33 // Returns the shared globals | 30 // Returns the shared globals |
| 34 static SkGlyphCache_Globals& getSharedGlobals() { | 31 static SkGlyphCache_Globals& getSharedGlobals() { |
| 35 return *globals.get(); | 32 return *globals.get(); |
| 36 } | 33 } |
| 37 | 34 |
| 38 // Returns the TLS globals (if set), or the shared globals | 35 // Returns the TLS globals (if set), or the shared globals |
| 39 static SkGlyphCache_Globals& getGlobals() { | 36 static SkGlyphCache_Globals& getGlobals() { |
| 40 SkGlyphCache_Globals* tls = SkGlyphCache_Globals::FindTLS(); | 37 SkGlyphCache_Globals* tls = SkGlyphCache_Globals::FindTLS(); |
| 41 return tls ? *tls : getSharedGlobals(); | 38 return tls ? *tls : getSharedGlobals(); |
| 42 } | 39 } |
| 43 | 40 |
| 44 /////////////////////////////////////////////////////////////////////////////// | 41 /////////////////////////////////////////////////////////////////////////////// |
| 45 | 42 |
| 46 #ifdef RECORD_HASH_EFFICIENCY | 43 #ifdef SK_GLYPHCACHE_TRACK_HASH_STATS |
| 47 static uint32_t gHashSuccess; | 44 #define RecordHashSuccess() fHashHitCount += 1 |
| 48 static uint32_t gHashCollision; | 45 #define RecordHashCollisionIf(pred) do { if (pred) fHashMissCount += 1;
} while (0) |
| 49 | |
| 50 static void RecordHashSuccess() { | |
| 51 gHashSuccess += 1; | |
| 52 } | |
| 53 | |
| 54 static void RecordHashCollisionIf(bool pred) { | |
| 55 if (pred) { | |
| 56 gHashCollision += 1; | |
| 57 | |
| 58 uint32_t total = gHashSuccess + gHashCollision; | |
| 59 SkDebugf("Font Cache Hash success rate: %d%%\n", | |
| 60 100 * gHashSuccess / total); | |
| 61 } | |
| 62 } | |
| 63 #else | 46 #else |
| 64 #define RecordHashSuccess() (void)0 | 47 #define RecordHashSuccess() (void)0 |
| 65 #define RecordHashCollisionIf(pred) (void)0 | 48 #define RecordHashCollisionIf(pred) (void)0 |
| 66 #endif | 49 #endif |
| 67 #define RecordHashCollision() RecordHashCollisionIf(true) | 50 #define RecordHashCollision() RecordHashCollisionIf(true) |
| 68 | 51 |
| 69 /////////////////////////////////////////////////////////////////////////////// | 52 /////////////////////////////////////////////////////////////////////////////// |
| 70 | 53 |
| 71 // so we don't grow our arrays a lot | 54 // so we don't grow our arrays a lot |
| 72 #define kMinGlyphCount 16 | 55 #define kMinGlyphCount 16 |
| 73 #define kMinGlyphImageSize (16*2) | 56 #define kMinGlyphImageSize (16*2) |
| 74 #define kMinAllocAmount ((sizeof(SkGlyph) + kMinGlyphImageSize) * kMinGlyphC
ount) | 57 #define kMinAllocAmount ((sizeof(SkGlyph) + kMinGlyphImageSize) * kMinGlyphC
ount) |
| 75 | 58 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 87 // init to 0 so that all of the pointers will be null | 70 // init to 0 so that all of the pointers will be null |
| 88 memset(fGlyphHash, 0, sizeof(fGlyphHash)); | 71 memset(fGlyphHash, 0, sizeof(fGlyphHash)); |
| 89 // init with 0xFF so that the charCode field will be -1, which is invalid | 72 // init with 0xFF so that the charCode field will be -1, which is invalid |
| 90 memset(fCharToGlyphHash, 0xFF, sizeof(fCharToGlyphHash)); | 73 memset(fCharToGlyphHash, 0xFF, sizeof(fCharToGlyphHash)); |
| 91 | 74 |
| 92 fMemoryUsed = sizeof(*this); | 75 fMemoryUsed = sizeof(*this); |
| 93 | 76 |
| 94 fGlyphArray.setReserve(kMinGlyphCount); | 77 fGlyphArray.setReserve(kMinGlyphCount); |
| 95 | 78 |
| 96 fAuxProcList = NULL; | 79 fAuxProcList = NULL; |
| 80 |
| 81 #ifdef SK_GLYPHCACHE_TRACK_HASH_STATS |
| 82 fHashHitCount = fHashMissCount = 0; |
| 83 #endif |
| 97 } | 84 } |
| 98 | 85 |
| 99 SkGlyphCache::~SkGlyphCache() { | 86 SkGlyphCache::~SkGlyphCache() { |
| 100 #if 0 | 87 #if 0 |
| 101 { | 88 { |
| 102 size_t ptrMem = fGlyphArray.count() * sizeof(SkGlyph*); | 89 size_t ptrMem = fGlyphArray.count() * sizeof(SkGlyph*); |
| 103 size_t glyphAlloc = fGlyphAlloc.totalCapacity(); | 90 size_t glyphAlloc = fGlyphAlloc.totalCapacity(); |
| 104 size_t glyphHashUsed = 0; | 91 size_t glyphHashUsed = 0; |
| 105 size_t uniHashUsed = 0; | 92 size_t uniHashUsed = 0; |
| 106 for (int i = 0; i < kHashCount; ++i) { | 93 for (int i = 0; i < kHashCount; ++i) { |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 253 } else { | 240 } else { |
| 254 RecordHashSuccess(); | 241 RecordHashSuccess(); |
| 255 if (glyph->isJustAdvance()) { | 242 if (glyph->isJustAdvance()) { |
| 256 fScalerContext->getMetrics(glyph); | 243 fScalerContext->getMetrics(glyph); |
| 257 } | 244 } |
| 258 } | 245 } |
| 259 SkASSERT(glyph->isFullMetrics()); | 246 SkASSERT(glyph->isFullMetrics()); |
| 260 return *glyph; | 247 return *glyph; |
| 261 } | 248 } |
| 262 | 249 |
| 263 const SkGlyph& SkGlyphCache::getGlyphIDMetrics(uint16_t glyphID, | 250 const SkGlyph& SkGlyphCache::getGlyphIDMetrics(uint16_t glyphID, SkFixed x, SkFi
xed y) { |
| 264 SkFixed x, SkFixed y) { | |
| 265 VALIDATE(); | 251 VALIDATE(); |
| 266 uint32_t id = SkGlyph::MakeID(glyphID, x, y); | 252 uint32_t id = SkGlyph::MakeID(glyphID, x, y); |
| 267 unsigned index = ID2HashIndex(id); | 253 unsigned index = ID2HashIndex(id); |
| 268 SkGlyph* glyph = fGlyphHash[index]; | 254 SkGlyph* glyph = fGlyphHash[index]; |
| 269 | 255 |
| 270 if (NULL == glyph || glyph->fID != id) { | 256 if (NULL == glyph || glyph->fID != id) { |
| 271 RecordHashCollisionIf(glyph != NULL); | 257 RecordHashCollisionIf(glyph != NULL); |
| 272 glyph = this->lookupMetrics(id, kFull_MetricsType); | 258 glyph = this->lookupMetrics(id, kFull_MetricsType); |
| 273 fGlyphHash[index] = glyph; | 259 fGlyphHash[index] = glyph; |
| 274 } else { | 260 } else { |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 357 if (glyph.fPath == NULL) { | 343 if (glyph.fPath == NULL) { |
| 358 const_cast<SkGlyph&>(glyph).fPath = SkNEW(SkPath); | 344 const_cast<SkGlyph&>(glyph).fPath = SkNEW(SkPath); |
| 359 fScalerContext->getPath(glyph, glyph.fPath); | 345 fScalerContext->getPath(glyph, glyph.fPath); |
| 360 fMemoryUsed += sizeof(SkPath) + | 346 fMemoryUsed += sizeof(SkPath) + |
| 361 glyph.fPath->countPoints() * sizeof(SkPoint); | 347 glyph.fPath->countPoints() * sizeof(SkPoint); |
| 362 } | 348 } |
| 363 } | 349 } |
| 364 return glyph.fPath; | 350 return glyph.fPath; |
| 365 } | 351 } |
| 366 | 352 |
| 353 void SkGlyphCache::dump() const { |
| 354 const SkTypeface* face = fScalerContext->getTypeface(); |
| 355 const SkScalerContextRec& rec = fScalerContext->getRec(); |
| 356 SkMatrix matrix; |
| 357 rec.getSingleMatrix(&matrix); |
| 358 matrix.preScale(SkScalarInvert(rec.fTextSize), SkScalarInvert(rec.fTextSize)
); |
| 359 SkString name; |
| 360 face->getFamilyName(&name); |
| 361 |
| 362 SkString msg; |
| 363 msg.printf("cache typeface:%x %25s:%d size:%2g [%g %g %g %g] lum:%02X devG:%
d pntG:%d cntr:%d glyphs:%3d", |
| 364 face->uniqueID(), name.c_str(), face->style(), rec.fTextSize, |
| 365 matrix[SkMatrix::kMScaleX], matrix[SkMatrix::kMSkewX], |
| 366 matrix[SkMatrix::kMSkewY], matrix[SkMatrix::kMScaleY], |
| 367 rec.fLumBits & 0xFF, rec.fDeviceGamma, rec.fPaintGamma, rec.fCont
rast, |
| 368 fGlyphArray.count()); |
| 369 #ifdef SK_GLYPHCACHE_TRACK_HASH_STATS |
| 370 const int sum = SkTMax(fHashHitCount + fHashMissCount, 1); // avoid divide
-by-zero |
| 371 msg.appendf(" hash:%2d\n", 100 * fHashHitCount / sum); |
| 372 #endif |
| 373 SkDebugf("%s\n", msg.c_str()); |
| 374 } |
| 375 |
| 367 /////////////////////////////////////////////////////////////////////////////// | 376 /////////////////////////////////////////////////////////////////////////////// |
| 368 | 377 |
| 369 bool SkGlyphCache::getAuxProcData(void (*proc)(void*), void** dataPtr) const { | 378 bool SkGlyphCache::getAuxProcData(void (*proc)(void*), void** dataPtr) const { |
| 370 const AuxProcRec* rec = fAuxProcList; | 379 const AuxProcRec* rec = fAuxProcList; |
| 371 while (rec) { | 380 while (rec) { |
| 372 if (rec->fProc == proc) { | 381 if (rec->fProc == proc) { |
| 373 if (dataPtr) { | 382 if (dataPtr) { |
| 374 *dataPtr = rec->fData; | 383 *dataPtr = rec->fData; |
| 375 } | 384 } |
| 376 return true; | 385 return true; |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 513 return cache; | 522 return cache; |
| 514 } | 523 } |
| 515 | 524 |
| 516 void SkGlyphCache::AttachCache(SkGlyphCache* cache) { | 525 void SkGlyphCache::AttachCache(SkGlyphCache* cache) { |
| 517 SkASSERT(cache); | 526 SkASSERT(cache); |
| 518 SkASSERT(cache->fNext == NULL); | 527 SkASSERT(cache->fNext == NULL); |
| 519 | 528 |
| 520 getGlobals().attachCacheToHead(cache); | 529 getGlobals().attachCacheToHead(cache); |
| 521 } | 530 } |
| 522 | 531 |
| 532 void SkGlyphCache::Dump() { |
| 533 SkGlyphCache_Globals& globals = getGlobals(); |
| 534 SkAutoMutexAcquire ac(globals.fMutex); |
| 535 SkGlyphCache* cache; |
| 536 |
| 537 globals.validate(); |
| 538 |
| 539 SkDebugf("SkGlyphCache strikes:%d memory:%d\n", |
| 540 globals.getCacheCountUsed(), (int)globals.getTotalMemoryUsed()); |
| 541 |
| 542 #ifdef SK_GLYPHCACHE_TRACK_HASH_STATS |
| 543 int hitCount = 0; |
| 544 int missCount = 0; |
| 545 #endif |
| 546 |
| 547 for (cache = globals.internalGetHead(); cache != NULL; cache = cache->fNext)
{ |
| 548 #ifdef SK_GLYPHCACHE_TRACK_HASH_STATS |
| 549 hitCount += cache->fHashHitCount; |
| 550 missCount += cache->fHashMissCount; |
| 551 #endif |
| 552 cache->dump(); |
| 553 } |
| 554 #ifdef SK_GLYPHCACHE_TRACK_HASH_STATS |
| 555 SkDebugf("Hash hit percent:%2d\n", 100 * hitCount / (hitCount + missCount)); |
| 556 #endif |
| 557 } |
| 558 |
| 523 /////////////////////////////////////////////////////////////////////////////// | 559 /////////////////////////////////////////////////////////////////////////////// |
| 524 | 560 |
| 525 void SkGlyphCache_Globals::attachCacheToHead(SkGlyphCache* cache) { | 561 void SkGlyphCache_Globals::attachCacheToHead(SkGlyphCache* cache) { |
| 526 SkAutoMutexAcquire ac(fMutex); | 562 SkAutoMutexAcquire ac(fMutex); |
| 527 | 563 |
| 528 this->validate(); | 564 this->validate(); |
| 529 cache->validate(); | 565 cache->validate(); |
| 530 | 566 |
| 531 this->internalAttachCacheToHead(cache); | 567 this->internalAttachCacheToHead(cache); |
| 532 this->internalPurge(); | 568 this->internalPurge(); |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 701 return tls ? tls->getCacheSizeLimit() : 0; | 737 return tls ? tls->getCacheSizeLimit() : 0; |
| 702 } | 738 } |
| 703 | 739 |
| 704 void SkGraphics::SetTLSFontCacheLimit(size_t bytes) { | 740 void SkGraphics::SetTLSFontCacheLimit(size_t bytes) { |
| 705 if (0 == bytes) { | 741 if (0 == bytes) { |
| 706 SkGlyphCache_Globals::DeleteTLS(); | 742 SkGlyphCache_Globals::DeleteTLS(); |
| 707 } else { | 743 } else { |
| 708 SkGlyphCache_Globals::GetTLS().setCacheSizeLimit(bytes); | 744 SkGlyphCache_Globals::GetTLS().setCacheSizeLimit(bytes); |
| 709 } | 745 } |
| 710 } | 746 } |
| OLD | NEW |