Skip to content

Commit

Permalink
VSyncWaiter on Fuchsia will defer firing until frame start time (#29287)
Browse files Browse the repository at this point in the history
* VSyncWaiter on Fuchsia will defer firing until frame start time

The common vsync waiter implementation expects this invariant to be
held.

* Add a test for vsync_waiter
  • Loading branch information
iskakaushik authored Oct 21, 2021
1 parent 731431d commit f555769
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 8 deletions.
1 change: 1 addition & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -1498,6 +1498,7 @@ FILE: ../../../flutter/shell/platform/fuchsia/flutter/task_runner_adapter.h
FILE: ../../../flutter/shell/platform/fuchsia/flutter/unique_fdio_ns.h
FILE: ../../../flutter/shell/platform/fuchsia/flutter/vsync_waiter.cc
FILE: ../../../flutter/shell/platform/fuchsia/flutter/vsync_waiter.h
FILE: ../../../flutter/shell/platform/fuchsia/flutter/vsync_waiter_unittest.cc
FILE: ../../../flutter/shell/platform/fuchsia/flutter/vulkan_surface.cc
FILE: ../../../flutter/shell/platform/fuchsia/flutter/vulkan_surface.h
FILE: ../../../flutter/shell/platform/fuchsia/flutter/vulkan_surface_pool.cc
Expand Down
1 change: 1 addition & 0 deletions shell/platform/fuchsia/flutter/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,7 @@ executable("flutter_runner_unittests") {
"tests/gfx_session_connection_unittests.cc",
"tests/pointer_event_utility.cc",
"tests/pointer_event_utility.h",
"vsync_waiter_unittest.cc",
]

# This is needed for //third_party/googletest for linking zircon symbols.
Expand Down
18 changes: 13 additions & 5 deletions shell/platform/fuchsia/flutter/vsync_waiter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,27 @@ VsyncWaiter::VsyncWaiter(AwaitVsyncCallback await_vsync_callback,
weak_factory_(this) {
fire_callback_callback_ = [this](fml::TimePoint frame_start,
fml::TimePoint frame_end) {
// Note: It is VERY important to set |pause_secondary_tasks| to false, else
// Animator will almost immediately crash on Fuchsia.
// FML_LOG(INFO) << "CRASH:: VsyncWaiter about to FireCallback";
FireCallback(frame_start, frame_end, /*pause_secondary_tasks=*/false);
task_runners_.GetUITaskRunner()->PostTaskForTime(
[frame_start, frame_end, weak_this = weak_ui_]() {
if (weak_this) {
// Note: It is VERY important to set |pause_secondary_tasks| to
// false, else Animator will almost immediately crash on Fuchsia.
// FML_LOG(INFO) << "CRASH:: VsyncWaiter about to FireCallback";
weak_this->FireCallback(frame_start, frame_end,
/*pause_secondary_tasks*/ false);
}
},
frame_start);
};

// Generate a WeakPtrFactory for use with the UI thread. This does not need
// to wait on a latch because we only ever use the WeakPtrFactory on the UI
// thread so we have ordering guarantees (see ::AwaitVSync())
fml::TaskRunner::RunNowOrPostTask(
task_runners_.GetUITaskRunner(), fml::MakeCopyable([this]() mutable {
this->weak_factory_ui_ =
weak_factory_ui_ =
std::make_unique<fml::WeakPtrFactory<VsyncWaiter>>(this);
weak_ui_ = weak_factory_ui_->GetWeakPtr();
}));
}

Expand Down
7 changes: 4 additions & 3 deletions shell/platform/fuchsia/flutter/vsync_waiter.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef FLUTTER_SHELL_PLATFORM_FUCHSIA_VSYNC_WAITER_H_
#define FLUTTER_SHELL_PLATFORM_FUCHSIA_VSYNC_WAITER_H_
#ifndef FLUTTER_SHELL_PLATFORM_FUCHSIA_FLUTTER_VSYNC_WAITER_H_
#define FLUTTER_SHELL_PLATFORM_FUCHSIA_FLUTTER_VSYNC_WAITER_H_

#include <lib/async/cpp/wait.h>

Expand Down Expand Up @@ -46,6 +46,7 @@ class VsyncWaiter final : public flutter::VsyncWaiter {
AwaitVsyncForSecondaryCallbackCallback
await_vsync_for_secondary_callback_callback_;

fml::WeakPtr<VsyncWaiter> weak_ui_;
std::unique_ptr<fml::WeakPtrFactory<VsyncWaiter>> weak_factory_ui_;
fml::WeakPtrFactory<VsyncWaiter> weak_factory_;

Expand All @@ -54,4 +55,4 @@ class VsyncWaiter final : public flutter::VsyncWaiter {

} // namespace flutter_runner

#endif // FLUTTER_SHELL_PLATFORM_FUCHSIA_VSYNC_WAITER_H_
#endif // FLUTTER_SHELL_PLATFORM_FUCHSIA_FLUTTER_VSYNC_WAITER_H_
63 changes: 63 additions & 0 deletions shell/platform/fuchsia/flutter/vsync_waiter_unittest.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <gtest/gtest.h>

#include <string>

#include "flutter/fml/task_runner.h"
#include "flutter/shell/common/thread_host.h"
#include "fml/make_copyable.h"
#include "fml/message_loop.h"
#include "fml/synchronization/waitable_event.h"
#include "fml/time/time_delta.h"
#include "fml/time/time_point.h"
#include "vsync_waiter.h"

namespace flutter_runner {

TEST(VSyncWaiterFuchsia, FrameScheduledForStartTime) {
using flutter::ThreadHost;
std::string prefix = "vsync_waiter_test";

fml::MessageLoop::EnsureInitializedForCurrentThread();
auto platform_task_runner = fml::MessageLoop::GetCurrent().GetTaskRunner();

ThreadHost thread_host =
ThreadHost(prefix, flutter::ThreadHost::Type::RASTER |
flutter::ThreadHost::Type::UI |
flutter::ThreadHost::Type::IO);
const flutter::TaskRunners task_runners(
prefix, // Dart thread labels
platform_task_runner, // platform
thread_host.raster_thread->GetTaskRunner(), // raster
thread_host.ui_thread->GetTaskRunner(), // ui
thread_host.io_thread->GetTaskRunner() // io
);

// await vsync will invoke the callback right away, but vsync waiter will post
// the task for frame_start time.
VsyncWaiter vsync_waiter(
[](FireCallbackCallback callback) {
const auto now = fml::TimePoint::Now();
const auto frame_start = now + fml::TimeDelta::FromMilliseconds(20);
const auto frame_end = now + fml::TimeDelta::FromMilliseconds(36);
callback(frame_start, frame_end);
},
/*secondary callback*/ nullptr, task_runners);

fml::AutoResetWaitableEvent latch;
task_runners.GetUITaskRunner()->PostTask([&]() {
vsync_waiter.AsyncWaitForVsync(
[&](std::unique_ptr<flutter::FrameTimingsRecorder> recorder) {
const auto now = fml::TimePoint::Now();
EXPECT_GT(now, recorder->GetVsyncStartTime());
latch.Signal();
});
});

latch.Wait();
}

} // namespace flutter_runner

0 comments on commit f555769

Please sign in to comment.