BufferQueue: use max acquired buffer count

This change makes BufferQueue derive the min undequeued buffer count from a max
acquired buffer count that is set by the consumer.  This value may be set at
any time that a producer is not connected to the BufferQueue rather than at
BufferQueue construction time.

Change-Id: Icf9f1d91ec612a079968ba0a4621deffe48f4e22
diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h
index 5b68b05..0a95bb3 100644
--- a/include/gui/BufferQueue.h
+++ b/include/gui/BufferQueue.h
@@ -92,13 +92,11 @@
     };
 
 
-    // BufferQueue manages a pool of gralloc memory slots to be used
-    // by producers and consumers.
-    // allowSynchronousMode specifies whether or not synchronous mode can be
-    // enabled.
-    // bufferCount sets the minimum number of undequeued buffers for this queue
+    // BufferQueue manages a pool of gralloc memory slots to be used by
+    // producers and consumers. allowSynchronousMode specifies whether or not
+    // synchronous mode can be enabled by the producer. allocator is used to
+    // allocate all the needed gralloc buffers.
     BufferQueue(bool allowSynchronousMode = true,
-            int bufferCount = MIN_UNDEQUEUED_BUFFERS,
             const sp<IGraphicBufferAlloc>& allocator = NULL);
     virtual ~BufferQueue();
 
@@ -257,6 +255,11 @@
     // take effect once the client sets the count back to zero.
     status_t setDefaultMaxBufferCount(int bufferCount);
 
+    // setMaxAcquiredBufferCount sets the maximum number of buffers that can
+    // be acquired by the consumer at one time.  This call will fail if a
+    // producer is connected to the BufferQueue.
+    status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers);
+
     // isSynchronousMode returns whether the SurfaceTexture is currently in
     // synchronous mode.
     bool isSynchronousMode() const;
@@ -307,12 +310,16 @@
     // given the current BufferQueue state.
     int getMinMaxBufferCountLocked() const;
 
+    // getMinUndequeuedBufferCountLocked returns the minimum number of buffers
+    // that must remain in a state other than DEQUEUED.
+    int getMinUndequeuedBufferCountLocked() const;
+
     // getMaxBufferCountLocked returns the maximum number of buffers that can
     // be allocated at once.  This value depends upon the following member
     // variables:
     //
     //      mSynchronousMode
-    //      mMinUndequeuedBuffers
+    //      mMaxAcquiredBufferCount
     //      mDefaultMaxBufferCount
     //      mOverrideMaxBufferCount
     //
@@ -442,9 +449,14 @@
     // in requestBuffers() if a width and height of zero is specified.
     uint32_t mDefaultHeight;
 
-    // mMinUndequeuedBuffers is a constraint on the number of buffers
-    // not dequeued at any time
-    int mMinUndequeuedBuffers;
+    // mMaxAcquiredBufferCount is the number of buffers that the consumer may
+    // acquire at one time.  It defaults to 1 and can be changed by the
+    // consumer via the setMaxAcquiredBufferCount method, but this may only be
+    // done when no producer is connected to the BufferQueue.
+    //
+    // This value is used to derive the value returned for the
+    // MIN_UNDEQUEUED_BUFFERS query by the producer.
+    int mMaxAcquiredBufferCount;
 
     // mDefaultMaxBufferCount is the default limit on the number of buffers
     // that will be allocated at one time.  This default limit is set by the
diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp
index 218d929..57df39c 100644
--- a/libs/gui/BufferItemConsumer.cpp
+++ b/libs/gui/BufferItemConsumer.cpp
@@ -31,10 +31,11 @@
 
 BufferItemConsumer::BufferItemConsumer(uint32_t consumerUsage,
         int bufferCount, bool synchronousMode) :
-    ConsumerBase(new BufferQueue(true, bufferCount) )
+    ConsumerBase(new BufferQueue(true) )
 {
     mBufferQueue->setConsumerUsageBits(consumerUsage);
     mBufferQueue->setSynchronousMode(synchronousMode);
+    mBufferQueue->setMaxAcquiredBufferCount(bufferCount);
 }
 
 BufferItemConsumer::~BufferItemConsumer() {
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 6689e84..db021ff 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -81,12 +81,12 @@
     }
 }
 
