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

Commit 9675ca2

Browse files
authored
Reland "Smooth out iOS irregular input events delivery (#12280)" (#12385)
This reverts commit c2879ca. Additionally, we fix flutter/flutter#40863 by adding a secondary VSYNC callback. Unit tests are updated to provide VSYNC mocking and check the fix of flutter/flutter#40863. The root cause of having flutter/flutter#40863 is the false assumption that each input event must trigger a new frame. That was true in the framework PR flutter/flutter#36616 because the input events there are all scrolling move events. When the PR was ported to the engine, we can no longer distinguish different types of events, and tap events may no longer trigger a new frame. Therefore, this PR directly hooks into the `VsyncWaiter` and uses its (newly added) secondary callback to dispatch the pending input event.
1 parent be9039e commit 9675ca2

19 files changed

Lines changed: 886 additions & 84 deletions

ci/licenses_golden/licenses_flutter

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,7 @@ FILE: ../../../flutter/shell/common/canvas_spy_unittests.cc
487487
FILE: ../../../flutter/shell/common/engine.cc
488488
FILE: ../../../flutter/shell/common/engine.h
489489
FILE: ../../../flutter/shell/common/fixtures/shell_test.dart
490+
FILE: ../../../flutter/shell/common/input_events_unittests.cc
490491
FILE: ../../../flutter/shell/common/isolate_configuration.cc
491492
FILE: ../../../flutter/shell/common/isolate_configuration.h
492493
FILE: ../../../flutter/shell/common/persistent_cache.cc
@@ -496,6 +497,8 @@ FILE: ../../../flutter/shell/common/pipeline.h
496497
FILE: ../../../flutter/shell/common/pipeline_unittests.cc
497498
FILE: ../../../flutter/shell/common/platform_view.cc
498499
FILE: ../../../flutter/shell/common/platform_view.h
500+
FILE: ../../../flutter/shell/common/pointer_data_dispatcher.cc
501+
FILE: ../../../flutter/shell/common/pointer_data_dispatcher.h
499502
FILE: ../../../flutter/shell/common/rasterizer.cc
500503
FILE: ../../../flutter/shell/common/rasterizer.h
501504
FILE: ../../../flutter/shell/common/run_configuration.cc

shell/common/BUILD.gn

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ source_set("common") {
7474
"pipeline.h",
7575
"platform_view.cc",
7676
"platform_view.h",
77+
"pointer_data_dispatcher.cc",
78+
"pointer_data_dispatcher.h",
7779
"rasterizer.cc",
7880
"rasterizer.h",
7981
"run_configuration.cc",
@@ -156,6 +158,7 @@ if (current_toolchain == host_toolchain) {
156158
shell_host_executable("shell_unittests") {
157159
sources = [
158160
"canvas_spy_unittests.cc",
161+
"input_events_unittests.cc",
159162
"pipeline_unittests.cc",
160163
"shell_test.cc",
161164
"shell_test.h",

shell/common/animator.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,4 +244,8 @@ void Animator::AwaitVSync() {
244244
delegate_.OnAnimatorNotifyIdle(dart_frame_deadline_);
245245
}
246246

247+
void Animator::ScheduleSecondaryVsyncCallback(fml::closure callback) {
248+
waiter_->ScheduleSecondaryCallback(std::move(callback));
249+
}
250+
247251
} // namespace flutter

shell/common/animator.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,23 @@ class Animator final {
5252

5353
void Render(std::unique_ptr<flutter::LayerTree> layer_tree);
5454

55+
//--------------------------------------------------------------------------
56+
/// @brief Schedule a secondary callback to be executed right after the
57+
/// main `VsyncWaiter::AsyncWaitForVsync` callback (which is added
58+
/// by `Animator::RequestFrame`).
59+
///
60+
/// Like the callback in `AsyncWaitForVsync`, this callback is
61+
/// only scheduled to be called once, and it's supposed to be
62+
/// called in the UI thread. If there is no AsyncWaitForVsync
63+
/// callback (`Animator::RequestFrame` is not called), this
64+
/// secondary callback will still be executed at vsync.
65+
///
66+
/// This callback is used to provide the vsync signal needed by
67+
/// `SmoothPointerDataDispatcher`.
68+
///
69+
/// @see `PointerDataDispatcher::ScheduleSecondaryVsyncCallback`.
70+
void ScheduleSecondaryVsyncCallback(fml::closure callback);
71+
5572
void Start();
5673

5774
void Stop();

shell/common/engine.cc

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ static constexpr char kSettingsChannel[] = "flutter/settings";
3636
static constexpr char kIsolateChannel[] = "flutter/isolate";
3737

3838
Engine::Engine(Delegate& delegate,
39+
const PointerDataDispatcherMaker& dispatcher_maker,
3940
DartVM& vm,
4041
fml::RefPtr<const DartSnapshot> isolate_snapshot,
4142
fml::RefPtr<const DartSnapshot> shared_snapshot,
@@ -51,6 +52,7 @@ Engine::Engine(Delegate& delegate,
5152
image_decoder_(task_runners,
5253
vm.GetConcurrentWorkerTaskRunner(),
5354
io_manager),
55+
task_runners_(std::move(task_runners)),
5456
weak_factory_(this) {
5557
// Runtime controller is initialized here because it takes a reference to this
5658
// object as its delegate. The delegate may be called in the constructor and
@@ -60,7 +62,7 @@ Engine::Engine(Delegate& delegate,
6062
&vm, // VM
6163
std::move(isolate_snapshot), // isolate snapshot
6264
std::move(shared_snapshot), // shared snapshot
63-
std::move(task_runners), // task runners
65+
task_runners_, // task runners
6466
std::move(io_manager), // io manager
6567
image_decoder_.GetWeakPtr(), // image decoder
6668
settings_.advisory_script_uri, // advisory script uri
@@ -69,6 +71,8 @@ Engine::Engine(Delegate& delegate,
6971
settings_.isolate_create_callback, // isolate create callback
7072
settings_.isolate_shutdown_callback // isolate shutdown callback
7173
);
74+
75+
pointer_data_dispatcher_ = dispatcher_maker(*this);
7276
}
7377

7478
Engine::~Engine() = default;
@@ -381,12 +385,12 @@ void Engine::HandleSettingsPlatformMessage(PlatformMessage* message) {
381385
}
382386
}
383387

384-
void Engine::DispatchPointerDataPacket(const PointerDataPacket& packet,
385-
uint64_t trace_flow_id) {
388+
void Engine::DispatchPointerDataPacket(
389+
std::unique_ptr<PointerDataPacket> packet,
390+
uint64_t trace_flow_id) {
386391
TRACE_EVENT0("flutter", "Engine::DispatchPointerDataPacket");
387392
TRACE_FLOW_STEP("flutter", "PointerEvent", trace_flow_id);
388-
animator_->EnqueueTraceFlowId(trace_flow_id);
389-
runtime_controller_->DispatchPointerDataPacket(packet);
393+
pointer_data_dispatcher_->DispatchPacket(std::move(packet), trace_flow_id);
390394
}
391395

392396
void Engine::DispatchSemanticsAction(int id,
@@ -462,6 +466,18 @@ FontCollection& Engine::GetFontCollection() {
462466
return font_collection_;
463467
}
464468

469+
void Engine::DoDispatchPacket(std::unique_ptr<PointerDataPacket> packet,
470+
uint64_t trace_flow_id) {
471+
animator_->EnqueueTraceFlowId(trace_flow_id);
472+
if (runtime_controller_) {
473+
runtime_controller_->DispatchPointerDataPacket(*packet);
474+
}
475+
}
476+
477+
void Engine::ScheduleSecondaryVsyncCallback(fml::closure callback) {
478+
animator_->ScheduleSecondaryVsyncCallback(std::move(callback));
479+
}
480+
465481
void Engine::HandleAssetPlatformMessage(fml::RefPtr<PlatformMessage> message) {
466482
fml::RefPtr<PlatformMessageResponse> response = message->response();
467483
if (!response) {

shell/common/engine.h

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
#include "flutter/runtime/runtime_controller.h"
2323
#include "flutter/runtime/runtime_delegate.h"
2424
#include "flutter/shell/common/animator.h"
25+
#include "flutter/shell/common/platform_view.h"
26+
#include "flutter/shell/common/pointer_data_dispatcher.h"
2527
#include "flutter/shell/common/rasterizer.h"
2628
#include "flutter/shell/common/run_configuration.h"
2729
#include "flutter/shell/common/shell_io_manager.h"
@@ -65,7 +67,7 @@ namespace flutter {
6567
/// name and it does happen to be one of the older classes in the
6668
/// repository.
6769
///
68-
class Engine final : public RuntimeDelegate {
70+
class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate {
6971
public:
7072
//----------------------------------------------------------------------------
7173
/// @brief Indicates the result of the call to `Engine::Run`.
@@ -234,6 +236,12 @@ class Engine final : public RuntimeDelegate {
234236
/// tasks that require access to components
235237
/// that cannot be safely accessed by the
236238
/// engine. This is the shell.
239+
/// @param dispatcher_maker The callback provided by `PlatformView` for
240+
/// engine to create the pointer data
241+
/// dispatcher. Similar to other engine
242+
/// resources, this dispatcher_maker and its
243+
/// returned dispatcher is only safe to be
244+
/// called from the UI thread.
237245
/// @param vm An instance of the running Dart VM.
238246
/// @param[in] isolate_snapshot The snapshot used to create the root
239247
/// isolate. Even though the isolate is not
@@ -265,6 +273,7 @@ class Engine final : public RuntimeDelegate {
265273
/// GPU.
266274
///
267275
Engine(Delegate& delegate,
276+
const PointerDataDispatcherMaker& dispatcher_maker,
268277
DartVM& vm,
269278
fml::RefPtr<const DartSnapshot> isolate_snapshot,
270279
fml::RefPtr<const DartSnapshot> shared_snapshot,
@@ -649,7 +658,7 @@ class Engine final : public RuntimeDelegate {
649658
/// timeline and allow grouping frames and input
650659
/// events into logical chunks.
651660
///
652-
void DispatchPointerDataPacket(const PointerDataPacket& packet,
661+
void DispatchPointerDataPacket(std::unique_ptr<PointerDataPacket> packet,
653662
uint64_t trace_flow_id);
654663

655664
//----------------------------------------------------------------------------
@@ -700,18 +709,32 @@ class Engine final : public RuntimeDelegate {
700709
// |RuntimeDelegate|
701710
FontCollection& GetFontCollection() override;
702711

712+
// |PointerDataDispatcher::Delegate|
713+
void DoDispatchPacket(std::unique_ptr<PointerDataPacket> packet,
714+
uint64_t trace_flow_id) override;
715+
716+
// |PointerDataDispatcher::Delegate|
717+
void ScheduleSecondaryVsyncCallback(fml::closure callback) override;
718+
703719
private:
704720
Engine::Delegate& delegate_;
705721
const Settings settings_;
706722
std::unique_ptr<Animator> animator_;
707723
std::unique_ptr<RuntimeController> runtime_controller_;
724+
725+
// The pointer_data_dispatcher_ depends on animator_ and runtime_controller_.
726+
// So it should be defined after them to ensure that pointer_data_dispatcher_
727+
// is destructed first.
728+
std::unique_ptr<PointerDataDispatcher> pointer_data_dispatcher_;
729+
708730
std::string initial_route_;
709731
ViewportMetrics viewport_metrics_;
710732
std::shared_ptr<AssetManager> asset_manager_;
711733
bool activity_running_;
712734
bool have_surface_;
713735
FontCollection font_collection_;
714736
ImageDecoder image_decoder_;
737+
TaskRunners task_runners_;
715738
fml::WeakPtrFactory<Engine> weak_factory_;
716739

717740
// |RuntimeDelegate|

shell/common/fixtures/shell_test.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ void main() {}
1111

1212
void nativeReportTimingsCallback(List<int> timings) native 'NativeReportTimingsCallback';
1313
void nativeOnBeginFrame(int microseconds) native 'NativeOnBeginFrame';
14+
void nativeOnPointerDataPacket() native 'NativeOnPointerDataPacket';
1415

1516
@pragma('vm:entry-point')
1617
void reportTimingsMain() {
@@ -32,6 +33,13 @@ void onBeginFrameMain() {
3233
};
3334
}
3435

36+
@pragma('vm:entry-point')
37+
void onPointerDataPacketMain() {
38+
window.onPointerDataPacket = (PointerDataPacket packet) {
39+
nativeOnPointerDataPacket();
40+
};
41+
}
42+
3543
@pragma('vm:entry-point')
3644
void emptyMain() {}
3745

0 commit comments

Comments
 (0)