Add BufferQueueInterposer and use it for virtual displays

BufferQueueInterposer allows a client to tap into a
IGraphicBufferProducer-based buffer queue, and modify buffers as they
pass from producer to consumer. VirtualDisplaySurface uses this to
layer HWC composition on top of GLES composition before passing the
buffer to the virtual display consumer.

Bug: 8384764
Change-Id: I61ae54f3d90de6a35f4f02bb5e64e7cc88e1cb83
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index d30e9bf..433e1eb 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#include <gui/IGraphicBufferProducer.h>
 #include "VirtualDisplaySurface.h"
+#include "HWComposer.h"
 
 // ---------------------------------------------------------------------------
 namespace android {
@@ -25,15 +25,22 @@
         const sp<IGraphicBufferProducer>& sink, const String8& name)
 :   mHwc(hwc),
     mDisplayId(disp),
-    mSink(sink),
-    mName(name)
+    mSource(new BufferQueueInterposer(sink, name)),
+    mName(name),
+    mReleaseFence(Fence::NO_FENCE)
 {}
 
 VirtualDisplaySurface::~VirtualDisplaySurface() {
+    if (mAcquiredBuffer != NULL) {
+        status_t result = mSource->releaseBuffer(mReleaseFence);
+        ALOGE_IF(result != NO_ERROR, "VirtualDisplaySurface \"%s\": "
+                "failed to release previous buffer: %d",
+                mName.string(), result);
+    }
 }
 
 sp<IGraphicBufferProducer> VirtualDisplaySurface::getIGraphicBufferProducer() const {
-    return mSink;
+    return mSource;
 }
 
 status_t VirtualDisplaySurface::compositionComplete() {
@@ -41,13 +48,49 @@
 }
 
 status_t VirtualDisplaySurface::advanceFrame() {
-    return NO_ERROR;
+    Mutex::Autolock lock(mMutex);
+    status_t result = NO_ERROR;
+
+    if (mAcquiredBuffer != NULL) {
+        result = mSource->releaseBuffer(mReleaseFence);
+        ALOGE_IF(result != NO_ERROR, "VirtualDisplaySurface \"%s\": "
+                "failed to release previous buffer: %d",
+                mName.string(), result);
+        mAcquiredBuffer.clear();
+        mReleaseFence = Fence::NO_FENCE;
+    }
+
+    sp<Fence> fence;
+    result = mSource->acquireBuffer(&mAcquiredBuffer, &fence);
+    if (result == BufferQueueInterposer::NO_BUFFER_AVAILABLE) {
+        result = mSource->pullEmptyBuffer();
+        if (result != NO_ERROR)
+            return result;
+        result = mSource->acquireBuffer(&mAcquiredBuffer, &fence);
+    }
+    if (result != NO_ERROR)
+        return result;
+
+    return mHwc.fbPost(mDisplayId, fence, mAcquiredBuffer);
 }
 
 status_t VirtualDisplaySurface::setReleaseFenceFd(int fenceFd) {
     if (fenceFd >= 0) {
-        ALOGW("[%s] unexpected release fence", mName.string());
-        close(fenceFd);
+        sp<Fence> fence(new Fence(fenceFd));
+        Mutex::Autolock lock(mMutex);
+        sp<Fence> mergedFence = Fence::merge(
+                String8::format("VirtualDisplaySurface \"%s\"",
+                        mName.string()),
+                mReleaseFence, fence);
+        if (!mergedFence->isValid()) {
+            ALOGE("VirtualDisplaySurface \"%s\": failed to merge release fence",
+                    mName.string());
+            // synchronization is broken, the best we can do is hope fences
+            // signal in order so the new fence will act like a union
+            mReleaseFence = fence;
+            return BAD_VALUE;
+        }
+        mReleaseFence = mergedFence;
     }
     return NO_ERROR;
 }