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
This commit is contained in:
parent
010dd4fb89
commit
61e04b92bd
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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.
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user