Surface: Add allocateBuffers to avoid render delay

This plumbs up a new call on the native Surface object that allows
the client to request that BufferQueue pre-allocate all of the buffers
that it might need for rendering. This hopefully prevents allocation
delays during dequeuing and reduces jank.

Bug: 11792166
Change-Id: Ibeaa7475492d4ac2bcacb107ef60c6240081d8b7
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index fdaae01..78986d9 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -51,6 +51,8 @@
     private static native long nativeReadFromParcel(long nativeObject, Parcel source);
     private static native void nativeWriteToParcel(long nativeObject, Parcel dest);
 
+    private static native void nativeAllocateBuffers(long nativeObject);
+
     public static final Parcelable.Creator<Surface> CREATOR =
             new Parcelable.Creator<Surface>() {
         @Override
@@ -420,6 +422,17 @@
     }
 
     /**
+     * Allocate buffers ahead of time to avoid allocation delays during rendering
+     * @hide
+     */
+    public void allocateBuffers() {
+        synchronized (mLock) {
+            checkNotReleasedLocked();
+            nativeAllocateBuffers(mNativeObject);
+        }
+    }
+
+    /**
      * Exception thrown when a Canvas couldn't be locked with {@link Surface#lockCanvas}, or
      * when a SurfaceTexture could not successfully be allocated.
      */
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 166edc2..3f5f6c4 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -113,7 +113,9 @@
     boolean initialize(Surface surface) throws OutOfResourcesException {
         mInitialized = true;
         updateEnabledState(surface);
-        return nInitialize(mNativeProxy, surface);
+        boolean status = nInitialize(mNativeProxy, surface);
+        surface.allocateBuffers();
+        return status;
     }
 
     @Override
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 3d14aaf5..8331a9f 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -273,6 +273,16 @@
     }
 }
 
+static void nativeAllocateBuffers(JNIEnv* /* env */ , jclass /* clazz */,
+        jlong nativeObject) {
+    sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));
+    if (!isSurfaceValid(surface)) {
+        return;
+    }
+
+    surface->allocateBuffers();
+}
+
 // ----------------------------------------------------------------------------
 
 static jlong nativeCreateFromSurfaceControl(JNIEnv* env, jclass clazz,
@@ -353,6 +363,8 @@
             (void*)nativeLockCanvas },
     {"nativeUnlockCanvasAndPost", "(JLandroid/graphics/Canvas;)V",
             (void*)nativeUnlockCanvasAndPost },
+    {"nativeAllocateBuffers", "(J)V",
+            (void*)nativeAllocateBuffers },
     {"nativeCreateFromSurfaceControl", "(J)J",
             (void*)nativeCreateFromSurfaceControl },
     {"nativeReadFromParcel", "(JLandroid/os/Parcel;)J",