Add sideband streams to BufferQueue and related classes

Sideband streams are essentially a device-specific buffer queue that
bypasses the BufferQueue system. They can be used for situations with
hard real-time requirements like high-quality TV and video playback
with A/V sync. A handle to the stream is provided by the source HAL,
and attached to a BufferQueue. The sink HAL can read buffers via the
stream handle rather than acquiring individual buffers from the
BufferQueue.

Change-Id: Ib3f262eddfc520f4bbe3d9b91753ed7dd09d3a9b
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 474f633..0ca93c8 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -25,6 +25,7 @@
 
 #include <utils/Errors.h>
 #include <utils/misc.h>
+#include <utils/NativeHandle.h>
 #include <utils/String8.h>
 #include <utils/Thread.h>
 #include <utils/Trace.h>
@@ -942,12 +943,22 @@
         SharedBuffer const* sb = reg.getSharedBuffer(&visibleRegion.numRects);
         visibleRegion.rects = reinterpret_cast<hwc_rect_t const *>(sb->data());
     }
+    virtual void setSidebandStream(const sp<NativeHandle>& stream) {
+        ALOG_ASSERT(stream->handle() != NULL);
+        getLayer()->compositionType = HWC_SIDEBAND;
+        getLayer()->sidebandStream = stream->handle();
+    }
     virtual void setBuffer(const sp<GraphicBuffer>& buffer) {
         if (buffer == 0 || buffer->handle == 0) {
             getLayer()->compositionType = HWC_FRAMEBUFFER;
             getLayer()->flags |= HWC_SKIP_LAYER;
             getLayer()->handle = 0;
         } else {
+            if (getLayer()->compositionType == HWC_SIDEBAND) {
+                // If this was a sideband layer but the stream was removed, reset
+                // it to FRAMEBUFFER. The HWC can change it to OVERLAY in prepare.
+                getLayer()->compositionType = HWC_FRAMEBUFFER;
+            }
             getLayer()->handle = buffer->handle;
         }
     }
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 9f96113..9218bf6 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -45,9 +45,10 @@
 namespace android {
 // ---------------------------------------------------------------------------
 
-class GraphicBuffer;
 class Fence;
 class FloatRect;
+class GraphicBuffer;
+class NativeHandle;
 class Region;
 class String8;
 class SurfaceFlinger;
@@ -164,6 +165,7 @@
         virtual void setFrame(const Rect& frame) = 0;
         virtual void setCrop(const FloatRect& crop) = 0;
         virtual void setVisibleRegionScreen(const Region& reg) = 0;
+        virtual void setSidebandStream(const sp<NativeHandle>& stream) = 0;
         virtual void setBuffer(const sp<GraphicBuffer>& buffer) = 0;
         virtual void setAcquireFenceFd(int fenceFd) = 0;
         virtual void setPlaneAlpha(uint8_t alpha) = 0;
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index a1820ab..0f87066 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -458,6 +458,10 @@
     return mSource[SOURCE_SINK]->disconnect(api);
 }
 
+status_t VirtualDisplaySurface::setSidebandStream(const sp<NativeHandle>& /*stream*/) {
+    return INVALID_OPERATION;
+}
+
 void VirtualDisplaySurface::updateQueueBufferOutput(
         const QueueBufferOutput& qbo) {
     uint32_t w, h, transformHint, numPendingBuffers;
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 6899904..c2cd779 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -105,6 +105,7 @@
     virtual status_t connect(const sp<IBinder>& token,
             int api, bool producerControlledByApp, QueueBufferOutput* output);
     virtual status_t disconnect(int api);
+    virtual status_t setSidebandStream(const sp<NativeHandle>& stream);
 
     //
     // Utility methods
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 465d376..019d892 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -27,6 +27,7 @@
 
 #include <utils/Errors.h>
 #include <utils/Log.h>
+#include <utils/NativeHandle.h>
 #include <utils/StopWatch.h>
 #include <utils/Trace.h>
 
@@ -66,6 +67,7 @@
         mFormat(PIXEL_FORMAT_NONE),
         mTransactionFlags(0),
         mQueuedFrames(0),
+        mSidebandStreamChanged(false),
         mCurrentTransform(0),
         mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
         mCurrentOpacity(true),
@@ -118,7 +120,7 @@
     mBufferQueue = new SurfaceTextureLayer(mFlinger);
     mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(mBufferQueue, mTextureName);
     mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
-    mSurfaceFlingerConsumer->setFrameAvailableListener(this);
+    mSurfaceFlingerConsumer->setContentsChangedListener(this);
     mSurfaceFlingerConsumer->setName(mName);
 
 #ifdef TARGET_DISABLE_TRIPLE_BUFFERING
@@ -158,6 +160,13 @@
     mFlinger->signalLayerUpdate();
 }
 
+void Layer::onSidebandStreamChanged() {
+    if (android_atomic_release_cas(false, true, &mSidebandStreamChanged) == 0) {
+        // mSidebandStreamChanged was false
+        mFlinger->signalLayerUpdate();
+    }
+}
+
 // called with SurfaceFlinger::mStateLock from the drawing thread after
 // the layer has been remove from the current state list (and just before
 // it's removed from the drawing state list)
@@ -413,9 +422,13 @@
     Region visible = tr.transform(visibleRegion.intersect(hw->getViewport()));
     layer.setVisibleRegionScreen(visible);
 
