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

Commit 8550c4c7 authored by Romain Guy's avatar Romain Guy
Browse files

Better cache for layers, reduce memory usage and increase framerate.

Change-Id: I5ff864a361db4791bd5ff6be716f7ce692ef572d
parent ecd31740
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ include $(CLEAR_VARS)
# defined in the current device/board configuration
ifeq ($(USE_OPENGL_RENDERER),true)
	LOCAL_SRC_FILES:= \
		utils/SortedListImpl.cpp \
		DisplayListRenderer.cpp \
		FboCache.cpp \
		FontRenderer.cpp \
+5 −2
Original line number Diff line number Diff line
@@ -62,7 +62,7 @@ public:
    bool contains(K key) const;
    V get(K key);
    K getKeyAt(uint32_t index) const;
    void put(K key, V value);
    bool put(K key, V value);
    V remove(K key);
    V removeOldest();
    V getValueAt(uint32_t index) const;
@@ -149,7 +149,7 @@ V GenerationCache<K, V>::get(K key) {
}

template<typename K, typename V>
void GenerationCache<K, V>::put(K key, V value) {
bool GenerationCache<K, V>::put(K key, V value) {
    if (mMaxCapacity != kUnlimitedCapacity && mCache.size() >= mMaxCapacity) {
        removeOldest();
    }
@@ -158,7 +158,10 @@ void GenerationCache<K, V>::put(K key, V value) {
    if (index < 0) {
        sp<Entry<K, V> > entry = new Entry<K, V>;
        addToCache(entry, key, value);
        return true;
    }

    return false;
}

template<typename K, typename V>
+26 −25
Original line number Diff line number Diff line
@@ -28,46 +28,33 @@
namespace android {
namespace uirenderer {

/**
 * Dimensions of a layer.
 */
struct LayerSize {
    LayerSize(): width(0), height(0) { }
    LayerSize(const uint32_t width, const uint32_t height): width(width), height(height) { }
    LayerSize(const LayerSize& size): width(size.width), height(size.height) { }

    uint32_t width;
    uint32_t height;

    bool operator<(const LayerSize& rhs) const {
        if (width == rhs.width) {
            return height < rhs.height;
        }
        return width < rhs.width;
    }

    bool operator==(const LayerSize& rhs) const {
        return width == rhs.width && height == rhs.height;
    }
}; // struct LayerSize
///////////////////////////////////////////////////////////////////////////////
// Layers
///////////////////////////////////////////////////////////////////////////////

/**
 * A layer has dimensions and is backed by an OpenGL texture or FBO.
 */
struct Layer {
    Layer(const uint32_t layerWidth, const uint32_t layerHeight):
            width(layerWidth), height(layerHeight) {
    }

    /**
     * Coordinates of the layer.
     * Bounds of the layer.
     */
    Rect layer;
    /**
     * Name of the texture used to render the layer.
     * Texture coordinates of the layer.
     */
    GLuint texture;
    Rect texCoords;

    /**
     * Name of the FBO used to render the layer. If the name is 0
     * this layer is not backed by an FBO, but a simple texture.
     */
    GLuint fbo;

    /**
     * Opacity of the layer.
     */
@@ -80,10 +67,24 @@ struct Layer {
     * Indicates whether this layer should be blended.
     */
    bool blend;

    /**
     * Indicates whether this layer has been used already.
     */
    bool empty;

    /**
     * Name of the texture used to render the layer.
     */
    GLuint texture;
    /**
     * Width of the layer texture.
     */
    uint32_t width;
    /**
     * Height of the layer texture.
     */
    uint32_t height;
}; // struct Layer

}; // namespace uirenderer
+38 −41
Original line number Diff line number Diff line
@@ -30,9 +30,7 @@ namespace uirenderer {
// Constructors/destructor
///////////////////////////////////////////////////////////////////////////////

LayerCache::LayerCache():
        mCache(GenerationCache<LayerSize, Layer*>::kUnlimitedCapacity),
        mSize(0), mMaxSize(MB(DEFAULT_LAYER_CACHE_SIZE)) {
LayerCache::LayerCache(): mSize(0), mMaxSize(MB(DEFAULT_LAYER_CACHE_SIZE)) {
    char property[PROPERTY_VALUE_MAX];
    if (property_get(PROPERTY_LAYER_CACHE_SIZE, property, NULL) > 0) {
        LOGD("  Setting layer cache size to %sMB", property);
@@ -42,11 +40,6 @@ LayerCache::LayerCache():
    }
}

LayerCache::LayerCache(uint32_t maxByteSize):
        mCache(GenerationCache<LayerSize, Layer*>::kUnlimitedCapacity),
        mSize(0), mMaxSize(maxByteSize) {
}

LayerCache::~LayerCache() {
    clear();
}
@@ -64,19 +57,8 @@ uint32_t LayerCache::getMaxSize() {
}

void LayerCache::setMaxSize(uint32_t maxSize) {
    clear();
    mMaxSize = maxSize;
    while (mSize > mMaxSize) {
        Layer* oldest = mCache.removeOldest();
        deleteLayer(oldest);
    }
}

///////////////////////////////////////////////////////////////////////////////
// Callbacks
///////////////////////////////////////////////////////////////////////////////

void LayerCache::operator()(LayerSize& size, Layer*& layer) {
    deleteLayer(layer);
}

///////////////////////////////////////////////////////////////////////////////
@@ -85,7 +67,7 @@ void LayerCache::operator()(LayerSize& size, Layer*& layer) {

void LayerCache::deleteLayer(Layer* layer) {
    if (layer) {
        mSize -= layer->layer.getWidth() * layer->layer.getHeight() * 4;
        mSize -= layer->width * layer->height * 4;

        glDeleteTextures(1, &layer->texture);
        delete layer;
@@ -93,21 +75,31 @@ void LayerCache::deleteLayer(Layer* layer) {
}

void LayerCache::clear() {
    mCache.setOnEntryRemovedListener(this);
    size_t count = mCache.size();
    for (size_t i = 0; i < count; i++) {
        deleteLayer(mCache.itemAt(i).mLayer);
    }
    mCache.clear();
    mCache.setOnEntryRemovedListener(NULL);
}

Layer* LayerCache::get(LayerSize& size) {
    Layer* layer = mCache.remove(size);
    if (layer) {
        LAYER_LOGD("Reusing layer");
Layer* LayerCache::get(const uint32_t width, const uint32_t height) {
    Layer* layer = NULL;

    LayerEntry entry(width, height);
    ssize_t index = mCache.indexOf(entry);

        mSize -= layer->layer.getWidth() * layer->layer.getHeight() * 4;
    if (index >= 0) {
        entry = mCache.itemAt(index);
        mCache.removeAt(index);

        layer = entry.mLayer;
        mSize -= layer->width * layer->height * 4;

        LAYER_LOGD("Reusing layer %dx%d", layer->width, layer->height);
    } else {
        LAYER_LOGD("Creating new layer");
        LAYER_LOGD("Creating new layer %dx%d", entry.mWidth, entry.mHeight);

        layer = new Layer;
        layer = new Layer(entry.mWidth, entry.mHeight);
        layer->blend = true;
        layer->empty = true;
        layer->fbo = 0;
@@ -124,10 +116,10 @@ Layer* LayerCache::get(LayerSize& size) {
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

#if DEBUG_LAYERS
        uint32_t size = mCache.size();
        for (uint32_t i = 0; i < size; i++) {
            LayerSize ls = mCache.getKeyAt(i);
            LAYER_LOGD("  Layer size %dx%d", ls.width, ls.height);
        size_t size = mCache.size();
        for (size_t i = 0; i < size; i++) {
            const LayerEntry& entry = mCache.itemAt(i);
            LAYER_LOGD("  Layer size %dx%d", entry.mWidth, entry.mHeight);
        }
#endif
    }
@@ -135,18 +127,23 @@ Layer* LayerCache::get(LayerSize& size) {
    return layer;
}

bool LayerCache::put(LayerSize& layerSize, Layer* layer) {
    const uint32_t size = layerSize.width * layerSize.height * 4;
bool LayerCache::put(Layer* layer) {
    const uint32_t size = layer->width * layer->height * 4;
    // Don't even try to cache a layer that's bigger than the cache
    if (size < mMaxSize) {
        // TODO: Use an LRU
        while (mSize + size > mMaxSize) {
            Layer* oldest = mCache.removeOldest();
            deleteLayer(oldest);
            LAYER_LOGD("  Deleting layer %.2fx%.2f", oldest->layer.getWidth(),
                    oldest->layer.getHeight());
            Layer* biggest = mCache.top().mLayer;
            deleteLayer(biggest);
            mCache.removeAt(mCache.size() - 1);

            LAYER_LOGD("  Deleting layer %.2fx%.2f", biggest->layer.getWidth(),
                    biggest->layer.getHeight());
        }

        mCache.put(layerSize, layer);
        LayerEntry entry(layer);

        mCache.add(entry);
        mSize += size;

        return true;
+48 −17
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@
#define ANDROID_UI_LAYER_CACHE_H

#include "Layer.h"
#include "GenerationCache.h"
#include "utils/SortedList.h"

namespace android {
namespace uirenderer {
@@ -30,6 +30,9 @@ namespace uirenderer {
// Debug
#define DEBUG_LAYERS 0

// Textures used by layers must have dimensions multiples of this number
#define LAYER_SIZE 64

// Debug
#if DEBUG_LAYERS
    #define LAYER_LOGD(...) LOGD(__VA_ARGS__)
@@ -41,40 +44,34 @@ namespace uirenderer {
// Cache
///////////////////////////////////////////////////////////////////////////////

class LayerCache: public OnEntryRemoved<LayerSize, Layer*> {
class LayerCache {
public:
    LayerCache();
    LayerCache(uint32_t maxByteSize);
    ~LayerCache();

    /**
     * Used as a callback when an entry is removed from the cache.
     * Do not invoke directly.
     */
    void operator()(LayerSize& size, Layer*& layer);

    /**
     * Returns the layer of specified dimensions. If not suitable layer
     * can be found, a new one is created and returned. If creating a new
     * Returns a layer large enough for the specified dimensions. If no suitable
     * layer can be found, a new one is created and returned. If creating a new
     * layer fails, NULL is returned.
     *
     * When a layer is obtained from the cache, it is removed and the total
     * size of the cache goes down.
     *
     * @param size The dimensions of the desired layer
     * @param width The desired width of the layer
     * @param width The desired height of the layer
     */
    Layer* get(LayerSize& size);
    Layer* get(const uint32_t width, const uint32_t height);

    /**
     * Adds the layer to the cache. The layer will not be added if there is
     * not enough space available.
     * not enough space available. Adding a layer can cause other layers to
     * be removed from the cache.
     *
     * @param size The dimensions of the layer
     * @param layer The layer to add to the cache
     *
     * @return True if the layer was added, false otherwise.
     */
    bool put(LayerSize& size, Layer* layer);
    bool put(Layer* layer);
    /**
     * Clears the cache. This causes all layers to be deleted.
     */
@@ -96,7 +93,41 @@ public:
private:
    void deleteLayer(Layer* layer);

    GenerationCache<LayerSize, Layer*> mCache;
    struct LayerEntry {
        LayerEntry():
            mLayer(NULL), mWidth(0), mHeight(0) {
        }

        LayerEntry(const uint32_t layerWidth, const uint32_t layerHeight): mLayer(NULL) {
            mWidth = uint32_t(ceilf(layerWidth / float(LAYER_SIZE)) * LAYER_SIZE);
            mHeight = uint32_t(ceilf(layerHeight / float(LAYER_SIZE)) * LAYER_SIZE);
        }

        LayerEntry(const LayerEntry& entry):
            mLayer(entry.mLayer), mWidth(entry.mWidth), mHeight(entry.mHeight) {
        }

        LayerEntry(Layer* layer):
            mLayer(layer), mWidth(layer->width), mHeight(layer->height) {
        }

        bool operator<(const LayerEntry& rhs) const {
            if (mWidth == rhs.mWidth) {
                return mHeight < rhs.mHeight;
            }
            return mWidth < rhs.mWidth;
        }

        bool operator==(const LayerEntry& rhs) const {
            return mWidth == rhs.mWidth && mHeight == rhs.mHeight;
        }

        Layer* mLayer;
        uint32_t mWidth;
        uint32_t mHeight;
    }; // struct LayerEntry

    SortedList<LayerEntry> mCache;

    uint32_t mSize;
    uint32_t mMaxSize;
Loading