Commit 23b4abe0 authored by Pablo Ceballos's avatar Pablo Ceballos
Browse files

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
parent c2a3d7aa
......@@ -125,6 +125,10 @@ class BufferItem : public Flattenable<BufferItem> {
// 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
......
......@@ -105,17 +105,23 @@ private:
// 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 @@ private:
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;
......
......@@ -187,9 +187,9 @@ private:
// 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 @@ private:
Dequeue,
Attach,
};
status_t waitForFreeSlotThenRelock(FreeSlotCaller caller, int* found,
status_t* returnFlags) const;
status_t waitForFreeSlotThenRelock(FreeSlotCaller caller, int* found) const;
sp<BufferQueueCore> mCore;
......
......@@ -174,14 +174,15 @@ struct BufferState {
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 @@ struct BufferSlot {
// 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 @@ struct BufferSlot {
// 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
......
......@@ -199,7 +199,9 @@ public:
// 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 @@ public:
// 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;
......
......@@ -101,8 +101,9 @@ public:
// * 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 @@ public:
//
// 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 @@ public:
// * 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 @@ public:
// 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;
};
......
......@@ -39,7 +39,8 @@ BufferItem::BufferItem() :
mTransformToDisplayInverse(false),
mSurfaceDamage(),
mSingleBufferMode(false),
mQueuedBuffer(true) {
mQueuedBuffer(true),
mIsStale(false) {
}
BufferItem::~BufferItem() {}
......
......@@ -49,7 +49,7 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
// 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 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
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 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
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 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
outBuffer->mSurfaceDamage = Region::INVALID_REGION;
outBuffer->mSingleBufferMode = true;
outBuffer->mQueuedBuffer = false;
outBuffer->mIsStale = false;
} else {
slot = front->mSlot;
*outBuffer = *front;
......@@ -216,10 +222,9 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
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 @@ status_t BufferQueueConsumer::detachBuffer(int slot) {
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 @@ status_t BufferQueueConsumer::detachBuffer(int slot) {
}
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 @@ status_t BufferQueueConsumer::attachBuffer(int* outSlot,
// 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 @@ status_t BufferQueueConsumer::attachBuffer(int* outSlot,
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 @@ status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber,
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 @@ status_t BufferQueueConsumer::disconnect() {
mCore->mConsumerListener = NULL;
mCore->mQueue.clear();
mCore->freeAllBuffersLocked();
mCore->mSingleBufferSlot = BufferQueueCore::INVALID_BUFFER_SLOT;
mCore->mDequeueCondition.broadcast();
return NO_ERROR;
}
......@@ -579,6 +581,15 @@ status_t BufferQueueConsumer::setMaxBufferCount(int bufferCount) {
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 @@ status_t BufferQueueConsumer::setMaxAcquiredBufferCount(
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;
}
......
......@@ -52,6 +52,8 @@ BufferQueueCore::BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator) :
mQueue(),
mFreeSlots(),
mFreeBuffers(),
mUnusedSlots(),
mActiveBuffers(),
mDequeueCondition(),
mDequeueBufferCannotBlock(false),
mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888),
......@@ -82,8 +84,14 @@ BufferQueueCore::BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator) :
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 @@ void BufferQueueCore::dump(String8& result, const char* prefix) const {
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 = 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);
}
}
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);
}
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 @@ int BufferQueueCore::getMinMaxBufferCountLocked() const {
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 @@ void BufferQueueCore::freeBufferLocked(int slot, bool validate) {
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;
validateConsistencyLocked();
}
bool BufferQueueCore::stillTracking(const BufferItem* item) const {
const BufferSlot& slot = mSlots[item->mSlot];
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;
}
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));
validateConsistencyLocked();
}
// 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::waitWhileAllocatingLocked() const {
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()) {
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 mUnusedSlots and in mFreeSlots", slot);
usleep(PAUSE_TIME);
}
if (isInFreeBuffers) {
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) {
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);
}
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);
}
} else {
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 mActiveBuffers 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 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
......@@ -96,7 +96,7 @@ status_t BufferQueueProducer::setMaxDequeuedBufferCount(
}
// 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 @@ status_t BufferQueueProducer::setMaxDequeuedBufferCount(
// 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 @@ status_t BufferQueueProducer::setAsyncMode(bool async) {
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 @@ int BufferQueueProducer::getFreeBufferLocked() const {
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 @@ status_t BufferQueueProducer::waitForFreeSlotThenRelock(FreeSlotCaller caller,
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 @@ status_t BufferQueueProducer::waitForFreeSlotThenRelock(FreeSlotCaller caller,
// 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 @@ status_t BufferQueueProducer::waitForFreeSlotThenRelock(FreeSlotCaller caller,
} 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 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot,
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 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot,
// 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 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot,
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 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot,
*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 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot,
BQ_LOGE("dequeueBuffer: BufferQueue has been abandoned");
return NO_INIT;
}
mCore->validateConsistencyLocked();
} // Autolock scope
}
......@@ -527,9 +542,8 @@ status_t BufferQueueProducer::detachBuffer(int slot) {
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 @@ status_t BufferQueueProducer::detachBuffer(int slot) {
}
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 @@ status_t BufferQueueProducer::detachNextBuffer(sp<GraphicBuffer>* outBuffer,
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 BufferQueueProducer::attachBuffer(int* outSlot,
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 @@ status_t BufferQueueProducer::attachBuffer(int* outSlot,
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 @@ status_t BufferQueueProducer::queueBuffer(int slot,
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 @@ status_t BufferQueueProducer::queueBuffer(int slot,
// 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 @@ status_t BufferQueueProducer::queueBuffer(int slot,
}
// 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 @@ status_t BufferQueueProducer::cancelBuffer(int slot, const sp<Fence>& fence) {
// 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 @@ status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener,
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 @@ status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener,
mCore->mDequeueBufferCannotBlock =
mCore->mConsumerControlledByApp && producerControlledByApp;
}
mCore->mAllowAllocation = true;
mCore->mAllowAllocation = true;
mCore->validateConsistencyLocked();
return status;
}
......@@ -1094,6 +1124,8 @@ status_t BufferQueueProducer::disconnect(int api) {
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 @@ void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height,
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 @@ void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height,
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 @@ void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height,
}
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 @@ status_t BufferQueueProducer::setDequeueTimeout(nsecs_t timeout) {
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;
}
......
......@@ -759,6 +759,13 @@ int Surface::detachNextBuffer(sp<GraphicBuffer>* outBuffer,
*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;
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment