Optimize FBO drawing with regions.
This optimization is currently disabled until Launcher is
modified to take advantage of it. The optimization can be
enabled by turning on RENDER_LAYERS_AS_REGIONS in the
OpenGLRenderer.h file.

Change-Id: I2fdf59d0f4dc690a3d7f712173ab8db3848b27b1
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index 007e7b9..f80fbd8 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -129,6 +129,7 @@
     private long[] mVibePattern;
 
     private int mAspect;
+    private final Matrix mArrowMatrix = new Matrix();
 
     /**
      * Represents a cell in the 3 X 3 matrix of the unlock pattern view.
@@ -923,7 +924,6 @@
         // This assumes that the arrow image is drawn at 12:00 with it's top edge
         // coincident with the circle bitmap's top edge.
         Bitmap arrow = green ? mBitmapArrowGreenUp : mBitmapArrowRedUp;
-        Matrix matrix = new Matrix();
         final int cellWidth = mBitmapCircleDefault.getWidth();
         final int cellHeight = mBitmapCircleDefault.getHeight();
 
@@ -933,10 +933,10 @@
         final float angle = (float) Math.toDegrees(theta) + 90.0f;
 
         // compose matrix
-        matrix.setTranslate(leftX + offsetX, topY + offsetY); // transform to cell position
-        matrix.preRotate(angle, cellWidth / 2.0f, cellHeight / 2.0f);  // rotate about cell center
-        matrix.preTranslate((cellWidth - arrow.getWidth()) / 2.0f, 0.0f); // translate to 12:00 pos
-        canvas.drawBitmap(arrow, matrix, mPaint);
+        mArrowMatrix.setTranslate(leftX + offsetX, topY + offsetY); // transform to cell position
+        mArrowMatrix.preRotate(angle, cellWidth / 2.0f, cellHeight / 2.0f);  // rotate about cell center
+        mArrowMatrix.preTranslate((cellWidth - arrow.getWidth()) / 2.0f, 0.0f); // translate to 12:00 pos
+        canvas.drawBitmap(arrow, mArrowMatrix, mPaint);
     }
 
     /**
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index d661f7b..29158e5 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -38,7 +38,7 @@
 
 	LOCAL_CFLAGS += -DUSE_OPENGL_RENDERER
 	LOCAL_MODULE_CLASS := SHARED_LIBRARIES
-	LOCAL_SHARED_LIBRARIES := libcutils libutils libGLESv2 libskia
+	LOCAL_SHARED_LIBRARIES := libcutils libutils libGLESv2 libskia libui
 	LOCAL_MODULE := libhwui
 	LOCAL_MODULE_TAGS := optional
 	LOCAL_PRELINK_MODULE := false
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 0994d82..93c5b34 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -46,18 +46,21 @@
     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
 
     mCurrentBuffer = meshBuffer;
+    mRegionMesh = NULL;
 }
 
-/**
- * Binds the VBO used to render simple textured quads.
- */
+Caches::~Caches() {
+    delete[] mRegionMesh;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// VBO
+///////////////////////////////////////////////////////////////////////////////
+
 void Caches::bindMeshBuffer() {
     bindMeshBuffer(meshBuffer);
 }
 
-/**
- * Binds the specified VBO.
- */
 void Caches::bindMeshBuffer(const GLuint buffer) {
     if (mCurrentBuffer != buffer) {
         glBindBuffer(GL_ARRAY_BUFFER, buffer);
@@ -65,9 +68,6 @@
     }
 }
 
-/**
- * Unbinds the VBO used to render simple textured quads.
- */
 void Caches::unbindMeshBuffer() {
     if (mCurrentBuffer) {
         glBindBuffer(GL_ARRAY_BUFFER, 0);
@@ -75,5 +75,35 @@
     }
 }
 
+TextureVertex* Caches::getRegionMesh() {
+    // Create the mesh, 2 triangles and 4 vertices per rectangle in the region
+    if (!mRegionMesh) {
+        mRegionMesh = new TextureVertex[REGION_MESH_QUAD_COUNT * 4];
+
+        uint16_t* regionIndices = new uint16_t[REGION_MESH_QUAD_COUNT * 6];
+        for (int i = 0; i < REGION_MESH_QUAD_COUNT; i++) {
+            uint16_t quad = i * 4;
+            int index = i * 6;
+            regionIndices[index    ] = quad;       // top-left
+            regionIndices[index + 1] = quad + 1;   // top-right
+            regionIndices[index + 2] = quad + 2;   // bottom-left
+            regionIndices[index + 3] = quad + 2;   // bottom-left
+            regionIndices[index + 4] = quad + 1;   // top-right
+            regionIndices[index + 5] = quad + 3;   // bottom-right
+        }
+
+        glGenBuffers(1, &mRegionMeshIndices);
+        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mRegionMeshIndices);
+        glBufferData(GL_ELEMENT_ARRAY_BUFFER, REGION_MESH_QUAD_COUNT * 6 * sizeof(uint16_t),
+                regionIndices, GL_STATIC_DRAW);
+
+        delete[] regionIndices;
+    } else {
+        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mRegionMeshIndices);
+    }
+
+    return mRegionMesh;
+}
+
 }; // namespace uirenderer
 }; // namespace android
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index ca22867..c019fd1 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_UI_CACHES_H
-#define ANDROID_UI_CACHES_H
+#ifndef ANDROID_HWUI_CACHES_H
+#define ANDROID_HWUI_CACHES_H
 
 #ifndef LOG_TAG
     #define LOG_TAG "OpenGLRenderer"
@@ -46,6 +46,8 @@
 
 #define REQUIRED_TEXTURE_UNITS_COUNT 3
 
+#define REGION_MESH_QUAD_COUNT 512
+
 // Generates simple and textured vertices
 #define FV(x, y, u, v) { { x, y }, { u, v } }
 
@@ -77,6 +79,7 @@
 
 class Caches: public Singleton<Caches> {
     Caches();
+    ~Caches();
 
     friend class Singleton<Caches>;
 
@@ -84,11 +87,33 @@
 
     GLuint mCurrentBuffer;
 
+    // Used to render layers
+    TextureVertex* mRegionMesh;
+    GLuint mRegionMeshIndices;
+
 public:
+    /**
+     * Binds the VBO used to render simple textured quads.
+     */
     void bindMeshBuffer();
+
+    /**
+     * Binds the specified VBO if needed.
+     */
     void bindMeshBuffer(const GLuint buffer);
+
+    /**
+     * Unbinds the VBO used to render simple textured quads.
+     */
     void unbindMeshBuffer();
 
+    /**
+     * Returns the mesh used to draw regions. Calling this method will
+     * bind a VBO of type GL_ELEMENT_ARRAY_BUFFER that contains the
+     * indices for the region mesh.
+     */
+    TextureVertex* getRegionMesh();
+
     bool blend;
     GLenum lastSrcMode;
     GLenum lastDstMode;
@@ -118,7 +143,6 @@
 }; // class Caches
 
 }; // namespace uirenderer
-
 }; // namespace android
 
-#endif // ANDROID_UI_CACHES_H
+#endif // ANDROID_HWUI_CACHES_H
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 0dd9c5a..23ccef6 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -169,7 +169,8 @@
     int saveCount = renderer.getSaveCount() - 1;
 
     while (!mReader.eof()) {
-        switch (mReader.readInt()) {
+        int op = mReader.readInt();
+        switch (op) {
             case AcquireContext: {
                 renderer.acquireContext();
             }
@@ -195,6 +196,11 @@
                         getPaint(), getInt());
             }
             break;
+            case SaveLayerAlpha: {
+                renderer.saveLayerAlpha(getFloat(), getFloat(), getFloat(), getFloat(),
+                        getInt(), getInt());
+            }
+            break;
             case Translate: {
                 renderer.translate(getFloat(), getFloat());
             }
@@ -400,6 +406,15 @@
     return OpenGLRenderer::save(flags);
 }
 
