diff --git a/include/gui/ConsumerBase.h b/include/gui/ConsumerBase.h index a0ddca872..68cce5ae7 100644 --- a/include/gui/ConsumerBase.h +++ b/include/gui/ConsumerBase.h @@ -152,7 +152,14 @@ protected: // 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); + 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); // 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 2570cd947..80a010b53 100644 --- a/include/gui/SurfaceTexture.h +++ b/include/gui/SurfaceTexture.h @@ -220,7 +220,7 @@ protected: // 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); + EGLSyncKHR eglFence); static bool isExternalFormat(uint32_t format); diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp index 57df39c74..74b684f80 100644 --- a/libs/gui/BufferItemConsumer.cpp +++ b/libs/gui/BufferItemConsumer.cpp @@ -82,8 +82,10 @@ status_t BufferItemConsumer::releaseBuffer(const BufferItem &item, 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 17bbfd11e..fd2d1ccc1 100644 --- a/libs/gui/ConsumerBase.cpp +++ b/libs/gui/ConsumerBase.cpp @@ -185,15 +185,40 @@ status_t ConsumerBase::acquireBufferLocked(BufferQueue::BufferItem *item) { 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) { + CB_LOGV("addReleaseFence: slot=%d", slot); + + if (!mSlots[slot].mFence.get()) { + mSlots[slot].mFence = fence; + } else { + sp 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) { + 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 fc4a85493..e1a28381d 100644 --- a/libs/gui/CpuConsumer.cpp +++ b/libs/gui/CpuConsumer.cpp @@ -134,7 +134,7 @@ status_t CpuConsumer::unlockBuffer(const LockedBuffer &nativeBuffer) { 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 975eb236c..b5872b8c3 100644 --- a/libs/gui/SurfaceTexture.cpp +++ b/libs/gui/SurfaceTexture.cpp @@ -172,9 +172,9 @@ status_t SurfaceTexture::acquireBufferLocked(BufferQueue::BufferItem *item) { } status_t SurfaceTexture::releaseBufferLocked(int buf, EGLDisplay display, - EGLSyncKHR eglFence, const sp& fence) { + EGLSyncKHR eglFence) { status_t err = ConsumerBase::releaseBufferLocked(buf, mEglDisplay, - eglFence, fence); + eglFence); mEglSlots[mCurrentTexture].mEglFence = EGL_NO_SYNC_KHR; @@ -229,7 +229,7 @@ status_t SurfaceTexture::updateTexImage(BufferRejecter* rejecter) { // 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 @@ status_t SurfaceTexture::updateTexImage(BufferRejecter* rejecter) { 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 @@ status_t SurfaceTexture::updateTexImage(BufferRejecter* rejecter) { // 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 @@ void SurfaceTexture::setReleaseFence(int fenceFd) { sp fence(new Fence(fenceFd)); if (fenceFd == -1 || mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT) return; - if (!mSlots[mCurrentTexture].mFence.get()) { - mSlots[mCurrentTexture].mFence = fence; - } else { - sp 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 7fb1159bf..f85f6043e 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp @@ -125,7 +125,7 @@ status_t FramebufferSurface::nextBuffer(sp* buffer) { 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;