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

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

Merge "Create FBOs in LayerCache."

parents a3dcc4cc f18fd99b
Loading
Loading
Loading
Loading
+47 −1
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@

#include <GLES2/gl2.h>

#include <utils/Log.h>

#include "LayerCache.h"

namespace android {
@@ -84,11 +86,55 @@ void LayerCache::clear() {
    mCache.setOnEntryRemovedListener(NULL);
}

Layer* LayerCache::get(LayerSize& size) {
Layer* LayerCache::get(LayerSize& size, GLuint previousFbo) {
    Layer* layer = mCache.remove(size);
    if (layer) {
        LAYER_LOGD("Reusing layer");

        mSize -= layer->layer.getWidth() * layer->layer.getHeight() * 4;
    } else {
        LAYER_LOGD("Creating new layer");

        layer = new Layer;
        layer->blend = true;

        // Generate the FBO and attach the texture
        glGenFramebuffers(1, &layer->fbo);
        glBindFramebuffer(GL_FRAMEBUFFER, layer->fbo);

        // Generate the texture in which the FBO will draw
        glGenTextures(1, &layer->texture);
        glBindTexture(GL_TEXTURE_2D, layer->texture);

        // The FBO will not be scaled, so we can use lower quality filtering
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width, size.height, 0,
                GL_RGBA, GL_UNSIGNED_BYTE, NULL);
        glBindTexture(GL_TEXTURE_2D, 0);

        // Bind texture to FBO
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
                layer->texture, 0);

        GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
        if (status != GL_FRAMEBUFFER_COMPLETE) {
            LOGE("Framebuffer incomplete (GL error code 0x%x)", status);

            glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);

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

            return NULL;
        }
    }

    return layer;
}

+32 −2
Original line number Diff line number Diff line
@@ -23,6 +23,24 @@
namespace android {
namespace uirenderer {

///////////////////////////////////////////////////////////////////////////////
// Defines
///////////////////////////////////////////////////////////////////////////////

// Debug
#define DEBUG_LAYERS 0

// Debug
#if DEBUG_LAYERS
    #define LAYER_LOGD(...) LOGD(__VA_ARGS__)
#else
    #define LAYER_LOGD(...)
#endif

///////////////////////////////////////////////////////////////////////////////
// Cache
///////////////////////////////////////////////////////////////////////////////

class LayerCache: public OnEntryRemoved<LayerSize, Layer*> {
public:
    LayerCache(uint32_t maxByteSize);
@@ -35,13 +53,25 @@ public:
    void operator()(LayerSize& bitmap, Layer*& texture);

    /**
     * Returns the layer of specified dimensions, NULL if cannot be found.
     * Returns the layer of specified dimensions. If not 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 previousFbo The name of the FBO to bind to if creating a new
     *        layer fails
     */
    Layer* get(LayerSize& size);
    Layer* get(LayerSize& size, GLuint previousFbo);
    /**
     * Adds the layer to the cache. The layer will not be added if there is
     * not enough space available.
     *
     * @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);
+10 −61
Original line number Diff line number Diff line
@@ -34,9 +34,6 @@ namespace uirenderer {
// Defines
///////////////////////////////////////////////////////////////////////////////

// Debug
#define DEBUG_LAYERS 0

// These properties are defined in mega-bytes
#define PROPERTY_TEXTURE_CACHE_SIZE "ro.hwui.texture_cache_size"
#define PROPERTY_LAYER_CACHE_SIZE "ro.hwui.layer_cache_size"
@@ -51,13 +48,6 @@ namespace uirenderer {
#define SV(x, y) { { x, y } }
#define FV(x, y, u, v) { { x, y }, { u, v } }

// Debug
#if DEBUG_LAYERS
    #define LAYER_LOGD(...) LOGD(__VA_ARGS__)
#else
    #define LAYER_LOGD(...)
#endif

///////////////////////////////////////////////////////////////////////////////
// Globals
///////////////////////////////////////////////////////////////////////////////
@@ -253,6 +243,8 @@ void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) {
            layer->texture, layer->alpha, layer->mode, layer->blend, true);

    LayerSize size(rect.getWidth(), rect.getHeight());
    // Failing to add the layer to the cache should happen only if the
    // layer is too large
    if (!mLayerCache.put(size, layer)) {
        LAYER_LOGD("Deleting layer");

@@ -300,62 +292,19 @@ int OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bot
bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top,
        float right, float bottom, int alpha, SkXfermode::Mode mode,int flags) {

    LayerSize size(right - left, bottom - top);
    Layer* layer = mLayerCache.get(size);

    LAYER_LOGD("Requesting layer %dx%d", size.width, size.height);
    LAYER_LOGD("Layer cache size = %d", mLayerCache.getSize());

    if (!layer) {
        LAYER_LOGD("Creating new layer");

        layer = new Layer;
        layer->blend = true;

        // Generate the FBO and attach the texture
        glGenFramebuffers(1, &layer->fbo);
        glBindFramebuffer(GL_FRAMEBUFFER, layer->fbo);

        // Generate the texture in which the FBO will draw
        glGenTextures(1, &layer->texture);
        glBindTexture(GL_TEXTURE_2D, layer->texture);

        // The FBO will not be scaled, so we can use lower quality filtering
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

        // TODO VERY IMPORTANT: Fix TextView to not call saveLayer() all the time

        const GLsizei width = right - left;
        const GLsizei height = bottom - top;

        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
        glBindTexture(GL_TEXTURE_2D, 0);

        // Bind texture to FBO
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
                layer->texture, 0);

        GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
        if (status != GL_FRAMEBUFFER_COMPLETE) {
            LOGD("Framebuffer incomplete (GL error code 0x%x)", status);

    GLuint previousFbo = snapshot->previous.get() ? snapshot->previous->fbo : 0;
            glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);

            glDeleteFramebuffers(1, &layer->fbo);
            glDeleteTextures(1, &layer->texture);
            delete layer;
    LayerSize size(right - left, bottom - top);

    // TODO VERY IMPORTANT: Fix TextView to not call saveLayer() all the time
    Layer* layer = mLayerCache.get(size, previousFbo);
    if (!layer) {
        return false;
    }
    } else {
        LAYER_LOGD("Reusing layer");

    glBindFramebuffer(GL_FRAMEBUFFER, layer->fbo);
    }

    // Clear the FBO
    glDisable(GL_SCISSOR_TEST);