BQ: Modify consumer buffer count interfaces

- Rename setDefaultMaxBufferCount() to setMaxBufferCount(). Modify it
  to be hard maximum on the number of buffers that can't be overwritten
  by the producer.
- Enforce the maximum buffer count in setMaxAcquiredBufferCount(),
  setMaxDequeuedBufferCount(), and setAsyncMode().
- Remove mOverrideMaxBufferCount as it's no longer needed since
  overriding is no longer possible.
- Expose setMaxAcquiredBufferCount() in GLConsumer.
- Remove disableAsyncBuffer(), it was only being used for single buffer
  mode. Single buffer mode is now achievable with setMaxBufferCount().

Bug 13174928

Change-Id: Ia33799f42751272a711fbd8559f7602ce9f18e4f
diff --git a/cmds/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp
index 3155766..ddf3aa8 100644
--- a/cmds/flatland/GLHelper.cpp
+++ b/cmds/flatland/GLHelper.cpp
@@ -207,7 +207,7 @@
     sp<GLConsumer> glc = new GLConsumer(consumer, name,
             GL_TEXTURE_EXTERNAL_OES, false, true);
     glc->setDefaultBufferSize(w, h);
-    glc->setDefaultMaxBufferCount(3);
+    producer->setMaxDequeuedBufferCount(2);
     glc->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER);
 
     sp<ANativeWindow> anw = new Surface(producer);
diff --git a/include/gui/BufferQueueConsumer.h b/include/gui/BufferQueueConsumer.h
index cde302f..b2daae4 100644
--- a/include/gui/BufferQueueConsumer.h
+++ b/include/gui/BufferQueueConsumer.h
@@ -100,20 +100,8 @@
     // is 1x1.
     virtual status_t setDefaultBufferSize(uint32_t width, uint32_t height);
 
-    // setDefaultMaxBufferCount sets the default value for the maximum buffer
-    // count (the initial default is 2). If the producer has requested a
-    // buffer count using setBufferCount, the default buffer count will only
-    // take effect if the producer sets the count back to zero.
-    //
-    // The count must be between 2 and NUM_BUFFER_SLOTS, inclusive.
-    virtual status_t setDefaultMaxBufferCount(int bufferCount);
-
-    // disableAsyncBuffer disables the extra buffer used in async mode
-    // (when both producer and consumer have set their "isControlledByApp"
-    // flag) and has dequeueBuffer() return WOULD_BLOCK instead.
-    //
-    // This can only be called before connect().
-    virtual status_t disableAsyncBuffer();
+    // see IGraphicBufferConsumer::setMaxBufferCount
+    virtual status_t setMaxBufferCount(int bufferCount);
 
     // setMaxAcquiredBufferCount sets the maximum number of buffers that can
     // be acquired by the consumer at one time (default 1).  This call will
diff --git a/include/gui/BufferQueueCore.h b/include/gui/BufferQueueCore.h
index c6643ea..e824124 100644
--- a/include/gui/BufferQueueCore.h
+++ b/include/gui/BufferQueueCore.h
@@ -105,12 +105,6 @@
     // connected, mDequeueCondition must be broadcast.
     int getMaxBufferCountLocked(bool async) const;
 
-    // setDefaultMaxBufferCountLocked sets the maximum number of buffer slots
-    // that will be used if the producer does not override the buffer slot
-    // count. The count must be between 2 and NUM_BUFFER_SLOTS, inclusive. The
-    // initial default is 2.
-    status_t setDefaultMaxBufferCountLocked(int count);
-
     // freeBufferLocked frees the GraphicBuffer and sync resources for the
     // given slot.
     void freeBufferLocked(int slot);
@@ -196,10 +190,6 @@
     // synchronous mode.
     mutable Condition mDequeueCondition;
 
-    // mUseAsyncBuffer indicates whether an extra buffer is used in async mode
-    // to prevent dequeueBuffer from blocking.
-    bool mUseAsyncBuffer;
-
     // mDequeueBufferCannotBlock indicates whether dequeueBuffer is allowed to
     // block. This flag is set during connect when both the producer and
     // consumer are controlled by the application.
@@ -222,11 +212,9 @@
     // is specified.
     android_dataspace mDefaultBufferDataSpace;
 
