Use LruCache instead of GenerationCache in libhwui
Change-Id: Ic26ddc7151eb5462bcd243b21daf7187ed6d3bec
This commit is contained in:
@@ -792,7 +792,9 @@ public:
|
||||
static void doTextBounds(JNIEnv* env, const jchar* text, int count,
|
||||
jobject bounds, const SkPaint& paint)
|
||||
{
|
||||
SkRect r{0,0,0,0};
|
||||
SkRect r;
|
||||
r.set(0,0,0,0);
|
||||
|
||||
SkIRect ir;
|
||||
|
||||
sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(&paint,
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#define LOG_TAG "OpenGLRenderer"
|
||||
|
||||
#include <utils/JenkinsHash.h>
|
||||
#include <utils/threads.h>
|
||||
|
||||
#include "Caches.h"
|
||||
@@ -42,12 +43,39 @@ static inline T min(T a, T b) {
|
||||
return a < b ? a : 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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual bool lessThan(const ShapeCacheEntry& rhs) const {
|
||||
return false;
|
||||
}
|
||||
}; // struct ShapeCacheEntry
|
||||
|
||||
// Cache support
|
||||
|
||||
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) {
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
#define LOG_TAG "OpenGLRenderer"
|
||||
|
||||
#include <utils/JenkinsHash.h>
|
||||
|
||||
#include "Debug.h"
|
||||
#include "TextDropShadowCache.h"
|
||||
#include "Properties.h"
|
||||
@@ -23,12 +25,72 @@
|
||||
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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user