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/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));