Pass fence to HWC on first use of buffer

Also do a CPU-wait on the fence before using it for GL composition.

Change-Id: I0f645a42a44803276cae11b904e5a26d65871562
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index 622724e..66c390a 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -172,6 +172,10 @@
     // getCurrentScalingMode returns the scaling mode of the current buffer.
     uint32_t getCurrentScalingMode() const;
 
+    // getCurrentFence returns the fence indicating when the current buffer is
+    // ready to be read from.
+    sp<Fence> getCurrentFence() const;
+
     // isSynchronousMode returns whether the SurfaceTexture is currently in
     // synchronous mode.
     bool isSynchronousMode() const;
@@ -303,6 +307,9 @@
     // set to each time updateTexImage is called.
     uint32_t mCurrentScalingMode;
 
+    // mCurrentFence is the fence received from BufferQueue in updateTexImage.
+    sp<Fence> mCurrentFence;
+
     // mCurrentTransformMatrix is the transform matrix for the current texture.
     // It gets computed by computeTransformMatrix each time updateTexImage is
     // called.
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 435a665..9c76e6e 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -260,14 +260,6 @@
             }
         }
 
-        // Temporary; fence will be provided to clients soon
-        if (item.mFence.get()) {
-            err = item.mFence->wait(Fence::TIMEOUT_NEVER);
-            if (err != OK) {
-                ST_LOGE("updateTexImage: failure waiting for fence: %d", err);
-            }
-        }
-
         if (err == NO_ERROR) {
             GLint error;
             while ((error = glGetError()) != GL_NO_ERROR) {
@@ -322,6 +314,7 @@
         mCurrentTransform = item.mTransform;
         mCurrentScalingMode = item.mScalingMode;
         mCurrentTimestamp = item.mTimestamp;
+        mCurrentFence = item.mFence;
         computeCurrentTransformMatrix();
     } else  {
         if (err < 0) {
@@ -733,6 +726,11 @@
     return mCurrentScalingMode;
 }
 
+sp<Fence> SurfaceTexture::getCurrentFence() const {
+    Mutex::Autolock lock(mMutex);
+    return mCurrentFence;
+}
+
 bool SurfaceTexture::isSynchronousMode() const {
     Mutex::Autolock lock(mMutex);
     return mBufferQueue->isSynchronousMode();
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 7c09ab2..4ed692f 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -350,6 +350,12 @@
         // not supported on VERSION_03
         return -1;
     }
+    virtual void setAcquireFenceFd(int fenceFd) {
+        if (fenceFd != -1) {
+            ALOGE("HWC 0.x can't handle acquire fences");
+            close(fenceFd);
+        }
+    }
 
     virtual void setDefaultState() {
         getLayer()->compositionType = HWC_FRAMEBUFFER;
@@ -416,6 +422,9 @@
         getLayer()->releaseFenceFd = -1;
         return fd;
     }
+    virtual void setAcquireFenceFd(int fenceFd) {
+        getLayer()->acquireFenceFd = fenceFd;
+    }
 
     virtual void setDefaultState() {
         getLayer()->compositionType = HWC_FRAMEBUFFER;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index cb4c2db..a662b25 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -109,6 +109,7 @@
         virtual void setCrop(const Rect& crop) = 0;
         virtual void setVisibleRegionScreen(const Region& reg) = 0;
         virtual void setBuffer(const sp<GraphicBuffer>& buffer) = 0;
+        virtual void setAcquireFenceFd(int fenceFd) = 0;
     };
 
     /*
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 6aba16a..5b9327d 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -60,6 +60,7 @@
         mCurrentOpacity(true),
         mRefreshPending(false),
         mFrameLatencyNeeded(false),
+        mNeedHwcFence(false),
         mFrameLatencyOffset(0),
         mFormat(PIXEL_FORMAT_NONE),
         mGLExtensions(GLExtensions::getInstance()),
@@ -299,6 +300,20 @@
     // NOTE: buffer can be NULL if the client never drew into this
     // layer yet, or if we ran out of memory
     layer.setBuffer(buffer);
+
+    if (mNeedHwcFence) {
+        sp<Fence> fence = mSurfaceTexture->getCurrentFence();
+        if (fence.get()) {
+            int fenceFd = fence->dup();
+            if (fenceFd == -1) {
+                ALOGW("failed to dup layer fence, skipping sync: %d", errno);
+            }
+            layer.setAcquireFenceFd(fenceFd);
+        }
+        mNeedHwcFence = false;
+    } else {
+        layer.setAcquireFenceFd(-1);
+    }
 }
 
 void Layer::onDraw(const DisplayHardware& hw, const Region& clip) const
@@ -333,6 +348,15 @@
         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);
+        // Go ahead and draw the buffer anyway; no matter what we do the screen
+        // is probably going to have something visibly wrong.
+    }
+
     if (!isProtected()) {
         // TODO: we could be more subtle with isFixedSize()
         const bool useFiltering = getFiltering() || needsFiltering() || isFixedSize();
@@ -627,6 +651,7 @@
 
         mRefreshPending = true;
         mFrameLatencyNeeded = true;
+        mNeedHwcFence = true;
         if (oldActiveBuffer == NULL) {
              // the first time we receive a buffer, we need to trigger a
              // geometry invalidation.
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index d47f2e8..29515f0 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -120,6 +120,7 @@
     bool mCurrentOpacity;
     bool mRefreshPending;
     bool mFrameLatencyNeeded;
+    bool mNeedHwcFence;
     int mFrameLatencyOffset;
 
     struct Statistics {