No-fail invokeFunctor

 Bug: 15513308
 Bug: 15449247

Change-Id: I13a29f9c8d4975cdda6dcb33b6332c2555ff0f7c
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index c0e42a3..cfb4af2 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -387,17 +387,6 @@
     abstract boolean copyLayerInto(HardwareLayer layer, Bitmap bitmap);
 
     /**
-     * Schedules the functor for execution in either kModeProcess or
-     * kModeProcessNoContext, depending on whether or not there is an EGLContext.
-     *
-     * @param functor The native functor to invoke
-     * @param waitForCompletion If true, this will not return until the functor
-     *                          has invoked. If false, the functor may be invoked
-     *                          asynchronously.
-     */
-    abstract void invokeFunctor(long functor, boolean waitForCompletion);
-
-    /**
      * Initializes the hardware renderer for the specified surface and setup the
      * renderer for drawing, if needed. This is invoked when the ViewAncestor has
      * potentially lost the hardware renderer. The hardware renderer should be
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index a2ff0fb..5c67da9 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -80,13 +80,13 @@
     private boolean mProfilingEnabled;
 
     ThreadedRenderer(Context context, boolean translucent) {
-        AtlasInitializer.sInstance.init(context);
-
         long rootNodePtr = nCreateRootRenderNode();
         mRootNode = RenderNode.adopt(rootNodePtr);
         mRootNode.setClipToBounds(false);
         mNativeProxy = nCreateProxy(translucent, rootNodePtr);
 
+        AtlasInitializer.sInstance.init(context, mNativeProxy);
+
         // Setup timing
         mChoreographer = Choreographer.getInstance();
         nSetFrameInterval(mNativeProxy, mChoreographer.getFrameIntervalNanos());
@@ -259,9 +259,8 @@
         }
     }
 
-    @Override
-    void invokeFunctor(long functor, boolean waitForCompletion) {
-        nInvokeFunctor(mNativeProxy, functor, waitForCompletion);
+    static void invokeFunctor(long functor, boolean waitForCompletion) {
+        nInvokeFunctor(functor, waitForCompletion);
     }
 
     @Override
@@ -342,7 +341,7 @@
 
         private AtlasInitializer() {}
 
-        synchronized void init(Context context) {
+        synchronized void init(Context context, long renderProxy) {
             if (mInitialized) return;
             IBinder binder = ServiceManager.getService("assetatlas");
             if (binder == null) return;
@@ -356,7 +355,7 @@
                         if (map != null) {
                             // TODO Remove after fixing b/15425820
                             validateMap(context, map);
-                            nSetAtlas(buffer, map);
+                            nSetAtlas(renderProxy, buffer, map);
                             mInitialized = true;
                         }
                         // If IAssetAtlas is not the same class as the IBinder
@@ -399,7 +398,7 @@
 
     static native void setupShadersDiskCache(String cacheFile);
 
-    private static native void nSetAtlas(GraphicBuffer buffer, long[] map);
+    private static native void nSetAtlas(long nativeProxy, GraphicBuffer buffer, long[] map);
 
     private static native long nCreateRootRenderNode();
     private static native long nCreateProxy(boolean translucent, long rootRenderNode);
@@ -419,7 +418,7 @@
     private static native void nRunWithGlContext(long nativeProxy, Runnable runnable);
     private static native void nDestroyCanvasAndSurface(long nativeProxy);
 
-    private static native void nInvokeFunctor(long nativeProxy, long functor, boolean waitForCompletion);
+    private static native void nInvokeFunctor(long functor, boolean waitForCompletion);
 
     private static native long nCreateDisplayListLayer(long nativeProxy, int width, int height);
     private static native long nCreateTextureLayer(long nativeProxy);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index f574042..329efcc 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -661,11 +661,19 @@
         }
     }
 
+    /**
+     * Schedules the functor for execution in either kModeProcess or
+     * kModeProcessNoContext, depending on whether or not there is an EGLContext.
+     *
+     * @param functor The native functor to invoke
+     * @param waitForCompletion If true, this will not return until the functor
+     *                          has invoked. If false, the functor may be invoked
+     *                          asynchronously.
+     */
     public boolean invokeFunctor(long functor, boolean waitForCompletion) {
-        if (mAttachInfo.mHardwareRenderer == null) {
-            return false;
-        }
-        mAttachInfo.mHardwareRenderer.invokeFunctor(functor, waitForCompletion);
+        ThreadedRenderer.invokeFunctor(functor, waitForCompletion);
+        // TODO: Remove the return value. This is here for compatibility
+        // with current webview, which expects a boolean
         return true;
     }
 
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 329e371..ca8fb30 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -20,15 +20,10 @@
 #include "GraphicsJNI.h"
 #include <nativehelper/JNIHelp.h>
 
-#include "android_view_GraphicBuffer.h"
-
 #include <android_runtime/AndroidRuntime.h>
-#include <android_runtime/android_graphics_SurfaceTexture.h>
 
 #include <androidfw/ResourceTypes.h>
 
-#include <gui/GLConsumer.h>
-
 #include <private/hwui/DrawGlInfo.h>
 
 #include <cutils/properties.h>
@@ -43,9 +38,6 @@
 #include <SkXfermode.h>
 
 #include <DisplayListRenderer.h>
-#include <LayerRenderer.h>
-#include <OpenGLRenderer.h>
-#include <Stencil.h>
 #include <Rect.h>
 #include <RenderNode.h>
 #include <CanvasProperty.h>
@@ -64,7 +56,7 @@
 using namespace uirenderer;
 
 /**
- * Note: OpenGLRenderer JNI layer is generated and compiled only on supported
+ * Note: DisplayListRenderer JNI layer is generated and compiled only on supported
  *       devices. This means all the logic must be compiled only when the
  *       preprocessor variable USE_OPENGL_RENDERER is defined.
  */
@@ -96,8 +88,8 @@
 
 static void android_view_GLES20Canvas_destroyRenderer(JNIEnv* env, jobject clazz,
         jlong rendererPtr) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
-    RENDERER_LOGD("Destroy OpenGLRenderer");
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
+    RENDERER_LOGD("Destroy DisplayListRenderer");
     delete renderer;
 }
 
@@ -107,26 +99,26 @@
 
 static void android_view_GLES20Canvas_setViewport(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jint width, jint height) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     renderer->setViewport(width, height);
 }
 
 static int android_view_GLES20Canvas_prepare(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jboolean opaque) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     return renderer->prepare(opaque);
 }
 
 static int android_view_GLES20Canvas_prepareDirty(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jint left, jint top, jint right, jint bottom,
         jboolean opaque) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     return renderer->prepareDirty(left, top, right, bottom, opaque);
 }
 
 static void android_view_GLES20Canvas_finish(JNIEnv* env, jobject clazz,
         jlong rendererPtr) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     renderer->finish();
 }
 
@@ -154,7 +146,7 @@
 
 static jint android_view_GLES20Canvas_callDrawGLFunction(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jlong functorPtr) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     Functor* functor = reinterpret_cast<Functor*>(functorPtr);
     android::uirenderer::Rect dirty;
     return renderer->callDrawGLFunction(functor, dirty);
@@ -178,25 +170,25 @@
 
 static jint android_view_GLES20Canvas_save(JNIEnv* env, jobject clazz, jlong rendererPtr,
         jint flags) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     return renderer->save(flags);
 }
 
 static jint android_view_GLES20Canvas_getSaveCount(JNIEnv* env, jobject clazz,
         jlong rendererPtr) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     return renderer->getSaveCount();
 }
 
 static void android_view_GLES20Canvas_restore(JNIEnv* env, jobject clazz,
         jlong rendererPtr) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     renderer->restore();
 }
 
 static void android_view_GLES20Canvas_restoreToCount(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jint saveCount) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     renderer->restoreToCount(saveCount);
 }
 
@@ -207,14 +199,14 @@
 static jint android_view_GLES20Canvas_saveLayer(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jfloat left, jfloat top, jfloat right, jfloat bottom,
         jlong paintPtr, jint saveFlags) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
     return renderer->saveLayer(left, top, right, bottom, paint, saveFlags);
 }
 
 static jint android_view_GLES20Canvas_saveLayerClip(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jlong paintPtr, jint saveFlags) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
     const android::uirenderer::Rect& bounds(renderer->getLocalClipBounds());
     return renderer->saveLayer(bounds.left, bounds.top, bounds.right, bounds.bottom,
@@ -224,13 +216,13 @@
 static jint android_view_GLES20Canvas_saveLayerAlpha(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jfloat left, jfloat top, jfloat right, jfloat bottom,
         jint alpha, jint saveFlags) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     return renderer->saveLayerAlpha(left, top, right, bottom, alpha, saveFlags);
 }
 
 static jint android_view_GLES20Canvas_saveLayerAlphaClip(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jint alpha, jint saveFlags) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     const android::uirenderer::Rect& bounds(renderer->getLocalClipBounds());
     return renderer->saveLayerAlpha(bounds.left, bounds.top, bounds.right, bounds.bottom,
             alpha, saveFlags);
@@ -242,7 +234,7 @@
 
 static jboolean android_view_GLES20Canvas_quickReject(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jfloat left, jfloat top, jfloat right, jfloat bottom) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     const bool result = renderer->quickRejectConservative(left, top, right, bottom);
     return result ? JNI_TRUE : JNI_FALSE;
 }
@@ -250,7 +242,7 @@
 static jboolean android_view_GLES20Canvas_clipRectF(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jfloat left, jfloat top, jfloat right, jfloat bottom,
         jint op) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     const bool result = renderer->clipRect(left, top, right, bottom,
                                            static_cast<SkRegion::Op>(op));
     return result ? JNI_TRUE : JNI_FALSE;
@@ -259,7 +251,7 @@
 static jboolean android_view_GLES20Canvas_clipRect(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jint left, jint top, jint right, jint bottom,
         jint op) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     const bool result = renderer->clipRect(float(left), float(top), float(right),
                                            float(bottom),
                                            static_cast<SkRegion::Op>(op));
@@ -268,7 +260,7 @@
 
 static jboolean android_view_GLES20Canvas_clipPath(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jlong pathPtr, jint op) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     SkPath* path = reinterpret_cast<SkPath*>(pathPtr);
     const bool result = renderer->clipPath(path, static_cast<SkRegion::Op>(op));
     return result ? JNI_TRUE : JNI_FALSE;
@@ -276,7 +268,7 @@
 
 static jboolean android_view_GLES20Canvas_clipRegion(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jlong regionPtr, jint op) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     SkRegion* region = reinterpret_cast<SkRegion*>(regionPtr);
     const bool result = renderer->clipRegion(region, static_cast<SkRegion::Op>(op));
     return result ? JNI_TRUE : JNI_FALSE;
@@ -284,7 +276,7 @@
 
 static jboolean android_view_GLES20Canvas_getClipBounds(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jobject rect) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     const android::uirenderer::Rect& bounds(renderer->getLocalClipBounds());
 
     env->CallVoidMethod(rect, gRectClassInfo.set,
@@ -299,45 +291,45 @@
 
 static void android_view_GLES20Canvas_translate(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jfloat dx, jfloat dy) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     renderer->translate(dx, dy);
 }
 
 static void android_view_GLES20Canvas_rotate(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jfloat degrees) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     renderer->rotate(degrees);
 }
 
 static void android_view_GLES20Canvas_scale(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jfloat sx, jfloat sy) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     renderer->scale(sx, sy);
 }
 
 static void android_view_GLES20Canvas_skew(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jfloat sx, jfloat sy) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     renderer->skew(sx, sy);
 }
 
 static void android_view_GLES20Canvas_setMatrix(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jlong matrixPtr) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr);
     renderer->setMatrix(matrix ? *matrix : SkMatrix::I());
 }
 
 static void android_view_GLES20Canvas_getMatrix(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jlong matrixPtr) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr);
     renderer->getMatrix(matrix);
 }
 
 static void android_view_GLES20Canvas_concatMatrix(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jlong matrixPtr) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr);
     renderer->concatMatrix(*matrix);
 }
@@ -353,7 +345,7 @@
     // This object allows the renderer to allocate a global JNI ref to the buffer object.
     JavaHeapBitmapRef bitmapRef(env, bitmap, buffer);
 
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
     renderer->drawBitmap(bitmap, left, top, paint);
 }
@@ -366,7 +358,7 @@
     // This object allows the renderer to allocate a global JNI ref to the buffer object.
     JavaHeapBitmapRef bitmapRef(env, bitmap, buffer);
 
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
     renderer->drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom,
             dstLeft, dstTop, dstRight, dstBottom, paint);
@@ -379,7 +371,7 @@
     // This object allows the renderer to allocate a global JNI ref to the buffer object.
     JavaHeapBitmapRef bitmapRef(env, bitmap, buffer);
 
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr);
     SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
     renderer->drawBitmap(bitmap, *matrix, paint);
@@ -402,7 +394,7 @@
         return;
     }
 
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
     renderer->drawBitmapData(bitmap, left, top, paint);
 
@@ -423,7 +415,7 @@
     jfloat* verticesArray = vertices ? env->GetFloatArrayElements(vertices, NULL) + offset : NULL;
     jint* colorsArray = colors ? env->GetIntArrayElements(colors, NULL) + colorOffset : NULL;
 
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
     renderer->drawBitmapMesh(bitmap, meshWidth, meshHeight, verticesArray, colorsArray, paint);
 
