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

Commit 0908764b authored by Romain Guy's avatar Romain Guy
Browse files

First OpenGL ES 3.0 based optimization

This change uses a new OpenGL ES 3.0 feature to upload less data when
the font cache needs to be update. This can result in significant
performance improvements on device with large textures or with locales
that use a lot of glyphs (CJK for instance.)

This change also fixes various unpack alignment issues. The unpack
alignment, as well as the unpack row length, is not texture specific
but a global state that affect all glTex/SubImage2D calls. Some of
them were missing the appropriate glPixelStorei() call. This could
result in corrupted textures.

Change-Id: Iefb429d4d0d0b4e0faeadf27daafee6d30a21d85
parent df1dc28b
Loading
Loading
Loading
Loading
+31 −4
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@

#include "Caches.h"
#include "Debug.h"
#include "Extensions.h"
#include "FontRenderer.h"
#include "Rect.h"

@@ -375,34 +376,60 @@ void FontRenderer::checkTextureUpdate() {

    Caches& caches = Caches::getInstance();
    GLuint lastTextureId = 0;

    // OpenGL ES 3.0+ lets us specify the row length for unpack operations such
    // as glTexSubImage2D(). This allows us to upload a sub-rectangle of a texture.
    // With OpenGL ES 2.0 we have to upload entire stripes instead.
    const bool hasUnpackRowLength = Extensions::getInstance().getMajorGlVersion() >= 3;
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

    // Iterate over all the cache textures and see which ones need to be updated
    for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
        CacheTexture* cacheTexture = mCacheTextures[i];
        if (cacheTexture->isDirty() && cacheTexture->getTexture()) {
            // Can't copy inner rect; glTexSubimage expects pointer to deal with entire buffer
            // of data. So expand the dirty rect to the encompassing horizontal stripe.
            const Rect* dirtyRect = cacheTexture->getDirtyRect();
            uint32_t x = 0;
            uint32_t x = hasUnpackRowLength ? dirtyRect->left : 0;
            uint32_t y = dirtyRect->top;
            uint32_t width = cacheTexture->getWidth();
            uint32_t height = dirtyRect->getHeight();
            void* textureData = cacheTexture->getTexture() + y * width;
            void* textureData = cacheTexture->getTexture() + y * width + x;

            if (cacheTexture->getTextureId() != lastTextureId) {
                lastTextureId = cacheTexture->getTextureId();
                caches.activeTexture(0);
                glBindTexture(GL_TEXTURE_2D, lastTextureId);

                // The unpack row length only needs to be specified when a new
                // texture is bound
                if (hasUnpackRowLength) {
                    glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
                }
            }

            // If we can upload a sub-rectangle, use the dirty rect width
            // instead of the width of the entire texture
            if (hasUnpackRowLength) {
                width = dirtyRect->getWidth();
            }

#if DEBUG_FONT_RENDERER
            ALOGD("glTexSubimage for cacheTexture %d: x, y, width height = %d, %d, %d, %d",
                    i, x, y, width, height);
#endif

            glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height,
                    GL_ALPHA, GL_UNSIGNED_BYTE, textureData);

            cacheTexture->setDirty(false);
        }
    }

    // Reset to default unpack row length to avoid affecting texture
    // uploads in other parts of the renderer
    if (hasUnpackRowLength) {
        glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
    }

    mUploadTexture = false;
}

+1 −1
Original line number Diff line number Diff line
@@ -90,7 +90,7 @@ bool Layer::resize(const uint32_t width, const uint32_t height) {
    if (fbo) {
        Caches::getInstance().activeTexture(0);
        bindTexture();
        allocateTexture(GL_RGBA, GL_UNSIGNED_BYTE);
        allocateTexture();

        if (glGetError() != GL_NO_ERROR) {
            setSize(oldWidth, oldHeight);
+4 −3
Original line number Diff line number Diff line
@@ -255,13 +255,14 @@ struct Layer {
        texture.id = 0;
    }

    inline void allocateTexture(GLenum format, GLenum storage) {
    inline void allocateTexture() {
#if DEBUG_LAYERS
        ALOGD("  Allocate layer: %dx%d", getWidth(), getHeight());
#endif
        if (texture.id) {
            glTexImage2D(renderTarget, 0, format, getWidth(), getHeight(), 0,
                    format, storage, NULL);
            glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
            glTexImage2D(renderTarget, 0, GL_RGBA, getWidth(), getHeight(), 0,
                    GL_RGBA, GL_UNSIGNED_BYTE, NULL);
        }
    }

+1 −1
Original line number Diff line number Diff line
@@ -256,7 +256,7 @@ Layer* LayerRenderer::createLayer(uint32_t width, uint32_t height, bool isOpaque
    // Initialize the texture if needed
    if (layer->isEmpty()) {
        layer->setEmpty(false);
        layer->allocateTexture(GL_RGBA, GL_UNSIGNED_BYTE);
        layer->allocateTexture();

        // This should only happen if we run out of memory
        if (glGetError() != GL_NO_ERROR) {
+1 −1
Original line number Diff line number Diff line
@@ -921,7 +921,7 @@ bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip, GLui

    // Initialize the texture if needed
    if (layer->isEmpty()) {
        layer->allocateTexture(GL_RGBA, GL_UNSIGNED_BYTE);
        layer->allocateTexture();
        layer->setEmpty(false);
    }

Loading