bufferqueues: Move the gl fence wait from dequeue to releaseBuffer

Bug: 339705065
Flag: com.android.graphics.libgui.flags.bq_gl_fence_cleanup
Test: old tests

Change-Id: I429118e2f23691c8858100343f40b8cc156133ea
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index d0607bf..9855b5b 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -28,6 +28,10 @@
 #define VALIDATE_CONSISTENCY()
 #endif
 
+#define EGL_EGLEXT_PROTOTYPES
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
 #include <gui/BufferItem.h>
 #include <gui/BufferQueueConsumer.h>
 #include <gui/BufferQueueCore.h>
@@ -486,6 +490,27 @@
         return BAD_VALUE;
     }
 
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP)
+    if (eglFence != EGL_NO_SYNC_KHR) {
+        // Most platforms will be using native fences, so it's unlikely that we'll ever have to
+        // process an eglFence. Ideally we can remove this code eventually. In the mean time, do our
+        // best to wait for it so the buffer stays valid, otherwise return an error to the caller.
+        //
+        // EGL_SYNC_FLUSH_COMMANDS_BIT_KHR so that we don't wait forever on a fence that hasn't
+        // shown up on the GPU yet.
+        EGLint result = eglClientWaitSyncKHR(eglDisplay, eglFence, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
+                                             1000000000);
+        if (result == EGL_FALSE) {
+            BQ_LOGE("releaseBuffer: error %#x waiting for fence", eglGetError());
+            return UNKNOWN_ERROR;
+        } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
+            BQ_LOGE("releaseBuffer: timeout waiting for fence");
+            return UNKNOWN_ERROR;
+        }
+        eglDestroySyncKHR(eglDisplay, eglFence);
+    }
+#endif
+
     sp<IProducerListener> listener;
     { // Autolock scope
         std::lock_guard<std::mutex> lock(mCore->mMutex);
@@ -507,8 +532,10 @@
             return BAD_VALUE;
         }
 
+#if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP)
         mSlots[slot].mEglDisplay = eglDisplay;
         mSlots[slot].mEglFence = eglFence;
+#endif
         mSlots[slot].mFence = releaseFence;
         mSlots[slot].mBufferState.release();
 
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index d52cf70..5a09399 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -262,14 +262,16 @@
     mSlots[slot].mFrameNumber = 0;
     mSlots[slot].mAcquireCalled = false;
     mSlots[slot].mNeedsReallocation = true;
+    mSlots[slot].mFence = Fence::NO_FENCE;
 
+#if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP)
     // Destroy fence as BufferQueue now takes ownership
     if (mSlots[slot].mEglFence != EGL_NO_SYNC_KHR) {
         eglDestroySyncKHR(mSlots[slot].mEglDisplay, mSlots[slot].mEglFence);
         mSlots[slot].mEglFence = EGL_NO_SYNC_KHR;
     }
-    mSlots[slot].mFence = Fence::NO_FENCE;
     mSlots[slot].mEglDisplay = EGL_NO_DISPLAY;
+#endif
 
     if (mLastQueuedSlot == slot) {
         mLastQueuedSlot = INVALID_BUFFER_SLOT;
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 39209f9..2e7cef0 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -451,8 +451,10 @@
     }
 
     status_t returnFlags = NO_ERROR;
+#if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP)
     EGLDisplay eglDisplay = EGL_NO_DISPLAY;
     EGLSyncKHR eglFence = EGL_NO_SYNC_KHR;
+#endif
     bool attachedByConsumer = false;
 
     sp<IConsumerListener> listener;
@@ -569,8 +571,10 @@
             mSlots[found].mAcquireCalled = false;
             mSlots[found].mGraphicBuffer = nullptr;
             mSlots[found].mRequestBufferCalled = false;
+#if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP)
             mSlots[found].mEglDisplay = EGL_NO_DISPLAY;
             mSlots[found].mEglFence = EGL_NO_SYNC_KHR;
+#endif
             mSlots[found].mFence = Fence::NO_FENCE;
             mCore->mBufferAge = 0;
             mCore->mIsAllocating = true;