@@ -438,7 +430,7 @@
     // This object allows the renderer to allocate a global JNI ref to the buffer object.
     JavaHeapBitmapRef bitmapRef(env, bitmap, buffer);
 
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     Res_png_9patch* patch = reinterpret_cast<Res_png_9patch*>(patchPtr);
     SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
     renderer->drawPatch(bitmap, patch, left, top, right, bottom, paint);
@@ -446,14 +438,14 @@
 
 static void android_view_GLES20Canvas_drawColor(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jint color, jint mode) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     renderer->drawColor(color, static_cast<SkXfermode::Mode>(mode));
 }
 
 static void android_view_GLES20Canvas_drawRect(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jfloat left, jfloat top, jfloat right, jfloat bottom,
         jlong paintPtr) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
     renderer->drawRect(left, top, right, bottom, paint);
 }
@@ -461,21 +453,21 @@
 static void android_view_GLES20Canvas_drawRoundRect(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jfloat left, jfloat top, jfloat right, jfloat bottom,
         jfloat rx, jfloat ry, jlong paintPtr) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
     renderer->drawRoundRect(left, top, right, bottom, rx, ry, paint);
 }
 
 static void android_view_GLES20Canvas_drawCircle(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jfloat x, jfloat y, jfloat radius, jlong paintPtr) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
     renderer->drawCircle(x, y, radius, paint);
 }
 
 static void android_view_GLES20Canvas_drawCircleProps(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jlong xPropPtr, jlong yPropPtr, jlong radiusPropPtr, jlong paintPropPtr) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     CanvasPropertyPrimitive* xProp = reinterpret_cast<CanvasPropertyPrimitive*>(xPropPtr);
     CanvasPropertyPrimitive* yProp = reinterpret_cast<CanvasPropertyPrimitive*>(yPropPtr);
     CanvasPropertyPrimitive* radiusProp = reinterpret_cast<CanvasPropertyPrimitive*>(radiusPropPtr);
@@ -486,7 +478,7 @@
 static void android_view_GLES20Canvas_drawOval(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jfloat left, jfloat top, jfloat right, jfloat bottom,
         jlong paintPtr) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
     renderer->drawOval(left, top, right, bottom, paint);
 }
@@ -494,14 +486,14 @@
 static void android_view_GLES20Canvas_drawArc(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jfloat left, jfloat top, jfloat right, jfloat bottom,
         jfloat startAngle, jfloat sweepAngle, jboolean useCenter, jlong paintPtr) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
     renderer->drawArc(left, top, right, bottom, startAngle, sweepAngle, useCenter, paint);
 }
 
 static void android_view_GLES20Canvas_drawRegionAsRects(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jlong regionPtr, jlong paintPtr) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     SkRegion* region = reinterpret_cast<SkRegion*>(regionPtr);
     SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
     if (paint->getStyle() != SkPaint::kFill_Style ||
@@ -531,7 +523,7 @@
 
 static void android_view_GLES20Canvas_drawPoints(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jfloatArray points, jint offset, jint count, jlong paintPtr) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     jfloat* storage = env->GetFloatArrayElements(points, NULL);
     SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
     renderer->drawPoints(storage + offset, count, paint);
@@ -540,7 +532,7 @@
 
 static void android_view_GLES20Canvas_drawPath(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jlong pathPtr, jlong paintPtr) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     SkPath* path = reinterpret_cast<SkPath*>(pathPtr);
     SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
     renderer->drawPath(path, paint);
@@ -548,7 +540,7 @@
 
 static void android_view_GLES20Canvas_drawLines(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jfloatArray points, jint offset, jint count, jlong paintPtr) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     jfloat* storage = env->GetFloatArrayElements(points, NULL);
     SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
     renderer->drawLines(storage + offset, count, paint);
@@ -561,13 +553,13 @@
 
 static void android_view_GLES20Canvas_setupPaintFilter(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jint clearBits, jint setBits) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     renderer->setupPaintFilter(clearBits, setBits);
 }
 
 static void android_view_GLES20Canvas_resetPaintFilter(JNIEnv* env, jobject clazz,
         jlong rendererPtr) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     renderer->resetPaintFilter();
 }
 
@@ -594,7 +586,7 @@
 
 class RenderTextFunctor {
 public:
-    RenderTextFunctor(const Layout& layout, OpenGLRenderer* renderer, jfloat x, jfloat y,
+    RenderTextFunctor(const Layout& layout, DisplayListRenderer* renderer, jfloat x, jfloat y,
                 SkPaint* paint, uint16_t* glyphs, float* pos, float totalAdvance,
                 uirenderer::Rect& bounds)
             : layout(layout), renderer(renderer), x(x), y(y), paint(paint), glyphs(glyphs),
@@ -612,7 +604,7 @@
     }
 private:
     const Layout& layout;
-    OpenGLRenderer* renderer;
+    DisplayListRenderer* renderer;
     jfloat x;
     jfloat y;
     SkPaint* paint;
@@ -622,7 +614,7 @@
     uirenderer::Rect& bounds;
 };
 
-static void renderTextLayout(OpenGLRenderer* renderer, Layout* layout,
+static void renderTextLayout(DisplayListRenderer* renderer, Layout* layout,
     jfloat x, jfloat y, SkPaint* paint) {
     size_t nGlyphs = layout->nGlyphs();
     float* pos = new float[nGlyphs * 2];
@@ -640,7 +632,7 @@
 }
 #endif
 
-static void renderText(OpenGLRenderer* renderer, const jchar* text, int count,
+static void renderText(DisplayListRenderer* renderer, const jchar* text, int count,
         jfloat x, jfloat y, int bidiFlags, SkPaint* paint, TypefaceImpl* typeface) {
 #ifdef USE_MINIKIN
     Layout layout;
@@ -672,7 +664,7 @@
 #ifdef USE_MINIKIN
 class RenderTextOnPathFunctor {
 public:
-    RenderTextOnPathFunctor(const Layout& layout, OpenGLRenderer* renderer, float hOffset,
+    RenderTextOnPathFunctor(const Layout& layout, DisplayListRenderer* renderer, float hOffset,
                 float vOffset, SkPaint* paint, SkPath* path)
             : layout(layout), renderer(renderer), hOffset(hOffset), vOffset(vOffset),
                 paint(paint), path(path) {
@@ -688,7 +680,7 @@
     }
 private:
     const Layout& layout;
-    OpenGLRenderer* renderer;
+    DisplayListRenderer* renderer;
     float hOffset;
     float vOffset;
     SkPaint* paint;
@@ -696,7 +688,7 @@
 };
 #endif
 
-static void renderTextOnPath(OpenGLRenderer* renderer, const jchar* text, int count,
+static void renderTextOnPath(DisplayListRenderer* renderer, const jchar* text, int count,
         SkPath* path, jfloat hOffset, jfloat vOffset, int bidiFlags, SkPaint* paint,
         TypefaceImpl* typeface) {
 #ifdef USE_MINIKIN
@@ -724,7 +716,7 @@
 #endif
 }
 
-static void renderTextRun(OpenGLRenderer* renderer, const jchar* text,
+static void renderTextRun(DisplayListRenderer* renderer, const jchar* text,
         jint start, jint count, jint contextCount, jfloat x, jfloat y,
         int bidiFlags, SkPaint* paint, TypefaceImpl* typeface) {
 #ifdef USE_MINIKIN
@@ -757,7 +749,7 @@
 static void android_view_GLES20Canvas_drawTextArray(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jcharArray text, jint index, jint count,
         jfloat x, jfloat y, jint bidiFlags, jlong paintPtr, jlong typefacePtr) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     jchar* textArray = env->GetCharArrayElements(text, NULL);
     SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
     TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefacePtr);
@@ -769,7 +761,7 @@
 static void android_view_GLES20Canvas_drawText(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jstring text, jint start, jint end,
         jfloat x, jfloat y, jint bidiFlags, jlong paintPtr, jlong typefacePtr) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     const jchar* textArray = env->GetStringChars(text, NULL);
     SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
     TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefacePtr);
@@ -782,7 +774,7 @@
         jlong rendererPtr, jcharArray text, jint index, jint count,
         jlong pathPtr, jfloat hOffset, jfloat vOffset, jint bidiFlags, jlong paintPtr,
         jlong typefacePtr) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     jchar* textArray = env->GetCharArrayElements(text, NULL);
     SkPath* path = reinterpret_cast<SkPath*>(pathPtr);
     SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
@@ -797,7 +789,7 @@
         jlong rendererPtr, jstring text, jint start, jint end,
         jlong pathPtr, jfloat hOffset, jfloat vOffset, jint bidiFlags, jlong paintPtr,
         jlong typefacePtr) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     const jchar* textArray = env->GetStringChars(text, NULL);
     SkPath* path = reinterpret_cast<SkPath*>(pathPtr);
     SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
@@ -812,7 +804,7 @@
         jlong rendererPtr, jcharArray text, jint index, jint count,
         jint contextIndex, jint contextCount, jfloat x, jfloat y, jboolean isRtl,
         jlong paintPtr, jlong typefacePtr) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     jchar* textArray = env->GetCharArrayElements(text, NULL);
     SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
     TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefacePtr);
@@ -827,7 +819,7 @@
         jlong rendererPtr, jstring text, jint start, jint end,
         jint contextStart, int contextEnd, jfloat x, jfloat y, jboolean isRtl,
         jlong paintPtr, jlong typefacePtr) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     const jchar* textArray = env->GetStringChars(text, NULL);
     jint count = end - start;
     jint contextCount = contextEnd - contextStart;
@@ -857,7 +849,7 @@
 static jint android_view_GLES20Canvas_drawRenderNode(JNIEnv* env,
         jobject clazz, jlong rendererPtr, jlong renderNodePtr,
         jobject dirty, jint flags) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     android::uirenderer::Rect bounds;
     status_t status = renderer->drawRenderNode(renderNode, bounds, flags);
@@ -874,7 +866,7 @@
 
 static void android_view_GLES20Canvas_drawLayer(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jlong layerPtr, jfloat x, jfloat y) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
     Layer* layer = reinterpret_cast<Layer*>(layerPtr);
     renderer->drawLayer(layer, x, y);
 }
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 2b94b65..3e62d0b 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -76,26 +76,6 @@
     jobject mRunnable;
 };
 
