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:
parent
05fe2d1cfb
commit
399184a4cd
|
@ -67,6 +67,7 @@ public:
|
||||||
virtual ~ProxyConsumerListener();
|
virtual ~ProxyConsumerListener();
|
||||||
virtual void onFrameAvailable();
|
virtual void onFrameAvailable();
|
||||||
virtual void onBuffersReleased();
|
virtual void onBuffersReleased();
|
||||||
|
virtual void onSidebandStreamChanged();
|
||||||
private:
|
private:
|
||||||
// mConsumerListener is a weak reference to the IConsumerListener. This is
|
// mConsumerListener is a weak reference to the IConsumerListener. This is
|
||||||
// the raison d'etre of ProxyConsumerListener.
|
// the raison d'etre of ProxyConsumerListener.
|
||||||
|
@ -204,6 +205,18 @@ public:
|
||||||
// connected to the specified producer API.
|
// connected to the specified producer API.
|
||||||
virtual status_t disconnect(int 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
|
* IGraphicBufferConsumer interface
|
||||||
*/
|
*/
|
||||||
|
@ -306,6 +319,9 @@ public:
|
||||||
// NATIVE_WINDOW_TRANSFORM_ROT_90. The default is 0 (no transform).
|
// NATIVE_WINDOW_TRANSFORM_ROT_90. The default is 0 (no transform).
|
||||||
virtual status_t setTransformHint(uint32_t hint);
|
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
|
// dump our state in a String
|
||||||
virtual void dump(String8& result, const char* prefix) const;
|
virtual void dump(String8& result, const char* prefix) const;
|
||||||
|
|
||||||
|
|
|
@ -133,6 +133,9 @@ public:
|
||||||
// NATIVE_WINDOW_TRANSFORM_ROT_90. The default is 0 (no transform).
|
// NATIVE_WINDOW_TRANSFORM_ROT_90. The default is 0 (no transform).
|
||||||
virtual status_t setTransformHint(uint32_t hint);
|
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
|
// dump our state in a String
|
||||||
virtual void dump(String8& result, const char* prefix) const;
|
virtual void dump(String8& result, const char* prefix) const;
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
|
|
||||||
#include <utils/Condition.h>
|
#include <utils/Condition.h>
|
||||||
#include <utils/Mutex.h>
|
#include <utils/Mutex.h>
|
||||||
|
#include <utils/NativeHandle.h>
|
||||||
#include <utils/RefBase.h>
|
#include <utils/RefBase.h>
|
||||||
#include <utils/String8.h>
|
#include <utils/String8.h>
|
||||||
#include <utils/StrongPointer.h>
|
#include <utils/StrongPointer.h>
|
||||||
|
@ -230,6 +231,9 @@ private:
|
||||||
// mTransformHint is used to optimize for screen rotations.
|
// mTransformHint is used to optimize for screen rotations.
|
||||||
uint32_t mTransformHint;
|
uint32_t mTransformHint;
|
||||||
|
|
||||||
|
// mSidebandStream is a handle to the sideband buffer stream, if any
|
||||||
|
sp<NativeHandle> mSidebandStream;
|
||||||
|
|
||||||
}; // class BufferQueueCore
|
}; // class BufferQueueCore
|
||||||
|
|
||||||
} // namespace android
|
} // namespace android
|
||||||
|
|
|
@ -147,6 +147,18 @@ public:
|
||||||
// connected to the specified producer API.
|
// connected to the specified producer API.
|
||||||
virtual status_t disconnect(int 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:
|
private:
|
||||||
// This is required by the IBinder::DeathRecipient interface
|
// This is required by the IBinder::DeathRecipient interface
|
||||||
virtual void binderDied(const wp<IBinder>& who);
|
virtual void binderDied(const wp<IBinder>& who);
|
||||||
|
|
|
@ -101,11 +101,14 @@ protected:
|
||||||
|
|
||||||
// Implementation of the IConsumerListener interface. These
|
// Implementation of the IConsumerListener interface. These
|
||||||
// calls are used to notify the ConsumerBase of asynchronous events in the
|
// calls are used to notify the ConsumerBase of asynchronous events in the
|
||||||
// BufferQueue. These methods should not need to be overridden by derived
|
// BufferQueue. The onFrameAvailable and onBuffersReleased methods should
|
||||||
// classes, but if they are overridden the ConsumerBase implementation
|
// not need to be overridden by derived classes, but if they are overridden
|
||||||
// must be called from the derived class.
|
// 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 onFrameAvailable();
|
||||||
virtual void onBuffersReleased();
|
virtual void onBuffersReleased();
|
||||||
|
virtual void onSidebandStreamChanged();
|
||||||
|
|
||||||
// freeBufferLocked frees up the given buffer slot. If the slot has been
|
// freeBufferLocked frees up the given buffer slot. If the slot has been
|
||||||
// initialized this will release the reference to the GraphicBuffer in that
|
// initialized this will release the reference to the GraphicBuffer in that
|
||||||
|
|
|
@ -57,6 +57,12 @@ public:
|
||||||
// This is called without any lock held and can be called concurrently
|
// This is called without any lock held and can be called concurrently
|
||||||
// by multiple threads.
|
// by multiple threads.
|
||||||
virtual void onBuffersReleased() = 0; /* Asynchronous */
|
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 */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -30,9 +30,10 @@
|
||||||
namespace android {
|
namespace android {
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
class IConsumerListener;
|
|
||||||
class GraphicBuffer;
|
|
||||||
class Fence;
|
class Fence;
|
||||||
|
class GraphicBuffer;
|
||||||
|
class IConsumerListener;
|
||||||
|
class NativeHandle;
|
||||||
|
|
||||||
class IGraphicBufferConsumer : public IInterface {
|
class IGraphicBufferConsumer : public IInterface {
|
||||||
|
|
||||||
|
@ -266,6 +267,9 @@ public:
|
||||||
// Return of a value other than NO_ERROR means an unknown error has occurred.
|
// Return of a value other than NO_ERROR means an unknown error has occurred.
|
||||||
virtual status_t setTransformHint(uint32_t hint) = 0;
|
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
|
// dump state into a string
|
||||||
virtual void dump(String8& result, const char* prefix) const = 0;
|
virtual void dump(String8& result, const char* prefix) const = 0;
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
namespace android {
|
namespace android {
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class NativeHandle;
|
||||||
class Surface;
|
class Surface;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -347,6 +348,18 @@ public:
|
||||||
// * api was out of range (see above).
|
// * api was out of range (see above).
|
||||||
// * DEAD_OBJECT - the token is hosted by an already-dead process
|
// * DEAD_OBJECT - the token is hosted by an already-dead process
|
||||||
virtual status_t disconnect(int api) = 0;
|
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
|
@ -78,6 +78,19 @@ public:
|
||||||
return surface != NULL && surface->getIGraphicBufferProducer() != NULL;
|
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:
|
protected:
|
||||||
virtual ~Surface();
|
virtual ~Surface();
|
||||||
|
|
||||||
|
|
|
@ -93,6 +93,10 @@ status_t BufferQueue::disconnect(int api) {
|
||||||
return mProducer->disconnect(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) {
|
status_t BufferQueue::acquireBuffer(BufferItem* buffer, nsecs_t presentWhen) {
|
||||||
return mConsumer->acquireBuffer(buffer, presentWhen);
|
return mConsumer->acquireBuffer(buffer, presentWhen);
|
||||||
}
|
}
|
||||||
|
@ -148,8 +152,19 @@ status_t BufferQueue::setTransformHint(uint32_t hint) {
|
||||||
return mConsumer->setTransformHint(hint);
|
return mConsumer->setTransformHint(hint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sp<NativeHandle> BufferQueue::getSidebandStream() const {
|
||||||
|
return mConsumer->getSidebandStream();
|
||||||
|
}
|
||||||
|
|
||||||
void BufferQueue::dump(String8& result, const char* prefix) const {
|
void BufferQueue::dump(String8& result, const char* prefix) const {
|
||||||
mConsumer->dump(result, prefix);
|
mConsumer->dump(result, prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BufferQueue::ProxyConsumerListener::onSidebandStreamChanged() {
|
||||||
|
sp<ConsumerListener> listener(mConsumerListener.promote());
|
||||||
|
if (listener != NULL) {
|
||||||
|
listener->onSidebandStreamChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}; // namespace android
|
}; // namespace android
|
||||||
|
|
|
@ -395,6 +395,10 @@ status_t BufferQueueConsumer::setTransformHint(uint32_t hint) {
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sp<NativeHandle> BufferQueueConsumer::getSidebandStream() const {
|
||||||
|
return mCore->mSidebandStream;
|
||||||
|
}
|
||||||
|
|
||||||
void BufferQueueConsumer::dump(String8& result, const char* prefix) const {
|
void BufferQueueConsumer::dump(String8& result, const char* prefix) const {
|
||||||
mCore->dump(result, prefix);
|
mCore->dump(result, prefix);
|
||||||
}
|
}
|
||||||
|
|
|
@ -674,6 +674,7 @@ status_t BufferQueueProducer::disconnect(int api) {
|
||||||
}
|
}
|
||||||
mCore->mConnectedProducerToken = NULL;
|
mCore->mConnectedProducerToken = NULL;
|
||||||
mCore->mConnectedApi = BufferQueueCore::NO_CONNECTED_API;
|
mCore->mConnectedApi = BufferQueueCore::NO_CONNECTED_API;
|
||||||
|
mCore->mSidebandStream.clear();
|
||||||
mCore->mDequeueCondition.broadcast();
|
mCore->mDequeueCondition.broadcast();
|
||||||
listener = mCore->mConsumerListener;
|
listener = mCore->mConsumerListener;
|
||||||
} else {
|
} else {
|
||||||
|
@ -697,6 +698,12 @@ status_t BufferQueueProducer::disconnect(int api) {
|
||||||
return status;
|
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 */) {
|
void BufferQueueProducer::binderDied(const wp<android::IBinder>& /* who */) {
|
||||||
// If we're here, it means that a producer we were connected to died.
|
// 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
|
// We're guaranteed that we are still connected to it because we remove
|
||||||
|
|
|
@ -130,6 +130,9 @@ void ConsumerBase::onBuffersReleased() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ConsumerBase::onSidebandStreamChanged() {
|
||||||
|
}
|
||||||
|
|
||||||
void ConsumerBase::abandon() {
|
void ConsumerBase::abandon() {
|
||||||
CB_LOGV("abandon");
|
CB_LOGV("abandon");
|
||||||
Mutex::Autolock lock(mMutex);
|
Mutex::Autolock lock(mMutex);
|
||||||
|
|
|
@ -28,7 +28,8 @@ namespace android {
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
ON_FRAME_AVAILABLE = IBinder::FIRST_CALL_TRANSACTION,
|
ON_FRAME_AVAILABLE = IBinder::FIRST_CALL_TRANSACTION,
|
||||||
ON_BUFFER_RELEASED
|
ON_BUFFER_RELEASED,
|
||||||
|
ON_SIDEBAND_STREAM_CHANGED,
|
||||||
};
|
};
|
||||||
|
|
||||||
class BpConsumerListener : public BpInterface<IConsumerListener>
|
class BpConsumerListener : public BpInterface<IConsumerListener>
|
||||||
|
@ -49,6 +50,12 @@ public:
|
||||||
data.writeInterfaceToken(IConsumerListener::getInterfaceDescriptor());
|
data.writeInterfaceToken(IConsumerListener::getInterfaceDescriptor());
|
||||||
remote()->transact(ON_BUFFER_RELEASED, data, &reply, IBinder::FLAG_ONEWAY);
|
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");
|
IMPLEMENT_META_INTERFACE(ConsumerListener, "android.gui.IConsumerListener");
|
||||||
|
@ -67,6 +74,10 @@ status_t BnConsumerListener::onTransact(
|
||||||
CHECK_INTERFACE(IConsumerListener, data, reply);
|
CHECK_INTERFACE(IConsumerListener, data, reply);
|
||||||
onBuffersReleased();
|
onBuffersReleased();
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
|
case ON_SIDEBAND_STREAM_CHANGED:
|
||||||
|
CHECK_INTERFACE(IConsumerListener, data, reply);
|
||||||
|
onSidebandStreamChanged();
|
||||||
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
return BBinder::onTransact(code, data, reply, flags);
|
return BBinder::onTransact(code, data, reply, flags);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include <utils/Errors.h>
|
#include <utils/Errors.h>
|
||||||
|
#include <utils/NativeHandle.h>
|
||||||
|
|
||||||
#include <binder/Parcel.h>
|
#include <binder/Parcel.h>
|
||||||
#include <binder/IInterface.h>
|
#include <binder/IInterface.h>
|
||||||
|
@ -195,6 +196,7 @@ enum {
|
||||||
SET_DEFAULT_BUFFER_FORMAT,
|
SET_DEFAULT_BUFFER_FORMAT,
|
||||||
SET_CONSUMER_USAGE_BITS,
|
SET_CONSUMER_USAGE_BITS,
|
||||||
SET_TRANSFORM_HINT,
|
SET_TRANSFORM_HINT,
|
||||||
|
GET_SIDEBAND_STREAM,
|
||||||
DUMP,
|
DUMP,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -354,6 +356,20 @@ public:
|
||||||
return reply.readInt32();
|
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 {
|
virtual void dump(String8& result, const char* prefix) const {
|
||||||
Parcel data, reply;
|
Parcel data, reply;
|
||||||
data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
|
data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
|
||||||
|
|
|
@ -18,9 +18,10 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include <utils/Errors.h>
|
#include <utils/Errors.h>
|
||||||
|
#include <utils/NativeHandle.h>
|
||||||
#include <utils/RefBase.h>
|
#include <utils/RefBase.h>
|
||||||
#include <utils/Vector.h>
|
|
||||||
#include <utils/Timers.h>
|
#include <utils/Timers.h>
|
||||||
|
#include <utils/Vector.h>
|
||||||
|
|
||||||
#include <binder/Parcel.h>
|
#include <binder/Parcel.h>
|
||||||
#include <binder/IInterface.h>
|
#include <binder/IInterface.h>
|
||||||
|
@ -39,6 +40,7 @@ enum {
|
||||||
QUERY,
|
QUERY,
|
||||||
CONNECT,
|
CONNECT,
|
||||||
DISCONNECT,
|
DISCONNECT,
|
||||||
|
SET_SIDEBAND_STREAM,
|
||||||
};
|
};
|
||||||
|
|
||||||
class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
|
class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
|
||||||
|
@ -169,6 +171,22 @@ public:
|
||||||
result = reply.readInt32();
|
result = reply.readInt32();
|
||||||
return result;
|
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");
|
IMPLEMENT_META_INTERFACE(GraphicBufferProducer, "android.gui.IGraphicBufferProducer");
|
||||||
|
@ -263,6 +281,16 @@ status_t BnGraphicBufferProducer::onTransact(
|
||||||
reply->writeInt32(res);
|
reply->writeInt32(res);
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
} break;
|
} 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);
|
return BBinder::onTransact(code, data, reply, flags);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
#include <utils/Errors.h>
|
#include <utils/Errors.h>
|
||||||
#include <utils/misc.h>
|
#include <utils/misc.h>
|
||||||
|
#include <utils/NativeHandle.h>
|
||||||
#include <utils/String8.h>
|
#include <utils/String8.h>
|
||||||
#include <utils/Thread.h>
|
#include <utils/Thread.h>
|
||||||
#include <utils/Trace.h>
|
#include <utils/Trace.h>
|
||||||
|
@ -942,12 +943,22 @@ public:
|
||||||
SharedBuffer const* sb = reg.getSharedBuffer(&visibleRegion.numRects);
|
SharedBuffer const* sb = reg.getSharedBuffer(&visibleRegion.numRects);
|
||||||
visibleRegion.rects = reinterpret_cast<hwc_rect_t const *>(sb->data());
|
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) {
|
virtual void setBuffer(const sp<GraphicBuffer>& buffer) {
|
||||||
if (buffer == 0 || buffer->handle == 0) {
|
if (buffer == 0 || buffer->handle == 0) {
|
||||||
getLayer()->compositionType = HWC_FRAMEBUFFER;
|
getLayer()->compositionType = HWC_FRAMEBUFFER;
|
||||||
getLayer()->flags |= HWC_SKIP_LAYER;
|
getLayer()->flags |= HWC_SKIP_LAYER;
|
||||||
getLayer()->handle = 0;
|
getLayer()->handle = 0;
|
||||||
} else {
|
} 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;
|
getLayer()->handle = buffer->handle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,9 +45,10 @@ struct framebuffer_device_t;
|
||||||
namespace android {
|
namespace android {
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
class GraphicBuffer;
|
|
||||||
class Fence;
|
class Fence;
|
||||||
class FloatRect;
|
class FloatRect;
|
||||||
|
class GraphicBuffer;
|
||||||
|
class NativeHandle;
|
||||||
class Region;
|
class Region;
|
||||||
class String8;
|
class String8;
|
||||||
class SurfaceFlinger;
|
class SurfaceFlinger;
|
||||||
|
@ -164,6 +165,7 @@ public:
|
||||||
virtual void setFrame(const Rect& frame) = 0;
|
virtual void setFrame(const Rect& frame) = 0;
|
||||||
virtual void setCrop(const FloatRect& crop) = 0;
|
virtual void setCrop(const FloatRect& crop) = 0;
|
||||||
virtual void setVisibleRegionScreen(const Region& reg) = 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 setBuffer(const sp<GraphicBuffer>& buffer) = 0;
|
||||||
virtual void setAcquireFenceFd(int fenceFd) = 0;
|
virtual void setAcquireFenceFd(int fenceFd) = 0;
|
||||||
virtual void setPlaneAlpha(uint8_t alpha) = 0;
|
virtual void setPlaneAlpha(uint8_t alpha) = 0;
|
||||||
|
|
|
@ -458,6 +458,10 @@ status_t VirtualDisplaySurface::disconnect(int api) {
|
||||||
return mSource[SOURCE_SINK]->disconnect(api);
|
return mSource[SOURCE_SINK]->disconnect(api);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status_t VirtualDisplaySurface::setSidebandStream(const sp<NativeHandle>& /*stream*/) {
|
||||||
|
return INVALID_OPERATION;
|
||||||
|
}
|
||||||
|
|
||||||
void VirtualDisplaySurface::updateQueueBufferOutput(
|
void VirtualDisplaySurface::updateQueueBufferOutput(
|
||||||
const QueueBufferOutput& qbo) {
|
const QueueBufferOutput& qbo) {
|
||||||
uint32_t w, h, transformHint, numPendingBuffers;
|
uint32_t w, h, transformHint, numPendingBuffers;
|
||||||
|
|
|
@ -105,6 +105,7 @@ private:
|
||||||
virtual status_t connect(const sp<IBinder>& token,
|
virtual status_t connect(const sp<IBinder>& token,
|
||||||
int api, bool producerControlledByApp, QueueBufferOutput* output);
|
int api, bool producerControlledByApp, QueueBufferOutput* output);
|
||||||
virtual status_t disconnect(int api);
|
virtual status_t disconnect(int api);
|
||||||
|
virtual status_t setSidebandStream(const sp<NativeHandle>& stream);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Utility methods
|
// Utility methods
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
|
|
||||||
#include <utils/Errors.h>
|
#include <utils/Errors.h>
|
||||||
#include <utils/Log.h>
|
#include <utils/Log.h>
|
||||||
|
#include <utils/NativeHandle.h>
|
||||||
#include <utils/StopWatch.h>
|
#include <utils/StopWatch.h>
|
||||||
#include <utils/Trace.h>
|
#include <utils/Trace.h>
|
||||||
|
|
||||||
|
@ -66,6 +67,7 @@ Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client,
|
||||||
mFormat(PIXEL_FORMAT_NONE),
|
mFormat(PIXEL_FORMAT_NONE),
|
||||||
mTransactionFlags(0),
|
mTransactionFlags(0),
|
||||||
mQueuedFrames(0),
|
mQueuedFrames(0),
|
||||||
|
mSidebandStreamChanged(false),
|
||||||
mCurrentTransform(0),
|
mCurrentTransform(0),
|
||||||
mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
|
mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
|
||||||
mCurrentOpacity(true),
|
mCurrentOpacity(true),
|
||||||
|
@ -118,7 +120,7 @@ void Layer::onFirstRef() {
|
||||||
mBufferQueue = new SurfaceTextureLayer(mFlinger);
|
mBufferQueue = new SurfaceTextureLayer(mFlinger);
|
||||||
mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(mBufferQueue, mTextureName);
|
mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(mBufferQueue, mTextureName);
|
||||||
mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
|
mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
|
||||||
mSurfaceFlingerConsumer->setFrameAvailableListener(this);
|
mSurfaceFlingerConsumer->setContentsChangedListener(this);
|
||||||
mSurfaceFlingerConsumer->setName(mName);
|
mSurfaceFlingerConsumer->setName(mName);
|
||||||
|
|
||||||
#ifdef TARGET_DISABLE_TRIPLE_BUFFERING
|
#ifdef TARGET_DISABLE_TRIPLE_BUFFERING
|
||||||
|
@ -158,6 +160,13 @@ void Layer::onFrameAvailable() {
|
||||||
mFlinger->signalLayerUpdate();
|
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
|
// called with SurfaceFlinger::mStateLock from the drawing thread after
|
||||||
// the layer has been remove from the current state list (and just before
|
// the layer has been remove from the current state list (and just before
|
||||||
// it's removed from the drawing state list)
|
// 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()));
|
Region visible = tr.transform(visibleRegion.intersect(hw->getViewport()));
|
||||||
layer.setVisibleRegionScreen(visible);
|
layer.setVisibleRegionScreen(visible);
|
||||||
|
|
||||||
// NOTE: buffer can be NULL if the client never drew into this
|
if (mSidebandStream.get()) {
|
||||||
// layer yet, or if we ran out of memory
|
layer.setSidebandStream(mSidebandStream);
|
||||||
layer.setBuffer(mActiveBuffer);
|
} 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 */,
|
void Layer::setAcquireFence(const sp<const DisplayDevice>& /* hw */,
|
||||||
|
@ -907,7 +920,7 @@ bool Layer::setLayerStack(uint32_t layerStack) {
|
||||||
|
|
||||||
bool Layer::onPreComposition() {
|
bool Layer::onPreComposition() {
|
||||||
mRefreshPending = false;
|
mRefreshPending = false;
|
||||||
return mQueuedFrames > 0;
|
return mQueuedFrames > 0 || mSidebandStreamChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Layer::onPostComposition() {
|
void Layer::onPostComposition() {
|
||||||
|
@ -950,6 +963,11 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions)
|
||||||
{
|
{
|
||||||
ATRACE_CALL();
|
ATRACE_CALL();
|
||||||
|
|
||||||
|
if (android_atomic_acquire_cas(true, false, &mSidebandStreamChanged) == 0) {
|
||||||
|
// mSidebandStreamChanged was true
|
||||||
|
mSidebandStream = mSurfaceFlingerConsumer->getSidebandStream();
|
||||||
|
}
|
||||||
|
|
||||||
Region outDirtyRegion;
|
Region outDirtyRegion;
|
||||||
if (mQueuedFrames > 0) {
|
if (mQueuedFrames > 0) {
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,7 @@ class SurfaceFlinger;
|
||||||
* This also implements onFrameAvailable(), which notifies SurfaceFlinger
|
* This also implements onFrameAvailable(), which notifies SurfaceFlinger
|
||||||
* that new data has arrived.
|
* that new data has arrived.
|
||||||
*/
|
*/
|
||||||
class Layer : public SurfaceFlingerConsumer::FrameAvailableListener {
|
class Layer : public SurfaceFlingerConsumer::ContentsChangedListener {
|
||||||
static int32_t sSequence;
|
static int32_t sSequence;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -313,8 +313,9 @@ protected:
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Interface implementation for SurfaceFlingerConsumer::FrameAvailableListener
|
// Interface implementation for SurfaceFlingerConsumer::ContentsChangedListener
|
||||||
virtual void onFrameAvailable();
|
virtual void onFrameAvailable();
|
||||||
|
virtual void onSidebandStreamChanged();
|
||||||
|
|
||||||
void commitTransaction();
|
void commitTransaction();
|
||||||
|
|
||||||
|
@ -351,10 +352,12 @@ private:
|
||||||
|
|
||||||
// thread-safe
|
// thread-safe
|
||||||
volatile int32_t mQueuedFrames;
|
volatile int32_t mQueuedFrames;
|
||||||
|
volatile int32_t mSidebandStreamChanged; // used like an atomic boolean
|
||||||
FrameTracker mFrameTracker;
|
FrameTracker mFrameTracker;
|
||||||
|
|
||||||
// main thread
|
// main thread
|
||||||
sp<GraphicBuffer> mActiveBuffer;
|
sp<GraphicBuffer> mActiveBuffer;
|
||||||
|
sp<NativeHandle> mSidebandStream;
|
||||||
Rect mCurrentCrop;
|
Rect mCurrentCrop;
|
||||||
uint32_t mCurrentTransform;
|
uint32_t mCurrentTransform;
|
||||||
uint32_t mCurrentScalingMode;
|
uint32_t mCurrentScalingMode;
|
||||||
|
|
|
@ -21,8 +21,9 @@
|
||||||
|
|
||||||
#include <private/gui/SyncFeatures.h>
|
#include <private/gui/SyncFeatures.h>
|
||||||
|
|
||||||
#include <utils/Trace.h>
|
|
||||||
#include <utils/Errors.h>
|
#include <utils/Errors.h>
|
||||||
|
#include <utils/NativeHandle.h>
|
||||||
|
#include <utils/Trace.h>
|
||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
|
|
||||||
|
@ -112,6 +113,10 @@ bool SurfaceFlingerConsumer::getTransformToDisplayInverse() const {
|
||||||
return mTransformToDisplayInverse;
|
return mTransformToDisplayInverse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sp<NativeHandle> SurfaceFlingerConsumer::getSidebandStream() const {
|
||||||
|
return mConsumer->getSidebandStream();
|
||||||
|
}
|
||||||
|
|
||||||
// We need to determine the time when a buffer acquired now will be
|
// We need to determine the time when a buffer acquired now will be
|
||||||
// displayed. This can be calculated:
|
// displayed. This can be calculated:
|
||||||
// time when previous buffer's actual-present fence was signaled
|
// time when previous buffer's actual-present fence was signaled
|
||||||
|
@ -154,6 +159,26 @@ nsecs_t SurfaceFlingerConsumer::computeExpectedPresent()
|
||||||
return prevVsync + hwcLatency * vsyncPeriod + extraPadding;
|
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
|
}; // namespace android
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,10 @@ namespace android {
|
||||||
*/
|
*/
|
||||||
class SurfaceFlingerConsumer : public GLConsumer {
|
class SurfaceFlingerConsumer : public GLConsumer {
|
||||||
public:
|
public:
|
||||||
|
struct ContentsChangedListener: public FrameAvailableListener {
|
||||||
|
virtual void onSidebandStreamChanged() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
SurfaceFlingerConsumer(const sp<BufferQueue>& bq, uint32_t tex)
|
SurfaceFlingerConsumer(const sp<BufferQueue>& bq, uint32_t tex)
|
||||||
: GLConsumer(bq, tex, GLConsumer::TEXTURE_EXTERNAL, false)
|
: GLConsumer(bq, tex, GLConsumer::TEXTURE_EXTERNAL, false)
|
||||||
{}
|
{}
|
||||||
|
@ -54,9 +58,19 @@ public:
|
||||||
// must be called from SF main thread
|
// must be called from SF main thread
|
||||||
bool getTransformToDisplayInverse() const;
|
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:
|
private:
|
||||||
nsecs_t computeExpectedPresent();
|
nsecs_t computeExpectedPresent();
|
||||||
|
|
||||||
|
virtual void onSidebandStreamChanged();
|
||||||
|
|
||||||
|
wp<ContentsChangedListener> mContentsChangedListener;
|
||||||
|
|
||||||
// Indicates this buffer must be transformed by the inverse transform of the screen
|
// Indicates this buffer must be transformed by the inverse transform of the screen
|
||||||
// it is displayed onto. This is applied after GLConsumer::mCurrentTransform.
|
// it is displayed onto. This is applied after GLConsumer::mCurrentTransform.
|
||||||
// This must be set/read from SurfaceFlinger's main thread.
|
// This must be set/read from SurfaceFlinger's main thread.
|
||||||
|
|
Loading…
Reference in New Issue