Transfer HWC release fences to BufferQueue

After a HWC set, each SurfaceFlinger Layer retrieves the release fence
HWC returned and gives it to the layer's SurfaceTexture. The
SurfaceTexture accumulates the fences into a merged fence until the
next updateTexImage, then passes the merged fence to the BufferQueue
in releaseBuffer.

In a follow-on change, BufferQueue will return the fence along with
the buffer slot in dequeueBuffer. For now, dequeueBuffer waits for the
fence to signal before returning.

The releaseFence default value for BufferQueue::releaseBuffer() is
temporary to avoid transient build breaks with a multi-project
checkin. It'll disappear in the next change.

Change-Id: Iaa9a0d5775235585d9cbf453d3a64623d08013d9
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 55be4bc..8ef885b 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -236,8 +236,10 @@
         // not accept this buffer. this is used by SurfaceFlinger to
         // reject buffers which have the wrong size
         if (rejecter && rejecter->reject(mEGLSlots[buf].mGraphicBuffer, item)) {
-            mBufferQueue->releaseBuffer(buf, dpy, mEGLSlots[buf].mFence);
+            mBufferQueue->releaseBuffer(buf, dpy, mEGLSlots[buf].mFence,
+                    mEGLSlots[buf].mReleaseFence);
             mEGLSlots[buf].mFence = EGL_NO_SYNC_KHR;
+            mEGLSlots[buf].mReleaseFence.clear();
             glBindTexture(mTexTarget, mTexName);
             return NO_ERROR;
         }
@@ -284,8 +286,10 @@
         if (err != NO_ERROR) {
             // Release the buffer we just acquired.  It's not safe to
             // release the old buffer, so instead we just drop the new frame.
-            mBufferQueue->releaseBuffer(buf, dpy, mEGLSlots[buf].mFence);
+            mBufferQueue->releaseBuffer(buf, dpy, mEGLSlots[buf].mFence,
+                    mEGLSlots[buf].mReleaseFence);
             mEGLSlots[buf].mFence = EGL_NO_SYNC_KHR;
+            mEGLSlots[buf].mReleaseFence.clear();
             return err;
         }
 
@@ -297,9 +301,10 @@
         // release old buffer
         if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
             status_t status = mBufferQueue->releaseBuffer(mCurrentTexture, dpy,
-                    mEGLSlots[mCurrentTexture].mFence);
-
+                    mEGLSlots[mCurrentTexture].mFence,
+                    mEGLSlots[mCurrentTexture].mReleaseFence);
             mEGLSlots[mCurrentTexture].mFence = EGL_NO_SYNC_KHR;
+            mEGLSlots[mCurrentTexture].mReleaseFence.clear();
             if (status == BufferQueue::STALE_BUFFER_SLOT) {
                 freeBufferLocked(mCurrentTexture);
             } else if (status != NO_ERROR) {
@@ -328,6 +333,27 @@
     return err;
 }
 
+void SurfaceTexture::setReleaseFence(int fenceFd) {
+    if (fenceFd == -1)
+        return;
+    sp<Fence> fence(new Fence(fenceFd));
+    if (!mEGLSlots[mCurrentTexture].mReleaseFence.get()) {
+        mEGLSlots[mCurrentTexture].mReleaseFence = fence;
+    } else {
+        sp<Fence> mergedFence = Fence::merge(
+                String8("SurfaceTexture merged release"),
+                mEGLSlots[mCurrentTexture].mReleaseFence, fence);
+        if (mergedFence.get()) {
+            ALOGE("failed to merge release fences");
+            // synchronization is broken, the best we can do is hope fences
+            // signal in order so the new fence will act like a union
+            mEGLSlots[mCurrentTexture].mReleaseFence = fence;
+        } else {
+            mEGLSlots[mCurrentTexture].mReleaseFence = mergedFence;
+        }
+    }
+}
+
 status_t SurfaceTexture::detachFromContext() {
     ATRACE_CALL();
     ST_LOGV("detachFromContext");