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 |