Allow BlastBufferQueue to acquire an additional buffer
We want to be able to send buffers from BlastBufferQueue to the server
as soon as possible. This allows us among other things, dropping the
oldest buffer when multiple buffers with timestamps are queued up.
To support this behavior with BlastBufferQueue, we need to acquire an
additional buffer and send it to SurfaceFlinger.
This requires changing the consumer owned by BlastBufferQueue to
acquire an additional buffer. This change is safe because we will only
acquire the buffer if its not droppable, maintaining the contract
with the producer.
If the buffer is not droppable, i.e. the producer is in sync mode, once
the buffer has been queued, the buffer is owned by the queue until it
is released or acquired by the consumer. By acquiring an additional
buffer, we transfer the ownership to the consumer earlier. The server
has more info to make decisions faster. The producer still has access
the same number of buffers and is unaffected.
If the producer is in async mode, then this buffer may be released by
the producer when trying to queue a buffer. So we check if the buffer is
droppable, and we do not acquire the extra buffer in this scenario.
Test: atest BlastBufferQueueTests android.media.cts.PresentationSyncTest
Bug: b/176507654, b/176967609
Change-Id: I494a9edcbea0b1c297ee75df2b840d8328e59eca
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 0a3d44d..f9b152c 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -248,7 +248,7 @@
mPendingReleaseItem.item = std::move(mSubmitted.front());
mSubmitted.pop();
- processNextBufferLocked(false);
+ processNextBufferLocked(false /* useNextTransaction */);
currFrameNumber = mPendingReleaseItem.item.mFrameNumber;
if (mTransactionCompleteCallback && mTransactionCompleteFrameNumber == currFrameNumber) {
@@ -269,9 +269,10 @@
ATRACE_CALL();
BQA_LOGV("processNextBufferLocked useNextTransaction=%s", toString(useNextTransaction));
- // Wait to acquire a buffer if there are no frames available or we have acquired the max
- // number of buffers.
- if (mNumFrameAvailable == 0 || maxBuffersAcquired()) {
+ // If the next transaction is set, we want to guarantee the our acquire will not fail, so don't
+ // include the extra buffer when checking if we can acquire the next buffer.
+ const bool includeExtraAcquire = !useNextTransaction;
+ if (mNumFrameAvailable == 0 || maxBuffersAcquired(includeExtraAcquire)) {
BQA_LOGV("processNextBufferLocked waiting for frame available or callback");
mCallbackCV.notify_all();
return;
@@ -295,7 +296,10 @@
status_t status =
mBufferItemConsumer->acquireBuffer(&bufferItem, 0 /* expectedPresent */, false);
- if (status != OK) {
+ if (status == BufferQueue::NO_BUFFER_AVAILABLE) {
+ BQA_LOGV("Failed to acquire a buffer, err=NO_BUFFER_AVAILABLE");
+ return;
+ } else if (status != OK) {
BQA_LOGE("Failed to acquire a buffer, err=%s", statusToString(status).c_str());
return;
}
@@ -414,7 +418,7 @@
item.mFrameNumber, toString(nextTransactionSet), toString(mFlushShadowQueue));
if (nextTransactionSet || mFlushShadowQueue) {
- while (mNumFrameAvailable > 0 || maxBuffersAcquired()) {
+ while (mNumFrameAvailable > 0 || maxBuffersAcquired(false /* includeExtraAcquire */)) {
BQA_LOGV("waiting in onFrameAvailable...");
mCallbackCV.wait(_lock);
}
@@ -422,7 +426,7 @@
mFlushShadowQueue = false;
// add to shadow queue
mNumFrameAvailable++;
- processNextBufferLocked(true);
+ processNextBufferLocked(nextTransactionSet /* useNextTransaction */);
}
void BLASTBufferQueue::onFrameReplaced(const BufferItem& item) {
@@ -482,9 +486,12 @@
// Check if we have acquired the maximum number of buffers.
// As a special case, we wait for the first callback before acquiring the second buffer so we
// can ensure the first buffer is presented if multiple buffers are queued in succession.
-bool BLASTBufferQueue::maxBuffersAcquired() const {
- return mNumAcquired == MAX_ACQUIRED_BUFFERS + 1 ||
- (!mInitialCallbackReceived && mNumAcquired == 1);
+// Consumer can acquire an additional buffer if that buffer is not droppable. Set
+// includeExtraAcquire is true to include this buffer to the count. Since this depends on the state
+// of the buffer, the next acquire may return with NO_BUFFER_AVAILABLE.
+bool BLASTBufferQueue::maxBuffersAcquired(bool includeExtraAcquire) const {
+ int maxAcquiredBuffers = MAX_ACQUIRED_BUFFERS + (includeExtraAcquire ? 2 : 1);
+ return mNumAcquired == maxAcquiredBuffers || (!mInitialCallbackReceived && mNumAcquired == 1);
}
class BBQSurface : public Surface {
@@ -654,7 +661,8 @@
LOG_ALWAYS_FATAL_IF(producer == nullptr,
"BLASTBufferQueue: failed to create BBQBufferQueueProducer");
- sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core));
+ sp<BufferQueueConsumer> consumer(new BufferQueueConsumer(core));
+ consumer->setAllowExtraAcquire(true);
LOG_ALWAYS_FATAL_IF(consumer == nullptr,
"BLASTBufferQueue: failed to create BufferQueueConsumer");