summaryrefslogtreecommitdiffstats
path: root/libs
diff options
context:
space:
mode:
authorJesse Hall <jessehall@google.com>2012-06-14 14:45:17 -0700
committerJesse Hall <jessehall@google.com>2012-06-21 22:21:12 -0700
commitef19414bd8b77a26f5751f3845be79025a8263fe (patch)
tree9624b3d718e065747bedff50cb969151d675a471 /libs
parenta74cbc06493ed941a8a54f2f1d0074f03fc9aafb (diff)
downloadframeworks_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.mk9
-rw-r--r--libs/gui/BufferQueue.cpp21
-rw-r--r--libs/gui/CpuConsumer.cpp6
-rw-r--r--libs/gui/SurfaceTexture.cpp34
-rw-r--r--libs/ui/Fence.cpp4
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));
}