Enable partial invalidates when rendering with OpenGL.

Change-Id: Ie8be06c4776b815e8737753eb8003b4fd8936130
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index dce1a6c..dac3135 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -192,21 +192,36 @@
         nSetViewport(mRenderer, width, height);
     }
     
-    private native void nSetViewport(int renderer, int width, int height);
+    private static native void nSetViewport(int renderer, int width, int height);
 
-    @Override
-    void onPreDraw() {
-        nPrepare(mRenderer, mOpaque);
+    /**
+     * @hide
+     */
+    public static boolean preserveBackBuffer() {
+        return nPreserveBackBuffer();
     }
 
-    private native void nPrepare(int renderer, boolean opaque);
+    private static native boolean nPreserveBackBuffer();    
+    
+    @Override
+    void onPreDraw(Rect dirty) {
+        if (dirty != null) {
+            nPrepareDirty(mRenderer, dirty.left, dirty.top, dirty.right, dirty.bottom, mOpaque);
+        } else {
+            nPrepare(mRenderer, mOpaque);
+        }
+    }
+
+    private static native void nPrepare(int renderer, boolean opaque);
+    private static native void nPrepareDirty(int renderer, int left, int top, int right, int bottom,
+            boolean opaque);
 
     @Override
     void onPostDraw() {
         nFinish(mRenderer);
     }
     
-    private native void nFinish(int renderer);
+    private static native void nFinish(int renderer);
 
     @Override
     public boolean acquireContext() {
@@ -217,14 +232,14 @@
         return mContextLocked;
     }
 
-    private native void nAcquireContext(int renderer);
+    private static native void nAcquireContext(int renderer);
 
     @Override
     public boolean callDrawGLFunction(int drawGLFunction) {
         return nCallDrawGLFunction(mRenderer, drawGLFunction);
     }
 
-    private native boolean nCallDrawGLFunction(int renderer, int drawGLFunction);
+    private static native boolean nCallDrawGLFunction(int renderer, int drawGLFunction);
 
     @Override
     public void releaseContext() {
@@ -234,7 +249,7 @@
         }
     }
 
-    private native void nReleaseContext(int renderer);
+    private static native void nReleaseContext(int renderer);
     
     ///////////////////////////////////////////////////////////////////////////
     // Display list
@@ -244,7 +259,7 @@
         return nGetDisplayList(mRenderer);
     }
 
-    private native int nGetDisplayList(int renderer);
+    private static native int nGetDisplayList(int renderer);
     
     static void destroyDisplayList(int displayList) {
         nDestroyDisplayList(displayList);
@@ -257,7 +272,7 @@
         return nDrawDisplayList(mRenderer, ((GLES20DisplayList) displayList).mNativeDisplayList);
     }
 
-    private native boolean nDrawDisplayList(int renderer, int displayList);
+    private static native boolean nDrawDisplayList(int renderer, int displayList);
 
     ///////////////////////////////////////////////////////////////////////////
     // Hardware layer
@@ -271,7 +286,7 @@
         if (hasColorFilter) nResetModifiers(mRenderer);
     }
 
-    private native void nDrawLayer(int renderer, int layer, float x, float y, int paint);
+    private static native void nDrawLayer(int renderer, int layer, float x, float y, int paint);
     
     void interrupt() {
         nInterrupt(mRenderer);
@@ -281,8 +296,8 @@
         nResume(mRenderer);
     }
 
-    private native void nInterrupt(int renderer);
-    private native void nResume(int renderer);
+    private static native void nInterrupt(int renderer);
+    private static native void nResume(int renderer);
 
     ///////////////////////////////////////////////////////////////////////////
     // Clipping
@@ -303,7 +318,7 @@
         return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt);
     }
     
-    private native boolean nClipRect(int renderer, float left, float top,
+    private static native boolean nClipRect(int renderer, float left, float top,
             float right, float bottom, int op);
 
     @Override
@@ -316,7 +331,8 @@
         return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt);
     }
     
-    private native boolean nClipRect(int renderer, int left, int top, int right, int bottom, int op);
+    private static native boolean nClipRect(int renderer, int left, int top, int right, int bottom,
+            int op);
 
     @Override
     public boolean clipRect(Rect rect) {
@@ -355,14 +371,14 @@
         return nGetClipBounds(mRenderer, bounds);
     }
 
-    private native boolean nGetClipBounds(int renderer, Rect bounds);
+    private static native boolean nGetClipBounds(int renderer, Rect bounds);
 
     @Override
     public boolean quickReject(float left, float top, float right, float bottom, EdgeType type) {
         return nQuickReject(mRenderer, left, top, right, bottom, type.nativeInt);
     }
     
-    private native boolean nQuickReject(int renderer, float left, float top,
+    private static native boolean nQuickReject(int renderer, float left, float top,
             float right, float bottom, int edge);
 
     @Override
@@ -384,56 +400,56 @@
         if (dx != 0.0f || dy != 0.0f) nTranslate(mRenderer, dx, dy);
     }
     
-    private native void nTranslate(int renderer, float dx, float dy);
+    private static native void nTranslate(int renderer, float dx, float dy);
 
     @Override
     public void skew(float sx, float sy) {
         nSkew(mRenderer, sx, sy);
     }
 
-    private native void nSkew(int renderer, float sx, float sy);
+    private static native void nSkew(int renderer, float sx, float sy);
 
     @Override
     public void rotate(float degrees) {
         nRotate(mRenderer, degrees);
     }
     
-    private native void nRotate(int renderer, float degrees);
+    private static native void nRotate(int renderer, float degrees);
 
     @Override
     public void scale(float sx, float sy) {
         nScale(mRenderer, sx, sy);
     }
     
-    private native void nScale(int renderer, float sx, float sy);
+    private static native void nScale(int renderer, float sx, float sy);
 
     @Override
     public void setMatrix(Matrix matrix) {
         nSetMatrix(mRenderer, matrix.native_instance);
     }
     
-    private native void nSetMatrix(int renderer, int matrix);
+    private static native void nSetMatrix(int renderer, int matrix);
 
     @Override
     public int getNativeMatrix() {
         return nGetMatrix(mRenderer);
     }
 
-    private native int nGetMatrix(int renderer);    
+    private static native int nGetMatrix(int renderer);    
 
     @Override
     public void getMatrix(Matrix matrix) {
         nGetMatrix(mRenderer, matrix.native_instance);
     }
     
