From 595264f1af12e25dce57d7c5b1d52ed86ac0d0c9 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Tue, 16 Jul 2013 22:56:09 -0700 Subject: BufferQueue improvements and APIs changes this is the first step of a series of improvements to BufferQueue. A few things happen in this change: - setSynchronousMode() goes away as well as the SynchronousModeAllowed flag - BufferQueue now defaults to (what used to be) synchronous mode - a new "controlled by app" flag is passed when creating consumers and producers those flags are used to put the BufferQueue in a mode where it will never block if both flags are set. This is achieved by: - returning an error from dequeueBuffer() if it would block - making sure a buffer is always available by replacing the previous buffer with the new one in queueBuffer() (note: this is similar to what asynchrnous mode used to be) Note: in this change EGL's swap-interval 0 is broken; this will be fixed in another change. Change-Id: I691f9507d6e2e158287e3039f2a79a4d4434211d --- libs/gui/BufferQueue.cpp | 57 ++++++++++++------------------------------------ 1 file changed, 14 insertions(+), 43 deletions(-) (limited to 'libs/gui/BufferQueue.cpp') diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index 8d4b174450..1e86a4f3df 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -63,15 +63,15 @@ static const char* scalingModeName(int scalingMode) { } } -BufferQueue::BufferQueue(bool allowSynchronousMode, - const sp& allocator) : +BufferQueue::BufferQueue(const sp& allocator) : mDefaultWidth(1), mDefaultHeight(1), mMaxAcquiredBufferCount(1), mDefaultMaxBufferCount(2), mOverrideMaxBufferCount(0), - mSynchronousMode(false), - mAllowSynchronousMode(allowSynchronousMode), + mConsumerControlledByApp(false), + mDequeueBufferCannotBlock(false), + mSynchronousMode(true), mConnectedApi(NO_CONNECTED_API), mAbandoned(false), mFrameCounter(0), @@ -109,11 +109,6 @@ status_t BufferQueue::setDefaultMaxBufferCountLocked(int count) { return NO_ERROR; } -bool BufferQueue::isSynchronousMode() const { - Mutex::Autolock lock(mMutex); - return mSynchronousMode; -} - void BufferQueue::setConsumerName(const String8& name) { Mutex::Autolock lock(mMutex); mConsumerName = name; @@ -348,6 +343,10 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp* outFence, // the max buffer count to change. tryAgain = found == INVALID_BUFFER_SLOT; if (tryAgain) { + if (mDequeueBufferCannotBlock) { + ST_LOGE("dequeueBuffer: would block! returning an error instead."); + return WOULD_BLOCK; + } mDequeueCondition.wait(mMutex); } } @@ -441,38 +440,6 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp* outFence, return returnFlags; } -status_t BufferQueue::setSynchronousMode(bool enabled) { - ATRACE_CALL(); - ST_LOGV("setSynchronousMode: enabled=%d", enabled); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ST_LOGE("setSynchronousMode: BufferQueue has been abandoned!"); - return NO_INIT; - } - - status_t err = OK; - if (!mAllowSynchronousMode && enabled) - return err; - - if (!enabled) { - // going to asynchronous mode, drain the queue - err = drainQueueLocked(); - if (err != NO_ERROR) - return err; - } - - if (mSynchronousMode != enabled) { - // - if we're going to asynchronous mode, the queue is guaranteed to be - // empty here - // - if the client set the number of buffers, we're guaranteed that - // we have at least 3 (because we don't allow less) - mSynchronousMode = enabled; - mDequeueCondition.broadcast(); - } - return err; -} - status_t BufferQueue::queueBuffer(int buf, const QueueBufferInput& input, QueueBufferOutput* output) { ATRACE_CALL(); @@ -630,7 +597,7 @@ void BufferQueue::cancelBuffer(int buf, const sp& fence) { mDequeueCondition.broadcast(); } -status_t BufferQueue::connect(int api, QueueBufferOutput* output) { +status_t BufferQueue::connect(int api, bool producerControlledByApp, QueueBufferOutput* output) { ATRACE_CALL(); ST_LOGV("connect: api=%d", api); Mutex::Autolock lock(mMutex); @@ -667,6 +634,8 @@ status_t BufferQueue::connect(int api, QueueBufferOutput* output) { } mBufferHasBeenQueued = false; + mDequeueBufferCannotBlock = mConsumerControlledByApp && producerControlledByApp; + mSynchronousMode = !mDequeueBufferCannotBlock; return err; } @@ -950,7 +919,8 @@ status_t BufferQueue::releaseBuffer( return NO_ERROR; } -status_t BufferQueue::consumerConnect(const sp& consumerListener) { +status_t BufferQueue::consumerConnect(const sp& consumerListener, + bool controlledByApp) { ST_LOGV("consumerConnect"); Mutex::Autolock lock(mMutex); @@ -964,6 +934,7 @@ status_t BufferQueue::consumerConnect(const sp& consumerListen } mConsumerListener = consumerListener; + mConsumerControlledByApp = controlledByApp; return NO_ERROR; } -- cgit v1.2.3-59-g8ed1b From a3fbda3cef04d51a35a3eb64b2f744a989800856 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Thu, 18 Jul 2013 15:55:03 -0700 Subject: BuffferQueue disconnect is now always asynchrnous we tag queued buffers with the "bufferqueue cannot block" flag and use that bit to discard a buffer in the queue by new ones comming in. this allows us to remove the buffer queue drain in disconnect while maintaining the right behaviour if it gets connected again (since each buffer remembers how it was enqueued). Change-Id: I1e703d363a687b70b19ba49cef32213116e8bd3f --- include/gui/BufferQueue.h | 36 +++++++++----------- libs/gui/BufferQueue.cpp | 74 +++++++++++------------------------------ libs/gui/tests/Surface_test.cpp | 4 +-- 3 files changed, 36 insertions(+), 78 deletions(-) (limited to 'libs/gui/BufferQueue.cpp') diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h index f02e25f254..b968287cac 100644 --- a/include/gui/BufferQueue.h +++ b/include/gui/BufferQueue.h @@ -223,13 +223,13 @@ public: // public facing structure for BufferSlot struct BufferItem { - BufferItem() - : + BufferItem() : mTransform(0), mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), mTimestamp(0), mFrameNumber(0), mBuf(INVALID_BUFFER_SLOT), + mDequeueBufferCannotBlock(false), mAcquireCalled(false) { mCrop.makeInvalid(); } @@ -260,6 +260,13 @@ public: // mFence is a fence that will signal when the buffer is idle. sp mFence; + // mDequeueBufferCannotBlock whether this buffer was queued with the + // property that it can be replaced by a new buffer for the purpose of + // making sure dequeueBuffer() won't block. + // i.e.: was the BufferQueue in "mDequeueBufferCannotBlock" when this buffer + // was queued. + bool mDequeueBufferCannotBlock; + // Indicates whether this buffer has been seen by a consumer yet bool mAcquireCalled; }; @@ -366,17 +373,6 @@ private: // all slots. void freeAllBuffersLocked(); - // drainQueueLocked waits for the buffer queue to empty if we're in - // synchronous mode, or returns immediately otherwise. It returns NO_INIT - // if the BufferQueue is abandoned (consumer disconnected) or disconnected - // (producer disconnected) during the call. - status_t drainQueueLocked(); - - // drainQueueAndFreeBuffersLocked drains the buffer queue if we're in - // synchronous mode and free all buffers. In asynchronous mode, all buffers - // are freed except the currently queued buffer (if it exists). - status_t drainQueueAndFreeBuffersLocked(); - // setDefaultMaxBufferCountLocked sets the maximum number of buffer slots // that will be used if the producer does not override the buffer slot // count. The count must be between 2 and NUM_BUFFER_SLOTS, inclusive. @@ -387,15 +383,11 @@ private: // given the current BufferQueue state. int getMinMaxBufferCountLocked() const; - // getMinUndequeuedBufferCountLocked returns the minimum number of buffers - // that must remain in a state other than DEQUEUED. - int getMinUndequeuedBufferCountLocked() const; - // getMaxBufferCountLocked returns the maximum number of buffers that can // be allocated at once. This value depends upon the following member // variables: // - // mSynchronousMode + // mDequeueBufferCannotBlock // mMaxAcquiredBufferCount // mDefaultMaxBufferCount // mOverrideMaxBufferCount @@ -524,6 +516,11 @@ private: // in dequeueBuffer() if a width and height of zero is specified. uint32_t mDefaultHeight; + // mMinUndequeuedBufferCount holds the minimum number of buffers + // that must remain in a state other than DEQUEUED. + // This value cannot change while connected. + int mMinUndequeuedBufferCount; + // mMaxAcquiredBufferCount is the number of buffers that the consumer may // acquire at one time. It defaults to 1 and can be changed by the // consumer via the setMaxAcquiredBufferCount method, but this may only be @@ -564,9 +561,6 @@ private: // by the application. bool mDequeueBufferCannotBlock; - // mSynchronousMode whether we're in synchronous mode or not - bool mSynchronousMode; - // mConnectedApi indicates the producer API that is currently connected // to this BufferQueue. It defaults to NO_CONNECTED_API (= 0), and gets // updated by the connect and disconnect methods. diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index 1e86a4f3df..f99bd29bd5 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -71,7 +71,6 @@ BufferQueue::BufferQueue(const sp& allocator) : mOverrideMaxBufferCount(0), mConsumerControlledByApp(false), mDequeueBufferCannotBlock(false), - mSynchronousMode(true), mConnectedApi(NO_CONNECTED_API), mAbandoned(false), mFrameCounter(0), @@ -210,7 +209,7 @@ int BufferQueue::query(int what, int* outValue) value = mDefaultBufferFormat; break; case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS: - value = getMinUndequeuedBufferCountLocked(); + value = mMinUndequeuedBufferCount; break; case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: value = (mQueue.size() >= 2); @@ -329,7 +328,7 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp* outFence, // make sure the client is not trying to dequeue more buffers // than allowed. const int newUndequeuedCount = maxBufferCount - (dequeuedCount+1); - const int minUndequeuedCount = getMinUndequeuedBufferCountLocked(); + const int minUndequeuedCount = mMinUndequeuedBufferCount; if (newUndequeuedCount < minUndequeuedCount) { ST_LOGE("dequeueBuffer: min undequeued buffer count (%d) " "exceeded (dequeued=%d undequeudCount=%d)", @@ -524,31 +523,27 @@ status_t BufferQueue::queueBuffer(int buf, item.mFrameNumber = mFrameCounter; item.mBuf = buf; item.mFence = fence; + item.mDequeueBufferCannotBlock = mDequeueBufferCannotBlock; - if (mSynchronousMode) { - // In synchronous mode we queue all buffers in a FIFO. + if (mQueue.empty()) { + // when the queue is empty, we can ignore "mDequeueBufferCannotBlock", and + // simply queue this buffer. mQueue.push_back(item); - - // Synchronous mode always signals that an additional frame should - // be consumed. listener = mConsumerListener; } else { - // In asynchronous mode we only keep the most recent buffer. - if (mQueue.empty()) { - mQueue.push_back(item); - - // 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 = mConsumerListener; - } else { - Fifo::iterator front(mQueue.begin()); + // when the queue is not empty, we need to look at the front buffer + // state and see if we need to replace it. + Fifo::iterator front(mQueue.begin()); + if (front->mDequeueBufferCannotBlock) { // buffer slot currently queued is marked free if still tracked if (stillTracking(front)) { mSlots[front->mBuf].mBufferState = BufferSlot::FREE; } - // and we record the new buffer index in the queued list + // and we record the new buffer in the queued list *front = item; + } else { + mQueue.push_back(item); + listener = mConsumerListener; } } @@ -635,7 +630,8 @@ status_t BufferQueue::connect(int api, bool producerControlledByApp, QueueBuffer mBufferHasBeenQueued = false; mDequeueBufferCannotBlock = mConsumerControlledByApp && producerControlledByApp; - mSynchronousMode = !mDequeueBufferCannotBlock; + mMinUndequeuedBufferCount = mDequeueBufferCannotBlock ? + mMaxAcquiredBufferCount+1 : mMaxAcquiredBufferCount; return err; } @@ -662,7 +658,7 @@ status_t BufferQueue::disconnect(int api) { case NATIVE_WINDOW_API_MEDIA: case NATIVE_WINDOW_API_CAMERA: if (mConnectedApi == api) { - drainQueueAndFreeBuffersLocked(); + freeAllBuffersLocked(); mConnectedApi = NO_CONNECTED_API; mDequeueCondition.broadcast(); listener = mConsumerListener; @@ -711,9 +707,9 @@ void BufferQueue::dump(String8& result, const char* prefix) const { int maxBufferCount = getMaxBufferCountLocked(); result.appendFormat( - "%s-BufferQueue maxBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], " + "%s-BufferQueue maxBufferCount=%d, mDequeueBufferCannotBlock=%d, default-size=[%dx%d], " "default-format=%d, transform-hint=%02x, FIFO(%d)={%s}\n", - prefix, maxBufferCount, mSynchronousMode, mDefaultWidth, + prefix, maxBufferCount, mDequeueBufferCannotBlock, mDefaultWidth, mDefaultHeight, mDefaultBufferFormat, mTransformHint, fifoSize, fifo.string()); @@ -768,8 +764,6 @@ void BufferQueue::freeBufferLocked(int slot) { } void BufferQueue::freeAllBuffersLocked() { - ALOGD_IF(!mQueue.isEmpty(), - "freeAllBuffersLocked called with non-empty mQueue"); mBufferHasBeenQueued = false; for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { freeBufferLocked(i); @@ -1024,36 +1018,8 @@ status_t BufferQueue::setMaxAcquiredBufferCount(int maxAcquiredBuffers) { return NO_ERROR; } -status_t BufferQueue::drainQueueLocked() { - while (mSynchronousMode && mQueue.size() > 1) { - mDequeueCondition.wait(mMutex); - if (mAbandoned) { - ST_LOGE("drainQueueLocked: BufferQueue has been abandoned!"); - return NO_INIT; - } - if (mConnectedApi == NO_CONNECTED_API) { - ST_LOGE("drainQueueLocked: BufferQueue is not connected!"); - return NO_INIT; - } - } - return NO_ERROR; -} - -status_t BufferQueue::drainQueueAndFreeBuffersLocked() { - status_t err = drainQueueLocked(); - if (err == NO_ERROR) { - freeAllBuffersLocked(); - } - return err; -} - int BufferQueue::getMinMaxBufferCountLocked() const { - return getMinUndequeuedBufferCountLocked() + 1; -} - -int BufferQueue::getMinUndequeuedBufferCountLocked() const { - return mSynchronousMode ? mMaxAcquiredBufferCount : - mMaxAcquiredBufferCount + 1; + return mMinUndequeuedBufferCount + 1; } int BufferQueue::getMaxBufferCountLocked() const { diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index c55b02aa21..953f6f91dc 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -83,9 +83,7 @@ TEST_F(SurfaceTest, QueuesToWindowComposerIsTrueWhenPurgatorized) { } // This test probably doesn't belong here. -// DISABLED because it hangs when disconnecting because of draining the queue. -// will be fixed in a subsequent BQ change -TEST_F(SurfaceTest, DISABLED_ScreenshotsOfProtectedBuffersSucceed) { +TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersSucceed) { sp anw(mSurface); // Verify the screenshot works with no protected buffers. -- cgit v1.2.3-59-g8ed1b From 7cdd786fa80cf03551291ae8feca7b77583be1c5 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Thu, 18 Jul 2013 22:10:56 -0700 Subject: Make ANW.setSwapInterval(0) work again we can now queue/dequeue a buffer in asynchrnous mode by using the async parameter to these calls. async mode is only specified with those calls (it is not modal anymore). as a consequence it can only be specified when the buffer count is not overidden, as error is returned otherwise. Change-Id: Ic63f4f96f671cb9d65c4cecbcc192615e09a8b6b --- include/gui/BufferQueue.h | 24 +++--- include/gui/IGraphicBufferProducer.h | 17 ++-- include/gui/Surface.h | 4 + libs/gui/BufferQueue.cpp | 91 ++++++++++++++-------- libs/gui/IGraphicBufferProducer.cpp | 9 ++- libs/gui/Surface.cpp | 12 ++- libs/gui/tests/BufferQueue_test.cpp | 6 +- libs/gui/tests/SurfaceTextureClient_test.cpp | 6 -- .../DisplayHardware/VirtualDisplaySurface.cpp | 15 ++-- .../DisplayHardware/VirtualDisplaySurface.h | 4 +- 10 files changed, 113 insertions(+), 75 deletions(-) (limited to 'libs/gui/BufferQueue.cpp') diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h index b968287cac..628678f604 100644 --- a/include/gui/BufferQueue.h +++ b/include/gui/BufferQueue.h @@ -167,7 +167,7 @@ public: // // In both cases, the producer will need to call requestBuffer to get a // GraphicBuffer handle for the returned slot. - virtual status_t dequeueBuffer(int *buf, sp* fence, + virtual status_t dequeueBuffer(int *buf, sp* fence, bool async, uint32_t width, uint32_t height, uint32_t format, uint32_t usage); // queueBuffer returns a filled buffer to the BufferQueue. @@ -229,7 +229,7 @@ public: mTimestamp(0), mFrameNumber(0), mBuf(INVALID_BUFFER_SLOT), - mDequeueBufferCannotBlock(false), + mIsDroppable(false), mAcquireCalled(false) { mCrop.makeInvalid(); } @@ -260,12 +260,12 @@ public: // mFence is a fence that will signal when the buffer is idle. sp mFence; - // mDequeueBufferCannotBlock whether this buffer was queued with the + // mIsDroppable whether this buffer was queued with the // property that it can be replaced by a new buffer for the purpose of // making sure dequeueBuffer() won't block. // i.e.: was the BufferQueue in "mDequeueBufferCannotBlock" when this buffer // was queued. - bool mDequeueBufferCannotBlock; + bool mIsDroppable; // Indicates whether this buffer has been seen by a consumer yet bool mAcquireCalled; @@ -379,9 +379,15 @@ private: // The initial default is 2. status_t setDefaultMaxBufferCountLocked(int count); + // getMinUndequeuedBufferCount returns the minimum number of buffers + // that must remain in a state other than DEQUEUED. + // The async parameter tells whether we're in asynchronous mode. + int getMinUndequeuedBufferCount(bool async) const; + // getMinBufferCountLocked returns the minimum number of buffers allowed // given the current BufferQueue state. - int getMinMaxBufferCountLocked() const; + // The async parameter tells whether we're in asynchronous mode. + int getMinMaxBufferCountLocked(bool async) const; // getMaxBufferCountLocked returns the maximum number of buffers that can // be allocated at once. This value depends upon the following member @@ -391,10 +397,11 @@ private: // mMaxAcquiredBufferCount // mDefaultMaxBufferCount // mOverrideMaxBufferCount + // async parameter // // Any time one of these member variables is changed while a producer is // connected, mDequeueCondition must be broadcast. - int getMaxBufferCountLocked() const; + int getMaxBufferCountLocked(bool async) const; // stillTracking returns true iff the buffer item is still being tracked // in one of the slots. @@ -516,11 +523,6 @@ private: // in dequeueBuffer() if a width and height of zero is specified. uint32_t mDefaultHeight; - // mMinUndequeuedBufferCount holds the minimum number of buffers - // that must remain in a state other than DEQUEUED. - // This value cannot change while connected. - int mMinUndequeuedBufferCount; - // mMaxAcquiredBufferCount is the number of buffers that the consumer may // acquire at one time. It defaults to 1 and can be changed by the // consumer via the setMaxAcquiredBufferCount method, but this may only be diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h index af5fcfc79b..9677962a59 100644 --- a/include/gui/IGraphicBufferProducer.h +++ b/include/gui/IGraphicBufferProducer.h @@ -84,7 +84,10 @@ public: // the buffer. The contents of the buffer must not be overwritten until the // fence signals. If the fence is NULL, the buffer may be written // immediately. - virtual status_t dequeueBuffer(int *slot, sp* fence, + // + // The async parameter sets whether we're in asynchrnous mode for this + // deququeBuffer() call. + virtual status_t dequeueBuffer(int *slot, sp* fence, bool async, uint32_t w, uint32_t h, uint32_t format, uint32_t usage) = 0; // queueBuffer indicates that the client has finished filling in the @@ -96,6 +99,8 @@ public: // must be monotonically increasing. Its other properties (zero point, etc) // are client-dependent, and should be documented by the client. // + // The async parameter sets whether we're queuing a buffer in asynchronous mode. + // // outWidth, outHeight and outTransform are filled with the default width // and height of the window and current transform applied to buffers, // respectively. @@ -103,17 +108,18 @@ public: struct QueueBufferInput : public Flattenable { inline QueueBufferInput(const Parcel& parcel); inline QueueBufferInput(int64_t timestamp, - const Rect& crop, int scalingMode, uint32_t transform, - sp fence) + const Rect& crop, int scalingMode, uint32_t transform, bool async, + const sp& fence) : timestamp(timestamp), crop(crop), scalingMode(scalingMode), - transform(transform), fence(fence) { } + transform(transform), async(async), fence(fence) { } inline void deflate(int64_t* outTimestamp, Rect* outCrop, - int* outScalingMode, uint32_t* outTransform, + int* outScalingMode, uint32_t* outTransform, bool* outAsync, sp* outFence) const { *outTimestamp = timestamp; *outCrop = crop; *outScalingMode = scalingMode; *outTransform = transform; + *outAsync = bool(async); *outFence = fence; } @@ -130,6 +136,7 @@ public: Rect crop; int scalingMode; uint32_t transform; + int async; sp fence; }; diff --git a/include/gui/Surface.h b/include/gui/Surface.h index 6f12e77113..2f7406e2bf 100644 --- a/include/gui/Surface.h +++ b/include/gui/Surface.h @@ -235,6 +235,10 @@ private: // by the application bool mProducerControlledByApp; + // mSwapIntervalZero set if we should drop buffers at queue() time to + // achieve an asynchronous swap interval + bool mSwapIntervalZero; + // mConsumerRunningBehind whether the consumer is running more than // one buffer behind the producer. mutable bool mConsumerRunningBehind; diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index f99bd29bd5..cf8143135e 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -30,6 +30,7 @@ #include #include +#include // Macros for including the BufferQueue name in log messages #define ST_LOGV(x, ...) ALOGV("[%s] "x, mConsumerName.string(), ##__VA_ARGS__) @@ -150,21 +151,21 @@ status_t BufferQueue::setBufferCount(int bufferCount) { } // Error out if the user has dequeued buffers - int maxBufferCount = getMaxBufferCountLocked(); - for (int i=0 ; i= 2); @@ -229,15 +230,11 @@ status_t BufferQueue::requestBuffer(int slot, sp* buf) { ST_LOGE("requestBuffer: BufferQueue has been abandoned!"); return NO_INIT; } - int maxBufferCount = getMaxBufferCountLocked(); - if (slot < 0 || maxBufferCount <= slot) { + if (slot < 0 || slot >= NUM_BUFFER_SLOTS) { ST_LOGE("requestBuffer: slot index out of range [0, %d]: %d", - maxBufferCount, slot); + NUM_BUFFER_SLOTS, slot); return BAD_VALUE; } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) { - // XXX: I vaguely recall there was some reason this can be valid, but - // for the life of me I can't recall under what circumstances that's - // the case. ST_LOGE("requestBuffer: slot %d is not owned by the client (state=%d)", slot, mSlots[slot].mBufferState); return BAD_VALUE; @@ -247,7 +244,7 @@ status_t BufferQueue::requestBuffer(int slot, sp* buf) { return NO_ERROR; } -status_t BufferQueue::dequeueBuffer(int *outBuf, sp* outFence, +status_t BufferQueue::dequeueBuffer(int *outBuf, sp* outFence, bool async, uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { ATRACE_CALL(); ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage); @@ -279,7 +276,16 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp* outFence, return NO_INIT; } - const int maxBufferCount = getMaxBufferCountLocked(); + const int maxBufferCount = getMaxBufferCountLocked(async); + if (async && mOverrideMaxBufferCount) { + // FIXME: some drivers are manually setting the buffer-count (which they + // shouldn't), so we do this extra test here to handle that case. + // This is TEMPORARY, until we get this fixed. + if (mOverrideMaxBufferCount < maxBufferCount) { + ST_LOGE("dequeueBuffer: async mode is invalid with buffercount override"); + return BAD_VALUE; + } + } // Free up any buffers that are in slots beyond the max buffer // count. @@ -328,7 +334,7 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp* outFence, // make sure the client is not trying to dequeue more buffers // than allowed. const int newUndequeuedCount = maxBufferCount - (dequeuedCount+1); - const int minUndequeuedCount = mMinUndequeuedBufferCount; + const int minUndequeuedCount = getMinUndequeuedBufferCount(async); if (newUndequeuedCount < minUndequeuedCount) { ST_LOGE("dequeueBuffer: min undequeued buffer count (%d) " "exceeded (dequeued=%d undequeudCount=%d)", @@ -448,9 +454,10 @@ status_t BufferQueue::queueBuffer(int buf, uint32_t transform; int scalingMode; int64_t timestamp; + bool async; sp fence; - input.deflate(×tamp, &crop, &scalingMode, &transform, &fence); + input.deflate(×tamp, &crop, &scalingMode, &transform, &async, &fence); if (fence == NULL) { ST_LOGE("queueBuffer: fence is NULL"); @@ -477,7 +484,17 @@ status_t BufferQueue::queueBuffer(int buf, ST_LOGE("queueBuffer: BufferQueue has been abandoned!"); return NO_INIT; } - int maxBufferCount = getMaxBufferCountLocked(); + + const int maxBufferCount = getMaxBufferCountLocked(async); + if (async && mOverrideMaxBufferCount) { + // FIXME: some drivers are manually setting the buffer-count (which they + // shouldn't), so we do this extra test here to handle that case. + // This is TEMPORARY, until we get this fixed. + if (mOverrideMaxBufferCount < maxBufferCount) { + ST_LOGE("queueBuffer: async mode is invalid with buffercount override"); + return BAD_VALUE; + } + } if (buf < 0 || buf >= maxBufferCount) { ST_LOGE("queueBuffer: slot index out of range [0, %d]: %d", maxBufferCount, buf); @@ -523,7 +540,7 @@ status_t BufferQueue::queueBuffer(int buf, item.mFrameNumber = mFrameCounter; item.mBuf = buf; item.mFence = fence; - item.mDequeueBufferCannotBlock = mDequeueBufferCannotBlock; + item.mIsDroppable = mDequeueBufferCannotBlock || async; if (mQueue.empty()) { // when the queue is empty, we can ignore "mDequeueBufferCannotBlock", and @@ -534,7 +551,7 @@ status_t BufferQueue::queueBuffer(int buf, // when the queue is not empty, we need to look at the front buffer // state and see if we need to replace it. Fifo::iterator front(mQueue.begin()); - if (front->mDequeueBufferCannotBlock) { + if (front->mIsDroppable) { // buffer slot currently queued is marked free if still tracked if (stillTracking(front)) { mSlots[front->mBuf].mBufferState = BufferSlot::FREE; @@ -573,10 +590,9 @@ void BufferQueue::cancelBuffer(int buf, const sp& fence) { return; } - int maxBufferCount = getMaxBufferCountLocked(); - if (buf < 0 || buf >= maxBufferCount) { + if (buf < 0 || buf >= NUM_BUFFER_SLOTS) { ST_LOGE("cancelBuffer: slot index out of range [0, %d]: %d", - maxBufferCount, buf); + NUM_BUFFER_SLOTS, buf); return; } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) { ST_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)", @@ -630,8 +646,6 @@ status_t BufferQueue::connect(int api, bool producerControlledByApp, QueueBuffer mBufferHasBeenQueued = false; mDequeueBufferCannotBlock = mConsumerControlledByApp && producerControlledByApp; - mMinUndequeuedBufferCount = mDequeueBufferCannotBlock ? - mMaxAcquiredBufferCount+1 : mMaxAcquiredBufferCount; return err; } @@ -704,12 +718,11 @@ void BufferQueue::dump(String8& result, const char* prefix) const { fifoSize++; } - int maxBufferCount = getMaxBufferCountLocked(); result.appendFormat( - "%s-BufferQueue maxBufferCount=%d, mDequeueBufferCannotBlock=%d, default-size=[%dx%d], " + "%s-BufferQueue mMaxAcquiredBufferCount=%d, mDequeueBufferCannotBlock=%d, default-size=[%dx%d], " "default-format=%d, transform-hint=%02x, FIFO(%d)={%s}\n", - prefix, maxBufferCount, mDequeueBufferCannotBlock, mDefaultWidth, + prefix, mMaxAcquiredBufferCount, mDequeueBufferCannotBlock, mDefaultWidth, mDefaultHeight, mDefaultBufferFormat, mTransformHint, fifoSize, fifo.string()); @@ -725,16 +738,25 @@ void BufferQueue::dump(String8& result, const char* prefix) const { } } stateName; + // just trim the free buffers to not spam the dump + int maxBufferCount = 0; + for (int i=NUM_BUFFER_SLOTS-1 ; i>=0 ; i--) { + const BufferSlot& slot(mSlots[i]); + if ((slot.mBufferState != BufferSlot::FREE) || (slot.mGraphicBuffer != NULL)) { + maxBufferCount = i+1; + break; + } + } + for (int i=0 ; i& buf(slot.mGraphicBuffer); result.appendFormat( "%s%s[%02d:%p] state=%-8s", - prefix, (slot.mBufferState == BufferSlot::ACQUIRED)?">":" ", i, - slot.mGraphicBuffer.get(), + prefix, (slot.mBufferState == BufferSlot::ACQUIRED)?">":" ", i, buf.get(), stateName(slot.mBufferState) ); - const sp& buf(slot.mGraphicBuffer); if (buf != NULL) { result.appendFormat( ", %p [%4ux%4u:%4u,%3X]", @@ -1018,12 +1040,17 @@ status_t BufferQueue::setMaxAcquiredBufferCount(int maxAcquiredBuffers) { return NO_ERROR; } -int BufferQueue::getMinMaxBufferCountLocked() const { - return mMinUndequeuedBufferCount + 1; +int BufferQueue::getMinUndequeuedBufferCount(bool async) const { + return (mDequeueBufferCannotBlock || async) ? + mMaxAcquiredBufferCount+1 : mMaxAcquiredBufferCount; +} + +int BufferQueue::getMinMaxBufferCountLocked(bool async) const { + return getMinUndequeuedBufferCount(async) + 1; } -int BufferQueue::getMaxBufferCountLocked() const { - int minMaxBufferCount = getMinMaxBufferCountLocked(); +int BufferQueue::getMaxBufferCountLocked(bool async) const { + int minMaxBufferCount = getMinMaxBufferCountLocked(async); int maxBufferCount = mDefaultMaxBufferCount; if (maxBufferCount < minMaxBufferCount) { diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index 9f65fc3f2b..2e561dfc29 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -80,10 +80,11 @@ public: return result; } - virtual status_t dequeueBuffer(int *buf, sp* fence, + virtual status_t dequeueBuffer(int *buf, sp* fence, bool async, uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); + data.writeInt32(async); data.writeInt32(w); data.writeInt32(h); data.writeInt32(format); @@ -197,13 +198,14 @@ status_t BnGraphicBufferProducer::onTransact( } break; case DEQUEUE_BUFFER: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); + bool async = data.readInt32(); uint32_t w = data.readInt32(); uint32_t h = data.readInt32(); uint32_t format = data.readInt32(); uint32_t usage = data.readInt32(); int buf; sp fence; - int result = dequeueBuffer(&buf, &fence, w, h, format, usage); + int result = dequeueBuffer(&buf, &fence, async, w, h, format, usage); reply->writeInt32(buf); reply->writeInt32(fence != NULL); if (fence != NULL) { @@ -274,6 +276,7 @@ size_t IGraphicBufferProducer::QueueBufferInput::getFlattenedSize() const + sizeof(crop) + sizeof(scalingMode) + sizeof(transform) + + sizeof(async) + fence->getFlattenedSize(); } @@ -291,6 +294,7 @@ status_t IGraphicBufferProducer::QueueBufferInput::flatten(void* buffer, size_t memcpy(p, &crop, sizeof(crop)); p += sizeof(crop); memcpy(p, &scalingMode, sizeof(scalingMode)); p += sizeof(scalingMode); memcpy(p, &transform, sizeof(transform)); p += sizeof(transform); + memcpy(p, &async, sizeof(async)); p += sizeof(async); err = fence->flatten(p, size - (p - (char*)buffer), fds, count); return err; } @@ -304,6 +308,7 @@ status_t IGraphicBufferProducer::QueueBufferInput::unflatten(void const* buffer, memcpy(&crop, p, sizeof(crop)); p += sizeof(crop); memcpy(&scalingMode, p, sizeof(scalingMode)); p += sizeof(scalingMode); memcpy(&transform, p, sizeof(transform)); p += sizeof(transform); + memcpy(&async, p, sizeof(async)); p += sizeof(async); fence = new Fence(); err = fence->unflatten(p, size - (p - (const char*)buffer), fds, count); return err; diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 0d4449af65..998ea8ac8c 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -73,6 +73,7 @@ Surface::Surface( mConsumerRunningBehind = false; mConnectedToCpu = false; mProducerControlledByApp = true; + mSwapIntervalZero = false; } Surface::~Surface() { @@ -162,7 +163,6 @@ int Surface::setSwapInterval(int interval) { // EGL specification states: // interval is silently clamped to minimum and maximum implementation // dependent values before being stored. - // Although we don't have to, we apply the same logic here. if (interval < minSwapInterval) interval = minSwapInterval; @@ -170,11 +170,9 @@ int Surface::setSwapInterval(int interval) { if (interval > maxSwapInterval) interval = maxSwapInterval; - // FIXME: re-implement swap-interval - //status_t res = mGraphicBufferProducer->setSynchronousMode(interval ? true : false); - status_t res = NO_ERROR; + mSwapIntervalZero = (interval == 0); - return res; + return NO_ERROR; } int Surface::dequeueBuffer(android_native_buffer_t** buffer, @@ -186,7 +184,7 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer, int reqW = mReqWidth ? mReqWidth : mUserWidth; int reqH = mReqHeight ? mReqHeight : mUserHeight; sp fence; - status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, + status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, mSwapIntervalZero, reqW, reqH, mReqFormat, mReqUsage); if (result < 0) { ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer(%d, %d, %d, %d)" @@ -282,7 +280,7 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { sp fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE); IGraphicBufferProducer::QueueBufferOutput output; IGraphicBufferProducer::QueueBufferInput input(timestamp, crop, mScalingMode, - mTransform, fence); + mTransform, mSwapIntervalZero, fence); status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output); if (err != OK) { ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err); diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp index 1f8e7fa0db..b691fc111f 100644 --- a/libs/gui/tests/BufferQueue_test.cpp +++ b/libs/gui/tests/BufferQueue_test.cpp @@ -71,12 +71,12 @@ TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) { sp fence; sp buf; IGraphicBufferProducer::QueueBufferInput qbi(0, Rect(0, 0, 1, 1), - NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); + NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, Fence::NO_FENCE); BufferQueue::BufferItem item; for (int i = 0; i < 2; i++) { ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mBQ->dequeueBuffer(&slot, &fence, 1, 1, 0, + mBQ->dequeueBuffer(&slot, &fence, false, 1, 1, 0, GRALLOC_USAGE_SW_READ_OFTEN)); ASSERT_EQ(OK, mBQ->requestBuffer(slot, &buf)); ASSERT_EQ(OK, mBQ->queueBuffer(slot, qbi, &qbo)); @@ -84,7 +84,7 @@ TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) { } ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mBQ->dequeueBuffer(&slot, &fence, 1, 1, 0, + mBQ->dequeueBuffer(&slot, &fence, false, 1, 1, 0, GRALLOC_USAGE_SW_READ_OFTEN)); ASSERT_EQ(OK, mBQ->requestBuffer(slot, &buf)); ASSERT_EQ(OK, mBQ->queueBuffer(slot, qbi, &qbo)); diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp index 9908cc9db5..158c94b696 100644 --- a/libs/gui/tests/SurfaceTextureClient_test.cpp +++ b/libs/gui/tests/SurfaceTextureClient_test.cpp @@ -361,7 +361,6 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureTooManyUpdateTexImage) { TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeSlowRetire) { android_native_buffer_t* buf[3]; - ASSERT_EQ(OK, mANW->setSwapInterval(mANW.get(), 1)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); @@ -382,7 +381,6 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeSlowRetire) { TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeFastRetire) { android_native_buffer_t* buf[3]; - ASSERT_EQ(OK, mANW->setSwapInterval(mANW.get(), 1)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); @@ -403,7 +401,6 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeFastRetire) { TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeDQQR) { android_native_buffer_t* buf[3]; - ASSERT_EQ(OK, mANW->setSwapInterval(mANW.get(), 1)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); @@ -429,7 +426,6 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeDQQR) { TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeDequeueCurrent) { android_native_buffer_t* buf[3]; android_native_buffer_t* firstBuf; - ASSERT_EQ(OK, mANW->setSwapInterval(mANW.get(), 1)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &firstBuf)); ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), firstBuf, -1)); @@ -449,7 +445,6 @@ TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeDequeueCurrent) TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeMinUndequeued) { android_native_buffer_t* buf[3]; - ASSERT_EQ(OK, mANW->setSwapInterval(mANW.get(), 1)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3)); // We should be able to dequeue all the buffers before we've queued mANWy. @@ -528,7 +523,6 @@ TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeWaitRetire) { }; android_native_buffer_t* buf[3]; - ASSERT_EQ(OK, mANW->setSwapInterval(mANW.get(), 1)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3)); // dequeue/queue/update so we have a current buffer ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp index c92b66654e..57cb361710 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp @@ -126,7 +126,7 @@ status_t VirtualDisplaySurface::advanceFrame() { mQueueBufferOutput.deflate(&mSinkBufferWidth, &mSinkBufferHeight, &transformHint, &numPendingBuffers); int sslot; - result = dequeueBuffer(SOURCE_SINK, 0, &sslot, &outFence); + result = dequeueBuffer(SOURCE_SINK, 0, &sslot, &outFence, false); if (result < 0) return result; mOutputProducerSlot = mapSource2ProducerSlot(SOURCE_SINK, sslot); @@ -196,7 +196,7 @@ void VirtualDisplaySurface::onFrameCommitted() { status_t result = mSource[SOURCE_SINK]->queueBuffer(sslot, QueueBufferInput(systemTime(), Rect(mSinkBufferWidth, mSinkBufferHeight), - NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, outFence), + NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, outFence), &qbo); if (result == NO_ERROR) { updateQueueBufferOutput(qbo); @@ -224,8 +224,8 @@ status_t VirtualDisplaySurface::setBufferCount(int bufferCount) { } status_t VirtualDisplaySurface::dequeueBuffer(Source source, - uint32_t format, int* sslot, sp* fence) { - status_t result = mSource[source]->dequeueBuffer(sslot, fence, + uint32_t format, int* sslot, sp* fence, bool async) { + status_t result = mSource[source]->dequeueBuffer(sslot, fence, async, mSinkBufferWidth, mSinkBufferHeight, format, mProducerUsage); if (result < 0) return result; @@ -257,7 +257,7 @@ status_t VirtualDisplaySurface::dequeueBuffer(Source source, return result; } -status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp* fence, +status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp* fence, bool async, uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { VDS_LOGW_IF(mDbgState != DBG_STATE_PREPARED, "Unexpected dequeueBuffer() in %s state", dbgStateStr()); @@ -273,7 +273,7 @@ status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp* fence, } int sslot; - status_t result = dequeueBuffer(source, format, &sslot, fence); + status_t result = dequeueBuffer(source, format, &sslot, fence, async); if (result >= 0) { *pslot = mapSource2ProducerSlot(source, sslot); } @@ -321,8 +321,9 @@ status_t VirtualDisplaySurface::queueBuffer(int pslot, Rect crop; int scalingMode; uint32_t transform; + bool async; input.deflate(×tamp, &crop, &scalingMode, &transform, - &mFbFence); + &async, &mFbFence); mFbProducerSlot = pslot; } diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h index 94b24d2e1f..dc9655b626 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h @@ -95,7 +95,7 @@ private: // virtual status_t requestBuffer(int pslot, sp* outBuf); virtual status_t setBufferCount(int bufferCount); - virtual status_t dequeueBuffer(int* pslot, sp* fence, + virtual status_t dequeueBuffer(int* pslot, sp* fence, bool async, uint32_t w, uint32_t h, uint32_t format, uint32_t usage); virtual status_t queueBuffer(int pslot, const QueueBufferInput& input, QueueBufferOutput* output); @@ -109,7 +109,7 @@ private: // static Source fbSourceForCompositionType(CompositionType type); status_t dequeueBuffer(Source source, uint32_t format, - int* sslot, sp* fence); + int* sslot, sp* fence, bool async); void updateQueueBufferOutput(const QueueBufferOutput& qbo); void resetPerFrameState(); -- cgit v1.2.3-59-g8ed1b From 26a6f37cc06b8014edcedbee8d5558ca7da9abe3 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Thu, 18 Jul 2013 22:25:55 -0700 Subject: make sure to reset the framenumber when a buffer is marked FREE Change-Id: Ic45929f35553de209801f74e8006fb1bf0b25b45 --- libs/gui/BufferQueue.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'libs/gui/BufferQueue.cpp') diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index cf8143135e..73bd4888ba 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -555,6 +555,9 @@ status_t BufferQueue::queueBuffer(int buf, // buffer slot currently queued is marked free if still tracked if (stillTracking(front)) { mSlots[front->mBuf].mBufferState = BufferSlot::FREE; + // reset the frame number of the freed buffer so that it is the first in + // line to be dequeued again. + mSlots[front->mBuf].mFrameNumber = 0; } // and we record the new buffer in the queued list *front = item; -- cgit v1.2.3-59-g8ed1b