+int DisplayListRenderer::saveLayerAlpha(float left, float top, float right, float bottom,
+        int alpha, int flags) {
+    addOp(DisplayList::SaveLayerAlpha);
+    addBounds(left, top, right, bottom);
+    addInt(alpha);
+    addInt(flags);
+    return OpenGLRenderer::save(flags);
+}
+
 void DisplayListRenderer::translate(float dx, float dy) {
     addOp(DisplayList::Translate);
     addPoint(dx, dy);
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 6636de6..fd69fab 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_UI_DISPLAY_LIST_RENDERER_H
-#define ANDROID_UI_DISPLAY_LIST_RENDERER_H
+#ifndef ANDROID_HWUI_DISPLAY_LIST_RENDERER_H
+#define ANDROID_HWUI_DISPLAY_LIST_RENDERER_H
 
 #include <SkChunkAlloc.h>
 #include <SkFlattenable.h>
@@ -85,6 +85,7 @@
         Restore,
         RestoreToCount,
         SaveLayer,
+        SaveLayerAlpha,
         Translate,
         Rotate,
         Scale,
@@ -222,6 +223,8 @@
 
     int saveLayer(float left, float top, float right, float bottom,
             SkPaint* p, int flags);
+    int saveLayerAlpha(float left, float top, float right, float bottom,
+                int alpha, int flags);
 
     void translate(float dx, float dy);
     void rotate(float degrees);
@@ -411,4 +414,4 @@
 }; // namespace uirenderer
 }; // namespace android
 
-#endif // ANDROID_UI_DISPLAY_LIST_RENDERER_H
+#endif // ANDROID_HWUI_DISPLAY_LIST_RENDERER_H
diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h
index d50d36e..eceb5c1c 100644
--- a/libs/hwui/Extensions.h
+++ b/libs/hwui/Extensions.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_UI_EXTENSIONS_H
-#define ANDROID_UI_EXTENSIONS_H
+#ifndef ANDROID_HWUI_EXTENSIONS_H
+#define ANDROID_HWUI_EXTENSIONS_H
 
 #include <utils/SortedVector.h>
 #include <utils/String8.h>
@@ -93,4 +93,4 @@
 }; // namespace uirenderer
 }; // namespace android
 
-#endif // ANDROID_UI_EXTENSIONS_H
+#endif // ANDROID_HWUI_EXTENSIONS_H
diff --git a/libs/hwui/FboCache.h b/libs/hwui/FboCache.h
index ec4afe9..ad6cc3e 100644
--- a/libs/hwui/FboCache.h
+++ b/libs/hwui/FboCache.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_UI_FBO_CACHE_H
-#define ANDROID_UI_FBO_CACHE_H
+#ifndef ANDROID_HWUI_FBO_CACHE_H
+#define ANDROID_HWUI_FBO_CACHE_H
 
 #include <GLES2/gl2.h>
 
@@ -76,4 +76,4 @@
 }; // namespace uirenderer
 }; // namespace android
 
-#endif // ANDROID_UI_FBO_CACHE_H
+#endif // ANDROID_HWUI_FBO_CACHE_H
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index e1a236c..5224689 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -556,6 +556,8 @@
 
     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBufferID);
     glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, NULL);
+
+    mDrawn = true;
 }
 
 void FontRenderer::appendMeshQuad(float x1, float y1, float z1, float u1, float v1, float x2,
@@ -595,6 +597,13 @@
 
     mCurrentQuadIndex++;
 
+    if (mBounds) {
+        mBounds->left = fmin(mBounds->left, x1);
+        mBounds->top = fmin(mBounds->top, y3);
+        mBounds->right = fmax(mBounds->right, x3);
+        mBounds->bottom = fmax(mBounds->bottom, y1);
+    }
+
     if (mCurrentQuadIndex == mMaxNumberOfQuads) {
         issueDrawCommand();
         mCurrentQuadIndex = 0;
@@ -674,22 +683,27 @@
     return image;
 }
 
-void FontRenderer::renderText(SkPaint* paint, const Rect* clip, const char *text,
-        uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y) {
+bool FontRenderer::renderText(SkPaint* paint, const Rect* clip, const char *text,
+        uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y, Rect* bounds) {
     checkInit();
 
     if (!mCurrentFont) {
         LOGE("No font set");
-        return;
+        return false;
     }
 
+    mDrawn = false;
+    mBounds = bounds;
     mClip = clip;
     mCurrentFont->renderUTF(paint, text, startIndex, len, numGlyphs, x, y);
+    mBounds = NULL;
 
     if (mCurrentQuadIndex != 0) {
         issueDrawCommand();
         mCurrentQuadIndex = 0;
     }
+
+    return mDrawn;
 }
 
 void FontRenderer::computeGaussianWeights(float* weights, int32_t radius) {
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index f10efad..a76cb86 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_UI_FONT_RENDERER_H
-#define ANDROID_UI_FONT_RENDERER_H
+#ifndef ANDROID_HWUI_FONT_RENDERER_H
+#define ANDROID_HWUI_FONT_RENDERER_H
 
 #include <utils/String8.h>
 #include <utils/String16.h>
@@ -132,8 +132,8 @@
     }
 
     void setFont(SkPaint* paint, uint32_t fontId, float fontSize);
-    void renderText(SkPaint* paint, const Rect* clip, const char *text, uint32_t startIndex,
-            uint32_t len, int numGlyphs, int x, int y);
+    bool renderText(SkPaint* paint, const Rect* clip, const char *text, uint32_t startIndex,
+            uint32_t len, int numGlyphs, int x, int y, Rect* bounds);
 
     struct DropShadow {
         DropShadow() { };
@@ -257,6 +257,8 @@
     uint32_t mIndexBufferID;
 
     const Rect* mClip;
+    Rect* mBounds;
+    bool mDrawn;
 
     bool mInitialized;
 
@@ -273,4 +275,4 @@
 }; // namespace uirenderer
 }; // namespace android
 
-#endif // ANDROID_UI_FONT_RENDERER_H
+#endif // ANDROID_HWUI_FONT_RENDERER_H
diff --git a/libs/hwui/GammaFontRenderer.h b/libs/hwui/GammaFontRenderer.h
index 5fa45cf..b59ae81 100644
--- a/libs/hwui/GammaFontRenderer.h
+++ b/libs/hwui/GammaFontRenderer.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_UI_GAMMA_FONT_RENDERER_H
-#define ANDROID_UI_GAMMA_FONT_RENDERER_H
+#ifndef ANDROID_HWUI_GAMMA_FONT_RENDERER_H
+#define ANDROID_HWUI_GAMMA_FONT_RENDERER_H
 
 #include <SkPaint.h>
 
@@ -45,4 +45,4 @@
 }; // namespace uirenderer
 }; // namespace android
 
-#endif // ANDROID_UI_GAMMA_FONT_RENDERER_H
+#endif // ANDROID_HWUI_GAMMA_FONT_RENDERER_H
diff --git a/libs/hwui/GradientCache.h b/libs/hwui/GradientCache.h
index 48877f6..c9553f4 100644
--- a/libs/hwui/GradientCache.h
+++ b/libs/hwui/GradientCache.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_UI_GRADIENT_CACHE_H
-#define ANDROID_UI_GRADIENT_CACHE_H
+#ifndef ANDROID_HWUI_GRADIENT_CACHE_H
+#define ANDROID_HWUI_GRADIENT_CACHE_H
 
 #include <SkShader.h>
 
@@ -93,4 +93,4 @@
 }; // namespace uirenderer
 }; // namespace android
 
-#endif // ANDROID_UI_GRADIENT_CACHE_H
+#endif // ANDROID_HWUI_GRADIENT_CACHE_H
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 2afe2fa..a780183 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -14,13 +14,15 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_UI_LAYER_H
-#define ANDROID_UI_LAYER_H
+#ifndef ANDROID_HWUI_LAYER_H
+#define ANDROID_HWUI_LAYER_H
 
 #include <sys/types.h>
 
 #include <GLES2/gl2.h>
 
+#include <ui/Region.h>
+
 #include <SkXfermode.h>
 
 #include "Rect.h"
@@ -85,9 +87,15 @@
      * Height of the layer texture.
      */
     uint32_t height;
+
+    /**
+     * Dirty region indicating what parts of the layer
+     * have been drawn.
+     */
+    Region region;
 }; // struct Layer
 
 }; // namespace uirenderer
 }; // namespace android
 
-#endif // ANDROID_UI_LAYER_H
+#endif // ANDROID_HWUI_LAYER_H
diff --git a/libs/hwui/LayerCache.h b/libs/hwui/LayerCache.h
index ae792ab..4df8ab3 100644
--- a/libs/hwui/LayerCache.h
+++ b/libs/hwui/LayerCache.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_UI_LAYER_CACHE_H
-#define ANDROID_UI_LAYER_CACHE_H
+#ifndef ANDROID_HWUI_LAYER_CACHE_H
+#define ANDROID_HWUI_LAYER_CACHE_H
 
 #include "Layer.h"
 #include "utils/SortedList.h"
@@ -138,4 +138,4 @@
 }; // namespace uirenderer
 }; // namespace android
 
