Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
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
1 change: 1 addition & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -1003,6 +1003,7 @@ FILE: ../../../flutter/shell/platform/fuchsia/flutter/vsync_recorder.cc
FILE: ../../../flutter/shell/platform/fuchsia/flutter/vsync_recorder.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_unittests.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
9 changes: 9 additions & 0 deletions shell/platform/fuchsia/flutter/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -260,15 +260,24 @@ executable("flutter_runner_unittests") {
"fuchsia_intl.h",
"fuchsia_intl_unittest.cc",
"logging.h",
"loop.cc",
"loop.h",
"platform_view.cc",
"platform_view.h",
"platform_view_unittest.cc",
"surface.cc",
"surface.h",
"task_observers.cc",
"task_observers.h",
"task_runner_adapter.cc",
"task_runner_adapter.h",
"thread.cc",
"thread.h",
"vsync_recorder.cc",
"vsync_recorder.h",
"vsync_waiter.cc",
"vsync_waiter.h",
"vsync_waiter_unittests.cc",
]

# This is needed for //third_party/googletest for linking zircon symbols.
Expand Down
31 changes: 29 additions & 2 deletions shell/platform/fuchsia/flutter/vsync_waiter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include "vsync_waiter.h"

#include <lib/async/default.h>
#include "flutter/fml/make_copyable.h"
#include "flutter/fml/synchronization/waitable_event.h"
#include "flutter/fml/trace_event.h"

#include "vsync_recorder.h"
Expand All @@ -17,7 +19,8 @@ VsyncWaiter::VsyncWaiter(std::string debug_label,
: flutter::VsyncWaiter(task_runners),
debug_label_(std::move(debug_label)),
session_wait_(session_present_handle, SessionPresentSignal),
weak_factory_(this) {
weak_factory_(this),
weak_factory_ui_(nullptr) {
auto wait_handler = [&](async_dispatcher_t* dispatcher, //
async::Wait* wait, //
zx_status_t status, //
Expand All @@ -33,11 +36,29 @@ VsyncWaiter::VsyncWaiter(std::string debug_label,
FireCallbackNow();
};

// 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_ =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@chinmaygarde should we block this call. I think its ok to not block but jut want to confirm.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is fine because of the reason mentioned in the comment.

std::make_unique<fml::WeakPtrFactory<VsyncWaiter>>(this);
}));
session_wait_.set_handler(wait_handler);
}

VsyncWaiter::~VsyncWaiter() {
session_wait_.Cancel();

fml::AutoResetWaitableEvent ui_latch;
fml::TaskRunner::RunNowOrPostTask(
task_runners_.GetUITaskRunner(),
fml::MakeCopyable(
[weak_factory_ui = std::move(weak_factory_ui_), &ui_latch]() mutable {
weak_factory_ui.reset();
ui_latch.Signal();
}));
ui_latch.Wait();
}

static fml::TimePoint SnapToNextPhase(fml::TimePoint value,
Expand All @@ -57,7 +78,13 @@ void VsyncWaiter::AwaitVSync() {
fml::TimePoint next_vsync = SnapToNextPhase(now, vsync_info.presentation_time,
vsync_info.presentation_interval);
task_runners_.GetUITaskRunner()->PostDelayedTask(
[self = weak_factory_.GetWeakPtr()] {
[& weak_factory_ui = this->weak_factory_ui_] {
if (!weak_factory_ui) {
FML_LOG(WARNING) << "WeakPtrFactory for VsyncWaiter is null, likely "
"due to the VsyncWaiter being destroyed.";
return;
}
auto self = weak_factory_ui->GetWeakPtr();
if (self) {
self->FireCallbackWhenSessionAvailable();
}
Expand Down
4 changes: 4 additions & 0 deletions shell/platform/fuchsia/flutter/vsync_waiter.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ class VsyncWaiter final : public flutter::VsyncWaiter {
async::Wait session_wait_;
fml::WeakPtrFactory<VsyncWaiter> weak_factory_;

// For accessing the VsyncWaiter via the UI thread, necessary for the callback
// for AwaitVSync()
std::unique_ptr<fml::WeakPtrFactory<VsyncWaiter>> weak_factory_ui_;

// |flutter::VsyncWaiter|
void AwaitVSync() override;

Expand Down
87 changes: 87 additions & 0 deletions shell/platform/fuchsia/flutter/vsync_waiter_unittests.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// 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 <array>

#include <gtest/gtest.h>
#include <lib/zx/event.h>
#include <zircon/syscalls.h>

#include "flutter/fml/synchronization/waitable_event.h"
#include "flutter/shell/common/thread_host.h"
#include "flutter/shell/common/vsync_waiter.h"
#include "flutter/shell/platform/fuchsia/flutter/task_runner_adapter.h"
#include "flutter/shell/platform/fuchsia/flutter/thread.h"
#include "flutter/shell/platform/fuchsia/flutter/vsync_waiter.h"

namespace flutter_runner_test {

class VsyncWaiterTest : public testing::Test {
public:
VsyncWaiterTest() {}

~VsyncWaiterTest() = default;

std::unique_ptr<flutter::VsyncWaiter> CreateVsyncWaiter(
flutter::TaskRunners task_runners) {
return std::make_unique<flutter_runner::VsyncWaiter>(
"VsyncWaiterTest", vsync_event_.get(), task_runners);
}

void SignalVsyncEvent() {
auto status =
zx_object_signal(vsync_event_.get(), 0,
flutter_runner::VsyncWaiter::SessionPresentSignal);
EXPECT_EQ(status, ZX_OK);
}

protected:
void SetUp() override {
auto status = zx::event::create(0, &vsync_event_);
EXPECT_EQ(status, ZX_OK);
}

private:
zx::event vsync_event_;
};

TEST_F(VsyncWaiterTest, AwaitVsync) {
std::array<std::unique_ptr<flutter_runner::Thread>, 3> threads;

for (auto& thread : threads) {
thread.reset(new flutter_runner::Thread());
}

async::Loop loop(&kAsyncLoopConfigAttachToThread);

const flutter::TaskRunners task_runners(
"VsyncWaiterTests", // Dart thread labels
flutter_runner::CreateFMLTaskRunner(
async_get_default_dispatcher()), // platform
flutter_runner::CreateFMLTaskRunner(threads[0]->dispatcher()), // gpu
flutter_runner::CreateFMLTaskRunner(threads[1]->dispatcher()), // ui
flutter_runner::CreateFMLTaskRunner(threads[2]->dispatcher()) // io
);

auto vsync_waiter = CreateVsyncWaiter(std::move(task_runners));

fml::AutoResetWaitableEvent latch;
vsync_waiter->AsyncWaitForVsync(
[&latch](fml::TimePoint frame_start_time,
fml::TimePoint frame_target_time) { latch.Signal(); });
SignalVsyncEvent();

bool did_timeout =
latch.WaitWithTimeout(fml::TimeDelta::FromMilliseconds(5000));

// False indicates we were signalled rather than timed out
EXPECT_FALSE(did_timeout);

vsync_waiter.reset();
for (const auto& thread : threads) {
thread->Quit();
}
}

} // namespace flutter_runner_test