Loading include/gui/BufferQueue.h +13 −4 Original line number Diff line number Diff line Loading @@ -307,6 +307,19 @@ private: // given the current BufferQueue state. 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 { BufferSlot() Loading Loading @@ -433,10 +446,6 @@ private: // not dequeued at any time 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 // 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 Loading libs/gui/BufferQueue.cpp +68 −82 Original line number Diff line number Diff line Loading @@ -86,7 +86,6 @@ BufferQueue::BufferQueue(bool allowSynchronousMode, int bufferCount, mDefaultWidth(1), mDefaultHeight(1), mMinUndequeuedBuffers(bufferCount), mMaxBufferCount(bufferCount + 1), mDefaultMaxBufferCount(bufferCount + 1), mOverrideMaxBufferCount(0), mSynchronousMode(false), Loading Loading @@ -119,37 +118,12 @@ BufferQueue::~BufferQueue() { } status_t BufferQueue::setDefaultMaxBufferCountLocked(int count) { if (count > NUM_BUFFER_SLOTS) if (count < 2 || count > NUM_BUFFER_SLOTS) return BAD_VALUE; mDefaultMaxBufferCount = count; 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; } Loading Loading @@ -198,7 +172,8 @@ status_t BufferQueue::setBufferCount(int bufferCount) { } // 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) { ST_LOGE("setBufferCount: client owns some buffers"); return -EINVAL; Loading @@ -208,9 +183,8 @@ status_t BufferQueue::setBufferCount(int bufferCount) { const int minBufferSlots = getMinMaxBufferCountLocked(); if (bufferCount == 0) { mOverrideMaxBufferCount = 0; bufferCount = (mDefaultMaxBufferCount >= minBufferSlots) ? mDefaultMaxBufferCount : minBufferSlots; return setDefaultMaxBufferCountLocked(bufferCount); mDequeueCondition.broadcast(); return OK; } if (bufferCount < minBufferSlots) { Loading @@ -221,11 +195,11 @@ status_t BufferQueue::setBufferCount(int bufferCount) { // here we're guaranteed that the client doesn't have dequeued buffers // and will release all of its buffer references. // // XXX: Should this use drainQueueAndFreeBuffersLocked instead? freeAllBuffersLocked(); mMaxBufferCount = bufferCount; mOverrideMaxBufferCount = bufferCount; mBufferHasBeenQueued = false; mQueue.clear(); mDequeueCondition.broadcast(); listener = mConsumerListener; } // scope for lock Loading Loading @@ -280,9 +254,17 @@ status_t BufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) { ST_LOGE("requestBuffer: SurfaceTexture has been abandoned!"); 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", 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; } mSlots[slot].mRequestBufferCalled = true; Loading Loading @@ -322,49 +304,22 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>& outFence, return NO_INIT; } // We need to wait for the FIFO to drain if the number of buffer // 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(); const int maxBufferCount = getMaxBufferCountLocked(); const bool numberOfBuffersNeedsToChange = !mOverrideMaxBufferCount && ((mDefaultMaxBufferCount != mMaxBufferCount) || (mDefaultMaxBufferCount < minBufferCountNeeded)); if (!mQueue.isEmpty() && numberOfBuffersNeedsToChange) { // 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; // Free up any buffers that are in slots beyond the max buffer // count. for (int i = maxBufferCount; i < NUM_BUFFER_SLOTS; i++) { assert(mSlots[i].mBufferState == BufferSlot::FREE); if (mSlots[i].mGraphicBuffer != NULL) { freeBufferLocked(i); returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS; } } // look for a free buffer to give to the client found = INVALID_BUFFER_SLOT; dequeuedCount = 0; for (int i = 0; i < mMaxBufferCount; i++) { for (int i = 0; i < maxBufferCount; i++) { const int state = mSlots[i].mBufferState; if (state == BufferSlot::DEQUEUED) { dequeuedCount++; Loading Loading @@ -406,7 +361,7 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>& outFence, if (mBufferHasBeenQueued) { // make sure the client is not trying to dequeue more buffers // than allowed. const int avail = mMaxBufferCount - (dequeuedCount+1); const int avail = maxBufferCount - (dequeuedCount+1); if (avail < (mMinUndequeuedBuffers-int(mSynchronousMode))) { ST_LOGE("dequeueBuffer: mMinUndequeuedBuffers=%d exceeded " "(dequeued=%d)", Loading @@ -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; if (tryAgain) { mDequeueCondition.wait(mMutex); Loading Loading @@ -557,9 +513,10 @@ status_t BufferQueue::queueBuffer(int buf, ST_LOGE("queueBuffer: SurfaceTexture has been abandoned!"); 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", mMaxBufferCount, buf); maxBufferCount, buf); return -EINVAL; } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) { ST_LOGE("queueBuffer: slot %d is not owned by the client " Loading Loading @@ -653,9 +610,10 @@ void BufferQueue::cancelBuffer(int buf, sp<Fence> fence) { 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", mMaxBufferCount, buf); maxBufferCount, buf); return; } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) { ST_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)", Loading Loading @@ -775,10 +733,12 @@ void BufferQueue::dump(String8& result, const char* prefix, fifo.append(buffer); } int maxBufferCount = getMaxBufferCountLocked(); 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", prefix, mMaxBufferCount, mSynchronousMode, mDefaultWidth, prefix, maxBufferCount, mSynchronousMode, mDefaultWidth, mDefaultHeight, mDefaultBufferFormat, fifoSize, fifo.string()); result.append(buffer); Loading @@ -795,7 +755,7 @@ void BufferQueue::dump(String8& result, const char* prefix, } } stateName; for (int i=0 ; i<mMaxBufferCount ; i++) { for (int i=0 ; i<maxBufferCount ; i++) { const BufferSlot& slot(mSlots[i]); snprintf(buffer, SIZE, "%s%s[%02d] " Loading Loading @@ -1039,6 +999,32 @@ int BufferQueue::getMinMaxBufferCountLocked() const { 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( const wp<BufferQueue::ConsumerListener>& consumerListener): mConsumerListener(consumerListener) {} Loading Loading
include/gui/BufferQueue.h +13 −4 Original line number Diff line number Diff line Loading @@ -307,6 +307,19 @@ private: // given the current BufferQueue state. 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 { BufferSlot() Loading Loading @@ -433,10 +446,6 @@ private: // not dequeued at any time 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 // 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 Loading
libs/gui/BufferQueue.cpp +68 −82 Original line number Diff line number Diff line Loading @@ -86,7 +86,6 @@ BufferQueue::BufferQueue(bool allowSynchronousMode, int bufferCount, mDefaultWidth(1), mDefaultHeight(1), mMinUndequeuedBuffers(bufferCount), mMaxBufferCount(bufferCount + 1), mDefaultMaxBufferCount(bufferCount + 1), mOverrideMaxBufferCount(0), mSynchronousMode(false), Loading Loading @@ -119,37 +118,12 @@ BufferQueue::~BufferQueue() { } status_t BufferQueue::setDefaultMaxBufferCountLocked(int count) { if (count > NUM_BUFFER_SLOTS) if (count < 2 || count > NUM_BUFFER_SLOTS) return BAD_VALUE; mDefaultMaxBufferCount = count; 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; } Loading Loading @@ -198,7 +172,8 @@ status_t BufferQueue::setBufferCount(int bufferCount) { } // 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) { ST_LOGE("setBufferCount: client owns some buffers"); return -EINVAL; Loading @@ -208,9 +183,8 @@ status_t BufferQueue::setBufferCount(int bufferCount) { const int minBufferSlots = getMinMaxBufferCountLocked(); if (bufferCount == 0) { mOverrideMaxBufferCount = 0; bufferCount = (mDefaultMaxBufferCount >= minBufferSlots) ? mDefaultMaxBufferCount : minBufferSlots; return setDefaultMaxBufferCountLocked(bufferCount); mDequeueCondition.broadcast(); return OK; } if (bufferCount < minBufferSlots) { Loading @@ -221,11 +195,11 @@ status_t BufferQueue::setBufferCount(int bufferCount) { // here we're guaranteed that the client doesn't have dequeued buffers // and will release all of its buffer references. // // XXX: Should this use drainQueueAndFreeBuffersLocked instead? freeAllBuffersLocked(); mMaxBufferCount = bufferCount; mOverrideMaxBufferCount = bufferCount; mBufferHasBeenQueued = false; mQueue.clear(); mDequeueCondition.broadcast(); listener = mConsumerListener; } // scope for lock Loading Loading @@ -280,9 +254,17 @@ status_t BufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) { ST_LOGE("requestBuffer: SurfaceTexture has been abandoned!"); 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", 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; } mSlots[slot].mRequestBufferCalled = true; Loading Loading @@ -322,49 +304,22 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>& outFence, return NO_INIT; } // We need to wait for the FIFO to drain if the number of buffer // 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(); const int maxBufferCount = getMaxBufferCountLocked(); const bool numberOfBuffersNeedsToChange = !mOverrideMaxBufferCount && ((mDefaultMaxBufferCount != mMaxBufferCount) || (mDefaultMaxBufferCount < minBufferCountNeeded)); if (!mQueue.isEmpty() && numberOfBuffersNeedsToChange) { // 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; // Free up any buffers that are in slots beyond the max buffer // count. for (int i = maxBufferCount; i < NUM_BUFFER_SLOTS; i++) { assert(mSlots[i].mBufferState == BufferSlot::FREE); if (mSlots[i].mGraphicBuffer != NULL) { freeBufferLocked(i); returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS; } } // look for a free buffer to give to the client found = INVALID_BUFFER_SLOT; dequeuedCount = 0; for (int i = 0; i < mMaxBufferCount; i++) { for (int i = 0; i < maxBufferCount; i++) { const int state = mSlots[i].mBufferState; if (state == BufferSlot::DEQUEUED) { dequeuedCount++; Loading Loading @@ -406,7 +361,7 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>& outFence, if (mBufferHasBeenQueued) { // make sure the client is not trying to dequeue more buffers // than allowed. const int avail = mMaxBufferCount - (dequeuedCount+1); const int avail = maxBufferCount - (dequeuedCount+1); if (avail < (mMinUndequeuedBuffers-int(mSynchronousMode))) { ST_LOGE("dequeueBuffer: mMinUndequeuedBuffers=%d exceeded " "(dequeued=%d)", Loading @@ -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; if (tryAgain) { mDequeueCondition.wait(mMutex); Loading Loading @@ -557,9 +513,10 @@ status_t BufferQueue::queueBuffer(int buf, ST_LOGE("queueBuffer: SurfaceTexture has been abandoned!"); 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", mMaxBufferCount, buf); maxBufferCount, buf); return -EINVAL; } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) { ST_LOGE("queueBuffer: slot %d is not owned by the client " Loading Loading @@ -653,9 +610,10 @@ void BufferQueue::cancelBuffer(int buf, sp<Fence> fence) { 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", mMaxBufferCount, buf); maxBufferCount, buf); return; } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) { ST_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)", Loading Loading @@ -775,10 +733,12 @@ void BufferQueue::dump(String8& result, const char* prefix, fifo.append(buffer); } int maxBufferCount = getMaxBufferCountLocked(); 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", prefix, mMaxBufferCount, mSynchronousMode, mDefaultWidth, prefix, maxBufferCount, mSynchronousMode, mDefaultWidth, mDefaultHeight, mDefaultBufferFormat, fifoSize, fifo.string()); result.append(buffer); Loading @@ -795,7 +755,7 @@ void BufferQueue::dump(String8& result, const char* prefix, } } stateName; for (int i=0 ; i<mMaxBufferCount ; i++) { for (int i=0 ; i<maxBufferCount ; i++) { const BufferSlot& slot(mSlots[i]); snprintf(buffer, SIZE, "%s%s[%02d] " Loading Loading @@ -1039,6 +999,32 @@ int BufferQueue::getMinMaxBufferCountLocked() const { 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( const wp<BufferQueue::ConsumerListener>& consumerListener): mConsumerListener(consumerListener) {} Loading