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

Commit ef19414b authored by Jesse Hall's avatar Jesse Hall
Browse files

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
parent a74cbc06
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include <gui/IGraphicBufferAlloc.h>
#include <gui/ISurfaceTexture.h>

#include <ui/Fence.h>
#include <ui/GraphicBuffer.h>

#include <utils/String8.h>
@@ -218,7 +219,8 @@ public:
    //
    // Note that the dependencies on EGL will be removed once we switch to using
    // the Android HW Sync HAL.
    status_t releaseBuffer(int buf, EGLDisplay display, EGLSyncKHR fence);
    status_t releaseBuffer(int buf, EGLDisplay display, EGLSyncKHR fence,
            const sp<Fence>& releaseFence = Fence::NO_FENCE);

    // consumerConnect connects a consumer to the BufferQueue.  Only one
    // consumer may be connected, and when that consumer disconnects the
@@ -378,6 +380,10 @@ private:
        // on a compile-time option) set to a new sync object in updateTexImage.
        EGLSyncKHR mFence;

        // mReleaseFence is a fence which must signal before the contents of
        // the buffer associated with this buffer slot may be overwritten.
        sp<Fence> mReleaseFence;

        // Indicates whether this buffer has been seen by a consumer yet
        bool mAcquireCalled;

+15 −0
Original line number Diff line number Diff line
@@ -91,6 +91,14 @@ public:
    // target texture belongs is bound to the calling thread.
    status_t updateTexImage();

    // setReleaseFence stores a fence file descriptor that will signal when the
    // current buffer is no longer being read. This fence will be returned to
    // the producer when the current buffer is released by updateTexImage().
    // Multiple fences can be set for a given buffer; they will be merged into
    // a single union fence. The SurfaceTexture will close the file descriptor
    // when finished with it.
    void setReleaseFence(int fenceFd);

    // setBufferCountServer set the buffer count. If the client has requested
    // a buffer count using setBufferCount, the server-buffer count will
    // take effect once the client sets the count back to zero.
@@ -349,6 +357,13 @@ private:
        // to EGL_NO_SYNC_KHR when the buffer is created and (optionally, based
        // on a compile-time option) set to a new sync object in updateTexImage.
        EGLSyncKHR mFence;

        // mReleaseFence is a fence which will signal when the buffer
        // associated with this buffer slot is no longer being used by the
        // consumer and can be overwritten. The buffer can be dequeued before
        // the fence signals; the producer is responsible for delaying writes
        // until it signals.
        sp<Fence> mReleaseFence;
    };

    // mEglDisplay is the EGLDisplay with which this SurfaceTexture is currently
+1 −0
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ class Fence
    : public LightRefBase<Fence>, public Flattenable
{
public:
    static const sp<Fence> NO_FENCE;

    // Construct a new Fence object with an invalid file descriptor.  This
    // should be done when the Fence object will be set up by unflattening
+5 −4
Original line number Diff line number Diff line
@@ -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
+17 −4
Original line number Diff line number Diff line
@@ -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) {
Loading