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

Commit 1cb94653 authored by Romain Guy's avatar Romain Guy Committed by Android (Google) Code Review
Browse files

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

parents 0594476f 8550c4c7
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