Merge "Memory optimizations for libhwui Bug #5566149" into ics-mr1
This commit is contained in:
@ -170,8 +170,11 @@ void Caches::flush(FlushMode mode) {
|
|||||||
patchCache.clear();
|
patchCache.clear();
|
||||||
dropShadowCache.clear();
|
dropShadowCache.clear();
|
||||||
gradientCache.clear();
|
gradientCache.clear();
|
||||||
|
fontRenderer.clear();
|
||||||
// fall through
|
// fall through
|
||||||
case kFlushMode_Moderate:
|
case kFlushMode_Moderate:
|
||||||
|
fontRenderer.flush();
|
||||||
|
textureCache.flush();
|
||||||
pathCache.clear();
|
pathCache.clear();
|
||||||
roundRectShapeCache.clear();
|
roundRectShapeCache.clear();
|
||||||
circleShapeCache.clear();
|
circleShapeCache.clear();
|
||||||
|
@ -67,20 +67,63 @@ GammaFontRenderer::GammaFontRenderer() {
|
|||||||
const float whiteGamma = 1.0f / gamma;
|
const float whiteGamma = 1.0f / gamma;
|
||||||
|
|
||||||
for (uint32_t i = 0; i <= 255; i++) {
|
for (uint32_t i = 0; i <= 255; i++) {
|
||||||
mDefault[i] = i;
|
mGammaTable[i] = i;
|
||||||
|
|
||||||
const float v = i / 255.0f;
|
const float v = i / 255.0f;
|
||||||
const float black = pow(v, blackGamma);
|
const float black = pow(v, blackGamma);
|
||||||
const float white = pow(v, whiteGamma);
|
const float white = pow(v, whiteGamma);
|
||||||
|
|
||||||
mBlackGamma[i] = uint8_t((float)::floor(black * 255.0f + 0.5f));
|
mGammaTable[256 + i] = uint8_t((float)::floor(black * 255.0f + 0.5f));
|
||||||
mWhiteGamma[i] = uint8_t((float)::floor(white * 255.0f + 0.5f));
|
mGammaTable[512 + i] = uint8_t((float)::floor(white * 255.0f + 0.5f));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure the font renderers
|
memset(mRenderers, 0, sizeof(FontRenderer*) * kGammaCount);
|
||||||
mDefaultRenderer.setGammaTable(&mDefault[0]);
|
memset(mRenderersUsageCount, 0, sizeof(uint32_t) * kGammaCount);
|
||||||
mBlackGammaRenderer.setGammaTable(&mBlackGamma[0]);
|
}
|
||||||
mWhiteGammaRenderer.setGammaTable(&mWhiteGamma[0]);
|
|
||||||
|
GammaFontRenderer::~GammaFontRenderer() {
|
||||||
|
for (int i = 0; i < kGammaCount; i++) {
|
||||||
|
delete mRenderers[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GammaFontRenderer::clear() {
|
||||||
|
for (int i = 0; i < kGammaCount; i++) {
|
||||||
|
delete mRenderers[i];
|
||||||
|
mRenderers[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GammaFontRenderer::flush() {
|
||||||
|
int count = 0;
|
||||||
|
int min = -1;
|
||||||
|
uint32_t minCount = UINT_MAX;
|
||||||
|
|
||||||
|
for (int i = 0; i < kGammaCount; i++) {
|
||||||
|
if (mRenderers[i]) {
|
||||||
|
count++;
|
||||||
|
if (mRenderersUsageCount[i] < minCount) {
|
||||||
|
minCount = mRenderersUsageCount[i];
|
||||||
|
min = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count <= 1 || min < 0) return;
|
||||||
|
|
||||||
|
delete mRenderers[min];
|
||||||
|
mRenderers[min] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
FontRenderer* GammaFontRenderer::getRenderer(Gamma gamma) {
|
||||||
|
FontRenderer* renderer = mRenderers[gamma];
|
||||||
|
if (!renderer) {
|
||||||
|
renderer = new FontRenderer();
|
||||||
|
mRenderers[gamma] = renderer;
|
||||||
|
renderer->setGammaTable(&mGammaTable[gamma * 256]);
|
||||||
|
}
|
||||||
|
mRenderersUsageCount[gamma]++;
|
||||||
|
return renderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
FontRenderer& GammaFontRenderer::getFontRenderer(const SkPaint* paint) {
|
FontRenderer& GammaFontRenderer::getFontRenderer(const SkPaint* paint) {
|
||||||
@ -92,12 +135,12 @@ FontRenderer& GammaFontRenderer::getFontRenderer(const SkPaint* paint) {
|
|||||||
const int luminance = (r * 2 + g * 5 + b) >> 3;
|
const int luminance = (r * 2 + g * 5 + b) >> 3;
|
||||||
|
|
||||||
if (luminance <= mBlackThreshold) {
|
if (luminance <= mBlackThreshold) {
|
||||||
return mBlackGammaRenderer;
|
return *getRenderer(kGammaBlack);
|
||||||
} else if (luminance >= mWhiteThreshold) {
|
} else if (luminance >= mWhiteThreshold) {
|
||||||
return mWhiteGammaRenderer;
|
return *getRenderer(kGammaWhite);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return mDefaultRenderer;
|
return *getRenderer(kGammaDefault);
|
||||||
}
|
}
|
||||||
|
|
||||||
}; // namespace uirenderer
|
}; // namespace uirenderer
|
||||||
|
@ -26,36 +26,43 @@ namespace uirenderer {
|
|||||||
|
|
||||||
struct GammaFontRenderer {
|
struct GammaFontRenderer {
|
||||||
GammaFontRenderer();
|
GammaFontRenderer();
|
||||||
|
~GammaFontRenderer();
|
||||||
|
|
||||||
|
enum Gamma {
|
||||||
|
kGammaDefault = 0,
|
||||||
|
kGammaBlack = 1,
|
||||||
|
kGammaWhite = 2,
|
||||||
|
kGammaCount = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
void flush();
|
||||||
|
|
||||||
FontRenderer& getFontRenderer(const SkPaint* paint);
|
FontRenderer& getFontRenderer(const SkPaint* paint);
|
||||||
|
|
||||||
uint32_t getFontRendererCount() const {
|
uint32_t getFontRendererCount() const {
|
||||||
return 3;
|
return kGammaCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t getFontRendererSize(uint32_t fontRenderer) const {
|
uint32_t getFontRendererSize(uint32_t fontRenderer) const {
|
||||||
switch (fontRenderer) {
|
if (fontRenderer >= kGammaCount) return 0;
|
||||||
case 0:
|
|
||||||
return mDefaultRenderer.getCacheHeight() * mDefaultRenderer.getCacheWidth();
|
FontRenderer* renderer = mRenderers[fontRenderer];
|
||||||
case 1:
|
if (!renderer) return 0;
|
||||||
return mBlackGammaRenderer.getCacheHeight() * mBlackGammaRenderer.getCacheWidth();
|
|
||||||
case 2:
|
return renderer->getCacheHeight() * renderer->getCacheWidth();
|
||||||
return mWhiteGammaRenderer.getCacheHeight() * mWhiteGammaRenderer.getCacheWidth();
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FontRenderer mDefaultRenderer;
|
FontRenderer* getRenderer(Gamma gamma);
|
||||||
FontRenderer mBlackGammaRenderer;
|
|
||||||
FontRenderer mWhiteGammaRenderer;
|
uint32_t mRenderersUsageCount[kGammaCount];
|
||||||
|
FontRenderer* mRenderers[kGammaCount];
|
||||||
|
|
||||||
int mBlackThreshold;
|
int mBlackThreshold;
|
||||||
int mWhiteThreshold;
|
int mWhiteThreshold;
|
||||||
|
|
||||||
uint8_t mDefault[256];
|
uint8_t mGammaTable[256 * kGammaCount];
|
||||||
uint8_t mBlackGamma[256];
|
|
||||||
uint8_t mWhiteGamma[256];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}; // namespace uirenderer
|
}; // namespace uirenderer
|
||||||
|
@ -61,6 +61,9 @@ enum DebugLevel {
|
|||||||
#define PROPERTY_DROP_SHADOW_CACHE_SIZE "ro.hwui.drop_shadow_cache_size"
|
#define PROPERTY_DROP_SHADOW_CACHE_SIZE "ro.hwui.drop_shadow_cache_size"
|
||||||
#define PROPERTY_FBO_CACHE_SIZE "ro.hwui.fbo_cache_size"
|
#define PROPERTY_FBO_CACHE_SIZE "ro.hwui.fbo_cache_size"
|
||||||
|
|
||||||
|
// These properties are defined in percentage (range 0..1)
|
||||||
|
#define PROPERTY_TEXTURE_CACHE_FLUSH_RATE "ro.hwui.texture_cache_flush_rate"
|
||||||
|
|
||||||
// These properties are defined in pixels
|
// These properties are defined in pixels
|
||||||
#define PROPERTY_TEXT_CACHE_WIDTH "ro.hwui.text_cache_width"
|
#define PROPERTY_TEXT_CACHE_WIDTH "ro.hwui.text_cache_width"
|
||||||
#define PROPERTY_TEXT_CACHE_HEIGHT "ro.hwui.text_cache_height"
|
#define PROPERTY_TEXT_CACHE_HEIGHT "ro.hwui.text_cache_height"
|
||||||
@ -82,6 +85,8 @@ enum DebugLevel {
|
|||||||
#define DEFAULT_DROP_SHADOW_CACHE_SIZE 2.0f
|
#define DEFAULT_DROP_SHADOW_CACHE_SIZE 2.0f
|
||||||
#define DEFAULT_FBO_CACHE_SIZE 16
|
#define DEFAULT_FBO_CACHE_SIZE 16
|
||||||
|
|
||||||
|
#define DEFAULT_TEXTURE_CACHE_FLUSH_RATE 0.6f
|
||||||
|
|
||||||
#define DEFAULT_TEXT_GAMMA 1.4f
|
#define DEFAULT_TEXT_GAMMA 1.4f
|
||||||
#define DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD 64
|
#define DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD 64
|
||||||
#define DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD 192
|
#define DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD 192
|
||||||
|
@ -34,7 +34,8 @@ namespace uirenderer {
|
|||||||
|
|
||||||
TextureCache::TextureCache():
|
TextureCache::TextureCache():
|
||||||
mCache(GenerationCache<SkBitmap*, Texture*>::kUnlimitedCapacity),
|
mCache(GenerationCache<SkBitmap*, Texture*>::kUnlimitedCapacity),
|
||||||
mSize(0), mMaxSize(MB(DEFAULT_TEXTURE_CACHE_SIZE)) {
|
mSize(0), mMaxSize(MB(DEFAULT_TEXTURE_CACHE_SIZE)),
|
||||||
|
mFlushRate(DEFAULT_TEXTURE_CACHE_FLUSH_RATE) {
|
||||||
char property[PROPERTY_VALUE_MAX];
|
char property[PROPERTY_VALUE_MAX];
|
||||||
if (property_get(PROPERTY_TEXTURE_CACHE_SIZE, property, NULL) > 0) {
|
if (property_get(PROPERTY_TEXTURE_CACHE_SIZE, property, NULL) > 0) {
|
||||||
INIT_LOGD(" Setting texture cache size to %sMB", property);
|
INIT_LOGD(" Setting texture cache size to %sMB", property);
|
||||||
@ -43,6 +44,15 @@ TextureCache::TextureCache():
|
|||||||
INIT_LOGD(" Using default texture cache size of %.2fMB", DEFAULT_TEXTURE_CACHE_SIZE);
|
INIT_LOGD(" Using default texture cache size of %.2fMB", DEFAULT_TEXTURE_CACHE_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (property_get(PROPERTY_TEXTURE_CACHE_FLUSH_RATE, property, NULL) > 0) {
|
||||||
|
float flushRate = atof(property);
|
||||||
|
INIT_LOGD(" Setting texture cache flush rate to %.2f%%", flushRate * 100.0f);
|
||||||
|
setFlushRate(flushRate);
|
||||||
|
} else {
|
||||||
|
INIT_LOGD(" Using default texture cache flush rate of %.2f%%",
|
||||||
|
DEFAULT_TEXTURE_CACHE_FLUSH_RATE * 100.0f);
|
||||||
|
}
|
||||||
|
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,6 +94,10 @@ void TextureCache::setMaxSize(uint32_t maxSize) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TextureCache::setFlushRate(float flushRate) {
|
||||||
|
mFlushRate = fmaxf(0.0f, fminf(1.0f, flushRate));
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// Callbacks
|
// Callbacks
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
@ -168,6 +182,21 @@ void TextureCache::clear() {
|
|||||||
TEXTURE_LOGD("TextureCache:clear(), mSize = %d", mSize);
|
TEXTURE_LOGD("TextureCache:clear(), mSize = %d", mSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TextureCache::flush() {
|
||||||
|
if (mFlushRate >= 1.0f || mCache.size() == 0) return;
|
||||||
|
if (mFlushRate <= 0.0f) {
|
||||||
|
clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t targetSize = uint32_t(mSize * mFlushRate);
|
||||||
|
TEXTURE_LOGD("TextureCache::flush: target size: %d", targetSize);
|
||||||
|
|
||||||
|
while (mSize > targetSize) {
|
||||||
|
mCache.removeOldest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void TextureCache::generateTexture(SkBitmap* bitmap, Texture* texture, bool regenerate) {
|
void TextureCache::generateTexture(SkBitmap* bitmap, Texture* texture, bool regenerate) {
|
||||||
SkAutoLockPixels alp(*bitmap);
|
SkAutoLockPixels alp(*bitmap);
|
||||||
|
|
||||||
|
@ -98,6 +98,17 @@ public:
|
|||||||
*/
|
*/
|
||||||
uint32_t getSize();
|
uint32_t getSize();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Partially flushes the cache. The amount of memory freed by a flush
|
||||||
|
* is defined by the flush rate.
|
||||||
|
*/
|
||||||
|
void flush();
|
||||||
|
/**
|
||||||
|
* Indicates the percentage of the cache to retain when a
|
||||||
|
* memory trim is requested (see Caches::flush).
|
||||||
|
*/
|
||||||
|
void setFlushRate(float flushRate);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* Generates the texture from a bitmap into the specified texture structure.
|
* Generates the texture from a bitmap into the specified texture structure.
|
||||||
@ -119,6 +130,8 @@ private:
|
|||||||
uint32_t mMaxSize;
|
uint32_t mMaxSize;
|
||||||
GLint mMaxTextureSize;
|
GLint mMaxTextureSize;
|
||||||
|
|
||||||
|
float mFlushRate;
|
||||||
|
|
||||||
bool mDebugEnabled;
|
bool mDebugEnabled;
|
||||||
|
|
||||||
Vector<SkBitmap*> mGarbage;
|
Vector<SkBitmap*> mGarbage;
|
||||||
|
Reference in New Issue
Block a user