BQ: add setMaxDequeuedBufferCount
Adds the new setMaxDequeuedBufferCount() function to
BufferQueueProducer. This will eventually replace setBufferCount.
Also add setAsyncMode.
Bug 13174928
Change-Id: Iea1adcd5d74a75f67d8e9dde06d521695628ad5a
diff --git a/include/gui/BufferQueueCore.h b/include/gui/BufferQueueCore.h
index 99134ea..d8bec88 100644
--- a/include/gui/BufferQueueCore.h
+++ b/include/gui/BufferQueueCore.h
@@ -242,6 +242,11 @@
// the value returned for the MIN_UNDEQUEUED_BUFFERS query to the producer.
int mMaxAcquiredBufferCount;
+ // mMaxDequeuedBufferCount is the number of buffers that the producer may
+ // dequeue at one time. It defaults to 1, and can be changed by the producer
+ // via setMaxDequeuedBufferCount.
+ int mMaxDequeuedBufferCount;
+
// 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).
@@ -280,6 +285,11 @@
// number will fail.
uint32_t mGenerationNumber;
+ // mAsyncMode indicates whether or not async mode is enabled.
+ // In async mode an extra buffer will be allocated to allow the producer to
+ // enqueue buffers without blocking.
+ bool mAsyncMode;
+
}; // class BufferQueueCore
} // namespace android
diff --git a/include/gui/BufferQueueProducer.h b/include/gui/BufferQueueProducer.h
index 9754a89..4fbfca7 100644
--- a/include/gui/BufferQueueProducer.h
+++ b/include/gui/BufferQueueProducer.h
@@ -56,6 +56,12 @@
// to discard buffers through the onBuffersReleased callback.
virtual status_t setBufferCount(int bufferCount);
+ // see IGraphicsBufferProducer::setMaxDequeuedBufferCount
+ virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers);
+
+ // see IGraphicsBufferProducer::setAsyncMode
+ virtual status_t setAsyncMode(bool async);
+
// dequeueBuffer gets the next buffer slot index for the producer to use.
// If a buffer slot is available then that slot index is written to the
// location pointed to by the buf argument and a status of OK is returned.
diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
index 9530de1..7925e74 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/include/gui/IGraphicBufferProducer.h
@@ -102,6 +102,45 @@
// * client has one or more buffers dequeued
virtual status_t setBufferCount(int bufferCount) = 0;
+ // setMaxDequeuedBufferCount sets the maximum number of buffers that can be
+ // dequeued by the producer at one time. If this method succeeds, buffer
+ // slots will be both unallocated and owned by the BufferQueue object (i.e.
+ // they are not owned by the producer or consumer). Calling this will also
+ // cause all buffer slots to be emptied. If the caller is caching the
+ // contents of the buffer slots, it should empty that cache after calling
+ // this method.
+ //
+ // This function should not be called when there are any currently dequeued
+ // buffer slots. Doing so will result in a BAD_VALUE error.
+ //
+ // The buffer count should be at least 1 (inclusive), but at most
+ // (NUM_BUFFER_SLOTS - the minimum undequeued buffer count) (exclusive). The
+ // minimum undequeued buffer count can be obtained by calling
+ // query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS).
+ //
+ // 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
+ virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers) = 0;
+
+ // Set the async flag if the producer intends to asynchronously queue
+ // buffers without blocking. Typically this is used for triple-buffering
+ // and/or when the swap interval is set to zero.
+ //
+ // Enabling async mode will internally allocate an additional buffer to
+ // allow for the asynchronous behavior. If it is not enabled queue/dequeue
+ // calls may block.
+ //
+ // This function should not be called when there are any currently dequeued
+ // buffer slots, doing so will result in a BAD_VALUE error.
+ //
+ // 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
+ virtual status_t setAsyncMode(bool async) = 0;
+
// dequeueBuffer requests a new buffer slot for the client to use. Ownership
// of the slot is transfered to the client, meaning that the server will not
// use the contents of the buffer associated with that slot.
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index 72f1067..25b6719 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -170,6 +170,8 @@
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);
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index 851a396..70d80a7 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -65,6 +65,7 @@
mDefaultBufferDataSpace(HAL_DATASPACE_UNKNOWN),
mDefaultMaxBufferCount(2),
mMaxAcquiredBufferCount(1),
+ mMaxDequeuedBufferCount(1),
mBufferHasBeenQueued(false),
mFrameCounter(0),
mTransformHint(0),
@@ -72,7 +73,8 @@
mIsAllocatingCondition(),
mAllowAllocation(true),
mBufferAge(0),
- mGenerationNumber(0)
+ mGenerationNumber(0),
+ mAsyncMode(false)
{
if (allocator == NULL) {
sp<ISurfaceComposer> composer(ComposerService::getComposerService());
@@ -104,11 +106,12 @@
}
result.appendFormat("%s-BufferQueue mMaxAcquiredBufferCount=%d, "
- "mDequeueBufferCannotBlock=%d, default-size=[%dx%d], "
- "default-format=%d, transform-hint=%02x, FIFO(%zu)={%s}\n",
- prefix, mMaxAcquiredBufferCount, mDequeueBufferCannotBlock,
- mDefaultWidth, mDefaultHeight, mDefaultBufferFormat, mTransformHint,
- mQueue.size(), fifo.string());
+ "mMaxDequeuedBufferCount=%d, mDequeueBufferCannotBlock=%d, "
+ "default-size=[%dx%d], default-format=%d, transform-hint=%02x, "
+ "FIFO(%zu)={%s}\n",
+ prefix, mMaxAcquiredBufferCount, mMaxDequeuedBufferCount,
+ mDequeueBufferCannotBlock, mDefaultWidth, mDefaultHeight,
+ mDefaultBufferFormat, mTransformHint, mQueue.size(), fifo.string());
// Trim the free buffers so as to not spam the dump
int maxBufferCount = 0;
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index a440f6e..5ea4a10 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -118,6 +118,7 @@
// clear the queue, however, so that currently queued buffers still
// get displayed.
mCore->freeAllBuffersLocked();
+ mCore->mMaxDequeuedBufferCount = bufferCount - minBufferSlots + 1;
mCore->mOverrideMaxBufferCount = bufferCount;
mCore->mDequeueCondition.broadcast();
listener = mCore->mConsumerListener;
@@ -131,6 +132,102 @@
return NO_ERROR;
}
+status_t BufferQueueProducer::setMaxDequeuedBufferCount(
+ int maxDequeuedBuffers) {
+ ATRACE_CALL();
+ BQ_LOGV("setMaxDequeuedBufferCount: maxDequeuedBuffers = %d",
+ maxDequeuedBuffers);
+
+ sp<IConsumerListener> listener;
+ { // Autolock scope
+ Mutex::Autolock lock(mCore->mMutex);
+ mCore->waitWhileAllocatingLocked();
+
+ if (mCore->mIsAbandoned) {
+ BQ_LOGE("setMaxDequeuedBufferCount: BufferQueue has been "
+ "abandoned");
+ return NO_INIT;
+ }
+
+ // There must be no dequeued buffers when changing the buffer count.
+ for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
+ if (mSlots[s].mBufferState == BufferSlot::DEQUEUED) {
+ BQ_LOGE("setMaxDequeuedBufferCount: buffer owned by producer");
+ return BAD_VALUE;
+ }
+ }
+
+ int bufferCount = mCore->getMinUndequeuedBufferCountLocked(
+ mCore->mAsyncMode);
+ bufferCount += maxDequeuedBuffers;
+
+ if (bufferCount > BufferQueueDefs::NUM_BUFFER_SLOTS) {
+ BQ_LOGE("setMaxDequeuedBufferCount: bufferCount %d too large "
+ "(max %d)", bufferCount, BufferQueueDefs::NUM_BUFFER_SLOTS);
+ return BAD_VALUE;
+ }
+
+ const int minBufferSlots = mCore->getMinMaxBufferCountLocked(
+ mCore->mAsyncMode);
+ if (bufferCount < minBufferSlots) {
+ BQ_LOGE("setMaxDequeuedBufferCount: requested buffer count %d is "
+ "less than minimum %d", bufferCount, minBufferSlots);
+ 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 = bufferCount;
+ mCore->mDequeueCondition.broadcast();
+ listener = mCore->mConsumerListener;
+ } // Autolock scope
+
+ // Call back without lock held
+ if (listener != NULL) {
+ listener->onBuffersReleased();
+ }
+
+ return NO_ERROR;
+}
+
+status_t BufferQueueProducer::setAsyncMode(bool async) {
+ ATRACE_CALL();
+ BQ_LOGV("setAsyncMode: async = %d", async);
+
+ sp<IConsumerListener> listener;
+ { // Autolock scope
+ Mutex::Autolock lock(mCore->mMutex);
+ mCore->waitWhileAllocatingLocked();
+
+ if (mCore->mIsAbandoned) {
+ BQ_LOGE("setAsyncMode: BufferQueue has been abandoned");
+ return NO_INIT;
+ }
+
+ // There must be no dequeued buffers when changing the async mode.
+ for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
+ if (mSlots[s].mBufferState == BufferSlot::DEQUEUED) {
+ BQ_LOGE("setAsyncMode: buffer owned by producer");
+ return BAD_VALUE;
+ }
+ }
+
+ mCore->mAsyncMode = async;
+ mCore->mDequeueCondition.broadcast();
+ listener = mCore->mConsumerListener;
+ } // Autolock scope
+
+ // Call back without lock held
+ if (listener != NULL) {
+ listener->onBuffersReleased();
+ }
+ return NO_ERROR;
+}
+
status_t BufferQueueProducer::waitForFreeSlotThenRelock(const char* caller,
bool async, int* found, status_t* returnFlags) const {
bool tryAgain = true;
@@ -241,7 +338,7 @@
// buffer (which could cause us to have to wait here), which is
// okay, since it is only used to implement an atomic acquire +
// release (e.g., in GLConsumer::updateTexImage())
- if (mCore->mDequeueBufferCannotBlock &&
+ if ((mCore->mDequeueBufferCannotBlock || mCore->mAsyncMode) &&
(acquiredCount <= mCore->mMaxAcquiredBufferCount)) {
return WOULD_BLOCK;
}
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index d7a7885..4a6bada 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -49,6 +49,8 @@
ALLOW_ALLOCATION,
SET_GENERATION_NUMBER,
GET_CONSUMER_NAME,
+ SET_MAX_DEQUEUED_BUFFER_COUNT,
+ SET_ASYNC_MODE
};
class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
@@ -95,6 +97,34 @@
return result;
}
+ virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers) {
+ Parcel data, reply;
+ data.writeInterfaceToken(
+ IGraphicBufferProducer::getInterfaceDescriptor());
+ data.writeInt32(maxDequeuedBuffers);
+ status_t result = remote()->transact(SET_MAX_DEQUEUED_BUFFER_COUNT,
+ data, &reply);
+ if (result != NO_ERROR) {
+ return result;
+ }
+ result = reply.readInt32();
+ return result;
+ }
+
+ virtual status_t setAsyncMode(bool async) {
+ Parcel data, reply;
+ data.writeInterfaceToken(
+ IGraphicBufferProducer::getInterfaceDescriptor());
+ data.writeInt32(async);
+ status_t result = remote()->transact(SET_ASYNC_MODE,
+ data, &reply);
+ if (result != NO_ERROR) {
+ return result;
+ }
+ result = reply.readInt32();
+ return result;
+ }
+
virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence, bool async,
uint32_t width, uint32_t height, PixelFormat format,
uint32_t usage) {
@@ -341,6 +371,20 @@
reply->writeInt32(result);
return NO_ERROR;
}
+ case SET_MAX_DEQUEUED_BUFFER_COUNT: {
+ CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
+ int maxDequeuedBuffers = data.readInt32();
+ int result = setMaxDequeuedBufferCount(maxDequeuedBuffers);
+ reply->writeInt32(result);
+ return NO_ERROR;
+ }
+ case SET_ASYNC_MODE: {
+ CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
+ bool async = data.readInt32();
+ int result = setAsyncMode(async);
+ reply->writeInt32(result);
+ return NO_ERROR;
+ }
case DEQUEUE_BUFFER: {
CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
bool async = static_cast<bool>(data.readInt32());
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 0a36c56..2a9273d 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -811,6 +811,39 @@
return err;
}
+int Surface::setMaxDequeuedBufferCount(int maxDequeuedBuffers) {
+ ATRACE_CALL();
+ ALOGV("Surface::setMaxDequeuedBufferCount");
+ Mutex::Autolock lock(mMutex);
+
+ status_t err = mGraphicBufferProducer->setMaxDequeuedBufferCount(
+ maxDequeuedBuffers);
+ ALOGE_IF(err, "IGraphicBufferProducer::setMaxDequeuedBufferCount(%d) "
+ "returned %s", maxDequeuedBuffers, strerror(-err));
+
+ if (err == NO_ERROR) {
+ freeAllBuffers();
+ }
+
+ return err;
+}
+
+int Surface::setAsyncMode(bool async) {
+ ATRACE_CALL();
+ ALOGV("Surface::setAsyncMode");
+ Mutex::Autolock lock(mMutex);
+
+ status_t err = mGraphicBufferProducer->setAsyncMode(async);
+ ALOGE_IF(err, "IGraphicBufferProducer::setAsyncMode(%d) returned %s",
+ async, strerror(-err));
+
+ if (err == NO_ERROR) {
+ freeAllBuffers();
+ }
+
+ return err;
+}
+
int Surface::setBuffersDimensions(uint32_t width, uint32_t height)
{
ATRACE_CALL();
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index 1a54875..115e4db 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -145,7 +145,7 @@
IGraphicBufferProducer::QueueBufferOutput qbo;
mProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false,
&qbo);
- mProducer->setBufferCount(4);
+ mProducer->setMaxDequeuedBufferCount(3);
int slot;
sp<Fence> fence;
diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp
index 4ef9a69..ced1555 100644
--- a/libs/gui/tests/IGraphicBufferProducer_test.cpp
+++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp
@@ -569,4 +569,145 @@
}
+TEST_F(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Succeeds) {
+ int minUndequeuedBuffers;
+ ASSERT_OK(mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+ &minUndequeuedBuffers));
+
+ const int minBuffers = 1;
+ const int maxBuffers = BufferQueue::NUM_BUFFER_SLOTS - minUndequeuedBuffers;
+
+ ASSERT_OK(mProducer->setAsyncMode(false)) << "async mode: " << false;
+ ASSERT_OK(mProducer->setMaxDequeuedBufferCount(minBuffers))
+ << "bufferCount: " << minBuffers;
+
+ std::vector<DequeueBufferResult> dequeueList;
+
+ // Should now be able to dequeue up to minBuffers times
+ for (int i = 0; i < minBuffers; ++i) {
+ DequeueBufferResult result;
+
+ EXPECT_LE(OK,
+ dequeueBuffer(QUEUE_BUFFER_INPUT_ASYNC,
+ DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
+ TEST_PRODUCER_USAGE_BITS, &result))
+ << "iteration: " << i << ", slot: " << result.slot;
+
+ dequeueList.push_back(result);
+ }
+
+ // Cancel every buffer, so we can set buffer count again
+ for (auto& result : dequeueList) {
+ mProducer->cancelBuffer(result.slot, result.fence);
+ }
+
+ ASSERT_OK(mProducer->setMaxDequeuedBufferCount(maxBuffers));
+
+ // Should now be able to dequeue up to maxBuffers times
+ for (int i = 0; i < maxBuffers; ++i) {
+ int dequeuedSlot = -1;
+ sp<Fence> dequeuedFence;
+
+ EXPECT_LE(OK,
+ mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
+ QUEUE_BUFFER_INPUT_ASYNC,
+ DEFAULT_WIDTH, DEFAULT_HEIGHT,
+ DEFAULT_FORMAT,
+ TEST_PRODUCER_USAGE_BITS))
+ << "iteration: " << i << ", slot: " << dequeuedSlot;
+ }
+}
+
+TEST_F(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Fails) {
+ int minUndequeuedBuffers;
+ ASSERT_OK(mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+ &minUndequeuedBuffers));
+
+ const int minBuffers = 1;
+ const int maxBuffers = BufferQueue::NUM_BUFFER_SLOTS - minUndequeuedBuffers;
+
+ ASSERT_OK(mProducer->setAsyncMode(false)) << "async mode: " << false;
+ // Buffer count was out of range
+ EXPECT_EQ(BAD_VALUE, mProducer->setMaxDequeuedBufferCount(0))
+ << "bufferCount: " << 0;
+ EXPECT_EQ(BAD_VALUE, mProducer->setMaxDequeuedBufferCount(maxBuffers + 1))
+ << "bufferCount: " << maxBuffers + 1;
+
+ // Prerequisite to fail out a valid setBufferCount call
+ {
+ int dequeuedSlot = -1;
+ sp<Fence> dequeuedFence;
+
+ ASSERT_LE(OK,
+ mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
+ QUEUE_BUFFER_INPUT_ASYNC,
+ DEFAULT_WIDTH, DEFAULT_HEIGHT,
+ DEFAULT_FORMAT,
+ TEST_PRODUCER_USAGE_BITS))
+ << "slot: " << dequeuedSlot;
+ }
+
+ // Client has one or more buffers dequeued
+ EXPECT_EQ(BAD_VALUE, mProducer->setMaxDequeuedBufferCount(minBuffers))
+ << "bufferCount: " << minBuffers;
+
+ // Abandon buffer queue
+ ASSERT_OK(mConsumer->consumerDisconnect());
+
+ // Fail because the buffer queue was abandoned
+ EXPECT_EQ(NO_INIT, mProducer->setMaxDequeuedBufferCount(minBuffers))
+ << "bufferCount: " << minBuffers;
+
+}
+
+TEST_F(IGraphicBufferProducerTest, SetAsyncMode_Succeeds) {
+ ASSERT_OK(mConsumer->setMaxAcquiredBufferCount(1)) << "maxAcquire: " << 1;
+ ASSERT_OK(mProducer->setAsyncMode(true)) << "async mode: " << true;
+ ASSERT_OK(mProducer->setMaxDequeuedBufferCount(1)) << "maxDequeue: " << 1;
+
+ int dequeuedSlot = -1;
+ sp<Fence> dequeuedFence;
+ IGraphicBufferProducer::QueueBufferInput input(QUEUE_BUFFER_INPUT_TIMESTAMP,
+ QUEUE_BUFFER_INPUT_IS_AUTO_TIMESTAMP, QUEUE_BUFFER_INPUT_DATASPACE,
+ QUEUE_BUFFER_INPUT_RECT, QUEUE_BUFFER_INPUT_SCALING_MODE,
+ QUEUE_BUFFER_INPUT_TRANSFORM, true, QUEUE_BUFFER_INPUT_FENCE);
+ IGraphicBufferProducer::QueueBufferOutput output;
+ sp<GraphicBuffer> dequeuedBuffer;
+
+ // Should now be able to queue/dequeue as many buffers as we want without
+ // blocking
+ for (int i = 0; i < 5; ++i) {
+ ASSERT_LE(OK, mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
+ true, DEFAULT_WIDTH, DEFAULT_HEIGHT,
+ DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS)) << "slot : "
+ << dequeuedSlot;
+ ASSERT_OK(mProducer->requestBuffer(dequeuedSlot, &dequeuedBuffer));
+ ASSERT_OK(mProducer->queueBuffer(dequeuedSlot, input, &output));
+ }
+}
+
+TEST_F(IGraphicBufferProducerTest, SetAsyncMode_Fails) {
+ // Prerequisite to fail out a valid setBufferCount call
+ {
+ int dequeuedSlot = -1;
+ sp<Fence> dequeuedFence;
+
+ ASSERT_LE(OK, mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
+ QUEUE_BUFFER_INPUT_ASYNC, DEFAULT_WIDTH, DEFAULT_HEIGHT,
+ DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS)) << "slot: "
+ << dequeuedSlot;
+ }
+
+ // Client has one or more buffers dequeued
+ EXPECT_EQ(BAD_VALUE, mProducer->setAsyncMode(false)) << "asyncMode: "
+ << false;
+
+ // Abandon buffer queue
+ ASSERT_OK(mConsumer->consumerDisconnect());
+
+ // Fail because the buffer queue was abandoned
+ EXPECT_EQ(NO_INIT, mProducer->setAsyncMode(false)) << "asyncMode: "
+ << false;
+}
+
} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index ba4c198..49e8bc0 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -286,6 +286,15 @@
return mSource[SOURCE_SINK]->setBufferCount(bufferCount);
}
+status_t VirtualDisplaySurface::setMaxDequeuedBufferCount(
+ int maxDequeuedBuffers) {
+ return mSource[SOURCE_SINK]->setMaxDequeuedBufferCount(maxDequeuedBuffers);
+}
+
+status_t VirtualDisplaySurface::setAsyncMode(bool async) {
+ return mSource[SOURCE_SINK]->setAsyncMode(async);
+}
+
status_t VirtualDisplaySurface::dequeueBuffer(Source source,
PixelFormat format, uint32_t usage, int* sslot, sp<Fence>* fence) {
LOG_FATAL_IF(mDisplayId < 0, "mDisplayId=%d but should not be < 0.", mDisplayId);
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 6298751..c315562 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -99,6 +99,8 @@
//
virtual status_t requestBuffer(int pslot, sp<GraphicBuffer>* outBuf);
virtual status_t setBufferCount(int bufferCount);
+ virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers);
+ virtual status_t setAsyncMode(bool async);
virtual status_t dequeueBuffer(int* pslot, sp<Fence>* fence, bool async,
uint32_t w, uint32_t h, PixelFormat format, uint32_t usage);
virtual status_t detachBuffer(int slot);
diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp
index fb7af97..b537d67 100644
--- a/services/surfaceflinger/MonitoredProducer.cpp
+++ b/services/surfaceflinger/MonitoredProducer.cpp
@@ -60,6 +60,15 @@
return mProducer->setBufferCount(bufferCount);
}
+status_t MonitoredProducer::setMaxDequeuedBufferCount(
+ int maxDequeuedBuffers) {
+ return mProducer->setMaxDequeuedBufferCount(maxDequeuedBuffers);
+}
+
+status_t MonitoredProducer::setAsyncMode(bool async) {
+ return mProducer->setAsyncMode(async);
+}
+
status_t MonitoredProducer::dequeueBuffer(int* slot, sp<Fence>* fence,
bool async, uint32_t w, uint32_t h, PixelFormat format, uint32_t usage) {
return mProducer->dequeueBuffer(slot, fence, async, w, h, format, usage);
diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h
index da95766..9800f31 100644
--- a/services/surfaceflinger/MonitoredProducer.h
+++ b/services/surfaceflinger/MonitoredProducer.h
@@ -36,6 +36,8 @@
// From IGraphicBufferProducer
virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf);
virtual status_t setBufferCount(int bufferCount);
+ virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers);
+ virtual status_t setAsyncMode(bool async);
virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, bool async,
uint32_t w, uint32_t h, PixelFormat format, uint32_t usage);
virtual status_t detachBuffer(int slot);