Merge "Pass fences from BufferQueue to SurfaceTextureClient"
diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h
index 6db2c87..1ea22fd 100644
--- a/include/gui/BufferQueue.h
+++ b/include/gui/BufferQueue.h
@@ -116,12 +116,18 @@
     // pointed to by the buf argument and a status of OK is returned.  If no
     // slot is available then a status of -EBUSY is returned and buf is
     // unmodified.
+    //
+    // The fence parameter will be updated to hold the fence associated with
+    // the buffer. The contents of the buffer must not be overwritten until the
+    // fence signals. If the fence is NULL, the buffer may be written
+    // immediately.
+    //
     // The width and height parameters must be no greater than the minimum of
     // GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv).
     // An error due to invalid dimensions might not be reported until
     // updateTexImage() is called.
-    virtual status_t dequeueBuffer(int *buf, uint32_t width, uint32_t height,
-            uint32_t format, uint32_t usage);
+    virtual status_t dequeueBuffer(int *buf, sp<Fence>& fence,
+            uint32_t width, uint32_t height, uint32_t format, uint32_t usage);
 
     // queueBuffer returns a filled buffer to the BufferQueue. In addition, a
     // timestamp must be provided for the buffer. The timestamp is in
@@ -220,7 +226,7 @@
     // Note that the dependencies on EGL will be removed once we switch to using
     // the Android HW Sync HAL.
     status_t releaseBuffer(int buf, EGLDisplay display, EGLSyncKHR fence,
-            const sp<Fence>& releaseFence = Fence::NO_FENCE);
+            const sp<Fence>& releaseFence);
 
     // consumerConnect connects a consumer to the BufferQueue.  Only one
     // consumer may be connected, and when that consumer disconnects the
diff --git a/include/gui/ISurfaceTexture.h b/include/gui/ISurfaceTexture.h
index 1e33764..019606a 100644
--- a/include/gui/ISurfaceTexture.h
+++ b/include/gui/ISurfaceTexture.h
@@ -25,6 +25,7 @@
 
 #include <binder/IInterface.h>
 
+#include <ui/Fence.h>
 #include <ui/GraphicBuffer.h>
 #include <ui/Rect.h>
 
@@ -67,8 +68,13 @@
     // in the contents of its associated buffer contents and call queueBuffer.
     // If dequeueBuffer return BUFFER_NEEDS_REALLOCATION, the client is
     // expected to call requestBuffer immediately.
-    virtual status_t dequeueBuffer(int *slot, uint32_t w, uint32_t h,
-            uint32_t format, uint32_t usage) = 0;
+    //
+    // The fence parameter will be updated to hold the fence associated with
+    // the buffer. The contents of the buffer must not be overwritten until the
+    // fence signals. If the fence is NULL, the buffer may be written
+    // immediately.
+    virtual status_t dequeueBuffer(int *slot, sp<Fence>& fence,
+            uint32_t w, uint32_t h, uint32_t format, uint32_t usage) = 0;
 
     // queueBuffer indicates that the client has finished filling in the
     // contents of the buffer associated with slot and transfers ownership of
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 23ac882..40e43a1 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -294,8 +294,8 @@
     return NO_ERROR;
 }
 
-status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
-        uint32_t format, uint32_t usage) {
+status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>& outFence,
+        uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
     ATRACE_CALL();
     ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage);
 
@@ -307,7 +307,6 @@
     status_t returnFlags(OK);
     EGLDisplay dpy = EGL_NO_DISPLAY;
     EGLSyncKHR fence = EGL_NO_SYNC_KHR;
-    sp<Fence> releaseFence;
 
     { // Scope for the lock
         Mutex::Autolock lock(mMutex);
@@ -490,7 +489,7 @@
 
         dpy = mSlots[buf].mEglDisplay;
         fence = mSlots[buf].mFence;
-        releaseFence = mSlots[buf].mReleaseFence;
+        outFence = mSlots[buf].mReleaseFence;
         mSlots[buf].mFence = EGL_NO_SYNC_KHR;
         mSlots[buf].mReleaseFence.clear();
     }  // end lock scope
@@ -508,16 +507,6 @@
         eglDestroySyncKHR(dpy, fence);
     }
 
-    if (releaseFence.get()) {
-        int err = releaseFence->wait(1000);
-        if (err == -ETIME) {
-            ALOGE("dequeueBuffer: timeout waiting for release fence");
-        } else if (err != NO_ERROR) {
-            ALOGE("dequeueBuffer: error waiting for sync fence: %d", err);
-        }
-        releaseFence.clear();
-    }
-
     ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", *outBuf,
             mSlots[*outBuf].mGraphicBuffer->handle, returnFlags);
 
diff --git a/libs/gui/ISurfaceTexture.cpp b/libs/gui/ISurfaceTexture.cpp
index 3eb5e7a..c8fef06 100644
--- a/libs/gui/ISurfaceTexture.cpp
+++ b/libs/gui/ISurfaceTexture.cpp
@@ -81,8 +81,8 @@
         return result;
     }
 
-    virtual status_t dequeueBuffer(int *buf, uint32_t w, uint32_t h,
-            uint32_t format, uint32_t usage) {
+    virtual status_t dequeueBuffer(int *buf, sp<Fence>& fence,
+            uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
         data.writeInt32(w);
@@ -94,6 +94,12 @@
             return result;
         }
         *buf = reply.readInt32();
+        fence.clear();
+        bool hasFence = reply.readInt32();
+        if (hasFence) {
+            fence = new Fence();
+            reply.read(*fence.get());
+        }
         result = reply.readInt32();
         return result;
     }
@@ -205,8 +211,13 @@
             uint32_t format = data.readInt32();
             uint32_t usage  = data.readInt32();
             int buf;
-            int result = dequeueBuffer(&buf, w, h, format, usage);
+            sp<Fence> fence;
+            int result = dequeueBuffer(&buf, fence, w, h, format, usage);
             reply->writeInt32(buf);
+            reply->writeInt32(fence.get() != NULL);
+            if (fence.get() != NULL) {
+                reply->write(*fence.get());
+            }
             reply->writeInt32(result);
             return NO_ERROR;
         } break;
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index 8195de9..57bc604 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -198,7 +198,8 @@
     int buf = -1;
     int reqW = mReqWidth ? mReqWidth : mUserWidth;
     int reqH = mReqHeight ? mReqHeight : mUserHeight;
-    status_t result = mSurfaceTexture->dequeueBuffer(&buf, reqW, reqH,
+    sp<Fence> fence;
+    status_t result = mSurfaceTexture->dequeueBuffer(&buf, fence, reqW, reqH,
             mReqFormat, mReqUsage);
     if (result < 0) {
         ALOGV("dequeueBuffer: ISurfaceTexture::dequeueBuffer(%d, %d, %d, %d)"
@@ -219,6 +220,15 @@
             return result;
         }
     }
+
+    if (fence.get()) {
+        status_t err = fence->wait(Fence::TIMEOUT_NEVER);
+        if (err != OK) {
+            ALOGE("dequeueBuffer: error waiting for fence: %d", err);
+        }
+        fence.clear();
+    }
+
     *buffer = gbuf.get();
     *fenceFd = -1;
     return OK;