Merge "Add some free zoom to lockHardwareCanvas" into lmp-mr1-dev
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index b3d9890..a0b2ca8 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -374,6 +374,7 @@
     ContextFactory factory;
     RenderProxy* proxy = new RenderProxy(false, rootNode, &factory);
     proxy->loadSystemProperties();
+    proxy->setSwapBehavior(kSwap_discardBuffer);
     proxy->initialize(surface);
     // Shadows can't be used via this interface, so just set the light source
     // to all 0s. (and width & height are unused, TODO remove them)
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 3bb4778..9d2ae8b 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -42,7 +42,8 @@
         : mRenderThread(thread)
         , mEglManager(thread.eglManager())
         , mEglSurface(EGL_NO_SURFACE)
-        , mDirtyRegionsEnabled(false)
+        , mBufferPreserved(false)
+        , mSwapBehavior(kSwap_default)
         , mOpaque(!translucent)
         , mCanvas(NULL)
         , mHaveNewSurface(false)
@@ -82,7 +83,8 @@
     }
 
     if (mEglSurface != EGL_NO_SURFACE) {
-        mDirtyRegionsEnabled = mEglManager.enableDirtyRegions(mEglSurface);
+        const bool preserveBuffer = (mSwapBehavior != kSwap_discardBuffer);
+        mBufferPreserved = mEglManager.setPreserveBuffer(mEglSurface, preserveBuffer);
         mHaveNewSurface = true;
         makeCurrent();
     } else {
@@ -103,6 +105,10 @@
     makeCurrent();
 }
 