-#endif // ANDROID_UI_LAYER_CACHE_H
+#endif // ANDROID_HWUI_LAYER_CACHE_H
diff --git a/libs/hwui/Line.h b/libs/hwui/Line.h
index c529354..5c6f3d8 100644
--- a/libs/hwui/Line.h
+++ b/libs/hwui/Line.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_UI_LINE_H
-#define ANDROID_UI_LINE_H
+#ifndef ANDROID_HWUI_LINE_H
+#define ANDROID_HWUI_LINE_H
 
 #include <GLES2/gl2.h>
 
@@ -123,4 +123,4 @@
 }; // namespace uirenderer
 }; // namespace android
 
-#endif // ANDROID_UI_LINE_H
+#endif // ANDROID_HWUI_LINE_H
diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp
index 83ea615..7462d5b 100644
--- a/libs/hwui/Matrix.cpp
+++ b/libs/hwui/Matrix.cpp
@@ -271,6 +271,19 @@
         MUL_ADD_STORE(r.right, data[kScaleX], data[kTranslateX]);
         MUL_ADD_STORE(r.top, data[kScaleY], data[kTranslateY]);
         MUL_ADD_STORE(r.bottom, data[kScaleY], data[kTranslateY]);
+
+        if (r.left > r.right) {
+            float x = r.left;
+            r.left = r.right;
+            r.right = x;
+        }
+
+        if (r.top > r.bottom) {
+            float y = r.top;
+            r.top = r.bottom;
+            r.bottom = y;
+        }
+
         return;
     }
 
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index fe81159..d678bd0 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_UI_MATRIX_H
-#define ANDROID_UI_MATRIX_H
+#ifndef ANDROID_HWUI_MATRIX_H
+#define ANDROID_HWUI_MATRIX_H
 
 #include <SkMatrix.h>
 
@@ -137,4 +137,4 @@
 }; // namespace uirenderer
 }; // namespace android
 
-#endif // ANDROID_UI_MATRIX_H
+#endif // ANDROID_HWUI_MATRIX_H
diff --git a/libs/hwui/OpenGLDebugRenderer.h b/libs/hwui/OpenGLDebugRenderer.h
index ce6a4aa..7787ff1 100644
--- a/libs/hwui/OpenGLDebugRenderer.h
+++ b/libs/hwui/OpenGLDebugRenderer.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_UI_OPENGL_DEBUG_RENDERER_H
-#define ANDROID_UI_OPENGL_DEBUG_RENDERER_H
+#ifndef ANDROID_HWUI_OPENGL_DEBUG_RENDERER_H
+#define ANDROID_HWUI_OPENGL_DEBUG_RENDERER_H
 
 #include "OpenGLRenderer.h"
 
@@ -66,4 +66,4 @@
 }; // namespace uirenderer
 }; // namespace android
 
-#endif // ANDROID_UI_OPENGL_DEBUG_RENDERER_H
+#endif // ANDROID_HWUI_OPENGL_DEBUG_RENDERER_H
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index b167131..0f0316f 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -26,6 +26,8 @@
 #include <utils/Log.h>
 #include <utils/StopWatch.h>
 
+#include <ui/Rect.h>
+
 #include "OpenGLRenderer.h"
 
 namespace android {
@@ -285,7 +287,7 @@
 
 int OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bottom,
         int alpha, int flags) {
-    if (alpha == 0xff) {
+    if (alpha >= 255 - ALPHA_THRESHOLD) {
         return saveLayer(left, top, right, bottom, NULL, flags);
     } else {
         SkPaint paint;
@@ -377,7 +379,6 @@
             bounds.getHeight() > mCaches.maxTextureSize) {
         snapshot->invisible = true;
     } else {
-        // TODO: Should take the mode into account
         snapshot->invisible = snapshot->previous->invisible ||
                 (alpha <= ALPHA_THRESHOLD && fboLayer);
     }
@@ -387,8 +388,7 @@
         return false;
     }
 
-    glActiveTexture(GL_TEXTURE0);
-
+    glActiveTexture(gTextureUnits[0]);
     Layer* layer = mCaches.layerCache.get(bounds.getWidth(), bounds.getHeight());
     if (!layer) {
         return false;
@@ -405,56 +405,7 @@
     snapshot->layer = layer;
 
     if (fboLayer) {
-        layer->fbo = mCaches.fboCache.get();
-
-        snapshot->flags |= Snapshot::kFlagIsFboLayer;
-        snapshot->fbo = layer->fbo;
-        snapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
-        snapshot->resetClip(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
-        snapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
-        snapshot->height = bounds.getHeight();
-        snapshot->flags |= Snapshot::kFlagDirtyOrtho;
-        snapshot->orthoMatrix.load(mOrthoMatrix);
-
-        // Bind texture to FBO
-        glBindFramebuffer(GL_FRAMEBUFFER, layer->fbo);
-        glBindTexture(GL_TEXTURE_2D, layer->texture);
-
-        // Initialize the texture if needed
-        if (layer->empty) {
-            layer->empty = false;
-            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, layer->width, layer->height, 0,
-                    GL_RGBA, GL_UNSIGNED_BYTE, NULL);
-        }
-
-        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
-                layer->texture, 0);
-
-#if DEBUG_LAYERS
-        GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
-        if (status != GL_FRAMEBUFFER_COMPLETE) {
-            LOGE("Framebuffer incomplete (GL error code 0x%x)", status);
-
-            glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
-            glDeleteTextures(1, &layer->texture);
-            mCaches.fboCache.put(layer->fbo);
-
-            delete layer;
-
-            return false;
-        }
-#endif
-
-        // Clear the FBO
-        glScissor(0.0f, 0.0f, bounds.getWidth() + 1.0f, bounds.getHeight() + 1.0f);
-        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
-        glClear(GL_COLOR_BUFFER_BIT);
-
-        dirtyClip();
-
-        // Change the ortho projection
-        glViewport(0, 0, bounds.getWidth(), bounds.getHeight());
-        mOrthoMatrix.loadOrtho(0.0f, bounds.getWidth(), bounds.getHeight(), 0.0f, -1.0f, 1.0f);
+        return createFboLayer(layer, bounds, snapshot, previousFbo);
     } else {
         // Copy the framebuffer into the layer
         glBindTexture(GL_TEXTURE_2D, layer->texture);
@@ -475,6 +426,82 @@
     return true;
 }
 
+bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, sp<Snapshot> snapshot,
+        GLuint previousFbo) {
+    layer->fbo = mCaches.fboCache.get();
+
+#if RENDER_LAYERS_AS_REGIONS
+    snapshot->region = &snapshot->layer->region;
+    snapshot->flags |= Snapshot::kFlagFboTarget;
+#endif
+
+    Rect clip(bounds);
+    snapshot->transform->mapRect(clip);
+    clip.intersect(*snapshot->clipRect);
+    clip.snapToPixelBoundaries();
+    clip.intersect(snapshot->previous->viewport);
+
+    mat4 inverse;
+    inverse.loadInverse(*mSnapshot->transform);
+
+    inverse.mapRect(clip);
+    clip.snapToPixelBoundaries();
+    clip.intersect(bounds);
+
+    snapshot->flags |= Snapshot::kFlagIsFboLayer;
+    snapshot->fbo = layer->fbo;
+    snapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
+    //snapshot->resetClip(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
+    snapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
+    snapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
+    snapshot->height = bounds.getHeight();
+    snapshot->flags |= Snapshot::kFlagDirtyOrtho;
+    snapshot->orthoMatrix.load(mOrthoMatrix);
+
+    // Bind texture to FBO
+    glBindFramebuffer(GL_FRAMEBUFFER, layer->fbo);
+    glBindTexture(GL_TEXTURE_2D, layer->texture);
+
+    // Initialize the texture if needed
+    if (layer->empty) {
+        layer->empty = false;
+        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, layer->width, layer->height, 0,
+                GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+    }
+
+    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+            layer->texture, 0);
+
+#if DEBUG_LAYERS_AS_REGIONS
+    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+    if (status != GL_FRAMEBUFFER_COMPLETE) {
+        LOGE("Framebuffer incomplete (GL error code 0x%x)", status);
+
+        glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
+        glDeleteTextures(1, &layer->texture);
+        mCaches.fboCache.put(layer->fbo);
+
+        delete layer;
+
+        return false;
+    }
+#endif
+
+    // Clear the FBO, expand the clear region by 1 to get nice bilinear filtering
+    glScissor(clip.left - 1.0f, bounds.getHeight() - clip.bottom - 1.0f,
+            clip.getWidth() + 2.0f, clip.getHeight() + 2.0f);
+    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+    glClear(GL_COLOR_BUFFER_BIT);
+
+    dirtyClip();
+
+    // Change the ortho projection
+    glViewport(0, 0, bounds.getWidth(), bounds.getHeight());
+    mOrthoMatrix.loadOrtho(0.0f, bounds.getWidth(), bounds.getHeight(), 0.0f, -1.0f, 1.0f);
+
+    return true;
+}
+
 /**
  * Read the documentation of createLayer() before doing anything in this method.
  */
