Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

[fuchsia] Set presentation end times based on Flatland feedback #38549

Merged
merged 1 commit into from
Dec 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 27 additions & 9 deletions shell/platform/fuchsia/flutter/flatland_connection.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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_));
Expand Down Expand Up @@ -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;
}
Expand All @@ -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<std::mutex> lock(threadsafe_state_.mutex_);
callback(now, GetNextPresentationTime(
now, threadsafe_state_.next_presentation_time_));
}

void FlatlandConnection::OnError(
Expand All @@ -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<std::mutex> 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;
}
}
}
Expand Down
7 changes: 5 additions & 2 deletions shell/platform/fuchsia/flutter/flatland_connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand All @@ -22,9 +23,10 @@ namespace flutter_runner {
using on_frame_presented_event =
std::function<void(fuchsia::scenic::scheduling::FramePresentedInfo)>;

// 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.
Expand Down Expand Up @@ -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<zx::event> acquire_fences_;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<fuchsia::scenic::scheduling::PresentationInfo>
CreateFuturePresentationInfos(int presentation_time) {
fuchsia::scenic::scheduling::PresentationInfo info_1;
info_1.set_presentation_time(presentation_time);
std::vector<fuchsia::scenic::scheduling::PresentationInfo> infos;
infos.push_back(std::move(info_1));
return infos;
}

} // namespace

class FlatlandConnectionTest : public ::testing::Test {
Expand All @@ -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));
}
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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);
Expand All @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -300,8 +300,12 @@ Matcher<std::shared_ptr<FakeTransform>> 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<fuchsia::scenic::scheduling::PresentationInfo> infos;
infos.push_back(std::move(info_1));
values.set_future_presentation_infos(std::move(infos));
return values;
}

Expand Down