Add ability to process buffers into the same syncTransaction
In a normal sync case, we send the syncTransaction and then clear it as
soon as a buffer is acquired and placed in the transaction. However, in
some cases, we want to continue processing buffers into the sync
transaction until we get the signal to stop. This is for cases when we
don't have a clear signal which buffer wants to be synced, but know when
it's done waiting for the correct buffer.
This also adds a way to retrieve and clear the buffer from the
transaction to allow BBQ to release the buffer when it knows it's ready
to acquire a new buffer. This speeds up the process so BBQ doesn't need
to wait for the asynchronous callback to release the previous buffer.
This new machanism can be used to synchronize SurfaceViews because it
knows when something has been changed and to wait until the app has
notified that it's drawn. Once it's notified, we can stop processing
frames into the sync transaction and allow the transaction to be applied
with the main window.
Bug: 200284684
Test: BLASTBufferQueueTest
Change-Id: Ibdb524270de368033cf8835f0c305e8a5756ff6e
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index 194757f..48b8621 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -109,8 +109,8 @@
mBlastBufferQueueAdapter->update(sc, width, height, PIXEL_FORMAT_RGBA_8888);
}
- void setSyncTransaction(Transaction* sync) {
- mBlastBufferQueueAdapter->setSyncTransaction(sync);
+ void setSyncTransaction(Transaction* next, bool acquireSingleBuffer = true) {
+ mBlastBufferQueueAdapter->setSyncTransaction(next, acquireSingleBuffer);
}
int getWidth() { return mBlastBufferQueueAdapter->mSize.width; }
@@ -143,6 +143,11 @@
mBlastBufferQueueAdapter->waitForCallback(frameNumber);
}
+ void validateNumFramesSubmitted(int64_t numFramesSubmitted) {
+ std::unique_lock lock{mBlastBufferQueueAdapter->mMutex};
+ ASSERT_EQ(numFramesSubmitted, mBlastBufferQueueAdapter->mSubmitted.size());
+ }
+
private:
sp<TestBLASTBufferQueue> mBlastBufferQueueAdapter;
};
@@ -298,7 +303,7 @@
auto ret = igbp->dequeueBuffer(&slot, &fence, mDisplayWidth, mDisplayHeight,
PIXEL_FORMAT_RGBA_8888, GRALLOC_USAGE_SW_WRITE_OFTEN,
nullptr, nullptr);
- ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret);
+ ASSERT_TRUE(ret == IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION || ret == NO_ERROR);
ASSERT_EQ(OK, igbp->requestBuffer(slot, &buf));
uint32_t* bufData;
@@ -818,7 +823,7 @@
CallbackData callbackData;
transactionCallback.getCallbackData(&callbackData);
- // capture screen and verify that it is red
+ // capture screen and verify that it is green
ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
ASSERT_NO_FATAL_FAILURE(
checkScreenCapture(0, 255, 0, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
@@ -1025,6 +1030,45 @@
checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
}
+TEST_F(BLASTBufferQueueTest, SetSyncTransactionAcquireMultipleBuffers) {
+ BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+
+ sp<IGraphicBufferProducer> igbProducer;
+ setUpProducer(adapter, igbProducer);
+
+ Transaction next;
+ adapter.setSyncTransaction(&next, false);
+ queueBuffer(igbProducer, 0, 255, 0, 0);
+ queueBuffer(igbProducer, 0, 0, 255, 0);
+ // There should only be one frame submitted since the first frame will be released.
+ adapter.validateNumFramesSubmitted(1);
+ adapter.setSyncTransaction(nullptr);
+
+ // queue non sync buffer, so this one should get blocked
+ // Add a present delay to allow the first screenshot to get taken.
+ nsecs_t presentTimeDelay = std::chrono::nanoseconds(500ms).count();
+ queueBuffer(igbProducer, 255, 0, 0, presentTimeDelay);
+
+ CallbackHelper transactionCallback;
+ next.addTransactionCompletedCallback(transactionCallback.function,
+ transactionCallback.getContext())
+ .apply();
+
+ CallbackData callbackData;
+ transactionCallback.getCallbackData(&callbackData);
+
+ // capture screen and verify that it is blue
+ ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+ ASSERT_NO_FATAL_FAILURE(
+ checkScreenCapture(0, 0, 255, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
+
+ mProducerListener->waitOnNumberReleased(2);
+ // capture screen and verify that it is red
+ ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+ ASSERT_NO_FATAL_FAILURE(
+ checkScreenCapture(255, 0, 0, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
+}
+
class TestProducerListener : public BnProducerListener {
public:
sp<IGraphicBufferProducer> mIgbp;