From 399184a4cd728ea1421fb0bc1722274a29e38f4a Mon Sep 17 00:00:00 2001 From: Jesse Hall Date: Mon, 3 Mar 2014 15:42:54 -0800 Subject: [PATCH] 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 --- include/gui/BufferQueue.h | 16 ++++++++++ include/gui/BufferQueueConsumer.h | 3 ++ include/gui/BufferQueueCore.h | 4 +++ include/gui/BufferQueueProducer.h | 12 ++++++++ include/gui/ConsumerBase.h | 9 ++++-- include/gui/IConsumerListener.h | 6 ++++ include/gui/IGraphicBufferConsumer.h | 8 +++-- include/gui/IGraphicBufferProducer.h | 13 ++++++++ include/gui/Surface.h | 13 ++++++++ libs/gui/BufferQueue.cpp | 15 ++++++++++ libs/gui/BufferQueueConsumer.cpp | 4 +++ libs/gui/BufferQueueProducer.cpp | 7 +++++ libs/gui/ConsumerBase.cpp | 3 ++ libs/gui/IConsumerListener.cpp | 13 +++++++- libs/gui/IGraphicBufferConsumer.cpp | 16 ++++++++++ libs/gui/IGraphicBufferProducer.cpp | 30 ++++++++++++++++++- .../DisplayHardware/HWComposer.cpp | 11 +++++++ .../DisplayHardware/HWComposer.h | 4 ++- .../DisplayHardware/VirtualDisplaySurface.cpp | 4 +++ .../DisplayHardware/VirtualDisplaySurface.h | 1 + services/surfaceflinger/Layer.cpp | 28 +++++++++++++---- services/surfaceflinger/Layer.h | 7 +++-- .../surfaceflinger/SurfaceFlingerConsumer.cpp | 27 ++++++++++++++++- .../surfaceflinger/SurfaceFlingerConsumer.h | 14 +++++++++ 24 files changed, 252 insertions(+), 16 deletions(-) diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h index 7eaf84223..867486bdb 100644 --- a/include/gui/BufferQueue.h +++ b/include/gui/BufferQueue.h @@ -67,6 +67,7 @@ public: virtual ~ProxyConsumerListener(); virtual void onFrameAvailable(); virtual void onBuffersReleased(); + virtual void onSidebandStreamChanged(); private: // mConsumerListener is a weak reference to the IConsumerListener. This is // the raison d'etre of ProxyConsumerListener. @@ -204,6 +205,18 @@ public: // connected to the specified producer API. virtual status_t disconnect(int api); + // Attaches a sideband buffer stream to the BufferQueue. + // + // A sideband stream is a device-specific mechanism for passing buffers + // from the producer to the consumer without using dequeueBuffer/ + // queueBuffer. If a sideband stream is present, the consumer can choose + // whether to acquire buffers from the sideband stream or from the queued + // buffers. + // + // Passing NULL or a different stream handle will detach the previous + // handle if any. + virtual status_t setSidebandStream(const sp& stream); + /* * IGraphicBufferConsumer interface */ @@ -306,6 +319,9 @@ public: // NATIVE_WINDOW_TRANSFORM_ROT_90. The default is 0 (no transform). virtual status_t setTransformHint(uint32_t hint); + // Retrieve the BufferQueue's sideband stream, if any. + virtual sp getSidebandStream() const; + // dump our state in a String virtual void dump(String8& result, const char* prefix) const; diff --git a/include/gui/BufferQueueConsumer.h b/include/gui/BufferQueueConsumer.h index 20db98cd1..2bdcf28e2 100644 --- a/include/gui/BufferQueueConsumer.h +++ b/include/gui/BufferQueueConsumer.h @@ -133,6 +133,9 @@ public: // NATIVE_WINDOW_TRANSFORM_ROT_90. The default is 0 (no transform). virtual status_t setTransformHint(uint32_t hint); + // Retrieve the sideband buffer stream, if any. + virtual sp getSidebandStream() const; + // dump our state in a String virtual void dump(String8& result, const char* prefix) const; diff --git a/include/gui/BufferQueueCore.h b/include/gui/BufferQueueCore.h index f4341f81f..89f277996 100644 --- a/include/gui/BufferQueueCore.h +++ b/include/gui/BufferQueueCore.h @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -230,6 +231,9 @@ private: // mTransformHint is used to optimize for screen rotations. uint32_t mTransformHint; + // mSidebandStream is a handle to the sideband buffer stream, if any + sp mSidebandStream; + }; // class BufferQueueCore } // namespace android diff --git a/include/gui/BufferQueueProducer.h b/include/gui/BufferQueueProducer.h index 8912097f7..250d33c94 100644 --- a/include/gui/BufferQueueProducer.h +++ b/include/gui/BufferQueueProducer.h @@ -147,6 +147,18 @@ public: // connected to the specified producer API. virtual status_t disconnect(int api); + // Attaches a sideband buffer stream to the IGraphicBufferProducer. + // + // A sideband stream is a device-specific mechanism for passing buffers + // from the producer to the consumer without using dequeueBuffer/ + // queueBuffer. If a sideband stream is present, the consumer can choose + // whether to acquire buffers from the sideband stream or from the queued + // buffers. + // + // Passing NULL or a different stream handle will detach the previous + // handle if any. + virtual status_t setSidebandStream(const sp& stream); + private: // This is required by the IBinder::DeathRecipient interface virtual void binderDied(const wp& who); diff --git a/include/gui/ConsumerBase.h b/include/gui/ConsumerBase.h index fb21185fd..100bb260f 100644 --- a/include/gui/ConsumerBase.h +++ b/include/gui/ConsumerBase.h @@ -101,11 +101,14 @@ protected: // Implementation of the IConsumerListener interface. These // calls are used to notify the ConsumerBase of asynchronous events in the - // BufferQueue. These methods should not need to be overridden by derived - // classes, but if they are overridden the ConsumerBase implementation - // must be called from the derived class. + // BufferQueue. The onFrameAvailable and onBuffersReleased methods should + // not need to be overridden by derived classes, but if they are overridden + // the ConsumerBase implementation must be called from the derived class. + // The ConsumerBase version of onSidebandStreamChanged does nothing and can + // be overriden by derived classes if they want the notification. virtual void onFrameAvailable(); virtual void onBuffersReleased(); + virtual void onSidebandStreamChanged(); // freeBufferLocked frees up the given buffer slot. If the slot has been // initialized this will release the reference to the GraphicBuffer in that diff --git a/include/gui/IConsumerListener.h b/include/gui/IConsumerListener.h index ac2f9bb56..260099e8d 100644 --- a/include/gui/IConsumerListener.h +++ b/include/gui/IConsumerListener.h @@ -57,6 +57,12 @@ public: // This is called without any lock held and can be called concurrently // by multiple threads. virtual void onBuffersReleased() = 0; /* Asynchronous */ + + // onSidebandStreamChanged is called to notify the buffer consumer that the + // BufferQueue's sideband buffer stream has changed. This is called when a + // stream is first attached and when it is either detached or replaced by a + // different stream. + virtual void onSidebandStreamChanged() = 0; /* Asynchronous */ }; diff --git a/include/gui/IGraphicBufferConsumer.h b/include/gui/IGraphicBufferConsumer.h index 9a6645cf2..67b2b04f0 100644 --- a/include/gui/IGraphicBufferConsumer.h +++ b/include/gui/IGraphicBufferConsumer.h @@ -30,9 +30,10 @@ namespace android { // ---------------------------------------------------------------------------- -class IConsumerListener; -class GraphicBuffer; class Fence; +class GraphicBuffer; +class IConsumerListener; +class NativeHandle; class IGraphicBufferConsumer : public IInterface { @@ -266,6 +267,9 @@ public: // Return of a value other than NO_ERROR means an unknown error has occurred. virtual status_t setTransformHint(uint32_t hint) = 0; + // Retrieve the sideband buffer stream, if any. + virtual sp getSidebandStream() const = 0; + // dump state into a string virtual void dump(String8& result, const char* prefix) const = 0; diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h index 70025308c..3fe564d60 100644 --- a/include/gui/IGraphicBufferProducer.h +++ b/include/gui/IGraphicBufferProducer.h @@ -32,6 +32,7 @@ namespace android { // ---------------------------------------------------------------------------- +class NativeHandle; class Surface; /* @@ -347,6 +348,18 @@ public: // * api was out of range (see above). // * DEAD_OBJECT - the token is hosted by an already-dead process virtual status_t disconnect(int api) = 0; + + // Attaches a sideband buffer stream to the IGraphicBufferProducer. + // + // A sideband stream is a device-specific mechanism for passing buffers + // from the producer to the consumer without using dequeueBuffer/ + // queueBuffer. If a sideband stream is present, the consumer can choose + // whether to acquire buffers from the sideband stream or from the queued + // buffers. + // + // Passing NULL or a different stream handle will detach the previous + // handle if any. + virtual status_t setSidebandStream(const sp& stream) = 0; }; // ---------------------------------------------------------------------------- diff --git a/include/gui/Surface.h b/include/gui/Surface.h index 6f8a97c80..d8e975694 100644 --- a/include/gui/Surface.h +++ b/include/gui/Surface.h @@ -78,6 +78,19 @@ public: return surface != NULL && surface->getIGraphicBufferProducer() != NULL; } + /* Attaches a sideband buffer stream to the Surface's IGraphicBufferProducer. + * + * A sideband stream is a device-specific mechanism for passing buffers + * from the producer to the consumer without using dequeueBuffer/ + * queueBuffer. If a sideband stream is present, the consumer can choose + * whether to acquire buffers from the sideband stream or from the queued + * buffers. + * + * Passing NULL or a different stream handle will detach the previous + * handle if any. + */ + void setSidebandStream(const sp& stream); + protected: virtual ~Surface(); diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index af857fd3e..8584dc9b3 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -93,6 +93,10 @@ status_t BufferQueue::disconnect(int api) { return mProducer->disconnect(api); } +status_t BufferQueue::setSidebandStream(const sp& stream) { + return mProducer->setSidebandStream(stream); +} + status_t BufferQueue::acquireBuffer(BufferItem* buffer, nsecs_t presentWhen) { return mConsumer->acquireBuffer(buffer, presentWhen); } @@ -148,8 +152,19 @@ status_t BufferQueue::setTransformHint(uint32_t hint) { return mConsumer->setTransformHint(hint); } +sp BufferQueue::getSidebandStream() const { + return mConsumer->getSidebandStream(); +} + void BufferQueue::dump(String8& result, const char* prefix) const { mConsumer->dump(result, prefix); } +void BufferQueue::ProxyConsumerListener::onSidebandStreamChanged() { + sp listener(mConsumerListener.promote()); + if (listener != NULL) { + listener->onSidebandStreamChanged(); + } +} + }; // namespace android diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp index dc7aa157f..e34f716c6 100644 --- a/libs/gui/BufferQueueConsumer.cpp +++ b/libs/gui/BufferQueueConsumer.cpp @@ -395,6 +395,10 @@ status_t BufferQueueConsumer::setTransformHint(uint32_t hint) { return NO_ERROR; } +sp BufferQueueConsumer::getSidebandStream() const { + return mCore->mSidebandStream; +} + void BufferQueueConsumer::dump(String8& result, const char* prefix) const { mCore->dump(result, prefix); } diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 0e9de88a1..0ff7b80bc 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -674,6 +674,7 @@ status_t BufferQueueProducer::disconnect(int api) { } mCore->mConnectedProducerToken = NULL; mCore->mConnectedApi = BufferQueueCore::NO_CONNECTED_API; + mCore->mSidebandStream.clear(); mCore->mDequeueCondition.broadcast(); listener = mCore->mConsumerListener; } else { @@ -697,6 +698,12 @@ status_t BufferQueueProducer::disconnect(int api) { return status; } +status_t BufferQueueProducer::setSidebandStream(const sp& stream) { + Mutex::Autolock _l(mCore->mMutex); + mCore->mSidebandStream = stream; + return NO_ERROR; +} + void BufferQueueProducer::binderDied(const wp& /* who */) { // If we're here, it means that a producer we were connected to died. // We're guaranteed that we are still connected to it because we remove diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp index c5900aa5b..b6adc54d7 100644 --- a/libs/gui/ConsumerBase.cpp +++ b/libs/gui/ConsumerBase.cpp @@ -130,6 +130,9 @@ void ConsumerBase::onBuffersReleased() { } } +void ConsumerBase::onSidebandStreamChanged() { +} + void ConsumerBase::abandon() { CB_LOGV("abandon"); Mutex::Autolock lock(mMutex); diff --git a/libs/gui/IConsumerListener.cpp b/libs/gui/IConsumerListener.cpp index 53044624a..4ccf0ac82 100644 --- a/libs/gui/IConsumerListener.cpp +++ b/libs/gui/IConsumerListener.cpp @@ -28,7 +28,8 @@ namespace android { enum { ON_FRAME_AVAILABLE = IBinder::FIRST_CALL_TRANSACTION, - ON_BUFFER_RELEASED + ON_BUFFER_RELEASED, + ON_SIDEBAND_STREAM_CHANGED, }; class BpConsumerListener : public BpInterface @@ -49,6 +50,12 @@ public: data.writeInterfaceToken(IConsumerListener::getInterfaceDescriptor()); remote()->transact(ON_BUFFER_RELEASED, data, &reply, IBinder::FLAG_ONEWAY); } + + virtual void onSidebandStreamChanged() { + Parcel data, reply; + data.writeInterfaceToken(IConsumerListener::getInterfaceDescriptor()); + remote()->transact(ON_SIDEBAND_STREAM_CHANGED, data, &reply, IBinder::FLAG_ONEWAY); + } }; IMPLEMENT_META_INTERFACE(ConsumerListener, "android.gui.IConsumerListener"); @@ -67,6 +74,10 @@ status_t BnConsumerListener::onTransact( CHECK_INTERFACE(IConsumerListener, data, reply); onBuffersReleased(); return NO_ERROR; + case ON_SIDEBAND_STREAM_CHANGED: + CHECK_INTERFACE(IConsumerListener, data, reply); + onSidebandStreamChanged(); + return NO_ERROR; } return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp index 876c89568..c97d15be1 100644 --- a/libs/gui/IGraphicBufferConsumer.cpp +++ b/libs/gui/IGraphicBufferConsumer.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -195,6 +196,7 @@ enum { SET_DEFAULT_BUFFER_FORMAT, SET_CONSUMER_USAGE_BITS, SET_TRANSFORM_HINT, + GET_SIDEBAND_STREAM, DUMP, }; @@ -354,6 +356,20 @@ public: return reply.readInt32(); } + virtual sp getSidebandStream() const { + Parcel data, reply; + status_t err; + data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + if ((err = remote()->transact(GET_SIDEBAND_STREAM, data, &reply)) != NO_ERROR) { + return NULL; + } + sp stream; + if (reply.readInt32()) { + stream = NativeHandle::create(reply.readNativeHandle()); + } + return stream; + } + virtual void dump(String8& result, const char* prefix) const { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index 0f461e59c..efbe87862 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -18,9 +18,10 @@ #include #include +#include #include -#include #include +#include #include #include @@ -39,6 +40,7 @@ enum { QUERY, CONNECT, DISCONNECT, + SET_SIDEBAND_STREAM, }; class BpGraphicBufferProducer : public BpInterface @@ -169,6 +171,22 @@ public: result = reply.readInt32(); return result; } + + virtual status_t setSidebandStream(const sp& stream) { + Parcel data, reply; + status_t result; + data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); + if (stream.get()) { + data.writeInt32(true); + data.writeNativeHandle(stream->handle()); + } else { + data.writeInt32(false); + } + if ((result = remote()->transact(SET_SIDEBAND_STREAM, data, &reply)) == NO_ERROR) { + result = reply.readInt32(); + } + return result; + } }; IMPLEMENT_META_INTERFACE(GraphicBufferProducer, "android.gui.IGraphicBufferProducer"); @@ -263,6 +281,16 @@ status_t BnGraphicBufferProducer::onTransact( reply->writeInt32(res); return NO_ERROR; } break; + case SET_SIDEBAND_STREAM: { + CHECK_INTERFACE(IGraphicBufferProducer, data, reply); + sp stream; + if (data.readInt32()) { + stream = NativeHandle::create(data.readNativeHandle()); + } + status_t result = setSidebandStream(stream); + reply->writeInt32(result); + return NO_ERROR; + } break; } return BBinder::onTransact(code, data, reply, flags); } diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 474f63342..0ca93c8ce 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -942,12 +943,22 @@ public: SharedBuffer const* sb = reg.getSharedBuffer(&visibleRegion.numRects); visibleRegion.rects = reinterpret_cast(sb->data()); } + virtual void setSidebandStream(const sp& stream) { + ALOG_ASSERT(stream->handle() != NULL); + getLayer()->compositionType = HWC_SIDEBAND; + getLayer()->sidebandStream = stream->handle(); + } virtual void setBuffer(const sp& 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 9f961139b..9218bf609 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -45,9 +45,10 @@ struct framebuffer_device_t; namespace android { // --------------------------------------------------------------------------- -class GraphicBuffer; class Fence; class FloatRect; +class GraphicBuffer; +class NativeHandle; class Region; class String8; class SurfaceFlinger; @@ -164,6 +165,7 @@ public: 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& stream) = 0; virtual void setBuffer(const sp& 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 a1820abc6..0f87066b8 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp @@ -458,6 +458,10 @@ status_t VirtualDisplaySurface::disconnect(int api) { return mSource[SOURCE_SINK]->disconnect(api); } +status_t VirtualDisplaySurface::setSidebandStream(const sp& /*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 68999049d..c2cd77996 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h @@ -105,6 +105,7 @@ private: virtual status_t connect(const sp& token, int api, bool producerControlledByApp, QueueBufferOutput* output); virtual status_t disconnect(int api); + virtual status_t setSidebandStream(const sp& stream); // // Utility methods diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 465d3764a..019d89223 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -66,6 +67,7 @@ Layer::Layer(SurfaceFlinger* flinger, const sp& client, mFormat(PIXEL_FORMAT_NONE), mTransactionFlags(0), mQueuedFrames(0), + mSidebandStreamChanged(false), mCurrentTransform(0), mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), mCurrentOpacity(true), @@ -118,7 +120,7 @@ void Layer::onFirstRef() { 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 @@ void Layer::onFrameAvailable() { 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 @@ void Layer::setPerFrameData(const sp& hw, 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& /* hw */, @@ -907,7 +920,7 @@ bool Layer::setLayerStack(uint32_t layerStack) { bool Layer::onPreComposition() { mRefreshPending = false; - return mQueuedFrames > 0; + return mQueuedFrames > 0 || mSidebandStreamChanged; } void Layer::onPostComposition() { @@ -950,6 +963,11 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions) { 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 9283eaa8a..43de9991a 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -66,7 +66,7 @@ class SurfaceFlinger; * 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 @@ protected: private: - // Interface implementation for SurfaceFlingerConsumer::FrameAvailableListener + // Interface implementation for SurfaceFlingerConsumer::ContentsChangedListener virtual void onFrameAvailable(); + virtual void onSidebandStreamChanged(); void commitTransaction(); @@ -351,10 +352,12 @@ private: // thread-safe volatile int32_t mQueuedFrames; + volatile int32_t mSidebandStreamChanged; // used like an atomic boolean FrameTracker mFrameTracker; // main thread sp mActiveBuffer; + sp mSidebandStream; Rect mCurrentCrop; uint32_t mCurrentTransform; uint32_t mCurrentScalingMode; diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp index 6dc093e78..a412543ef 100644 --- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp +++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp @@ -21,8 +21,9 @@ #include -#include #include +#include +#include namespace android { @@ -112,6 +113,10 @@ bool SurfaceFlingerConsumer::getTransformToDisplayInverse() const { return mTransformToDisplayInverse; } +sp 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 @@ nsecs_t SurfaceFlingerConsumer::computeExpectedPresent() return prevVsync + hwcLatency * vsyncPeriod + extraPadding; } +void SurfaceFlingerConsumer::setContentsChangedListener( + const wp& listener) { + setFrameAvailableListener(listener); + Mutex::Autolock lock(mMutex); + mContentsChangedListener = listener; +} + +void SurfaceFlingerConsumer::onSidebandStreamChanged() { + sp 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 688ad3224..becd5d365 100644 --- a/services/surfaceflinger/SurfaceFlingerConsumer.h +++ b/services/surfaceflinger/SurfaceFlingerConsumer.h @@ -27,6 +27,10 @@ namespace android { */ class SurfaceFlingerConsumer : public GLConsumer { public: + struct ContentsChangedListener: public FrameAvailableListener { + virtual void onSidebandStreamChanged() = 0; + }; + SurfaceFlingerConsumer(const sp& bq, uint32_t tex) : GLConsumer(bq, tex, GLConsumer::TEXTURE_EXTERNAL, false) {} @@ -54,9 +58,19 @@ public: // 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& listener); + + sp getSidebandStream() const; + private: nsecs_t computeExpectedPresent(); + virtual void onSidebandStreamChanged(); + + wp 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.