Merge "Add a BufferItem parameter to onFrameAvailable" into lmp-mr1-dev

This commit is contained in:
Dan Stoza 2014-11-07 19:44:30 +00:00 committed by Android (Google) Code Review
commit 98d20f82ca
23 changed files with 99 additions and 38 deletions

View File

@ -44,6 +44,7 @@ class BufferItem : public Flattenable<BufferItem> {
// The default value of mBuf, used to indicate this doesn't correspond to a slot. // The default value of mBuf, used to indicate this doesn't correspond to a slot.
enum { INVALID_BUFFER_SLOT = -1 }; enum { INVALID_BUFFER_SLOT = -1 };
BufferItem(); BufferItem();
~BufferItem();
operator IGraphicBufferConsumer::BufferItem() const; operator IGraphicBufferConsumer::BufferItem() const;
static const char* scalingModeName(uint32_t scalingMode); static const char* scalingModeName(uint32_t scalingMode);

View File

@ -62,7 +62,7 @@ public:
public: public:
ProxyConsumerListener(const wp<ConsumerListener>& consumerListener); ProxyConsumerListener(const wp<ConsumerListener>& consumerListener);
virtual ~ProxyConsumerListener(); virtual ~ProxyConsumerListener();
virtual void onFrameAvailable(); virtual void onFrameAvailable(const android::BufferItem& item);
virtual void onBuffersReleased(); virtual void onBuffersReleased();
virtual void onSidebandStreamChanged(); virtual void onSidebandStreamChanged();
private: private:

View File

@ -203,6 +203,16 @@ private:
// since the previous buffer might have already been acquired. // since the previous buffer might have already been acquired.
sp<Fence> mLastQueueBufferFence; sp<Fence> mLastQueueBufferFence;
// Take-a-ticket system for ensuring that onFrame* callbacks are called in
// the order that frames are queued. While the BufferQueue lock
// (mCore->mMutex) is held, a ticket is retained by the producer. After
// dropping the BufferQueue lock, the producer must wait on the condition
// variable until the current callback ticket matches its retained ticket.
Mutex mCallbackMutex;
int mNextCallbackTicket; // Protected by mCore->mMutex
int mCurrentCallbackTicket; // Protected by mCallbackMutex
Condition mCallbackCondition;
}; // class BufferQueueProducer }; // class BufferQueueProducer
} // namespace android } // namespace android

View File

@ -46,7 +46,7 @@ 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 onFrameAvailable() = 0; virtual void onFrameAvailable(const BufferItem& item) = 0;
}; };
virtual ~ConsumerBase(); virtual ~ConsumerBase();
@ -106,7 +106,7 @@ protected:
// the ConsumerBase implementation 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 // The ConsumerBase version of onSidebandStreamChanged does nothing and can
// be overriden by derived classes if they want the notification. // be overriden by derived classes if they want the notification.
virtual void onFrameAvailable(); virtual void onFrameAvailable(const BufferItem& item);
virtual void onBuffersReleased(); virtual void onBuffersReleased();
virtual void onSidebandStreamChanged(); virtual void onSidebandStreamChanged();

View File