@@ -595,14 +599,18 @@
                     found, buffer->width, buffer->height, buffer->format);
         }
 
+#if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP)
         eglDisplay = mSlots[found].mEglDisplay;
         eglFence = mSlots[found].mEglFence;
+#endif
         // Don't return a fence in shared buffer mode, except for the first
         // frame.
         *outFence = (mCore->mSharedBufferMode &&
                 mCore->mSharedBufferSlot == found) ?
                 Fence::NO_FENCE : mSlots[found].mFence;
+#if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP)
         mSlots[found].mEglFence = EGL_NO_SYNC_KHR;
+#endif
         mSlots[found].mFence = Fence::NO_FENCE;
 
         // If shared buffer mode has just been enabled, cache the slot of the
@@ -691,6 +699,7 @@
         returnFlags |= BUFFER_NEEDS_REALLOCATION;
     }
 
+#if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP)
     if (eglFence != EGL_NO_SYNC_KHR) {
         EGLint result = eglClientWaitSyncKHR(eglDisplay, eglFence, 0,
                 1000000000);
@@ -705,6 +714,7 @@
         }
         eglDestroySyncKHR(eglDisplay, eglFence);
     }
+#endif
 
     BQ_LOGV("dequeueBuffer: returning slot=%d/%" PRIu64 " buf=%p flags=%#x",
             *outSlot,
@@ -908,7 +918,9 @@
 
     mSlots[*outSlot].mGraphicBuffer = buffer;
     mSlots[*outSlot].mBufferState.attachProducer();
+#if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP)
     mSlots[*outSlot].mEglFence = EGL_NO_SYNC_KHR;
+#endif
     mSlots[*outSlot].mFence = Fence::NO_FENCE;
     mSlots[*outSlot].mRequestBufferCalled = true;
     mSlots[*outSlot].mAcquireCalled = false;
diff --git a/libs/gui/include/gui/BufferSlot.h b/libs/gui/include/gui/BufferSlot.h
index 5b32710..e83d2e3 100644
--- a/libs/gui/include/gui/BufferSlot.h
+++ b/libs/gui/include/gui/BufferSlot.h
@@ -174,26 +174,30 @@
 };
 
 struct BufferSlot {
-
     BufferSlot()
-    : mGraphicBuffer(nullptr),
-      mEglDisplay(EGL_NO_DISPLAY),
-      mBufferState(),
-      mRequestBufferCalled(false),
-      mFrameNumber(0),
-      mEglFence(EGL_NO_SYNC_KHR),
-      mFence(Fence::NO_FENCE),
-      mAcquireCalled(false),
-      mNeedsReallocation(false) {
+          : mGraphicBuffer(nullptr),
+#if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP)
+            mEglDisplay(EGL_NO_DISPLAY),
+#endif
+            mBufferState(),
+            mRequestBufferCalled(false),
+            mFrameNumber(0),
+#if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP)
+            mEglFence(EGL_NO_SYNC_KHR),
+#endif
+            mFence(Fence::NO_FENCE),
+            mAcquireCalled(false),
+            mNeedsReallocation(false) {
     }
 
     // mGraphicBuffer points to the buffer allocated for this slot or is NULL
     // if no buffer has been allocated.
     sp<GraphicBuffer> mGraphicBuffer;
 
+#if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP)
     // mEglDisplay is the EGLDisplay used to create EGLSyncKHR objects.
     EGLDisplay mEglDisplay;
-
+#endif
     // mBufferState is the current state of this buffer slot.
     BufferState mBufferState;
 
@@ -207,12 +211,14 @@
     // may be released before their release fence is signaled).
     uint64_t mFrameNumber;
 
+#if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_GL_FENCE_CLEANUP)
     // mEglFence is the EGL sync object that must signal before the buffer
     // associated with this buffer slot may be dequeued. It is initialized
     // to EGL_NO_SYNC_KHR when the buffer is created and may be set to a
     // new sync object in releaseBuffer.  (This is deprecated in favor of
     // mFence, below.)
     EGLSyncKHR mEglFence;
+#endif
 
     // mFence is a fence which will signal when work initiated by the
     // previous owner of the buffer is finished. When the buffer is FREE,