-    // NOTE: buffer can be NULL if the client never drew into this
-    // layer yet, or if we ran out of memory
-    layer.setBuffer(mActiveBuffer);
+    if (mSidebandStream.get()) {
+        layer.setSidebandStream(mSidebandStream);
+    } else {
+        // NOTE: buffer can be NULL if the client never drew into this
+        // layer yet, or if we ran out of memory
+        layer.setBuffer(mActiveBuffer);
+    }
 }
 
 void Layer::setAcquireFence(const sp<const DisplayDevice>& /* hw */,
@@ -907,7 +920,7 @@
 
 bool Layer::onPreComposition() {
     mRefreshPending = false;
-    return mQueuedFrames > 0;
+    return mQueuedFrames > 0 || mSidebandStreamChanged;
 }
 
 void Layer::onPostComposition() {
@@ -950,6 +963,11 @@
 {
     ATRACE_CALL();
 
+    if (android_atomic_acquire_cas(true, false, &mSidebandStreamChanged) == 0) {
+        // mSidebandStreamChanged was true
+        mSidebandStream = mSurfaceFlingerConsumer->getSidebandStream();
+    }
+
     Region outDirtyRegion;
     if (mQueuedFrames > 0) {
 
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 9283eaa..43de999 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -66,7 +66,7 @@
  * This also implements onFrameAvailable(), which notifies SurfaceFlinger
  * that new data has arrived.
  */
-class Layer : public SurfaceFlingerConsumer::FrameAvailableListener {
+class Layer : public SurfaceFlingerConsumer::ContentsChangedListener {
     static int32_t sSequence;
 
 public:
@@ -313,8 +313,9 @@
 
 
 private:
-    // Interface implementation for SurfaceFlingerConsumer::FrameAvailableListener
+    // Interface implementation for SurfaceFlingerConsumer::ContentsChangedListener
     virtual void onFrameAvailable();
+    virtual void onSidebandStreamChanged();
 
     void commitTransaction();
 
@@ -351,10 +352,12 @@
 
     // thread-safe
     volatile int32_t mQueuedFrames;
+    volatile int32_t mSidebandStreamChanged; // used like an atomic boolean
     FrameTracker mFrameTracker;
 
     // main thread
     sp<GraphicBuffer> mActiveBuffer;
+    sp<NativeHandle> mSidebandStream;
     Rect mCurrentCrop;
     uint32_t mCurrentTransform;
     uint32_t mCurrentScalingMode;
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index 6dc093e..a412543 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -21,8 +21,9 @@
 
 #include <private/gui/SyncFeatures.h>
 
-#include <utils/Trace.h>
 #include <utils/Errors.h>
+#include <utils/NativeHandle.h>
+#include <utils/Trace.h>
 
 namespace android {
 
@@ -112,6 +113,10 @@
     return mTransformToDisplayInverse;
 }
 
+sp<NativeHandle> SurfaceFlingerConsumer::getSidebandStream() const {
+    return mConsumer->getSidebandStream();
+}
+
 // We need to determine the time when a buffer acquired now will be
 // displayed.  This can be calculated:
 //   time when previous buffer's actual-present fence was signaled
@@ -154,6 +159,26 @@
     return prevVsync + hwcLatency * vsyncPeriod + extraPadding;
 }
 
+void SurfaceFlingerConsumer::setContentsChangedListener(
+        const wp<ContentsChangedListener>& listener) {
+    setFrameAvailableListener(listener);
+    Mutex::Autolock lock(mMutex);
+    mContentsChangedListener = listener;
+}
+
+void SurfaceFlingerConsumer::onSidebandStreamChanged() {
+    sp<ContentsChangedListener> listener;
+    {   // scope for the lock
+        Mutex::Autolock lock(mMutex);
+        ALOG_ASSERT(mFrameAvailableListener.unsafe_get() == mContentsChangedListener.unsafe_get());
+        listener = mContentsChangedListener.promote();
+    }
+
+    if (listener != NULL) {
+        listener->onSidebandStreamChanged();
+    }
+}
+
 // ---------------------------------------------------------------------------
 }; // namespace android
 
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h
index 688ad32..becd5d3 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.h
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.h
@@ -27,6 +27,10 @@
  */
 class SurfaceFlingerConsumer : public GLConsumer {
 public:
+    struct ContentsChangedListener: public FrameAvailableListener {
+        virtual void onSidebandStreamChanged() = 0;
+    };
+
     SurfaceFlingerConsumer(const sp<BufferQueue>& bq, uint32_t tex)
         : GLConsumer(bq, tex, GLConsumer::TEXTURE_EXTERNAL, false)
     {}
@@ -54,9 +58,19 @@
     // must be called from SF main thread
     bool getTransformToDisplayInverse() const;
 
+    // Sets the contents changed listener. This should be used instead of
+    // ConsumerBase::setFrameAvailableListener().
+    void setContentsChangedListener(const wp<ContentsChangedListener>& listener);
+
+    sp<NativeHandle> getSidebandStream() const;
+
 private:
     nsecs_t computeExpectedPresent();
 
+    virtual void onSidebandStreamChanged();
+
+    wp<ContentsChangedListener> mContentsChangedListener;
+
     // Indicates this buffer must be transformed by the inverse transform of the screen
     // it is displayed onto. This is applied after GLConsumer::mCurrentTransform.
     // This must be set/read from SurfaceFlinger's main thread.