@@ -484,42 +511,36 @@
         return;
     }
 
-    const bool fboLayer = current->flags & SkCanvas::kClipToLayer_SaveFlag;
+    const bool fboLayer = current->flags & Snapshot::kFlagIsFboLayer;
 
     if (fboLayer) {
         // Unbind current FBO and restore previous one
         glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo);
     }
 
-    // Restore the clip from the previous snapshot
-    Rect& clip(*previous->clipRect);
-    clip.snapToPixelBoundaries();
-    glScissor(clip.left, previous->height - clip.bottom, clip.getWidth(), clip.getHeight());
-
     Layer* layer = current->layer;
     const Rect& rect = layer->layer;
 
     if (!fboLayer && layer->alpha < 255) {
         drawColorRect(rect.left, rect.top, rect.right, rect.bottom,
                 layer->alpha << 24, SkXfermode::kDstIn_Mode, true);
+        // Required below, composeLayerRect() will divide by 255
+        layer->alpha = 255;
     }
 
-    const Rect& texCoords = layer->texCoords;
     mCaches.unbindMeshBuffer();
-    resetDrawTextureTexCoords(texCoords.left, texCoords.top, texCoords.right, texCoords.bottom);
 
     glActiveTexture(gTextureUnits[0]);
-    if (fboLayer) {
-        drawTextureMesh(rect.left, rect.top, rect.right, rect.bottom, layer->texture,
-                layer->alpha / 255.0f, layer->mode, layer->blend, &mMeshVertices[0].position[0],
-                &mMeshVertices[0].texture[0], GL_TRIANGLE_STRIP, gMeshCount);
-    } else {
-        drawTextureMesh(rect.left, rect.top, rect.right, rect.bottom, layer->texture,
-                1.0f, layer->mode, layer->blend, &mMeshVertices[0].position[0],
-                &mMeshVertices[0].texture[0], GL_TRIANGLE_STRIP, gMeshCount, true, true);
-    }
 
-    resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
+    // When the layer is stored in an FBO, we can save a bit of fillrate by
+    // drawing only the dirty region
+    if (fboLayer) {
+        dirtyLayer(rect.left, rect.top, rect.right, rect.bottom, *previous->transform);
+        composeLayerRegion(layer, rect);
+    } else {
+        dirtyLayer(rect.left, rect.top, rect.right, rect.bottom);
+        composeLayerRect(layer, rect, true);
+    }
 
     if (fboLayer) {
         // Detach the texture from the FBO
@@ -541,6 +562,159 @@
     }
 }
 
+void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) {
+    const Rect& texCoords = layer->texCoords;
+    resetDrawTextureTexCoords(texCoords.left, texCoords.top, texCoords.right, texCoords.bottom);
+
+    drawTextureMesh(rect.left, rect.top, rect.right, rect.bottom, layer->texture,
+            layer->alpha / 255.0f, layer->mode, layer->blend, &mMeshVertices[0].position[0],
+            &mMeshVertices[0].texture[0], GL_TRIANGLE_STRIP, gMeshCount, swap, swap);
+
+    resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
+}
+
+void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
+#if RENDER_LAYERS_AS_REGIONS
+    if (layer->region.isRect()) {
+        composeLayerRect(layer, rect);
+        layer->region.clear();
+        return;
+    }
+
+    if (!layer->region.isEmpty()) {
+        size_t count;
+        const android::Rect* rects = layer->region.getArray(&count);
+
+        setupDraw();
+
+        ProgramDescription description;
+        description.hasTexture = true;
+
+        const float alpha = layer->alpha / 255.0f;
+        const bool setColor = description.setColor(alpha, alpha, alpha, alpha);
+        chooseBlending(layer->blend || layer->alpha < 255, layer->mode, description, false);
+
+        useProgram(mCaches.programCache.get(description));
+
+        // Texture
+        bindTexture(layer->texture);
+        glUniform1i(mCaches.currentProgram->getUniform("sampler"), 0);
+
+        // Always premultiplied
+        if (setColor) {
+            mCaches.currentProgram->setColor(alpha, alpha, alpha, alpha);
+        }
+
+        // Mesh
+        int texCoordsSlot = mCaches.currentProgram->getAttrib("texCoords");
+        glEnableVertexAttribArray(texCoordsSlot);
+
+        mModelView.loadIdentity();
+        mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform);
+
+        const float texX = 1.0f / float(layer->width);
+        const float texY = 1.0f / float(layer->height);
+
+        TextureVertex* mesh = mCaches.getRegionMesh();
+        GLsizei numQuads = 0;
+
+        glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE,
+                gMeshStride, &mesh[0].position[0]);
+        glVertexAttribPointer(texCoordsSlot, 2, GL_FLOAT, GL_FALSE,
+                gMeshStride, &mesh[0].texture[0]);
+
+        for (size_t i = 0; i < count; i++) {
+            const android::Rect* r = &rects[i];
+
+            const float u1 = r->left * texX;
+            const float v1 = (rect.getHeight() - r->top) * texY;
+            const float u2 = r->right * texX;
+            const float v2 = (rect.getHeight() - r->bottom) * texY;
+
+            // TODO: Reject quads outside of the clip
+            TextureVertex::set(mesh++, r->left, r->top, u1, v1);
+            TextureVertex::set(mesh++, r->right, r->top, u2, v1);
+            TextureVertex::set(mesh++, r->left, r->bottom, u1, v2);
+            TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
+
+            numQuads++;
+
+            if (numQuads >= REGION_MESH_QUAD_COUNT) {
+                glDrawElements(GL_TRIANGLES, numQuads * 6, GL_UNSIGNED_SHORT, NULL);
+                numQuads = 0;
+                mesh = mCaches.getRegionMesh();
+            }
+        }
+
+        if (numQuads > 0) {
+            glDrawElements(GL_TRIANGLES, numQuads * 6, GL_UNSIGNED_SHORT, NULL);
+        }
+
+        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+        glDisableVertexAttribArray(texCoordsSlot);
+
+#if DEBUG_LAYERS_AS_REGIONS
+        uint32_t colors[] = {
+                0x7fff0000, 0x7f00ff00,
+                0x7f0000ff, 0x7fff00ff,
+        };
+
+        int offset = 0;
+        int32_t top = rects[0].top;
+        int i = 0;
+
+        for (size_t i = 0; i < count; i++) {
+            if (top != rects[i].top) {
+                offset ^= 0x2;
+                top = rects[i].top;
+            }
+
+            Rect r(rects[i].left, rects[i].top, rects[i].right, rects[i].bottom);
+            drawColorRect(r.left, r.top, r.right, r.bottom, colors[offset + (i & 0x1)],
+                    SkXfermode::kSrcOver_Mode);
+        }
+#endif
+
+        layer->region.clear();
+    }
+#else
+    composeLayerRect(layer, rect);
+#endif
+}
+
+void OpenGLRenderer::dirtyLayer(const float left, const float top,
+        const float right, const float bottom, const mat4 transform) {
+#if RENDER_LAYERS_AS_REGIONS
+    if ((mSnapshot->flags & Snapshot::kFlagFboTarget) && mSnapshot->region) {
+        Rect bounds(left, top, right, bottom);
+        transform.mapRect(bounds);
+        bounds.intersect(*mSnapshot->clipRect);
+        bounds.snapToPixelBoundaries();
+
+        android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom);
+        if (!dirty.isEmpty()) {
+            mSnapshot->region->orSelf(dirty);
+        }
+    }
+#endif
+}
+
+void OpenGLRenderer::dirtyLayer(const float left, const float top,
+        const float right, const float bottom) {
+#if RENDER_LAYERS_AS_REGIONS
+    if ((mSnapshot->flags & Snapshot::kFlagFboTarget) && mSnapshot->region) {
+        Rect bounds(left, top, right, bottom);
+        bounds.intersect(*mSnapshot->clipRect);
+        bounds.snapToPixelBoundaries();
+
+        android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom);
+        if (!dirty.isEmpty()) {
+            mSnapshot->region->orSelf(dirty);
+        }
+    }
+#endif
+}
+
 void OpenGLRenderer::setupDraw() {
     clearLayerRegions();
     if (mDirtyClip) {
@@ -551,21 +725,26 @@
 void OpenGLRenderer::clearLayerRegions() {
     if (mLayers.size() == 0 || mSnapshot->invisible) return;
 
+    Rect clipRect(*mSnapshot->clipRect);
+    clipRect.snapToPixelBoundaries();
+
     for (uint32_t i = 0; i < mLayers.size(); i++) {
         Rect* bounds = mLayers.itemAt(i);
+        if (clipRect.intersects(*bounds)) {
+            // Clear the framebuffer where the layer will draw
+            glScissor(bounds->left, mSnapshot->height - bounds->bottom,
+                    bounds->getWidth(), bounds->getHeight());
+            glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+            glClear(GL_COLOR_BUFFER_BIT);
 
-        // Clear the framebuffer where the layer will draw
-        glScissor(bounds->left, mSnapshot->height - bounds->bottom,
-                bounds->getWidth(), bounds->getHeight());
-        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
-        glClear(GL_COLOR_BUFFER_BIT);
+            // Restore the clip
+            dirtyClip();
+        }
 
         delete bounds;
     }
-    mLayers.clear();
 
-    // Restore the clip
-    dirtyClip();
+    mLayers.clear();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -678,7 +857,12 @@
     if (!texture) return;
     const AutoTexture autoCleanup(texture);
 
-    drawTextureRect(r.left, r.top, r.right, r.bottom, texture, paint);
+    // This could be done in a cheaper way, all we need is pass the matrix
+    // to the vertex shader. The save/restore is a bit overkill.
+    save(SkCanvas::kMatrix_SaveFlag);
+    concatMatrix(matrix);
+    drawTextureRect(0.0f, 0.0f, bitmap->width(), bitmap->height(), texture, paint);
+    restore();
 }
 
 void OpenGLRenderer::drawBitmap(SkBitmap* bitmap,
@@ -738,11 +922,21 @@
             right - left, bottom - top, xDivs, yDivs, colors, width, height, numColors);
 
     if (mesh) {
-        // Specify right and bottom as +1.0f from left/top to prevent scaling since the
-        // patch mesh already defines the final size
-        drawTextureMesh(left, top, left + 1.0f, top + 1.0f, texture->id, alpha / 255.0f,
+        // Mark the current layer dirty where we are going to draw the patch
+        if ((mSnapshot->flags & Snapshot::kFlagFboTarget) &&
+                mSnapshot->region && mesh->hasEmptyQuads) {
+            const size_t count = mesh->quads.size();
+            for (size_t i = 0; i < count; i++) {
+                Rect bounds = mesh->quads.itemAt(i);
+                dirtyLayer(bounds.left, bounds.top, bounds.right, bounds.bottom,
+                        *mSnapshot->transform);
+            }
+        }
+
+        drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f,
                 mode, texture->blend, (GLvoid*) 0, (GLvoid*) gMeshTextureOffset,
-                GL_TRIANGLES, mesh->verticesCount, false, false, mesh->meshBuffer);
+                GL_TRIANGLES, mesh->verticesCount, false, false, mesh->meshBuffer,
+                true, !mesh->hasEmptyQuads);
     }
 }
 
