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;
};