Merge "SurfaceFlinger: Support out of order transactions"
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 89de629..eaa47f9 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -371,7 +371,7 @@
mPendingTransactions.end());
if (applyTransaction) {
- t->apply();
+ t->setApplyToken(mApplyToken).apply();
}
BQA_LOGV("processNextBufferLocked size=%dx%d mFrameNumber=%" PRIu64
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 5570d99..97c2693 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -396,7 +396,8 @@
mContainsBuffer(other.mContainsBuffer),
mDesiredPresentTime(other.mDesiredPresentTime),
mIsAutoTimestamp(other.mIsAutoTimestamp),
- mFrameTimelineVsyncId(other.mFrameTimelineVsyncId) {
+ mFrameTimelineVsyncId(other.mFrameTimelineVsyncId),
+ mApplyToken(other.mApplyToken) {
mDisplayStates = other.mDisplayStates;
mComposerStates = other.mComposerStates;
mInputWindowCommands = other.mInputWindowCommands;
@@ -427,7 +428,8 @@
const int64_t desiredPresentTime = parcel->readInt64();
const bool isAutoTimestamp = parcel->readBool();
const int64_t frameTimelineVsyncId = parcel->readInt64();
-
+ sp<IBinder> applyToken;
+ parcel->readNullableStrongBinder(&applyToken);
size_t count = static_cast<size_t>(parcel->readUint32());
if (count > parcel->dataSize()) {
return BAD_VALUE;
@@ -505,6 +507,7 @@
mListenerCallbacks = listenerCallbacks;
mComposerStates = composerStates;
mInputWindowCommands = inputWindowCommands;
+ mApplyToken = applyToken;
return NO_ERROR;
}
@@ -532,6 +535,7 @@
parcel->writeInt64(mDesiredPresentTime);
parcel->writeBool(mIsAutoTimestamp);
parcel->writeInt64(mFrameTimelineVsyncId);
+ parcel->writeStrongBinder(mApplyToken);
parcel->writeUint32(static_cast<uint32_t>(mDisplayStates.size()));
for (auto const& displayState : mDisplayStates) {
displayState.write(*parcel);
@@ -607,6 +611,7 @@
mEarlyWakeup = mEarlyWakeup || other.mEarlyWakeup;
mExplicitEarlyWakeupStart = mExplicitEarlyWakeupStart || other.mExplicitEarlyWakeupStart;
mExplicitEarlyWakeupEnd = mExplicitEarlyWakeupEnd || other.mExplicitEarlyWakeupEnd;
+ mApplyToken = other.mApplyToken;
// When merging vsync Ids we take the oldest one
if (mFrameTimelineVsyncId != ISurfaceComposer::INVALID_VSYNC_ID &&
@@ -635,6 +640,7 @@
mDesiredPresentTime = 0;
mIsAutoTimestamp = true;
mFrameTimelineVsyncId = ISurfaceComposer::INVALID_VSYNC_ID;
+ mApplyToken = nullptr;
}
void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) {
@@ -763,7 +769,10 @@
flags |= ISurfaceComposer::eExplicitEarlyWakeupEnd;
}
- sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ sp<IBinder> applyToken = mApplyToken
+ ? mApplyToken
+ : IInterface::asBinder(TransactionCompletedListener::getIInstance());
+
sf->setTransactionState(mFrameTimelineVsyncId, composerStates, displayStates, flags, applyToken,
mInputWindowCommands, mDesiredPresentTime, mIsAutoTimestamp,
{} /*uncacheBuffer - only set in doUncacheBufferTransaction*/,
@@ -1579,6 +1588,12 @@
return *this;
}
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setApplyToken(
+ const sp<IBinder>& applyToken) {
+ mApplyToken = applyToken;
+ return *this;
+}
+
// ---------------------------------------------------------------------------
DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp<IBinder>& token) {
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index c4cdb65..1198135 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -165,6 +165,10 @@
std::function<void(int64_t)> mTransactionCompleteCallback GUARDED_BY(mMutex) = nullptr;
uint64_t mTransactionCompleteFrameNumber GUARDED_BY(mMutex){0};
+
+ // Queues up transactions using this token in SurfaceFlinger. This prevents queued up
+ // transactions from other parts of the client from blocking this transaction.
+ const sp<IBinder> mApplyToken = new BBinder();
};
} // namespace android
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 0abe72c..48bc5d5 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -388,6 +388,10 @@
// The vsync Id provided by Choreographer.getVsyncId
int64_t mFrameTimelineVsyncId = ISurfaceComposer::INVALID_VSYNC_ID;
+ // If not null, transactions will be queued up using this token otherwise a common token
+ // per process will be used.
+ sp<IBinder> mApplyToken = nullptr;
+
InputWindowCommands mInputWindowCommands;
int mStatus = NO_ERROR;
@@ -555,6 +559,11 @@
// in shared buffer mode.
Transaction& setAutoRefresh(const sp<SurfaceControl>& sc, bool autoRefresh);
+ // Queues up transactions using this token in SurfaceFlinger. By default, all transactions
+ // from a client are placed on the same queue. This can be used to prevent multiple
+ // transactions from blocking each other.
+ Transaction& setApplyToken(const sp<IBinder>& token);
+
status_t setDisplaySurface(const sp<IBinder>& token,
const sp<IGraphicBufferProducer>& bufferProducer);
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index 170ad87..d69b7c3 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -221,6 +221,32 @@
return captureResults.result;
}
+ void queueBuffer(sp<IGraphicBufferProducer> igbp, uint8_t r, uint8_t g, uint8_t b,
+ nsecs_t presentTimeDelay) {
+ int slot;
+ sp<Fence> fence;
+ sp<GraphicBuffer> buf;
+ 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_EQ(OK, igbp->requestBuffer(slot, &buf));
+
+ uint32_t* bufData;
+ buf->lock(static_cast<uint32_t>(GraphicBuffer::USAGE_SW_WRITE_OFTEN),
+ reinterpret_cast<void**>(&bufData));
+ fillBuffer(bufData, Rect(buf->getWidth(), buf->getHeight() / 2), buf->getStride(), r, g, b);
+ buf->unlock();
+
+ IGraphicBufferProducer::QueueBufferOutput qbOutput;
+ nsecs_t timestampNanos = systemTime() + presentTimeDelay;
+ IGraphicBufferProducer::QueueBufferInput input(timestampNanos, false, HAL_DATASPACE_UNKNOWN,
+ Rect(mDisplayWidth, mDisplayHeight / 2),
+ NATIVE_WINDOW_SCALING_MODE_FREEZE, 0,
+ Fence::NO_FENCE);
+ igbp->queueBuffer(slot, input, &qbOutput);
+ }
+
sp<SurfaceComposerClient> mClient;
sp<ISurfaceComposer> mComposer;
@@ -528,6 +554,41 @@
ASSERT_EQ(queuesToNativeWindow, 1);
}
+TEST_F(BLASTBufferQueueTest, OutOfOrderTransactionTest) {
+ sp<SurfaceControl> bgSurface =
+ mClient->createSurface(String8("BGTest"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceBufferState);
+ ASSERT_NE(nullptr, bgSurface.get());
+ Transaction t;
+ t.setLayerStack(bgSurface, 0)
+ .show(bgSurface)
+ .setDataspace(bgSurface, ui::Dataspace::V0_SRGB)
+ .setFrame(bgSurface, Rect(0, 0, mDisplayWidth, mDisplayHeight))
+ .setLayer(bgSurface, std::numeric_limits<int32_t>::max() - 1)
+ .apply();
+
+ BLASTBufferQueueHelper slowAdapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+ sp<IGraphicBufferProducer> slowIgbProducer;
+ setUpProducer(slowAdapter, slowIgbProducer);
+ nsecs_t presentTimeDelay = std::chrono::nanoseconds(500ms).count();
+ queueBuffer(slowIgbProducer, 0 /* r */, 0 /* g */, 0 /* b */, presentTimeDelay);
+
+ BLASTBufferQueueHelper fastAdapter(bgSurface, mDisplayWidth, mDisplayHeight);
+ sp<IGraphicBufferProducer> fastIgbProducer;
+ setUpProducer(fastAdapter, fastIgbProducer);
+ uint8_t r = 255;
+ uint8_t g = 0;
+ uint8_t b = 0;
+ queueBuffer(fastIgbProducer, r, g, b, 0 /* presentTimeDelay */);
+ fastAdapter.waitForCallbacks();
+
+ // capture screen and verify that it is red
+ ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+
+ ASSERT_NO_FATAL_FAILURE(
+ checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
+}
+
class BLASTBufferQueueTransformTest : public BLASTBufferQueueTest {
public:
void test(uint32_t tr) {