-    private native void nGetMatrix(int renderer, int matrix);
+    private static native void nGetMatrix(int renderer, int matrix);
 
     @Override
     public void concat(Matrix matrix) {
         nConcatMatrix(mRenderer, matrix.native_instance);
     }
     
-    private native void nConcatMatrix(int renderer, int matrix);
+    private static native void nConcatMatrix(int renderer, int matrix);
     
     ///////////////////////////////////////////////////////////////////////////
     // State management
@@ -449,7 +465,7 @@
         return nSave(mRenderer, saveFlags);
     }
 
-    private native int nSave(int renderer, int flags);
+    private static native int nSave(int renderer, int flags);
     
     @Override
     public int saveLayer(RectF bounds, Paint paint, int saveFlags) {
@@ -469,8 +485,8 @@
         return save(saveFlags);
     }
 
-    private native int nSaveLayer(int renderer, float left, float top, float right, float bottom,
-            int paint, int saveFlags);
+    private static native int nSaveLayer(int renderer, float left, float top,
+            float right, float bottom, int paint, int saveFlags);
 
     @Override
     public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags) {
@@ -487,7 +503,7 @@
         return save(saveFlags);
     }
 
-    private native int nSaveLayerAlpha(int renderer, float left, float top, float right,
+    private static native int nSaveLayerAlpha(int renderer, float left, float top, float right,
             float bottom, int alpha, int saveFlags);
     
     @Override
@@ -495,21 +511,21 @@
         nRestore(mRenderer);
     }
     
-    private native void nRestore(int renderer);
+    private static native void nRestore(int renderer);
 
     @Override
     public void restoreToCount(int saveCount) {
         nRestoreToCount(mRenderer, saveCount);
     }
 
-    private native void nRestoreToCount(int renderer, int saveCount);
+    private static native void nRestoreToCount(int renderer, int saveCount);
     
     @Override
     public int getSaveCount() {
         return nGetSaveCount(mRenderer);
     }
     
-    private native int nGetSaveCount(int renderer);
+    private static native int nGetSaveCount(int renderer);
 
     ///////////////////////////////////////////////////////////////////////////
     // Filtering
@@ -538,8 +554,9 @@
         if (hasModifier) nResetModifiers(mRenderer);
     }
 
-    private native void nDrawArc(int renderer, float left, float top, float right, float bottom,
-            float startAngle, float sweepAngle, boolean useCenter, int paint);
+    private static native void nDrawArc(int renderer, float left, float top,
+            float right, float bottom, float startAngle, float sweepAngle,
+            boolean useCenter, int paint);
 
     @Override
     public void drawARGB(int a, int r, int g, int b) {
@@ -556,7 +573,7 @@
         if (hasColorFilter) nResetModifiers(mRenderer);
     }
 
-    private native void nDrawPatch(int renderer, int bitmap, byte[] buffer, byte[] chunks,
+    private static native void nDrawPatch(int renderer, int bitmap, byte[] buffer, byte[] chunks,
             float left, float top, float right, float bottom, int paint);
 
     @Override
@@ -568,7 +585,7 @@
         if (hasColorFilter) nResetModifiers(mRenderer);
     }
 
-    private native void nDrawBitmap(
+    private static native void nDrawBitmap(
             int renderer, int bitmap, byte[] buffer, float left, float top, int paint);
 
     @Override
@@ -581,7 +598,8 @@
         if (hasColorFilter) nResetModifiers(mRenderer);
     }
 
-    private native void nDrawBitmap(int renderer, int bitmap, byte[] buff, int matrix, int paint);
+    private static native void nDrawBitmap(int renderer, int bitmap, byte[] buff,
+            int matrix, int paint);
 
     @Override
     public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
@@ -616,7 +634,7 @@
         if (hasColorFilter) nResetModifiers(mRenderer);
     }
 
-    private native void nDrawBitmap(int renderer, int bitmap, byte[] buffer,
+    private static native void nDrawBitmap(int renderer, int bitmap, byte[] buffer,
             float srcLeft, float srcTop, float srcRight, float srcBottom,
             float left, float top, float right, float bottom, int paint);
 
@@ -665,7 +683,7 @@
         if (hasColorFilter) nResetModifiers(mRenderer);
     }
 
-    private native void nDrawBitmapMesh(int renderer, int bitmap, byte[] buffer,
+    private static native void nDrawBitmapMesh(int renderer, int bitmap, byte[] buffer,
             int meshWidth, int meshHeight, float[] verts, int vertOffset,
             int[] colors, int colorOffset, int paint);
 
@@ -676,7 +694,8 @@
         if (hasModifier) nResetModifiers(mRenderer);        
     }
 
-    private native void nDrawCircle(int renderer, float cx, float cy, float radius, int paint);
+    private static native void nDrawCircle(int renderer, float cx, float cy,
+            float radius, int paint);
 
     @Override
     public void drawColor(int color) {
@@ -688,7 +707,7 @@
         nDrawColor(mRenderer, color, mode.nativeInt);
     }
     
-    private native void nDrawColor(int renderer, int color, int mode);
+    private static native void nDrawColor(int renderer, int color, int mode);
 
     @Override
     public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) {
@@ -709,7 +728,8 @@
         if (hasModifier) nResetModifiers(mRenderer);
     }
 
-    private native void nDrawLines(int renderer, float[] points, int offset, int count, int paint);
+    private static native void nDrawLines(int renderer, float[] points,
+            int offset, int count, int paint);
 
     @Override
     public void drawLines(float[] pts, Paint paint) {
@@ -723,8 +743,8 @@
         if (hasModifier) nResetModifiers(mRenderer); 
     }
 
-    private native void nDrawOval(int renderer, float left, float top, float right, float bottom,
-            int paint);
+    private static native void nDrawOval(int renderer, float left, float top,
+            float right, float bottom, int paint);
 
     @Override
     public void drawPaint(Paint paint) {
@@ -746,8 +766,8 @@
         if (hasModifier) nResetModifiers(mRenderer);
     }
 
-    private native void nDrawPath(int renderer, int path, int paint);
-    private native void nDrawRects(int renderer, int region, int paint);
+    private static native void nDrawPath(int renderer, int path, int paint);
+    private static native void nDrawRects(int renderer, int region, int paint);
 
     @Override
     public void drawPicture(Picture picture) {
@@ -798,8 +818,8 @@
         if (hasModifier) nResetModifiers(mRenderer);
     }
 
