-
/*
* Copyright 2006 The Android Open Source Project
*
* found in the LICENSE file.
*/
-
#include "SkGlyphCache.h"
#include "SkGlyphCache_Globals.h"
#include "SkGraphics.h"
#include "SkTypeface.h"
//#define SPEW_PURGE_STATUS
-//#define RECORD_HASH_EFFICIENCY
namespace {
///////////////////////////////////////////////////////////////////////////////
-#ifdef RECORD_HASH_EFFICIENCY
- static uint32_t gHashSuccess;
- static uint32_t gHashCollision;
-
- static void RecordHashSuccess() {
- gHashSuccess += 1;
- }
-
- static void RecordHashCollisionIf(bool pred) {
- if (pred) {
- gHashCollision += 1;
-
- uint32_t total = gHashSuccess + gHashCollision;
- SkDebugf("Font Cache Hash success rate: %d%%\n",
- 100 * gHashSuccess / total);
- }
- }
+#ifdef SK_GLYPHCACHE_TRACK_HASH_STATS
+ #define RecordHashSuccess() fHashHitCount += 1
+ #define RecordHashCollisionIf(pred) do { if (pred) fHashMissCount += 1; } while (0)
#else
- #define RecordHashSuccess() (void)0
- #define RecordHashCollisionIf(pred) (void)0
+ #define RecordHashSuccess() (void)0
+ #define RecordHashCollisionIf(pred) (void)0
#endif
#define RecordHashCollision() RecordHashCollisionIf(true)
fGlyphArray.setReserve(kMinGlyphCount);
fAuxProcList = NULL;
+
+#ifdef SK_GLYPHCACHE_TRACK_HASH_STATS
+ fHashHitCount = fHashMissCount = 0;
+#endif
}
SkGlyphCache::~SkGlyphCache() {
return *glyph;
}
-const SkGlyph& SkGlyphCache::getGlyphIDMetrics(uint16_t glyphID,
- SkFixed x, SkFixed y) {
+const SkGlyph& SkGlyphCache::getGlyphIDMetrics(uint16_t glyphID, SkFixed x, SkFixed y) {
VALIDATE();
uint32_t id = SkGlyph::MakeID(glyphID, x, y);
unsigned index = ID2HashIndex(id);
return glyph.fPath;
}
+void SkGlyphCache::dump() const {
+ const SkTypeface* face = fScalerContext->getTypeface();
+ const SkScalerContextRec& rec = fScalerContext->getRec();
+ SkMatrix matrix;
+ rec.getSingleMatrix(&matrix);
+ matrix.preScale(SkScalarInvert(rec.fTextSize), SkScalarInvert(rec.fTextSize));
+ SkString name;
+ face->getFamilyName(&name);
+
+ SkString msg;
+ msg.printf("cache typeface:%x %25s:%d size:%2g [%g %g %g %g] lum:%02X devG:%d pntG:%d cntr:%d glyphs:%3d",
+ face->uniqueID(), name.c_str(), face->style(), rec.fTextSize,
+ matrix[SkMatrix::kMScaleX], matrix[SkMatrix::kMSkewX],
+ matrix[SkMatrix::kMSkewY], matrix[SkMatrix::kMScaleY],
+ rec.fLumBits & 0xFF, rec.fDeviceGamma, rec.fPaintGamma, rec.fContrast,
+ fGlyphArray.count());
+#ifdef SK_GLYPHCACHE_TRACK_HASH_STATS
+ const int sum = SkTMax(fHashHitCount + fHashMissCount, 1); // avoid divide-by-zero
+ msg.appendf(" hash:%2d\n", 100 * fHashHitCount / sum);
+#endif
+ SkDebugf("%s\n", msg.c_str());
+}
+
///////////////////////////////////////////////////////////////////////////////
bool SkGlyphCache::getAuxProcData(void (*proc)(void*), void** dataPtr) const {
getGlobals().attachCacheToHead(cache);
}
+void SkGlyphCache::Dump() {
+ SkGlyphCache_Globals& globals = getGlobals();
+ SkAutoMutexAcquire ac(globals.fMutex);
+ SkGlyphCache* cache;
+
+ globals.validate();
+
+ SkDebugf("SkGlyphCache strikes:%d memory:%d\n",
+ globals.getCacheCountUsed(), (int)globals.getTotalMemoryUsed());
+
+#ifdef SK_GLYPHCACHE_TRACK_HASH_STATS
+ int hitCount = 0;
+ int missCount = 0;
+#endif
+
+ for (cache = globals.internalGetHead(); cache != NULL; cache = cache->fNext) {
+#ifdef SK_GLYPHCACHE_TRACK_HASH_STATS
+ hitCount += cache->fHashHitCount;
+ missCount += cache->fHashMissCount;
+#endif
+ cache->dump();
+ }
+#ifdef SK_GLYPHCACHE_TRACK_HASH_STATS
+ SkDebugf("Hash hit percent:%2d\n", 100 * hitCount / (hitCount + missCount));
+#endif
+}
+
///////////////////////////////////////////////////////////////////////////////
void SkGlyphCache_Globals::attachCacheToHead(SkGlyphCache* cache) {
-
/*
* Copyright 2006 The Android Open Source Project
*
* found in the LICENSE file.
*/
-
#ifndef SkGlyphCache_DEFINED
#define SkGlyphCache_DEFINED
#include "SkBitmap.h"
+#include "SkChecksum.h"
#include "SkChunkAlloc.h"
#include "SkDescriptor.h"
#include "SkGlyph.h"
class SkGlyphCache_Globals;
+// Enable this locally to add stats for hash-table hit rates. It also extends the dump()
+// output to show those stats.
+//#define SK_GLYPHCACHE_TRACK_HASH_STATS
+
/** \class SkGlyphCache
This class represents a strike: a specific combination of typeface, size,
return fScalerContext->isSubpixel();
}
+ void dump() const;
+
/* AuxProc/Data allow a client to associate data with this cache entry.
Multiple clients can use this, as their data is keyed with a function
pointer. In addition to serving as a key, the function pointer is called
return VisitCache(typeface, desc, DetachProc, NULL);
}
+ static void Dump();
+
#ifdef SK_DEBUG
void validate() const;
#else
// no reason to use the same kHashCount as fGlyphHash, but we do for now
CharGlyphRec fCharToGlyphHash[kHashCount];
- static inline unsigned ID2HashIndex(uint32_t id) {
- id ^= id >> 16;
- id ^= id >> 8;
- return id & kHashMask;
+ static inline unsigned ID2HashIndex(uint32_t h) {
+ return SkChecksum::CheapMix(h) & kHashMask;
}
// 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;
+#endif
+
struct AuxProcRec {
AuxProcRec* fNext;
void (*fProc)(void*);