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
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 26c7e5d..44dc731 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 @@
 
     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 63bb73f..b9473a9 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -90,7 +90,7 @@
     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 27e0cf1..715dfa4 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -255,13 +255,14 @@
         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 8451048..3e55fff 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -256,7 +256,7 @@
     // 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 4a5785c..046bcfd 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -921,7 +921,7 @@
 
     // 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 1096642..577f463 100644
--- a/libs/hwui/font/CacheTexture.cpp
+++ b/libs/hwui/font/CacheTexture.cpp
@@ -15,10 +15,9 @@
  */
 
 #include <SkGlyph.h>
-#include <utils/Log.h>
 
-#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 5742941..e7fb474 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 <GLES2/gl2.h>
+#include <GLES3/gl3.h>
 
 #include <SkScalerContext.h>