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;