@@ -801,6 +995,7 @@
             mModelView.scale(length, strokeWidth, 1.0f);
         }
         mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform);
+        // TODO: Add bounds to the layer's region
 
         if (mShader) {
             mShader->updateTransforms(mCaches.currentProgram, mModelView, *mSnapshot);
@@ -904,13 +1099,34 @@
 
     // Assume that the modelView matrix does not force scales, rotates, etc.
     const bool linearFilter = mSnapshot->transform->changesBounds();
+
+    // Dimensions are set to (0,0), the layer (if any) won't be dirtied
     setupTextureAlpha8(fontRenderer.getTexture(linearFilter), 0, 0, textureUnit,
             x, y, r, g, b, a, mode, false, true, NULL, NULL);
 
     const Rect& clip = mSnapshot->getLocalClip();
+    Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
+
+#if RENDER_LAYERS_AS_REGIONS
+    bool hasLayer = (mSnapshot->flags & Snapshot::kFlagFboTarget) && mSnapshot->region;
+#else
+    bool hasLayer = false;
+#endif
 
     mCaches.unbindMeshBuffer();
-    fontRenderer.renderText(paint, &clip, text, 0, bytesCount, count, x, y);
+    if (fontRenderer.renderText(paint, &clip, text, 0, bytesCount, count, x, y,
+            hasLayer ? &bounds : NULL)) {
+#if RENDER_LAYERS_AS_REGIONS
+        if (hasLayer) {
+            mSnapshot->transform->mapRect(bounds);
+            bounds.intersect(*mSnapshot->clipRect);
+            bounds.snapToPixelBoundaries();
+
+            android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom);
+            mSnapshot->region->orSelf(dirty);
+        }
+#endif
+    }
 
     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
     glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords"));
@@ -1081,7 +1297,12 @@
      } else {
          mModelView.loadIdentity();
      }
+
      mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform);
+     if (width > 0 && height > 0) {
+         dirtyLayer(x, y, x + width, y + height, *mSnapshot->transform);
+     }
+
      if (setColor) {
          mCaches.currentProgram->setColor(r, g, b, a);
      }
@@ -1214,9 +1435,11 @@
     mModelView.scale(right - left, bottom - top, 1.0f);
     if (!ignoreTransform) {
         mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform);
+        dirtyLayer(left, top, right, bottom, *mSnapshot->transform);
     } else {
         mat4 identity;
         mCaches.currentProgram->set(mOrthoMatrix, mModelView, identity);
+        dirtyLayer(left, top, right, bottom);
     }
     mCaches.currentProgram->setColor(r, g, b, a);
 
@@ -1251,7 +1474,7 @@
 void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float bottom,
         GLuint texture, float alpha, SkXfermode::Mode mode, bool blend,
         GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
-        bool swapSrcDst, bool ignoreTransform, GLuint vbo) {
+        bool swapSrcDst, bool ignoreTransform, GLuint vbo, bool ignoreScale, bool dirty) {
     setupDraw();
 
     ProgramDescription description;
@@ -1262,16 +1485,20 @@
     }
 
     mModelView.loadTranslate(left, top, 0.0f);
-    mModelView.scale(right - left, bottom - top, 1.0f);
+    if (!ignoreScale) {
+        mModelView.scale(right - left, bottom - top, 1.0f);
+    }
 
     chooseBlending(blend || alpha < 1.0f, mode, description, swapSrcDst);
 
     useProgram(mCaches.programCache.get(description));
     if (!ignoreTransform) {
         mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform);
+        if (dirty) dirtyLayer(left, top, right, bottom, *mSnapshot->transform);
     } else {
-        mat4 m;
-        mCaches.currentProgram->set(mOrthoMatrix, mModelView, m);
+        mat4 identity;
+        mCaches.currentProgram->set(mOrthoMatrix, mModelView, identity);
+        if (dirty) dirtyLayer(left, top, right, bottom);
     }
 
     // Texture
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 3492d2c..2d612d4 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_UI_OPENGL_RENDERER_H
-#define ANDROID_UI_OPENGL_RENDERER_H
+#ifndef ANDROID_HWUI_OPENGL_RENDERER_H
+#define ANDROID_HWUI_OPENGL_RENDERER_H
 
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
@@ -50,6 +50,10 @@
 // Debug
 #define DEBUG_OPENGL 1
 
+// If turned on, layers drawn inside FBOs are optimized with regions
+#define RENDER_LAYERS_AS_REGIONS 0
+#define DEBUG_LAYERS_AS_REGIONS 0
+
 ///////////////////////////////////////////////////////////////////////////////
 // Renderer
 ///////////////////////////////////////////////////////////////////////////////
@@ -176,6 +180,34 @@
             int alpha, SkXfermode::Mode mode, int flags, GLuint previousFbo);
 
     /**
+     * Creates a new layer stored in the specified snapshot as an FBO.
+     *
+     * @param layer The layer to store as an FBO
+     * @param snapshot The snapshot associated with the new layer
+     * @param bounds The bounds of the layer
+     * @param previousFbo The name of the current framebuffer
+     */
+    bool createFboLayer(Layer* layer, Rect& bounds, sp<Snapshot> snapshot,
+            GLuint previousFbo);
+
+    /**
+     * Compose the specified layer as a region.
+     *
+     * @param layer The layer to compose
+     * @param rect The layer's bounds
+     */
+    void composeLayerRegion(Layer* layer, const Rect& rect);
+
+    /**
+     * Compose the specified layer as a simple rectangle.
+     *
+     * @param layer The layer to compose
+     * @param rect The layer's bounds
+     * @param swap If true, the source and destination are swapped
+     */
+    void composeLayerRect(Layer* layer, const Rect& rect, bool swap = false);
+
+    /**
      * Clears all the regions corresponding to the current list of layers.
      * This method MUST be invoked before any drawing operation.
      */
