// 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();
}
// mFence is a fence that will signal when the buffer is idle.
sp<Fence> 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;
};
// 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.
// 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
// 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
// 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.
mOverrideMaxBufferCount(0),
mConsumerControlledByApp(false),
mDequeueBufferCannotBlock(false),
- mSynchronousMode(true),
mConnectedApi(NO_CONNECTED_API),
mAbandoned(false),
mFrameCounter(0),
value = mDefaultBufferFormat;
break;
case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
- value = getMinUndequeuedBufferCountLocked();
+ value = mMinUndequeuedBufferCount;
break;
case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND:
value = (mQueue.size() >= 2);
// 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)",
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;
}
}
mBufferHasBeenQueued = false;
mDequeueBufferCannotBlock = mConsumerControlledByApp && producerControlledByApp;
- mSynchronousMode = !mDequeueBufferCannotBlock;
+ mMinUndequeuedBufferCount = mDequeueBufferCannotBlock ?
+ mMaxAcquiredBufferCount+1 : mMaxAcquiredBufferCount;
return err;
}
case NATIVE_WINDOW_API_MEDIA:
case NATIVE_WINDOW_API_CAMERA:
if (mConnectedApi == api) {
- drainQueueAndFreeBuffersLocked();
+ freeAllBuffersLocked();
mConnectedApi = NO_CONNECTED_API;
mDequeueCondition.broadcast();
listener = mConsumerListener;
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());
}
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);
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 {