BQ: Improved buffer/slot tracking
- Explicitly track active buffers and unused slots on top of the
already existing tracking for free slots and free buffers.
Change-Id: Ife2678678e96f0eb0b3fb21571058378134bd868
diff --git a/include/gui/BufferItem.h b/include/gui/BufferItem.h
index 370f5d5..a515f39 100644
--- a/include/gui/BufferItem.h
+++ b/include/gui/BufferItem.h
@@ -125,6 +125,10 @@
// Indicates that this buffer was queued by the producer. When in single
// buffer mode acquire() can return a BufferItem that wasn't in the queue.
bool mQueuedBuffer;
+
+ // Indicates that this BufferItem contains a stale buffer which has already
+ // been released by the BufferQueue.
+ bool mIsStale;
};
} // namespace android
diff --git a/include/gui/BufferQueueCore.h b/include/gui/BufferQueueCore.h
index fbd5114..23cd066 100644
--- a/include/gui/BufferQueueCore.h
+++ b/include/gui/BufferQueueCore.h
@@ -105,17 +105,23 @@
// connected, mDequeueCondition must be broadcast.
int getMaxBufferCountLocked() const;
- // freeBufferLocked frees the GraphicBuffer and sync resources for the
+ // This performs the same computation but uses the given arguments instead
+ // of the member variables for mMaxBufferCount, mAsyncMode, and
+ // mDequeueBufferCannotBlock.
+ int getMaxBufferCountLocked(bool asyncMode,
+ bool dequeueBufferCannotBlock, int maxBufferCount) const;
+
+ // clearBufferSlotLocked frees the GraphicBuffer and sync resources for the
// given slot.
- void freeBufferLocked(int slot, bool validate = true);
+ void clearBufferSlotLocked(int slot);
// freeAllBuffersLocked frees the GraphicBuffer and sync resources for
// all slots, even if they're currently dequeued, queued, or acquired.
void freeAllBuffersLocked();
- // stillTracking returns true iff the buffer item is still being tracked
- // in one of the slots.
- bool stillTracking(const BufferItem* item) const;
+ // If delta is positive, makes more slots available. If negative, takes
+ // away slots. Returns false if the request can't be met.
+ bool adjustAvailableSlotsLocked(int delta);
// waitWhileAllocatingLocked blocks until mIsAllocating is false.
void waitWhileAllocatingLocked() const;
@@ -179,13 +185,20 @@
Fifo mQueue;
// mFreeSlots contains all of the slots which are FREE and do not currently
- // have a buffer attached
+ // have a buffer attached.
std::set<int> mFreeSlots;
// mFreeBuffers contains all of the slots which are FREE and currently have
- // a buffer attached
+ // a buffer attached.
std::list<int> mFreeBuffers;
+ // mUnusedSlots contains all slots that are currently unused. They should be
+ // free and not have a buffer attached.
+ std::list<int> mUnusedSlots;
+
+ // mActiveBuffers contains all slots which have a non-FREE buffer attached.
+ std::set<int> mActiveBuffers;
+
// mDequeueCondition is a condition variable used for dequeueBuffer in
// synchronous mode.
mutable Condition mDequeueCondition;
diff --git a/include/gui/BufferQueueProducer.h b/include/gui/BufferQueueProducer.h
index 645a07b..dc05e98 100644
--- a/include/gui/BufferQueueProducer.h
+++ b/include/gui/BufferQueueProducer.h
@@ -187,9 +187,9 @@
// BufferQueueCore::INVALID_BUFFER_SLOT otherwise
int getFreeBufferLocked() const;
- // Returns the next free slot if one less than or equal to maxBufferCount
- // is available or BufferQueueCore::INVALID_BUFFER_SLOT otherwise
- int getFreeSlotLocked(int maxBufferCount) const;
+ // Returns the next free slot if one is available or
+ // BufferQueueCore::INVALID_BUFFER_SLOT otherwise
+ int getFreeSlotLocked() const;
// waitForFreeSlotThenRelock finds the oldest slot in the FREE state. It may
// block if there are no available slots and we are not in non-blocking
@@ -200,8 +200,7 @@
Dequeue,
Attach,
};
- status_t waitForFreeSlotThenRelock(FreeSlotCaller caller, int* found,
- status_t* returnFlags) const;
+ status_t waitForFreeSlotThenRelock(FreeSlotCaller caller, int* found) const;
sp<BufferQueueCore> mCore;
diff --git a/include/gui/BufferSlot.h b/include/gui/BufferSlot.h
index 17a654a..943fa82 100644
--- a/include/gui/BufferSlot.h
+++ b/include/gui/BufferSlot.h
@@ -174,14 +174,15 @@
struct BufferSlot {
BufferSlot()
- : mEglDisplay(EGL_NO_DISPLAY),
+ : mGraphicBuffer(nullptr),
+ mEglDisplay(EGL_NO_DISPLAY),
mBufferState(),
mRequestBufferCalled(false),
mFrameNumber(0),
mEglFence(EGL_NO_SYNC_KHR),
+ mFence(Fence::NO_FENCE),
mAcquireCalled(false),
- mNeedsCleanupOnRelease(false),
- mAttachedByConsumer(false) {
+ mNeedsReallocation(false) {
}
// mGraphicBuffer points to the buffer allocated for this slot or is NULL
@@ -191,8 +192,6 @@
// mEglDisplay is the EGLDisplay used to create EGLSyncKHR objects.
EGLDisplay mEglDisplay;
- static const char* bufferStateName(BufferState state);
-
// mBufferState is the current state of this buffer slot.
BufferState mBufferState;
@@ -227,15 +226,10 @@
// Indicates whether this buffer has been seen by a consumer yet
bool mAcquireCalled;
- // Indicates whether this buffer needs to be cleaned up by the
- // consumer. This is set when a buffer in ACQUIRED state is freed.
- // It causes releaseBuffer to return STALE_BUFFER_SLOT.
- bool mNeedsCleanupOnRelease;
-
- // Indicates whether the buffer was attached on the consumer side.
- // If so, it needs to set the BUFFER_NEEDS_REALLOCATION flag when dequeued
- // to prevent the producer from using a stale cached buffer.
- bool mAttachedByConsumer;
+ // Indicates whether the buffer was re-allocated without notifying the
+ // producer. If so, it needs to set the BUFFER_NEEDS_REALLOCATION flag when
+ // dequeued to prevent the producer from using a stale cached buffer.
+ bool mNeedsReallocation;
};
} // namespace android
diff --git a/include/gui/IGraphicBufferConsumer.h b/include/gui/IGraphicBufferConsumer.h
index d4c9ee5..ebce7fb 100644
--- a/include/gui/IGraphicBufferConsumer.h
+++ b/include/gui/IGraphicBufferConsumer.h
@@ -199,7 +199,9 @@
// cannot be less than maxAcquiredBufferCount.
//
// Return of a value other than NO_ERROR means an error has occurred:
- // * BAD_VALUE - bufferCount was out of range (see above).
+ // * BAD_VALUE - one of the below conditions occurred:
+ // * bufferCount was out of range (see above).
+ // * failure to adjust the number of available slots.
// * INVALID_OPERATION - attempting to call this after a producer connected.
virtual status_t setMaxBufferCount(int bufferCount) = 0;
@@ -212,7 +214,9 @@
// to be exceeded.
//
// Return of a value other than NO_ERROR means an error has occurred:
- // * BAD_VALUE - maxAcquiredBuffers was out of range (see above).
+ // * BAD_VALUE - one of the below conditions occurred:
+ // * maxAcquiredBuffers was out of range (see above).
+ // * failure to adjust the number of available slots.
// * INVALID_OPERATION - attempting to call this after a producer connected.
virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) = 0;
diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
index 8646981..1f4c8ac 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/include/gui/IGraphicBufferProducer.h
@@ -101,8 +101,9 @@
// * NO_INIT - the buffer queue has been abandoned.
// * BAD_VALUE - one of the below conditions occurred:
// * bufferCount was out of range (see above)
- // * client has one or more buffers dequeued
+ // * client has too many buffers dequeued
// * this call would cause the maxBufferCount value to be exceeded
+ // * failure to adjust the number of available slots.
virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers) = 0;
// Set the async flag if the producer intends to asynchronously queue
@@ -115,8 +116,10 @@
//
// Return of a value other than NO_ERROR means an error has occurred:
// * NO_INIT - the buffer queue has been abandoned.
- // * BAD_VALUE - this call would cause the maxBufferCount value to be
+ // * BAD_VALUE - one of the following has occurred:
+ // * this call would cause the maxBufferCount value to be
// exceeded
+ // * failure to adjust the number of available slots.
virtual status_t setAsyncMode(bool async) = 0;
// dequeueBuffer requests a new buffer slot for the client to use. Ownership
@@ -436,6 +439,9 @@
// * the producer is already connected
// * api was out of range (see above).
// * output was NULL.
+ // * Failure to adjust the number of available slots. This can
+ // happen because of trying to allocate/deallocate the async
+ // buffer in response to the value of producerControlledByApp.
// * DEAD_OBJECT - the token is hosted by an already-dead process
//
// Additional negative errors may be returned by the internals, they
@@ -534,6 +540,11 @@
// timeout of -1. If set (to a value other than -1), this will disable
// non-blocking mode and its corresponding spare buffer (which is used to
// ensure a buffer is always available).
+ //
+ // Return of a value other than NO_ERROR means an error has occurred:
+ // * BAD_VALUE - Failure to adjust the number of available slots. This can
+ // happen because of trying to allocate/deallocate the async
+ // buffer.
virtual status_t setDequeueTimeout(nsecs_t timeout) = 0;
};
diff --git a/libs/gui/BufferItem.cpp b/libs/gui/BufferItem.cpp
index de8ff70..036ef1e 100644
--- a/libs/gui/BufferItem.cpp
+++ b/libs/gui/BufferItem.cpp
@@ -39,7 +39,8 @@
mTransformToDisplayInverse(false),
mSurfaceDamage(),
mSingleBufferMode(false),
- mQueuedBuffer(true) {
+ mQueuedBuffer(true),
+ mIsStale(false) {
}
BufferItem::~BufferItem() {}
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index 6f9f21f..d182f6b 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -49,7 +49,7 @@
// buffer so that the consumer can successfully set up the newly acquired
// buffer before releasing the old one.
int numAcquiredBuffers = 0;
- for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
+ for (int s : mCore->mActiveBuffers) {
if (mSlots[s].mBufferState.isAcquired()) {
++numAcquiredBuffers;
}
@@ -133,7 +133,8 @@
BQ_LOGV("acquireBuffer: drop desire=%" PRId64 " expect=%" PRId64
" size=%zu",
desiredPresent, expectedPresent, mCore->mQueue.size());
- if (mCore->stillTracking(front)) {
+
+ if (!front->mIsStale) {
// Front buffer is still in mSlots, so mark the slot as free
mSlots[front->mSlot].mBufferState.freeQueued();
@@ -144,13 +145,17 @@
mSlots[front->mSlot].mBufferState.isFree()) {
mSlots[front->mSlot].mBufferState.mShared = false;
}
- // Don't put the shared buffer on the free list.
+
+ // Don't put the shared buffer on the free list
if (!mSlots[front->mSlot].mBufferState.isShared()) {
+ mCore->mActiveBuffers.erase(front->mSlot);
mCore->mFreeBuffers.push_back(front->mSlot);
}
+
listener = mCore->mConnectedProducerListener;
++numDroppedBuffers;
}
+
mCore->mQueue.erase(front);
front = mCore->mQueue.begin();
}
@@ -205,6 +210,7 @@
outBuffer->mSurfaceDamage = Region::INVALID_REGION;
outBuffer->mSingleBufferMode = true;
outBuffer->mQueuedBuffer = false;
+ outBuffer->mIsStale = false;
} else {
slot = front->mSlot;
*outBuffer = *front;
@@ -216,10 +222,9 @@
BQ_LOGV("acquireBuffer: acquiring { slot=%d/%" PRIu64 " buffer=%p }",
slot, outBuffer->mFrameNumber, outBuffer->mGraphicBuffer->handle);
- // If the front buffer is still being tracked, update its slot state
- if (mCore->stillTracking(outBuffer)) {
+
+ if (!outBuffer->mIsStale) {
mSlots[slot].mAcquireCalled = true;
- mSlots[slot].mNeedsCleanupOnRelease = false;
// Don't decrease the queue count if the BufferItem wasn't
// previously in the queue. This happens in single buffer mode when
// the queue is empty and the BufferItem is created above.
@@ -270,7 +275,7 @@
return NO_INIT;
}
- if (mCore->mSingleBufferMode) {
+ if (mCore->mSingleBufferMode || slot == mCore->mSingleBufferSlot) {
BQ_LOGE("detachBuffer: detachBuffer not allowed in single buffer"
"mode");
return BAD_VALUE;
@@ -287,7 +292,9 @@
}
mSlots[slot].mBufferState.detachConsumer();
- mCore->freeBufferLocked(slot);
+ mCore->mActiveBuffers.erase(slot);
+ mCore->mFreeSlots.insert(slot);
+ mCore->clearBufferSlotLocked(slot);
mCore->mDequeueCondition.broadcast();
mCore->validateConsistencyLocked();
@@ -316,7 +323,7 @@
// Make sure we don't have too many acquired buffers
int numAcquiredBuffers = 0;
- for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
+ for (int s : mCore->mActiveBuffers) {
if (mSlots[s].mBufferState.isAcquired()) {
++numAcquiredBuffers;
}
@@ -351,14 +358,14 @@
return NO_MEMORY;
}
+ mCore->mActiveBuffers.insert(found);
*outSlot = found;
ATRACE_BUFFER_INDEX(*outSlot);
BQ_LOGV("attachBuffer: returning slot %d", *outSlot);
mSlots[*outSlot].mGraphicBuffer = buffer;
mSlots[*outSlot].mBufferState.attachConsumer();
- mSlots[*outSlot].mAttachedByConsumer = true;
- mSlots[*outSlot].mNeedsCleanupOnRelease = false;
+ mSlots[*outSlot].mNeedsReallocation = true;
mSlots[*outSlot].mFence = Fence::NO_FENCE;
mSlots[*outSlot].mFrameNumber = 0;
@@ -411,39 +418,33 @@
return STALE_BUFFER_SLOT;
}
-
- if (mSlots[slot].mBufferState.isAcquired()) {
- mSlots[slot].mEglDisplay = eglDisplay;
- mSlots[slot].mEglFence = eglFence;
- mSlots[slot].mFence = releaseFence;
- mSlots[slot].mBufferState.release();
-
- // After leaving single buffer mode, the shared buffer will
- // still be around. Mark it as no longer shared if this
- // operation causes it to be free.
- if (!mCore->mSingleBufferMode &&
- mSlots[slot].mBufferState.isFree()) {
- mSlots[slot].mBufferState.mShared = false;
- }
- // Don't put the shared buffer on the free list.
- if (!mSlots[slot].mBufferState.isShared()) {
- mCore->mFreeBuffers.push_back(slot);
- }
-
- listener = mCore->mConnectedProducerListener;
- BQ_LOGV("releaseBuffer: releasing slot %d", slot);
- } else if (mSlots[slot].mNeedsCleanupOnRelease) {
- BQ_LOGV("releaseBuffer: releasing a stale buffer slot %d "
- "(state = %s)", slot, mSlots[slot].mBufferState.string());
- mSlots[slot].mNeedsCleanupOnRelease = false;
- return STALE_BUFFER_SLOT;
- } else {
+ if (!mSlots[slot].mBufferState.isAcquired()) {
BQ_LOGE("releaseBuffer: attempted to release buffer slot %d "
"but its state was %s", slot,
mSlots[slot].mBufferState.string());
return BAD_VALUE;
}
+ mSlots[slot].mEglDisplay = eglDisplay;
+ mSlots[slot].mEglFence = eglFence;
+ mSlots[slot].mFence = releaseFence;
+ mSlots[slot].mBufferState.release();
+
+ // After leaving single buffer mode, the shared buffer will
+ // still be around. Mark it as no longer shared if this
+ // operation causes it to be free.
+ if (!mCore->mSingleBufferMode && mSlots[slot].mBufferState.isFree()) {
+ mSlots[slot].mBufferState.mShared = false;
+ }
+ // Don't put the shared buffer on the free list.
+ if (!mSlots[slot].mBufferState.isShared()) {
+ mCore->mActiveBuffers.erase(slot);
+ mCore->mFreeBuffers.push_back(slot);
+ }
+
+ listener = mCore->mConnectedProducerListener;
+ BQ_LOGV("releaseBuffer: releasing slot %d", slot);
+
mCore->mDequeueCondition.broadcast();
mCore->validateConsistencyLocked();
} // Autolock scope
@@ -497,6 +498,7 @@
mCore->mConsumerListener = NULL;
mCore->mQueue.clear();
mCore->freeAllBuffersLocked();
+ mCore->mSingleBufferSlot = BufferQueueCore::INVALID_BUFFER_SLOT;
mCore->mDequeueCondition.broadcast();
return NO_ERROR;
}
@@ -579,6 +581,15 @@
return BAD_VALUE;
}
+ int delta = mCore->getMaxBufferCountLocked(mCore->mAsyncMode,
+ mCore->mDequeueBufferCannotBlock, bufferCount) -
+ mCore->getMaxBufferCountLocked();
+ if (!mCore->adjustAvailableSlotsLocked(delta)) {
+ BQ_LOGE("setMaxBufferCount: BufferQueue failed to adjust the number of "
+ "available slots. Delta = %d", delta);
+ return BAD_VALUE;
+ }
+
mCore->mMaxBufferCount = bufferCount;
return NO_ERROR;
}
@@ -612,8 +623,17 @@
return BAD_VALUE;
}
+ if (!mCore->adjustAvailableSlotsLocked(
+ maxAcquiredBuffers - mCore->mMaxAcquiredBufferCount)) {
+ BQ_LOGE("setMaxAcquiredBufferCount: BufferQueue failed to adjust the "
+ "number of available slots. Delta = %d",
+ maxAcquiredBuffers - mCore->mMaxAcquiredBufferCount);
+ return BAD_VALUE;
+ }
+
BQ_LOGV("setMaxAcquiredBufferCount: %d", maxAcquiredBuffers);
mCore->mMaxAcquiredBufferCount = maxAcquiredBuffers;
+ mCore->validateConsistencyLocked();
return NO_ERROR;
}
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index c24ad19..f02ff5f 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -52,6 +52,8 @@
mQueue(),
mFreeSlots(),
mFreeBuffers(),
+ mUnusedSlots(),
+ mActiveBuffers(),
mDequeueCondition(),
mDequeueBufferCannotBlock(false),
mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888),
@@ -82,8 +84,14 @@
BQ_LOGE("createGraphicBufferAlloc failed");
}
}
- for (int slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) {
- mFreeSlots.insert(slot);
+
+ int numStartingBuffers = getMaxBufferCountLocked();
+ for (int s = 0; s < numStartingBuffers; s++) {
+ mFreeSlots.insert(s);
+ }
+ for (int s = numStartingBuffers; s < BufferQueueDefs::NUM_BUFFER_SLOTS;
+ s++) {
+ mUnusedSlots.push_front(s);
}
}
@@ -113,32 +121,26 @@
mDefaultHeight, mDefaultBufferFormat, mTransformHint, mQueue.size(),
fifo.string());
- // Trim the free buffers so as to not spam the dump
- int maxBufferCount = 0;
- for (int s = BufferQueueDefs::NUM_BUFFER_SLOTS - 1; s >= 0; --s) {
- const BufferSlot& slot(mSlots[s]);
- if (!slot.mBufferState.isFree() ||
- slot.mGraphicBuffer != NULL) {
- maxBufferCount = s + 1;
- break;
- }
+ for (int s : mActiveBuffers) {
+ const sp<GraphicBuffer>& buffer(mSlots[s].mGraphicBuffer);
+ result.appendFormat("%s%s[%02d:%p] state=%-8s, %p [%4ux%4u:%4u,%3X]\n",
+ prefix, (mSlots[s].mBufferState.isAcquired()) ? ">" : " ", s,
+ buffer.get(), mSlots[s].mBufferState.string(), buffer->handle,
+ buffer->width, buffer->height, buffer->stride, buffer->format);
+
+ }
+ for (int s : mFreeBuffers) {
+ const sp<GraphicBuffer>& buffer(mSlots[s].mGraphicBuffer);
+ result.appendFormat("%s [%02d:%p] state=%-8s, %p [%4ux%4u:%4u,%3X]\n",
+ prefix, s, buffer.get(), mSlots[s].mBufferState.string(),
+ buffer->handle, buffer->width, buffer->height, buffer->stride,
+ buffer->format);
}
- for (int s = 0; s < maxBufferCount; ++s) {
- const BufferSlot& slot(mSlots[s]);
- const sp<GraphicBuffer>& buffer(slot.mGraphicBuffer);
- result.appendFormat("%s%s[%02d:%p] state=%-8s", prefix,
- (slot.mBufferState.isAcquired()) ? ">" : " ",
- s, buffer.get(),
- slot.mBufferState.string());
-
- if (buffer != NULL) {
- result.appendFormat(", %p [%4ux%4u:%4u,%3X]", buffer->handle,
- buffer->width, buffer->height, buffer->stride,
- buffer->format);
- }
-
- result.append("\n");
+ for (int s : mFreeSlots) {
+ const sp<GraphicBuffer>& buffer(mSlots[s].mGraphicBuffer);
+ result.appendFormat("%s [%02d:%p] state=%-8s\n", prefix, s,
+ buffer.get(), mSlots[s].mBufferState.string());
}
}
@@ -156,44 +158,33 @@
return getMinUndequeuedBufferCountLocked() + 1;
}
+int BufferQueueCore::getMaxBufferCountLocked(bool asyncMode,
+ bool dequeueBufferCannotBlock, int maxBufferCount) const {
+ int maxCount = mMaxAcquiredBufferCount + mMaxDequeuedBufferCount +
+ ((asyncMode || dequeueBufferCannotBlock) ? 1 : 0);
+ maxCount = std::min(maxBufferCount, maxCount);
+ return maxCount;
+}
+
int BufferQueueCore::getMaxBufferCountLocked() const {
int maxBufferCount = mMaxAcquiredBufferCount + mMaxDequeuedBufferCount +
- (mAsyncMode || mDequeueBufferCannotBlock ? 1 : 0);
+ ((mAsyncMode || mDequeueBufferCannotBlock) ? 1 : 0);
// limit maxBufferCount by mMaxBufferCount always
maxBufferCount = std::min(mMaxBufferCount, maxBufferCount);
- // 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 s = maxBufferCount; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
- BufferState state = mSlots[s].mBufferState;
- if (state.isQueued() || state.isDequeued()) {
- maxBufferCount = s + 1;
- }
- }
-
return maxBufferCount;
}
-void BufferQueueCore::freeBufferLocked(int slot, bool validate) {
- BQ_LOGV("freeBufferLocked: slot %d", slot);
- bool hadBuffer = mSlots[slot].mGraphicBuffer != NULL;
+void BufferQueueCore::clearBufferSlotLocked(int slot) {
+ BQ_LOGV("clearBufferSlotLocked: slot %d", slot);
+
mSlots[slot].mGraphicBuffer.clear();
- if (mSlots[slot].mBufferState.isAcquired()) {
- mSlots[slot].mNeedsCleanupOnRelease = true;
- }
- if (!mSlots[slot].mBufferState.isFree()) {
- mFreeSlots.insert(slot);
- } else if (hadBuffer) {
- // If the slot was FREE, but we had a buffer, we need to move this slot
- // from the free buffers list to the the free slots list
- mFreeBuffers.remove(slot);
- mFreeSlots.insert(slot);
- }
- mSlots[slot].mAcquireCalled = false;
+ mSlots[slot].mBufferState.reset();
+ mSlots[slot].mRequestBufferCalled = false;
mSlots[slot].mFrameNumber = 0;
+ mSlots[slot].mAcquireCalled = false;
+ mSlots[slot].mNeedsReallocation = true;
// Destroy fence as BufferQueue now takes ownership
if (mSlots[slot].mEglFence != EGL_NO_SYNC_KHR) {
@@ -201,35 +192,63 @@
mSlots[slot].mEglFence = EGL_NO_SYNC_KHR;
}
mSlots[slot].mFence = Fence::NO_FENCE;
- if (validate) {
- validateConsistencyLocked();
- }
+ mSlots[slot].mEglDisplay = EGL_NO_DISPLAY;
}
void BufferQueueCore::freeAllBuffersLocked() {
- mBufferHasBeenQueued = false;
- for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
- freeBufferLocked(s, false);
- mSlots[s].mBufferState.reset();
+ for (int s : mFreeSlots) {
+ clearBufferSlotLocked(s);
}
- mSingleBufferSlot = INVALID_BUFFER_SLOT;
+
+ for (int s : mFreeBuffers) {
+ mFreeSlots.insert(s);
+ clearBufferSlotLocked(s);
+ }
+ mFreeBuffers.clear();
+
+ for (int s : mActiveBuffers) {
+ mFreeSlots.insert(s);
+ clearBufferSlotLocked(s);
+ }
+ mActiveBuffers.clear();
+
+ for (auto& b : mQueue) {
+ b.mIsStale = true;
+ }
+
validateConsistencyLocked();
}
-bool BufferQueueCore::stillTracking(const BufferItem* item) const {
- const BufferSlot& slot = mSlots[item->mSlot];
-
- BQ_LOGV("stillTracking: item { slot=%d/%" PRIu64 " buffer=%p } "
- "slot { slot=%d/%" PRIu64 " buffer=%p }",
- item->mSlot, item->mFrameNumber,
- (item->mGraphicBuffer.get() ? item->mGraphicBuffer->handle : 0),
- item->mSlot, slot.mFrameNumber,
- (slot.mGraphicBuffer.get() ? slot.mGraphicBuffer->handle : 0));
-
- // Compare item with its original buffer slot. We can check the slot as
- // the buffer would not be moved to a different slot by the producer.
- return (slot.mGraphicBuffer != NULL) &&
- (item->mGraphicBuffer->handle == slot.mGraphicBuffer->handle);
+bool BufferQueueCore::adjustAvailableSlotsLocked(int delta) {
+ if (delta >= 0) {
+ while (delta > 0) {
+ if (mUnusedSlots.empty()) {
+ return false;
+ }
+ int slot = mUnusedSlots.back();
+ mUnusedSlots.pop_back();
+ mFreeSlots.insert(slot);
+ delta--;
+ }
+ } else {
+ while (delta < 0) {
+ if (!mFreeSlots.empty()) {
+ auto slot = mFreeSlots.begin();
+ clearBufferSlotLocked(*slot);
+ mUnusedSlots.push_back(*slot);
+ mFreeSlots.erase(slot);
+ } else if (!mFreeBuffers.empty()) {
+ int slot = mFreeBuffers.back();
+ clearBufferSlotLocked(slot);
+ mUnusedSlots.push_back(slot);
+ mFreeBuffers.pop_back();
+ } else {
+ return false;
+ }
+ delta++;
+ }
+ }
+ return true;
}
void BufferQueueCore::waitWhileAllocatingLocked() const {
@@ -241,47 +260,127 @@
void BufferQueueCore::validateConsistencyLocked() const {
static const useconds_t PAUSE_TIME = 0;
+ int allocatedSlots = 0;
for (int slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) {
bool isInFreeSlots = mFreeSlots.count(slot) != 0;
bool isInFreeBuffers =
std::find(mFreeBuffers.cbegin(), mFreeBuffers.cend(), slot) !=
mFreeBuffers.cend();
- if (mSlots[slot].mBufferState.isFree() &&
- !mSlots[slot].mBufferState.isShared()) {
- if (mSlots[slot].mGraphicBuffer == NULL) {
- if (!isInFreeSlots) {
- BQ_LOGE("Slot %d is FREE but is not in mFreeSlots", slot);
- usleep(PAUSE_TIME);
- }
- if (isInFreeBuffers) {
- BQ_LOGE("Slot %d is in mFreeSlots "
- "but is also in mFreeBuffers", slot);
- usleep(PAUSE_TIME);
- }
- } else {
- if (!isInFreeBuffers) {
- BQ_LOGE("Slot %d is FREE but is not in mFreeBuffers", slot);
- usleep(PAUSE_TIME);
- }
- if (isInFreeSlots) {
- BQ_LOGE("Slot %d is in mFreeBuffers "
- "but is also in mFreeSlots", slot);
- usleep(PAUSE_TIME);
- }
- }
- } else {
+ bool isInActiveBuffers = mActiveBuffers.count(slot) != 0;
+ bool isInUnusedSlots =
+ std::find(mUnusedSlots.cbegin(), mUnusedSlots.cend(), slot) !=
+ mUnusedSlots.cend();
+
+ if (isInFreeSlots || isInFreeBuffers || isInActiveBuffers) {
+ allocatedSlots++;
+ }
+
+ if (isInUnusedSlots) {
if (isInFreeSlots) {
- BQ_LOGE("Slot %d is in mFreeSlots but is not FREE (%s)",
- slot, mSlots[slot].mBufferState.string());
+ BQ_LOGE("Slot %d is in mUnusedSlots and in mFreeSlots", slot);
usleep(PAUSE_TIME);
}
if (isInFreeBuffers) {
- BQ_LOGE("Slot %d is in mFreeBuffers but is not FREE (%s)",
- slot, mSlots[slot].mBufferState.string());
+ BQ_LOGE("Slot %d is in mUnusedSlots and in mFreeBuffers", slot);
usleep(PAUSE_TIME);
}
+ if (isInActiveBuffers) {
+ BQ_LOGE("Slot %d is in mUnusedSlots and in mActiveBuffers",
+ slot);
+ usleep(PAUSE_TIME);
+ }
+ if (!mSlots[slot].mBufferState.isFree()) {
+ BQ_LOGE("Slot %d is in mUnusedSlots but is not FREE", slot);
+ usleep(PAUSE_TIME);
+ }
+ if (mSlots[slot].mGraphicBuffer != NULL) {
+ BQ_LOGE("Slot %d is in mUnusedSluts but has an active buffer",
+ slot);
+ usleep(PAUSE_TIME);
+ }
+ } else if (isInFreeSlots) {
+ if (isInUnusedSlots) {
+ BQ_LOGE("Slot %d is in mFreeSlots and in mUnusedSlots", slot);
+ usleep(PAUSE_TIME);
+ }
+ if (isInFreeBuffers) {
+ BQ_LOGE("Slot %d is in mFreeSlots and in mFreeBuffers", slot);
+ usleep(PAUSE_TIME);
+ }
+ if (isInActiveBuffers) {
+ BQ_LOGE("Slot %d is in mFreeSlots and in mActiveBuffers", slot);
+ usleep(PAUSE_TIME);
+ }
+ if (!mSlots[slot].mBufferState.isFree()) {
+ BQ_LOGE("Slot %d is in mFreeSlots but is not FREE", slot);
+ usleep(PAUSE_TIME);
+ }
+ if (mSlots[slot].mGraphicBuffer != NULL) {
+ BQ_LOGE("Slot %d is in mFreeSlots but has a buffer",
+ slot);
+ usleep(PAUSE_TIME);
+ }
+ } else if (isInFreeBuffers) {
+ if (isInUnusedSlots) {
+ BQ_LOGE("Slot %d is in mFreeBuffers and in mUnusedSlots", slot);
+ usleep(PAUSE_TIME);
+ }
+ if (isInFreeSlots) {
+ BQ_LOGE("Slot %d is in mFreeBuffers and in mFreeSlots", slot);
+ usleep(PAUSE_TIME);
+ }
+ if (isInActiveBuffers) {
+ BQ_LOGE("Slot %d is in mFreeBuffers and in mActiveBuffers",
+ slot);
+ usleep(PAUSE_TIME);
+ }
+ if (!mSlots[slot].mBufferState.isFree()) {
+ BQ_LOGE("Slot %d is in mFreeBuffers but is not FREE", slot);
+ usleep(PAUSE_TIME);
+ }
+ if (mSlots[slot].mGraphicBuffer == NULL) {
+ BQ_LOGE("Slot %d is in mFreeBuffers but has no buffer", slot);
+ usleep(PAUSE_TIME);
+ }
+ } else if (isInActiveBuffers) {
+ if (isInUnusedSlots) {
+ BQ_LOGE("Slot %d is in mActiveBuffers and in mUnusedSlots",
+ slot);
+ usleep(PAUSE_TIME);
+ }
+ if (isInFreeSlots) {
+ BQ_LOGE("Slot %d is in mActiveBuffers and in mFreeSlots", slot);
+ usleep(PAUSE_TIME);
+ }
+ if (isInFreeBuffers) {
+ BQ_LOGE("Slot %d is in mActiveBuffers and in mFreeBuffers",
+ slot);
+ usleep(PAUSE_TIME);
+ }
+ if (mSlots[slot].mBufferState.isFree() &&
+ !mSlots[slot].mBufferState.isShared()) {
+ BQ_LOGE("Slot %d is in mActiveBuffers but is FREE", slot);
+ usleep(PAUSE_TIME);
+ }
+ if (mSlots[slot].mGraphicBuffer == NULL && !mIsAllocating) {
+ BQ_LOGE("Slot %d is in mActiveBuffers but has no buffer", slot);
+ usleep(PAUSE_TIME);
+ }
+ } else {
+ BQ_LOGE("Slot %d isn't in any of mUnusedSlots, mFreeSlots, "
+ "mFreeBuffers, or mActiveBuffers", slot);
+ usleep(PAUSE_TIME);
}
}
+
+ if (allocatedSlots != getMaxBufferCountLocked()) {
+ BQ_LOGE("Number of allocated slots is incorrect. Allocated = %d, "
+ "Should be %d (%zu free slots, %zu free buffers, "
+ "%zu activeBuffers, %zu unusedSlots)", allocatedSlots,
+ getMaxBufferCountLocked(), mFreeSlots.size(),
+ mFreeBuffers.size(), mActiveBuffers.size(),
+ mUnusedSlots.size());
+ }
}
} // namespace android
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 5b1aaa0..22a2d79 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -96,7 +96,7 @@
}
// There must be no dequeued buffers when changing the buffer count.
- for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
+ for (int s : mCore->mActiveBuffers) {
if (mSlots[s].mBufferState.isDequeued()) {
BQ_LOGE("setMaxDequeuedBufferCount: buffer owned by producer");
return BAD_VALUE;
@@ -132,8 +132,15 @@
// buffers and will release all of its buffer references. We don't
// clear the queue, however, so that currently queued buffers still
// get displayed.
- mCore->freeAllBuffersLocked();
+ if (!mCore->adjustAvailableSlotsLocked(
+ maxDequeuedBuffers - mCore->mMaxDequeuedBufferCount)) {
+ BQ_LOGE("setMaxDequeuedBufferCount: BufferQueue failed to adjust "
+ "the number of available slots. Delta = %d",
+ maxDequeuedBuffers - mCore->mMaxDequeuedBufferCount);
+ return BAD_VALUE;
+ }
mCore->mMaxDequeuedBufferCount = maxDequeuedBuffers;
+ mCore->validateConsistencyLocked();
mCore->mDequeueCondition.broadcast();
listener = mCore->mConsumerListener;
} // Autolock scope
@@ -172,7 +179,17 @@
return BAD_VALUE;
}
+ int delta = mCore->getMaxBufferCountLocked(async,
+ mCore->mDequeueBufferCannotBlock, mCore->mMaxBufferCount)
+ - mCore->getMaxBufferCountLocked();
+
+ if (!mCore->adjustAvailableSlotsLocked(delta)) {
+ BQ_LOGE("setAsyncMode: BufferQueue failed to adjust the number of "
+ "available slots. Delta = %d", delta);
+ return BAD_VALUE;
+ }
mCore->mAsyncMode = async;
+ mCore->validateConsistencyLocked();
mCore->mDequeueCondition.broadcast();
listener = mCore->mConsumerListener;
} // Autolock scope
@@ -188,25 +205,22 @@
if (mCore->mFreeBuffers.empty()) {
return BufferQueueCore::INVALID_BUFFER_SLOT;
}
- auto slot = mCore->mFreeBuffers.front();
+ int slot = mCore->mFreeBuffers.front();
mCore->mFreeBuffers.pop_front();
return slot;
}
-int BufferQueueProducer::getFreeSlotLocked(int maxBufferCount) const {
+int BufferQueueProducer::getFreeSlotLocked() const {
if (mCore->mFreeSlots.empty()) {
return BufferQueueCore::INVALID_BUFFER_SLOT;
}
- auto slot = *(mCore->mFreeSlots.begin());
- if (slot < maxBufferCount) {
- mCore->mFreeSlots.erase(slot);
- return slot;
- }
- return BufferQueueCore::INVALID_BUFFER_SLOT;
+ auto slot = mCore->mFreeSlots.begin();
+ mCore->mFreeSlots.erase(slot);
+ return *slot;
}
status_t BufferQueueProducer::waitForFreeSlotThenRelock(FreeSlotCaller caller,
- int* found, status_t* returnFlags) const {
+ int* found) const {
auto callerString = (caller == FreeSlotCaller::Dequeue) ?
"dequeueBuffer" : "attachBuffer";
bool tryAgain = true;
@@ -216,20 +230,9 @@
return NO_INIT;
}
- const int maxBufferCount = mCore->getMaxBufferCountLocked();
-
- // Free up any buffers that are in slots beyond the max buffer count
- for (int s = maxBufferCount; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
- assert(mSlots[s].mBufferState.isFree());
- if (mSlots[s].mGraphicBuffer != NULL) {
- mCore->freeBufferLocked(s);
- *returnFlags |= RELEASE_ALL_BUFFERS;
- }
- }
-
int dequeuedCount = 0;
int acquiredCount = 0;
- for (int s = 0; s < maxBufferCount; ++s) {
+ for (int s : mCore->mActiveBuffers) {
if (mSlots[s].mBufferState.isDequeued()) {
++dequeuedCount;
}
@@ -254,6 +257,7 @@
// our slots are empty but we have many buffers in the queue. This can
// cause us to run out of memory if we outrun the consumer. Wait here if
// it looks like we have too many buffers queued up.
+ const int maxBufferCount = mCore->getMaxBufferCountLocked();
bool tooManyBuffers = mCore->mQueue.size()
> static_cast<size_t>(maxBufferCount);
if (tooManyBuffers) {
@@ -268,15 +272,15 @@
} else {
if (caller == FreeSlotCaller::Dequeue) {
// If we're calling this from dequeue, prefer free buffers
- auto slot = getFreeBufferLocked();
+ int slot = getFreeBufferLocked();
if (slot != BufferQueueCore::INVALID_BUFFER_SLOT) {
*found = slot;
} else if (mCore->mAllowAllocation) {
- *found = getFreeSlotLocked(maxBufferCount);
+ *found = getFreeSlotLocked();
}
} else {
// If we're calling this from attach, prefer free slots
- auto slot = getFreeSlotLocked(maxBufferCount);
+ int slot = getFreeSlotLocked();
if (slot != BufferQueueCore::INVALID_BUFFER_SLOT) {
*found = slot;
} else {
@@ -369,7 +373,7 @@
int found = BufferItem::INVALID_BUFFER_SLOT;
while (found == BufferItem::INVALID_BUFFER_SLOT) {
status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Dequeue,
- &found, &returnFlags);
+ &found);
if (status != NO_ERROR) {
return status;
}
@@ -388,24 +392,36 @@
// requested attributes, we free it and attempt to get another one.
if (!mCore->mAllowAllocation) {
if (buffer->needsReallocation(width, height, format, usage)) {
- if (mCore->mSingleBufferMode &&
- mCore->mSingleBufferSlot == found) {
+ if (mCore->mSingleBufferSlot == found) {
BQ_LOGE("dequeueBuffer: cannot re-allocate a shared"
"buffer");
return BAD_VALUE;
}
-
- mCore->freeBufferLocked(found);
+ mCore->mFreeSlots.insert(found);
+ mCore->clearBufferSlotLocked(found);
found = BufferItem::INVALID_BUFFER_SLOT;
continue;
}
}
}
+ const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);
+ if (mCore->mSingleBufferSlot == found &&
+ buffer->needsReallocation(width, height, format, usage)) {
+ BQ_LOGE("dequeueBuffer: cannot re-allocate a shared"
+ "buffer");
+
+ return BAD_VALUE;
+ }
+
+ if (mCore->mSingleBufferSlot != found) {
+ mCore->mActiveBuffers.insert(found);
+ }
*outSlot = found;
ATRACE_BUFFER_INDEX(found);
- attachedByConsumer = mSlots[found].mAttachedByConsumer;
+ attachedByConsumer = mSlots[found].mNeedsReallocation;
+ mSlots[found].mNeedsReallocation = false;
mSlots[found].mBufferState.dequeue();
@@ -417,7 +433,6 @@
mSlots[found].mBufferState.mShared = true;
}
- const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);
if ((buffer == NULL) ||
buffer->needsReallocation(width, height, format, usage))
{
@@ -452,8 +467,6 @@
*outFence = mSlots[found].mFence;
mSlots[found].mEglFence = EGL_NO_SYNC_KHR;
mSlots[found].mFence = Fence::NO_FENCE;
-
- mCore->validateConsistencyLocked();
} // Autolock scope
if (returnFlags & BUFFER_NEEDS_REALLOCATION) {
@@ -481,6 +494,8 @@
BQ_LOGE("dequeueBuffer: BufferQueue has been abandoned");
return NO_INIT;
}
+
+ mCore->validateConsistencyLocked();
} // Autolock scope
}
@@ -527,9 +542,8 @@
return NO_INIT;
}
- if (mCore->mSingleBufferMode) {
- BQ_LOGE("detachBuffer: cannot detach a buffer in single buffer"
- "mode");
+ if (mCore->mSingleBufferMode || mCore->mSingleBufferSlot == slot) {
+ BQ_LOGE("detachBuffer: cannot detach a buffer in single buffer mode");
return BAD_VALUE;
}
@@ -548,7 +562,9 @@
}
mSlots[slot].mBufferState.detachProducer();
- mCore->freeBufferLocked(slot);
+ mCore->mActiveBuffers.erase(slot);
+ mCore->mFreeSlots.insert(slot);
+ mCore->clearBufferSlotLocked(slot);
mCore->mDequeueCondition.broadcast();
mCore->validateConsistencyLocked();
@@ -593,12 +609,13 @@
int found = mCore->mFreeBuffers.front();
mCore->mFreeBuffers.remove(found);
+ mCore->mFreeSlots.insert(found);
BQ_LOGV("detachNextBuffer detached slot %d", found);
*outBuffer = mSlots[found].mGraphicBuffer;
*outFence = mSlots[found].mFence;
- mCore->freeBufferLocked(found);
+ mCore->clearBufferSlotLocked(found);
mCore->validateConsistencyLocked();
return NO_ERROR;
@@ -644,8 +661,7 @@
status_t returnFlags = NO_ERROR;
int found;
- status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Attach, &found,
- &returnFlags);
+ status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Attach, &found);
if (status != NO_ERROR) {
return status;
}
@@ -666,7 +682,8 @@
mSlots[*outSlot].mEglFence = EGL_NO_SYNC_KHR;
mSlots[*outSlot].mFence = Fence::NO_FENCE;
mSlots[*outSlot].mRequestBufferCalled = true;
-
+ mSlots[*outSlot].mAcquireCalled = false;
+ mCore->mActiveBuffers.insert(found);
mCore->validateConsistencyLocked();
return returnFlags;
@@ -722,11 +739,9 @@
return NO_INIT;
}
- const int maxBufferCount = mCore->getMaxBufferCountLocked();
-
- if (slot < 0 || slot >= maxBufferCount) {
+ if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
BQ_LOGE("queueBuffer: slot index %d out of range [0, %d)",
- slot, maxBufferCount);
+ slot, BufferQueueDefs::NUM_BUFFER_SLOTS);
return BAD_VALUE;
} else if (!mSlots[slot].mBufferState.isDequeued()) {
BQ_LOGE("queueBuffer: slot %d is not owned by the producer "
@@ -807,9 +822,8 @@
// state to see if we need to replace it
BufferQueueCore::Fifo::iterator front(mCore->mQueue.begin());
if (front->mIsDroppable) {
- // If the front queued buffer is still being tracked, we first
- // mark it as freed
- if (mCore->stillTracking(front)) {
+
+ if (!front->mIsStale) {
mSlots[front->mSlot].mBufferState.freeQueued();
// After leaving single buffer mode, the shared buffer will
@@ -821,9 +835,11 @@
}
// Don't put the shared buffer on the free list.
if (!mSlots[front->mSlot].mBufferState.isShared()) {
- mCore->mFreeBuffers.push_front(front->mSlot);
+ mCore->mActiveBuffers.erase(front->mSlot);
+ mCore->mFreeBuffers.push_back(front->mSlot);
}
}
+
// Overwrite the droppable buffer with the incoming one
*front = item;
frameReplacedListener = mCore->mConsumerListener;
@@ -926,8 +942,10 @@
// Don't put the shared buffer on the free list.
if (!mSlots[slot].mBufferState.isShared()) {
- mCore->mFreeBuffers.push_front(slot);
+ mCore->mActiveBuffers.erase(slot);
+ mCore->mFreeBuffers.push_back(slot);
}
+
mSlots[slot].mFence = fence;
mCore->mDequeueCondition.broadcast();
mCore->validateConsistencyLocked();
@@ -1020,6 +1038,17 @@
return BAD_VALUE;
}
+ int delta = mCore->getMaxBufferCountLocked(mCore->mAsyncMode,
+ mDequeueTimeout < 0 ?
+ mCore->mConsumerControlledByApp && producerControlledByApp : false,
+ mCore->mMaxBufferCount) -
+ mCore->getMaxBufferCountLocked();
+ if (!mCore->adjustAvailableSlotsLocked(delta)) {
+ BQ_LOGE("connect: BufferQueue failed to adjust the number of available "
+ "slots. Delta = %d", delta);
+ return BAD_VALUE;
+ }
+
int status = NO_ERROR;
switch (api) {
case NATIVE_WINDOW_API_EGL:
@@ -1056,8 +1085,9 @@
mCore->mDequeueBufferCannotBlock =
mCore->mConsumerControlledByApp && producerControlledByApp;
}
- mCore->mAllowAllocation = true;
+ mCore->mAllowAllocation = true;
+ mCore->validateConsistencyLocked();
return status;
}
@@ -1094,6 +1124,8 @@
token->unlinkToDeath(
static_cast<IBinder::DeathRecipient*>(this));
}
+ mCore->mSingleBufferSlot =
+ BufferQueueCore::INVALID_BUFFER_SLOT;
mCore->mConnectedProducerListener = NULL;
mCore->mConnectedApi = BufferQueueCore::NO_CONNECTED_API;
mCore->mSidebandStream.clear();
@@ -1138,7 +1170,6 @@
PixelFormat format, uint32_t usage) {
ATRACE_CALL();
while (true) {
- Vector<int> freeSlots;
size_t newBufferCount = 0;
uint32_t allocWidth = 0;
uint32_t allocHeight = 0;
@@ -1154,32 +1185,11 @@
return;
}
- int currentBufferCount = 0;
- for (int slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) {
- if (mSlots[slot].mGraphicBuffer != NULL) {
- ++currentBufferCount;
- } else {
- if (!mSlots[slot].mBufferState.isFree()) {
- BQ_LOGE("allocateBuffers: slot %d without buffer is not FREE",
- slot);
- continue;
- }
-
- freeSlots.push_back(slot);
- }
- }
-
- int maxBufferCount = mCore->getMaxBufferCountLocked();
- BQ_LOGV("allocateBuffers: allocating from %d buffers up to %d buffers",
- currentBufferCount, maxBufferCount);
- if (maxBufferCount <= currentBufferCount)
- return;
- newBufferCount =
- static_cast<size_t>(maxBufferCount - currentBufferCount);
- if (freeSlots.size() < newBufferCount) {
- BQ_LOGE("allocateBuffers: ran out of free slots");
+ newBufferCount = mCore->mFreeSlots.size();
+ if (newBufferCount == 0) {
return;
}
+
allocWidth = width > 0 ? width : mCore->mDefaultWidth;
allocHeight = height > 0 ? height : mCore->mDefaultHeight;
allocFormat = format != 0 ? format : mCore->mDefaultBufferFormat;
@@ -1221,24 +1231,23 @@
}
for (size_t i = 0; i < newBufferCount; ++i) {
- int slot = freeSlots[i];
- if (!mSlots[slot].mBufferState.isFree()) {
- // A consumer allocated the FREE slot with attachBuffer. Discard the buffer we
- // allocated.
- BQ_LOGV("allocateBuffers: slot %d was acquired while allocating. "
- "Dropping allocated buffer.", slot);
+ if (mCore->mFreeSlots.empty()) {
+ BQ_LOGV("allocateBuffers: a slot was occupied while "
+ "allocating. Dropping allocated buffer.");
continue;
}
- mCore->freeBufferLocked(slot); // Clean up the slot first
- mSlots[slot].mGraphicBuffer = buffers[i];
- mSlots[slot].mFence = Fence::NO_FENCE;
+ auto slot = mCore->mFreeSlots.begin();
+ mCore->clearBufferSlotLocked(*slot); // Clean up the slot first
+ mSlots[*slot].mGraphicBuffer = buffers[i];
+ mSlots[*slot].mFence = Fence::NO_FENCE;
// freeBufferLocked puts this slot on the free slots list. Since
// we then attached a buffer, move the slot to free buffer list.
mCore->mFreeSlots.erase(slot);
- mCore->mFreeBuffers.push_front(slot);
+ mCore->mFreeBuffers.push_front(*slot);
- BQ_LOGV("allocateBuffers: allocated a new buffer in slot %d", slot);
+ BQ_LOGV("allocateBuffers: allocated a new buffer in slot %d",
+ *slot);
}
mCore->mIsAllocating = false;
@@ -1297,8 +1306,17 @@
BQ_LOGV("setDequeueTimeout: %" PRId64, timeout);
Mutex::Autolock lock(mCore->mMutex);
+ int delta = mCore->getMaxBufferCountLocked(mCore->mAsyncMode, false,
+ mCore->mMaxBufferCount) - mCore->getMaxBufferCountLocked();
+ if (!mCore->adjustAvailableSlotsLocked(delta)) {
+ BQ_LOGE("setDequeueTimeout: BufferQueue failed to adjust the number of "
+ "available slots. Delta = %d", delta);
+ return BAD_VALUE;
+ }
+
mDequeueTimeout = timeout;
mCore->mDequeueBufferCannotBlock = false;
+ mCore->validateConsistencyLocked();
return NO_ERROR;
}
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 9e90ad0..6fc55c3 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -759,6 +759,13 @@
*outFence = Fence::NO_FENCE;
}
+ for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+ if (mSlots[i].buffer != NULL &&
+ mSlots[i].buffer->handle == buffer->handle) {
+ mSlots[i].buffer = NULL;
+ }
+ }
+
return NO_ERROR;
}