diff --git a/shell/platform/fuchsia/flutter/flatland_connection.cc b/shell/platform/fuchsia/flutter/flatland_connection.cc index ec7846a5ed1c0..710dd0bd2e7c0 100644 --- a/shell/platform/fuchsia/flutter/flatland_connection.cc +++ b/shell/platform/fuchsia/flutter/flatland_connection.cc @@ -10,6 +10,17 @@ namespace flutter_runner { +namespace { + +fml::TimePoint GetNextPresentationTime(fml::TimePoint now, + fml::TimePoint next_presentation_time) { + return now > next_presentation_time + ? now + flutter_runner::kDefaultFlatlandPresentationInterval + : next_presentation_time; +} + +} // namespace + FlatlandConnection::FlatlandConnection( std::string debug_label, fuchsia::ui::composition::FlatlandHandle flatland, @@ -54,7 +65,6 @@ void FlatlandConnection::DoPresent() { --present_credits_; fuchsia::ui::composition::PresentArgs present_args; - // TODO(fxbug.dev/114588): compute a better presentation time; present_args.set_requested_presentation_time(0); present_args.set_acquire_fences(std::move(acquire_fences_)); present_args.set_release_fences(std::move(previous_present_release_fences_)); @@ -85,10 +95,10 @@ void FlatlandConnection::AwaitVsync(FireCallbackCallback callback) { threadsafe_state_.fire_callback_ = callback; if (threadsafe_state_.fire_callback_pending_) { - fml::TimePoint now = fml::TimePoint::Now(); - // TODO(fxbug.dev/114588): Calculate correct frame times. + const fml::TimePoint now = fml::TimePoint::Now(); threadsafe_state_.fire_callback_( - now, now + kDefaultFlatlandPresentationInterval); + now, GetNextPresentationTime( + now, threadsafe_state_.next_presentation_time_)); threadsafe_state_.fire_callback_ = nullptr; threadsafe_state_.fire_callback_pending_ = false; } @@ -97,8 +107,10 @@ void FlatlandConnection::AwaitVsync(FireCallbackCallback callback) { // This method is called from the UI thread. void FlatlandConnection::AwaitVsyncForSecondaryCallback( FireCallbackCallback callback) { - fml::TimePoint now = fml::TimePoint::Now(); - callback(now, now); + const fml::TimePoint now = fml::TimePoint::Now(); + std::scoped_lock lock(threadsafe_state_.mutex_); + callback(now, GetNextPresentationTime( + now, threadsafe_state_.next_presentation_time_)); } void FlatlandConnection::OnError( @@ -118,15 +130,21 @@ void FlatlandConnection::OnNextFrameBegin( } if (present_credits_ > 0) { + FML_CHECK(values.has_future_presentation_infos() && + !values.future_presentation_infos().empty()); + const auto next_presentation_time = + fml::TimePoint::FromEpochDelta(fml::TimeDelta::FromNanoseconds( + values.future_presentation_infos().front().presentation_time())); + std::scoped_lock lock(threadsafe_state_.mutex_); if (threadsafe_state_.fire_callback_) { - fml::TimePoint now = fml::TimePoint::Now(); - // TODO(fxbug.dev/114588): Calculate correct frame times. threadsafe_state_.fire_callback_( - now, now + kDefaultFlatlandPresentationInterval); + /*frame_start=*/fml::TimePoint::Now(), + /*frame_target=*/next_presentation_time); threadsafe_state_.fire_callback_ = nullptr; } else { threadsafe_state_.fire_callback_pending_ = true; + threadsafe_state_.next_presentation_time_ = next_presentation_time; } } } diff --git a/shell/platform/fuchsia/flutter/flatland_connection.h b/shell/platform/fuchsia/flutter/flatland_connection.h index 72940ace243cc..46efd45483d42 100644 --- a/shell/platform/fuchsia/flutter/flatland_connection.h +++ b/shell/platform/fuchsia/flutter/flatland_connection.h @@ -10,6 +10,7 @@ #include "flutter/fml/closure.h" #include "flutter/fml/macros.h" #include "flutter/fml/time/time_delta.h" +#include "flutter/fml/time/time_point.h" #include "vsync_waiter.h" @@ -22,9 +23,10 @@ namespace flutter_runner { using on_frame_presented_event = std::function; -// Set to zero for now for maximum simplicity until we have real values. +// 2ms interval to target vsync is only used until Scenic sends presentation +// feedback, or when we run out of present credits. static constexpr fml::TimeDelta kDefaultFlatlandPresentationInterval = - fml::TimeDelta::FromSecondsF(0); + fml::TimeDelta::FromMilliseconds(2); // The component residing on the raster thread that is responsible for // maintaining the Flatland instance connection and presenting updates. @@ -87,6 +89,7 @@ class FlatlandConnection final { FireCallbackCallback fire_callback_; bool fire_callback_pending_ = false; bool first_present_called_ = false; + fml::TimePoint next_presentation_time_; } threadsafe_state_; std::vector acquire_fences_; diff --git a/shell/platform/fuchsia/flutter/tests/flatland_connection_unittests.cc b/shell/platform/fuchsia/flutter/tests/flatland_connection_unittests.cc index 5da43cc8e1d5b..7aab5477182f7 100644 --- a/shell/platform/fuchsia/flutter/tests/flatland_connection_unittests.cc +++ b/shell/platform/fuchsia/flutter/tests/flatland_connection_unittests.cc @@ -40,6 +40,26 @@ void AwaitVsyncChecked(FlatlandConnection& flatland_connection, }); } +void AwaitVsyncChecked(FlatlandConnection& flatland_connection, + bool& condition_variable, + fml::TimePoint expected_frame_end) { + flatland_connection.AwaitVsync( + [&condition_variable, expected_frame_end = std::move(expected_frame_end)]( + fml::TimePoint frame_start, fml::TimePoint frame_end) { + EXPECT_EQ(frame_end, expected_frame_end); + condition_variable = true; + }); +} + +std::vector +CreateFuturePresentationInfos(int presentation_time) { + fuchsia::scenic::scheduling::PresentationInfo info_1; + info_1.set_presentation_time(presentation_time); + std::vector infos; + infos.push_back(std::move(info_1)); + return infos; +} + } // namespace class FlatlandConnectionTest : public ::testing::Test { @@ -61,10 +81,12 @@ class FlatlandConnectionTest : public ::testing::Test { } // Syntactic sugar for OnNextFrameBegin - void OnNextFrameBegin(int num_present_credits) { + void OnNextFrameBegin(int num_present_credits, int presentation_time = 345) { fuchsia::ui::composition::OnNextFrameBeginValues on_next_frame_begin_values; on_next_frame_begin_values.set_additional_present_credits( num_present_credits); + on_next_frame_begin_values.set_future_presentation_infos( + CreateFuturePresentationInfos(presentation_time)); fake_flatland().FireOnNextFrameBeginEvent( std::move(on_next_frame_begin_values)); } @@ -171,10 +193,14 @@ TEST_F(FlatlandConnectionTest, BasicPresent) { EXPECT_FALSE(await_vsync_fired); // Fire the `OnNextFrameBegin` event. AwaitVsync should be fired. + const int kPresentationTime = 123; AwaitVsyncChecked(flatland_connection, await_vsync_fired, - kDefaultFlatlandPresentationInterval); + fml::TimePoint::FromEpochDelta( + fml::TimeDelta::FromNanoseconds(kPresentationTime))); fuchsia::ui::composition::OnNextFrameBeginValues on_next_frame_begin_values; on_next_frame_begin_values.set_additional_present_credits(3); + on_next_frame_begin_values.set_future_presentation_infos( + CreateFuturePresentationInfos(kPresentationTime)); fake_flatland().FireOnNextFrameBeginEvent( std::move(on_next_frame_begin_values)); loop().RunUntilIdle(); @@ -275,24 +301,29 @@ TEST_F(FlatlandConnectionTest, OutOfOrderAwait) { // Set the callback with AwaitVsync, callback should not be fired await_vsync_callback_fired = false; + const int kPresentationTime1 = 567; AwaitVsyncChecked(flatland_connection, await_vsync_callback_fired, - kDefaultFlatlandPresentationInterval); + fml::TimePoint::FromEpochDelta( + fml::TimeDelta::FromNanoseconds(kPresentationTime1))); EXPECT_FALSE(await_vsync_callback_fired); - // Fire the `OnNextFrameBegin` event. AwaitVsync callback should be fired. + // Fire the `OnNextFrameBegin` event. AwaitVsync callback should be fired with + // the given presentation time. await_vsync_callback_fired = false; - OnNextFrameBegin(1); + OnNextFrameBegin(1, kPresentationTime1); loop().RunUntilIdle(); EXPECT_TRUE(await_vsync_callback_fired); // Second consecutive ONFB should not call the fire callback and should // instead set it to be pending to fire on next AwaitVsync await_vsync_callback_fired = false; - OnNextFrameBegin(1); + const int kPresentationTime2 = 678; + OnNextFrameBegin(1, kPresentationTime2); loop().RunUntilIdle(); EXPECT_FALSE(await_vsync_callback_fired); - // Now an AwaitVsync should immediately fire the pending callback + // Now an AwaitVsync should immediately fire the pending callback with the + // default presentation interval. await_vsync_callback_fired = false; AwaitVsyncChecked(flatland_connection, await_vsync_callback_fired, kDefaultFlatlandPresentationInterval); @@ -301,13 +332,15 @@ TEST_F(FlatlandConnectionTest, OutOfOrderAwait) { // With the pending callback fired, The new callback should be set for the // next OnNextFrameBegin to call await_vsync_callback_fired = false; + const int kPresentationTime3 = 789; AwaitVsyncChecked(flatland_connection, await_vsync_callback_fired, - kDefaultFlatlandPresentationInterval); + fml::TimePoint::FromEpochDelta( + fml::TimeDelta::FromNanoseconds(kPresentationTime3))); EXPECT_FALSE(await_vsync_callback_fired); // Now OnNextFrameBegin should fire the callback await_vsync_callback_fired = false; - OnNextFrameBegin(1); + OnNextFrameBegin(1, kPresentationTime3); loop().RunUntilIdle(); EXPECT_TRUE(await_vsync_callback_fired); } diff --git a/shell/platform/fuchsia/flutter/tests/flatland_external_view_embedder_unittests.cc b/shell/platform/fuchsia/flutter/tests/flatland_external_view_embedder_unittests.cc index eb9b79d46d111..57e740ed710d3 100644 --- a/shell/platform/fuchsia/flutter/tests/flatland_external_view_embedder_unittests.cc +++ b/shell/platform/fuchsia/flutter/tests/flatland_external_view_embedder_unittests.cc @@ -300,8 +300,12 @@ Matcher> IsClipTransformLayer( fuchsia::ui::composition::OnNextFrameBeginValues WithPresentCredits( uint32_t additional_present_credits) { fuchsia::ui::composition::OnNextFrameBeginValues values; - values.set_additional_present_credits(additional_present_credits); + fuchsia::scenic::scheduling::PresentationInfo info_1; + info_1.set_presentation_time(123); + std::vector infos; + infos.push_back(std::move(info_1)); + values.set_future_presentation_infos(std::move(infos)); return values; }