@@ -192,7 +224,7 @@
      * @param color The rectangle's ARGB color, defined as a packed 32 bits word
      * @param mode The Skia xfermode to use
      * @param ignoreTransform True if the current transform should be ignored
-     * @paran ignoreBlending True if the blending is set by the caller
+     * @param ignoreBlending True if the blending is set by the caller
      */
     void drawColorRect(float left, float top, float right, float bottom,
             int color, SkXfermode::Mode mode, bool ignoreTransform = false);
@@ -252,11 +284,14 @@
      * @param swapSrcDst Whether or not the src and dst blending operations should be swapped
      * @param ignoreTransform True if the current transform should be ignored
      * @param vbo The VBO used to draw the mesh
+     * @param ignoreScale True if the model view matrix should not be scaled
+     * @param dirty True if calling this method should dirty the current layer
      */
     void drawTextureMesh(float left, float top, float right, float bottom, GLuint texture,
             float alpha, SkXfermode::Mode mode, bool blend,
             GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
-            bool swapSrcDst = false, bool ignoreTransform = false, GLuint vbo = 0);
+            bool swapSrcDst = false, bool ignoreTransform = false, GLuint vbo = 0,
+            bool ignoreScale = false, bool dirty = true);
 
     /**
      * Prepares the renderer to draw the specified shadow. The active texture
@@ -411,6 +446,18 @@
         mDirtyClip = true;
     }
 
+    /**
+     * Mark the layer as dirty at the specified coordinates. The coordinates
+     * are transformed with the supplied matrix.
+     */
+    void dirtyLayer(const float left, const float top, const float right, const float bottom,
+            const mat4 transform);
+
+    /**
+     * Mark the layer as dirty at the specified coordinates.
+     */
+    void dirtyLayer(const float left, const float top, const float right, const float bottom);
+
     // Dimensions of the drawing surface
     int mWidth, mHeight;
 
@@ -462,4 +509,4 @@
 }; // namespace uirenderer
 }; // namespace android
 
-#endif // ANDROID_UI_OPENGL_RENDERER_H
+#endif // ANDROID_HWUI_OPENGL_RENDERER_H
diff --git a/libs/hwui/Patch.cpp b/libs/hwui/Patch.cpp
index 3d21431..9b2d476 100644
--- a/libs/hwui/Patch.cpp
+++ b/libs/hwui/Patch.cpp
@@ -34,6 +34,7 @@
     // 2 triangles per patch, 3 vertices per triangle
     verticesCount = ((xCount + 1) * (yCount + 1) - emptyQuads) * 2 * 3;
     mVertices = new TextureVertex[verticesCount];
+    hasEmptyQuads = emptyQuads > 0;
 
     glGenBuffers(1, &meshBuffer);
 }
@@ -51,6 +52,8 @@
         float left, float top, float right, float bottom,
         const int32_t* xDivs, const int32_t* yDivs,
         const uint32_t width, const uint32_t height, const uint32_t colorKey) {
+    if (hasEmptyQuads) quads.clear();
+
     const uint32_t xStretchCount = (width + 1) >> 1;
     const uint32_t yStretchCount = (height + 1) >> 1;
 
@@ -118,7 +121,7 @@
                 mVertices, GL_STATIC_DRAW);
 }
 
-inline void Patch::generateRow(TextureVertex*& vertex, float y1, float y2, float v1, float v2,
+void Patch::generateRow(TextureVertex*& vertex, float y1, float y2, float v1, float v2,
         const int32_t xDivs[], uint32_t xCount, float stretchX, float width, float bitmapWidth,
         uint32_t& quadCount, const uint32_t colorKey) {
     float previousStepX = 0.0f;
@@ -150,12 +153,17 @@
     generateQuad(vertex, x1, y1, width, y2, u1, v1, 1.0f, v2, quadCount, colorKey);
 }
 
-inline void Patch::generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2,
+void Patch::generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2,
             float u1, float v1, float u2, float v2, uint32_t& quadCount, const uint32_t colorKey) {
     if (((colorKey >> quadCount++) & 0x1) == 1) {
         return;
     }
 
+    if (hasEmptyQuads) {
+        Rect bounds(x1, y1, x2, y2);
+        quads.add(bounds);
+    }
+
     // Left triangle
     TextureVertex::set(vertex++, x1, y1, u1, v1);
     TextureVertex::set(vertex++, x2, y1, u2, v1);
diff --git a/libs/hwui/Patch.h b/libs/hwui/Patch.h
index ce898937..1e78b2f 100644
--- a/libs/hwui/Patch.h
+++ b/libs/hwui/Patch.h
@@ -14,13 +14,16 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_UI_PATCH_H
-#define ANDROID_UI_PATCH_H
+#ifndef ANDROID_HWUI_PATCH_H
+#define ANDROID_HWUI_PATCH_H
 
 #include <sys/types.h>
 
 #include <GLES2/gl2.h>
 
+#include <utils/Vector.h>
+
+#include "Rect.h"
 #include "Vertex.h"
 #include "utils/Compare.h"
 
@@ -96,15 +99,17 @@
 
     GLuint meshBuffer;
     uint32_t verticesCount;
+    Vector<Rect> quads;
+    bool hasEmptyQuads;
 
 private:
     TextureVertex* mVertices;
 
-    static inline void generateRow(TextureVertex*& vertex, float y1, float y2,
+    void generateRow(TextureVertex*& vertex, float y1, float y2,
             float v1, float v2, const int32_t xDivs[], uint32_t xCount,
             float stretchX, float width, float bitmapWidth,
             uint32_t& quadCount, const uint32_t colorKey);
-    static inline void generateQuad(TextureVertex*& vertex,
+    void generateQuad(TextureVertex*& vertex,
             float x1, float y1, float x2, float y2,
             float u1, float v1, float u2, float v2,
             uint32_t& quadCount, const uint32_t colorKey);
@@ -113,4 +118,4 @@
 }; // namespace uirenderer
 }; // namespace android
 
-#endif // ANDROID_UI_PATCH_H
+#endif // ANDROID_HWUI_PATCH_H
diff --git a/libs/hwui/PatchCache.h b/libs/hwui/PatchCache.h
index f4eeb09..deba40d 100644
--- a/libs/hwui/PatchCache.h
+++ b/libs/hwui/PatchCache.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_UI_PATCH_CACHE_H
-#define ANDROID_UI_PATCH_CACHE_H
+#ifndef ANDROID_HWUI_PATCH_CACHE_H
+#define ANDROID_HWUI_PATCH_CACHE_H
 
 #include <utils/KeyedVector.h>
 
@@ -62,4 +62,4 @@
 }; // namespace uirenderer
 }; // namespace android
 
-#endif // ANDROID_UI_PATCH_CACHE_H
+#endif // ANDROID_HWUI_PATCH_CACHE_H
diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h
index 9a5fc45..db5ce08 100644
--- a/libs/hwui/PathCache.h
+++ b/libs/hwui/PathCache.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_UI_PATH_CACHE_H
-#define ANDROID_UI_PATH_CACHE_H
+#ifndef ANDROID_HWUI_PATH_CACHE_H
+#define ANDROID_HWUI_PATH_CACHE_H
 
 #include <SkBitmap.h>
 #include <SkPaint.h>
@@ -170,4 +170,4 @@
 }; // namespace uirenderer
 }; // namespace android
 
-#endif // ANDROID_UI_PATH_CACHE_H
+#endif // ANDROID_HWUI_PATH_CACHE_H
diff --git a/libs/hwui/Program.cpp b/libs/hwui/Program.cpp
index 25674c6..baed5fd7 100644
--- a/libs/hwui/Program.cpp
+++ b/libs/hwui/Program.cpp
@@ -22,12 +22,6 @@
 namespace uirenderer {
 
 ///////////////////////////////////////////////////////////////////////////////
-// Shaders
-///////////////////////////////////////////////////////////////////////////////
-
-#define SHADER_SOURCE(name, source) const char* name = #source
-
-///////////////////////////////////////////////////////////////////////////////
 // Base program
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index 026097c..5981662 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_UI_PROGRAM_H
-#define ANDROID_UI_PROGRAM_H
+#ifndef ANDROID_HWUI_PROGRAM_H
+#define ANDROID_HWUI_PROGRAM_H
 
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
@@ -131,4 +131,4 @@
 }; // namespace uirenderer
 }; // namespace android
 