-    // mDefaultMaxBufferCount is the default limit on the number of buffers that
-    // will be allocated at one time. This default limit is set by the consumer.
-    // The limit (as opposed to the default limit) may be overriden by the
-    // producer.
-    int mDefaultMaxBufferCount;
+    // mMaxBufferCount is the limit on the number of buffers that will be
+    // allocated at one time. This limit can be set by the consumer.
+    int mMaxBufferCount;
 
     // 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
@@ -240,13 +228,6 @@
     // via setMaxDequeuedBufferCount.
     int mMaxDequeuedBufferCount;
 
-    // mOverrideMaxBufferCount defaults to false and is set to true once the
-    // producer has called setMaxDequeuedBufferCount or setAsyncMode. Once it is
-    // set mDefaultMaxBufferCount is ignored and the max buffer count is
-    // calculated based on mMaxAcquiredBufferCount, mMaxDequeuedBufferCount, and
-    // mAsyncMode.
-    bool mOverrideMaxBufferCount;
-
     // mBufferHasBeenQueued is true once a buffer has been queued. It is reset
     // when something causes all buffers to be freed (e.g., changing the buffer
     // count).
diff --git a/include/gui/GLConsumer.h b/include/gui/GLConsumer.h
index c35c7be..0e4acee 100644
--- a/include/gui/GLConsumer.h
+++ b/include/gui/GLConsumer.h
@@ -112,11 +112,6 @@
     // union fence.
     void setReleaseFence(const sp<Fence>& fence);
 
-    // setDefaultMaxBufferCount sets the default limit on the maximum number
-    // of buffers that will be allocated at one time. The image producer may
-    // override the limit.
-    status_t setDefaultMaxBufferCount(int bufferCount);
-
     // getTransformMatrix retrieves the 4x4 texture coordinate transform matrix
     // associated with the texture image set by the most recent call to
     // updateTexImage.
@@ -201,6 +196,7 @@
     status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace);
     status_t setConsumerUsageBits(uint32_t usage);
     status_t setTransformHint(uint32_t hint);
+    status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers);
 
     // detachFromContext detaches the GLConsumer from the calling thread's
     // current OpenGL ES context.  This context must be the same as the context
diff --git a/include/gui/IGraphicBufferConsumer.h b/include/gui/IGraphicBufferConsumer.h
index 60ec9cc..d4c9ee5 100644
--- a/include/gui/IGraphicBufferConsumer.h
+++ b/include/gui/IGraphicBufferConsumer.h
@@ -188,32 +188,28 @@
     // * BAD_VALUE - either w or h was zero
     virtual status_t setDefaultBufferSize(uint32_t w, uint32_t h) = 0;
 
-    // setDefaultMaxBufferCount sets the default value for the maximum buffer
-    // count (the initial default is 2). If the producer has requested a
-    // buffer count using setBufferCount, the default buffer count will only
-    // take effect if the producer sets the count back to zero.
+    // setMaxBufferCount sets the maximum value for the number of buffers used
+    // in the buffer queue (the initial default is NUM_BUFFER_SLOTS). If a call
+    // to setMaxAcquiredBufferCount (by the consumer), or a call to setAsyncMode
+    // or setMaxDequeuedBufferCount (by the producer), would cause this value to
+    // be exceeded then that call will fail. This call will fail if a producer
+    // is connected to the BufferQueue.
     //
-    // The count must be between 2 and NUM_BUFFER_SLOTS, inclusive.
+    // The count must be between 1 and NUM_BUFFER_SLOTS, inclusive. The count
+    // 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).
-    virtual status_t setDefaultMaxBufferCount(int bufferCount) = 0;
-
-    // disableAsyncBuffer disables the extra buffer used in async mode
-    // (when both producer and consumer have set their "isControlledByApp"
-    // flag) and has dequeueBuffer() return WOULD_BLOCK instead.
-    //
-    // This can only be called before consumerConnect().
-    //
-    // Return of a value other than NO_ERROR means an error has occurred:
-    // * INVALID_OPERATION - attempting to call this after consumerConnect.
-    virtual status_t disableAsyncBuffer() = 0;
+    // * INVALID_OPERATION - attempting to call this after a producer connected.
+    virtual status_t setMaxBufferCount(int bufferCount) = 0;
 
     // setMaxAcquiredBufferCount sets the maximum number of buffers that can
     // be acquired by the consumer at one time (default 1).  This call will
     // fail if a producer is connected to the BufferQueue.
     //
