Restore buildLayer()'s old behavior; it's synchronous again
Bug #9193833

Change-Id: I4ee07e65c0a8967f0b55da030ecaad6dfc46136f
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 88539f21..e5a6263 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -163,6 +163,11 @@
     }
 
     @Override
+    void flushLayerUpdates() {
+        nFlushLayerUpdates(mRenderer);
+    }
+
+    @Override
     void clearLayerUpdates() {
         nClearLayerUpdates(mRenderer);
     }
@@ -184,6 +189,7 @@
     static native boolean nCopyLayer(int layerId, int bitmap);
 
     private static native void nClearLayerUpdates(int renderer);
+    private static native void nFlushLayerUpdates(int renderer);
     private static native void nPushLayerUpdate(int renderer, int layer);
 
     ///////////////////////////////////////////////////////////////////////////
diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java
index 0dfed69..88b0986 100644
--- a/core/java/android/view/HardwareCanvas.java
+++ b/core/java/android/view/HardwareCanvas.java
@@ -202,6 +202,15 @@
     abstract void pushLayerUpdate(HardwareLayer layer);
 
     /**
+     * Immediately executes all enqueued layer updates.
+     *
+     * @see #pushLayerUpdate(HardwareLayer)
+     *
+     * @hide
+     */
+    abstract void flushLayerUpdates();
+
+    /**
      * Removes all enqueued layer updates.
      * 
      * @see #pushLayerUpdate(HardwareLayer)
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index c07b187..4bbf1a6 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -449,10 +449,19 @@
      * as soon as possible.
      * 
      * @param layer The hardware layer that needs an update
+     *
+     * @see #flushLayerUpdates()
      */
     abstract void pushLayerUpdate(HardwareLayer layer);
 
     /**
+     * Forces all enqueued layer updates to be executed immediately.
+     *
+     * @see #pushLayerUpdate(HardwareLayer)
+     */
+    abstract void flushLayerUpdates();
+
+    /**
      * Interface used to receive callbacks whenever a view is drawn by
      * a hardware renderer instance.
      */
@@ -2124,6 +2133,11 @@
         }
 
         @Override
+        void flushLayerUpdates() {
+            mGlCanvas.flushLayerUpdates();
+        }
+
+        @Override
         public DisplayList createDisplayList(String name) {
             return new GLES20DisplayList(name);
         }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index e860dca..192492b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -12615,16 +12615,18 @@
     public void buildLayer() {
         if (mLayerType == LAYER_TYPE_NONE) return;
 
-        if (mAttachInfo == null) {
+        final AttachInfo attachInfo = mAttachInfo;
+        if (attachInfo == null) {
             throw new IllegalStateException("This view must be attached to a window first");
         }
 
         switch (mLayerType) {
             case LAYER_TYPE_HARDWARE:
-                if (mAttachInfo.mHardwareRenderer != null &&
-                        mAttachInfo.mHardwareRenderer.isEnabled() &&
-                        mAttachInfo.mHardwareRenderer.validate()) {
+                if (attachInfo.mHardwareRenderer != null &&
+                        attachInfo.mHardwareRenderer.isEnabled() &&
+                        attachInfo.mHardwareRenderer.validate()) {
                     getHardwareLayer();
+                    attachInfo.mViewRootImpl.dispatchFlushHardwareLayerUpdates();
                 }
                 break;
             case LAYER_TYPE_SOFTWARE:
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 60d8a75..c28eb98 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -640,6 +640,18 @@
         }
     }
 
+    void flushHardwareLayerUpdates() {
+        if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled() &&
+                mAttachInfo.mHardwareRenderer.validate()) {
+            mAttachInfo.mHardwareRenderer.flushLayerUpdates();
+        }
+    }
+
+    void dispatchFlushHardwareLayerUpdates() {
+        mHandler.removeMessages(MSG_FLUSH_LAYER_UPDATES);
+        mHandler.sendMessageAtFrontOfQueue(mHandler.obtainMessage(MSG_FLUSH_LAYER_UPDATES));
+    }
+
     public boolean attachFunctor(int functor) {
         //noinspection SimplifiableIfStatement
         if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
@@ -2900,6 +2912,7 @@
     private final static int MSG_DISPATCH_DONE_ANIMATING = 22;
     private final static int MSG_INVALIDATE_WORLD = 23;
     private final static int MSG_WINDOW_MOVED = 24;
+    private final static int MSG_FLUSH_LAYER_UPDATES = 25;
 
     final class ViewRootHandler extends Handler {
         @Override
@@ -2949,6 +2962,8 @@
                     return "MSG_DISPATCH_DONE_ANIMATING";
                 case MSG_WINDOW_MOVED:
                     return "MSG_WINDOW_MOVED";
+                case MSG_FLUSH_LAYER_UPDATES:
+                    return "MSG_FLUSH_LAYER_UPDATES";
             }
             return super.getMessageName(message);
         }
@@ -3171,6 +3186,9 @@
                     invalidateWorld(mView);
                 }
             } break;
+            case MSG_FLUSH_LAYER_UPDATES: {
+                flushHardwareLayerUpdates();
+            } break;
             }
         }
     }
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 983a838..5866404 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -916,6 +916,11 @@
     renderer->clearLayerUpdates();
 }
 
+static void android_view_GLES20Canvas_flushLayerUpdates(JNIEnv* env, jobject clazz,
+        OpenGLRenderer* renderer) {
+    renderer->flushLayerUpdates();
+}
+
 #endif // USE_OPENGL_RENDERER
 
 // ----------------------------------------------------------------------------
