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