-    // maxAcquiredBuffers must be (inclusive) between 1 and MAX_MAX_ACQUIRED_BUFFERS.
+    // maxAcquiredBuffers must be (inclusive) between 1 and
+    // MAX_MAX_ACQUIRED_BUFFERS. It also cannot cause the maxBufferCount value
+    // 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).
diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
index 91502e2..5b84bdc 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/include/gui/IGraphicBufferProducer.h
@@ -99,8 +99,9 @@
     // Return of a value other than NO_ERROR means an error has occurred:
     // * 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
+    //     * bufferCount was out of range (see above)
+    //     * client has one or more buffers dequeued
+    //     * this call would cause the maxBufferCount value to be exceeded
     virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers) = 0;
 
     // Set the async flag if the producer intends to asynchronously queue
@@ -116,7 +117,9 @@
     //
     // Return of a value other than NO_ERROR means an error has occurred:
     // * NO_INIT - the buffer queue has been abandoned.
-    // * BAD_VALUE - client has one or more buffers dequeued
+    // * BAD_VALUE - one of the below conditions occurred:
+    //     * client has one or more buffers dequeued
+    //     * this call would cause the maxBufferCount value to be exceeded
     virtual status_t setAsyncMode(bool async) = 0;
 
     // dequeueBuffer requests a new buffer slot for the client to use. Ownership
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index 25b6719..ed2331b 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -170,8 +170,6 @@
     virtual int connect(int api);
     virtual int disconnect(int api);
     virtual int setBufferCount(int bufferCount);
-    virtual int setMaxDequeuedBufferCount(int maxDequeuedBuffers);
-    virtual int setAsyncMode(bool async);
     virtual int setBuffersDimensions(uint32_t width, uint32_t height);
     virtual int setBuffersUserDimensions(uint32_t width, uint32_t height);
     virtual int setBuffersFormat(PixelFormat format);
@@ -185,6 +183,8 @@
     virtual void setSurfaceDamage(android_native_rect_t* rects, size_t numRects);
 
 public:
+    virtual int setMaxDequeuedBufferCount(int maxDequeuedBuffers);
+    virtual int setAsyncMode(bool async);
     virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds);
     virtual int unlockAndPost();
 
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index bb3e1b0..950a074 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -482,24 +482,29 @@
     return NO_ERROR;
 }
 
-status_t BufferQueueConsumer::setDefaultMaxBufferCount(int bufferCount) {
+status_t BufferQueueConsumer::setMaxBufferCount(int bufferCount) {
     ATRACE_CALL();
-    Mutex::Autolock lock(mCore->mMutex);
-    return mCore->setDefaultMaxBufferCountLocked(bufferCount);
-}
 
-status_t BufferQueueConsumer::disableAsyncBuffer() {
-    ATRACE_CALL();
+    if (bufferCount < 1 || bufferCount > BufferQueueDefs::NUM_BUFFER_SLOTS) {
+        BQ_LOGE("setMaxBufferCount: invalid count %d", bufferCount);
+        return BAD_VALUE;
+    }
 
     Mutex::Autolock lock(mCore->mMutex);
 
-    if (mCore->mConsumerListener != NULL) {
-        BQ_LOGE("disableAsyncBuffer: consumer already connected");
+    if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) {
+        BQ_LOGE("setMaxBufferCount: producer is already connected");
         return INVALID_OPERATION;
     }
 
-    BQ_LOGV("disableAsyncBuffer");
-    mCore->mUseAsyncBuffer = false;
+    if (bufferCount < mCore->mMaxAcquiredBufferCount) {
+        BQ_LOGE("setMaxBufferCount: invalid buffer count (%d) less than"
+                "mMaxAcquiredBufferCount (%d)", bufferCount,
+                mCore->mMaxAcquiredBufferCount);
+        return BAD_VALUE;
+    }
+
+    mCore->mMaxBufferCount = bufferCount;
     return NO_ERROR;
 }
 
@@ -521,6 +526,15 @@
         return INVALID_OPERATION;
     }
 