-    private native void nDrawRect(int renderer, float left, float top, float right, float bottom,
-            int paint);
+    private static native void nDrawRect(int renderer, float left, float top,
+            float right, float bottom, int paint);
 
     @Override
     public void drawRect(Rect r, Paint paint) {
@@ -824,7 +844,7 @@
         if (hasModifier) nResetModifiers(mRenderer);        
     }
 
-    private native void nDrawRoundRect(int renderer, float left, float top,
+    private static native void nDrawRoundRect(int renderer, float left, float top,
             float right, float bottom, float rx, float y, int paint);
 
     @Override
@@ -841,8 +861,8 @@
         }
     }
     
-    private native void nDrawText(int renderer, char[] text, int index, int count, float x, float y,
-            int bidiFlags, int paint);
+    private static native void nDrawText(int renderer, char[] text, int index, int count,
+            float x, float y, int bidiFlags, int paint);
 
     @Override
     public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
@@ -858,7 +878,8 @@
             } else {
                 char[] buf = TemporaryBuffer.obtain(end - start);
                 TextUtils.getChars(text, start, end, buf, 0);
-                nDrawText(mRenderer, buf, 0, end - start, x, y, paint.mBidiFlags, paint.mNativePaint);
+                nDrawText(mRenderer, buf, 0, end - start, x, y,
+                        paint.mBidiFlags, paint.mNativePaint);
                 TemporaryBuffer.recycle(buf);
             }
         } finally {
@@ -880,8 +901,8 @@
         }
     }
 
-    private native void nDrawText(int renderer, String text, int start, int end, float x, float y,
-            int bidiFlags, int paint);
+    private static native void nDrawText(int renderer, String text, int start, int end,
+            float x, float y, int bidiFlags, int paint);
 
     @Override
     public void drawText(String text, float x, float y, Paint paint) {
@@ -924,7 +945,7 @@
         }
     }
 
-    private native void nDrawTextRun(int renderer, char[] text, int index, int count,
+    private static native void nDrawTextRun(int renderer, char[] text, int index, int count,
             int contextIndex, int contextCount, float x, float y, int dir, int nativePaint);
 
     @Override
@@ -958,7 +979,7 @@
         }
     }
 
-    private native void nDrawTextRun(int renderer, String text, int start, int end,
+    private static native void nDrawTextRun(int renderer, String text, int start, int end,
             int contextStart, int contextEnd, float x, float y, int flags, int nativePaint);
 
     @Override
@@ -1001,9 +1022,10 @@
         return false;        
     }
     
-    private native void nSetupShader(int renderer, int shader);
-    private native void nSetupColorFilter(int renderer, int colorFilter);
-    private native void nSetupShadow(int renderer, float radius, float dx, float dy, int color);
+    private static native void nSetupShader(int renderer, int shader);
+    private static native void nSetupColorFilter(int renderer, int colorFilter);
+    private static native void nSetupShadow(int renderer, float radius,
+            float dx, float dy, int color);
 
-    private native void nResetModifiers(int renderer);
+    private static native void nResetModifiers(int renderer);
 }
diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java
index a4d36b7..e6fecc8 100644
--- a/core/java/android/view/HardwareCanvas.java
+++ b/core/java/android/view/HardwareCanvas.java
@@ -19,6 +19,7 @@
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Paint;
+import android.graphics.Rect;
 
 /**
  * Hardware accelerated canvas.
@@ -38,8 +39,10 @@
     
     /**
      * Invoked before any drawing operation is performed in this canvas.
+     * 
+     * @param dirty The dirty rectangle to update, can be null.
      */
-    abstract void onPreDraw();
+    abstract void onPreDraw(Rect dirty);
 
     /**
      * Invoked after all drawing operation have been performed.
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index c82184a..271fa1a 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -18,6 +18,8 @@
 package android.view;
 
 import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
 import android.os.SystemClock;
 import android.util.EventLog;
 import android.util.Log;
@@ -39,6 +41,16 @@
     static final String LOG_TAG = "HardwareRenderer";
 
     /**
+     * Turn on to only refresh the parts of the screen that need updating.
+     */
+    public static final boolean RENDER_DIRTY_REGIONS = true;
+
+    /**
+     * Turn on to draw dirty regions every other frame.
+     */
+    private static final boolean DEBUG_DIRTY_REGION = false;
+    
+    /**
      * A process can set this flag to false to prevent the use of hardware
      * rendering.
      * 
@@ -108,11 +120,14 @@
 
     /**
      * Draws the specified view.
-     * 
+     *
      * @param view The view to draw.
      * @param attachInfo AttachInfo tied to the specified view.
+     * @param callbacks Callbacks invoked when drawing happens.
+     * @param dirty The dirty rectangle to update, can be null.
      */