-class SetAtlasTask : public RenderTask {
-public:
-    SetAtlasTask(const sp<GraphicBuffer>& buffer, int64_t* map, size_t size)
-            : mBuffer(buffer)
-            , mMap(map)
-            , mMapSize(size) {
-    }
-
-    virtual void run() {
-        CanvasContext::setTextureAtlas(mBuffer, mMap, mMapSize);
-        mMap = 0;
-        delete this;
-    }
-
-private:
-    sp<GraphicBuffer> mBuffer;
-    int64_t* mMap;
-    size_t mMapSize;
-};
-
 class OnFinishedEvent {
 public:
     OnFinishedEvent(BaseRenderNodeAnimator* animator, AnimationListener* listener)
@@ -193,7 +173,7 @@
 };
 
 static void android_view_ThreadedRenderer_setAtlas(JNIEnv* env, jobject clazz,
-        jobject graphicBuffer, jlongArray atlasMapArray) {
+        jlong proxyPtr, jobject graphicBuffer, jlongArray atlasMapArray) {
     sp<GraphicBuffer> buffer = graphicBufferForJavaObject(env, graphicBuffer);
     jsize len = env->GetArrayLength(atlasMapArray);
     if (len <= 0) {
@@ -203,8 +183,8 @@
     int64_t* map = new int64_t[len];
     env->GetLongArrayRegion(atlasMapArray, 0, len, map);
 
-    SetAtlasTask* task = new SetAtlasTask(buffer, map, len);
-    RenderThread::getInstance().queue(task);
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+    proxy->setTextureAtlas(buffer, map, len);
 }
 
 static jlong android_view_ThreadedRenderer_createRootRenderNode(JNIEnv* env, jobject clazz) {
@@ -291,10 +271,9 @@
 }
 
 static void android_view_ThreadedRenderer_invokeFunctor(JNIEnv* env, jobject clazz,
-        jlong proxyPtr, jlong functorPtr, jboolean waitForCompletion) {
-    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+        jlong functorPtr, jboolean waitForCompletion) {
     Functor* functor = reinterpret_cast<Functor*>(functorPtr);
-    proxy->invokeFunctor(functor, waitForCompletion);
+    RenderProxy::invokeFunctor(functor, waitForCompletion);
 }
 
 static void android_view_ThreadedRenderer_runWithGlContext(JNIEnv* env, jobject clazz,
@@ -387,7 +366,7 @@
 
 static JNINativeMethod gMethods[] = {
 #ifdef USE_OPENGL_RENDERER
-    { "nSetAtlas", "(Landroid/view/GraphicBuffer;[J)V",   (void*) android_view_ThreadedRenderer_setAtlas },
+    { "nSetAtlas", "(JLandroid/view/GraphicBuffer;[J)V",   (void*) android_view_ThreadedRenderer_setAtlas },
     { "nCreateRootRenderNode", "()J", (void*) android_view_ThreadedRenderer_createRootRenderNode },
     { "nCreateProxy", "(ZJ)J", (void*) android_view_ThreadedRenderer_createProxy },
     { "nDeleteProxy", "(J)V", (void*) android_view_ThreadedRenderer_deleteProxy },
@@ -400,7 +379,7 @@
     { "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque },
     { "nSyncAndDrawFrame", "(JJJF)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
     { "nDestroyCanvasAndSurface", "(J)V", (void*) android_view_ThreadedRenderer_destroyCanvasAndSurface },
-    { "nInvokeFunctor", "(JJZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },
+    { "nInvokeFunctor", "(JZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },
     { "nRunWithGlContext", "(JLjava/lang/Runnable;)V", (void*) android_view_ThreadedRenderer_runWithGlContext },
     { "nCreateDisplayListLayer", "(JII)J", (void*) android_view_ThreadedRenderer_createDisplayListLayer },
     { "nCreateTextureLayer", "(J)J", (void*) android_view_ThreadedRenderer_createTextureLayer },
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 02e85fe..95d8a97 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -45,6 +45,7 @@
 		RenderBufferCache.cpp \
 		RenderNode.cpp \
 		RenderProperties.cpp \
+		RenderState.cpp \
 		ResourceCache.cpp \
 		ShadowTessellator.cpp \
 		SkiaShader.cpp \
@@ -61,6 +62,7 @@
 	LOCAL_SRC_FILES += \
 		renderthread/CanvasContext.cpp \
 		renderthread/DrawFrameTask.cpp \
+		renderthread/EglManager.cpp \
 		renderthread/RenderProxy.cpp \
 		renderthread/RenderTask.cpp \
 		renderthread/RenderThread.cpp \
diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp
index 937bf8d..a998594 100644
--- a/libs/hwui/DeferredDisplayList.cpp
+++ b/libs/hwui/DeferredDisplayList.cpp
@@ -500,7 +500,7 @@
 void DeferredDisplayList::addDrawOp(OpenGLRenderer& renderer, DrawOp* op) {
     /* 1: op calculates local bounds */
     DeferredDisplayState* const state = createState();
-    if (op->getLocalBounds(renderer.getDrawModifiers(), state->mBounds)) {
+    if (op->getLocalBounds(state->mBounds)) {
         if (state->mBounds.isEmpty()) {
             // valid empty bounds, don't bother deferring
             tryRecycleState(state);
diff --git a/libs/hwui/DeferredDisplayList.h b/libs/hwui/DeferredDisplayList.h
index 48489c2..8a015b21 100644
--- a/libs/hwui/DeferredDisplayList.h
+++ b/libs/hwui/DeferredDisplayList.h
@@ -38,7 +38,6 @@
 class StateOp;
 
 class DeferredDisplayState;
-class OpenGLRenderer;
 
 class Batch;
 class DrawBatch;
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index 5082271..c76bd5e 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -23,7 +23,6 @@
 #include <utils/StrongPointer.h>
 
 #include "Layer.h"
-#include "OpenGLRenderer.h"
 #include "Rect.h"
 #include "RenderNode.h"
 
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 811af39..5ed04a0 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -171,7 +171,7 @@
      *
      * returns true if bounds exist
      */
-    virtual bool getLocalBounds(const DrawModifiers& drawModifiers, Rect& localBounds) {
+    virtual bool getLocalBounds(Rect& localBounds) {
         return false;
     }
 
@@ -253,7 +253,7 @@
     // default empty constructor for bounds, to be overridden in child constructor body
     DrawBoundedOp(const SkPaint* paint): DrawOp(paint) { }
 
-    bool getLocalBounds(const DrawModifiers& drawModifiers, Rect& localBounds) {
+    bool getLocalBounds(Rect& localBounds) {
         localBounds.set(mLocalBounds);
         OpenGLRenderer::TextShadow textShadow;
         if (OpenGLRenderer::getTextShadow(mPaint, &textShadow)) {
@@ -1029,7 +1029,7 @@
     DrawStrokableOp(float left, float top, float right, float bottom, const SkPaint* paint)
             : DrawBoundedOp(left, top, right, bottom, paint) {};
 
-    bool getLocalBounds(const DrawModifiers& drawModifiers, Rect& localBounds) {
+    bool getLocalBounds(Rect& localBounds) {
         localBounds.set(mLocalBounds);
         if (mPaint && mPaint->getStyle() != SkPaint::kFill_Style) {
             localBounds.outset(strokeWidthOutset());
@@ -1399,7 +1399,7 @@
 
     virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
         Rect bounds;
-        getLocalBounds(renderer.getDrawModifiers(), bounds);
+        getLocalBounds(bounds);
         return renderer.drawText(mText, mBytesCount, mCount, mX, mY,
                 mPositions, getPaint(renderer), mTotalAdvance, bounds);
     }
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index b6d3f4b..7789358 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -425,7 +425,7 @@
 
 void DisplayListRenderer::addDrawOp(DrawOp* op) {
     Rect localBounds;
-    if (op->getLocalBounds(mDrawModifiers, localBounds)) {
+    if (op->getLocalBounds(localBounds)) {
         bool rejected = quickRejectConservative(localBounds.left, localBounds.top,
                 localBounds.right, localBounds.bottom);
         op->setQuickRejected(rejected);
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 1de656e..8ca9af1 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -23,7 +23,6 @@
 #include <cutils/compiler.h>
 
 #include "DisplayListLogBuffer.h"
-#include "OpenGLRenderer.h"
 #include "RenderNode.h"
 
 namespace android {
@@ -53,12 +52,12 @@
 /**
  * Records drawing commands in a display list for later playback into an OpenGLRenderer.
  */
-class DisplayListRenderer: public OpenGLRenderer {
+class ANDROID_API DisplayListRenderer: public StatefulBaseRenderer {
 public:
-    ANDROID_API DisplayListRenderer();
+    DisplayListRenderer();
     virtual ~DisplayListRenderer();
 
-    ANDROID_API DisplayListData* finishRecording();
+    DisplayListData* finishRecording();
 
     virtual bool isRecording() const { return true; }
 
@@ -81,7 +80,7 @@
             const SkPaint* paint, int flags);
 
     // Matrix
-    virtual void translate(float dx, float dy, float dz);
+    virtual void translate(float dx, float dy, float dz = 0.0f);
     virtual void rotate(float degrees);
     virtual void scale(float sx, float sy);
     virtual void skew(float sx, float sy);
@@ -98,6 +97,10 @@
     virtual void resetPaintFilter();
     virtual void setupPaintFilter(int clearBits, int setBits);
 
+    bool isCurrentTransformSimple() {
+        return currentTransform()->isSimple();
+    }
+
 // ----------------------------------------------------------------------------
 // Canvas draw operations
 // ----------------------------------------------------------------------------
@@ -152,11 +155,6 @@
 
     // TODO: rename for consistency
     virtual status_t callDrawGLFunction(Functor* functor, Rect& dirty);
-protected:
-    // NOTE: must override these to avoid calling into super class, which calls GL. These may be
-    // removed once DisplayListRenderer no longer inherits from OpenGLRenderer
-    virtual void onViewportInitialized() {};
-    virtual void onSnapshotRestored() {};
 
 private:
     void insertRestoreToCount();
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index b6414e5..73a4da5 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -20,6 +20,7 @@
 
 #include "Caches.h"
 #include "DeferredDisplayList.h"
+#include "RenderState.h"
 #include "Layer.h"
 #include "LayerRenderer.h"
 #include "OpenGLRenderer.h"
@@ -28,8 +29,10 @@
 namespace android {
 namespace uirenderer {
 
-Layer::Layer(const uint32_t layerWidth, const uint32_t layerHeight):
-        caches(Caches::getInstance()), texture(caches) {
+Layer::Layer(RenderState& renderState, const uint32_t layerWidth, const uint32_t layerHeight)
+        : caches(Caches::getInstance())
+        , renderState(renderState)
+        , texture(caches) {
     mesh = NULL;
     meshElementCount = 0;
     cacheable = true;
@@ -72,7 +75,7 @@
 
 void Layer::requireRenderer() {
     if (!renderer) {
-        renderer = new LayerRenderer(this);
+        renderer = new LayerRenderer(renderState, this);
         renderer->initProperties();
     }
 }
@@ -123,18 +126,17 @@
 
 void Layer::removeFbo(bool flush) {
     if (stencil) {
-        GLuint previousFbo;
-        glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &previousFbo);
-        if (fbo != previousFbo) glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+        GLuint previousFbo = renderState.getFramebuffer();
+        renderState.bindFramebuffer(fbo);
         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
-        if (fbo != previousFbo) glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
+        renderState.bindFramebuffer(previousFbo);
 
         caches.renderBufferCache.put(stencil);
         stencil = NULL;
     }
 
     if (fbo) {
-        if (flush) LayerRenderer::flushLayer(this);
+        if (flush) LayerRenderer::flushLayer(renderState, this);
         // If put fails the cache will delete the FBO
         caches.fboCache.put(fbo);
         fbo = 0;
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 741f4c3..0bf05d0 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -43,6 +43,7 @@
 
 // Forward declarations
 class Caches;
+class RenderState;
 class OpenGLRenderer;
 class RenderNode;
 class DeferredDisplayList;
@@ -53,7 +54,7 @@
  */
 class Layer {
 public:
-    Layer(const uint32_t layerWidth, const uint32_t layerHeight);
+    Layer(RenderState& renderState, const uint32_t layerWidth, const uint32_t layerHeight);
     ~Layer();
 
     static uint32_t computeIdealWidth(uint32_t layerWidth);
@@ -306,6 +307,8 @@
 
     Caches& caches;
 
+    RenderState& renderState;
+
     /**
      * Name of the FBO used to render the layer. If the name is 0
      * this layer is not backed by an FBO, but a simple texture.
diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp
index 6be0146..13869aa 100644
--- a/libs/hwui/LayerCache.cpp
+++ b/libs/hwui/LayerCache.cpp
@@ -91,7 +91,7 @@
     mCache.clear();
 }
 
-Layer* LayerCache::get(const uint32_t width, const uint32_t height) {
+Layer* LayerCache::get(RenderState& renderState, const uint32_t width, const uint32_t height) {
     Layer* layer = NULL;
 
     LayerEntry entry(width, height);
@@ -108,7 +108,7 @@
     } else {
         LAYER_LOGD("Creating new layer %dx%d", entry.mWidth, entry.mHeight);
 
-        layer = new Layer(entry.mWidth, entry.mHeight);
+        layer = new Layer(renderState, entry.mWidth, entry.mHeight);
         layer->setBlend(true);
         layer->setEmpty(true);
         layer->setFbo(0);
diff --git a/libs/hwui/LayerCache.h b/libs/hwui/LayerCache.h
index 221bfe0..1b0fc2c 100644
--- a/libs/hwui/LayerCache.h
+++ b/libs/hwui/LayerCache.h
@@ -24,6 +24,8 @@
 namespace android {
 namespace uirenderer {
 
+class RenderState;
+
 ///////////////////////////////////////////////////////////////////////////////
 // Defines
 ///////////////////////////////////////////////////////////////////////////////
@@ -55,7 +57,7 @@
      * @param width The desired width of the layer
      * @param height The desired height of the layer
      */
-    Layer* get(const uint32_t width, const uint32_t height);
+    Layer* get(RenderState& renderState, const uint32_t width, const uint32_t height);
 
     /**
      * Adds the layer to the cache. The layer will not be added if there is
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index a5fd375..873baf5 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -20,6 +20,7 @@
 
 #include <private/hwui/DrawGlInfo.h>
 
+#include "RenderState.h"
 #include "LayerCache.h"
 #include "LayerRenderer.h"
 #include "Matrix.h"
@@ -33,7 +34,9 @@
 // Rendering
 ///////////////////////////////////////////////////////////////////////////////
 
-LayerRenderer::LayerRenderer(Layer* layer): mLayer(layer) {
+LayerRenderer::LayerRenderer(RenderState& renderState, Layer* layer)
+        : OpenGLRenderer(renderState)
+        , mLayer(layer) {
 }
 
 LayerRenderer::~LayerRenderer() {
@@ -43,7 +46,7 @@
         bool opaque) {
     LAYER_RENDERER_LOGD("Rendering into layer, fbo = %d", mLayer->getFbo());
 
-    glBindFramebuffer(GL_FRAMEBUFFER, mLayer->getFbo());
+    renderState().bindFramebuffer(mLayer->getFbo());
 
     const float width = mLayer->layer.getWidth();
     const float height = mLayer->layer.getHeight();
@@ -180,7 +183,7 @@
 // Layers management
 ///////////////////////////////////////////////////////////////////////////////
 
-Layer* LayerRenderer::createRenderLayer(uint32_t width, uint32_t height) {
+Layer* LayerRenderer::createRenderLayer(RenderState& renderState, uint32_t width, uint32_t height) {
     LAYER_RENDERER_LOGD("Requesting new render layer %dx%d", width, height);
 
     Caches& caches = Caches::getInstance();
@@ -191,7 +194,7 @@
     }
 
     caches.activeTexture(0);
-    Layer* layer = caches.layerCache.get(width, height);
+    Layer* layer = caches.layerCache.get(renderState, width, height);
     if (!layer) {
         ALOGW("Could not obtain a layer");
         return NULL;
@@ -221,10 +224,9 @@
     layer->setDirty(true);
     layer->region.clear();
 
-    GLuint previousFbo;
-    glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &previousFbo);
+    GLuint previousFbo = renderState.getFramebuffer();
 
-    glBindFramebuffer(GL_FRAMEBUFFER, layer->getFbo());
+    renderState.bindFramebuffer(layer->getFbo());
     layer->bindTexture();
 
     // Initialize the texture if needed
@@ -235,7 +237,7 @@
         // This should only happen if we run out of memory
         if (glGetError() != GL_NO_ERROR) {
             ALOGE("Could not allocate texture for layer (fbo=%d %dx%d)", fbo, width, height);
-            glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
+            renderState.bindFramebuffer(previousFbo);
             caches.resourceCache.decrementRefcount(layer);
             return NULL;
         }
@@ -244,7 +246,7 @@
     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
             layer->getTexture(), 0);
 
-    glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
+    renderState.bindFramebuffer(previousFbo);
 
     return layer;
 }
@@ -265,10 +267,10 @@
     return true;
 }
 
-Layer* LayerRenderer::createTextureLayer() {
+Layer* LayerRenderer::createTextureLayer(RenderState& renderState) {
     LAYER_RENDERER_LOGD("Creating new texture layer");
 
-    Layer* layer = new Layer(0, 0);
+    Layer* layer = new Layer(renderState, 0, 0);
     layer->setCacheable(false);
     layer->setTextureLayer(true);
     layer->setEmpty(true);
@@ -332,7 +334,7 @@
     }
 }
 
-void LayerRenderer::flushLayer(Layer* layer) {
+void LayerRenderer::flushLayer(RenderState& renderState, Layer* layer) {
 #ifdef GL_EXT_discard_framebuffer
     if (!layer) return;
 
@@ -341,20 +343,23 @@
         // If possible, discard any enqueud operations on deferred
         // rendering architectures
         if (Extensions::getInstance().hasDiscardFramebuffer()) {
-            GLuint previousFbo;
-            glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &previousFbo);
-            if (fbo != previousFbo) glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+            GLuint previousFbo = renderState.getFramebuffer();
+            if (fbo != previousFbo) {
+                renderState.bindFramebuffer(fbo);
+            }
 
             const GLenum attachments[] = { GL_COLOR_ATTACHMENT0 };
             glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, attachments);
 
-            if (fbo != previousFbo) glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
+            if (fbo != previousFbo) {
+                renderState.bindFramebuffer(previousFbo);
+            }
         }
     }
 #endif
 }
 
-bool LayerRenderer::copyLayer(Layer* layer, SkBitmap* bitmap) {
+bool LayerRenderer::copyLayer(RenderState& renderState, Layer* layer, SkBitmap* bitmap) {
     Caches& caches = Caches::getInstance();
     if (layer && bitmap->width() <= caches.maxTextureSize &&
             bitmap->height() <= caches.maxTextureSize) {
@@ -369,7 +374,8 @@
 
         GLuint texture;
         GLuint previousFbo;
-        GLuint previousViewport[4];
+        GLsizei previousViewportWidth;
+        GLsizei previousViewportHeight;
 
         GLenum format;
         GLenum type;
@@ -404,9 +410,9 @@
         layer->setAlpha(255, SkXfermode::kSrc_Mode);
         layer->setFbo(fbo);
 
-        glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &previousFbo);
-        glGetIntegerv(GL_VIEWPORT, (GLint*) &previousViewport);
-        glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+        previousFbo = renderState.getFramebuffer();
+        renderState.getViewport(&previousViewportWidth, &previousViewportHeight);
+        renderState.bindFramebuffer(fbo);
 
         glGenTextures(1, &texture);
         if ((error = glGetError()) != GL_NO_ERROR) goto error;
@@ -431,7 +437,7 @@
         if ((error = glGetError()) != GL_NO_ERROR) goto error;
 
         {
-            LayerRenderer renderer(layer);
+            LayerRenderer renderer(renderState, layer);
             renderer.setViewport(bitmap->width(), bitmap->height());
             renderer.OpenGLRenderer::prepareDirty(0.0f, 0.0f,
                     bitmap->width(), bitmap->height(), !layer->isBlend());
@@ -471,13 +477,12 @@
         }
 #endif
 
-        glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
+        renderState.bindFramebuffer(previousFbo);
         layer->setAlpha(alpha, mode);
         layer->setFbo(previousLayerFbo);
         caches.deleteTexture(texture);
         caches.fboCache.put(fbo);
-        glViewport(previousViewport[0], previousViewport[1],
-                previousViewport[2], previousViewport[3]);
+        renderState.setViewport(previousViewportWidth, previousViewportHeight);
 
         return status;
     }
diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h
index e79e7b8..9202e49 100644
--- a/libs/hwui/LayerRenderer.h
+++ b/libs/hwui/LayerRenderer.h
@@ -27,6 +27,8 @@
 namespace android {
 namespace uirenderer {
 
+class RenderState;
+
 ///////////////////////////////////////////////////////////////////////////////
 // Defines
 ///////////////////////////////////////////////////////////////////////////////
@@ -44,7 +46,7 @@
 
 class LayerRenderer: public OpenGLRenderer {
 public:
-    ANDROID_API LayerRenderer(Layer* layer);
+    LayerRenderer(RenderState& renderState, Layer* layer);
     virtual ~LayerRenderer();
 
     virtual void onViewportInitialized(int width, int height) { /* do nothing */ }
@@ -52,16 +54,16 @@
     virtual status_t clear(float left, float top, float right, float bottom, bool opaque);
     virtual void finish();
 
-    ANDROID_API static Layer* createTextureLayer();
-    ANDROID_API static Layer* createRenderLayer(uint32_t width, uint32_t height);
-    ANDROID_API static bool resizeLayer(Layer* layer, uint32_t width, uint32_t height);
-    ANDROID_API static void updateTextureLayer(Layer* layer, uint32_t width, uint32_t height,
+    static Layer* createTextureLayer(RenderState& renderState);
+    static Layer* createRenderLayer(RenderState& renderState, uint32_t width, uint32_t height);
+    static bool resizeLayer(Layer* layer, uint32_t width, uint32_t height);
+    static void updateTextureLayer(Layer* layer, uint32_t width, uint32_t height,
             bool isOpaque, bool forceFilter, GLenum renderTarget, float* textureTransform);
-    ANDROID_API static void destroyLayer(Layer* layer);
+    static void destroyLayer(Layer* layer);
     ANDROID_API static void destroyLayerDeferred(Layer* layer);
-    ANDROID_API static bool copyLayer(Layer* layer, SkBitmap* bitmap);
+    static bool copyLayer(RenderState& renderState, Layer* layer, SkBitmap* bitmap);
 
-    static void flushLayer(Layer* layer);
+    static void flushLayer(RenderState& renderState, Layer* layer);
 
 protected:
     virtual void ensureStencilBuffer();
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index afb65a6..ede89d7 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -35,6 +35,7 @@
 #include "DeferredDisplayList.h"
 #include "DisplayListRenderer.h"
 #include "Fence.h"
+#include "RenderState.h"
 #include "PathTessellator.h"
 #include "Properties.h"
 #include "ShadowTessellator.h"
@@ -129,8 +130,10 @@
 // Constructors/destructor
 ///////////////////////////////////////////////////////////////////////////////
 
-OpenGLRenderer::OpenGLRenderer():
-        mCaches(Caches::getInstance()), mExtensions(Extensions::getInstance()) {
+OpenGLRenderer::OpenGLRenderer(RenderState& renderState)
+        : mCaches(Caches::getInstance())
+        , mExtensions(Extensions::getInstance())
+        , mRenderState(renderState) {
     // *set* draw modifiers to be 0
     memset(&mDrawModifiers, 0, sizeof(mDrawModifiers));
     mDrawModifiers.mOverrideLayerAlpha = 1.0f;
@@ -187,7 +190,7 @@
 
     discardFramebuffer(mTilingClip.left, mTilingClip.top, mTilingClip.right, mTilingClip.bottom);
 
-    glViewport(0, 0, getWidth(), getHeight());
+    mRenderState.setViewport(getWidth(), getHeight());
 
     // Functors break the tiling extension in pretty spectacular ways
     // This ensures we don't use tiling when a functor is going to be
@@ -311,46 +314,9 @@
     mFrameStarted = false;
 }
 
-void OpenGLRenderer::interrupt() {
-    if (mCaches.currentProgram) {
-        if (mCaches.currentProgram->isInUse()) {
-            mCaches.currentProgram->remove();
-            mCaches.currentProgram = NULL;
-        }
-    }
-    mCaches.resetActiveTexture();
-    mCaches.unbindMeshBuffer();
-    mCaches.unbindIndicesBuffer();
-    mCaches.resetVertexPointers();
-    mCaches.disableTexCoordsVertexArray();
-    debugOverdraw(false, false);
-}
-
-void OpenGLRenderer::resume() {
-    const Snapshot* snapshot = currentSnapshot();
-    glViewport(0, 0, getViewportWidth(), getViewportHeight());
-    glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo);
-    debugOverdraw(true, false);
-
-    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
-
-    mCaches.scissorEnabled = glIsEnabled(GL_SCISSOR_TEST);
-    mCaches.enableScissor();
-    mCaches.resetScissor();
-    dirtyClip();
-
-    mCaches.activeTexture(0);
-    mCaches.resetBoundTextures();
-
-    mCaches.blend = true;
-    glEnable(GL_BLEND);
-    glBlendFunc(mCaches.lastSrcMode, mCaches.lastDstMode);
-    glBlendEquation(GL_FUNC_ADD);
-}
-
 void OpenGLRenderer::resumeAfterLayer() {
-    glViewport(0, 0, getViewportWidth(), getViewportHeight());
-    glBindFramebuffer(GL_FRAMEBUFFER, currentSnapshot()->fbo);
+    mRenderState.setViewport(getViewportWidth(), getViewportHeight());
+    mRenderState.bindFramebuffer(currentSnapshot()->fbo);
     debugOverdraw(true, false);
 
     mCaches.resetScissor();
@@ -379,20 +345,19 @@
     info.height = getViewportHeight();
     currentTransform()->copyTo(&info.transform[0]);
 
-    bool dirtyClip = mDirtyClip;
+    bool prevDirtyClip = mDirtyClip;
     // setup GL state for functor
     if (mDirtyClip) {
         setStencilFromClip(); // can issue draws, so must precede enableScissor()/interrupt()
     }
-    if (mCaches.enableScissor() || dirtyClip) {
+    if (mCaches.enableScissor() || prevDirtyClip) {
         setScissorFromClip();
     }
-    interrupt();
 
-    // call functor immediately after GL state setup
-    (*functor)(DrawGlInfo::kModeDraw, &info);
+    mRenderState.invokeFunctor(functor, DrawGlInfo::kModeDraw, &info);
+    // Scissor may have been modified, reset dirty clip
+    dirtyClip();
 
-    resume();
     return DrawGlInfo::kStatusDrew;
 }
 
@@ -413,17 +378,7 @@
 }
 
 void OpenGLRenderer::debugOverdraw(bool enable, bool clear) {
-    if (mCaches.debugOverdraw && getTargetFbo() == 0) {
-        if (clear) {
-            mCaches.disableScissor();
-            mCaches.stencil.clear();
-        }
-        if (enable) {
-            mCaches.stencil.enableDebugWrite();
-        } else {
-            mCaches.stencil.disable();
-        }
-    }
+    mRenderState.debugOverdraw(enable, clear);
 }
 
 void OpenGLRenderer::renderOverdraw() {
@@ -528,7 +483,7 @@
 
         if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
             mLayerUpdates.clear();
-            glBindFramebuffer(GL_FRAMEBUFFER, getTargetFbo());
+            mRenderState.bindFramebuffer(getTargetFbo());
         }
         endMark();
     }
@@ -556,7 +511,7 @@
         }
 
         mLayerUpdates.clear();
-        glBindFramebuffer(GL_FRAMEBUFFER, getTargetFbo());
+        mRenderState.bindFramebuffer(getTargetFbo());
 
         endMark();
     }
@@ -620,7 +575,7 @@
     bool restoreLayer = removed.flags & Snapshot::kFlagIsLayer;
 
     if (restoreViewport) {
-        glViewport(0, 0, getViewportWidth(), getViewportHeight());
+        mRenderState.setViewport(getViewportWidth(), getViewportHeight());
     }
 
     if (restoreClip) {
@@ -791,7 +746,7 @@
     }
 
     mCaches.activeTexture(0);
-    Layer* layer = mCaches.layerCache.get(bounds.getWidth(), bounds.getHeight());
+    Layer* layer = mCaches.layerCache.get(mRenderState, bounds.getWidth(), bounds.getHeight());
     if (!layer) {
         return false;
     }
@@ -853,7 +808,7 @@
     endTiling();
     debugOverdraw(false, false);
     // Bind texture to FBO
-    glBindFramebuffer(GL_FRAMEBUFFER, layer->getFbo());
+    mRenderState.bindFramebuffer(layer->getFbo());
     layer->bindTexture();
 
     // Initialize the texture if needed
@@ -876,7 +831,7 @@
     dirtyClip();
 
     // Change the ortho projection
-    glViewport(0, 0, bounds.getWidth(), bounds.getHeight());
+    mRenderState.setViewport(bounds.getWidth(), bounds.getHeight());
     return true;
 }
 
@@ -907,7 +862,7 @@
         layer->removeFbo(false);
 
         // Unbind current FBO and restore previous one
-        glBindFramebuffer(GL_FRAMEBUFFER, restored.fbo);
+        mRenderState.bindFramebuffer(restored.fbo);
         debugOverdraw(true, false);
 
         startTilingCurrentClip();
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 066b267..4ff5780 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -57,6 +57,7 @@
 namespace uirenderer {
 
 class DeferredDisplayState;
+class RenderState;
 class RenderNode;
 class TextSetupFunctor;
 class VertexBuffer;
@@ -119,33 +120,31 @@
  */
 class OpenGLRenderer : public StatefulBaseRenderer {
 public:
-    ANDROID_API OpenGLRenderer();
+    OpenGLRenderer(RenderState& renderState);
     virtual ~OpenGLRenderer();
 
-    ANDROID_API void initProperties();
+    void initProperties();
 
     virtual void onViewportInitialized();
     virtual status_t prepareDirty(float left, float top, float right, float bottom, bool opaque);
     virtual void finish();
-    virtual void interrupt();
-    virtual void resume();
 
-    ANDROID_API void setCountOverdrawEnabled(bool enabled) {
+    void setCountOverdrawEnabled(bool enabled) {
         mCountOverdraw = enabled;
     }
 
-    ANDROID_API float getOverdraw() {
+    float getOverdraw() {
         return mCountOverdraw ? mOverdraw : 0.0f;
     }
 
     virtual status_t callDrawGLFunction(Functor* functor, Rect& dirty);
 
-    ANDROID_API void pushLayerUpdate(Layer* layer);
-    ANDROID_API void cancelLayerUpdate(Layer* layer);
-    ANDROID_API void clearLayerUpdates();
-    ANDROID_API void flushLayerUpdates();
+    void pushLayerUpdate(Layer* layer);
+    void cancelLayerUpdate(Layer* layer);
+    void clearLayerUpdates();
+    void flushLayerUpdates();
 
-    ANDROID_API virtual int saveLayer(float left, float top, float right, float bottom,
+    virtual int saveLayer(float left, float top, float right, float bottom,
             const SkPaint* paint, int flags) {
         return saveLayer(left, top, right, bottom, paint, flags, NULL);
     }
@@ -231,7 +230,7 @@
     const DrawModifiers& getDrawModifiers() { return mDrawModifiers; }
     void setDrawModifiers(const DrawModifiers& drawModifiers) { mDrawModifiers = drawModifiers; }
 
-    ANDROID_API bool isCurrentTransformSimple() {
+    bool isCurrentTransformSimple() {
         return currentTransform()->isSimple();
     }
 
@@ -474,6 +473,8 @@
         return false;
     }
 
+    inline RenderState& renderState() { return mRenderState; }
+
 private:
     /**
      * Discards the content of the framebuffer if supported by the driver.
@@ -977,6 +978,7 @@
     // Various caches
     Caches& mCaches;
     Extensions& mExtensions;
+    RenderState& mRenderState;
 
     // List of rectangles to clear after saveLayer() is invoked
     Vector<Rect*> mLayers;
@@ -1012,7 +1014,6 @@
 
     bool mSkipOutlineClip;
 
-    friend class DisplayListRenderer;
     friend class Layer;
     friend class TextSetupFunctor;
     friend class DrawBitmapOp;
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index e8f2dd2..131384a 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -155,7 +155,7 @@
     }
 
     if (!mLayer) {
-        mLayer = LayerRenderer::createRenderLayer(getWidth(), getHeight());
+        mLayer = LayerRenderer::createRenderLayer(info.renderState, getWidth(), getHeight());
         applyLayerPropertiesToLayer(info);
         damageSelf(info);
     } else if (mLayer->layer.getWidth() != getWidth() || mLayer->layer.getHeight() != getHeight()) {
@@ -267,7 +267,7 @@
         mNeedsDisplayListDataSync = false;
         // Do a push pass on the old tree to handle freeing DisplayListData
         // that are no longer used
-        TreeInfo oldTreeInfo(TreeInfo::MODE_MAYBE_DETACHING);
+        TreeInfo oldTreeInfo(TreeInfo::MODE_MAYBE_DETACHING, info.renderState);
         oldTreeInfo.damageAccumulator = info.damageAccumulator;
         prepareSubTree(oldTreeInfo, mDisplayListData);
         delete mDisplayListData;
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 2fa6078..3980dad 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -55,7 +55,6 @@
 namespace android {
 namespace uirenderer {
 
-class DeferredDisplayList;
 class DisplayListOp;
 class DisplayListRenderer;
 class OpenGLRenderer;
diff --git a/libs/hwui/RenderState.cpp b/libs/hwui/RenderState.cpp
new file mode 100644
index 0000000..97f379d
--- /dev/null
+++ b/libs/hwui/RenderState.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "RenderState.h"
+
+namespace android {
+namespace uirenderer {
+
+RenderState::RenderState()
+        : mCaches(NULL)
+        , mViewportWidth(0)
+        , mViewportHeight(0)
+        , mFramebuffer(0) {
+}
+
+RenderState::~RenderState() {
+}
+
+void RenderState::onGLContextCreated() {
+    // This is delayed because the first access of Caches makes GL calls
+    mCaches = &Caches::getInstance();
+    mCaches->init();
+}
+
+void RenderState::setViewport(GLsizei width, GLsizei height) {
+    mViewportWidth = width;
+    mViewportHeight = height;
+    glViewport(0, 0, mViewportWidth, mViewportHeight);
+}
+
+
+void RenderState::getViewport(GLsizei* outWidth, GLsizei* outHeight) {
+    *outWidth = mViewportWidth;
+    *outHeight = mViewportHeight;
+}
+
+void RenderState::bindFramebuffer(GLuint fbo) {
+    if (mFramebuffer != fbo) {
+        mFramebuffer = fbo;
+        glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
+    }
+}
+
+void RenderState::invokeFunctor(Functor* functor, DrawGlInfo::Mode mode, DrawGlInfo* info) {
+    interruptForFunctorInvoke();
+    (*functor)(mode, info);
+    resumeFromFunctorInvoke();
+}
+
+void RenderState::interruptForFunctorInvoke() {
+    if (mCaches->currentProgram) {
+        if (mCaches->currentProgram->isInUse()) {
+            mCaches->currentProgram->remove();
+            mCaches->currentProgram = NULL;
+        }
+    }
+    mCaches->resetActiveTexture();
+    mCaches->unbindMeshBuffer();
+    mCaches->unbindIndicesBuffer();
+    mCaches->resetVertexPointers();
+    mCaches->disableTexCoordsVertexArray();
+    debugOverdraw(false, false);
+}
+
+void RenderState::resumeFromFunctorInvoke() {
+    glViewport(0, 0, mViewportWidth, mViewportHeight);
+    glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
+    debugOverdraw(false, false);
+
+    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+
+    mCaches->scissorEnabled = glIsEnabled(GL_SCISSOR_TEST);
+    mCaches->enableScissor();
+    mCaches->resetScissor();
+
+    mCaches->activeTexture(0);
+    mCaches->resetBoundTextures();
+
+    mCaches->blend = true;
+    glEnable(GL_BLEND);
+    glBlendFunc(mCaches->lastSrcMode, mCaches->lastDstMode);
+    glBlendEquation(GL_FUNC_ADD);
+}
+
+void RenderState::debugOverdraw(bool enable, bool clear) {
+    if (mCaches->debugOverdraw && mFramebuffer == 0) {
+        if (clear) {
+            mCaches->disableScissor();
+            mCaches->stencil.clear();
+        }
+        if (enable) {
+            mCaches->stencil.enableDebugWrite();
+        } else {
+            mCaches->stencil.disable();
+        }
+    }
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/RenderState.h b/libs/hwui/RenderState.h
new file mode 100644
index 0000000..f7116e2
--- /dev/null
+++ b/libs/hwui/RenderState.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef RENDERSTATE_H
+#define RENDERSTATE_H
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <private/hwui/DrawGlInfo.h>
+
+#include "Caches.h"
+#include "utils/Macros.h"
+
+namespace android {
+namespace uirenderer {
+
+namespace renderthread {
+class RenderThread;
+}
+
+// TODO: Replace Cache's GL state tracking with this. For now it's more a thin
+// wrapper of Caches for users to migrate to.
+class RenderState {
+    PREVENT_COPY_AND_ASSIGN(RenderState);
+public:
+    void onGLContextCreated();
+
+    void setViewport(GLsizei width, GLsizei height);
+    void getViewport(GLsizei* outWidth, GLsizei* outHeight);
+
+    void bindFramebuffer(GLuint fbo);
+    GLint getFramebuffer() { return mFramebuffer; }
+
+    void invokeFunctor(Functor* functor, DrawGlInfo::Mode mode, DrawGlInfo* info);
+
+    void debugOverdraw(bool enable, bool clear);
+
+private:
+    friend class renderthread::RenderThread;
+
+    void interruptForFunctorInvoke();
+    void resumeFromFunctorInvoke();
+
+    RenderState();
+    ~RenderState();
+
+    Caches* mCaches;
+
+    GLsizei mViewportWidth;
+    GLsizei mViewportHeight;
+    GLuint mFramebuffer;
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* RENDERSTATE_H */
diff --git a/libs/hwui/Renderer.h b/libs/hwui/Renderer.h
index d68b932..2ec99c9 100644
--- a/libs/hwui/Renderer.h
+++ b/libs/hwui/Renderer.h
@@ -129,21 +129,6 @@
      */
     virtual void finish() = 0;
 
-    /**
-     * This method must be invoked before handing control over to a draw functor.
-     * See callDrawGLFunction() for instance.
-     *
-     * This command must not be recorded inside display lists.
-     */
-    virtual void interrupt() = 0;
-
-    /**
-     * This method must be invoked after getting control back from a draw functor.
-     *
-     * This command must not be recorded inside display lists.
-     */
-    virtual void resume() = 0;
-
 // ----------------------------------------------------------------------------
 // Canvas state operations
 // ----------------------------------------------------------------------------
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index f67e434..249e525 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -29,6 +29,7 @@
 class BaseRenderNodeAnimator;
 class AnimationListener;
 class OpenGLRenderer;
+class RenderState;
 
 class AnimationHook {
 public:
@@ -67,14 +68,15 @@
         // TODO: TRIM_MEMORY?
     };
 
-    explicit TreeInfo(TraversalMode mode)
+    explicit TreeInfo(TraversalMode mode, RenderState& renderState)
         : mode(mode)
         , frameTimeMs(0)
         , animationHook(NULL)
         , prepareTextures(mode == MODE_FULL)
         , damageAccumulator(NullDamageAccumulator::instance())
-        , renderer(0)
-        , errorHandler(0)
+        , renderState(renderState)
+        , renderer(NULL)
+        , errorHandler(NULL)
     {}
 
     const TraversalMode mode;
@@ -85,6 +87,7 @@
     bool prepareTextures;
     // Must not be null
     IDamageAccumulator* damageAccumulator;
+    RenderState& renderState;
     // The renderer that will be drawing the next frame. Use this to push any
     // layer updates or similar. May be NULL.
     OpenGLRenderer* renderer;
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index eab9810..fe4edf8 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -18,332 +18,31 @@
 
 #include "CanvasContext.h"
 
-#include <cutils/properties.h>
 #include <private/hwui/DrawGlInfo.h>
 #include <strings.h>
 
+#include "EglManager.h"
 #include "RenderThread.h"
 #include "../Caches.h"
 #include "../DeferredLayerUpdater.h"
+#include "../RenderState.h"
 #include "../LayerRenderer.h"
 #include "../OpenGLRenderer.h"
 #include "../Stencil.h"
 
-#define PROPERTY_RENDER_DIRTY_REGIONS "debug.hwui.render_dirty_regions"
-#define GLES_VERSION 2
-
-// Android-specific addition that is used to show when frames began in systrace
-EGLAPI void EGLAPIENTRY eglBeginFrame(EGLDisplay dpy, EGLSurface surface);
-
 namespace android {
 namespace uirenderer {
 namespace renderthread {
 
-#define ERROR_CASE(x) case x: return #x;
-static const char* egl_error_str(EGLint error) {
-    switch (error) {
-        ERROR_CASE(EGL_SUCCESS)
-        ERROR_CASE(EGL_NOT_INITIALIZED)
-        ERROR_CASE(EGL_BAD_ACCESS)
-        ERROR_CASE(EGL_BAD_ALLOC)
-        ERROR_CASE(EGL_BAD_ATTRIBUTE)
-        ERROR_CASE(EGL_BAD_CONFIG)
-        ERROR_CASE(EGL_BAD_CONTEXT)
-        ERROR_CASE(EGL_BAD_CURRENT_SURFACE)
-        ERROR_CASE(EGL_BAD_DISPLAY)
-        ERROR_CASE(EGL_BAD_MATCH)
-        ERROR_CASE(EGL_BAD_NATIVE_PIXMAP)
-        ERROR_CASE(EGL_BAD_NATIVE_WINDOW)
-        ERROR_CASE(EGL_BAD_PARAMETER)
-        ERROR_CASE(EGL_BAD_SURFACE)
-        ERROR_CASE(EGL_CONTEXT_LOST)
-    default:
-        return "Unknown error";
-    }
-}
-static const char* egl_error_str() {
-    return egl_error_str(eglGetError());
-}
-
-static bool load_dirty_regions_property() {
-    char buf[PROPERTY_VALUE_MAX];
-    int len = property_get(PROPERTY_RENDER_DIRTY_REGIONS, buf, "true");
-    return !strncasecmp("true", buf, len);
-}
-
-// This class contains the shared global EGL objects, such as EGLDisplay
-// and EGLConfig, which are re-used by CanvasContext
-class GlobalContext {
-public:
-    static GlobalContext* get();
-
-    // Returns true on success, false on failure
-    void initialize();
-
-    bool hasContext();
-
-    void usePBufferSurface();
-    EGLSurface createSurface(EGLNativeWindowType window);
-    void destroySurface(EGLSurface surface);
-
-    void destroy();
-
-    bool isCurrent(EGLSurface surface) { return mCurrentSurface == surface; }
-    // Returns true if the current surface changed, false if it was already current
-    bool makeCurrent(EGLSurface surface);
-    void beginFrame(EGLSurface surface, EGLint* width, EGLint* height);
-    void swapBuffers(EGLSurface surface);
-
-    bool enableDirtyRegions(EGLSurface surface);
-
-    void setTextureAtlas(const sp<GraphicBuffer>& buffer, int64_t* map, size_t mapSize);
-
-private:
-    GlobalContext();
-    // GlobalContext is never destroyed, method is purposely not implemented
-    ~GlobalContext();
-
-    void loadConfig();
-    void createContext();
-    void initAtlas();
-
-    static GlobalContext* sContext;
-
-    EGLDisplay mEglDisplay;
-    EGLConfig mEglConfig;
-    EGLContext mEglContext;
-    EGLSurface mPBufferSurface;
-
-    const bool mRequestDirtyRegions;
-    bool mCanSetDirtyRegions;
-
-    EGLSurface mCurrentSurface;
-
-    sp<GraphicBuffer> mAtlasBuffer;
-    int64_t* mAtlasMap;
-    size_t mAtlasMapSize;
-};
-
-GlobalContext* GlobalContext::sContext = 0;
-
-GlobalContext* GlobalContext::get() {
-    if (!sContext) {
-        sContext = new GlobalContext();
-    }
-    return sContext;
-}
-
-GlobalContext::GlobalContext()
-        : mEglDisplay(EGL_NO_DISPLAY)
-        , mEglConfig(0)
-        , mEglContext(EGL_NO_CONTEXT)
-        , mPBufferSurface(EGL_NO_SURFACE)
-        , mRequestDirtyRegions(load_dirty_regions_property())
-        , mCurrentSurface(EGL_NO_SURFACE)
-        , mAtlasMap(NULL)
-        , mAtlasMapSize(0) {
-    mCanSetDirtyRegions = mRequestDirtyRegions;
-    ALOGD("Render dirty regions requested: %s", mRequestDirtyRegions ? "true" : "false");
-}
-
-void GlobalContext::initialize() {
-    if (hasContext()) return;
-
-    mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-    LOG_ALWAYS_FATAL_IF(mEglDisplay == EGL_NO_DISPLAY,
-            "Failed to get EGL_DEFAULT_DISPLAY! err=%s", egl_error_str());
-
-    EGLint major, minor;
-    LOG_ALWAYS_FATAL_IF(eglInitialize(mEglDisplay, &major, &minor) == EGL_FALSE,
-            "Failed to initialize display %p! err=%s", mEglDisplay, egl_error_str());
-
-    ALOGI("Initialized EGL, version %d.%d", (int)major, (int)minor);
-
-    loadConfig();
-    createContext();
-    usePBufferSurface();
-    Caches::getInstance().init();
-    initAtlas();
-}
-
-bool GlobalContext::hasContext() {
-    return mEglDisplay != EGL_NO_DISPLAY;
-}
-
-void GlobalContext::loadConfig() {
-    EGLint swapBehavior = mCanSetDirtyRegions ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
-    EGLint attribs[] = {
-            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
-            EGL_RED_SIZE, 8,
-            EGL_GREEN_SIZE, 8,
-            EGL_BLUE_SIZE, 8,
-            EGL_ALPHA_SIZE, 8,
-            EGL_DEPTH_SIZE, 0,
-            EGL_CONFIG_CAVEAT, EGL_NONE,
-            EGL_STENCIL_SIZE, Stencil::getStencilSize(),
-            EGL_SURFACE_TYPE, EGL_WINDOW_BIT | swapBehavior,
-            EGL_NONE
-    };
-
-    EGLint num_configs = 1;
-    if (!eglChooseConfig(mEglDisplay, attribs, &mEglConfig, num_configs, &num_configs)
-            || num_configs != 1) {
-        // Failed to get a valid config
-        if (mCanSetDirtyRegions) {
-            ALOGW("Failed to choose config with EGL_SWAP_BEHAVIOR_PRESERVED, retrying without...");
-            // Try again without dirty regions enabled
-            mCanSetDirtyRegions = false;
-            loadConfig();
-        } else {
-            LOG_ALWAYS_FATAL("Failed to choose config, error = %s", egl_error_str());
-        }
-    }
-}
-
-void GlobalContext::createContext() {
-    EGLint attribs[] = { EGL_CONTEXT_CLIENT_VERSION, GLES_VERSION, EGL_NONE };
-    mEglContext = eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT, attribs);
-    LOG_ALWAYS_FATAL_IF(mEglContext == EGL_NO_CONTEXT,
-        "Failed to create context, error = %s", egl_error_str());
-}
-
-void GlobalContext::setTextureAtlas(const sp<GraphicBuffer>& buffer,
-        int64_t* map, size_t mapSize) {
-
-    // Already initialized
-    if (mAtlasBuffer.get()) {
-        ALOGW("Multiple calls to setTextureAtlas!");
-        delete map;
-        return;
-    }
-
-    mAtlasBuffer = buffer;
-    mAtlasMap = map;
-    mAtlasMapSize = mapSize;
-
-    if (hasContext()) {
-        usePBufferSurface();
-        initAtlas();
-    }
-}
-
-void GlobalContext::initAtlas() {
-    if (mAtlasBuffer.get()) {
-        Caches::getInstance().assetAtlas.init(mAtlasBuffer, mAtlasMap, mAtlasMapSize);
-    }
-}
-
-void GlobalContext::usePBufferSurface() {
-    LOG_ALWAYS_FATAL_IF(mEglDisplay == EGL_NO_DISPLAY,
-            "usePBufferSurface() called on uninitialized GlobalContext!");
-
-    if (mPBufferSurface == EGL_NO_SURFACE) {
-        EGLint attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE };
-        mPBufferSurface = eglCreatePbufferSurface(mEglDisplay, mEglConfig, attribs);
-    }
-    makeCurrent(mPBufferSurface);
-}
-
-EGLSurface GlobalContext::createSurface(EGLNativeWindowType window) {
-    initialize();
-    return eglCreateWindowSurface(mEglDisplay, mEglConfig, window, NULL);
-}
-
-void GlobalContext::destroySurface(EGLSurface surface) {
-    if (isCurrent(surface)) {
-        makeCurrent(EGL_NO_SURFACE);
-    }
-    if (!eglDestroySurface(mEglDisplay, surface)) {
-        ALOGW("Failed to destroy surface %p, error=%s", (void*)surface, egl_error_str());
-    }
-}
-
-void GlobalContext::destroy() {
-    if (mEglDisplay == EGL_NO_DISPLAY) return;
-
-    usePBufferSurface();
-    if (Caches::hasInstance()) {
-        Caches::getInstance().terminate();
-    }
-
-    eglDestroyContext(mEglDisplay, mEglContext);
-    eglDestroySurface(mEglDisplay, mPBufferSurface);
-    eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-    eglTerminate(mEglDisplay);
-    eglReleaseThread();
-
-    mEglDisplay = EGL_NO_DISPLAY;
-    mEglContext = EGL_NO_CONTEXT;
-    mPBufferSurface = EGL_NO_SURFACE;
-    mCurrentSurface = EGL_NO_SURFACE;
-}
-
-bool GlobalContext::makeCurrent(EGLSurface surface) {
-    if (isCurrent(surface)) return false;
-
-    if (surface == EGL_NO_SURFACE) {
-        // If we are setting EGL_NO_SURFACE we don't care about any of the potential
-        // return errors, which would only happen if mEglDisplay had already been
-        // destroyed in which case the current context is already NO_CONTEXT
-        eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-    } else if (!eglMakeCurrent(mEglDisplay, surface, surface, mEglContext)) {
-        LOG_ALWAYS_FATAL("Failed to make current on surface %p, error=%s",
-                (void*)surface, egl_error_str());
-    }
-    mCurrentSurface = surface;
-    return true;
-}
-
-void GlobalContext::beginFrame(EGLSurface surface, EGLint* width, EGLint* height) {
-    LOG_ALWAYS_FATAL_IF(surface == EGL_NO_SURFACE,
-            "Tried to beginFrame on EGL_NO_SURFACE!");
-    makeCurrent(surface);
-    if (width) {
-        eglQuerySurface(mEglDisplay, surface, EGL_WIDTH, width);
-    }
-    if (height) {
-        eglQuerySurface(mEglDisplay, surface, EGL_HEIGHT, height);
-    }
-    eglBeginFrame(mEglDisplay, surface);
-}
-
-void GlobalContext::swapBuffers(EGLSurface surface) {
-    eglSwapBuffers(mEglDisplay, surface);
-    EGLint err = eglGetError();
-    LOG_ALWAYS_FATAL_IF(err != EGL_SUCCESS,
-            "Encountered EGL error %d %s during rendering", err, egl_error_str(err));
-}
-
-bool GlobalContext::enableDirtyRegions(EGLSurface surface) {
-    if (!mRequestDirtyRegions) return false;
-
-    if (mCanSetDirtyRegions) {
-        if (!eglSurfaceAttrib(mEglDisplay, surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED)) {
-            ALOGW("Failed to set EGL_SWAP_BEHAVIOR on surface %p, error=%s",
-                    (void*) surface, egl_error_str());
-            return false;
-        }
-        return true;
-    }
-    // Perhaps it is already enabled?
-    EGLint value;
-    if (!eglQuerySurface(mEglDisplay, surface, EGL_SWAP_BEHAVIOR, &value)) {
-        ALOGW("Failed to query EGL_SWAP_BEHAVIOR on surface %p, error=%p",
-                (void*) surface, egl_error_str());
-        return false;
-    }
-    return value == EGL_BUFFER_PRESERVED;
-}
-
-CanvasContext::CanvasContext(bool translucent, RenderNode* rootRenderNode)
-        : mRenderThread(RenderThread::getInstance())
+CanvasContext::CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode)
+        : mRenderThread(thread)
+        , mEglManager(thread.eglManager())
         , mEglSurface(EGL_NO_SURFACE)
         , mDirtyRegionsEnabled(false)
         , mOpaque(!translucent)
-        , mCanvas(0)
+        , mCanvas(NULL)
         , mHaveNewSurface(false)
         , mRootRenderNode(rootRenderNode) {
-    mGlobalContext = GlobalContext::get();
 }
 
 CanvasContext::~CanvasContext() {
@@ -363,19 +62,16 @@
     mNativeWindow = window;
 
     if (mEglSurface != EGL_NO_SURFACE) {
-        mGlobalContext->destroySurface(mEglSurface);
+        mEglManager.destroySurface(mEglSurface);
         mEglSurface = EGL_NO_SURFACE;
     }
 
     if (window) {
-        mEglSurface = mGlobalContext->createSurface(window);
-        LOG_ALWAYS_FATAL_IF(mEglSurface == EGL_NO_SURFACE,
-                "Failed to create EGLSurface for window %p, eglErr = %s",
-                (void*) window, egl_error_str());
+        mEglSurface = mEglManager.createSurface(window);
     }
 
     if (mEglSurface != EGL_NO_SURFACE) {
-        mDirtyRegionsEnabled = mGlobalContext->enableDirtyRegions(mEglSurface);
+        mDirtyRegionsEnabled = mEglManager.enableDirtyRegions(mEglSurface);
         mHaveNewSurface = true;
         makeCurrent();
     } else {
@@ -384,7 +80,7 @@
 }
 
 void CanvasContext::swapBuffers() {
-    mGlobalContext->swapBuffers(mEglSurface);
+    mEglManager.swapBuffers(mEglSurface);
     mHaveNewSurface = false;
 }
 
@@ -397,7 +93,7 @@
 bool CanvasContext::initialize(ANativeWindow* window) {
     if (mCanvas) return false;
     setSurface(window);
-    mCanvas = new OpenGLRenderer();
+    mCanvas = new OpenGLRenderer(mRenderThread.renderState());
     mCanvas->initProperties();
     return true;
 }
@@ -424,7 +120,7 @@
 void CanvasContext::makeCurrent() {
     // TODO: Figure out why this workaround is needed, see b/13913604
     // In the meantime this matches the behavior of GLRenderer, so it is not a regression
-    mHaveNewSurface |= mGlobalContext->makeCurrent(mEglSurface);
+    mHaveNewSurface |= mEglManager.makeCurrent(mEglSurface);
 }
 
 void CanvasContext::processLayerUpdate(DeferredLayerUpdater* layerUpdater, TreeInfo& info) {
@@ -477,7 +173,7 @@
     mDamageAccumulator.finish(&dirty);
 
     EGLint width, height;
-    mGlobalContext->beginFrame(mEglSurface, &width, &height);
+    mEglManager.beginFrame(mEglSurface, &width, &height);
     if (width != mCanvas->getViewportWidth() || height != mCanvas->getViewportHeight()) {
         mCanvas->setViewport(width, height);
         dirty.setEmpty();
@@ -521,7 +217,7 @@
 
     profiler().startFrame();
 
-    TreeInfo info(TreeInfo::MODE_RT_ONLY);
+    TreeInfo info(TreeInfo::MODE_RT_ONLY, mRenderThread.renderState());
     info.prepareTextures = false;
 
     prepareTree(info);
@@ -530,32 +226,26 @@
     }
 }
 
-void CanvasContext::invokeFunctor(Functor* functor) {
+void CanvasContext::invokeFunctor(RenderThread& thread, Functor* functor) {
     ATRACE_CALL();
     DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext;
-    if (mGlobalContext->hasContext()) {
-        requireGlContext();
+    if (thread.eglManager().hasEglContext()) {
+        thread.eglManager().requireGlContext();
         mode = DrawGlInfo::kModeProcess;
     }
 
-    if (mCanvas) {
-        mCanvas->interrupt();
-    }
-    (*functor)(mode, NULL);
-    if (mCanvas) {
-        mCanvas->resume();
-    }
+    thread.renderState().invokeFunctor(functor, mode, NULL);
 }
 
 bool CanvasContext::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
     requireGlContext();
-    TreeInfo info(TreeInfo::MODE_FULL);
+    TreeInfo info(TreeInfo::MODE_FULL, mRenderThread.renderState());
     layer->apply(info);
-    return LayerRenderer::copyLayer(layer->backingLayer(), bitmap);
+    return LayerRenderer::copyLayer(mRenderThread.renderState(), layer->backingLayer(), bitmap);
 }
 
 void CanvasContext::flushCaches(Caches::FlushMode flushMode) {
-    if (mGlobalContext->hasContext()) {
+    if (mEglManager.hasEglContext()) {
         requireGlContext();
         Caches::getInstance().flush(flushMode);
     }
@@ -568,25 +258,25 @@
 
 Layer* CanvasContext::createRenderLayer(int width, int height) {
     requireSurface();
-    return LayerRenderer::createRenderLayer(width, height);
+    return LayerRenderer::createRenderLayer(mRenderThread.renderState(), width, height);
 }
 
 Layer* CanvasContext::createTextureLayer() {
     requireSurface();
-    return LayerRenderer::createTextureLayer();
+    return LayerRenderer::createTextureLayer(mRenderThread.renderState());
 }
 
 void CanvasContext::requireGlContext() {
     if (mEglSurface != EGL_NO_SURFACE) {
         makeCurrent();
     } else {
-        mGlobalContext->usePBufferSurface();
+        mEglManager.usePBufferSurface();
     }
 }
 
-void CanvasContext::setTextureAtlas(const sp<GraphicBuffer>& buffer,
-        int64_t* map, size_t mapSize) {
-    GlobalContext::get()->setTextureAtlas(buffer, map, mapSize);
+void CanvasContext::setTextureAtlas(RenderThread& thread,
+        const sp<GraphicBuffer>& buffer, int64_t* map, size_t mapSize) {
+    thread.eglManager().setTextureAtlas(buffer, map, mapSize);
 }
 
 } /* namespace renderthread */
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index d926b38..d2ce1a6 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -41,13 +41,13 @@
 
 namespace renderthread {
 
-class GlobalContext;
+class EglManager;
 
 // This per-renderer class manages the bridge between the global EGL context
 // and the render surface.
 class CanvasContext : public IFrameCallback {
 public:
-    CanvasContext(bool translucent, RenderNode* rootRenderNode);
+    CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode);
     virtual ~CanvasContext();
 
     bool initialize(ANativeWindow* window);
@@ -68,15 +68,15 @@
 
     void flushCaches(Caches::FlushMode flushMode);
 
-    void invokeFunctor(Functor* functor);
+    static void invokeFunctor(RenderThread& thread, Functor* functor);
 
     void runWithGlContext(RenderTask* task);
 
     Layer* createRenderLayer(int width, int height);
     Layer* createTextureLayer();
 
-    ANDROID_API static void setTextureAtlas(const sp<GraphicBuffer>& buffer,
-            int64_t* map, size_t mapSize);
+    ANDROID_API static void setTextureAtlas(RenderThread& thread,
+            const sp<GraphicBuffer>& buffer, int64_t* map, size_t mapSize);
 
     void notifyFramePending();
 
@@ -91,8 +91,8 @@
 
     void requireGlContext();
 
-    GlobalContext* mGlobalContext;
     RenderThread& mRenderThread;
+    EglManager& mEglManager;
     sp<ANativeWindow> mNativeWindow;
     EGLSurface mEglSurface;
     bool mDirtyRegionsEnabled;
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 797566f..7d75e0f 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -98,7 +98,7 @@
     bool canUnblockUiThread;
     bool canDrawThisFrame;
     {
-        TreeInfo info(TreeInfo::MODE_FULL);
+        TreeInfo info(TreeInfo::MODE_FULL, mRenderThread->renderState());
         canUnblockUiThread = syncFrameState(info);
         canDrawThisFrame = info.out.canDrawThisFrame;
     }
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
new file mode 100644
index 0000000..05ca34d
--- /dev/null
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "EglContext"
+
+#include "EglManager.h"
+
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+#include "../RenderState.h"
+#include "RenderThread.h"
+
+#define PROPERTY_RENDER_DIRTY_REGIONS "debug.hwui.render_dirty_regions"
+#define GLES_VERSION 2
+
+// Android-specific addition that is used to show when frames began in systrace
+EGLAPI void EGLAPIENTRY eglBeginFrame(EGLDisplay dpy, EGLSurface surface);
+
+namespace android {
+namespace uirenderer {
+namespace renderthread {
+
+#define ERROR_CASE(x) case x: return #x;
+static const char* egl_error_str(EGLint error) {
+    switch (error) {
+        ERROR_CASE(EGL_SUCCESS)
+        ERROR_CASE(EGL_NOT_INITIALIZED)
+        ERROR_CASE(EGL_BAD_ACCESS)
+        ERROR_CASE(EGL_BAD_ALLOC)
+        ERROR_CASE(EGL_BAD_ATTRIBUTE)
+        ERROR_CASE(EGL_BAD_CONFIG)
+        ERROR_CASE(EGL_BAD_CONTEXT)
+        ERROR_CASE(EGL_BAD_CURRENT_SURFACE)
+        ERROR_CASE(EGL_BAD_DISPLAY)
+        ERROR_CASE(EGL_BAD_MATCH)
+        ERROR_CASE(EGL_BAD_NATIVE_PIXMAP)
+        ERROR_CASE(EGL_BAD_NATIVE_WINDOW)
+        ERROR_CASE(EGL_BAD_PARAMETER)
+        ERROR_CASE(EGL_BAD_SURFACE)
+        ERROR_CASE(EGL_CONTEXT_LOST)
+    default:
+        return "Unknown error";
+    }
+}
+static const char* egl_error_str() {
+    return egl_error_str(eglGetError());
+}
+
+static bool load_dirty_regions_property() {
+    char buf[PROPERTY_VALUE_MAX];
+    int len = property_get(PROPERTY_RENDER_DIRTY_REGIONS, buf, "true");
+    return !strncasecmp("true", buf, len);
+}
+
+EglManager::EglManager(RenderThread& thread)
+        : mRenderThread(thread)
+        , mEglDisplay(EGL_NO_DISPLAY)
+        , mEglConfig(0)
+        , mEglContext(EGL_NO_CONTEXT)
+        , mPBufferSurface(EGL_NO_SURFACE)
+        , mRequestDirtyRegions(load_dirty_regions_property())
+        , mCurrentSurface(EGL_NO_SURFACE)
+        , mAtlasMap(NULL)
+        , mAtlasMapSize(0) {
+    mCanSetDirtyRegions = mRequestDirtyRegions;
+    ALOGD("Render dirty regions requested: %s", mRequestDirtyRegions ? "true" : "false");
+}
+
+void EglManager::initialize() {
+    if (hasEglContext()) return;
+
+    mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    LOG_ALWAYS_FATAL_IF(mEglDisplay == EGL_NO_DISPLAY,
+            "Failed to get EGL_DEFAULT_DISPLAY! err=%s", egl_error_str());
+
+    EGLint major, minor;
+    LOG_ALWAYS_FATAL_IF(eglInitialize(mEglDisplay, &major, &minor) == EGL_FALSE,
+            "Failed to initialize display %p! err=%s", mEglDisplay, egl_error_str());
+
+    ALOGI("Initialized EGL, version %d.%d", (int)major, (int)minor);
+
+    loadConfig();
+    createContext();
+    usePBufferSurface();
+    mRenderThread.renderState().onGLContextCreated();
+    initAtlas();
+}
+
+bool EglManager::hasEglContext() {
+    return mEglDisplay != EGL_NO_DISPLAY;
+}
+
+void EglManager::requireGlContext() {
+    LOG_ALWAYS_FATAL_IF(mEglDisplay == EGL_NO_DISPLAY, "No EGL context");
+
+    // We don't care *WHAT* surface is active, just that one is active to give
+    // us access to the GL context
+    if (mCurrentSurface == EGL_NO_SURFACE) {
+        usePBufferSurface();
+    }
+}
+
+void EglManager::loadConfig() {
+    EGLint swapBehavior = mCanSetDirtyRegions ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
+    EGLint attribs[] = {
+            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+            EGL_RED_SIZE, 8,
+            EGL_GREEN_SIZE, 8,
+            EGL_BLUE_SIZE, 8,
+            EGL_ALPHA_SIZE, 8,
+            EGL_DEPTH_SIZE, 0,
+            EGL_CONFIG_CAVEAT, EGL_NONE,
+            EGL_STENCIL_SIZE, Stencil::getStencilSize(),
+            EGL_SURFACE_TYPE, EGL_WINDOW_BIT | swapBehavior,
+            EGL_NONE
+    };
+
+    EGLint num_configs = 1;
+    if (!eglChooseConfig(mEglDisplay, attribs, &mEglConfig, num_configs, &num_configs)
+            || num_configs != 1) {
+        // Failed to get a valid config
+        if (mCanSetDirtyRegions) {
+            ALOGW("Failed to choose config with EGL_SWAP_BEHAVIOR_PRESERVED, retrying without...");
+            // Try again without dirty regions enabled
+            mCanSetDirtyRegions = false;
+            loadConfig();
+        } else {
+            LOG_ALWAYS_FATAL("Failed to choose config, error = %s", egl_error_str());
+        }
+    }
+}
+
+void EglManager::createContext() {
+    EGLint attribs[] = { EGL_CONTEXT_CLIENT_VERSION, GLES_VERSION, EGL_NONE };
+    mEglContext = eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT, attribs);
+    LOG_ALWAYS_FATAL_IF(mEglContext == EGL_NO_CONTEXT,
+        "Failed to create context, error = %s", egl_error_str());
+}
+
+void EglManager::setTextureAtlas(const sp<GraphicBuffer>& buffer,
+        int64_t* map, size_t mapSize) {
+
+    // Already initialized
+    if (mAtlasBuffer.get()) {
+        ALOGW("Multiple calls to setTextureAtlas!");
+        delete map;
+        return;
+    }
+
+    mAtlasBuffer = buffer;
+    mAtlasMap = map;
+    mAtlasMapSize = mapSize;
+
+    if (hasEglContext()) {
+        usePBufferSurface();
+        initAtlas();
+    }
+}
+
+void EglManager::initAtlas() {
+    if (mAtlasBuffer.get()) {
+        Caches::getInstance().assetAtlas.init(mAtlasBuffer, mAtlasMap, mAtlasMapSize);
+    }
+}
+
+void EglManager::usePBufferSurface() {
+    LOG_ALWAYS_FATAL_IF(mEglDisplay == EGL_NO_DISPLAY,
+            "usePBufferSurface() called on uninitialized GlobalContext!");
+
+    if (mPBufferSurface == EGL_NO_SURFACE) {
+        EGLint attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE };
+        mPBufferSurface = eglCreatePbufferSurface(mEglDisplay, mEglConfig, attribs);
+    }
+    makeCurrent(mPBufferSurface);
+}
+
+EGLSurface EglManager::createSurface(EGLNativeWindowType window) {
+    initialize();
+    EGLSurface surface = eglCreateWindowSurface(mEglDisplay, mEglConfig, window, NULL);
+    LOG_ALWAYS_FATAL_IF(surface == EGL_NO_SURFACE,
+            "Failed to create EGLSurface for window %p, eglErr = %s",
+            (void*) window, egl_error_str());
+    return surface;
+}
+
+void EglManager::destroySurface(EGLSurface surface) {
+    if (isCurrent(surface)) {
+        makeCurrent(EGL_NO_SURFACE);
+    }
+    if (!eglDestroySurface(mEglDisplay, surface)) {
+        ALOGW("Failed to destroy surface %p, error=%s", (void*)surface, egl_error_str());
+    }
+}
+
+void EglManager::destroy() {
+    if (mEglDisplay == EGL_NO_DISPLAY) return;
+
+    usePBufferSurface();
+    if (Caches::hasInstance()) {
+        Caches::getInstance().terminate();
+    }
+
+    eglDestroyContext(mEglDisplay, mEglContext);
+    eglDestroySurface(mEglDisplay, mPBufferSurface);
+    eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+    eglTerminate(mEglDisplay);
+    eglReleaseThread();
+
+    mEglDisplay = EGL_NO_DISPLAY;
+    mEglContext = EGL_NO_CONTEXT;
+    mPBufferSurface = EGL_NO_SURFACE;
+    mCurrentSurface = EGL_NO_SURFACE;
+}
+
+bool EglManager::makeCurrent(EGLSurface surface) {
+    if (isCurrent(surface)) return false;
+
+    if (surface == EGL_NO_SURFACE) {
+        // If we are setting EGL_NO_SURFACE we don't care about any of the potential
+        // return errors, which would only happen if mEglDisplay had already been
+        // destroyed in which case the current context is already NO_CONTEXT
+        eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+    } else if (!eglMakeCurrent(mEglDisplay, surface, surface, mEglContext)) {
+        LOG_ALWAYS_FATAL("Failed to make current on surface %p, error=%s",
+                (void*)surface, egl_error_str());
+    }
+    mCurrentSurface = surface;
+    return true;
+}
+
+void EglManager::beginFrame(EGLSurface surface, EGLint* width, EGLint* height) {
+    LOG_ALWAYS_FATAL_IF(surface == EGL_NO_SURFACE,
+            "Tried to beginFrame on EGL_NO_SURFACE!");
+    makeCurrent(surface);
+    if (width) {
+        eglQuerySurface(mEglDisplay, surface, EGL_WIDTH, width);
+    }
+    if (height) {
+        eglQuerySurface(mEglDisplay, surface, EGL_HEIGHT, height);
+    }
+    eglBeginFrame(mEglDisplay, surface);
+}
+
+void EglManager::swapBuffers(EGLSurface surface) {
+    eglSwapBuffers(mEglDisplay, surface);
+    EGLint err = eglGetError();
+    LOG_ALWAYS_FATAL_IF(err != EGL_SUCCESS,
+            "Encountered EGL error %d %s during rendering", err, egl_error_str(err));
+}
+
+bool EglManager::enableDirtyRegions(EGLSurface surface) {
+    if (!mRequestDirtyRegions) return false;
+
+    if (mCanSetDirtyRegions) {
+        if (!eglSurfaceAttrib(mEglDisplay, surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED)) {
+            ALOGW("Failed to set EGL_SWAP_BEHAVIOR on surface %p, error=%s",
+                    (void*) surface, egl_error_str());
+            return false;
+        }
+        return true;
+    }
+    // Perhaps it is already enabled?
+    EGLint value;
+    if (!eglQuerySurface(mEglDisplay, surface, EGL_SWAP_BEHAVIOR, &value)) {
+        ALOGW("Failed to query EGL_SWAP_BEHAVIOR on surface %p, error=%p",
+                (void*) surface, egl_error_str());
+        return false;
+    }
+    return value == EGL_BUFFER_PRESERVED;
+}
+
+} /* namespace renderthread */
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h
new file mode 100644
index 0000000..a844cfc
--- /dev/null
+++ b/libs/hwui/renderthread/EglManager.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef EGLMANAGER_H
+#define EGLMANAGER_H
+
+#include <cutils/compiler.h>
+#include <EGL/egl.h>
+#include <ui/GraphicBuffer.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+namespace uirenderer {
+namespace renderthread {
+
+class RenderThread;
+
+// This class contains the shared global EGL objects, such as EGLDisplay
+// and EGLConfig, which are re-used by CanvasContext
+class EglManager {
+public:
+    // Returns true on success, false on failure
+    void initialize();
+
+    bool hasEglContext();
+    void requireGlContext();
+
+    void usePBufferSurface();
+    EGLSurface createSurface(EGLNativeWindowType window);
+    void destroySurface(EGLSurface surface);
+
+    void destroy();
+
+    bool isCurrent(EGLSurface surface) { return mCurrentSurface == surface; }
+    // Returns true if the current surface changed, false if it was already current
+    bool makeCurrent(EGLSurface surface);
+    void beginFrame(EGLSurface surface, EGLint* width, EGLint* height);
+    void swapBuffers(EGLSurface surface);
+
+    bool enableDirtyRegions(EGLSurface surface);
+
+    void setTextureAtlas(const sp<GraphicBuffer>& buffer, int64_t* map, size_t mapSize);
+
+private:
+    friend class RenderThread;
+
+    EglManager(RenderThread& thread);
+    // EglContext is never destroyed, method is purposely not implemented
+    ~EglManager();
+
+    void loadConfig();
+    void createContext();
+    void initAtlas();
+
+    RenderThread& mRenderThread;
+
+    EGLDisplay mEglDisplay;
+    EGLConfig mEglConfig;
+    EGLContext mEglContext;
+    EGLSurface mPBufferSurface;
+
+    const bool mRequestDirtyRegions;
+    bool mCanSetDirtyRegions;
+
+    EGLSurface mCurrentSurface;
+
+    sp<GraphicBuffer> mAtlasBuffer;
+    int64_t* mAtlasMap;
+    size_t mAtlasMapSize;
+};
+
+} /* namespace renderthread */
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* EGLMANAGER_H */
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 4988f19..f90a26a 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -52,8 +52,8 @@
     MethodInvokeRenderTask* task = new MethodInvokeRenderTask((RunnableMethod) Bridge_ ## method); \
     ARGS(method) *args = (ARGS(method) *) task->payload()
 
-CREATE_BRIDGE2(createContext, bool translucent, RenderNode* rootRenderNode) {
-    return new CanvasContext(args->translucent, args->rootRenderNode);
+CREATE_BRIDGE3(createContext, RenderThread* thread, bool translucent, RenderNode* rootRenderNode) {
+    return new CanvasContext(*args->thread, args->translucent, args->rootRenderNode);
 }
 
 RenderProxy::RenderProxy(bool translucent, RenderNode* rootRenderNode)
@@ -62,6 +62,7 @@
     SETUP_TASK(createContext);
     args->translucent = translucent;
     args->rootRenderNode = rootRenderNode;
+    args->thread = &mRenderThread;
     mContext = (CanvasContext*) postAndWait(task);
     mDrawFrameTask.setContext(&mRenderThread, mContext);
 }
@@ -199,20 +200,29 @@
     postAndWait(task);
 }
 
-CREATE_BRIDGE2(invokeFunctor, CanvasContext* context, Functor* functor) {
-    args->context->invokeFunctor(args->functor);
+CREATE_BRIDGE2(invokeFunctor, RenderThread* thread, Functor* functor) {
+    CanvasContext::invokeFunctor(*args->thread, args->functor);
     return NULL;
 }
 
 void RenderProxy::invokeFunctor(Functor* functor, bool waitForCompletion) {
     ATRACE_CALL();
+    RenderThread& thread = RenderThread::getInstance();
     SETUP_TASK(invokeFunctor);
-    args->context = mContext;
+    args->thread = &thread;
     args->functor = functor;
     if (waitForCompletion) {
-        postAndWait(task);
+        // waitForCompletion = true is expected to be fairly rare and only
+        // happen in destruction. Thus it should be fine to temporarily
+        // create a Mutex
+        Mutex mutex;
+        Condition condition;
+        SignalingRenderTask syncTask(task, &mutex, &condition);
+        AutoMutex _lock(mutex);
+        thread.queue(&syncTask);
+        condition.wait(mutex);
     } else {
-        post(task);
+        thread.queue(task);
     }
 }
 
@@ -233,7 +243,7 @@
     return NULL;
 }
 
-static void enqueueDestroyLayer(Layer* layer) {
+void RenderProxy::enqueueDestroyLayer(Layer* layer) {
     SETUP_TASK(destroyLayer);
     args->layer = layer;
     RenderThread::getInstance().queue(task);
@@ -242,7 +252,7 @@
 CREATE_BRIDGE3(createDisplayListLayer, CanvasContext* context, int width, int height) {
     Layer* layer = args->context->createRenderLayer(args->width, args->height);
     if (!layer) return 0;
-    return new DeferredLayerUpdater(layer, enqueueDestroyLayer);
+    return new DeferredLayerUpdater(layer, RenderProxy::enqueueDestroyLayer);
 }
 
 DeferredLayerUpdater* RenderProxy::createDisplayListLayer(int width, int height) {
@@ -258,7 +268,7 @@
 CREATE_BRIDGE1(createTextureLayer, CanvasContext* context) {
     Layer* layer = args->context->createTextureLayer();
     if (!layer) return 0;
-    return new DeferredLayerUpdater(layer, enqueueDestroyLayer);
+    return new DeferredLayerUpdater(layer, RenderProxy::enqueueDestroyLayer);
 }
 
 DeferredLayerUpdater* RenderProxy::createTextureLayer() {
@@ -336,6 +346,22 @@
     postAndWait(task);
 }
 
+CREATE_BRIDGE4(setTextureAtlas, RenderThread* thread, GraphicBuffer* buffer, int64_t* map, size_t size) {
+    CanvasContext::setTextureAtlas(*args->thread, args->buffer, args->map, args->size);
+    args->buffer->decStrong(0);
+    return NULL;
+}
+
+void RenderProxy::setTextureAtlas(const sp<GraphicBuffer>& buffer, int64_t* map, size_t size) {
+    SETUP_TASK(setTextureAtlas);
+    args->thread = &mRenderThread;
+    args->buffer = buffer.get();
+    args->buffer->incStrong(0);
+    args->map = map;
+    args->size = size;
+    post(task);
+}
+
 void RenderProxy::post(RenderTask* task) {
     mRenderThread.queue(task);
 }
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index a95f8f0..df0aff0 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -73,10 +73,11 @@
             float density);
     ANDROID_API void destroyCanvasAndSurface();
 
-    ANDROID_API void invokeFunctor(Functor* functor, bool waitForCompletion);
+    ANDROID_API static void invokeFunctor(Functor* functor, bool waitForCompletion);
 
     ANDROID_API void runWithGlContext(RenderTask* task);
 
+    static void enqueueDestroyLayer(Layer* layer);
     ANDROID_API DeferredLayerUpdater* createDisplayListLayer(int width, int height);
     ANDROID_API DeferredLayerUpdater* createTextureLayer();
     ANDROID_API bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap);
@@ -90,6 +91,8 @@
 
     ANDROID_API void dumpProfileInfo(int fd);
 
+    ANDROID_API void setTextureAtlas(const sp<GraphicBuffer>& buffer, int64_t* map, size_t size);
+
 private:
     RenderThread& mRenderThread;
     CanvasContext* mContext;
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 4a4e254..03e98d5 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -21,7 +21,9 @@
 #include <gui/DisplayEventReceiver.h>
 #include <utils/Log.h>
 
+#include "../RenderState.h"
 #include "CanvasContext.h"
+#include "EglManager.h"
 #include "RenderProxy.h"
 
 namespace android {
@@ -138,13 +140,16 @@
         , mDisplayEventReceiver(0)
         , mVsyncRequested(false)
         , mFrameCallbackTaskPending(false)
-        , mFrameCallbackTask(0) {
+        , mFrameCallbackTask(0)
+        , mRenderState(NULL)
+        , mEglManager(NULL) {
     mFrameCallbackTask = new DispatchFrameCallbacks(this);
     mLooper = new Looper(false);
     run("RenderThread");
 }
 
 RenderThread::~RenderThread() {
+    LOG_ALWAYS_FATAL("Can't destroy the render thread");
 }
 
 void RenderThread::initializeDisplayEventReceiver() {
@@ -159,6 +164,12 @@
             Looper::EVENT_INPUT, RenderThread::displayEventReceiverCallback, this);
 }
 
+void RenderThread::initThreadLocals() {
+    initializeDisplayEventReceiver();
+    mEglManager = new EglManager(*this);
+    mRenderState = new RenderState();
+}
+
 int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) {
     if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
         ALOGE("Display event receiver pipe was closed or an error occurred.  "
@@ -233,7 +244,7 @@
 }
 
 bool RenderThread::threadLoop() {
-    initializeDisplayEventReceiver();
+    initThreadLocals();
 
     int timeoutMillis = -1;
     for (;;) {
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 4412584..0b91e9d 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -31,12 +31,18 @@
 #include "TimeLord.h"
 
 namespace android {
+
 class DisplayEventReceiver;
 
 namespace uirenderer {
+
+class RenderState;
+
 namespace renderthread {
 
 class DispatchFrameCallbacks;
+class EglManager;
+class RenderProxy;
 
 class TaskQueue {
 public:
@@ -62,7 +68,7 @@
     ~IFrameCallback() {}
 };
 
-class ANDROID_API RenderThread : public Thread, public Singleton<RenderThread> {
+class ANDROID_API RenderThread : public Thread, protected Singleton<RenderThread> {
 public:
     // RenderThread takes complete ownership of tasks that are queued
     // and will delete them after they are run
@@ -79,6 +85,8 @@
     void pushBackFrameCallback(IFrameCallback* callback);
 
     TimeLord& timeLord() { return mTimeLord; }
+    RenderState& renderState() { return *mRenderState; }
+    EglManager& eglManager() { return *mEglManager; }
 
 protected:
     virtual bool threadLoop();
@@ -86,10 +94,12 @@
 private:
     friend class Singleton<RenderThread>;
     friend class DispatchFrameCallbacks;
+    friend class RenderProxy;
 
     RenderThread();
     virtual ~RenderThread();
 
+    void initThreadLocals();
     void initializeDisplayEventReceiver();
     static int displayEventReceiverCallback(int fd, int events, void* data);
     void drainDisplayEventQueue(bool skipCallbacks = false);
@@ -119,6 +129,8 @@
     DispatchFrameCallbacks* mFrameCallbackTask;
 
     TimeLord mTimeLord;
+    RenderState* mRenderState;
+    EglManager* mEglManager;
 };
 
 } /* namespace renderthread */