+void CanvasContext::setSwapBehavior(SwapBehavior swapBehavior) {
+    mSwapBehavior = swapBehavior;
+}
+
 bool CanvasContext::initialize(ANativeWindow* window) {
     setSurface(window);
     if (mCanvas) return false;
@@ -200,7 +206,7 @@
     if (width != mCanvas->getViewportWidth() || height != mCanvas->getViewportHeight()) {
         mCanvas->setViewport(width, height);
         dirty.setEmpty();
-    } else if (!mDirtyRegionsEnabled || mHaveNewSurface) {
+    } else if (!mBufferPreserved || mHaveNewSurface) {
         dirty.setEmpty();
     } else {
         if (!dirty.isEmpty() && !dirty.intersect(0, 0, width, height)) {
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index d4282fa..e20564b 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -48,6 +48,11 @@
 
 class EglManager;
 
+enum SwapBehavior {
+    kSwap_default,
+    kSwap_discardBuffer,
+};
+
 // This per-renderer class manages the bridge between the global EGL context
 // and the render surface.
 // TODO: Rename to Renderer or some other per-window, top-level manager
@@ -57,6 +62,9 @@
             IContextFactory* contextFactory);
     virtual ~CanvasContext();
 
+    // Won't take effect until next EGLSurface creation
+    void setSwapBehavior(SwapBehavior swapBehavior);
+
     bool initialize(ANativeWindow* window);
     void updateSurface(ANativeWindow* window);
     void pauseSurface(ANativeWindow* window);
@@ -111,7 +119,8 @@
     EglManager& mEglManager;
     sp<ANativeWindow> mNativeWindow;
     EGLSurface mEglSurface;
-    bool mDirtyRegionsEnabled;
+    bool mBufferPreserved;
+    SwapBehavior mSwapBehavior;
 
     bool mOpaque;
     OpenGLRenderer* mCanvas;
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index a87834e..760fc15 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -70,12 +70,12 @@
         , mEglConfig(0)
         , mEglContext(EGL_NO_CONTEXT)
         , mPBufferSurface(EGL_NO_SURFACE)
-        , mRequestDirtyRegions(load_dirty_regions_property())
+        , mAllowPreserveBuffer(load_dirty_regions_property())
         , mCurrentSurface(EGL_NO_SURFACE)
         , mAtlasMap(NULL)
         , mAtlasMapSize(0) {
-    mCanSetDirtyRegions = mRequestDirtyRegions;
-    ALOGD("Render dirty regions requested: %s", mRequestDirtyRegions ? "true" : "false");
+    mCanSetPreserveBuffer = mAllowPreserveBuffer;
+    ALOGD("Use EGL_SWAP_BEHAVIOR_PRESERVED: %s", mAllowPreserveBuffer ? "true" : "false");
 }
 
 void EglManager::initialize() {
@@ -113,7 +113,7 @@
 }
 
 void EglManager::loadConfig() {
-    EGLint swapBehavior = mCanSetDirtyRegions ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
+    EGLint swapBehavior = mCanSetPreserveBuffer ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
     EGLint attribs[] = {
             EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
             EGL_RED_SIZE, 8,
@@ -131,10 +131,10 @@
     if (!eglChooseConfig(mEglDisplay, attribs, &mEglConfig, num_configs, &num_configs)
             || num_configs != 1) {
         // Failed to get a valid config
-        if (mCanSetDirtyRegions) {
+        if (mCanSetPreserveBuffer) {
             ALOGW("Failed to choose config with EGL_SWAP_BEHAVIOR_PRESERVED, retrying without...");
             // Try again without dirty regions enabled
-            mCanSetDirtyRegions = false;
+            mCanSetPreserveBuffer = false;
             loadConfig();
         } else {
             LOG_ALWAYS_FATAL("Failed to choose config, error = %s", egl_error_str());
@@ -273,25 +273,30 @@
     return false;
 }
 
-bool EglManager::enableDirtyRegions(EGLSurface surface) {
-    if (!mRequestDirtyRegions) return false;
+bool EglManager::setPreserveBuffer(EGLSurface surface, bool preserve) {
+    if (CC_UNLIKELY(!mAllowPreserveBuffer)) return false;
 
-    if (mCanSetDirtyRegions) {
-        if (!eglSurfaceAttrib(mEglDisplay, surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED)) {
+    bool preserved = false;
+    if (mCanSetPreserveBuffer) {
+        preserved = eglSurfaceAttrib(mEglDisplay, surface, EGL_SWAP_BEHAVIOR,
+                preserve ? EGL_BUFFER_PRESERVED : EGL_BUFFER_DESTROYED);
+        if (CC_UNLIKELY(!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;
+    if (CC_UNLIKELY(!preserved)) {
+        // Maybe it's already set?
+        EGLint swapBehavior;
+        if (eglQuerySurface(mEglDisplay, surface, EGL_SWAP_BEHAVIOR, &swapBehavior)) {
+            preserved = (swapBehavior == EGL_BUFFER_PRESERVED);
+        } else {
+            ALOGW("Failed to query EGL_SWAP_BEHAVIOR on surface %p, error=%p",
+                                (void*) surface, egl_error_str());
+        }
     }
-    return value == EGL_BUFFER_PRESERVED;
+
+    return preserved;
 }
 
 } /* namespace renderthread */
diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h
index 71213fb..ae03ea1 100644
--- a/libs/hwui/renderthread/EglManager.h
+++ b/libs/hwui/renderthread/EglManager.h
@@ -49,7 +49,8 @@
     void beginFrame(EGLSurface surface, EGLint* width, EGLint* height);
     bool swapBuffers(EGLSurface surface);
 
-    bool enableDirtyRegions(EGLSurface surface);
+    // Returns true iff the surface is now preserving buffers.
+    bool setPreserveBuffer(EGLSurface surface, bool preserve);
 
     void setTextureAtlas(const sp<GraphicBuffer>& buffer, int64_t* map, size_t mapSize);
 
@@ -71,8 +72,8 @@
     EGLContext mEglContext;
     EGLSurface mPBufferSurface;
 
-    const bool mRequestDirtyRegions;
-    bool mCanSetDirtyRegions;
+    const bool mAllowPreserveBuffer;
+    bool mCanSetPreserveBuffer;
 
     EGLSurface mCurrentSurface;
 
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 047819d..8f99b4e 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -103,6 +103,18 @@
     post(task);
 }
 
+CREATE_BRIDGE2(setSwapBehavior, CanvasContext* context, SwapBehavior swapBehavior) {
+    args->context->setSwapBehavior(args->swapBehavior);
+    return NULL;
+}
+
+void RenderProxy::setSwapBehavior(SwapBehavior swapBehavior) {
+    SETUP_TASK(setSwapBehavior);
+    args->context = mContext;
+    args->swapBehavior = swapBehavior;
+    post(task);
+}
+
 CREATE_BRIDGE1(loadSystemProperties, CanvasContext* context) {
     bool needsRedraw = false;
     if (Caches::hasInstance()) {
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 678e7e2..dddf0c7 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -31,6 +31,7 @@
 
 #include "../Caches.h"
 #include "../IContextFactory.h"
+#include "CanvasContext.h"
 #include "DrawFrameTask.h"
 
 namespace android {
@@ -44,7 +45,6 @@
 
 namespace renderthread {
 
-class CanvasContext;
 class ErrorChannel;
 class RenderThread;
 class RenderProxyBridge;
@@ -63,6 +63,8 @@
     ANDROID_API virtual ~RenderProxy();
 
     ANDROID_API void setFrameInterval(nsecs_t frameIntervalNanos);
+    // Won't take effect until next EGLSurface creation
+    ANDROID_API void setSwapBehavior(SwapBehavior swapBehavior);
     ANDROID_API bool loadSystemProperties();
 
     ANDROID_API bool initialize(const sp<ANativeWindow>& window);