diff options
author | 2015-02-27 07:22:48 -0800 | |
---|---|---|
committer | 2015-02-27 07:22:48 -0800 | |
commit | e70de9e4f0b7bf73f7cd1a20dbabcb233ffbb7f1 (patch) | |
tree | 5a0d85a81aafd177425ee74cae31324bacd2054b /src/core | |
parent | 574290f61a47bd1ce1f9e2d941533bda9c8f03fe (diff) |
Make the glyph array entries inline.
Perf Reports
bin/c --match nytimes --config 8888
desk_nytimes.skp_1_mpd 1.41ms -> 1.38ms 0.98x
desk_nytimes.skp_1 1.94ms -> 1.87ms 0.97x
bin/c --match nytimes --config gpu
desk_nytimes.skp_1_mpd 1.63ms -> 1.59ms 0.97x
desk_nytimes.skp_1 1.56ms -> 1.5ms 0.97x
Here are results from mac instruments:
--match nytimes --config gpu --samples 10000 --skps /Users/herb/src/skia/skps
Inline:
Total Samples Running Time Self Symbol Name
94335 94335.0ms 98.3% 0.0 start
2365 2365.0ms 2.4% 2365.0 SkGlyphCache::getGlyphIDMetrics(unsigned short, int, int)
975 975.0ms 1.0% 975.0 SkGlyphCache::lookupMetrics(unsigned int, SkGlyphCache::MetricsType)
Clean:
Total Samples Running Time Self Symbol Name
96833 96833.0ms 97.3% 0.0 start
3418 3418.0ms 3.4% 3418.0 SkGlyphCache::getGlyphIDMetrics(unsigned short, int, int)
1961 1961.0ms 1.9% 1961.0 SkGlyphCache::lookupMetrics(unsigned int, SkGlyphCache::MetricsType)
BUG=skia:
Committed: https://skia.googlesource.com/skia/+/4c08f16b252a55e438a61f26e5581394ed177da1
Committed: https://skia.googlesource.com/skia/+/b4c29ac173e6f8844327338687248b98bc94132d
Review URL: https://codereview.chromium.org/885903002
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/SkGlyph.h | 13 | ||||
-rwxr-xr-x | src/core/SkGlyphCache.cpp | 221 | ||||
-rw-r--r-- | src/core/SkGlyphCache.h | 41 |
3 files changed, 138 insertions, 137 deletions
diff --git a/src/core/SkGlyph.h b/src/core/SkGlyph.h index 25aaed77a6..48b9815a03 100644 --- a/src/core/SkGlyph.h +++ b/src/core/SkGlyph.h @@ -53,6 +53,10 @@ class SkGlyph { this->initCommon(glyph.fID); } + void initGlyphFromCombinedID(uint32_t combined_id) { + this->initCommon(combined_id); + } + /** * Compute the rowbytes for the specified width and mask-format. */ @@ -106,7 +110,6 @@ class SkGlyph { */ void zeroMetrics(); - void toMask(SkMask* mask) const; private: @@ -120,8 +123,9 @@ class SkGlyph { fMaskFormat = MASK_FORMAT_UNKNOWN; fForceBW = 0; } + static unsigned ID2Code(uint32_t id) { - return (id & kCodeMask); + return id & kCodeMask; } static unsigned ID2SubX(uint32_t id) { @@ -142,6 +146,7 @@ class SkGlyph { } static uint32_t MakeID(unsigned code) { + SkASSERT(code <= kCodeMask); return code; } @@ -150,8 +155,8 @@ class SkGlyph { x = FixedToSub(x); y = FixedToSub(y); return (x << (kSubShift + kSubShiftX)) | - (y << (kSubShift + kSubShiftY)) | - code; + (y << (kSubShift + kSubShiftY)) | + code; } // FIXME - This is needed because the Android frame work directly diff --git a/src/core/SkGlyphCache.cpp b/src/core/SkGlyphCache.cpp index f0fd859385..3fe8f0ae9e 100755 --- a/src/core/SkGlyphCache.cpp +++ b/src/core/SkGlyphCache.cpp @@ -66,10 +66,14 @@ SkGlyphCache::SkGlyphCache(SkTypeface* typeface, const SkDescriptor* desc, SkSca fDesc = desc->copy(); fScalerContext->getFontMetrics(&fFontMetrics); - - // init to 0 so that all of the pointers will be null - memset(fGlyphHash, 0, sizeof(fGlyphHash)); + // Create the sentinel SkGlyph. + SkGlyph* sentinel = fGlyphArray.insert(kSentinelGlyphIndex); + sentinel->initGlyphFromCombinedID(kSentinelGlyphID); + + // Initialize all index to zero which points to the sentinel SkGlyph. + memset(fGlyphHash, 0x00, sizeof(fGlyphHash)); + fMemoryUsed = sizeof(*this); fGlyphArray.setReserve(kMinGlyphCount); @@ -106,10 +110,10 @@ SkGlyphCache::~SkGlyphCache() { } #endif - SkGlyph** gptr = fGlyphArray.begin(); - SkGlyph** stop = fGlyphArray.end(); + SkGlyph* gptr = fGlyphArray.begin(); + SkGlyph* stop = fGlyphArray.end(); while (gptr < stop) { - SkPath* path = (*gptr)->fPath; + SkPath* path = gptr->fPath; if (path) { SkDELETE(path); } @@ -122,15 +126,31 @@ SkGlyphCache::~SkGlyphCache() { SkGlyphCache::CharGlyphRec* SkGlyphCache::getCharGlyphRec(uint32_t id) { if (NULL == fCharToGlyphHash.get()) { + // Allocate the array. fCharToGlyphHash.reset(kHashCount); - // init with 0xFF so that the charCode field will be -1, which is invalid - memset(fCharToGlyphHash.get(), 0xFF, + // Initialize entries of fCharToGlyphHash to index the sentinel glyph. + memset(fCharToGlyphHash.get(), 0x00, sizeof(CharGlyphRec) * kHashCount); } return &fCharToGlyphHash[ID2HashIndex(id)]; } +void SkGlyphCache::adjustCaches(int insertion_index) { + for (int i = 0; i < kHashCount; ++i) { + if (fGlyphHash[i] >= SkToU16(insertion_index)) { + fGlyphHash[i] += 1; + } + } + if (fCharToGlyphHash.get() != NULL) { + for (int i = 0; i < kHashCount; ++i) { + if (fCharToGlyphHash[i].fGlyphIndex >= SkToU16(insertion_index)) { + fCharToGlyphHash[i].fGlyphIndex += 1; + } + } + } +} + /////////////////////////////////////////////////////////////////////////////// #ifdef SK_DEBUG @@ -145,7 +165,7 @@ uint16_t SkGlyphCache::unicharToGlyph(SkUnichar charCode) { const CharGlyphRec& rec = *this->getCharGlyphRec(id); if (rec.fID == id) { - return rec.fGlyph->getGlyphID(); + return fGlyphArray[rec.fGlyphIndex].getGlyphID(); } else { return fScalerContext->charToGlyphID(charCode); } @@ -163,159 +183,119 @@ unsigned SkGlyphCache::getGlyphCount() { const SkGlyph& SkGlyphCache::getUnicharAdvance(SkUnichar charCode) { VALIDATE(); - uint32_t id = SkGlyph::MakeID(charCode); - CharGlyphRec* rec = this->getCharGlyphRec(id); - - if (rec->fID != id) { - // this ID is based on the UniChar - rec->fID = id; - // this ID is based on the glyph index - id = SkGlyph::MakeID(fScalerContext->charToGlyphID(charCode)); - rec->fGlyph = this->lookupMetrics(id, kJustAdvance_MetricsType); - } - return *rec->fGlyph; + return *this->lookupByChar(charCode, kJustAdvance_MetricsType); } const SkGlyph& SkGlyphCache::getGlyphIDAdvance(uint16_t glyphID) { VALIDATE(); uint32_t id = SkGlyph::MakeID(glyphID); - unsigned index = ID2HashIndex(id); - SkGlyph* glyph = fGlyphHash[index]; - - if (NULL == glyph || glyph->fID != id) { - glyph = this->lookupMetrics(glyphID, kJustAdvance_MetricsType); - fGlyphHash[index] = glyph; - } - return *glyph; + return *this->lookupByCombinedID(id, kJustAdvance_MetricsType); } /////////////////////////////////////////////////////////////////////////////// const SkGlyph& SkGlyphCache::getUnicharMetrics(SkUnichar charCode) { VALIDATE(); - uint32_t id = SkGlyph::MakeID(charCode); - CharGlyphRec* rec = this->getCharGlyphRec(id); - - if (rec->fID != id) { - RecordHashCollisionIf(rec->fGlyph != NULL); - // this ID is based on the UniChar - rec->fID = id; - // this ID is based on the glyph index - id = SkGlyph::MakeID(fScalerContext->charToGlyphID(charCode)); - rec->fGlyph = this->lookupMetrics(id, kFull_MetricsType); - } else { - RecordHashSuccess(); - if (rec->fGlyph->isJustAdvance()) { - fScalerContext->getMetrics(rec->fGlyph); - } - } - SkASSERT(rec->fGlyph->isFullMetrics()); - return *rec->fGlyph; + return *this->lookupByChar(charCode, kFull_MetricsType); } const SkGlyph& SkGlyphCache::getUnicharMetrics(SkUnichar charCode, SkFixed x, SkFixed y) { VALIDATE(); + return *this->lookupByChar(charCode, kFull_MetricsType, x, y); +} + +const SkGlyph& SkGlyphCache::getGlyphIDMetrics(uint16_t glyphID) { + VALIDATE(); + uint32_t id = SkGlyph::MakeID(glyphID); + return *this->lookupByCombinedID(id, kFull_MetricsType); +} + +const SkGlyph& SkGlyphCache::getGlyphIDMetrics(uint16_t glyphID, SkFixed x, SkFixed y) { + VALIDATE(); + uint32_t id = SkGlyph::MakeID(glyphID, x, y); + return *this->lookupByCombinedID(id, kFull_MetricsType); +} + +SkGlyph* SkGlyphCache::lookupByChar(SkUnichar charCode, MetricsType type, SkFixed x, SkFixed y) { uint32_t id = SkGlyph::MakeID(charCode, x, y); CharGlyphRec* rec = this->getCharGlyphRec(id); - + SkGlyph* glyph; if (rec->fID != id) { - RecordHashCollisionIf(rec->fGlyph != NULL); + RecordHashCollisionIf(glyph_index != kSentinelGlyphIndex); // this ID is based on the UniChar rec->fID = id; // this ID is based on the glyph index id = SkGlyph::MakeID(fScalerContext->charToGlyphID(charCode), x, y); - rec->fGlyph = this->lookupMetrics(id, kFull_MetricsType); + rec->fGlyphIndex = this->lookupMetrics(id, type); + glyph = &fGlyphArray[rec->fGlyphIndex]; } else { RecordHashSuccess(); - if (rec->fGlyph->isJustAdvance()) { - fScalerContext->getMetrics(rec->fGlyph); - } - } - SkASSERT(rec->fGlyph->isFullMetrics()); - return *rec->fGlyph; -} - -const SkGlyph& SkGlyphCache::getGlyphIDMetrics(uint16_t glyphID) { - VALIDATE(); - uint32_t id = SkGlyph::MakeID(glyphID); - unsigned index = ID2HashIndex(id); - SkGlyph* glyph = fGlyphHash[index]; - - if (NULL == glyph || glyph->fID != id) { - RecordHashCollisionIf(glyph != NULL); - glyph = this->lookupMetrics(glyphID, kFull_MetricsType); - fGlyphHash[index] = glyph; - } else { - RecordHashSuccess(); - if (glyph->isJustAdvance()) { + glyph = &fGlyphArray[rec->fGlyphIndex]; + if (type == kFull_MetricsType && glyph->isJustAdvance()) { fScalerContext->getMetrics(glyph); } } - SkASSERT(glyph->isFullMetrics()); - return *glyph; + return glyph; } -const SkGlyph& SkGlyphCache::getGlyphIDMetrics(uint16_t glyphID, SkFixed x, SkFixed y) { - VALIDATE(); - uint32_t id = SkGlyph::MakeID(glyphID, x, y); - unsigned index = ID2HashIndex(id); - SkGlyph* glyph = fGlyphHash[index]; - - if (NULL == glyph || glyph->fID != id) { - RecordHashCollisionIf(glyph != NULL); - glyph = this->lookupMetrics(id, kFull_MetricsType); - fGlyphHash[index] = glyph; +SkGlyph* SkGlyphCache::lookupByCombinedID(uint32_t id, MetricsType type) { + uint32_t hash_index = ID2HashIndex(id); + uint16_t glyph_index = fGlyphHash[hash_index]; + SkGlyph* glyph = &fGlyphArray[glyph_index]; + + if (glyph->fID != id) { + RecordHashCollisionIf(glyph_index != kSentinelGlyphIndex); + glyph_index = this->lookupMetrics(id, type); + fGlyphHash[hash_index] = glyph_index; + glyph = &fGlyphArray[glyph_index]; } else { RecordHashSuccess(); - if (glyph->isJustAdvance()) { - fScalerContext->getMetrics(glyph); + if (type == kFull_MetricsType && glyph->isJustAdvance()) { + fScalerContext->getMetrics(glyph); } } - SkASSERT(glyph->isFullMetrics()); - return *glyph; + return glyph; } -SkGlyph* SkGlyphCache::lookupMetrics(uint32_t id, MetricsType mtype) { - SkGlyph* glyph; - - int hi = 0; - int count = fGlyphArray.count(); - - if (count) { - SkGlyph** gptr = fGlyphArray.begin(); - int lo = 0; - - hi = count - 1; - while (lo < hi) { - int mid = (hi + lo) >> 1; - if (gptr[mid]->fID < id) { - lo = mid + 1; - } else { - hi = mid; - } - } - glyph = gptr[hi]; - if (glyph->fID == id) { - if (kFull_MetricsType == mtype && glyph->isJustAdvance()) { - fScalerContext->getMetrics(glyph); - } - return glyph; +uint16_t SkGlyphCache::lookupMetrics(uint32_t id, MetricsType mtype) { + // Count is always greater than 0 because of the sentinel. + // The fGlyphArray cache is in descending order, so that the sentinel with a value of ~0 is + // always at index 0. + SkGlyph* gptr = fGlyphArray.begin(); + int lo = 0; + int hi = fGlyphArray.count() - 1; + while (lo < hi) { + int mid = (hi + lo) >> 1; + if (gptr[mid].fID > id) { + lo = mid + 1; + } else { + hi = mid; } + } - // check if we need to bump hi before falling though to the allocator - if (glyph->fID < id) { - hi += 1; + uint16_t glyph_index = hi; + SkGlyph* glyph = &gptr[glyph_index]; + if (glyph->fID == id) { + if (kFull_MetricsType == mtype && glyph->isJustAdvance()) { + fScalerContext->getMetrics(glyph); } + SkASSERT(glyph_index != kSentinelGlyphIndex); + return glyph_index; } - // not found, but hi tells us where to inser the new glyph + // check if we need to bump hi before falling though to the allocator + if (glyph->fID > id) { + glyph_index += 1; + } + + // Not found, but hi contains the index of the insertion point of the new glyph. fMemoryUsed += sizeof(SkGlyph); + + this->adjustCaches(glyph_index); - glyph = (SkGlyph*)fGlyphAlloc.alloc(sizeof(SkGlyph), - SkChunkAlloc::kThrow_AllocFailType); - glyph->initCommon(id); - *fGlyphArray.insert(hi) = glyph; + glyph = fGlyphArray.insert(glyph_index); + glyph->initGlyphFromCombinedID(id); if (kJustAdvance_MetricsType == mtype) { fScalerContext->getAdvance(glyph); @@ -324,7 +304,8 @@ SkGlyph* SkGlyphCache::lookupMetrics(uint32_t id, MetricsType mtype) { fScalerContext->getMetrics(glyph); } - return glyph; + SkASSERT(glyph_index != kSentinelGlyphIndex); + return glyph_index; } const void* SkGlyphCache::findImage(const SkGlyph& glyph) { diff --git a/src/core/SkGlyphCache.h b/src/core/SkGlyphCache.h index b335d29d2d..200655bb41 100644 --- a/src/core/SkGlyphCache.h +++ b/src/core/SkGlyphCache.h @@ -187,32 +187,48 @@ private: kFull_MetricsType }; - SkGlyph* lookupMetrics(uint32_t id, MetricsType); + // Return the SkGlyph* associated with MakeID. The id parameter is the combined glyph/x/y + // id generated by MakeID. If it is just a glyph id then x and y are assuemd to be zero. + SkGlyph* lookupByCombinedID(uint32_t id, MetricsType type); + + // Return a SkGlyph* associated with unicode id and position x and y. + SkGlyph* lookupByChar(SkUnichar id, MetricsType type, SkFixed x = 0, SkFixed y = 0); + + // Return the index of id in the fGlyphArray. If it does + // not exist, create a new one using MetricsType. + uint16_t lookupMetrics(uint32_t id, MetricsType type); static bool DetachProc(const SkGlyphCache*, void*) { return true; } - SkGlyphCache* fNext, *fPrev; - SkDescriptor* fDesc; - SkScalerContext* fScalerContext; + SkGlyphCache* fNext, *fPrev; + SkDescriptor* fDesc; + SkScalerContext* fScalerContext; SkPaint::FontMetrics fFontMetrics; enum { - kHashBits = 8, - kHashCount = 1 << kHashBits, - kHashMask = kHashCount - 1 + kHashBits = 8, + kHashCount = 1 << kHashBits, + kHashMask = kHashCount - 1, + kSentinelGlyphIndex = 0, + kSentinelGlyphID = ~0 }; - SkGlyph* fGlyphHash[kHashCount]; - SkTDArray<SkGlyph*> fGlyphArray; - SkChunkAlloc fGlyphAlloc; + + // A quick lookup to avoid the binary search looking for glyphs in fGlyphArray. + uint16_t fGlyphHash[kHashCount]; + SkTDArray<SkGlyph> fGlyphArray; + SkChunkAlloc fGlyphAlloc; struct CharGlyphRec { uint32_t fID; // unichar + subpixel - SkGlyph* fGlyph; + uint16_t fGlyphIndex; }; + // no reason to use the same kHashCount as fGlyphHash, but we do for now // Dynamically allocated when chars are encountered. SkAutoTArray<CharGlyphRec> fCharToGlyphHash; - + + // The id arg is a combined id generated by MakeID. CharGlyphRec* getCharGlyphRec(uint32_t id); + void adjustCaches(int insertion_index); static inline unsigned ID2HashIndex(uint32_t h) { return SkChecksum::CheapMix(h) & kHashMask; @@ -221,7 +237,6 @@ private: // used to track (approx) how much ram is tied-up in this cache size_t fMemoryUsed; - #ifdef SK_GLYPHCACHE_TRACK_HASH_STATS int fHashHitCount; int fHashMissCount; |