From 0908764b2b3cf5075df4178a5f0a8547dcb7b317 Mon Sep 17 00:00:00 2001 From: Romain Guy Date: Thu, 4 Apr 2013 12:27:54 -0700 Subject: [PATCH] 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 --- libs/hwui/FontRenderer.cpp | 35 +++++++++++++++++++++++++++++---- libs/hwui/Layer.cpp | 2 +- libs/hwui/Layer.h | 7 ++++--- libs/hwui/LayerRenderer.cpp | 2 +- libs/hwui/OpenGLRenderer.cpp | 2 +- libs/hwui/font/CacheTexture.cpp | 3 +-- libs/hwui/font/CacheTexture.h | 2 +- 7 files changed, 40 insertions(+), 13 deletions(-) diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp index 26c7e5d1ad6fe..44dc731c6be76 100644 --- a/libs/hwui/FontRenderer.cpp +++ b/libs/hwui/FontRenderer.cpp @@ -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; } diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp index 63bb73f12775b..b9473a9e30759 100644 --- a/libs/hwui/Layer.cpp +++ b/libs/hwui/Layer.cpp @@ -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); diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h index 27e0cf169e437..715dfa46660dd 100644 --- a/libs/hwui/Layer.h +++ b/libs/hwui/Layer.h @@ -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); } } diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp index 8451048e56223..3e55fffd93a9d 100644 --- a/libs/hwui/LayerRenderer.cpp +++ b/libs/hwui/LayerRenderer.cpp @@ -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) { diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 4a5785c02bea3..046bcfdec01d3 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -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); } diff --git a/libs/hwui/font/CacheTexture.cpp b/libs/hwui/font/CacheTexture.cpp index 109664282374d..577f46389fdb9 100644 --- a/libs/hwui/font/CacheTexture.cpp +++ b/libs/hwui/font/CacheTexture.cpp @@ -15,10 +15,9 @@ */ #include -#include -#include "Debug.h" #include "CacheTexture.h" +#include "../Debug.h" namespace android { namespace uirenderer { diff --git a/libs/hwui/font/CacheTexture.h b/libs/hwui/font/CacheTexture.h index 57429415254f5..e7fb4746492a7 100644 --- a/libs/hwui/font/CacheTexture.h +++ b/libs/hwui/font/CacheTexture.h @@ -17,7 +17,7 @@ #ifndef ANDROID_HWUI_CACHE_TEXTURE_H #define ANDROID_HWUI_CACHE_TEXTURE_H -#include +#include #include