@ -28,6 +28,8 @@
namespace android { namespace android {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
class BufferItem;
// ConsumerListener is the interface through which the BufferQueue notifies // ConsumerListener is the interface through which the BufferQueue notifies
// the consumer of events that the consumer may wish to react to. Because // the consumer of events that the consumer may wish to react to. Because
// the consumer will generally have a mutex that is locked during calls from // the consumer will generally have a mutex that is locked during calls from
@ -43,11 +45,24 @@ public:
// frame becomes available for consumption. This means that frames that // frame becomes available for consumption. This means that frames that
// are queued while in asynchronous mode only trigger the callback if no // are queued while in asynchronous mode only trigger the callback if no
// previous frames are pending. Frames queued while in synchronous mode // previous frames are pending. Frames queued while in synchronous mode
// always trigger the callback. // always trigger the callback. The item passed to the callback will contain
// all of the information about the queued frame except for its
// GraphicBuffer pointer, which will always be null.
// //
// 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 onFrameAvailable() = 0; /* Asynchronous */ virtual void onFrameAvailable(const BufferItem& item) = 0; /* Asynchronous */
// onFrameReplaced is called from queueBuffer if the frame being queued is
// replacing an existing slot in the queue. Any call to queueBuffer that
// doesn't call onFrameAvailable will call this callback instead. The item
// passed to the callback will contain all of the information about the
// queued frame except for its GraphicBuffer pointer, which will always be
// null.
//
// This is called without any lock held and can be called concurrently
// by multiple threads.
virtual void onFrameReplaced(const BufferItem& item) {} /* Asynchronous */
// onBuffersReleased is called to notify the buffer consumer that the // onBuffersReleased is called to notify the buffer consumer that the
// BufferQueue has released its references to one or more GraphicBuffers // BufferQueue has released its references to one or more GraphicBuffers

View File

@ -74,7 +74,7 @@ private:
// can block if there are too many outstanding buffers. If it blocks, it // can block if there are too many outstanding buffers. If it blocks, it
// will resume when onBufferReleasedByOutput releases a buffer back to the // will resume when onBufferReleasedByOutput releases a buffer back to the
// input. // input.
virtual void onFrameAvailable(); virtual void onFrameAvailable(const BufferItem& item);
// From IConsumerListener // From IConsumerListener
// We don't care about released buffers because we detach each buffer as // We don't care about released buffers because we detach each buffer as

View File

@ -36,6 +36,8 @@ BufferItem::BufferItem() :
mCrop.makeInvalid(); mCrop.makeInvalid();
} }
BufferItem::~BufferItem() {}
BufferItem::operator IGraphicBufferConsumer::BufferItem() const { BufferItem::operator IGraphicBufferConsumer::BufferItem() const {
IGraphicBufferConsumer::BufferItem bufferItem; IGraphicBufferConsumer::BufferItem bufferItem;
bufferItem.mGraphicBuffer = mGraphicBuffer; bufferItem.mGraphicBuffer = mGraphicBuffer;

View File

@ -31,10 +31,11 @@ BufferQueue::ProxyConsumerListener::ProxyConsumerListener(
BufferQueue::ProxyConsumerListener::~ProxyConsumerListener() {} BufferQueue::ProxyConsumerListener::~ProxyConsumerListener() {}
void BufferQueue::ProxyConsumerListener::onFrameAvailable() { void BufferQueue::ProxyConsumerListener::onFrameAvailable(
const android::BufferItem& item) {
sp<ConsumerListener> listener(mConsumerListener.promote()); sp<ConsumerListener> listener(mConsumerListener.promote());
if (listener != NULL) { if (listener != NULL) {
listener->onFrameAvailable(); listener->onFrameAvailable(item);
} }
} }

View File

@ -39,7 +39,11 @@ BufferQueueProducer::BufferQueueProducer(const sp<BufferQueueCore>& core) :
mSlots(core->mSlots), mSlots(core->mSlots),
mConsumerName(), mConsumerName(),
mStickyTransform(0), mStickyTransform(0),
mLastQueueBufferFence(Fence::NO_FENCE) {} mLastQueueBufferFence(Fence::NO_FENCE),
mCallbackMutex(),
mNextCallbackTicket(0),
mCurrentCallbackTicket(0),
mCallbackCondition() {}
BufferQueueProducer::~BufferQueueProducer() {} BufferQueueProducer::~BufferQueueProducer() {}
@ -537,7 +541,10 @@ status_t BufferQueueProducer::queueBuffer(int slot,
return BAD_VALUE; return BAD_VALUE;
} }
sp<IConsumerListener> listener; sp<IConsumerListener> frameAvailableListener;
sp<IConsumerListener> frameReplacedListener;
int callbackTicket = 0;
BufferItem item;
{ // Autolock scope { // Autolock scope
Mutex::Autolock lock(mCore->mMutex); Mutex::Autolock lock(mCore->mMutex);
@ -593,7 +600,6 @@ status_t BufferQueueProducer::queueBuffer(int slot,
++mCore->mFrameCounter; ++mCore->mFrameCounter;
mSlots[slot].mFrameNumber = mCore->mFrameCounter; mSlots[slot].mFrameNumber = mCore->mFrameCounter;
BufferItem item;
item.mAcquireCalled = mSlots[slot].mAcquireCalled; item.mAcquireCalled = mSlots[slot].mAcquireCalled;
item.mGraphicBuffer = mSlots[slot].mGraphicBuffer; item.mGraphicBuffer = mSlots[slot].mGraphicBuffer;
item.mCrop = crop; item.mCrop = crop;
@ -614,7 +620,7 @@ status_t BufferQueueProducer::queueBuffer(int slot,
// When the queue is empty, we can ignore mDequeueBufferCannotBlock // When the queue is empty, we can ignore mDequeueBufferCannotBlock
// and simply queue this buffer // and simply queue this buffer
mCore->mQueue.push_back(item); mCore->mQueue.push_back(item);
listener = mCore->mConsumerListener; frameAvailableListener = mCore->mConsumerListener;
} else { } else {
// When the queue is not empty, we need to look at the front buffer // When the queue is not empty, we need to look at the front buffer
// state to see if we need to replace it // state to see if we need to replace it
@ -630,9 +636,10 @@ status_t BufferQueueProducer::queueBuffer(int slot,
} }
// Overwrite the droppable buffer with the incoming one // Overwrite the droppable buffer with the incoming one
*front = item; *front = item;
frameReplacedListener = mCore->mConsumerListener;
} else { } else {
mCore->mQueue.push_back(item); mCore->mQueue.push_back(item);
listener = mCore->mConsumerListener; frameAvailableListener = mCore->mConsumerListener;
} }
} }
@ -643,6 +650,9 @@ status_t BufferQueueProducer::queueBuffer(int slot,
mCore->mTransformHint, mCore->mQueue.size()); mCore->mTransformHint, mCore->mQueue.size());
ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size()); ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size());
// Take a ticket for the callback functions
callbackTicket = mNextCallbackTicket++;
} // Autolock scope } // Autolock scope
// Wait without lock held // Wait without lock held
@ -654,9 +664,27 @@ status_t BufferQueueProducer::queueBuffer(int slot,
mLastQueueBufferFence = fence; mLastQueueBufferFence = fence;
} }
// Call back without lock held // Don't send the GraphicBuffer through the callback, and don't send
if (listener != NULL) { // the slot number, since the consumer shouldn't need it
listener->onFrameAvailable(); item.mGraphicBuffer.clear();
item.mSlot = BufferItem::INVALID_BUFFER_SLOT;
// Call back without the main BufferQueue lock held, but with the callback
// lock held so we can ensure that callbacks occur in order
{
Mutex::Autolock lock(mCallbackMutex);
while (callbackTicket != mCurrentCallbackTicket) {
mCallbackCondition.wait(mCallbackMutex);
}
if (frameAvailableListener != NULL) {
frameAvailableListener->onFrameAvailable(item);
} else if (frameReplacedListener != NULL) {
frameReplacedListener->onFrameReplaced(item);
}
++mCurrentCallbackTicket;
mCallbackCondition.broadcast();
} }
return NO_ERROR; return NO_ERROR;

