blast: add desired present time

Add the option to set a desiredPresentTime for a transaction. This
lets the framework know approximately when the transaction should
be presented.

Test: Transaction_test
Bug: 80477568

Change-Id: Ic25617fb93f2c249b3b3c7a8f90f72ec358938f0
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index b74b901..9b2a6fc 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -657,6 +657,9 @@
     Mutex::Autolock lock(mMutex);
     nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
     nsecs_t phase = mReferenceTime + mPhase;
+    if (mPeriod == 0) {
+        return 0;
+    }
     return (((now - phase) / mPeriod) + periodOffset + 1) * mPeriod + phase;
 }
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index dc02666..c0059d5 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3498,8 +3498,8 @@
         auto& [applyToken, transactionQueue] = *it;
 
         while (!transactionQueue.empty()) {
-            const auto& [states, displays, flags] = transactionQueue.front();
-            if (composerStateContainsUnsignaledFences(states)) {
+            const auto& [states, displays, flags, desiredPresentTime] = transactionQueue.front();
+            if (!transactionIsReadyToBeApplied(desiredPresentTime, states)) {
                 break;
             }
             applyTransactionState(states, displays, flags, mInputWindowCommands);
@@ -3533,23 +3533,33 @@
     return false;
 }
 
-bool SurfaceFlinger::composerStateContainsUnsignaledFences(const Vector<ComposerState>& states) {
+bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime,
+                                                   const Vector<ComposerState>& states) {
+    const nsecs_t expectedPresentTime = mPrimaryDispSync->expectedPresentTime();
+    // Do not present if the desiredPresentTime has not passed unless it is more than one second
+    // in the future. We ignore timestamps more than 1 second in the future for stability reasons.
+    if (desiredPresentTime >= 0 && desiredPresentTime >= expectedPresentTime &&
+        desiredPresentTime < expectedPresentTime + s2ns(1)) {
+        return false;
+    }
+
     for (const ComposerState& state : states) {
         const layer_state_t& s = state.state;
         if (!(s.what & layer_state_t::eAcquireFenceChanged)) {
             continue;
         }
         if (s.acquireFence && s.acquireFence->getStatus() == Fence::Status::Unsignaled) {
-            return true;
+            return false;
         }
     }
-    return false;
+    return true;
 }
 
 void SurfaceFlinger::setTransactionState(const Vector<ComposerState>& states,
                                          const Vector<DisplayState>& displays, uint32_t flags,
                                          const sp<IBinder>& applyToken,
-                                         const InputWindowCommands& inputWindowCommands) {
+                                         const InputWindowCommands& inputWindowCommands,
+                                         int64_t desiredPresentTime) {
     ATRACE_CALL();
     Mutex::Autolock _l(mStateLock);
 
@@ -3559,8 +3569,8 @@
 
     // If its TransactionQueue already has a pending TransactionState or if it is pending
     if (mTransactionQueues.find(applyToken) != mTransactionQueues.end() ||
-        composerStateContainsUnsignaledFences(states)) {
-        mTransactionQueues[applyToken].emplace(states, displays, flags);
+        !transactionIsReadyToBeApplied(desiredPresentTime, states)) {
+        mTransactionQueues[applyToken].emplace(states, displays, flags, desiredPresentTime);
         setTransactionFlags(eTransactionNeeded);
         return;
     }
@@ -4147,7 +4157,7 @@
     d.width = 0;
     d.height = 0;
     displays.add(d);
-    setTransactionState(state, displays, 0, nullptr, mInputWindowCommands);
+    setTransactionState(state, displays, 0, nullptr, mInputWindowCommands, -1);
 
     const auto display = getDisplayDevice(displayToken);
     if (!display) return;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index c92874b..e5b3570 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -412,7 +412,8 @@
     void setTransactionState(const Vector<ComposerState>& state,
                              const Vector<DisplayState>& displays, uint32_t flags,
                              const sp<IBinder>& applyToken,
-                             const InputWindowCommands& inputWindowCommands) override;
+                             const InputWindowCommands& inputWindowCommands,
+                             int64_t desiredPresentTime) override;
     void bootFinished() override;
     bool authenticateSurfaceTexture(
             const sp<IGraphicBufferProducer>& bufferProducer) const override;
@@ -537,7 +538,8 @@
     void latchAndReleaseBuffer(const sp<Layer>& layer);
     void commitTransaction();
     bool containsAnyInvalidClientState(const Vector<ComposerState>& states);
-    bool composerStateContainsUnsignaledFences(const Vector<ComposerState>& states);
+    bool transactionIsReadyToBeApplied(int64_t desiredPresentTime,
+                                       const Vector<ComposerState>& states);
     uint32_t setClientStateLocked(const ComposerState& composerState);
     uint32_t setDisplayStateLocked(const DisplayState& s);
     uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands);
@@ -982,12 +984,17 @@
     };
     struct TransactionState {
         TransactionState(const Vector<ComposerState>& composerStates,
-                         const Vector<DisplayState>& displayStates, uint32_t transactionFlags)
-              : states(composerStates), displays(displayStates), flags(transactionFlags) {}
+                         const Vector<DisplayState>& displayStates, uint32_t transactionFlags,
+                         int64_t desiredPresentTime)
+              : states(composerStates),
+                displays(displayStates),
+                flags(transactionFlags),
+                time(desiredPresentTime) {}
 
         Vector<ComposerState> states;
         Vector<DisplayState> displays;
         uint32_t flags;