+    if ((maxAcquiredBuffers + mCore->mMaxDequeuedBufferCount +
+            (mCore->mAsyncMode ? 1 : 0)) > mCore->mMaxBufferCount) {
+        BQ_LOGE("setMaxAcquiredBufferCount: %d acquired buffers would exceed "
+                "the maxBufferCount (%d) (maxDequeued %d async %d)",
+                maxAcquiredBuffers, mCore->mMaxBufferCount,
+                mCore->mMaxDequeuedBufferCount, mCore->mAsyncMode);
+        return BAD_VALUE;
+    }
+
     BQ_LOGV("setMaxAcquiredBufferCount: %d", maxAcquiredBuffers);
     mCore->mMaxAcquiredBufferCount = maxAcquiredBuffers;
     return NO_ERROR;
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index d297112..8b97c2a 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -30,9 +30,6 @@
 #include <gui/ISurfaceComposer.h>
 #include <private/gui/ComposerService.h>
 
-template <typename T>
-static inline T max(T a, T b) { return a > b ? a : b; }
-
 namespace android {
 
 static String8 getUniqueName() {
@@ -56,16 +53,14 @@
     mFreeSlots(),
     mFreeBuffers(),
     mDequeueCondition(),
-    mUseAsyncBuffer(true),
     mDequeueBufferCannotBlock(false),
     mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888),
     mDefaultWidth(1),
     mDefaultHeight(1),
     mDefaultBufferDataSpace(HAL_DATASPACE_UNKNOWN),
-    mDefaultMaxBufferCount(2),
+    mMaxBufferCount(BufferQueueDefs::NUM_BUFFER_SLOTS),
     mMaxAcquiredBufferCount(1),
     mMaxDequeuedBufferCount(1),
-    mOverrideMaxBufferCount(false),
     mBufferHasBeenQueued(false),
     mFrameCounter(0),
     mTransformHint(0),
@@ -145,10 +140,6 @@
 int BufferQueueCore::getMinUndequeuedBufferCountLocked(bool async) const {
     // If dequeueBuffer is allowed to error out, we don't have to add an
     // extra buffer.
-    if (!mUseAsyncBuffer) {
-        return mMaxAcquiredBufferCount;
-    }
-
     if (mDequeueBufferCannotBlock || async) {
         return mMaxAcquiredBufferCount + 1;
     }
@@ -161,15 +152,11 @@
 }
 
 int BufferQueueCore::getMaxBufferCountLocked(bool async) const {
-    int minMaxBufferCount = getMinMaxBufferCountLocked(async);
+    int maxBufferCount = mMaxAcquiredBufferCount + mMaxDequeuedBufferCount +
+            (async ? 1 : 0);
 
-    int maxBufferCount = max(mDefaultMaxBufferCount, minMaxBufferCount);
-    if (mOverrideMaxBufferCount) {
-        int bufferCount = mMaxAcquiredBufferCount + mMaxDequeuedBufferCount +
-                (async ? 1 : 0);
-        assert(bufferCount >= minMaxBufferCount);
-        maxBufferCount = bufferCount;
-    }
+    // 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
@@ -185,22 +172,6 @@
     return maxBufferCount;
 }
 
-status_t BufferQueueCore::setDefaultMaxBufferCountLocked(int count) {
-    const int minBufferCount = mUseAsyncBuffer ? 2 : 1;
-    if (count < minBufferCount || count > BufferQueueDefs::NUM_BUFFER_SLOTS) {
-        BQ_LOGV("setDefaultMaxBufferCount: invalid count %d, should be in "
-                "[%d, %d]",
-                count, minBufferCount, BufferQueueDefs::NUM_BUFFER_SLOTS);
-        return BAD_VALUE;
-    }
-
-    BQ_LOGV("setDefaultMaxBufferCount: setting count to %d", count);
-    mDefaultMaxBufferCount = count;
-    mDequeueCondition.broadcast();
-
-    return NO_ERROR;
-}
-
 void BufferQueueCore::freeBufferLocked(int slot) {
     BQ_LOGV("freeBufferLocked: slot %d", slot);
     bool hadBuffer = mSlots[slot].mGraphicBuffer != NULL;
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 61878f6..8cc0cfa 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -115,13 +115,20 @@
             return BAD_VALUE;
         }
 
+        if (bufferCount > mCore->mMaxBufferCount) {
+            BQ_LOGE("setMaxDequeuedBufferCount: %d dequeued buffers would "
+                    "exceed the maxBufferCount (%d) (maxAcquired %d async %d)",
+                    maxDequeuedBuffers, mCore->mMaxBufferCount,
+                    mCore->mMaxAcquiredBufferCount, mCore->mAsyncMode);
+            return BAD_VALUE;
+        }
+
         // Here we are guaranteed that the producer doesn't have any dequeued
         // 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();
         mCore->mMaxDequeuedBufferCount = maxDequeuedBuffers;
-        mCore->mOverrideMaxBufferCount = true;
         mCore->mDequeueCondition.broadcast();
         listener = mCore->mConsumerListener;
     } // Autolock scope
