libgui: move fence handling into ConsumerBase

This change moves some common fence handling code into the base class for
BufferQueue consumer classes.  It also makes the ConsumerBase class initialize
a buffer slot's fence with the acquire fence every time a buffer is acquired.

Change-Id: I0bd88bc269e919653b659bfb3ebfb04dd61692a0
diff --git a/include/gui/ConsumerBase.h b/include/gui/ConsumerBase.h
index a0ddca8..68cce5a 100644
--- a/include/gui/ConsumerBase.h
+++ b/include/gui/ConsumerBase.h
@@ -152,7 +152,14 @@
     // it is overridden the derived class's implementation must call
     // ConsumerBase::acquireBufferLocked.
     virtual status_t releaseBufferLocked(int buf, EGLDisplay display,
-           EGLSyncKHR eglFence, const sp<Fence>& fence);
+           EGLSyncKHR eglFence);
+
+    // addReleaseFence adds the sync points associated with a fence to the set
+    // of sync points that must be reached before the buffer in the given slot
+    // may be used after the slot has been released.  This should be called by
+    // derived classes each time some asynchronous work is kicked off that
+    // references the buffer.
+    status_t addReleaseFence(int slot, const sp<Fence>& fence);
 
     // Slot contains the information and object references that
     // ConsumerBase maintains about a BufferQueue buffer slot.
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index 2570cd9..80a010b 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -220,7 +220,7 @@
     // releaseBufferLocked overrides the ConsumerBase method to update the
     // mEglSlots array in addition to the ConsumerBase.
     virtual status_t releaseBufferLocked(int buf, EGLDisplay display,
-           EGLSyncKHR eglFence, const sp<Fence>& fence);
+           EGLSyncKHR eglFence);
 
     static bool isExternalFormat(uint32_t format);
 
diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp
index 57df39c..74b684f 100644
--- a/libs/gui/BufferItemConsumer.cpp
+++ b/libs/gui/BufferItemConsumer.cpp
@@ -82,8 +82,10 @@
 
     Mutex::Autolock _l(mMutex);
 
+    err = addReleaseFence(item.mBuf, releaseFence);
+
     err = releaseBufferLocked(item.mBuf, EGL_NO_DISPLAY,
-            EGL_NO_SYNC_KHR, releaseFence);
+            EGL_NO_SYNC_KHR);
     if (err != OK) {
         BI_LOGE("Failed to release buffer: %s (%d)",
                 strerror(-err), err);
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index 17bbfd1..fd2d1cc 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -185,15 +185,40 @@
         mSlots[item->mBuf].mGraphicBuffer = item->mGraphicBuffer;
     }
 
+    mSlots[item->mBuf].mFence = item->mFence;
+
     CB_LOGV("acquireBufferLocked: -> slot=%d", item->mBuf);
 
     return OK;
 }
 