@@ -1088,6 +1093,7 @@
     { "nDrawLayer",              "(IIFF)V",    (void*) android_view_GLES20Canvas_drawLayer },
     { "nCopyLayer",              "(II)Z",      (void*) android_view_GLES20Canvas_copyLayer },
     { "nClearLayerUpdates",      "(I)V",       (void*) android_view_GLES20Canvas_clearLayerUpdates },
+    { "nFlushLayerUpdates",      "(I)V",       (void*) android_view_GLES20Canvas_flushLayerUpdates },
     { "nPushLayerUpdate",        "(II)V",      (void*) android_view_GLES20Canvas_pushLayerUpdate },
 
     { "nSetTextureLayerTransform", "(II)V",    (void*) android_view_GLES20Canvas_setTextureLayerTransform },
diff --git a/libs/hwui/Fence.h b/libs/hwui/Fence.h
new file mode 100644
index 0000000..f175e98
--- /dev/null
+++ b/libs/hwui/Fence.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2013 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 ANDROID_HWUI_FENCE_H
+#define ANDROID_HWUI_FENCE_H
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+namespace android {
+namespace uirenderer {
+
+/**
+ * Creating a Fence instance inserts a new sync fence in the OpenGL
+ * commands stream. The caller can then wait for the fence to be signaled
+ * by calling the wait method.
+ */
+class Fence {
+public:
+    enum {
+        /**
+         * Default timeout in nano-seconds for wait()
+         */
+        kDefaultTimeout = 1000000000
+    };
+
+    /**
+     * Inserts a new sync fence in the OpenGL commands stream.
+     */
+    Fence() {
+        mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+        if (mDisplay != EGL_NO_DISPLAY) {
+            mFence = eglCreateSyncKHR(mDisplay, EGL_SYNC_FENCE_KHR, NULL);
+        } else {
+            mFence = EGL_NO_SYNC_KHR;
+        }
+    }
+
+    /**
+     * Destroys the fence. Any caller waiting on the fence will be
+     * signaled immediately.
+     */
+    ~Fence() {
+        if (mFence != EGL_NO_SYNC_KHR) {
+            eglDestroySyncKHR(mDisplay, mFence);
+        }
+    }
+
+    /**
+     * Blocks the calling thread until this fence is signaled, or until
+     * <timeout> nanoseconds have passed.
+     *
+     * Returns true if waiting for the fence was successful, false if
+     * a timeout or an error occurred.
+     */
+    bool wait(EGLTimeKHR timeout = kDefaultTimeout) {
+        EGLint waitStatus = eglClientWaitSyncKHR(mDisplay, mFence,
+                EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, timeout);
+        if (waitStatus == EGL_FALSE) {
+            ALOGW("Failed to wait for the fence %#x", eglGetError());
+        }
+        return waitStatus == EGL_CONDITION_SATISFIED_KHR;
+    }
+
+private:
+    EGLDisplay mDisplay;
+    EGLSyncKHR mFence;
+
+}; // class Fence
+
+/**
+ * An AutoFence creates a Fence instance and waits for the fence
+ * to be signaled when the AutoFence is destroyed. This is useful
+ * to automatically wait for a series of OpenGL commands to be
+ * executed. For example:
+ *
+ * void drawAndWait() {
+ *     glDrawElements();
+ *     AutoFence fence;
+ * }
+ */
+class AutoFence {
+public:
+    AutoFence(EGLTimeKHR timeout = Fence::kDefaultTimeout): mTimeout(timeout) {
+    }
+
+    ~AutoFence() {
+        mFence.wait(mTimeout);
+    }
+
+private:
+    EGLTimeKHR mTimeout;
+    Fence mFence;
+
+}; // class AutoFence
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_FENCE_H
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index d95a62c..fa1eb97 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -33,6 +33,7 @@
 #include "OpenGLRenderer.h"
 #include "DeferredDisplayList.h"
 #include "DisplayListRenderer.h"
+#include "Fence.h"
 #include "PathTessellator.h"
 #include "Properties.h"
 #include "Vector.h"
@@ -552,6 +553,8 @@
 bool OpenGLRenderer::updateLayer(Layer* layer, bool inFrame) {
     if (layer->deferredUpdateScheduled && layer->renderer &&
             layer->displayList && layer->displayList->isRenderable()) {
+        ATRACE_CALL();
+
         Rect& dirty = layer->dirtyRect;
 
         if (inFrame) {
@@ -619,8 +622,11 @@
             sprintf(layerName, "Layer #%d", i);
             startMark(layerName);
 
+            ATRACE_BEGIN("flushLayer");
             Layer* layer = mLayerUpdates.itemAt(i);
             layer->flush();
+            ATRACE_END();
+
             mCaches.resourceCache.decrementRefcount(layer);
 
             endMark();
@@ -661,6 +667,14 @@
     }
 }
 
+void OpenGLRenderer::flushLayerUpdates() {
+    syncState();
+    updateLayers();
+    flushLayers();
+    // Wait for all the layer updates to be executed
+    AutoFence fence;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // State management
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index ce4ce42..1ab493c 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -208,6 +208,7 @@
 
     ANDROID_API void pushLayerUpdate(Layer* layer);
     ANDROID_API void clearLayerUpdates();
+    ANDROID_API void flushLayerUpdates();
 
     ANDROID_API int getSaveCount() const;
     virtual int save(int flags);