-#endif // ANDROID_UI_PROGRAM_H
+#endif // ANDROID_HWUI_PROGRAM_H
diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h
index 9cb13b3..186e869 100644
--- a/libs/hwui/ProgramCache.h
+++ b/libs/hwui/ProgramCache.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_UI_PROGRAM_CACHE_H
-#define ANDROID_UI_PROGRAM_CACHE_H
+#ifndef ANDROID_HWUI_PROGRAM_CACHE_H
+#define ANDROID_HWUI_PROGRAM_CACHE_H
 
 #include <utils/KeyedVector.h>
 #include <utils/Log.h>
@@ -258,4 +258,4 @@
 }; // namespace uirenderer
 }; // namespace android
 
-#endif // ANDROID_UI_PROGRAM_CACHE_H
+#endif // ANDROID_HWUI_PROGRAM_CACHE_H
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index db3cb4d..813392b 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_UI_PROPERTIES_H
-#define ANDROID_UI_PROPERTIES_H
+#ifndef ANDROID_HWUI_PROPERTIES_H
+#define ANDROID_HWUI_PROPERTIES_H
 
 #include <cutils/properties.h>
 
@@ -45,15 +45,15 @@
 #define MB(s) s * 1024 * 1024
 
 #define DEFAULT_TEXTURE_CACHE_SIZE 20.0f
-#define DEFAULT_LAYER_CACHE_SIZE 6.0f
+#define DEFAULT_LAYER_CACHE_SIZE 8.0f
 #define DEFAULT_PATH_CACHE_SIZE 4.0f
 #define DEFAULT_PATCH_CACHE_SIZE 512
 #define DEFAULT_GRADIENT_CACHE_SIZE 0.5f
 #define DEFAULT_DROP_SHADOW_CACHE_SIZE 2.0f
-#define DEFAULT_FBO_CACHE_SIZE 25
+#define DEFAULT_FBO_CACHE_SIZE 12
 
 #define DEFAULT_TEXT_GAMMA 1.4f
 #define DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD 64
 #define DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD 192
 
-#endif // ANDROID_UI_PROPERTIES_H
+#endif // ANDROID_HWUI_PROPERTIES_H
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index 8f3655c..71951b7 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -14,8 +14,10 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_UI_RECT_H
-#define ANDROID_UI_RECT_H
+#ifndef ANDROID_HWUI_RECT_H
+#define ANDROID_HWUI_RECT_H
+
+#include <cmath>
 
 #include <utils/Log.h>
 
@@ -32,25 +34,35 @@
     float right;
     float bottom;
 
-    Rect():
+    // Used by Region
+    typedef float value_type;
+
+    inline Rect():
             left(0),
             top(0),
             right(0),
             bottom(0) {
     }
 
-    Rect(float left, float top, float right, float bottom):
+    inline Rect(float left, float top, float right, float bottom):
             left(left),
             top(top),
             right(right),
             bottom(bottom) {
     }
 
-    Rect(const Rect& r) {
+    inline Rect(float width, float height):
+            left(0.0f),
+            top(0.0f),
+            right(width),
+            bottom(height) {
+    }
+
+    inline Rect(const Rect& r) {
         set(r);
     }
 
-    Rect(Rect& r) {
+    inline Rect(Rect& r) {
         set(r);
     }
 
@@ -72,22 +84,26 @@
         return memcmp(&a, &b, sizeof(a));
     }
 
-    bool isEmpty() const {
+    inline void clear() {
+        left = top = right = bottom = 0.0f;
+    }
+
+    inline bool isEmpty() const {
         return left >= right || top >= bottom;
     }
 
-    void setEmpty() {
-        memset(this, 0, sizeof(*this));
+    inline void setEmpty() {
+        left = top = right = bottom = 0.0f;
     }
 
-    void set(float left, float top, float right, float bottom) {
+    inline void set(float left, float top, float right, float bottom) {
         this->left = left;
         this->right = right;
         this->top = top;
         this->bottom = bottom;
     }
 
-    void set(const Rect& r) {
+    inline void set(const Rect& r) {
         set(r.left, r.top, r.right, r.bottom);
     }
 
@@ -148,6 +164,13 @@
         return false;
     }
 
+    void translate(float dx, float dy) {
+        left += dx;
+        right += dx;
+        top += dy;
+        bottom += dy;
+    }
+
     void snapToPixelBoundaries() {
         left = floorf(left + 0.5f);
         top = floorf(top + 0.5f);
@@ -164,4 +187,4 @@
 }; // namespace uirenderer
 }; // namespace android
 
-#endif // ANDROID_UI_RECT_H
+#endif // ANDROID_HWUI_RECT_H
diff --git a/libs/hwui/ResourceCache.h b/libs/hwui/ResourceCache.h
index d9b3718..2256fd1 100644
--- a/libs/hwui/ResourceCache.h
+++ b/libs/hwui/ResourceCache.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_UI_RESOURCE_CACHE_H
-#define ANDROID_UI_RESOURCE_CACHE_H
+#ifndef ANDROID_HWUI_RESOURCE_CACHE_H
+#define ANDROID_HWUI_RESOURCE_CACHE_H
 
 #include <SkBitmap.h>
 #include <SkiaColorFilter.h>
@@ -75,4 +75,4 @@
 }; // namespace uirenderer
 }; // namespace android
 
-#endif // ANDROID_UI_RESOURCE_CACHE_H
+#endif // ANDROID_HWUI_RESOURCE_CACHE_H
diff --git a/libs/hwui/SkiaColorFilter.h b/libs/hwui/SkiaColorFilter.h
index 17f49f9..bf45e13 100644
--- a/libs/hwui/SkiaColorFilter.h
+++ b/libs/hwui/SkiaColorFilter.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_UI_SKIA_COLOR_FILTER_H
-#define ANDROID_UI_SKIA_COLOR_FILTER_H
+#ifndef ANDROID_HWUI_SKIA_COLOR_FILTER_H
+#define ANDROID_HWUI_SKIA_COLOR_FILTER_H
 
 #include <GLES2/gl2.h>
 #include <SkColorFilter.h>
@@ -123,4 +123,4 @@
 }; // namespace uirenderer
 }; // namespace android
 
-#endif // ANDROID_UI_SKIA_COLOR_FILTER_H
+#endif // ANDROID_HWUI_SKIA_COLOR_FILTER_H
diff --git a/libs/hwui/SkiaShader.h b/libs/hwui/SkiaShader.h
index 4cd1b8b..1d884ab 100644
--- a/libs/hwui/SkiaShader.h
+++ b/libs/hwui/SkiaShader.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_UI_SKIA_SHADER_H
-#define ANDROID_UI_SKIA_SHADER_H
+#ifndef ANDROID_HWUI_SKIA_SHADER_H
+#define ANDROID_HWUI_SKIA_SHADER_H
 
 #include <SkShader.h>
 #include <SkXfermode.h>
@@ -216,4 +216,4 @@
 }; // namespace uirenderer
 }; // namespace android
 
-#endif // ANDROID_UI_SKIA_SHADER_H
+#endif // ANDROID_HWUI_SKIA_SHADER_H
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index 2da1950..9f78063 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -14,16 +14,16 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_UI_SNAPSHOT_H
-#define ANDROID_UI_SNAPSHOT_H
+#ifndef ANDROID_HWUI_SNAPSHOT_H
+#define ANDROID_HWUI_SNAPSHOT_H
 
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 
 #include <utils/RefBase.h>
+#include <ui/Region.h>
 
 #include <SkCanvas.h>
-#include <SkRegion.h>
 
 #include "Layer.h"
 #include "Matrix.h"
@@ -46,6 +46,7 @@
     Snapshot(): flags(0), previous(NULL), layer(NULL), fbo(0), invisible(false) {
         transform = &mTransformRoot;
         clipRect = &mClipRectRoot;
+        region = NULL;
     }
 
     /**
@@ -75,6 +76,13 @@
         } else {
             flags |= Snapshot::kFlagDirtyLocalClip;
         }
+
+        if (s->flags & Snapshot::kFlagFboTarget) {
+            flags |= Snapshot::kFlagFboTarget;
+            region = s->region;
+        } else {
+            region = NULL;
+        }
     }
 
     /**
@@ -105,6 +113,11 @@
          * Indicates that this snapshot has changed the ortho matrix.
          */
         kFlagDirtyOrtho = 0x10,