-    abstract void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks);
+    abstract void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
+            Rect dirty);
 
     /**
      * Creates a new display list that can be used to record batches of
@@ -214,6 +229,8 @@
     @SuppressWarnings({"deprecation"})
     static abstract class GlRenderer extends HardwareRenderer {
         private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+        private static final int EGL_SURFACE_TYPE = 0x3033;
+        private static final int EGL_SWAP_BEHAVIOR_PRESERVED_BIT = 0x0400;
 
         static EGLContext sEglContext;
         static EGL10 sEgl;
@@ -226,6 +243,9 @@
         
         GL mGl;
         HardwareCanvas mCanvas;
+        int mFrameCount;
+        Paint mDebugPaint;
+
 
         final int mGlVersion;
         final boolean mTranslucent;
@@ -412,7 +432,7 @@
             if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) {
                 int error = sEgl.eglGetError();
                 if (error == EGL10.EGL_BAD_NATIVE_WINDOW) {
-                    Log.e("EglHelper", "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
+                    Log.e(LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
                     return null;
                 }
                 throw new RuntimeException("createWindowSurface failed "
@@ -427,6 +447,12 @@
                 throw new RuntimeException("eglMakeCurrent failed "
                         + getEGLErrorString(sEgl.eglGetError()));
             }
+            
+            if (RENDER_DIRTY_REGIONS) {
+                if (!GLES20Canvas.preserveBackBuffer()) {
+                    Log.w(LOG_TAG, "Backbuffer cannot be preserved");
+                }
+            }
 
             return sEglContext.getGL();
         }
@@ -471,12 +497,12 @@
         void setup(int width, int height) {
             mCanvas.setViewport(width, height);
         }
-        
+
         boolean canDraw() {
             return mGl != null && mCanvas != null;
         }        
         
-        void onPreDraw() {
+        void onPreDraw(Rect dirty) {
         }
 
         void onPostDraw() {
@@ -492,8 +518,14 @@
         }
 
         @Override
-        void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks) {
+        void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
+                Rect dirty) {
             if (canDraw()) {
+                //noinspection PointlessBooleanExpression,ConstantConditions
+                if (!HardwareRenderer.RENDER_DIRTY_REGIONS) {
+                    dirty = null;
+                }
+
                 attachInfo.mDrawingTime = SystemClock.uptimeMillis();
                 attachInfo.mIgnoreDirtyState = true;
                 view.mPrivateFlags |= View.DRAWN;
@@ -504,10 +536,11 @@
                 }
 
                 if (checkCurrent()) {
-                    onPreDraw();
+                    onPreDraw(dirty);
     
                     HardwareCanvas canvas = mCanvas;
                     attachInfo.mHardwareCanvas = canvas;
+
                     int saveCount = canvas.save();
                     callbacks.onHardwarePreDraw(canvas);
 
@@ -515,6 +548,7 @@
                         view.mRecreateDisplayList =
                                 (view.mPrivateFlags & View.INVALIDATED) == View.INVALIDATED;
                         view.mPrivateFlags &= ~View.INVALIDATED;
+
                         DisplayList displayList = view.getDisplayList();
                         if (displayList != null) {
                             if (canvas.drawDisplayList(displayList)) {
@@ -524,6 +558,16 @@
                             // Shouldn't reach here
                             view.draw(canvas);
                         }
+
+                        if (DEBUG_DIRTY_REGION) {
+                            if (mDebugPaint == null) {
+                                mDebugPaint = new Paint();
+                                mDebugPaint.setColor(0x7fff0000);
+                            }
+                            if (dirty != null && (mFrameCount++ & 1) == 0) {
+                                canvas.drawRect(dirty, mDebugPaint);
+                            }
+                        }
                     } finally {
                         callbacks.onHardwarePostDraw(canvas);
                         canvas.restoreToCount(saveCount);
@@ -636,6 +680,8 @@
                         EGL10.EGL_ALPHA_SIZE, alphaSize,
                         EGL10.EGL_DEPTH_SIZE, depthSize,
                         EGL10.EGL_STENCIL_SIZE, stencilSize,
+                        EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT |
+                                (RENDER_DIRTY_REGIONS ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0),
                         EGL10.EGL_NONE });
                 mValue = new int[1];
                 mRedSize = redSize;
@@ -656,7 +702,16 @@
                         int g = findConfigAttrib(egl, display, config, EGL10.EGL_GREEN_SIZE, 0);
                         int b = findConfigAttrib(egl, display, config, EGL10.EGL_BLUE_SIZE, 0);
                         int a = findConfigAttrib(egl, display, config, EGL10.EGL_ALPHA_SIZE, 0);
-                        if (r >= mRedSize && g >= mGreenSize && b >= mBlueSize && a >= mAlphaSize) {
+                        boolean backBuffer;
+                        if (RENDER_DIRTY_REGIONS) {
+                            int surfaceType = findConfigAttrib(egl, display, config,
+                                    EGL_SURFACE_TYPE, 0);
+                            backBuffer = (surfaceType & EGL_SWAP_BEHAVIOR_PRESERVED_BIT) != 0;
+                        } else {
+                            backBuffer = true;
+                        }
+                        if (r >= mRedSize && g >= mGreenSize && b >= mBlueSize && a >= mAlphaSize
+                                && backBuffer) {
                             return config;
                         }
                     }
@@ -696,8 +751,8 @@
         }                
 
         @Override
-        void onPreDraw() {
-            mGlCanvas.onPreDraw();
+        void onPreDraw(Rect dirty) {
+            mGlCanvas.onPreDraw(dirty);
         }
 
         @Override
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 8af2549..b073513 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -6730,11 +6730,14 @@
             mPrivateFlags |= INVALIDATED;
             final ViewParent p = mParent;
             final AttachInfo ai = mAttachInfo;
-            if (p != null && ai != null && ai.mHardwareAccelerated) {
-                // fast-track for GL-enabled applications; just invalidate the whole hierarchy
-                // with a null dirty rect, which tells the ViewRoot to redraw everything
-                p.invalidateChild(this, null);
-                return;
+            //noinspection PointlessBooleanExpression,ConstantConditions
+            if (!HardwareRenderer.RENDER_DIRTY_REGIONS) {
+                if (p != null && ai != null && ai.mHardwareAccelerated) {
+                    // fast-track for GL-enabled applications; just invalidate the whole hierarchy
+                    // with a null dirty rect, which tells the ViewRoot to redraw everything
+                    p.invalidateChild(this, null);
+                    return;
+                }
             }
             if (p != null && ai != null) {
                 final int scrollX = mScrollX;
@@ -6770,11 +6773,14 @@
             mPrivateFlags |= INVALIDATED;
             final ViewParent p = mParent;
             final AttachInfo ai = mAttachInfo;
-            if (p != null && ai != null && ai.mHardwareAccelerated) {
-                // fast-track for GL-enabled applications; just invalidate the whole hierarchy
-                // with a null dirty rect, which tells the ViewRoot to redraw everything
-                p.invalidateChild(this, null);
-                return;
+            //noinspection PointlessBooleanExpression,ConstantConditions
+            if (!HardwareRenderer.RENDER_DIRTY_REGIONS) {
+                if (p != null && ai != null && ai.mHardwareAccelerated) {
+                    // fast-track for GL-enabled applications; just invalidate the whole hierarchy
+                    // with a null dirty rect, which tells the ViewRoot to redraw everything
+                    p.invalidateChild(this, null);
+                    return;
+                }
             }
             if (p != null && ai != null && l < r && t < b) {
                 final int scrollX = mScrollX;
@@ -6823,11 +6829,14 @@
             }
             final AttachInfo ai = mAttachInfo;
             final ViewParent p = mParent;
-            if (p != null && ai != null && ai.mHardwareAccelerated) {
-                // fast-track for GL-enabled applications; just invalidate the whole hierarchy
-                // with a null dirty rect, which tells the ViewRoot to redraw everything
-                p.invalidateChild(this, null);
-                return;
+            //noinspection PointlessBooleanExpression,ConstantConditions
+            if (!HardwareRenderer.RENDER_DIRTY_REGIONS) {
+                if (p != null && ai != null && ai.mHardwareAccelerated) {
+                    // fast-track for GL-enabled applications; just invalidate the whole hierarchy
+                    // with a null dirty rect, which tells the ViewRoot to redraw everything
+                    p.invalidateChild(this, null);
+                    return;
+                }
             }
 
             if (p != null && ai != null) {
@@ -8101,7 +8110,8 @@
             final HardwareCanvas canvas = mHardwareLayer.start(mAttachInfo.mHardwareCanvas);
             try {
                 canvas.setViewport(width, height);
-                canvas.onPreDraw();
+                // TODO: We should pass the dirty rect
+                canvas.onPreDraw(null);
 
                 computeScroll();
                 canvas.translate(-mScrollX, -mScrollY);
@@ -8190,7 +8200,7 @@
             ViewGroup parent = (ViewGroup) this;
             final int count = parent.getChildCount();
             for (int i = 0; i < count; i++) {
-                final View child = (View) parent.getChildAt(i);
+                final View child = parent.getChildAt(i);
                 child.outputDirtyFlags(indent + "  ", clear, clearMask);
             }
         }
@@ -8251,7 +8261,8 @@
                 int height = mBottom - mTop;
 
                 canvas.setViewport(width, height);
-                canvas.onPreDraw();
+                // The dirty rect should always be null for a display list
+                canvas.onPreDraw(null);
 
                 final int restoreCount = canvas.save();
 
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index c73cbe6..3703a64 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3527,10 +3527,20 @@
                             (int) (boundingRect.bottom + 0.5f));
                 }
 
+                if (child.mLayerType != LAYER_TYPE_NONE) {
+                    mPrivateFlags |= INVALIDATED;
+                    mPrivateFlags &= ~DRAWING_CACHE_VALID;
+                }                
                 do {
                     View view = null;
                     if (parent instanceof View) {
                         view = (View) parent;
+                        if (view.mLayerType != LAYER_TYPE_NONE &&
+                                view.getParent() instanceof View) {
+                            final View grandParent = (View) view.getParent();
+                            grandParent.mPrivateFlags |= INVALIDATED;
+                            grandParent.mPrivateFlags &= ~DRAWING_CACHE_VALID;
+                        }
                     }
 
                     if (drawAnimation) {
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index ba671c0..19d7811 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -160,7 +160,9 @@
 
     int mWidth;
     int mHeight;
-    Rect mDirty; // will be a graphics.Region soon
+    Rect mDirty;
+    final Rect mCurrentDirty = new Rect();
+    final Rect mPreviousDirty = new Rect();
     boolean mIsAnimating;
 
     CompatibilityInfo.Translator mTranslator;
@@ -1055,6 +1057,7 @@
                     disposeResizeBitmap();
                 } else if (surfaceGenerationId != mSurface.getGenerationId() &&
                         mSurfaceHolder == null && mAttachInfo.mHardwareRenderer != null) {
+                    fullRedrawNeeded = true;
                     mAttachInfo.mHardwareRenderer.updateSurface(mHolder);
                 }
             } catch (RemoteException e) {
@@ -1488,10 +1491,15 @@
         if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
             if (!dirty.isEmpty() || mIsAnimating) {
                 mIsAnimating = false;
-                dirty.setEmpty();
                 mHardwareYOffset = yoff;
                 mResizeAlpha = resizeAlpha;
-                mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, this);
+
+                mCurrentDirty.set(dirty);
+                mCurrentDirty.union(mPreviousDirty);
+                mPreviousDirty.set(dirty);
+                dirty.setEmpty();
+
+                mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, this, mCurrentDirty);
             }
 
             if (animating) {
@@ -1986,6 +1994,7 @@
 
                     if (mAttachInfo.mHardwareRenderer != null &&
                             mSurface != null && mSurface.isValid()) {
+                        mFullRedrawNeeded = true;
                         mAttachInfo.mHardwareRenderer.initializeIfNeeded(mWidth, mHeight,
                                 mAttachInfo, mHolder);
                     }
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index e4a89d7..9de270d 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -16,6 +16,8 @@
 
 #define LOG_TAG "OpenGLRenderer"
 
+#include <EGL/egl.h>
+
 #include "jni.h"
 #include "GraphicsJNI.h"
 #include <nativehelper/JNIHelp.h>
@@ -75,6 +77,23 @@
 } gRectClassInfo;
 
 // ----------------------------------------------------------------------------
+// Misc
+// ----------------------------------------------------------------------------
+
+static jboolean android_view_GLES20Canvas_preserveBackBuffer(JNIEnv* env, jobject clazz) {
+    EGLDisplay display = eglGetCurrentDisplay();
+    EGLSurface surface = eglGetCurrentSurface(EGL_DRAW);
+
+    eglGetError();
+    eglSurfaceAttrib(display, surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED);
+
+    EGLint error = eglGetError();
+    RENDERER_LOGD("Could not enable buffer preserved swap behavior (%x)", error);
+
+    return error == EGL_SUCCESS;
+}
+
+// ----------------------------------------------------------------------------
 // Constructors
 // ----------------------------------------------------------------------------
 
@@ -97,32 +116,38 @@
 // Setup
 // ----------------------------------------------------------------------------
 
-static void android_view_GLES20Canvas_setViewport(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_setViewport(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jint width, jint height) {
     renderer->setViewport(width, height);
 }
 
-static void android_view_GLES20Canvas_prepare(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_prepare(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jboolean opaque) {
     renderer->prepare(opaque);
 }
 
-static void android_view_GLES20Canvas_finish(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_prepareDirty(JNIEnv* env, jobject clazz,
+        OpenGLRenderer* renderer, jint left, jint top, jint right, jint bottom,
+        jboolean opaque) {
+    renderer->prepareDirty(left, top, right, bottom, opaque);
+}
+
+static void android_view_GLES20Canvas_finish(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer) {
     renderer->finish();
 }
 
-static void android_view_GLES20Canvas_acquireContext(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_acquireContext(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer) {
     renderer->acquireContext();
 }
 
-static bool android_view_GLES20Canvas_callDrawGLFunction(JNIEnv* env, jobject canvas,
+static bool android_view_GLES20Canvas_callDrawGLFunction(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, Functor *functor) {
     return renderer->callDrawGLFunction(functor);
 }
 
-static void android_view_GLES20Canvas_releaseContext(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_releaseContext(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer) {
     renderer->releaseContext();
 }
@@ -131,22 +156,22 @@
 // State
 // ----------------------------------------------------------------------------
 
-static jint android_view_GLES20Canvas_save(JNIEnv* env, jobject canvas, OpenGLRenderer* renderer,
+static jint android_view_GLES20Canvas_save(JNIEnv* env, jobject clazz, OpenGLRenderer* renderer,
         jint flags) {
     return renderer->save(flags);
 }
 
-static jint android_view_GLES20Canvas_getSaveCount(JNIEnv* env, jobject canvas,
+static jint android_view_GLES20Canvas_getSaveCount(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer) {
     return renderer->getSaveCount();
 }
 
-static void android_view_GLES20Canvas_restore(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_restore(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer) {
     renderer->restore();
 }
 
-static void android_view_GLES20Canvas_restoreToCount(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_restoreToCount(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jint saveCount) {
     renderer->restoreToCount(saveCount);
 }
@@ -155,13 +180,13 @@
 // Layers
 // ----------------------------------------------------------------------------
 
-static jint android_view_GLES20Canvas_saveLayer(JNIEnv* env, jobject canvas,
+static jint android_view_GLES20Canvas_saveLayer(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jfloat left, jfloat top, jfloat right, jfloat bottom,
         SkPaint* paint, jint saveFlags) {
     return renderer->saveLayer(left, top, right, bottom, paint, saveFlags);
 }
 
-static jint android_view_GLES20Canvas_saveLayerAlpha(JNIEnv* env, jobject canvas,
+static jint android_view_GLES20Canvas_saveLayerAlpha(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jfloat left, jfloat top, jfloat right, jfloat bottom,
         jint alpha, jint saveFlags) {
     return renderer->saveLayerAlpha(left, top, right, bottom, alpha, saveFlags);
@@ -171,25 +196,25 @@
 // Clipping
 // ----------------------------------------------------------------------------
 
-static bool android_view_GLES20Canvas_quickReject(JNIEnv* env, jobject canvas,
+static bool android_view_GLES20Canvas_quickReject(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jfloat left, jfloat top, jfloat right, jfloat bottom,
         SkCanvas::EdgeType edge) {
     return renderer->quickReject(left, top, right, bottom);
 }
 
-static bool android_view_GLES20Canvas_clipRectF(JNIEnv* env, jobject canvas,
+static bool android_view_GLES20Canvas_clipRectF(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jfloat left, jfloat top, jfloat right, jfloat bottom,
         SkRegion::Op op) {
     return renderer->clipRect(left, top, right, bottom, op);
 }
 
-static bool android_view_GLES20Canvas_clipRect(JNIEnv* env, jobject canvas,
+static bool android_view_GLES20Canvas_clipRect(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jint left, jint top, jint right, jint bottom,
         SkRegion::Op op) {
     return renderer->clipRect(float(left), float(top), float(right), float(bottom), op);
 }
 
-static bool android_view_GLES20Canvas_getClipBounds(JNIEnv* env, jobject canvas,
+static bool android_view_GLES20Canvas_getClipBounds(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jobject rect) {
     const android::uirenderer::Rect& bounds(renderer->getClipBounds());
 
@@ -203,42 +228,42 @@
 // Transforms
 // ----------------------------------------------------------------------------
 
-static void android_view_GLES20Canvas_translate(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_translate(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jfloat dx, jfloat dy) {
     renderer->translate(dx, dy);
 }
 
-static void android_view_GLES20Canvas_rotate(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_rotate(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jfloat degrees) {
     renderer->rotate(degrees);
 }
 
-static void android_view_GLES20Canvas_scale(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_scale(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jfloat sx, jfloat sy) {
     renderer->scale(sx, sy);
 }
 
-static void android_view_GLES20Canvas_skew(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_skew(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jfloat sx, jfloat sy) {
     renderer->skew(sx, sy);
 }
 
-static void android_view_GLES20Canvas_setMatrix(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_setMatrix(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, SkMatrix* matrix) {
     renderer->setMatrix(matrix);
 }
 
 static const float* android_view_GLES20Canvas_getNativeMatrix(JNIEnv* env,
-        jobject canvas, OpenGLRenderer* renderer) {
+        jobject clazz, OpenGLRenderer* renderer) {
     return renderer->getMatrix();
 }
 
-static void android_view_GLES20Canvas_getMatrix(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_getMatrix(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, SkMatrix* matrix) {
     renderer->getMatrix(matrix);
 }
 
-static void android_view_GLES20Canvas_concatMatrix(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_concatMatrix(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, SkMatrix* matrix) {
     renderer->concatMatrix(matrix);
 }
@@ -247,7 +272,7 @@
 // Drawing
 // ----------------------------------------------------------------------------
 
-static void android_view_GLES20Canvas_drawBitmap(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_drawBitmap(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, SkBitmap* bitmap, jbyteArray buffer, float left,
         float top, SkPaint* paint) {
     // This object allows the renderer to allocate a global JNI ref to the buffer object.
@@ -256,7 +281,7 @@
     renderer->drawBitmap(bitmap, left, top, paint);
 }
 
-static void android_view_GLES20Canvas_drawBitmapRect(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_drawBitmapRect(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, SkBitmap* bitmap, jbyteArray buffer,
         float srcLeft, float srcTop, float srcRight, float srcBottom,
         float dstLeft, float dstTop, float dstRight, float dstBottom, SkPaint* paint) {
@@ -267,7 +292,7 @@
             dstLeft, dstTop, dstRight, dstBottom, paint);
 }
 
-static void android_view_GLES20Canvas_drawBitmapMatrix(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_drawBitmapMatrix(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, SkBitmap* bitmap, jbyteArray buffer, SkMatrix* matrix,
         SkPaint* paint) {
     // This object allows the renderer to allocate a global JNI ref to the buffer object.
@@ -276,7 +301,7 @@
     renderer->drawBitmap(bitmap, matrix, paint);
 }
 
-static void android_view_GLES20Canvas_drawBitmapMesh(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_drawBitmapMesh(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, SkBitmap* bitmap, jbyteArray buffer,
         jint meshWidth, jint meshHeight, jfloatArray vertices, jint offset,
         jintArray colors, jint colorOffset, SkPaint* paint) {
@@ -292,7 +317,7 @@
     if (colors) env->ReleaseIntArrayElements(colors, colorsArray, 0);
 }
 
-static void android_view_GLES20Canvas_drawPatch(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_drawPatch(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, SkBitmap* bitmap, jbyteArray buffer, jbyteArray chunks,
         float left, float top, float right, float bottom, SkPaint* paint) {
     // This object allows the renderer to allocate a global JNI ref to the buffer object.
@@ -309,41 +334,41 @@
     env->ReleaseByteArrayElements(chunks, storage, 0);
 }
 
-static void android_view_GLES20Canvas_drawColor(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_drawColor(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jint color, SkXfermode::Mode mode) {
     renderer->drawColor(color, mode);
 }
 
-static void android_view_GLES20Canvas_drawRect(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_drawRect(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jfloat left, jfloat top, jfloat right, jfloat bottom,
         SkPaint* paint) {
     renderer->drawRect(left, top, right, bottom, paint);
 }
 
-static void android_view_GLES20Canvas_drawRoundRect(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_drawRoundRect(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jfloat left, jfloat top, jfloat right, jfloat bottom,
         jfloat rx, jfloat ry, SkPaint* paint) {
     renderer->drawRoundRect(left, top, right, bottom, rx, ry, paint);
 }
 
-static void android_view_GLES20Canvas_drawCircle(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_drawCircle(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jfloat x, jfloat y, jfloat radius, SkPaint* paint) {
     renderer->drawCircle(x, y, radius, paint);
 }
 
-static void android_view_GLES20Canvas_drawOval(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_drawOval(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jfloat left, jfloat top, jfloat right, jfloat bottom,
         SkPaint* paint) {
     renderer->drawOval(left, top, right, bottom, paint);
 }
 
-static void android_view_GLES20Canvas_drawArc(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_drawArc(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jfloat left, jfloat top, jfloat right, jfloat bottom,
         jfloat startAngle, jfloat sweepAngle, jboolean useCenter, SkPaint* paint) {
     renderer->drawArc(left, top, right, bottom, startAngle, sweepAngle, useCenter, paint);
 }
 
-static void android_view_GLES20Canvas_drawRects(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_drawRects(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, SkRegion* region, SkPaint* paint) {
     SkRegion::Iterator it(*region);
     while (!it.done()) {
@@ -353,12 +378,12 @@
     }
 }
 
-static void android_view_GLES20Canvas_drawPath(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_drawPath(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, SkPath* path, SkPaint* paint) {
     renderer->drawPath(path, paint);
 }
 
-static void android_view_GLES20Canvas_drawLines(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_drawLines(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jfloatArray points, jint offset, jint count, SkPaint* paint) {
     jfloat* storage = env->GetFloatArrayElements(points, NULL);
 
@@ -371,24 +396,24 @@
 // Shaders and color filters
 // ----------------------------------------------------------------------------
 
-static void android_view_GLES20Canvas_resetModifiers(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_resetModifiers(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer) {
     renderer->resetShader();
     renderer->resetColorFilter();
     renderer->resetShadow();
 }
 
-static void android_view_GLES20Canvas_setupShader(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_setupShader(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, SkiaShader* shader) {
     renderer->setupShader(shader);
 }
 
-static void android_view_GLES20Canvas_setupColorFilter(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_setupColorFilter(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, SkiaColorFilter* filter) {
     renderer->setupColorFilter(filter);
 }
 
-static void android_view_GLES20Canvas_setupShadow(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_setupShadow(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jfloat radius, jfloat dx, jfloat dy, jint color) {
     renderer->setupShadow(radius, dx, dy, color);
 }
@@ -425,7 +450,7 @@
     }
 }
 
-static void android_view_GLES20Canvas_drawTextArray(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_drawTextArray(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jcharArray text, jint index, jint count,
         jfloat x, jfloat y, jint flags, SkPaint* paint) {
     jchar* textArray = env->GetCharArrayElements(text, NULL);
@@ -433,7 +458,7 @@
     env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
 }
 
-static void android_view_GLES20Canvas_drawText(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_drawText(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jstring text, jint start, jint end,
         jfloat x, jfloat y, jint flags, SkPaint* paint) {
     const jchar* textArray = env->GetStringChars(text, NULL);
@@ -441,7 +466,7 @@
     env->ReleaseStringChars(text, textArray);
 }
 
-static void android_view_GLES20Canvas_drawTextRunArray(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_drawTextRunArray(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jcharArray text, jint index, jint count,
         jint contextIndex, jint contextCount, jfloat x, jfloat y, jint dirFlags,
         SkPaint* paint) {
@@ -451,7 +476,7 @@
     env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
  }
 
-static void android_view_GLES20Canvas_drawTextRun(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_drawTextRun(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jstring text, jint start, jint end,
         jint contextStart, int contextEnd, jfloat x, jfloat y, jint dirFlags,
         SkPaint* paint) {
@@ -468,7 +493,7 @@
 // ----------------------------------------------------------------------------
 
 static DisplayList* android_view_GLES20Canvas_getDisplayList(JNIEnv* env,
-        jobject canvas, DisplayListRenderer* renderer) {
+        jobject clazz, DisplayListRenderer* renderer) {
     return renderer->getDisplayList();
 }
 
@@ -488,7 +513,7 @@
 }
 
 static bool android_view_GLES20Canvas_drawDisplayList(JNIEnv* env,
-        jobject canvas, OpenGLRenderer* renderer, DisplayList* displayList) {
+        jobject clazz, OpenGLRenderer* renderer, DisplayList* displayList) {
     return renderer->drawDisplayList(displayList);
 }
 
@@ -496,12 +521,12 @@
 // Layers
 // ----------------------------------------------------------------------------
 
-static void android_view_GLES20Canvas_interrupt(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_interrupt(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer) {
     renderer->interrupt();
 }
 
-static void android_view_GLES20Canvas_resume(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_resume(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer) {
     renderer->resume();
 }
@@ -547,7 +572,7 @@
     LayerRenderer::destroyLayerDeferred(layer);
 }
 
-static void android_view_GLES20Canvas_drawLayer(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_drawLayer(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, Layer* layer, jfloat x, jfloat y, SkPaint* paint) {
     renderer->drawLayer(layer, x, y, paint);
 }
@@ -576,16 +601,20 @@
     { "nIsAvailable",       "()Z",             (void*) android_view_GLES20Canvas_isAvailable },
 
 #ifdef USE_OPENGL_RENDERER
+    { "nPreserveBackBuffer", "()Z",            (void*) android_view_GLES20Canvas_preserveBackBuffer },
+
     { "nCreateRenderer",    "()I",             (void*) android_view_GLES20Canvas_createRenderer },
     { "nDestroyRenderer",   "(I)V",            (void*) android_view_GLES20Canvas_destroyRenderer },
     { "nSetViewport",       "(III)V",          (void*) android_view_GLES20Canvas_setViewport },
     { "nPrepare",           "(IZ)V",           (void*) android_view_GLES20Canvas_prepare },
+    { "nPrepareDirty",      "(IIIIIZ)V",       (void*) android_view_GLES20Canvas_prepareDirty },
     { "nFinish",            "(I)V",            (void*) android_view_GLES20Canvas_finish },
     { "nAcquireContext",    "(I)V",            (void*) android_view_GLES20Canvas_acquireContext },
-    { "nCallDrawGLFunction",    "(II)Z",
-            (void*) android_view_GLES20Canvas_callDrawGLFunction },
     { "nReleaseContext",    "(I)V",            (void*) android_view_GLES20Canvas_releaseContext },
 
+    { "nCallDrawGLFunction", "(II)Z",
+            (void*) android_view_GLES20Canvas_callDrawGLFunction },
+
     { "nSave",              "(II)I",           (void*) android_view_GLES20Canvas_save },
     { "nRestore",           "(I)V",            (void*) android_view_GLES20Canvas_restore },
     { "nRestoreToCount",    "(II)V",           (void*) android_view_GLES20Canvas_restoreToCount },
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index a768efe..d70fba8 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -629,7 +629,8 @@
     mHeight = height;
 }
 
-void DisplayListRenderer::prepare(bool opaque) {
+void DisplayListRenderer::prepareDirty(float left, float top,
+        float right, float bottom, bool opaque) {
     mSnapshot = new Snapshot(mFirstSnapshot,
             SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
     mSaveCount = 1;
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 6c8e8f5..bab5149 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -28,7 +28,7 @@
 #include <SkTSearch.h>
 
 #include "OpenGLRenderer.h"
-#include "Functor.h"
+#include "utils/Functor.h"
 
 namespace android {
 namespace uirenderer {
@@ -241,7 +241,7 @@
     DisplayList* getDisplayList();
 
     void setViewport(int width, int height);
-    void prepare(bool opaque);
+    void prepareDirty(float left, float top, float right, float bottom, bool opaque);
     void finish();
 
     bool callDrawGLFunction(Functor *functor);
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index 1c89577..36709dc 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -26,7 +26,7 @@
 // Rendering
 ///////////////////////////////////////////////////////////////////////////////
 
-void LayerRenderer::prepare(bool opaque) {
+void LayerRenderer::prepareDirty(float left, float top, float right, float bottom, bool opaque) {
     LAYER_RENDERER_LOGD("Rendering into layer, fbo = %d", mLayer->fbo);
 
 #if RENDER_LAYERS_AS_REGIONS
@@ -35,7 +35,7 @@
 
     glBindFramebuffer(GL_FRAMEBUFFER, mLayer->fbo);
 
-    OpenGLRenderer::prepare(opaque);
+    OpenGLRenderer::prepareDirty(0.0f, 0.0f, mLayer->width, mLayer->height, opaque);
 }
 
 void LayerRenderer::finish() {
diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h
index 1e39847..d2f565e 100644
--- a/libs/hwui/LayerRenderer.h
+++ b/libs/hwui/LayerRenderer.h
@@ -46,7 +46,7 @@
     ~LayerRenderer() {
     }
 
-    void prepare(bool opaque);
+    void prepareDirty(float left, float top, float right, float bottom, bool opaque);
     void finish();
 
     bool hasLayer();
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 98f8fc5..d343a6f 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -136,6 +136,10 @@
 }
 
 void OpenGLRenderer::prepare(bool opaque) {
+    prepareDirty(0.0f, 0.0f, mWidth, mHeight, opaque);
+}
+
+void OpenGLRenderer::prepareDirty(float left, float top, float right, float bottom, bool opaque) {
     mCaches.clearGarbage();
 
     mSnapshot = new Snapshot(mFirstSnapshot,
@@ -146,15 +150,14 @@
 
     glDisable(GL_DITHER);
 
+    glEnable(GL_SCISSOR_TEST);
+    glScissor(left, mSnapshot->height - bottom, right - left, bottom - top);
+    mSnapshot->setClip(left, top, right, bottom);
+
     if (!opaque) {
-        glDisable(GL_SCISSOR_TEST);
         glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
         glClear(GL_COLOR_BUFFER_BIT);
     }
-
-    glEnable(GL_SCISSOR_TEST);
-    glScissor(0, 0, mWidth, mHeight);
-    mSnapshot->setClip(0.0f, 0.0f, mWidth, mHeight);
 }
 
 void OpenGLRenderer::finish() {
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index bd29609..77de1d2 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -62,7 +62,8 @@
 
     virtual void setViewport(int width, int height);
 
-    virtual void prepare(bool opaque);
+    void prepare(bool opaque);
+    virtual void prepareDirty(float left, float top, float right, float bottom, bool opaque);
     virtual void finish();
 
     // These two calls must not be recorded in display lists
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 61f8e1a..2895b69 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -18,7 +18,7 @@
     package="com.android.test.hwui">
 
     <uses-permission android:name="android.permission.INTERNET" />
-    <uses-sdk android:minSdkVersion="Honeycomb" />
+    <uses-sdk android:minSdkVersion="11" />
     
     <application
         android:label="HwUi"
diff --git a/tests/HwAccelerationTest/default.properties b/tests/HwAccelerationTest/default.properties
index 5a8ea50..da2dcdd 100644
--- a/tests/HwAccelerationTest/default.properties
+++ b/tests/HwAccelerationTest/default.properties
@@ -8,4 +8,4 @@
 # project structure.
 
 # Project target.
-target=android-Froyo
+target=android-Honeycomb