-BufferQueue::BufferQueue(bool allowSynchronousMode, int bufferCount,
+BufferQueue::BufferQueue(bool allowSynchronousMode,
         const sp<IGraphicBufferAlloc>& allocator) :
     mDefaultWidth(1),
     mDefaultHeight(1),
-    mMinUndequeuedBuffers(bufferCount),
-    mDefaultMaxBufferCount(bufferCount + 1),
+    mMaxAcquiredBufferCount(1),
+    mDefaultMaxBufferCount(2),
     mOverrideMaxBufferCount(0),
     mSynchronousMode(false),
     mAllowSynchronousMode(allowSynchronousMode),
@@ -233,8 +233,7 @@
         value = mDefaultBufferFormat;
         break;
     case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
-        value = mSynchronousMode ?
-                (mMinUndequeuedBuffers-1) : mMinUndequeuedBuffers;
+        value = getMinUndequeuedBufferCountLocked();
         break;
     case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND:
         value = (mQueue.size() >= 2);
@@ -356,17 +355,18 @@
             }
 
             // See whether a buffer has been queued since the last
-            // setBufferCount so we know whether to perform the
-            // mMinUndequeuedBuffers check below.
+            // setBufferCount so we know whether to perform the min undequeued
+            // buffers check below.
             if (mBufferHasBeenQueued) {
                 // make sure the client is not trying to dequeue more buffers
                 // than allowed.
-                const int avail = maxBufferCount - (dequeuedCount+1);
-                if (avail < (mMinUndequeuedBuffers-int(mSynchronousMode))) {
-                    ST_LOGE("dequeueBuffer: mMinUndequeuedBuffers=%d exceeded "
-                            "(dequeued=%d)",
-                            mMinUndequeuedBuffers-int(mSynchronousMode),
-                            dequeuedCount);
+                const int newUndequeuedCount = maxBufferCount - (dequeuedCount+1);
+                const int minUndequeuedCount = getMinUndequeuedBufferCountLocked();
+                if (newUndequeuedCount < minUndequeuedCount) {
+                    ST_LOGE("dequeueBuffer: min undequeued buffer count (%d) "
+                            "exceeded (dequeued=%d undequeudCount=%d)",
+                            minUndequeuedCount, dequeuedCount,
+                            newUndequeuedCount);
                     return -EBUSY;
                 }
             }
@@ -954,6 +954,16 @@
     return setDefaultMaxBufferCountLocked(bufferCount);
 }
 
+status_t BufferQueue::setMaxAcquiredBufferCount(int maxAcquiredBuffers) {
+    ATRACE_CALL();
+    Mutex::Autolock lock(mMutex);
+    if (mConnectedApi != NO_CONNECTED_API) {
+        return INVALID_OPERATION;
+    }
+    mMaxAcquiredBufferCount = maxAcquiredBuffers;
+    return OK;
+}
+
 void BufferQueue::freeAllBuffersExceptHeadLocked() {
     int head = -1;
     if (!mQueue.empty()) {
@@ -996,7 +1006,12 @@
 }
 
 int BufferQueue::getMinMaxBufferCountLocked() const {
-    return mSynchronousMode ? mMinUndequeuedBuffers : mMinUndequeuedBuffers + 1;
+    return getMinUndequeuedBufferCountLocked() + 1;
+}
+
+int BufferQueue::getMinUndequeuedBufferCountLocked() const {
+    return mSynchronousMode ? mMaxAcquiredBufferCount :
+            mMaxAcquiredBufferCount + 1;
 }
 
 int BufferQueue::getMaxBufferCountLocked() const {
diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp
index 242ac45..fc4a854 100644
--- a/libs/gui/CpuConsumer.cpp
+++ b/libs/gui/CpuConsumer.cpp
@@ -30,7 +30,7 @@
 namespace android {
 
 CpuConsumer::CpuConsumer(uint32_t maxLockedBuffers) :
-    ConsumerBase(new BufferQueue(true, maxLockedBuffers) ),
+    ConsumerBase(new BufferQueue(true) ),
     mMaxLockedBuffers(maxLockedBuffers),
     mCurrentLockedBuffers(0)
 {
@@ -41,6 +41,7 @@
 
     mBufferQueue->setSynchronousMode(true);
     mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_SW_READ_OFTEN);
+    mBufferQueue->setMaxAcquiredBufferCount(maxLockedBuffers);
 }
 
 CpuConsumer::~CpuConsumer() {
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index d601fca..7fb1159 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -67,8 +67,7 @@
  */
 
 FramebufferSurface::FramebufferSurface():
-    ConsumerBase(new BufferQueue(true, NUM_FRAME_BUFFERS,
-            new GraphicBufferAlloc())),
+    ConsumerBase(new BufferQueue(true, new GraphicBufferAlloc())),
     fbDev(0),
     mCurrentBufferSlot(-1),
     mCurrentBuffer(0)