@@ -156,8 +163,17 @@
             }
         }
 
+        if ((mCore->mMaxAcquiredBufferCount + mCore->mMaxDequeuedBufferCount +
+                (async ? 1 : 0)) > mCore->mMaxBufferCount) {
+            BQ_LOGE("setAsyncMode(%d): this call would cause the "
+                    "maxBufferCount (%d) to be exceeded (maxAcquired %d "
+                    "maxDequeued %d)", async,mCore->mMaxBufferCount,
+                    mCore->mMaxAcquiredBufferCount,
+                    mCore->mMaxDequeuedBufferCount);
+            return BAD_VALUE;
+        }
+
         mCore->mAsyncMode = async;
-        mCore->mOverrideMaxBufferCount = true;
         mCore->mDequeueCondition.broadcast();
         listener = mCore->mConsumerListener;
     } // Autolock scope
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index be5075c..5394fb6 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -183,12 +183,6 @@
     mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
 }
 
-status_t GLConsumer::setDefaultMaxBufferCount(int bufferCount) {
-    Mutex::Autolock lock(mMutex);
-    return mConsumer->setDefaultMaxBufferCount(bufferCount);
-}
-
-
 status_t GLConsumer::setDefaultBufferSize(uint32_t w, uint32_t h)
 {
     Mutex::Autolock lock(mMutex);
@@ -1048,6 +1042,11 @@
     return mConsumer->setTransformHint(hint);
 }
 
+status_t GLConsumer::setMaxAcquiredBufferCount(int maxAcquiredBuffers) {
+    Mutex::Autolock lock(mMutex);
+    return mConsumer->setMaxAcquiredBufferCount(maxAcquiredBuffers);
+}
+
 void GLConsumer::dumpLocked(String8& result, const char* prefix) const
 {
     result.appendFormat(
diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp
index b86f4c5..d2f482e 100644
--- a/libs/gui/IGraphicBufferConsumer.cpp
+++ b/libs/gui/IGraphicBufferConsumer.cpp
@@ -43,8 +43,7 @@
     CONSUMER_DISCONNECT,
     GET_RELEASED_BUFFERS,
     SET_DEFAULT_BUFFER_SIZE,
-    SET_DEFAULT_MAX_BUFFER_COUNT,
-    DISABLE_ASYNC_BUFFER,
+    SET_MAX_BUFFER_COUNT,
     SET_MAX_ACQUIRED_BUFFER_COUNT,
     SET_CONSUMER_NAME,
     SET_DEFAULT_BUFFER_FORMAT,
@@ -172,21 +171,11 @@
         return reply.readInt32();
     }
 
-    virtual status_t setDefaultMaxBufferCount(int bufferCount) {
+    virtual status_t setMaxBufferCount(int bufferCount) {
         Parcel data, reply;
         data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
         data.writeInt32(bufferCount);
-        status_t result = remote()->transact(SET_DEFAULT_MAX_BUFFER_COUNT, data, &reply);
-        if (result != NO_ERROR) {
-            return result;
-        }
-        return reply.readInt32();
-    }
-
-    virtual status_t disableAsyncBuffer() {
-        Parcel data, reply;
-        data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
-        status_t result = remote()->transact(DISABLE_ASYNC_BUFFER, data, &reply);
+        status_t result = remote()->transact(SET_MAX_BUFFER_COUNT, data, &reply);
         if (result != NO_ERROR) {
             return result;
         }
@@ -363,16 +352,10 @@
             reply->writeInt32(result);
             return NO_ERROR;
         }
-        case SET_DEFAULT_MAX_BUFFER_COUNT: {
+        case SET_MAX_BUFFER_COUNT: {
             CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
             int bufferCount = data.readInt32();
-            status_t result = setDefaultMaxBufferCount(bufferCount);
-            reply->writeInt32(result);
-            return NO_ERROR;
-        }
-        case DISABLE_ASYNC_BUFFER: {
-            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
-            status_t result = disableAsyncBuffer();
+            status_t result = setMaxBufferCount(bufferCount);
             reply->writeInt32(result);
             return NO_ERROR;
         }
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index 115e4db..514b5fc 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -189,6 +189,9 @@
     EXPECT_EQ(BAD_VALUE, mConsumer->setMaxAcquiredBufferCount(
             BufferQueue::MAX_MAX_ACQUIRED_BUFFERS+1));
     EXPECT_EQ(BAD_VALUE, mConsumer->setMaxAcquiredBufferCount(100));
+
+    EXPECT_EQ(OK, mConsumer->setMaxBufferCount(5));
+    EXPECT_EQ(BAD_VALUE, mConsumer->setMaxAcquiredBufferCount(5));
 }
 
 TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithLegalValues_Succeeds) {
@@ -206,6 +209,28 @@
             BufferQueue::MAX_MAX_ACQUIRED_BUFFERS));
 }
 
