diff options
author | Romain Guy <romainguy@google.com> | 2012-11-28 17:35:51 -0800 |
---|---|---|
committer | Romain Guy <romainguy@google.com> | 2012-11-29 11:44:02 -0800 |
commit | 059e12ccd20f5c249724a8362d6bac325334ea76 (patch) | |
tree | 7b15fa6bc6d2963715ea298a51cca3909c1e50c9 /libs | |
parent | c653df46436a796556da2633f90353900344ce39 (diff) | |
download | frameworks_base-059e12ccd20f5c249724a8362d6bac325334ea76.zip frameworks_base-059e12ccd20f5c249724a8362d6bac325334ea76.tar.gz frameworks_base-059e12ccd20f5c249724a8362d6bac325334ea76.tar.bz2 |
Use LruCache instead of GenerationCache in libhwui
Change-Id: Ic26ddc7151eb5462bcd243b21daf7187ed6d3bec
Diffstat (limited to 'libs')
-rw-r--r-- | libs/hwui/GradientCache.cpp | 32 | ||||
-rw-r--r-- | libs/hwui/GradientCache.h | 46 | ||||
-rw-r--r-- | libs/hwui/PathCache.cpp | 19 | ||||
-rw-r--r-- | libs/hwui/PathCache.h | 22 | ||||
-rw-r--r-- | libs/hwui/ShapeCache.h | 327 | ||||
-rw-r--r-- | libs/hwui/TextDropShadowCache.cpp | 68 | ||||
-rw-r--r-- | libs/hwui/TextDropShadowCache.h | 96 | ||||
-rw-r--r-- | libs/hwui/TextureCache.cpp | 4 | ||||
-rw-r--r-- | libs/hwui/TextureCache.h | 4 |
9 files changed, 421 insertions, 197 deletions
diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp index 2e4e349..35a8487 100644 --- a/libs/hwui/GradientCache.cpp +++ b/libs/hwui/GradientCache.cpp @@ -16,6 +16,7 @@ #define LOG_TAG "OpenGLRenderer" +#include <utils/JenkinsHash.h> #include <utils/threads.h> #include "Caches.h" @@ -43,11 +44,38 @@ static inline T min(T a, T b) { } /////////////////////////////////////////////////////////////////////////////// +// Cache entry +/////////////////////////////////////////////////////////////////////////////// + +hash_t GradientCacheEntry::hash() const { + uint32_t hash = JenkinsHashMix(0, count); + hash = JenkinsHashMix(hash, tileMode); + for (uint32_t i = 0; i < count; i++) { + hash = JenkinsHashMix(hash, android::hash_type(colors[i])); + hash = JenkinsHashMix(hash, android::hash_type(positions[i])); + } + return JenkinsHashWhiten(hash); +} + +int GradientCacheEntry::compare(const GradientCacheEntry& lhs, const GradientCacheEntry& rhs) { + int deltaInt = int(lhs.count) - int(rhs.count); + if (deltaInt != 0) return deltaInt; + + deltaInt = lhs.tileMode - rhs.tileMode; + if (deltaInt != 0) return deltaInt; + + deltaInt = memcmp(lhs.colors, rhs.colors, lhs.count * sizeof(uint32_t)); + if (deltaInt != 0) return deltaInt; + + return memcmp(lhs.positions, rhs.positions, lhs.count * sizeof(float)); +} + +/////////////////////////////////////////////////////////////////////////////// // Constructors/destructor /////////////////////////////////////////////////////////////////////////////// GradientCache::GradientCache(): - mCache(GenerationCache<GradientCacheEntry, Texture*>::kUnlimitedCapacity), + mCache(LruCache<GradientCacheEntry, Texture*>::kUnlimitedCapacity), mSize(0), mMaxSize(MB(DEFAULT_GRADIENT_CACHE_SIZE)) { char property[PROPERTY_VALUE_MAX]; if (property_get(PROPERTY_GRADIENT_CACHE_SIZE, property, NULL) > 0) { @@ -63,7 +91,7 @@ GradientCache::GradientCache(): } GradientCache::GradientCache(uint32_t maxByteSize): - mCache(GenerationCache<GradientCacheEntry, Texture*>::kUnlimitedCapacity), + mCache(LruCache<GradientCacheEntry, Texture*>::kUnlimitedCapacity), mSize(0), mMaxSize(maxByteSize) { mCache.setOnEntryRemovedListener(this); } diff --git a/libs/hwui/GradientCache.h b/libs/hwui/GradientCache.h index 3b7c1fa..d183a85 100644 --- a/libs/hwui/GradientCache.h +++ b/libs/hwui/GradientCache.h @@ -21,12 +21,11 @@ #include <SkShader.h> +#include <utils/LruCache.h> #include <utils/Mutex.h> #include <utils/Vector.h> #include "Texture.h" -#include "utils/Compare.h" -#include "utils/GenerationCache.h" namespace android { namespace uirenderer { @@ -38,7 +37,7 @@ struct GradientCacheEntry { positions = NULL; } - GradientCacheEntry(uint32_t* colors, float* positions, int count) { + GradientCacheEntry(uint32_t* colors, float* positions, uint32_t count) { copy(colors, positions, count); } @@ -62,27 +61,26 @@ struct GradientCacheEntry { return *this; } - bool operator<(const GradientCacheEntry& r) const { - const GradientCacheEntry& rhs = (const GradientCacheEntry&) r; - LTE_INT(count) { - int result = memcmp(colors, rhs.colors, count * sizeof(uint32_t)); - if (result< 0) return true; - else if (result == 0) { - result = memcmp(positions, rhs.positions, count * sizeof(float)); - if (result < 0) return true; - } - } - return false; + hash_t hash() const; + + static int compare(const GradientCacheEntry& lhs, const GradientCacheEntry& rhs); + + bool operator==(const GradientCacheEntry& other) const { + return compare(*this, other) == 0; + } + + bool operator!=(const GradientCacheEntry& other) const { + return compare(*this, other) != 0; } uint32_t* colors; float* positions; - int count; + uint32_t count; SkShader::TileMode tileMode; private: - void copy(uint32_t* colors, float* positions, int count) { + void copy(uint32_t* colors, float* positions, uint32_t count) { this->count = count; this->colors = new uint32_t[count]; this->positions = new float[count]; @@ -93,6 +91,20 @@ private: }; // GradientCacheEntry +// Caching support + +inline int strictly_order_type(const GradientCacheEntry& lhs, const GradientCacheEntry& rhs) { + return GradientCacheEntry::compare(lhs, rhs) < 0; +} + +inline int compare_type(const GradientCacheEntry& lhs, const GradientCacheEntry& rhs) { + return GradientCacheEntry::compare(lhs, rhs); +} + +inline hash_t hash_type(const GradientCacheEntry& entry) { + return entry.hash(); +} + /** * A simple LRU gradient cache. The cache has a maximum size expressed in bytes. * Any texture added to the cache causing the cache to grow beyond the maximum @@ -150,7 +162,7 @@ private: void getGradientInfo(const uint32_t* colors, const int count, GradientInfo& info); - GenerationCache<GradientCacheEntry, Texture*> mCache; + LruCache<GradientCacheEntry, Texture*> mCache; uint32_t mSize; uint32_t mMaxSize; diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp index 71a4ed7..03ddf59 100644 --- a/libs/hwui/PathCache.cpp +++ b/libs/hwui/PathCache.cpp @@ -55,22 +55,19 @@ PathCache::PathCache(): ShapeCache<PathCacheEntry>("path", } void PathCache::remove(SkPath* path) { - // TODO: Linear search... - Vector<size_t> pathsToRemove; - for (size_t i = 0; i < mCache.size(); i++) { - if (mCache.getKeyAt(i).path == path) { - pathsToRemove.push(i); - removeTexture(mCache.getValueAt(i)); + Vector<PathCacheEntry> pathsToRemove; + LruCache<PathCacheEntry, PathTexture*>::Iterator i(mCache); + + while (i.next()) { + const PathCacheEntry& key = i.key(); + if (key.path == path) { + pathsToRemove.push(key); } } - mCache.setOnEntryRemovedListener(NULL); for (size_t i = 0; i < pathsToRemove.size(); i++) { - // This will work because pathsToRemove is sorted - // and because the cache is a sorted keyed vector - mCache.removeAt(pathsToRemove.itemAt(i) - i); + mCache.remove(pathsToRemove.itemAt(i)); } - mCache.setOnEntryRemovedListener(this); } void PathCache::removeDeferred(SkPath* path) { diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h index 4904a58..8a0235b 100644 --- a/libs/hwui/PathCache.h +++ b/libs/hwui/PathCache.h @@ -22,8 +22,6 @@ #include "Debug.h" #include "ShapeCache.h" -#include "utils/Compare.h" - namespace android { namespace uirenderer { @@ -41,18 +39,28 @@ struct PathCacheEntry: public ShapeCacheEntry { path = NULL; } - bool lessThan(const ShapeCacheEntry& r) const { + hash_t hash() const { + uint32_t hash = ShapeCacheEntry::hash(); + hash = JenkinsHashMix(hash, android::hash_type(path)); + return JenkinsHashWhiten(hash); + } + + int compare(const ShapeCacheEntry& r) const { + int deltaInt = ShapeCacheEntry::compare(r); + if (deltaInt != 0) return deltaInt; + const PathCacheEntry& rhs = (const PathCacheEntry&) r; - LTE_INT(path) { - return false; - } - return false; + return path - rhs.path; } SkPath* path; }; // PathCacheEntry +inline hash_t hash_type(const PathCacheEntry& entry) { + return entry.hash(); +} + /** * A simple LRU path cache. The cache has a maximum size expressed in bytes. * Any texture added to the cache causing the cache to grow beyond the maximum diff --git a/libs/hwui/ShapeCache.h b/libs/hwui/ShapeCache.h index 3a95b99..47cab83 100644 --- a/libs/hwui/ShapeCache.h +++ b/libs/hwui/ShapeCache.h @@ -25,11 +25,12 @@ #include <SkPath.h> #include <SkRect.h> +#include <utils/JenkinsHash.h> +#include <utils/LruCache.h> + #include "Debug.h" #include "Properties.h" #include "Texture.h" -#include "utils/Compare.h" -#include "utils/GenerationCache.h" namespace android { namespace uirenderer { @@ -89,10 +90,8 @@ struct ShapeCacheEntry { join = SkPaint::kDefault_Join; cap = SkPaint::kDefault_Cap; style = SkPaint::kFill_Style; - float v = 4.0f; - miter = *(uint32_t*) &v; - v = 1.0f; - strokeWidth = *(uint32_t*) &v; + miter = 4.0f; + strokeWidth = 1.0f; pathEffect = NULL; } @@ -100,10 +99,8 @@ struct ShapeCacheEntry { shapeType = type; join = paint->getStrokeJoin(); cap = paint->getStrokeCap(); - float v = paint->getStrokeMiter(); - miter = *(uint32_t*) &v; - v = paint->getStrokeWidth(); - strokeWidth = *(uint32_t*) &v; + miter = paint->getStrokeMiter(); + strokeWidth = paint->getStrokeWidth(); style = paint->getStyle(); pathEffect = paint->getPathEffect(); } @@ -111,47 +108,80 @@ struct ShapeCacheEntry { virtual ~ShapeCacheEntry() { } + virtual hash_t hash() const { + uint32_t hash = JenkinsHashMix(0, shapeType); + hash = JenkinsHashMix(hash, join); + hash = JenkinsHashMix(hash, cap); + hash = JenkinsHashMix(hash, style); + hash = JenkinsHashMix(hash, android::hash_type(miter)); + hash = JenkinsHashMix(hash, android::hash_type(strokeWidth)); + hash = JenkinsHashMix(hash, android::hash_type(pathEffect)); + return JenkinsHashWhiten(hash); + } + + virtual int compare(const ShapeCacheEntry& rhs) const { + int deltaInt = shapeType - rhs.shapeType; + if (deltaInt != 0) return deltaInt; + + deltaInt = join - rhs.join; + if (deltaInt != 0) return deltaInt; + + deltaInt = cap - rhs.cap; + if (deltaInt != 0) return deltaInt; + + deltaInt = style - rhs.style; + if (deltaInt != 0) return deltaInt; + + if (miter < rhs.miter) return -1; + if (miter > rhs.miter) return +1; + + if (strokeWidth < rhs.strokeWidth) return -1; + if (strokeWidth > rhs.strokeWidth) return +1; + + if (pathEffect < rhs.pathEffect) return -1; + if (pathEffect > rhs.pathEffect) return +1; + + return 0; + } + + bool operator==(const ShapeCacheEntry& other) const { + return compare(other) == 0; + } + + bool operator!=(const ShapeCacheEntry& other) const { + return compare(other) != 0; + } + ShapeType shapeType; SkPaint::Join join; SkPaint::Cap cap; SkPaint::Style style; - uint32_t miter; - uint32_t strokeWidth; + float miter; + float strokeWidth; SkPathEffect* pathEffect; +}; // struct ShapeCacheEntry - bool operator<(const ShapeCacheEntry& rhs) const { - LTE_INT(shapeType) { - LTE_INT(join) { - LTE_INT(cap) { - LTE_INT(style) { - LTE_INT(miter) { - LTE_INT(strokeWidth) { - LTE_INT(pathEffect) { - return lessThan(rhs); - } - } - } - } - } - } - } - return false; - } +// Cache support -protected: - virtual bool lessThan(const ShapeCacheEntry& rhs) const { - return false; - } -}; // struct ShapeCacheEntry +inline int strictly_order_type(const ShapeCacheEntry& lhs, const ShapeCacheEntry& rhs) { + return lhs.compare(rhs) < 0; +} + +inline int compare_type(const ShapeCacheEntry& lhs, const ShapeCacheEntry& rhs) { + return lhs.compare(rhs); +} +inline hash_t hash_type(const ShapeCacheEntry& entry) { + return entry.hash(); +} struct RoundRectShapeCacheEntry: public ShapeCacheEntry { RoundRectShapeCacheEntry(float width, float height, float rx, float ry, SkPaint* paint): ShapeCacheEntry(ShapeCacheEntry::kShapeRoundRect, paint) { - mWidth = *(uint32_t*) &width; - mHeight = *(uint32_t*) &height; - mRx = *(uint32_t*) ℞ - mRy = *(uint32_t*) &ry; + mWidth = width; + mHeight = height; + mRx = rx; + mRy = ry; } RoundRectShapeCacheEntry(): ShapeCacheEntry() { @@ -161,109 +191,175 @@ struct RoundRectShapeCacheEntry: public ShapeCacheEntry { mRy = 0; } - bool lessThan(const ShapeCacheEntry& r) const { + hash_t hash() const { + uint32_t hash = ShapeCacheEntry::hash(); + hash = JenkinsHashMix(hash, android::hash_type(mWidth)); + hash = JenkinsHashMix(hash, android::hash_type(mHeight)); + hash = JenkinsHashMix(hash, android::hash_type(mRx)); + hash = JenkinsHashMix(hash, android::hash_type(mRy)); + return JenkinsHashWhiten(hash); + } + + int compare(const ShapeCacheEntry& r) const { + int deltaInt = ShapeCacheEntry::compare(r); + if (deltaInt != 0) return deltaInt; + const RoundRectShapeCacheEntry& rhs = (const RoundRectShapeCacheEntry&) r; - LTE_INT(mWidth) { - LTE_INT(mHeight) { - LTE_INT(mRx) { - LTE_INT(mRy) { - return false; - } - } - } - } - return false; + + if (mWidth < rhs.mWidth) return -1; + if (mWidth > rhs.mWidth) return +1; + + if (mHeight < rhs.mHeight) return -1; + if (mHeight > rhs.mHeight) return +1; + + if (mRx < rhs.mRx) return -1; + if (mRx > rhs.mRx) return +1; + + if (mRy < rhs.mRy) return -1; + if (mRy > rhs.mRy) return +1; + + return 0; } private: - uint32_t mWidth; - uint32_t mHeight; - uint32_t mRx; - uint32_t mRy; + float mWidth; + float mHeight; + float mRx; + float mRy; }; // RoundRectShapeCacheEntry +inline hash_t hash_type(const RoundRectShapeCacheEntry& entry) { + return entry.hash(); +} + struct CircleShapeCacheEntry: public ShapeCacheEntry { CircleShapeCacheEntry(float radius, SkPaint* paint): ShapeCacheEntry(ShapeCacheEntry::kShapeCircle, paint) { - mRadius = *(uint32_t*) &radius; + mRadius = radius; } CircleShapeCacheEntry(): ShapeCacheEntry() { mRadius = 0; } - bool lessThan(const ShapeCacheEntry& r) const { + hash_t hash() const { + uint32_t hash = ShapeCacheEntry::hash(); + hash = JenkinsHashMix(hash, android::hash_type(mRadius)); + return JenkinsHashWhiten(hash); + } + + int compare(const ShapeCacheEntry& r) const { + int deltaInt = ShapeCacheEntry::compare(r); + if (deltaInt != 0) return deltaInt; + const CircleShapeCacheEntry& rhs = (const CircleShapeCacheEntry&) r; - LTE_INT(mRadius) { - return false; - } - return false; + + if (mRadius < rhs.mRadius) return -1; + if (mRadius > rhs.mRadius) return +1; + + return 0; } private: - uint32_t mRadius; + float mRadius; }; // CircleShapeCacheEntry +inline hash_t hash_type(const CircleShapeCacheEntry& entry) { + return entry.hash(); +} + struct OvalShapeCacheEntry: public ShapeCacheEntry { OvalShapeCacheEntry(float width, float height, SkPaint* paint): ShapeCacheEntry(ShapeCacheEntry::kShapeOval, paint) { - mWidth = *(uint32_t*) &width; - mHeight = *(uint32_t*) &height; + mWidth = width; + mHeight = height; } OvalShapeCacheEntry(): ShapeCacheEntry() { mWidth = mHeight = 0; } - bool lessThan(const ShapeCacheEntry& r) const { + hash_t hash() const { + uint32_t hash = ShapeCacheEntry::hash(); + hash = JenkinsHashMix(hash, android::hash_type(mWidth)); + hash = JenkinsHashMix(hash, android::hash_type(mHeight)); + return JenkinsHashWhiten(hash); + } + + int compare(const ShapeCacheEntry& r) const { + int deltaInt = ShapeCacheEntry::compare(r); + if (deltaInt != 0) return deltaInt; + const OvalShapeCacheEntry& rhs = (const OvalShapeCacheEntry&) r; - LTE_INT(mWidth) { - LTE_INT(mHeight) { - return false; - } - } - return false; + + if (mWidth < rhs.mWidth) return -1; + if (mWidth > rhs.mWidth) return +1; + + if (mHeight < rhs.mHeight) return -1; + if (mHeight > rhs.mHeight) return +1; + + return 0; } private: - uint32_t mWidth; - uint32_t mHeight; + float mWidth; + float mHeight; }; // OvalShapeCacheEntry +inline hash_t hash_type(const OvalShapeCacheEntry& entry) { + return entry.hash(); +} + struct RectShapeCacheEntry: public ShapeCacheEntry { RectShapeCacheEntry(float width, float height, SkPaint* paint): ShapeCacheEntry(ShapeCacheEntry::kShapeRect, paint) { - mWidth = *(uint32_t*) &width; - mHeight = *(uint32_t*) &height; + mWidth = width; + mHeight = height; } RectShapeCacheEntry(): ShapeCacheEntry() { mWidth = mHeight = 0; } - bool lessThan(const ShapeCacheEntry& r) const { + hash_t hash() const { + uint32_t hash = ShapeCacheEntry::hash(); + hash = JenkinsHashMix(hash, android::hash_type(mWidth)); + hash = JenkinsHashMix(hash, android::hash_type(mHeight)); + return JenkinsHashWhiten(hash); + } + + int compare(const ShapeCacheEntry& r) const { + int deltaInt = ShapeCacheEntry::compare(r); + if (deltaInt != 0) return deltaInt; + const RectShapeCacheEntry& rhs = (const RectShapeCacheEntry&) r; - LTE_INT(mWidth) { - LTE_INT(mHeight) { - return false; - } - } - return false; + + if (mWidth < rhs.mWidth) return -1; + if (mWidth > rhs.mWidth) return +1; + + if (mHeight < rhs.mHeight) return -1; + if (mHeight > rhs.mHeight) return +1; + + return 0; } private: - uint32_t mWidth; - uint32_t mHeight; + float mWidth; + float mHeight; }; // RectShapeCacheEntry +inline hash_t hash_type(const RectShapeCacheEntry& entry) { + return entry.hash(); +} + struct ArcShapeCacheEntry: public ShapeCacheEntry { ArcShapeCacheEntry(float width, float height, float startAngle, float sweepAngle, bool useCenter, SkPaint* paint): ShapeCacheEntry(ShapeCacheEntry::kShapeArc, paint) { - mWidth = *(uint32_t*) &width; - mHeight = *(uint32_t*) &height; - mStartAngle = *(uint32_t*) &startAngle; - mSweepAngle = *(uint32_t*) &sweepAngle; + mWidth = width; + mHeight = height; + mStartAngle = startAngle; + mSweepAngle = sweepAngle; mUseCenter = useCenter ? 1 : 0; } @@ -275,30 +371,49 @@ struct ArcShapeCacheEntry: public ShapeCacheEntry { mUseCenter = 0; } - bool lessThan(const ShapeCacheEntry& r) const { + hash_t hash() const { + uint32_t hash = ShapeCacheEntry::hash(); + hash = JenkinsHashMix(hash, android::hash_type(mWidth)); + hash = JenkinsHashMix(hash, android::hash_type(mHeight)); + hash = JenkinsHashMix(hash, android::hash_type(mStartAngle)); + hash = JenkinsHashMix(hash, android::hash_type(mSweepAngle)); + hash = JenkinsHashMix(hash, mUseCenter); + return JenkinsHashWhiten(hash); + } + + int compare(const ShapeCacheEntry& r) const { + int deltaInt = ShapeCacheEntry::compare(r); + if (deltaInt != 0) return deltaInt; + const ArcShapeCacheEntry& rhs = (const ArcShapeCacheEntry&) r; - LTE_INT(mWidth) { - LTE_INT(mHeight) { - LTE_INT(mStartAngle) { - LTE_INT(mSweepAngle) { - LTE_INT(mUseCenter) { - return false; - } - } - } - } - } - return false; + + if (mWidth < rhs.mWidth) return -1; + if (mWidth > rhs.mWidth) return +1; + + if (mHeight < rhs.mHeight) return -1; + if (mHeight > rhs.mHeight) return +1; + + if (mStartAngle < rhs.mStartAngle) return -1; + if (mStartAngle > rhs.mStartAngle) return +1; + + if (mSweepAngle < rhs.mSweepAngle) return -1; + if (mSweepAngle > rhs.mSweepAngle) return +1; + + return mUseCenter - rhs.mUseCenter; } private: - uint32_t mWidth; - uint32_t mHeight; - uint32_t mStartAngle; - uint32_t mSweepAngle; + float mWidth; + float mHeight; + float mStartAngle; + float mSweepAngle; uint32_t mUseCenter; }; // ArcShapeCacheEntry +inline hash_t hash_type(const ArcShapeCacheEntry& entry) { + return entry.hash(); +} + /** * A simple LRU shape cache. The cache has a maximum size expressed in bytes. * Any texture added to the cache causing the cache to grow beyond the maximum @@ -356,7 +471,7 @@ protected: void removeTexture(PathTexture* texture); - GenerationCache<Entry, PathTexture*> mCache; + LruCache<Entry, PathTexture*> mCache; uint32_t mSize; uint32_t mMaxSize; GLuint mMaxTextureSize; @@ -415,7 +530,7 @@ public: template<class Entry> ShapeCache<Entry>::ShapeCache(const char* name, const char* propertyName, float defaultSize): - mCache(GenerationCache<ShapeCacheEntry, PathTexture*>::kUnlimitedCapacity), + mCache(LruCache<ShapeCacheEntry, PathTexture*>::kUnlimitedCapacity), mSize(0), mMaxSize(MB(defaultSize)) { char property[PROPERTY_VALUE_MAX]; if (property_get(propertyName, property, NULL) > 0) { diff --git a/libs/hwui/TextDropShadowCache.cpp b/libs/hwui/TextDropShadowCache.cpp index 8426f58..4d80f73 100644 --- a/libs/hwui/TextDropShadowCache.cpp +++ b/libs/hwui/TextDropShadowCache.cpp @@ -16,6 +16,8 @@ #define LOG_TAG "OpenGLRenderer" +#include <utils/JenkinsHash.h> + #include "Debug.h" #include "TextDropShadowCache.h" #include "Properties.h" @@ -24,11 +26,71 @@ namespace android { namespace uirenderer { /////////////////////////////////////////////////////////////////////////////// +// Cache support +/////////////////////////////////////////////////////////////////////////////// + +hash_t ShadowText::hash() const { + uint32_t charCount = len * sizeof(char16_t); + uint32_t hash = JenkinsHashMix(0, len); + hash = JenkinsHashMix(hash, android::hash_type(radius)); + hash = JenkinsHashMix(hash, android::hash_type(textSize)); + hash = JenkinsHashMix(hash, android::hash_type(typeface)); + hash = JenkinsHashMix(hash, flags); + hash = JenkinsHashMix(hash, android::hash_type(italicStyle)); + hash = JenkinsHashMix(hash, android::hash_type(scaleX)); + hash = JenkinsHashMixShorts(hash, text, charCount); + for (uint32_t i = 0; i < charCount * 2; i++) { + hash = JenkinsHashMix(hash, android::hash_type(positions[i])); + } + return JenkinsHashWhiten(hash); +} + +int ShadowText::compare(const ShadowText& lhs, const ShadowText& rhs) { + int deltaInt = int(lhs.len) - int(rhs.len); + if (deltaInt != 0) return deltaInt; + + deltaInt = lhs.flags - rhs.flags; + if (deltaInt != 0) return deltaInt; + + if (lhs.radius < rhs.radius) return -1; + if (lhs.radius > rhs.radius) return +1; + + if (lhs.typeface < rhs.typeface) return -1; + if (lhs.typeface > rhs.typeface) return +1; + + if (lhs.textSize < rhs.textSize) return -1; + if (lhs.textSize > rhs.textSize) return +1; + + if (lhs.italicStyle < rhs.italicStyle) return -1; + if (lhs.italicStyle > rhs.italicStyle) return +1; + + if (lhs.scaleX < rhs.scaleX) return -1; + if (lhs.scaleX > rhs.scaleX) return +1; + + if (lhs.text != rhs.text) { + if (!lhs.text) return -1; + if (!rhs.text) return +1; + + deltaInt = memcmp(lhs.text, rhs.text, lhs.len); + if (deltaInt != 0) return deltaInt; + } + + if (lhs.positions != rhs.positions) { + if (!lhs.positions) return -1; + if (!rhs.positions) return +1; + + return memcmp(lhs.positions, rhs.positions, lhs.len << 2); + } + + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// // Constructors/destructor /////////////////////////////////////////////////////////////////////////////// TextDropShadowCache::TextDropShadowCache(): - mCache(GenerationCache<ShadowText, ShadowTexture*>::kUnlimitedCapacity), + mCache(LruCache<ShadowText, ShadowTexture*>::kUnlimitedCapacity), mSize(0), mMaxSize(MB(DEFAULT_DROP_SHADOW_CACHE_SIZE)) { char property[PROPERTY_VALUE_MAX]; if (property_get(PROPERTY_DROP_SHADOW_CACHE_SIZE, property, NULL) > 0) { @@ -43,7 +105,7 @@ TextDropShadowCache::TextDropShadowCache(): } TextDropShadowCache::TextDropShadowCache(uint32_t maxByteSize): - mCache(GenerationCache<ShadowText, ShadowTexture*>::kUnlimitedCapacity), + mCache(LruCache<ShadowText, ShadowTexture*>::kUnlimitedCapacity), mSize(0), mMaxSize(maxByteSize) { init(); } @@ -102,7 +164,7 @@ void TextDropShadowCache::clear() { } ShadowTexture* TextDropShadowCache::get(SkPaint* paint, const char* text, uint32_t len, - int numGlyphs, uint32_t radius, const float* positions) { + int numGlyphs, float radius, const float* positions) { ShadowText entry(paint, radius, len, text, positions); ShadowTexture* texture = mCache.get(entry); diff --git a/libs/hwui/TextDropShadowCache.h b/libs/hwui/TextDropShadowCache.h index bae0c49..38bf05a 100644 --- a/libs/hwui/TextDropShadowCache.h +++ b/libs/hwui/TextDropShadowCache.h @@ -21,10 +21,9 @@ #include <SkPaint.h> +#include <utils/LruCache.h> #include <utils/String16.h> -#include "utils/Compare.h" -#include "utils/GenerationCache.h" #include "FontRenderer.h" #include "Texture.h" @@ -32,12 +31,13 @@ namespace android { namespace uirenderer { struct ShadowText { - ShadowText(): radius(0), len(0), textSize(0.0f), typeface(NULL) { + ShadowText(): len(0), radius(0.0f), textSize(0.0f), typeface(NULL), + flags(0), italicStyle(0.0f), scaleX(0), text(NULL), positions(NULL) { } - ShadowText(SkPaint* paint, uint32_t radius, uint32_t len, const char* srcText, + ShadowText(SkPaint* paint, float radius, uint32_t len, const char* srcText, const float* positions): - radius(radius), len(len), positions(positions) { + len(len), radius(radius), positions(positions) { // TODO: Propagate this through the API, we should not cast here text = (const char16_t*) srcText; @@ -49,30 +49,27 @@ struct ShadowText { flags |= Font::kFakeBold; } - const float skewX = paint->getTextSkewX(); - italicStyle = *(uint32_t*) &skewX; - - const float scaleXFloat = paint->getTextScaleX(); - scaleX = *(uint32_t*) &scaleXFloat; + italicStyle = paint->getTextSkewX(); + scaleX = paint->getTextScaleX(); } ~ShadowText() { } - uint32_t radius; - uint32_t len; - float textSize; - SkTypeface* typeface; - uint32_t flags; - uint32_t italicStyle; - uint32_t scaleX; - const char16_t* text; - const float* positions; - String16 str; - Vector<float> positionsCopy; + hash_t hash() const; + + static int compare(const ShadowText& lhs, const ShadowText& rhs); + + bool operator==(const ShadowText& other) const { + return compare(*this, other) == 0; + } + + bool operator!=(const ShadowText& other) const { + return compare(*this, other) != 0; + } void copyTextLocally() { - str.setTo((const char16_t*) text, len >> 1); + str.setTo((const char16_t*) text, len * sizeof(char16_t)); text = str.string(); if (positions != NULL) { positionsCopy.clear(); @@ -81,31 +78,36 @@ struct ShadowText { } } - bool operator<(const ShadowText& rhs) const { - LTE_INT(len) { - LTE_INT(radius) { - LTE_FLOAT(textSize) { - LTE_INT(typeface) { - LTE_INT(flags) { - LTE_INT(italicStyle) { - LTE_INT(scaleX) { - int cmp = memcmp(text, rhs.text, len); - if (cmp < 0) return true; - if (cmp == 0 && rhs.positions != NULL) { - if (positions == NULL) return true; - return memcmp(positions, rhs.positions, len << 2) < 0; - } - } - } - } - } - } - } - } - return false; - } + uint32_t len; + float radius; + float textSize; + SkTypeface* typeface; + uint32_t flags; + float italicStyle; + float scaleX; + const char16_t* text; + const float* positions; + + // Not directly used to compute the cache key + String16 str; + Vector<float> positionsCopy; + }; // struct ShadowText +// Caching support + +inline int strictly_order_type(const ShadowText& lhs, const ShadowText& rhs) { + return ShadowText::compare(lhs, rhs) < 0; +} + +inline int compare_type(const ShadowText& lhs, const ShadowText& rhs) { + return ShadowText::compare(lhs, rhs); +} + +inline hash_t hash_type(const ShadowText& entry) { + return entry.hash(); +} + /** * Alpha texture used to represent a shadow. */ @@ -130,7 +132,7 @@ public: void operator()(ShadowText& text, ShadowTexture*& texture); ShadowTexture* get(SkPaint* paint, const char* text, uint32_t len, - int numGlyphs, uint32_t radius, const float* positions); + int numGlyphs, float radius, const float* positions); /** * Clears the cache. This causes all textures to be deleted. @@ -157,7 +159,7 @@ public: private: void init(); - GenerationCache<ShadowText, ShadowTexture*> mCache; + LruCache<ShadowText, ShadowTexture*> mCache; uint32_t mSize; uint32_t mMaxSize; diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp index 10d112a..abf2d98 100644 --- a/libs/hwui/TextureCache.cpp +++ b/libs/hwui/TextureCache.cpp @@ -34,7 +34,7 @@ namespace uirenderer { /////////////////////////////////////////////////////////////////////////////// TextureCache::TextureCache(): - mCache(GenerationCache<SkBitmap*, Texture*>::kUnlimitedCapacity), + mCache(LruCache<SkBitmap*, Texture*>::kUnlimitedCapacity), mSize(0), mMaxSize(MB(DEFAULT_TEXTURE_CACHE_SIZE)), mFlushRate(DEFAULT_TEXTURE_CACHE_FLUSH_RATE) { char property[PROPERTY_VALUE_MAX]; @@ -58,7 +58,7 @@ TextureCache::TextureCache(): } TextureCache::TextureCache(uint32_t maxByteSize): - mCache(GenerationCache<SkBitmap*, Texture*>::kUnlimitedCapacity), + mCache(LruCache<SkBitmap*, Texture*>::kUnlimitedCapacity), mSize(0), mMaxSize(maxByteSize) { init(); } diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h index 31a2e3d..80bb22e 100644 --- a/libs/hwui/TextureCache.h +++ b/libs/hwui/TextureCache.h @@ -19,12 +19,12 @@ #include <SkBitmap.h> +#include <utils/LruCache.h> #include <utils/Mutex.h> #include <utils/Vector.h> #include "Debug.h" #include "Texture.h" -#include "utils/GenerationCache.h" namespace android { namespace uirenderer { @@ -130,7 +130,7 @@ private: void init(); - GenerationCache<SkBitmap*, Texture*> mCache; + LruCache<SkBitmap*, Texture*> mCache; uint32_t mSize; uint32_t mMaxSize; |