Merge "BufferQueue: simplify max buffer count handling" into jb-mr1-dev

This commit is contained in:
Jamie Gennis 2012-08-30 18:23:26 -07:00 committed by Android (Google) Code Review
commit 1847f7fd79
2 changed files with 81 additions and 86 deletions

View File

@ -307,6 +307,19 @@ private:
// given the current BufferQueue state. // given the current BufferQueue state.
int getMinMaxBufferCountLocked() const; int getMinMaxBufferCountLocked() const;
// getMaxBufferCountLocked returns the maximum number of buffers that can
// be allocated at once. This value depends upon the following member
// variables:
//
// mSynchronousMode
// mMinUndequeuedBuffers
// mDefaultMaxBufferCount
// mOverrideMaxBufferCount
//
// Any time one of these member variables is changed while a producer is
// connected, mDequeueCondition must be broadcast.
int getMaxBufferCountLocked() const;
struct BufferSlot { struct BufferSlot {
BufferSlot() BufferSlot()
@ -433,10 +446,6 @@ private:
// not dequeued at any time // not dequeued at any time
int mMinUndequeuedBuffers; int mMinUndequeuedBuffers;
// mMaxBufferCount is the maximum number of buffers that will be allocated
// at once.
int mMaxBufferCount;
// mDefaultMaxBufferCount is the default limit on the number of buffers // mDefaultMaxBufferCount is the default limit on the number of buffers
// that will be allocated at one time. This default limit is set by the // that will be allocated at one time. This default limit is set by the
// consumer. The limit (as opposed to the default limit) may be // consumer. The limit (as opposed to the default limit) may be

View File

@ -86,7 +86,6 @@ BufferQueue::BufferQueue(bool allowSynchronousMode, int bufferCount,
mDefaultWidth(1), mDefaultWidth(1),
mDefaultHeight(1), mDefaultHeight(1),
mMinUndequeuedBuffers(bufferCount), mMinUndequeuedBuffers(bufferCount),
mMaxBufferCount(bufferCount + 1),
mDefaultMaxBufferCount(bufferCount + 1), mDefaultMaxBufferCount(bufferCount + 1),
mOverrideMaxBufferCount(0), mOverrideMaxBufferCount(0),
mSynchronousMode(false), mSynchronousMode(false),
@ -119,37 +118,12 @@ BufferQueue::~BufferQueue() {
} }
status_t BufferQueue::setDefaultMaxBufferCountLocked(int count) { status_t BufferQueue::setDefaultMaxBufferCountLocked(int count) {
if (count > NUM_BUFFER_SLOTS) if (count < 2 || count > NUM_BUFFER_SLOTS)
return BAD_VALUE; return BAD_VALUE;
mDefaultMaxBufferCount = count; mDefaultMaxBufferCount = count;
mDequeueCondition.broadcast();
if (count == mMaxBufferCount)
return OK;
if (!mOverrideMaxBufferCount &&
count >= mMaxBufferCount) {
// easy, we just have more buffers
mMaxBufferCount = count;
mDequeueCondition.broadcast();
} else {
// we're here because we're either
// - reducing the number of available buffers
// - or there is a client-buffer-count in effect
// less than 2 buffers is never allowed
if (count < 2)
return BAD_VALUE;
// When there is no client-buffer-count in effect, the client is not
// allowed to dequeue more than one buffer at a time, so the next time
// they dequeue a buffer, we know that they don't own one. the actual
// resizing will happen during the next dequeueBuffer.
// We signal this condition in case there is already a blocked
// dequeueBuffer call.
mDequeueCondition.broadcast();
}
return OK; return OK;
} }
@ -198,7 +172,8 @@ status_t BufferQueue::setBufferCount(int bufferCount) {
} }
// Error out if the user has dequeued buffers // Error out if the user has dequeued buffers
for (int i=0 ; i<mMaxBufferCount ; i++) { int maxBufferCount = getMaxBufferCountLocked();
for (int i=0 ; i<maxBufferCount; i++) {
if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) { if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) {
ST_LOGE("setBufferCount: client owns some buffers"); ST_LOGE("setBufferCount: client owns some buffers");
return -EINVAL; return -EINVAL;
@ -208,9 +183,8 @@ status_t BufferQueue::setBufferCount(int bufferCount) {
const int minBufferSlots = getMinMaxBufferCountLocked(); const int minBufferSlots = getMinMaxBufferCountLocked();
if (bufferCount == 0) { if (bufferCount == 0) {
mOverrideMaxBufferCount = 0; mOverrideMaxBufferCount = 0;
bufferCount = (mDefaultMaxBufferCount >= minBufferSlots) ? mDequeueCondition.broadcast();
mDefaultMaxBufferCount : minBufferSlots; return OK;
return setDefaultMaxBufferCountLocked(bufferCount);
} }
if (bufferCount < minBufferSlots) { if (bufferCount < minBufferSlots) {
@ -221,11 +195,11 @@ status_t BufferQueue::setBufferCount(int bufferCount) {
// here we're guaranteed that the client doesn't have dequeued buffers // here we're guaranteed that the client doesn't have dequeued buffers
// and will release all of its buffer references. // and will release all of its buffer references.
//
// XXX: Should this use drainQueueAndFreeBuffersLocked instead?
freeAllBuffersLocked(); freeAllBuffersLocked();
mMaxBufferCount = bufferCount;
mOverrideMaxBufferCount = bufferCount; mOverrideMaxBufferCount = bufferCount;
mBufferHasBeenQueued = false; mBufferHasBeenQueued = false;
mQueue.clear();
mDequeueCondition.broadcast(); mDequeueCondition.broadcast();
listener = mConsumerListener; listener = mConsumerListener;
} // scope for lock } // scope for lock
@ -280,9 +254,17 @@ status_t BufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
ST_LOGE("requestBuffer: SurfaceTexture has been abandoned!"); ST_LOGE("requestBuffer: SurfaceTexture has been abandoned!");
return NO_INIT; return NO_INIT;
} }
if (slot < 0 || mMaxBufferCount <= slot) { int maxBufferCount = getMaxBufferCountLocked();
if (slot < 0 || maxBufferCount <= slot) {
ST_LOGE("requestBuffer: slot index out of range [0, %d]: %d", ST_LOGE("requestBuffer: slot index out of range [0, %d]: %d",
mMaxBufferCount, slot); maxBufferCount, 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; return BAD_VALUE;
} }
mSlots[slot].mRequestBufferCalled = true; mSlots[slot].mRequestBufferCalled = true;
@ -322,49 +304,22 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>& outFence,
return NO_INIT; return NO_INIT;
} }
// We need to wait for the FIFO to drain if the number of buffer const int maxBufferCount = getMaxBufferCountLocked();
// needs to change.
//
// The condition "number of buffers needs to change" is true if
// - the client doesn't care about how many buffers there are
// - AND the actual number of buffer is different from what was
// set in the last setDefaultMaxBufferCount()
// - OR -
// setDefaultMaxBufferCount() was set to a value incompatible with
// the synchronization mode (for instance because the sync mode
// changed since)
//
// As long as this condition is true AND the FIFO is not empty, we
// wait on mDequeueCondition.
const int minBufferCountNeeded = getMinMaxBufferCountLocked(); // Free up any buffers that are in slots beyond the max buffer
// count.
const bool numberOfBuffersNeedsToChange = !mOverrideMaxBufferCount && for (int i = maxBufferCount; i < NUM_BUFFER_SLOTS; i++) {
((mDefaultMaxBufferCount != mMaxBufferCount) || assert(mSlots[i].mBufferState == BufferSlot::FREE);
(mDefaultMaxBufferCount < minBufferCountNeeded)); if (mSlots[i].mGraphicBuffer != NULL) {
freeBufferLocked(i);
if (!mQueue.isEmpty() && numberOfBuffersNeedsToChange) { returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS;
// wait for the FIFO to drain }
mDequeueCondition.wait(mMutex);
// NOTE: we continue here because we need to reevaluate our
// whole state (eg: we could be abandoned or disconnected)
continue;
}
if (numberOfBuffersNeedsToChange) {
// here we're guaranteed that mQueue is empty
freeAllBuffersLocked();
mMaxBufferCount = mDefaultMaxBufferCount;
if (mMaxBufferCount < minBufferCountNeeded)
mMaxBufferCount = minBufferCountNeeded;
mBufferHasBeenQueued = false;
returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS;
} }
// look for a free buffer to give to the client // look for a free buffer to give to the client
found = INVALID_BUFFER_SLOT; found = INVALID_BUFFER_SLOT;
dequeuedCount = 0; dequeuedCount = 0;
for (int i = 0; i < mMaxBufferCount; i++) { for (int i = 0; i < maxBufferCount; i++) {
const int state = mSlots[i].mBufferState; const int state = mSlots[i].mBufferState;
if (state == BufferSlot::DEQUEUED) { if (state == BufferSlot::DEQUEUED) {
dequeuedCount++; dequeuedCount++;
@ -406,7 +361,7 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>& outFence,
if (mBufferHasBeenQueued) { if (mBufferHasBeenQueued) {
// make sure the client is not trying to dequeue more buffers // make sure the client is not trying to dequeue more buffers
// than allowed. // than allowed.
const int avail = mMaxBufferCount - (dequeuedCount+1); const int avail = maxBufferCount - (dequeuedCount+1);
if (avail < (mMinUndequeuedBuffers-int(mSynchronousMode))) { if (avail < (mMinUndequeuedBuffers-int(mSynchronousMode))) {
ST_LOGE("dequeueBuffer: mMinUndequeuedBuffers=%d exceeded " ST_LOGE("dequeueBuffer: mMinUndequeuedBuffers=%d exceeded "
"(dequeued=%d)", "(dequeued=%d)",
@ -416,7 +371,8 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>& outFence,
} }
} }
// if no buffer is found, wait for a buffer to be released // If no buffer is found, wait for a buffer to be released or for
// the max buffer count to change.
tryAgain = found == INVALID_BUFFER_SLOT; tryAgain = found == INVALID_BUFFER_SLOT;
if (tryAgain) { if (tryAgain) {
mDequeueCondition.wait(mMutex); mDequeueCondition.wait(mMutex);
@ -557,9 +513,10 @@ status_t BufferQueue::queueBuffer(int buf,
ST_LOGE("queueBuffer: SurfaceTexture has been abandoned!"); ST_LOGE("queueBuffer: SurfaceTexture has been abandoned!");
return NO_INIT; return NO_INIT;
} }
if (buf < 0 || buf >= mMaxBufferCount) { int maxBufferCount = getMaxBufferCountLocked();
if (buf < 0 || buf >= maxBufferCount) {
ST_LOGE("queueBuffer: slot index out of range [0, %d]: %d", ST_LOGE("queueBuffer: slot index out of range [0, %d]: %d",
mMaxBufferCount, buf); maxBufferCount, buf);
return -EINVAL; return -EINVAL;
} else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) { } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
ST_LOGE("queueBuffer: slot %d is not owned by the client " ST_LOGE("queueBuffer: slot %d is not owned by the client "
@ -653,9 +610,10 @@ void BufferQueue::cancelBuffer(int buf, sp<Fence> fence) {
return; return;
} }
if (buf < 0 || buf >= mMaxBufferCount) { int maxBufferCount = getMaxBufferCountLocked();
if (buf < 0 || buf >= maxBufferCount) {
ST_LOGE("cancelBuffer: slot index out of range [0, %d]: %d", ST_LOGE("cancelBuffer: slot index out of range [0, %d]: %d",
mMaxBufferCount, buf); maxBufferCount, buf);
return; return;
} else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) { } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
ST_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)", ST_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)",
@ -775,10 +733,12 @@ void BufferQueue::dump(String8& result, const char* prefix,
fifo.append(buffer); fifo.append(buffer);
} }
int maxBufferCount = getMaxBufferCountLocked();
snprintf(buffer, SIZE, snprintf(buffer, SIZE,
"%s-BufferQueue mMaxBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], " "%s-BufferQueue maxBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], "
"default-format=%d, FIFO(%d)={%s}\n", "default-format=%d, FIFO(%d)={%s}\n",
prefix, mMaxBufferCount, mSynchronousMode, mDefaultWidth, prefix, maxBufferCount, mSynchronousMode, mDefaultWidth,
mDefaultHeight, mDefaultBufferFormat, fifoSize, fifo.string()); mDefaultHeight, mDefaultBufferFormat, fifoSize, fifo.string());
result.append(buffer); result.append(buffer);
@ -795,7 +755,7 @@ void BufferQueue::dump(String8& result, const char* prefix,
} }
} stateName; } stateName;
for (int i=0 ; i<mMaxBufferCount ; i++) { for (int i=0 ; i<maxBufferCount ; i++) {
const BufferSlot& slot(mSlots[i]); const BufferSlot& slot(mSlots[i]);
snprintf(buffer, SIZE, snprintf(buffer, SIZE,
"%s%s[%02d] " "%s%s[%02d] "
@ -1039,6 +999,32 @@ int BufferQueue::getMinMaxBufferCountLocked() const {
return mSynchronousMode ? mMinUndequeuedBuffers : mMinUndequeuedBuffers + 1; return mSynchronousMode ? mMinUndequeuedBuffers : mMinUndequeuedBuffers + 1;
} }
int BufferQueue::getMaxBufferCountLocked() const {
int minMaxBufferCount = getMinMaxBufferCountLocked();
int maxBufferCount = mDefaultMaxBufferCount;
if (maxBufferCount < minMaxBufferCount) {
maxBufferCount = minMaxBufferCount;
}
if (mOverrideMaxBufferCount != 0) {
assert(mOverrideMaxBufferCount >= minMaxBufferCount);
maxBufferCount = mOverrideMaxBufferCount;
}
// Any buffers that are dequeued by the producer or sitting in the queue
// waiting to be consumed need to have their slots preserved. Such
// buffers will temporarily keep the max buffer count up until the slots
// no longer need to be preserved.
for (int i = maxBufferCount; i < NUM_BUFFER_SLOTS; i++) {
BufferSlot::BufferState state = mSlots[i].mBufferState;
if (state == BufferSlot::QUEUED || state == BufferSlot::DEQUEUED) {
maxBufferCount = i + 1;
}
}
return maxBufferCount;
}
BufferQueue::ProxyConsumerListener::ProxyConsumerListener( BufferQueue::ProxyConsumerListener::ProxyConsumerListener(
const wp<BufferQueue::ConsumerListener>& consumerListener): const wp<BufferQueue::ConsumerListener>& consumerListener):
mConsumerListener(consumerListener) {} mConsumerListener(consumerListener) {}