+        int64_t time;
     };
     std::unordered_map<sp<IBinder>, std::queue<TransactionState>, IBinderHash> mTransactionQueues;
 
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 9339761..0ad2711 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -2568,11 +2568,23 @@
         }
     }
 
+    void addExpectedPresentTime(nsecs_t expectedPresentTime) {
+        mExpectedPresentTime = expectedPresentTime;
+    }
+
     void verifyTransactionStats(const TransactionStats& transactionStats) const {
         const auto& [latchTime, presentFence, surfaceStats] = transactionStats;
         if (mTransactionResult == ExpectedResult::Transaction::PRESENTED) {
             ASSERT_GE(latchTime, 0) << "bad latch time";
             ASSERT_NE(presentFence, nullptr);
+            if (mExpectedPresentTime >= 0) {
+                ASSERT_EQ(presentFence->wait(3000), NO_ERROR);
+                ASSERT_GE(presentFence->getSignalTime(), mExpectedPresentTime - nsecs_t(5 * 1e6));
+                // if the panel is running at 30 hz, at the worst case, our expected time just
+                // misses vsync and we have to wait another 33.3ms
+                ASSERT_LE(presentFence->getSignalTime(),
+                          mExpectedPresentTime + nsecs_t(66.666666 * 1e6));
+            }
         } else {
             ASSERT_EQ(presentFence, nullptr) << "transaction shouldn't have been presented";
             ASSERT_EQ(latchTime, -1) << "unpresented transactions shouldn't be latched";
@@ -2623,6 +2635,7 @@
         }
     };
     ExpectedResult::Transaction mTransactionResult = ExpectedResult::Transaction::NOT_PRESENTED;
+    nsecs_t mExpectedPresentTime = -1;
     std::unordered_map<sp<IBinder>, ExpectedSurfaceResult, IBinderHash> mExpectedSurfaceResults;
 };
 
@@ -3272,6 +3285,143 @@
     EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true));
 }
 
+TEST_F(LayerCallbackTest, DesiredPresentTime) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+    Transaction transaction;
+    CallbackHelper callback;
+    int err = fillTransaction(transaction, &callback, layer);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+
+    // Try to present 100ms in the future
+    nsecs_t time = systemTime() + (100 * 1e6);
+
+    transaction.setDesiredPresentTime(time);
+    transaction.apply();
+
+    ExpectedResult expected;
+    expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+    expected.addExpectedPresentTime(time);
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, DesiredPresentTime_Multiple) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+    Transaction transaction;
+    CallbackHelper callback1;
+    int err = fillTransaction(transaction, &callback1, layer);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+
+    // Try to present 100ms in the future
+    nsecs_t time = systemTime() + (100 * 1e6);
+
+    transaction.setDesiredPresentTime(time);
+    transaction.apply();
+
+    ExpectedResult expected1;
+    expected1.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+    expected1.addExpectedPresentTime(time);
+
+    CallbackHelper callback2;
+    err = fillTransaction(transaction, &callback2, layer);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+
+    // Try to present 33ms after the first frame
+    time += (33.3 * 1e6);
+
+    transaction.setDesiredPresentTime(time);
+    transaction.apply();
+
+    ExpectedResult expected2;
+    expected2.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+                         ExpectedResult::Buffer::ACQUIRED,
+                         ExpectedResult::PreviousBuffer::RELEASED);
+    expected2.addExpectedPresentTime(time);
+
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected1, true));
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected2, true));
+}
+
+TEST_F(LayerCallbackTest, DesiredPresentTime_OutOfOrder) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+    Transaction transaction;
+    CallbackHelper callback1;
+    int err = fillTransaction(transaction, &callback1, layer);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+
+    // Try to present 100ms in the future
+    nsecs_t time = systemTime() + (100 * 1e6);
+
+    transaction.setDesiredPresentTime(time);
+    transaction.apply();
+
+    ExpectedResult expected1;
+    expected1.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+    expected1.addExpectedPresentTime(time);
+
+    CallbackHelper callback2;
+    err = fillTransaction(transaction, &callback2, layer);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+
+    // Try to present 33ms before the previous frame
+    time -= (33.3 * 1e6);
+
+    transaction.setDesiredPresentTime(time);
+    transaction.apply();
+
+    ExpectedResult expected2;
+    expected2.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+                         ExpectedResult::Buffer::ACQUIRED,
+                         ExpectedResult::PreviousBuffer::RELEASED);
+
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected1, true));
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected2, true));
+}
+
+TEST_F(LayerCallbackTest, DesiredPresentTime_Past) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+    Transaction transaction;
+    CallbackHelper callback;
+    int err = fillTransaction(transaction, &callback, layer);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+
+    // Try to present 100ms in the past
+    nsecs_t time = systemTime() - (100 * 1e6);
+
+    transaction.setDesiredPresentTime(time);
+    transaction.apply();
+
+    ExpectedResult expected;
+    expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+    expected.addExpectedPresentTime(systemTime());
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
 class LayerUpdateTest : public LayerTransactionTest {
 protected:
     virtual void SetUp() {