+status_t ConsumerBase::addReleaseFence(int slot, const sp<Fence>& fence) {
+    CB_LOGV("addReleaseFence: slot=%d", slot);
+
+    if (!mSlots[slot].mFence.get()) {
+        mSlots[slot].mFence = fence;
+    } else {
+        sp<Fence> mergedFence = Fence::merge(
+                String8("ConsumerBase merged release"),
+                mSlots[slot].mFence, fence);
+        if (!mergedFence.get()) {
+            CB_LOGE("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
+            mSlots[slot].mFence = fence;
+            return BAD_VALUE;
+        }
+        mSlots[slot].mFence = mergedFence;
+    }
+
+    return OK;
+}
+
 status_t ConsumerBase::releaseBufferLocked(int slot, EGLDisplay display,
-       EGLSyncKHR eglFence, const sp<Fence>& fence) {
+       EGLSyncKHR eglFence) {
     CB_LOGV("releaseBufferLocked: slot=%d", slot);
-    status_t err = mBufferQueue->releaseBuffer(slot, display, eglFence, fence);
+    status_t err = mBufferQueue->releaseBuffer(slot, display, eglFence,
+            mSlots[slot].mFence);
     if (err == BufferQueue::STALE_BUFFER_SLOT) {
         freeBufferLocked(slot);
     }
diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp
index fc4a854..e1a2838 100644
--- a/libs/gui/CpuConsumer.cpp
+++ b/libs/gui/CpuConsumer.cpp
@@ -134,7 +134,7 @@
         CC_LOGE("%s: Unable to unlock graphic buffer %d", __FUNCTION__, slotIndex);
         return err;
     }
-    releaseBufferLocked(slotIndex, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE);
+    releaseBufferLocked(slotIndex, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
 
     mCurrentLockedBuffers--;
 
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 975eb23..b5872b8 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -172,9 +172,9 @@
 }
 
 status_t SurfaceTexture::releaseBufferLocked(int buf, EGLDisplay display,
-       EGLSyncKHR eglFence, const sp<Fence>& fence) {
+       EGLSyncKHR eglFence) {
     status_t err = ConsumerBase::releaseBufferLocked(buf, mEglDisplay,
-           eglFence, fence);
+           eglFence);
 
     mEglSlots[mCurrentTexture].mEglFence = EGL_NO_SYNC_KHR;
 
@@ -229,7 +229,7 @@
         // not accept this buffer. this is used by SurfaceFlinger to
         // reject buffers which have the wrong size
         if (rejecter && rejecter->reject(mSlots[buf].mGraphicBuffer, item)) {
-            releaseBufferLocked(buf, dpy, EGL_NO_SYNC_KHR, item.mFence);
+            releaseBufferLocked(buf, dpy, EGL_NO_SYNC_KHR);
             glBindTexture(mTexTarget, mTexName);
             return NO_ERROR;
         }
@@ -256,7 +256,7 @@
         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.
-            releaseBufferLocked(buf, dpy, EGL_NO_SYNC_KHR, item.mFence);
+            releaseBufferLocked(buf, dpy, EGL_NO_SYNC_KHR);
             return err;
         }
 
@@ -268,8 +268,7 @@
         // release old buffer
         if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
             status_t status = releaseBufferLocked(mCurrentTexture, dpy,
-                    mEglSlots[mCurrentTexture].mEglFence,
-                    mSlots[mCurrentTexture].mFence);
+                    mEglSlots[mCurrentTexture].mEglFence);
             if (status != NO_ERROR && status != BufferQueue::STALE_BUFFER_SLOT) {
                 ST_LOGE("updateTexImage: failed to release buffer: %s (%d)",
                        strerror(-status), status);
@@ -304,20 +303,10 @@
     sp<Fence> fence(new Fence(fenceFd));
     if (fenceFd == -1 || mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT)
         return;
-    if (!mSlots[mCurrentTexture].mFence.get()) {
-        mSlots[mCurrentTexture].mFence = fence;
-    } else {
-        sp<Fence> mergedFence = Fence::merge(
-                String8("SurfaceTexture merged release"),
-                mSlots[mCurrentTexture].mFence, fence);
-        if (!mergedFence.get()) {
-            ST_LOGE("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
-            mSlots[mCurrentTexture].mFence = fence;
-            return;
-        }
-        mSlots[mCurrentTexture].mFence = mergedFence;
+    status_t err = addReleaseFence(mCurrentTexture, fence);
+    if (err != OK) {
+        ST_LOGE("setReleaseFence: failed to add the fence: %s (%d)",
+                strerror(-err), err);
     }
 }
 
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 7fb1159..f85f604 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -125,7 +125,7 @@
         item.mBuf != mCurrentBufferSlot) {
         // Release the previous buffer.
         err = releaseBufferLocked(mCurrentBufferSlot, EGL_NO_DISPLAY,
-                EGL_NO_SYNC_KHR, Fence::NO_FENCE);
+                EGL_NO_SYNC_KHR);
         if (err != NO_ERROR && err != BufferQueue::STALE_BUFFER_SLOT) {
             ALOGE("error releasing buffer: %s (%d)", strerror(-err), err);
             return err;