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
This commit is contained in:
Jesse Hall 2014-03-03 15:42:54 -08:00
parent 05fe2d1cfb
commit 399184a4cd
24 changed files with 252 additions and 16 deletions

View File

@ -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<NativeHandle>& 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<NativeHandle> getSidebandStream() const;
// dump our state in a String
virtual void dump(String8& result, const char* prefix) const;

View File

@ -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<NativeHandle> getSidebandStream() const;
// dump our state in a String
virtual void dump(String8& result, const char* prefix) const;

View File

@ -22,6 +22,7 @@
#include <utils/Condition.h>
#include <utils/Mutex.h>
#include <utils/NativeHandle.h>
#include <utils/RefBase.h>
#include <utils/String8.h>
#include <utils/StrongPointer.h>
@ -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<NativeHandle> mSidebandStream;
}; // class BufferQueueCore
} // namespace android

View File

@ -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<NativeHandle>& stream);
private:
// This is required by the IBinder::DeathRecipient interface
virtual void binderDied(const wp<IBinder>& who);

View File

@ -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

View File

@ -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 */
};

View File

@ -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<NativeHandle> getSidebandStream() const = 0;
// dump state into a string
virtual void dump(String8& result, const char* prefix) const = 0;

View File

@ -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<NativeHandle>& stream) = 0;
};
// ----------------------------------------------------------------------------

View File

@ -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<NativeHandle>& stream);
protected:
virtual ~Surface();

View File

@ -93,6 +93,10 @@ status_t BufferQueue::disconnect(int api) {
return mProducer->disconnect(api);
}
status_t BufferQueue::setSidebandStream(const sp<NativeHandle>& 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<NativeHandle> BufferQueue::getSidebandStream() const {
return mConsumer->getSidebandStream();
}
void BufferQueue::dump(String8& result, const char* prefix) const {
mConsumer->dump(result, prefix);
}
void BufferQueue::ProxyConsumerListener::onSidebandStreamChanged() {
sp<ConsumerListener> listener(mConsumerListener.promote());
if (listener != NULL) {
listener->onSidebandStreamChanged();
}
}
}; // namespace android

View File

@ -395,6 +395,10 @@ status_t BufferQueueConsumer::setTransformHint(uint32_t hint) {
return NO_ERROR;
}
sp<NativeHandle> BufferQueueConsumer::getSidebandStream() const {
return mCore->mSidebandStream;
}
void BufferQueueConsumer::dump(String8& result, const char* prefix) const {
mCore->dump(result, prefix);
}

View File

@ -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<NativeHandle>& stream) {
Mutex::Autolock _l(mCore->mMutex);
mCore->mSidebandStream = stream;
return NO_ERROR;
}
void BufferQueueProducer::binderDied(const wp<android::IBinder>& /* 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

View File

@ -130,6 +130,9 @@ void ConsumerBase::onBuffersReleased() {
}
}
void ConsumerBase::onSidebandStreamChanged() {
}
void ConsumerBase::abandon() {
CB_LOGV("abandon");
Mutex::Autolock lock(mMutex);

View File

@ -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<IConsumerListener>
@ -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);
}

View File

@ -24,6 +24,7 @@
#include <sys/types.h>
#include <utils/Errors.h>
#include <utils/NativeHandle.h>
#include <binder/Parcel.h>
#include <binder/IInterface.h>
@ -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<NativeHandle> 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<NativeHandle> 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());

View File

@ -18,9 +18,10 @@
#include <sys/types.h>
#include <utils/Errors.h>
#include <utils/NativeHandle.h>
#include <utils/RefBase.h>
#include <utils/Vector.h>
#include <utils/Timers.h>
#include <utils/Vector.h>
#include <binder/Parcel.h>
#include <binder/IInterface.h>
@ -39,6 +40,7 @@ enum {
QUERY,
CONNECT,
DISCONNECT,
SET_SIDEBAND_STREAM,
};
class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
@ -169,6 +171,22 @@ public:
result = reply.readInt32();
return result;
}
virtual status_t setSidebandStream(const sp<NativeHandle>& 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<NativeHandle> 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);
}

View File

@ -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 @@ public:
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;
}
}

View File

@ -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<NativeHandle>& stream) = 0;
virtual void setBuffer(const sp<GraphicBuffer>& buffer) = 0;
virtual void setAcquireFenceFd(int fenceFd) = 0;
virtual void setPlaneAlpha(uint8_t alpha) = 0;

View File

@ -458,6 +458,10 @@ status_t VirtualDisplaySurface::disconnect(int api) {
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;

View File

@ -105,6 +105,7 @@ private:
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

View File

@ -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 @@ Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& 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<const DisplayDevice>& 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<const DisplayDevice>& /* 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) {

View File

@ -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<GraphicBuffer> mActiveBuffer;
sp<NativeHandle> mSidebandStream;
Rect mCurrentCrop;
uint32_t mCurrentTransform;
uint32_t mCurrentScalingMode;

View File

@ -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 @@ bool SurfaceFlingerConsumer::getTransformToDisplayInverse() const {
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 @@ nsecs_t SurfaceFlingerConsumer::computeExpectedPresent()
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

View File

@ -27,6 +27,10 @@ namespace android {
*/
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 @@ 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<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.