diff options
author | Jesse Hall <jessehall@google.com> | 2012-06-14 14:45:17 -0700 |
---|---|---|
committer | Jesse Hall <jessehall@google.com> | 2012-06-21 22:21:12 -0700 |
commit | ef19414bd8b77a26f5751f3845be79025a8263fe (patch) | |
tree | 9624b3d718e065747bedff50cb969151d675a471 /libs | |
parent | a74cbc06493ed941a8a54f2f1d0074f03fc9aafb (diff) | |
download | frameworks_native-ef19414bd8b77a26f5751f3845be79025a8263fe.zip frameworks_native-ef19414bd8b77a26f5751f3845be79025a8263fe.tar.gz frameworks_native-ef19414bd8b77a26f5751f3845be79025a8263fe.tar.bz2 |
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
Diffstat (limited to 'libs')
-rw-r--r-- | libs/gui/Android.mk | 9 | ||||
-rw-r--r-- | libs/gui/BufferQueue.cpp | 21 | ||||
-rw-r--r-- | libs/gui/CpuConsumer.cpp | 6 | ||||
-rw-r--r-- | libs/gui/SurfaceTexture.cpp | 34 | ||||
-rw-r--r-- | libs/ui/Fence.cpp | 4 |
5 files changed, 59 insertions, 15 deletions
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk index 8fc96cf..1cda14e 100644 --- a/libs/gui/Android.mk +++ b/libs/gui/Android.mk @@ -25,14 +25,15 @@ LOCAL_SRC_FILES:= \ CpuConsumer.cpp LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libutils \ libbinder \ + libcutils \ + libEGL \ + libGLESv2 \ libhardware \ libhardware_legacy \ + libsync \ libui \ - libEGL \ - libGLESv2 \ + libutils \ LOCAL_MODULE:= libgui diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index a2e08c0..23ac882 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -307,6 +307,7 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, 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); @@ -318,7 +319,6 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, usage |= mConsumerUsageBits; int found = -1; - int foundSync = -1; int dequeuedCount = 0; bool tryAgain = true; while (tryAgain) { @@ -369,7 +369,6 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, // look for a free buffer to give to the client found = INVALID_BUFFER_SLOT; - foundSync = INVALID_BUFFER_SLOT; dequeuedCount = 0; for (int i = 0; i < mBufferCount; i++) { const int state = mSlots[i].mBufferState; @@ -393,7 +392,6 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, bool isOlder = mSlots[i].mFrameNumber < mSlots[found].mFrameNumber; if (found < 0 || isOlder) { - foundSync = i; found = i; } } @@ -484,6 +482,7 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, mSlots[buf].mGraphicBuffer = graphicBuffer; mSlots[buf].mRequestBufferCalled = false; mSlots[buf].mFence = EGL_NO_SYNC_KHR; + mSlots[buf].mReleaseFence.clear(); mSlots[buf].mEglDisplay = EGL_NO_DISPLAY; returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION; @@ -491,7 +490,9 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, dpy = mSlots[buf].mEglDisplay; fence = mSlots[buf].mFence; + releaseFence = mSlots[buf].mReleaseFence; mSlots[buf].mFence = EGL_NO_SYNC_KHR; + mSlots[buf].mReleaseFence.clear(); } // end lock scope if (fence != EGL_NO_SYNC_KHR) { @@ -507,6 +508,16 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, 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); @@ -846,6 +857,7 @@ void BufferQueue::freeBufferLocked(int i) { eglDestroySyncKHR(mSlots[i].mEglDisplay, mSlots[i].mFence); mSlots[i].mFence = EGL_NO_SYNC_KHR; } + mSlots[i].mReleaseFence.clear(); } void BufferQueue::freeAllBuffersLocked() { @@ -896,7 +908,7 @@ status_t BufferQueue::acquireBuffer(BufferItem *buffer) { } status_t BufferQueue::releaseBuffer(int buf, EGLDisplay display, - EGLSyncKHR fence) { + EGLSyncKHR fence, const sp<Fence>& releaseFence) { ATRACE_CALL(); ATRACE_BUFFER_INDEX(buf); @@ -908,6 +920,7 @@ status_t BufferQueue::releaseBuffer(int buf, EGLDisplay display, mSlots[buf].mEglDisplay = display; mSlots[buf].mFence = fence; + mSlots[buf].mReleaseFence = releaseFence; // The buffer can now only be released if its in the acquired state if (mSlots[buf].mBufferState == BufferSlot::ACQUIRED) { diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp index 48a54c7..bf2539f 100644 --- a/libs/gui/CpuConsumer.cpp +++ b/libs/gui/CpuConsumer.cpp @@ -107,7 +107,8 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { if (b.mGraphicBuffer != NULL) { if (mBufferPointers[buf] != NULL) { CC_LOGE("Reallocation of buffer %d while in consumer use!", buf); - mBufferQueue->releaseBuffer(buf, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); + mBufferQueue->releaseBuffer(buf, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, + Fence::NO_FENCE); return BAD_VALUE; } mBufferSlot[buf] = b.mGraphicBuffer; @@ -161,7 +162,8 @@ status_t CpuConsumer::unlockBuffer(const LockedBuffer &nativeBuffer) { CC_LOGE("%s: Unable to unlock graphic buffer %d", __FUNCTION__, buf); return err; } - err = mBufferQueue->releaseBuffer(buf, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); + err = mBufferQueue->releaseBuffer(buf, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, + Fence::NO_FENCE); if (err == BufferQueue::STALE_BUFFER_SLOT) { freeBufferLocked(buf); } else if (err != OK) { 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 @@ 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(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 @@ 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. - 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 @@ status_t SurfaceTexture::updateTexImage(BufferRejecter* rejecter) { // 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 @@ status_t SurfaceTexture::updateTexImage(BufferRejecter* rejecter) { 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"); diff --git a/libs/ui/Fence.cpp b/libs/ui/Fence.cpp index 993585b..5c17d10 100644 --- a/libs/ui/Fence.cpp +++ b/libs/ui/Fence.cpp @@ -26,6 +26,8 @@ namespace android { +const sp<Fence> Fence::NO_FENCE = sp<Fence>(); + Fence::Fence() : mFenceFd(-1) { } @@ -55,7 +57,7 @@ sp<Fence> Fence::merge(const String8& name, const sp<Fence>& f1, if (result == -1) { ALOGE("merge: sync_merge returned an error: %s (%d)", strerror(-errno), errno); - return sp<Fence>(); + return NO_FENCE; } return sp<Fence>(new Fence(result)); } |