Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit eca0ca24 authored by Romain Guy's avatar Romain Guy
Browse files

Memory optimizations for libhwui

Bug #5566149

Lazily initialize font renderers
Keep 60% of the texture cache when an app goes to the background
Delete least used font renderer when going to the background
Delete all font renderers on full memory trim

Change-Id: I3c2454d46dc1107ec0f0f72a9ce69cbbcc8825e7
parent 650ee281
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -170,8 +170,11 @@ void Caches::flush(FlushMode mode) {
            patchCache.clear();
            dropShadowCache.clear();
            gradientCache.clear();
            fontRenderer.clear();
            // fall through
        case kFlushMode_Moderate:
            fontRenderer.flush();
            textureCache.flush();
            pathCache.clear();
            roundRectShapeCache.clear();
            circleShapeCache.clear();
+53 −10
Original line number Diff line number Diff line
@@ -67,20 +67,63 @@ GammaFontRenderer::GammaFontRenderer() {
    const float whiteGamma = 1.0f / gamma;

    for (uint32_t i = 0; i <= 255; i++) {
        mDefault[i] = i;
        mGammaTable[i] = i;

        const float v = i / 255.0f;
        const float black = pow(v, blackGamma);
        const float white = pow(v, whiteGamma);

        mBlackGamma[i] = uint8_t((float)::floor(black * 255.0f + 0.5f));
        mWhiteGamma[i] = uint8_t((float)::floor(white * 255.0f + 0.5f));
        mGammaTable[256 + i] = uint8_t((float)::floor(black * 255.0f + 0.5f));
        mGammaTable[512 + i] = uint8_t((float)::floor(white * 255.0f + 0.5f));
    }

    // Configure the font renderers
    mDefaultRenderer.setGammaTable(&mDefault[0]);
    mBlackGammaRenderer.setGammaTable(&mBlackGamma[0]);
    mWhiteGammaRenderer.setGammaTable(&mWhiteGamma[0]);
    memset(mRenderers, 0, sizeof(FontRenderer*) * kGammaCount);
    memset(mRenderersUsageCount, 0, sizeof(uint32_t) * kGammaCount);
}

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) {
@@ -92,12 +135,12 @@ FontRenderer& GammaFontRenderer::getFontRenderer(const SkPaint* paint) {
        const int luminance = (r * 2 + g * 5 + b) >> 3;

        if (luminance <= mBlackThreshold) {
            return mBlackGammaRenderer;
            return *getRenderer(kGammaBlack);
        } else if (luminance >= mWhiteThreshold) {
            return mWhiteGammaRenderer;
            return *getRenderer(kGammaWhite);
        }
    }
    return mDefaultRenderer;
    return *getRenderer(kGammaDefault);
}

}; // namespace uirenderer
+23 −16
Original line number Diff line number Diff line
@@ -26,36 +26,43 @@ namespace uirenderer {

struct GammaFontRenderer {
    GammaFontRenderer();
    ~GammaFontRenderer();

    enum Gamma {
        kGammaDefault = 0,
        kGammaBlack = 1,
        kGammaWhite = 2,
        kGammaCount = 3
    };

    void clear();
    void flush();

    FontRenderer& getFontRenderer(const SkPaint* paint);

    uint32_t getFontRendererCount() const {
        return 3;
        return kGammaCount;
    }

    uint32_t getFontRendererSize(uint32_t fontRenderer) const {
        switch (fontRenderer) {
            case 0:
                return mDefaultRenderer.getCacheHeight() * mDefaultRenderer.getCacheWidth();
            case 1:
                return mBlackGammaRenderer.getCacheHeight() * mBlackGammaRenderer.getCacheWidth();
            case 2:
                return mWhiteGammaRenderer.getCacheHeight() * mWhiteGammaRenderer.getCacheWidth();
        }
        return 0;
        if (fontRenderer >= kGammaCount) return 0;

        FontRenderer* renderer = mRenderers[fontRenderer];
        if (!renderer) return 0;

        return renderer->getCacheHeight() * renderer->getCacheWidth();
    }

private:
    FontRenderer mDefaultRenderer;
    FontRenderer mBlackGammaRenderer;
    FontRenderer mWhiteGammaRenderer;
    FontRenderer* getRenderer(Gamma gamma);

    uint32_t mRenderersUsageCount[kGammaCount];
    FontRenderer* mRenderers[kGammaCount];

    int mBlackThreshold;
    int mWhiteThreshold;

    uint8_t mDefault[256];
    uint8_t mBlackGamma[256];
    uint8_t mWhiteGamma[256];
    uint8_t mGammaTable[256 * kGammaCount];
};

}; // namespace uirenderer
+5 −0
Original line number Diff line number Diff line
@@ -61,6 +61,9 @@ enum DebugLevel {
#define PROPERTY_DROP_SHADOW_CACHE_SIZE "ro.hwui.drop_shadow_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
#define PROPERTY_TEXT_CACHE_WIDTH "ro.hwui.text_cache_width"
#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_FBO_CACHE_SIZE 16

#define DEFAULT_TEXTURE_CACHE_FLUSH_RATE 0.6f

#define DEFAULT_TEXT_GAMMA 1.4f
#define DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD 64
#define DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD 192
+30 −1
Original line number Diff line number Diff line
@@ -34,7 +34,8 @@ namespace uirenderer {

TextureCache::TextureCache():
        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];
    if (property_get(PROPERTY_TEXTURE_CACHE_SIZE, property, NULL) > 0) {
        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);
    }

    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();
}

@@ -84,6 +94,10 @@ void TextureCache::setMaxSize(uint32_t maxSize) {
    }
}

void TextureCache::setFlushRate(float flushRate) {
    mFlushRate = fmaxf(0.0f, fminf(1.0f, flushRate));
}

///////////////////////////////////////////////////////////////////////////////
// Callbacks
///////////////////////////////////////////////////////////////////////////////
@@ -168,6 +182,21 @@ void TextureCache::clear() {
    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) {
    SkAutoLockPixels alp(*bitmap);

Loading