Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 61e04b92 authored by Jamie Gennis's avatar Jamie Gennis
Browse files

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
parent 010dd4fb
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -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;
+72 −2
Original line number Diff line number Diff line
@@ -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();
+3 −5
Original line number Diff line number Diff line
@@ -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.
    }