+TEST_F(BufferQueueTest, SetMaxBufferCountWithLegalValues_Succeeds) {
+    createBufferQueue();
+    sp<DummyConsumer> dc(new DummyConsumer);
+    mConsumer->consumerConnect(dc, false);
+
+    // Test single buffer mode
+    EXPECT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(1));
+}
+
+TEST_F(BufferQueueTest, SetMaxBufferCountWithIllegalValues_ReturnsError) {
+    createBufferQueue();
+    sp<DummyConsumer> dc(new DummyConsumer);
+    mConsumer->consumerConnect(dc, false);
+
+    EXPECT_EQ(BAD_VALUE, mConsumer->setMaxBufferCount(0));
+    EXPECT_EQ(BAD_VALUE, mConsumer->setMaxBufferCount(
+            BufferQueue::NUM_BUFFER_SLOTS + 1));
+
+    EXPECT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(5));
+    EXPECT_EQ(BAD_VALUE, mConsumer->setMaxBufferCount(3));
+}
+
 TEST_F(BufferQueueTest, DetachAndReattachOnProducerSide) {
     createBufferQueue();
     sp<DummyConsumer> dc(new DummyConsumer);
diff --git a/libs/gui/tests/SurfaceTextureGLThreadToGL_test.cpp b/libs/gui/tests/SurfaceTextureGLThreadToGL_test.cpp
index 9776733..b4e25f3 100644
--- a/libs/gui/tests/SurfaceTextureGLThreadToGL_test.cpp
+++ b/libs/gui/tests/SurfaceTextureGLThreadToGL_test.cpp
@@ -134,8 +134,6 @@
         }
     };
 
-    ASSERT_EQ(OK, mST->setDefaultMaxBufferCount(2));
-
     runProducerThread(new PT());
 
     // Allow three frames to be rendered and queued before starting the
diff --git a/libs/gui/tests/SurfaceTextureGLToGL_test.cpp b/libs/gui/tests/SurfaceTextureGLToGL_test.cpp
index 6edbfb8..b3f6066 100644
--- a/libs/gui/tests/SurfaceTextureGLToGL_test.cpp
+++ b/libs/gui/tests/SurfaceTextureGLToGL_test.cpp
@@ -29,8 +29,9 @@
     mST->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_90);
 
     // This test requires 3 buffers to avoid deadlock because we're
-    // both producer and consumer, and only using one thread.
-    mST->setDefaultMaxBufferCount(3);
+    // both producer and consumer, and only using one thread. Set max dequeued
+    // to 2, and max acquired already defaults to 1.
+    ASSERT_EQ(OK, mSTC->setMaxDequeuedBufferCount(2));
 
     // Do the producer side of things
     EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
@@ -81,7 +82,8 @@
     mST->setDefaultBufferSize(texWidth, texHeight);
 
     // This test requires 3 buffers to complete run on a single thread.
-    mST->setDefaultMaxBufferCount(3);
+    // Set max dequeued to 2, and max acquired already defaults to 1.
+    ASSERT_EQ(OK, mSTC->setMaxDequeuedBufferCount(2));
 
     // Do the producer side of things
     EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
@@ -330,7 +332,8 @@
     enum { texHeight = 64 };
 
     // This test requires 3 buffers to complete run on a single thread.
-    mST->setDefaultMaxBufferCount(3);
+    // Set max dequeued to 2, and max acquired already defaults to 1.
+    ASSERT_EQ(OK, mSTC->setMaxDequeuedBufferCount(2));
 
     // Set the user buffer size.
     native_window_set_buffers_user_dimensions(mANW.get(), texWidth, texHeight);