View File

@ -98,7 +98,7 @@ void ConsumerBase::freeBufferLocked(int slotIndex) {
mSlots[slotIndex].mFrameNumber = 0; mSlots[slotIndex].mFrameNumber = 0;
} }
void ConsumerBase::onFrameAvailable() { void ConsumerBase::onFrameAvailable(const BufferItem& item) {
CB_LOGV("onFrameAvailable"); CB_LOGV("onFrameAvailable");
sp<FrameAvailableListener> listener; sp<FrameAvailableListener> listener;
@ -109,7 +109,7 @@ void ConsumerBase::onFrameAvailable() {
if (listener != NULL) { if (listener != NULL) {
CB_LOGV("actually calling onFrameAvailable"); CB_LOGV("actually calling onFrameAvailable");
listener->onFrameAvailable(); listener->onFrameAvailable(item);
} }
} }

View File

@ -21,6 +21,7 @@
#include <binder/Parcel.h> #include <binder/Parcel.h>
#include <gui/IConsumerListener.h> #include <gui/IConsumerListener.h>
#include <gui/BufferItem.h>
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
namespace android { namespace android {
@ -39,9 +40,10 @@ public:
: BpInterface<IConsumerListener>(impl) { : BpInterface<IConsumerListener>(impl) {
} }
virtual void onFrameAvailable() { virtual void onFrameAvailable(const BufferItem& item) {
Parcel data, reply; Parcel data, reply;
data.writeInterfaceToken(IConsumerListener::getInterfaceDescriptor()); data.writeInterfaceToken(IConsumerListener::getInterfaceDescriptor());
data.write(item);
remote()->transact(ON_FRAME_AVAILABLE, data, &reply, IBinder::FLAG_ONEWAY); remote()->transact(ON_FRAME_AVAILABLE, data, &reply, IBinder::FLAG_ONEWAY);
} }
@ -66,18 +68,20 @@ status_t BnConsumerListener::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{ {
switch(code) { switch(code) {
case ON_FRAME_AVAILABLE: case ON_FRAME_AVAILABLE: {
CHECK_INTERFACE(IConsumerListener, data, reply); CHECK_INTERFACE(IConsumerListener, data, reply);
onFrameAvailable(); BufferItem item;
return NO_ERROR; data.read(item);
case ON_BUFFER_RELEASED: onFrameAvailable(item);
return NO_ERROR; }
case ON_BUFFER_RELEASED: {
CHECK_INTERFACE(IConsumerListener, data, reply); CHECK_INTERFACE(IConsumerListener, data, reply);
onBuffersReleased(); onBuffersReleased();
return NO_ERROR; return NO_ERROR; }
case ON_SIDEBAND_STREAM_CHANGED: case ON_SIDEBAND_STREAM_CHANGED: {
CHECK_INTERFACE(IConsumerListener, data, reply); CHECK_INTERFACE(IConsumerListener, data, reply);
onSidebandStreamChanged(); onSidebandStreamChanged();
return NO_ERROR; return NO_ERROR; }
} }
return BBinder::onTransact(code, data, reply, flags); return BBinder::onTransact(code, data, reply, flags);
} }

View File

@ -98,7 +98,7 @@ void StreamSplitter::setName(const String8 &name) {
mInput->setConsumerName(name); mInput->setConsumerName(name);
} }
void StreamSplitter::onFrameAvailable() { void StreamSplitter::onFrameAvailable(const BufferItem& /* item */) {
ATRACE_CALL(); ATRACE_CALL();
Mutex::Autolock lock(mMutex); Mutex::Autolock lock(mMutex);

View File

@ -67,7 +67,7 @@ protected:
}; };
struct DummyConsumer : public BnConsumerListener { struct DummyConsumer : public BnConsumerListener {
virtual void onFrameAvailable() {} virtual void onFrameAvailable(const BufferItem& /* item */) {}
virtual void onBuffersReleased() {} virtual void onBuffersReleased() {}
virtual void onSidebandStreamChanged() {} virtual void onSidebandStreamChanged() {}
}; };

View File

@ -44,7 +44,7 @@ public:
mPendingFrames--; mPendingFrames--;
} }
virtual void onFrameAvailable() { virtual void onFrameAvailable(const BufferItem& /* item */) {
Mutex::Autolock lock(mMutex); Mutex::Autolock lock(mMutex);
mPendingFrames++; mPendingFrames++;
mFrameCondition.signal(); mFrameCondition.signal();

View File

@ -35,7 +35,7 @@ public:
mPendingFrames--; mPendingFrames--;
} }
virtual void onFrameAvailable() { virtual void onFrameAvailable(const BufferItem& /* item */) {
Mutex::Autolock lock(mMutex); Mutex::Autolock lock(mMutex);
mPendingFrames++; mPendingFrames++;
mCondition.signal(); mCondition.signal();

View File

@ -65,7 +65,7 @@ const sp<Fence> QUEUE_BUFFER_INPUT_FENCE = Fence::NO_FENCE;
}; // namespace anonymous }; // namespace anonymous
struct DummyConsumer : public BnConsumerListener { struct DummyConsumer : public BnConsumerListener {
virtual void onFrameAvailable() {} virtual void onFrameAvailable(const BufferItem& /* item */) {}
virtual void onBuffersReleased() {} virtual void onBuffersReleased() {}
virtual void onSidebandStreamChanged() {} virtual void onSidebandStreamChanged() {}
}; };

View File

@ -46,7 +46,7 @@ protected:
}; };
struct DummyListener : public BnConsumerListener { struct DummyListener : public BnConsumerListener {
virtual void onFrameAvailable() {} virtual void onFrameAvailable(const BufferItem& /* item */) {}
virtual void onBuffersReleased() {} virtual void onBuffersReleased() {}
virtual void onSidebandStreamChanged() {} virtual void onSidebandStreamChanged() {}
}; };

