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.