@@ -387,7 +390,8 @@
     enum { texHeight = 16 };
 
     // This test requires 3 buffers to complete run on a single thread.
-    mST->setDefaultMaxBufferCount(3);
+    // Set max dequeued to 2, and max acquired already defaults to 1.
+    ASSERT_EQ(OK, mSTC->setMaxDequeuedBufferCount(2));
 
     // Set the transform hint.
     mST->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_90);
@@ -448,7 +452,8 @@
     enum { texHeight = 16 };
 
     // This test requires 3 buffers to complete run on a single thread.
-    mST->setDefaultMaxBufferCount(3);
+    // Set max dequeued to 2, and max acquired already defaults to 1.
+    ASSERT_EQ(OK, mSTC->setMaxDequeuedBufferCount(2));
 
     // Set the transform hint.
     mST->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_90);
diff --git a/libs/gui/tests/SurfaceTextureGL_test.cpp b/libs/gui/tests/SurfaceTextureGL_test.cpp
index fad133f..0e85b90 100644
--- a/libs/gui/tests/SurfaceTextureGL_test.cpp
+++ b/libs/gui/tests/SurfaceTextureGL_test.cpp
@@ -190,7 +190,6 @@
     enum { texHeight = 16 };
     enum { numFrames = 1024 };
 
-    ASSERT_EQ(NO_ERROR, mST->setDefaultMaxBufferCount(2));
     ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(),
             texWidth, texHeight));
     ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
@@ -658,8 +657,6 @@
         Mutex mMutex;
     };
 
-    ASSERT_EQ(OK, mST->setDefaultMaxBufferCount(2));
-
     sp<Thread> pt(new ProducerThread(mANW));
     pt->run();
 
diff --git a/libs/gui/tests/SurfaceTextureMultiContextGL_test.cpp b/libs/gui/tests/SurfaceTextureMultiContextGL_test.cpp
index 1cd101e..f74ac3d 100644
--- a/libs/gui/tests/SurfaceTextureMultiContextGL_test.cpp
+++ b/libs/gui/tests/SurfaceTextureMultiContextGL_test.cpp
@@ -361,7 +361,6 @@
 
 TEST_F(SurfaceTextureMultiContextGLTest,
         UpdateTexImageSucceedsForBufferConsumedBeforeDetach) {
-    ASSERT_EQ(NO_ERROR, mST->setDefaultMaxBufferCount(2));
 
     // produce two frames and consume them both on the primary context
     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
@@ -388,7 +387,6 @@
 
 TEST_F(SurfaceTextureMultiContextGLTest,
        AttachAfterDisplayTerminatedSucceeds) {
-    ASSERT_EQ(NO_ERROR, mST->setDefaultMaxBufferCount(2));
 
     // produce two frames and consume them both on the primary context
     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 6ef3295..5574c7e 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -66,7 +66,7 @@
                                        GRALLOC_USAGE_HW_COMPOSER);
     mConsumer->setDefaultBufferFormat(mHwc.getFormat(disp));
     mConsumer->setDefaultBufferSize(mHwc.getWidth(disp),  mHwc.getHeight(disp));
-    mConsumer->setDefaultMaxBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS);
+    mConsumer->setMaxAcquiredBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS - 1);
 }
 
 status_t FramebufferSurface::beginFrame(bool /*mustRecompose*/) {
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 3180d29..07ed57d 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -92,7 +92,6 @@
     mConsumer->setConsumerName(ConsumerBase::mName);
     mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER);
     mConsumer->setDefaultBufferSize(sinkWidth, sinkHeight);
-    mConsumer->setDefaultMaxBufferCount(2);
 }
 
 VirtualDisplaySurface::~VirtualDisplaySurface() {
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 5ff79a9..33af4a5 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -135,9 +135,8 @@
 
 #ifdef TARGET_DISABLE_TRIPLE_BUFFERING
 #warning "disabling triple buffering"
-    mSurfaceFlingerConsumer->setDefaultMaxBufferCount(2);
 #else
-    mSurfaceFlingerConsumer->setDefaultMaxBufferCount(3);
+    mProducer->setMaxDequeuedBufferCount(2);
 #endif
 
     const sp<const DisplayDevice> hw(mFlinger->getDefaultDisplayDevice());