View File

@ -130,7 +130,7 @@ protected:
} }
// This should be called by GLConsumer on the producer thread. // This should be called by GLConsumer on the producer thread.
virtual void onFrameAvailable() { virtual void onFrameAvailable(const BufferItem& /* item */) {
Mutex::Autolock lock(mMutex); Mutex::Autolock lock(mMutex);
ALOGV("+onFrameAvailable"); ALOGV("+onFrameAvailable");
mFrameAvailable = true; mFrameAvailable = true;

View File

@ -101,7 +101,7 @@ TEST_F(EGLTest, EGLTerminateSucceedsWithRemainingObjects) {
EXPECT_TRUE(eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs)); EXPECT_TRUE(eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs));
struct DummyConsumer : public BnConsumerListener { struct DummyConsumer : public BnConsumerListener {
virtual void onFrameAvailable() {} virtual void onFrameAvailable(const BufferItem& /* item */) {}
virtual void onBuffersReleased() {} virtual void onBuffersReleased() {}
virtual void onSidebandStreamChanged() {} virtual void onSidebandStreamChanged() {}
}; };

View File

@ -122,7 +122,7 @@ status_t FramebufferSurface::nextBuffer(sp<GraphicBuffer>& outBuffer, sp<Fence>&
} }
// Overrides ConsumerBase::onFrameAvailable(), does not call base class impl. // Overrides ConsumerBase::onFrameAvailable(), does not call base class impl.
void FramebufferSurface::onFrameAvailable() { void FramebufferSurface::onFrameAvailable(const BufferItem& /* item */) {
sp<GraphicBuffer> buf; sp<GraphicBuffer> buf;
sp<Fence> acquireFence; sp<Fence> acquireFence;
status_t err = nextBuffer(buf, acquireFence); status_t err = nextBuffer(buf, acquireFence);

View File

@ -56,7 +56,7 @@ public:
private: private:
virtual ~FramebufferSurface() { }; // this class cannot be overloaded virtual ~FramebufferSurface() { }; // this class cannot be overloaded
virtual void onFrameAvailable(); virtual void onFrameAvailable(const BufferItem& item);
virtual void freeBufferLocked(int slotIndex); virtual void freeBufferLocked(int slotIndex);
virtual void dumpLocked(String8& result, const char* prefix) const; virtual void dumpLocked(String8& result, const char* prefix) const;

View File

@ -159,7 +159,7 @@ void Layer::onLayerDisplayed(const sp<const DisplayDevice>& /* hw */,
} }
} }
void Layer::onFrameAvailable() { void Layer::onFrameAvailable(const BufferItem& /* item */) {
android_atomic_inc(&mQueuedFrames); android_atomic_inc(&mQueuedFrames);
mFlinger->signalLayerUpdate(); mFlinger->signalLayerUpdate();
} }

View File

@ -330,7 +330,7 @@ protected:
private: private:
// Interface implementation for SurfaceFlingerConsumer::ContentsChangedListener // Interface implementation for SurfaceFlingerConsumer::ContentsChangedListener
virtual void onFrameAvailable(); virtual void onFrameAvailable(const BufferItem& item);
virtual void onSidebandStreamChanged(); virtual void onSidebandStreamChanged();
void commitTransaction(); void commitTransaction();