+        /**
+         * Indicates that this snapshot or an ancestor snapshot is
+         * an FBO layer.
+         */
+        kFlagFboTarget = 0x20
     };
 
     /**
@@ -243,6 +256,11 @@
      */
     Rect* clipRect;
 
+    /**
+     * The ancestor layer's dirty region..
+     */
+    Region* region;
+
 private:
     mat4 mTransformRoot;
     Rect mClipRectRoot;
@@ -253,4 +271,4 @@
 }; // namespace uirenderer
 }; // namespace android
 
-#endif // ANDROID_UI_SNAPSHOT_H
+#endif // ANDROID_HWUI_SNAPSHOT_H
diff --git a/libs/hwui/TextDropShadowCache.h b/libs/hwui/TextDropShadowCache.h
index 16e2814..adf09e2 100644
--- a/libs/hwui/TextDropShadowCache.h
+++ b/libs/hwui/TextDropShadowCache.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_UI_TEXT_DROP_SHADOW_CACHE_H
-#define ANDROID_UI_TEXT_DROP_SHADOW_CACHE_H
+#ifndef ANDROID_HWUI_TEXT_DROP_SHADOW_CACHE_H
+#define ANDROID_HWUI_TEXT_DROP_SHADOW_CACHE_H
 
 #include <GLES2/gl2.h>
 
@@ -148,4 +148,4 @@
 }; // namespace uirenderer
 }; // namespace android
 
-#endif // ANDROID_UI_TEXT_DROP_SHADOW_CACHE_H
+#endif // ANDROID_HWUI_TEXT_DROP_SHADOW_CACHE_H
diff --git a/libs/hwui/Texture.h b/libs/hwui/Texture.h
index 755074d..4922bb3 100644
--- a/libs/hwui/Texture.h
+++ b/libs/hwui/Texture.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_UI_TEXTURE_H
-#define ANDROID_UI_TEXTURE_H
+#ifndef ANDROID_HWUI_TEXTURE_H
+#define ANDROID_HWUI_TEXTURE_H
 
 #include <GLES2/gl2.h>
 
@@ -86,4 +86,4 @@
 }; // namespace uirenderer
 }; // namespace android
 
-#endif // ANDROID_UI_TEXTURE_H
+#endif // ANDROID_HWUI_TEXTURE_H
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index d860953..0c7948f 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -200,9 +200,13 @@
         texture->blend = !bitmap->isOpaque();
         break;
     case SkBitmap::kIndex8_Config:
-        uploadPalettedTexture(resize, bitmap, texture->width, texture->height);
+        uploadLoFiTexture(resize, bitmap, texture->width, texture->height);
         texture->blend = false;
         break;
+    case SkBitmap::kARGB_4444_Config:
+        uploadLoFiTexture(resize, bitmap, texture->width, texture->height);
+        texture->blend = true;
+        break;
     default:
         LOGW("Unsupported bitmap config: %d", bitmap->getConfig());
         break;
@@ -215,7 +219,7 @@
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 }
 
-void TextureCache::uploadPalettedTexture(bool resize, SkBitmap* bitmap,
+void TextureCache::uploadLoFiTexture(bool resize, SkBitmap* bitmap,
         uint32_t width, uint32_t height) {
     SkBitmap rgbaBitmap;
     rgbaBitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h
index 6718597..d9d2387 100644
--- a/libs/hwui/TextureCache.h
+++ b/libs/hwui/TextureCache.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_UI_TEXTURE_CACHE_H
-#define ANDROID_UI_TEXTURE_CACHE_H
+#ifndef ANDROID_HWUI_TEXTURE_CACHE_H
+#define ANDROID_HWUI_TEXTURE_CACHE_H
 
 #include <SkBitmap.h>
 
@@ -93,7 +93,7 @@
      */
     void generateTexture(SkBitmap* bitmap, Texture* texture, bool regenerate = false);
 
-    void uploadPalettedTexture(bool resize, SkBitmap* bitmap, uint32_t width, uint32_t height);
+    void uploadLoFiTexture(bool resize, SkBitmap* bitmap, uint32_t width, uint32_t height);
     void uploadToTexture(bool resize, GLenum format, GLsizei width, GLsizei height,
             GLenum type, const GLvoid * data);
 
@@ -115,4 +115,4 @@
 }; // namespace uirenderer
 }; // namespace android
 
-#endif // ANDROID_UI_TEXTURE_CACHE_H
+#endif // ANDROID_HWUI_TEXTURE_CACHE_H
diff --git a/libs/hwui/Vertex.h b/libs/hwui/Vertex.h
index 1f54086..bbf4d4a 100644
--- a/libs/hwui/Vertex.h
+++ b/libs/hwui/Vertex.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_UI_VERTEX_H
-#define ANDROID_UI_VERTEX_H
+#ifndef ANDROID_HWUI_VERTEX_H
+#define ANDROID_HWUI_VERTEX_H
 
 namespace android {
 namespace uirenderer {
@@ -43,4 +43,4 @@
 }; // namespace uirenderer
 }; // namespace android
 
-#endif // ANDROID_UI_VERTEX_H
+#endif // ANDROID_HWUI_VERTEX_H
diff --git a/libs/hwui/utils/Compare.h b/libs/hwui/utils/Compare.h
index 5ea0fc9..6531e78 100644
--- a/libs/hwui/utils/Compare.h
+++ b/libs/hwui/utils/Compare.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_UI_COMPARE_H
-#define ANDROID_UI_COMPARE_H
+#ifndef ANDROID_HWUI_COMPARE_H
+#define ANDROID_HWUI_COMPARE_H
 
 #include <cmath>
 
@@ -37,4 +37,4 @@
     if (a < rhs.a) return true; \
     if (a == rhs.a)
 
-#endif // ANDROID_UI_COMPARE_H
+#endif // ANDROID_HWUI_COMPARE_H
diff --git a/libs/hwui/utils/GenerationCache.h b/libs/hwui/utils/GenerationCache.h
index 5cea30f..2e76236 100644
--- a/libs/hwui/utils/GenerationCache.h
+++ b/libs/hwui/utils/GenerationCache.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_UI_GENERATION_CACHE_H
-#define ANDROID_UI_GENERATION_CACHE_H
+#ifndef ANDROID_HWUI_GENERATION_CACHE_H
+#define ANDROID_HWUI_GENERATION_CACHE_H
 
 #include <utils/KeyedVector.h>
 #include <utils/RefBase.h>
@@ -242,4 +242,4 @@
 }; // namespace uirenderer
 }; // namespace android
 
-#endif // ANDROID_UI_GENERATION_CACHE_H
+#endif // ANDROID_HWUI_GENERATION_CACHE_H
diff --git a/libs/hwui/utils/SortedList.h b/libs/hwui/utils/SortedList.h
index 68f5e9d..2fa890a 100644
--- a/libs/hwui/utils/SortedList.h
+++ b/libs/hwui/utils/SortedList.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_UI_SORTED_LIST_H
-#define ANDROID_UI_SORTED_LIST_H
+#ifndef ANDROID_HWUI_SORTED_LIST_H
+#define ANDROID_HWUI_SORTED_LIST_H
 
 #include <stdint.h>
 #include <sys/types.h>
@@ -239,4 +239,4 @@
 }; // namespace uirenderer
 }; // namespace android
 
-#endif // ANDROID_UI_SORTED_LIST_H
+#endif // ANDROID_HWUI_SORTED_LIST_H
diff --git a/libs/hwui/utils/SortedListImpl.h b/libs/hwui/utils/SortedListImpl.h
index 7da09ef..dc385b5 100644
--- a/libs/hwui/utils/SortedListImpl.h
+++ b/libs/hwui/utils/SortedListImpl.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_UI_SORTED_LIST_IMPL_H
-#define ANDROID_UI_SORTED_LIST_IMPL_H
+#ifndef ANDROID_HWUI_SORTED_LIST_IMPL_H
+#define ANDROID_HWUI_SORTED_LIST_IMPL_H
 
 #include <utils/VectorImpl.h>
 
@@ -62,4 +62,4 @@
 }; // namespace uirenderer
 }; // namespace android
 
-#endif // ANDROID_UI_SORTED_LIST_IMPL_H
+#endif // ANDROID_HWUI_SORTED_LIST_IMPL_H
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index 12db908..1994f6a 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -289,7 +289,7 @@
     void flushSpan() {
         bool merge = false;
         if (tail-head == ssize_t(span.size())) {
-            Rect const* p = cur;
+            Rect const* p = span.editArray();
             Rect const* q = head;
             if (p->top == q->bottom) {
                 merge = true;