Bag of scheduling tweaks

 Bug: 15118640

 * Prevent over-stuffing the queue by dropping frames
 * Prevent double-drawing in one pulse by RT by deferring
   vsync registration until post-draw so that it catches
   the next vsync pulse instead of the current one
 * Bias vsync race condition towards the UI thread
 * Fix queueDelay to actually work

Change-Id: Ibf584258bd93ebcbba058bd976dc8b307f1c6155
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 839ef91..b6b3428 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -360,7 +360,9 @@
     setSurface(NULL);
 }
 
-void CanvasContext::setSurface(EGLNativeWindowType window) {
+void CanvasContext::setSurface(ANativeWindow* window) {
+    mNativeWindow = window;
+
     if (mEglSurface != EGL_NO_SURFACE) {
         mGlobalContext->destroySurface(mEglSurface);
         mEglSurface = EGL_NO_SURFACE;
@@ -393,7 +395,7 @@
     makeCurrent();
 }
 
-bool CanvasContext::initialize(EGLNativeWindowType window) {
+bool CanvasContext::initialize(ANativeWindow* window) {
     if (mCanvas) return false;
     setSurface(window);
     mCanvas = new OpenGLRenderer();
@@ -401,11 +403,11 @@
     return true;
 }
 
-void CanvasContext::updateSurface(EGLNativeWindowType window) {
+void CanvasContext::updateSurface(ANativeWindow* window) {
     setSurface(window);
 }
 
-void CanvasContext::pauseSurface(EGLNativeWindowType window) {
+void CanvasContext::pauseSurface(ANativeWindow* window) {
     // TODO: For now we just need a fence, in the future suspend any animations
     // and such to prevent from trying to render into this surface
 }
@@ -456,7 +458,15 @@
     info.frameTimeMs = mRenderThread.timeLord().frameTimeMs();
     mRootRenderNode->prepareTree(info);
 
-    if (info.out.hasAnimations) {
+    int runningBehind = 0;
+    // TODO: This query is moderately expensive, investigate adding some sort
+    // of fast-path based off when we last called eglSwapBuffers() as well as
+    // last vsync time. Or something.
+    mNativeWindow->query(mNativeWindow.get(),
+            NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND, &runningBehind);
+    info.out.canDrawThisFrame = !runningBehind;
+
+    if (info.out.hasAnimations || !info.out.canDrawThisFrame) {
         if (info.out.hasFunctors) {
             info.out.requiresUiRedraw = true;
         } else if (!info.out.requiresUiRedraw) {
@@ -467,6 +477,11 @@
     }
 }
 
+void CanvasContext::notifyFramePending() {
+    ATRACE_CALL();
+    mRenderThread.pushBackFrameCallback(this);
+}
+
 void CanvasContext::draw(Rect* dirty) {
     LOG_ALWAYS_FATAL_IF(!mCanvas || mEglSurface == EGL_NO_SURFACE,
             "drawDisplayList called on a context with no canvas or surface!");
@@ -515,7 +530,9 @@
     info.prepareTextures = false;
 
     prepareTree(info);
-    draw(NULL);
+    if (info.out.canDrawThisFrame) {
+        draw(NULL);
+    }
 }
 
 void CanvasContext::invokeFunctor(Functor* functor) {