SurfaceTexture: change onFrameAvailable behavior

This change alters the conditions under which the onFrameAvailable
callback gets called by the C++ SurfaceTexture class.  The new behavior
is to call the callback whenever a frame gets queued that will be
visible to the buffer consumer.  This means that buffers queued in
synchronous mode always trigger the callback, as those buffers will
remain pending until they are consumed.  Buffers queued in asynchronous
mode will only trigger the callback if there was not previously an
unconsumed buffer pending.

The new behavior means that a consumer should perform a draw operation
exactly once for every onFrameAvailable call that it recieves.  This
change also modifies SurfaceFlinger and the SurfaceTexture JNI to
support of the new behavior.

Change-Id: I8b2c6e00961d3d58b11c6af50b555b6e4c5f5b40
This commit is contained in:
Jamie Gennis 2011-06-26 18:27:47 -07:00
parent 0c4b1e994c
commit 3d8063b02e
3 changed files with 27 additions and 32 deletions

View File

@ -46,11 +46,14 @@ public:
enum { NUM_BUFFER_SLOTS = 32 };
struct FrameAvailableListener : public virtual RefBase {
// onFrameAvailable() is called from queueBuffer() is the FIFO is
// empty. You can use SurfaceTexture::getQueuedCount() to
// figure out if there are more frames waiting.
// This is called without any lock held can be called concurrently by
// multiple threads.
// onFrameAvailable() is called from queueBuffer() each time an
// additional frame becomes available for consumption. This means that
// frames that are queued while in asynchronous mode only trigger the
// callback if no previous frames are pending. Frames queued while in
// synchronous mode always trigger the callback.
//
// This is called without any lock held and can be called concurrently
// by multiple threads.
virtual void onFrameAvailable() = 0;
};
@ -101,11 +104,6 @@ public:
// target texture belongs is bound to the calling thread.
status_t updateTexImage();
// getqueuedCount returns the number of queued frames waiting in the
// FIFO. In asynchronous mode, this always returns 0 or 1 since
// frames are not accumulating in the FIFO.
size_t getQueuedCount() const;
// setBufferCountServer set the buffer count. If the client has requested
// a buffer count using setBufferCount, the server-buffer count will
// take effect once the client sets the count back to zero.

View File

@ -417,17 +417,22 @@ status_t SurfaceTexture::queueBuffer(int buf, int64_t timestamp) {
return -EINVAL;
}
if (mQueue.empty()) {
listener = mFrameAvailableListener;
}
if (mSynchronousMode) {
// in synchronous mode we queue all buffers in a FIFO
// In synchronous mode we queue all buffers in a FIFO.
mQueue.push_back(buf);
// Synchronous mode always signals that an additional frame should
// be consumed.
listener = mFrameAvailableListener;
} else {
// in asynchronous mode we only keep the most recent buffer
// In asynchronous mode we only keep the most recent buffer.
if (mQueue.empty()) {
mQueue.push_back(buf);
// Asynchronous mode only signals that a frame should be
// consumed if no previous frame was pending. If a frame were
// pending then the consumer would have already been notified.
listener = mFrameAvailableListener;
} else {
Fifo::iterator front(mQueue.begin());
// buffer currently queued is freed
@ -561,11 +566,6 @@ status_t SurfaceTexture::updateTexImage() {
return OK;
}
size_t SurfaceTexture::getQueuedCount() const {
Mutex::Autolock lock(mMutex);
return mQueue.size();
}
bool SurfaceTexture::isExternalFormat(uint32_t format)
{
switch (format) {

View File

@ -101,9 +101,8 @@ Layer::~Layer()
}
void Layer::onFrameQueued() {
if (android_atomic_or(1, &mQueuedFrames) == 0) {
mFlinger->signalEvent();
}
android_atomic_inc(&mQueuedFrames);
mFlinger->signalEvent();
}
// called with SurfaceFlinger::mStateLock as soon as the layer is entered
@ -406,20 +405,18 @@ bool Layer::isCropped() const {
void Layer::lockPageFlip(bool& recomputeVisibleRegions)
{
if (android_atomic_and(0, &mQueuedFrames)) {
if (mQueuedFrames > 0) {
// signal another event if we have more frames pending
if (android_atomic_dec(&mQueuedFrames) > 1) {
mFlinger->signalEvent();
}
if (mSurfaceTexture->updateTexImage() < NO_ERROR) {
// something happened!
recomputeVisibleRegions = true;
return;
}
// signal another event if we have more frames waiting
if (mSurfaceTexture->getQueuedCount()) {
if (android_atomic_or(1, &mQueuedFrames) == 0) {
mFlinger->signalEvent();
}
}
mActiveBuffer = mSurfaceTexture->getCurrentBuffer();
mSurfaceTexture->getTransformMatrix(mTextureMatrix);