Avoid unnecessary texture bind

In SurfaceFlingerConsumer, check to see if native fence sync is
enabled.  If so, defer the texture binding step to Layer::onDraw.

Change-Id: I7d4034a31c0143207eea2509dfa13ef3820f9b8c
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index a8b7d74..ae5d57a 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -243,13 +243,9 @@
     status_t releaseAndUpdateLocked(const BufferQueue::BufferItem& item);
 
     // Binds mTexName and the current buffer to mTexTarget.  Uses
-    // mCurrentTexture if it's set, mCurrentTextureBuf if not.
-    status_t bindTextureImage();
-
-    // doGLFenceWaitLocked inserts a wait command into the OpenGL ES command
-    // stream to ensure that it is safe for future OpenGL ES commands to
-    // access the current texture buffer.
-    status_t doGLFenceWaitLocked() const;
+    // mCurrentTexture if it's set, mCurrentTextureBuf if not.  If the
+    // bind succeeds, this calls doGLFenceWait.
+    status_t bindTextureImageLocked();
 
     // Gets the current EGLDisplay and EGLContext values, and compares them
     // to mEglDisplay and mEglContext.  If the fields have been previously
@@ -257,6 +253,10 @@
     // values.
     status_t checkAndUpdateEglStateLocked();
 
+    // If set, SurfaceTexture will use the EGL_ANDROID_native_fence_sync
+    // extension to create Android native fences for GLES activity.
+    static const bool sUseNativeFenceSync;
+
 private:
     // createImage creates a new EGLImage from a GraphicBuffer.
     EGLImageKHR createImage(EGLDisplay dpy,
@@ -275,6 +275,11 @@
     // mCurrentTextureBuf must not be NULL.
     void computeCurrentTransformMatrixLocked();
 
+    // doGLFenceWaitLocked inserts a wait command into the OpenGL ES command
+    // stream to ensure that it is safe for future OpenGL ES commands to
+    // access the current texture buffer.
+    status_t doGLFenceWaitLocked() const;
+
     // syncForReleaseLocked performs the synchronization needed to release the
     // current slot from an OpenGL ES context.  If needed it will set the
     // current slot's fence to guard against a producer accessing the buffer
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 037f5fb..ee3079e 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -39,6 +39,8 @@
 #include <utils/String8.h>
 #include <utils/Trace.h>
 
+namespace android {
+
 // This compile option makes SurfaceTexture use the
 // EGL_ANDROID_native_fence_sync extension to create Android native fences to
 // signal when all GLES reads for a given buffer have completed.  It is not
@@ -48,9 +50,9 @@
 #ifdef USE_FENCE_SYNC
 #error "USE_NATIVE_FENCE_SYNC and USE_FENCE_SYNC are incompatible"
 #endif
-static const bool useNativeFenceSync = true;
+const bool SurfaceTexture::sUseNativeFenceSync = true;
 #else
-static const bool useNativeFenceSync = false;
+const bool SurfaceTexture::sUseNativeFenceSync = false;
 #endif
 
 // This compile option makes SurfaceTexture use the EGL_ANDROID_sync_wait
@@ -70,8 +72,6 @@
 #define ST_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__)
 #define ST_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__)
 
-namespace android {
-
 // Transform matrices
 static float mtxIdentity[16] = {
     1, 0, 0, 0,
@@ -196,14 +196,8 @@
         return err;
     }
 
-    // Bind the new buffer to the GL texture.
-    err = bindTextureImage();
-    if (err != NO_ERROR) {
-        return err;
-    }
-
-    // Wait for the new buffer to be ready.
-    return doGLFenceWaitLocked();
+    // Bind the new buffer to the GL texture, and wait until it's ready.
+    return bindTextureImageLocked();
 }
 
 status_t SurfaceTexture::acquireBufferLocked(BufferQueue::BufferItem *item) {
@@ -313,7 +307,7 @@
     return err;
 }
 
-status_t SurfaceTexture::bindTextureImage() {
+status_t SurfaceTexture::bindTextureImageLocked() {
     if (mEglDisplay == EGL_NO_DISPLAY) {
         ALOGE("bindTextureImage: invalid display");
         return INVALID_OPERATION;
@@ -330,7 +324,10 @@
             ST_LOGE("bindTextureImage: no currently-bound texture");
             return NO_INIT;
         }
-        return bindUnslottedBufferLocked(mEglDisplay);
+        status_t err = bindUnslottedBufferLocked(mEglDisplay);
+        if (err != NO_ERROR) {
+            return err;
+        }
     } else {
         EGLImageKHR image = mEglSlots[mCurrentTexture].mEglImage;
 
@@ -341,8 +338,11 @@
                     ": %#04x", image, error);
             return UNKNOWN_ERROR;
         }
-        return NO_ERROR;
     }
+
+    // Wait for the new buffer to be ready.
+    return doGLFenceWaitLocked();
+
 }
 
 status_t SurfaceTexture::checkAndUpdateEglStateLocked() {
@@ -521,7 +521,7 @@
     ST_LOGV("syncForReleaseLocked");
 
     if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
-        if (useNativeFenceSync) {
+        if (sUseNativeFenceSync) {
             EGLSyncKHR sync = eglCreateSyncKHR(dpy,
                     EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
             if (sync == EGL_NO_SYNC_KHR) {
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 1c5403f..a1d46d9 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -327,17 +327,11 @@
         return;
     }
 
-    // Bind the current buffer to the GL texture.
+    // Bind the current buffer to the GL texture, and wait for it to be
+    // ready for us to draw into.
     status_t err = mSurfaceFlingerConsumer->bindTextureImage();
     if (err != NO_ERROR) {
-        ALOGW("Layer::onDraw: bindTextureImage failed");
-        // keep going
-    }
-
-    // Wait for the buffer to be ready for us to draw into.
-    err = mSurfaceFlingerConsumer->doGLFenceWait();
-    if (err != OK) {
-        ALOGE("onDraw: failed waiting for fence: %d", err);
+        ALOGW("onDraw: bindTextureImage failed (err=%d)", err);
         // Go ahead and draw the buffer anyway; no matter what we do the screen
         // is probably going to have something visibly wrong.
     }
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index dbe187b..a316896 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -77,12 +77,24 @@
         return err;
     }
 
-    // Bind the new buffer to the GL texture.
-    // TODO: skip this on devices that support explicit sync
-    // (glEGLImageTargetTexture2DOES provides required implicit sync;
-    // without this we get wedged on older devices, but newer devices
-    // don't need it.)
-    return bindTextureImage();
+    if (!sUseNativeFenceSync) {
+        // Bind the new buffer to the GL texture.
+        //
+        // Older devices require the "implicit" synchronization provided
+        // by glEGLImageTargetTexture2DOES, which this method calls.  Newer
+        // devices will either call this in Layer::onDraw, or (if it's not
+        // a GL-composited layer) not at all.
+        err = bindTextureImageLocked();
+    }
+
+    return err;
+}
+
+status_t SurfaceFlingerConsumer::bindTextureImage()
+{
+    Mutex::Autolock lock(mMutex);
+
+    return bindTextureImageLocked();
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h
index d91f27e..308a288 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.h
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.h
@@ -49,8 +49,8 @@
     // texture.
     status_t updateTexImage(BufferRejecter* rejecter);
 
-    // Pass-through to SurfaceTexture implementation.
-    status_t bindTextureImage() { return SurfaceTexture::bindTextureImage(); }
+    // See SurfaceTexture::bindTextureImageLocked().
+    status_t bindTextureImage();
 };
 
 // ----------------------------------------------------------------------------