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

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

Merge "Add a layer (FBO) cache."

parents 6f9a6a31 dda57020
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \
	LayerCache.cpp \
	Matrix.cpp \
	OpenGLRenderer.cpp \
	Program.cpp \
+32 −28
Original line number Diff line number Diff line
@@ -27,7 +27,7 @@ template<typename EntryKey, typename EntryValue>
class OnEntryRemoved {
public:
    virtual ~OnEntryRemoved() { };
    virtual void operator()(EntryKey key, EntryValue value) = 0;
    virtual void operator()(EntryKey& key, EntryValue& value) = 0;
}; // class OnEntryRemoved

template<typename K, typename V>
@@ -40,15 +40,15 @@ public:
        kUnlimitedCapacity,
    };

    void setOnEntryRemovedListener(OnEntryRemoved<K*, V*>* listener);
    void setOnEntryRemovedListener(OnEntryRemoved<K, V>* listener);

    void clear();

    bool contains(K* key) const;
    V* get(K* key);
    void put(K* key, V* value);
    V* remove(K* key);
    void removeOldest();
    bool contains(K key) const;
    V get(K key);
    void put(K key, V value);
    V remove(K key);
    V removeOldest();

    uint32_t size() const;

@@ -68,18 +68,18 @@ private:
        sp<Entry<EntryKey, EntryValue> > child;
    }; // struct Entry

    void addToCache(sp<Entry<K*, V*> > entry, K* key, V* value);
    void attachToCache(sp<Entry<K*, V*> > entry);
    void detachFromCache(sp<Entry<K*, V*> > entry);
    void addToCache(sp<Entry<K, V> > entry, K key, V value);
    void attachToCache(sp<Entry<K, V> > entry);
    void detachFromCache(sp<Entry<K, V> > entry);

    uint32_t mMaxCapacity;

    OnEntryRemoved<K*, V*>* mListener;
    OnEntryRemoved<K, V>* mListener;

    KeyedVector<K*, sp<Entry<K*, V*> > > mCache;
    KeyedVector<K, sp<Entry<K, V> > > mCache;

    sp<Entry<K*, V*> > mOldest;
    sp<Entry<K*, V*> > mYougest;
    sp<Entry<K, V> > mOldest;
    sp<Entry<K, V> > mYougest;
}; // class GenerationCache

template<typename K, typename V>
@@ -88,7 +88,7 @@ uint32_t GenerationCache<K, V>::size() const {
}

