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

Commit 7041238

Browse files
author
George Wright
authored
Create a WeakPtrFactory for use on the UI thread in VsyncWaiter (#13781)
1 parent 1a8bc65 commit 7041238

File tree

5 files changed

+130
-2
lines changed

5 files changed

+130
-2
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,6 +1002,7 @@ FILE: ../../../flutter/shell/platform/fuchsia/flutter/vsync_recorder.cc
10021002
FILE: ../../../flutter/shell/platform/fuchsia/flutter/vsync_recorder.h
10031003
FILE: ../../../flutter/shell/platform/fuchsia/flutter/vsync_waiter.cc
10041004
FILE: ../../../flutter/shell/platform/fuchsia/flutter/vsync_waiter.h
1005+
FILE: ../../../flutter/shell/platform/fuchsia/flutter/vsync_waiter_unittests.cc
10051006
FILE: ../../../flutter/shell/platform/fuchsia/flutter/vulkan_surface.cc
10061007
FILE: ../../../flutter/shell/platform/fuchsia/flutter/vulkan_surface.h
10071008
FILE: ../../../flutter/shell/platform/fuchsia/flutter/vulkan_surface_pool.cc

shell/platform/fuchsia/flutter/BUILD.gn

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,15 +260,24 @@ executable("flutter_runner_unittests") {
260260
"fuchsia_intl.h",
261261
"fuchsia_intl_unittest.cc",
262262
"logging.h",
263+
"loop.cc",
264+
"loop.h",
263265
"platform_view.cc",
264266
"platform_view.h",
265267
"platform_view_unittest.cc",
266268
"surface.cc",
267269
"surface.h",
270+
"task_observers.cc",
271+
"task_observers.h",
272+
"task_runner_adapter.cc",
273+
"task_runner_adapter.h",
274+
"thread.cc",
275+
"thread.h",
268276
"vsync_recorder.cc",
269277
"vsync_recorder.h",
270278
"vsync_waiter.cc",
271279
"vsync_waiter.h",
280+
"vsync_waiter_unittests.cc",
272281
]
273282

274283
# This is needed for //third_party/googletest for linking zircon symbols.

shell/platform/fuchsia/flutter/vsync_waiter.cc

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
#include "vsync_waiter.h"
66

77
#include <lib/async/default.h>
8+
#include "flutter/fml/make_copyable.h"
9+
#include "flutter/fml/synchronization/waitable_event.h"
810
#include "flutter/fml/trace_event.h"
911

1012
#include "vsync_recorder.h"
@@ -17,7 +19,8 @@ VsyncWaiter::VsyncWaiter(std::string debug_label,
1719
: flutter::VsyncWaiter(task_runners),
1820
debug_label_(std::move(debug_label)),
1921
session_wait_(session_present_handle, SessionPresentSignal),
20-
weak_factory_(this) {
22+
weak_factory_(this),
23+
weak_factory_ui_(nullptr) {
2124
auto wait_handler = [&](async_dispatcher_t* dispatcher, //
2225
async::Wait* wait, //
2326
zx_status_t status, //
@@ -33,11 +36,29 @@ VsyncWaiter::VsyncWaiter(std::string debug_label,
3336
FireCallbackNow();
3437
};
3538

39+
// Generate a WeakPtrFactory for use with the UI thread. This does not need
40+
// to wait on a latch because we only ever use the WeakPtrFactory on the UI
41+
// thread so we have ordering guarantees (see ::AwaitVSync())
42+
fml::TaskRunner::RunNowOrPostTask(
43+
task_runners_.GetUITaskRunner(), fml::MakeCopyable([this]() mutable {
44+
this->weak_factory_ui_ =
45+
std::make_unique<fml::WeakPtrFactory<VsyncWaiter>>(this);
46+
}));
3647
session_wait_.set_handler(wait_handler);
3748
}
3849

3950
VsyncWaiter::~VsyncWaiter() {
4051
session_wait_.Cancel();
52+
53+
fml::AutoResetWaitableEvent ui_latch;
54+
fml::TaskRunner::RunNowOrPostTask(
55+
task_runners_.GetUITaskRunner(),
56+
fml::MakeCopyable(
57+
[weak_factory_ui = std::move(weak_factory_ui_), &ui_latch]() mutable {
58+
weak_factory_ui.reset();
59+
ui_latch.Signal();
60+
}));
61+
ui_latch.Wait();
4162
}
4263

4364
static fml::TimePoint SnapToNextPhase(fml::TimePoint value,
@@ -57,7 +78,13 @@ void VsyncWaiter::AwaitVSync() {
5778
fml::TimePoint next_vsync = SnapToNextPhase(now, vsync_info.presentation_time,
5879
vsync_info.presentation_interval);
5980
task_runners_.GetUITaskRunner()->PostDelayedTask(
60-
[self = weak_factory_.GetWeakPtr()] {
81+
[& weak_factory_ui = this->weak_factory_ui_] {
82+
if (!weak_factory_ui) {
83+
FML_LOG(WARNING) << "WeakPtrFactory for VsyncWaiter is null, likely "
84+
"due to the VsyncWaiter being destroyed.";
85+
return;
86+
}
87+
auto self = weak_factory_ui->GetWeakPtr();
6188
if (self) {
6289
self->FireCallbackWhenSessionAvailable();
6390
}

shell/platform/fuchsia/flutter/vsync_waiter.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ class VsyncWaiter final : public flutter::VsyncWaiter {
2929
async::Wait session_wait_;
3030
fml::WeakPtrFactory<VsyncWaiter> weak_factory_;
3131

32+
// For accessing the VsyncWaiter via the UI thread, necessary for the callback
33+
// for AwaitVSync()
34+
std::unique_ptr<fml::WeakPtrFactory<VsyncWaiter>> weak_factory_ui_;
35+
3236
// |flutter::VsyncWaiter|
3337
void AwaitVSync() override;
3438

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include <array>
6+
7+
#include <gtest/gtest.h>
8+
#include <lib/zx/event.h>
9+
#include <zircon/syscalls.h>
10+
11+
#include "flutter/fml/synchronization/waitable_event.h"
12+
#include "flutter/shell/common/thread_host.h"
13+
#include "flutter/shell/common/vsync_waiter.h"
14+
#include "flutter/shell/platform/fuchsia/flutter/task_runner_adapter.h"
15+
#include "flutter/shell/platform/fuchsia/flutter/thread.h"
16+
#include "flutter/shell/platform/fuchsia/flutter/vsync_waiter.h"
17+
18+
namespace flutter_runner_test {
19+
20+
class VsyncWaiterTest : public testing::Test {
21+
public:
22+
VsyncWaiterTest() {}
23+
24+
~VsyncWaiterTest() = default;
25+
26+
std::unique_ptr<flutter::VsyncWaiter> CreateVsyncWaiter(
27+
flutter::TaskRunners task_runners) {
28+
return std::make_unique<flutter_runner::VsyncWaiter>(
29+
"VsyncWaiterTest", vsync_event_.get(), task_runners);
30+
}
31+
32+
void SignalVsyncEvent() {
33+
auto status =
34+
zx_object_signal(vsync_event_.get(), 0,
35+
flutter_runner::VsyncWaiter::SessionPresentSignal);
36+
EXPECT_EQ(status, ZX_OK);
37+
}
38+
39+
protected:
40+
void SetUp() override {
41+
auto status = zx::event::create(0, &vsync_event_);
42+
EXPECT_EQ(status, ZX_OK);
43+
}
44+
45+
private:
46+
zx::event vsync_event_;
47+
};
48+
49+
TEST_F(VsyncWaiterTest, AwaitVsync) {
50+
std::array<std::unique_ptr<flutter_runner::Thread>, 3> threads;
51+
52+
for (auto& thread : threads) {
53+
thread.reset(new flutter_runner::Thread());
54+
}
55+
56+
async::Loop loop(&kAsyncLoopConfigAttachToThread);
57+
58+
const flutter::TaskRunners task_runners(
59+
"VsyncWaiterTests", // Dart thread labels
60+
flutter_runner::CreateFMLTaskRunner(
61+
async_get_default_dispatcher()), // platform
62+
flutter_runner::CreateFMLTaskRunner(threads[0]->dispatcher()), // gpu
63+
flutter_runner::CreateFMLTaskRunner(threads[1]->dispatcher()), // ui
64+
flutter_runner::CreateFMLTaskRunner(threads[2]->dispatcher()) // io
65+
);
66+
67+
auto vsync_waiter = CreateVsyncWaiter(std::move(task_runners));
68+
69+
fml::AutoResetWaitableEvent latch;
70+
vsync_waiter->AsyncWaitForVsync(
71+
[&latch](fml::TimePoint frame_start_time,
72+
fml::TimePoint frame_target_time) { latch.Signal(); });
73+
SignalVsyncEvent();
74+
75+
bool did_timeout =
76+
latch.WaitWithTimeout(fml::TimeDelta::FromMilliseconds(5000));
77+
78+
// False indicates we were signalled rather than timed out
79+
EXPECT_FALSE(did_timeout);
80+
81+
vsync_waiter.reset();
82+
for (const auto& thread : threads) {
83+
thread->Quit();
84+
}
85+
}
86+
87+
} // namespace flutter_runner_test

0 commit comments

Comments
 (0)