summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJamie Gennis <jgennis@google.com>2012-09-09 17:48:42 -0700
committerJamie Gennis <jgennis@google.com>2012-09-10 13:27:23 -0700
commit61e04b92bdeafc6fca89052d14dab1bd0c384a71 (patch)
treebbc279dd485ae70f48b57cca2cc8b9daf46252cc
parent010dd4fb892aecf71e4631c22148fe57ef5b3958 (diff)
downloadframeworks_native-61e04b92bdeafc6fca89052d14dab1bd0c384a71.zip
frameworks_native-61e04b92bdeafc6fca89052d14dab1bd0c384a71.tar.gz
frameworks_native-61e04b92bdeafc6fca89052d14dab1bd0c384a71.tar.bz2
SurfaceTexture: use eglWaitSync
This change adds a compile-option to use eglWaitSyncANDROID to ensure that texturing operations that access the current buffer of a SurfaceTexture do not occur until the buffer is completely written. It also moves this synchronization into a new SurfaceTexture method called doGLFenceWait and changes SurfaceFlinger's Layer class to use that method rather than performing its own wait on the fence. Change-Id: I70afa88086ca7ff49a80e3cd03d423767db7cb88
-rw-r--r--include/gui/SurfaceTexture.h9
-rw-r--r--libs/gui/SurfaceTexture.cpp74
-rw-r--r--services/surfaceflinger/Layer.cpp8
3 files changed, 84 insertions, 7 deletions
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index 80a010b..6e5a478 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -77,6 +77,9 @@ public:
//
// This call may only be made while the OpenGL ES context to which the
// target texture belongs is bound to the calling thread.
+ //
+ // After calling this method the doGLFenceWait method must be called
+ // before issuing OpenGL ES commands that access the texture contents.
status_t updateTexImage();
// setReleaseFence stores a fence file descriptor that will signal when the
@@ -154,6 +157,12 @@ public:
// ready to be read from.
sp<Fence> getCurrentFence() const;
+ // doGLFenceWait inserts a wait command into the OpenGL ES command stream
+ // to ensure that it is safe for future OpenGL ES commands to access the
+ // current texture buffer. This must be called each time updateTexImage
+ // is called before issuing OpenGL ES commands that access the texture.
+ status_t doGLFenceWait() const;
+
// isSynchronousMode returns whether the SurfaceTexture is currently in
// synchronous mode.
bool isSynchronousMode() const;
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index c999080..e21b65d 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -48,9 +48,19 @@
#ifdef USE_FENCE_SYNC
#error "USE_NATIVE_FENCE_SYNC and USE_FENCE_SYNC are incompatible"
#endif
-const bool useNativeFenceSync = true;
+static const bool useNativeFenceSync = true;
#else
-const bool useNativeFenceSync = false;
+static const bool useNativeFenceSync = false;
+#endif
+
+// This compile option makes SurfaceTexture use the EGL_ANDROID_sync_wait
+// extension to insert server-side waits into the GLES command stream. This
+// feature requires the EGL_ANDROID_native_fence_sync and
+// EGL_ANDROID_wait_sync extensions.
+#ifdef USE_WAIT_SYNC
+static const bool useWaitSync = true;
+#else
+static const bool useWaitSync = false;
#endif
// This compile option makes SurfaceTexture use the EGL_KHR_fence_sync extension
@@ -725,6 +735,66 @@ sp<Fence> SurfaceTexture::getCurrentFence() const {
return mCurrentFence;
}
+status_t SurfaceTexture::doGLFenceWait() const {
+ Mutex::Autolock lock(mMutex);
+
+ EGLDisplay dpy = eglGetCurrentDisplay();
+ EGLContext ctx = eglGetCurrentContext();
+
+ if (mEglDisplay != dpy || mEglDisplay == EGL_NO_DISPLAY) {
+ ST_LOGE("doGLFenceWait: invalid current EGLDisplay");
+ return INVALID_OPERATION;
+ }
+
+ if (mEglContext != ctx || mEglContext == EGL_NO_CONTEXT) {
+ ST_LOGE("doGLFenceWait: invalid current EGLContext");
+ return INVALID_OPERATION;
+ }
+
+ if (mCurrentFence != NULL) {
+ if (useWaitSync) {
+ // Create an EGLSyncKHR from the current fence.
+ int fenceFd = mCurrentFence->dup();
+ if (fenceFd == -1) {
+ ST_LOGE("doGLFenceWait: error dup'ing fence fd: %d", errno);
+ return -errno;
+ }
+ EGLint attribs[] = {
+ EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd,
+ EGL_NONE
+ };
+ EGLSyncKHR sync = eglCreateSyncKHR(dpy,
+ EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
+ if (sync == EGL_NO_SYNC_KHR) {
+ close(fenceFd);
+ ST_LOGE("doGLFenceWait: error creating EGL fence: %#x",
+ eglGetError());
+ return UNKNOWN_ERROR;
+ }
+
+ // XXX: The spec draft is inconsistent as to whether this should
+ // return an EGLint or void. Ignore the return value for now, as
+ // it's not strictly needed.
+ eglWaitSyncANDROID(dpy, sync, 0);
+ EGLint eglErr = eglGetError();
+ eglDestroySyncKHR(dpy, sync);
+ if (eglErr != EGL_SUCCESS) {
+ ST_LOGE("doGLFenceWait: error waiting for EGL fence: %#x",
+ eglErr);
+ return UNKNOWN_ERROR;
+ }
+ } else {
+ status_t err = mCurrentFence->wait(Fence::TIMEOUT_NEVER);
+ if (err != NO_ERROR) {
+ ST_LOGE("doGLFenceWait: error waiting for fence: %d", err);
+ return err;
+ }
+ }
+ }
+
+ return NO_ERROR;
+}
+
bool SurfaceTexture::isSynchronousMode() const {
Mutex::Autolock lock(mMutex);
return mBufferQueue->isSynchronousMode();
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index f39de4a..e78059d 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -333,11 +333,9 @@ void Layer::onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const
return;
}
- // TODO: replace this with a server-side wait
- sp<Fence> fence = mSurfaceTexture->getCurrentFence();
- if (fence.get()) {
- status_t err = fence->wait(Fence::TIMEOUT_NEVER);
- ALOGW_IF(err != OK, "Layer::onDraw: failed waiting for fence: %d", err);
+ status_t err = mSurfaceTexture->doGLFenceWait();
+ if (err != OK) {
+ ALOGE("onDraw: failed waiting for fence: %d", err);
// Go ahead and draw the buffer anyway; no matter what we do the screen
// is probably going to have something visibly wrong.
}