template<typename K, typename V>
void GenerationCache<K, V>::setOnEntryRemovedListener(OnEntryRemoved<K*, V*>* listener) {
void GenerationCache<K, V>::setOnEntryRemovedListener(OnEntryRemoved<K, V>* listener) {
    mListener = listener;
}

@@ -106,15 +106,15 @@ void GenerationCache<K, V>::clear() {
}

template<typename K, typename V>
bool GenerationCache<K, V>::contains(K* key) const {
bool GenerationCache<K, V>::contains(K key) const {
    return mCache.indexOfKey(key) >= 0;
}

template<typename K, typename V>
V* GenerationCache<K, V>::get(K* key) {
V GenerationCache<K, V>::get(K key) {
    ssize_t index = mCache.indexOfKey(key);
    if (index >= 0) {
        sp<Entry<K*, V*> > entry = mCache.valueAt(index);
        sp<Entry<K, V> > entry = mCache.valueAt(index);
        if (entry.get()) {
            detachFromCache(entry);
            attachToCache(entry);
@@ -126,24 +126,24 @@ V* GenerationCache<K, V>::get(K* key) {
}

template<typename K, typename V>
void GenerationCache<K, V>::put(K* key, V* value) {
void GenerationCache<K, V>::put(K key, V value) {
    if (mMaxCapacity != kUnlimitedCapacity && mCache.size() >= mMaxCapacity) {
        removeOldest();
    }

    ssize_t index = mCache.indexOfKey(key);
    if (index >= 0) {
        sp<Entry<K*, V*> > entry = mCache.valueAt(index);
        sp<Entry<K, V> > entry = mCache.valueAt(index);
        detachFromCache(entry);
        addToCache(entry, key, value);
    } else {
        sp<Entry<K*, V*> > entry = new Entry<K*, V*>;
        sp<Entry<K, V> > entry = new Entry<K, V>;
        addToCache(entry, key, value);
    }
}

template<typename K, typename V>
void GenerationCache<K, V>::addToCache(sp<Entry<K*, V*> > entry, K* key, V* value) {
void GenerationCache<K, V>::addToCache(sp<Entry<K, V> > entry, K key, V value) {
    entry->key = key;
    entry->value = value;
    mCache.add(key, entry);
@@ -151,29 +151,33 @@ void GenerationCache<K, V>::addToCache(sp<Entry<K*, V*> > entry, K* key, V* valu
}

template<typename K, typename V>
V* GenerationCache<K, V>::remove(K* key) {
V GenerationCache<K, V>::remove(K key) {
    ssize_t index = mCache.indexOfKey(key);
    if (index >= 0) {
        sp<Entry<K*, V*> > entry = mCache.valueAt(index);
        sp<Entry<K, V> > entry = mCache.valueAt(index);
        if (mListener) {
            (*mListener)(entry->key, entry->value);
        }
        mCache.removeItemsAt(index, 1);
        detachFromCache(entry);

        return entry->value;
    }

    return NULL;
}

template<typename K, typename V>
void GenerationCache<K, V>::removeOldest() {
V GenerationCache<K, V>::removeOldest() {
    if (mOldest.get()) {
        remove(mOldest->key);
        return remove(mOldest->key);
    }

    return NULL;
}

template<typename K, typename V>
void GenerationCache<K, V>::attachToCache(sp<Entry<K*, V*> > entry) {
void GenerationCache<K, V>::attachToCache(sp<Entry<K, V> > entry) {
    if (!mYougest.get()) {
        mYougest = mOldest = entry;
    } else {
@@ -184,7 +188,7 @@ void GenerationCache<K, V>::attachToCache(sp<Entry<K*, V*> > entry) {
}

template<typename K, typename V>
void GenerationCache<K, V>::detachFromCache(sp<Entry<K*, V*> > entry) {
void GenerationCache<K, V>::detachFromCache(sp<Entry<K, V> > entry) {
    if (entry->parent.get()) {
        entry->parent->child = entry->child;
    }

libs/hwui/Layer.h

0 → 100644
+90 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ANDROID_UI_LAYER_H
#define ANDROID_UI_LAYER_H

#include <GLES2/gl2.h>

#include <SkXfermode.h>

#include "Rect.h"

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

/**
 * A layer has dimensions and is backed by an OpenGL texture.
 */
struct Layer {
    /**
     * Coordinates of the layer corresponding to this snapshot.
     * Only set when the flag kFlagIsLayer is set.
     */
    Rect layer;
    /**
     * Name of the texture used to render the layer.
     * Only set when the flag kFlagIsLayer is set.
     */
    GLuint texture;
    /**
     * Name of the FBO used to render the layer.
     * Only set when the flag kFlagIsLayer is set.
     */
    GLuint fbo;
    /**
     * Opacity of the layer.
     * Only set when the flag kFlagIsLayer is set.
     */
    float alpha;
    /**
     * Blending mode of the layer.
     * Only set when the flag kFlagIsLayer is set.
     */
    SkXfermode::Mode mode;
    /**
     * Indicates whether this layer should be blended.
     */
    bool blend;
}; // struct Layer

}; // namespace uirenderer
}; // namespace android

#endif // ANDROID_UI_LAYER_H
+114 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define LOG_TAG "OpenGLRenderer"

#include <GLES2/gl2.h>

#include "LayerCache.h"

namespace android {
namespace uirenderer {

///////////////////////////////////////////////////////////////////////////////
// Constructors/destructor
///////////////////////////////////////////////////////////////////////////////

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

LayerCache::~LayerCache() {
    mCache.setOnEntryRemovedListener(this);
    mCache.clear();
}

///////////////////////////////////////////////////////////////////////////////
// Size management
///////////////////////////////////////////////////////////////////////////////

uint32_t LayerCache::getSize() {
    return mSize;
}

uint32_t LayerCache::getMaxSize() {
    return mMaxSize;
}

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

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

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

///////////////////////////////////////////////////////////////////////////////
// Caching
///////////////////////////////////////////////////////////////////////////////

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

        glDeleteFramebuffers(1, &layer->fbo);
        glDeleteTextures(1, &layer->texture);
        delete layer;
    }
}

void LayerCache::clear() {
    mCache.setOnEntryRemovedListener(this);
    mCache.clear();
    mCache.setOnEntryRemovedListener(NULL);
}

Layer* LayerCache::get(LayerSize& size) {
    Layer* layer = mCache.remove(size);
    if (layer) {
        mSize -= layer->layer.getWidth() * layer->layer.getHeight() * 4;
    }
    return layer;
}

bool LayerCache::put(LayerSize& layerSize, Layer* layer) {
    const uint32_t size = layerSize.width * layerSize.height * 4;
    // Don't even try to cache a layer that's bigger than the cache
    if (size < mMaxSize) {
        while (mSize + size > mMaxSize) {
            Layer* oldest = mCache.removeOldest();
            deleteLayer(oldest);
        }

        mCache.put(layerSize, layer);
        mSize += size;

        return true;
    }
    return false;
}

}; // namespace uirenderer
}; // namespace android

libs/hwui/LayerCache.h

0 → 100644
+78 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ANDROID_UI_LAYER_CACHE_H
#define ANDROID_UI_LAYER_CACHE_H

#include "Layer.h"
#include "GenerationCache.h"

namespace android {
namespace uirenderer {

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

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

    /**
     * Returns the layer of specified dimensions, NULL if cannot be found.
     */
    Layer* get(LayerSize& size);
    /**
     * Adds the layer to the cache. The layer will not be added if there is
     * not enough space available.
     *
     * @return True if the layer was added, false otherwise.
     */
    bool put(LayerSize& size, Layer* layer);
    /**
     * Clears the cache. This causes all layers to be deleted.
     */
    void clear();

    /**
     * Sets the maximum size of the cache in bytes.
     */
    void setMaxSize(uint32_t maxSize);
    /**
     * Returns the maximum size of the cache in bytes.
     */
    uint32_t getMaxSize();
    /**
     * Returns the current size of the cache in bytes.
     */
    uint32_t getSize();

private:
    void deleteLayer(Layer* layer);

    GenerationCache<LayerSize, Layer*> mCache;

    uint32_t mSize;
    uint32_t mMaxSize;
}; // class LayerCache

}; // namespace uirenderer
}; // namespace android

#endif // ANDROID_UI_LAYER_CACHE_H
Loading