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

Commit c4678d6

Browse files
Fix input flow event logic (#24526)
1 parent 1bdf5d3 commit c4678d6

File tree

8 files changed

+69
-28
lines changed

8 files changed

+69
-28
lines changed

shell/common/animator.cc

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ void Animator::EnqueueTraceFlowId(uint64_t trace_flow_id) {
8080
return;
8181
}
8282
self->trace_flow_ids_.push_back(trace_flow_id);
83+
self->ScheduleMaybeClearTraceFlowIds();
8384
});
8485
}
8586

@@ -249,8 +250,27 @@ void Animator::AwaitVSync() {
249250
delegate_.OnAnimatorNotifyIdle(dart_frame_deadline_);
250251
}
251252

252-
void Animator::ScheduleSecondaryVsyncCallback(const fml::closure& callback) {
253-
waiter_->ScheduleSecondaryCallback(callback);
253+
void Animator::ScheduleSecondaryVsyncCallback(uintptr_t id,
254+
const fml::closure& callback) {
255+
waiter_->ScheduleSecondaryCallback(id, callback);
256+
}
257+
258+
void Animator::ScheduleMaybeClearTraceFlowIds() {
259+
waiter_->ScheduleSecondaryCallback(
260+
reinterpret_cast<uintptr_t>(this), [self = weak_factory_.GetWeakPtr()] {
261+
if (!self) {
262+
return;
263+
}
264+
if (!self->frame_scheduled_ && !self->trace_flow_ids_.empty()) {
265+
TRACE_EVENT0("flutter",
266+
"Animator::ScheduleMaybeClearTraceFlowIds - callback");
267+
while (!self->trace_flow_ids_.empty()) {
268+
auto flow_id = self->trace_flow_ids_.front();
269+
TRACE_FLOW_END("flutter", "PointerEvent", flow_id);
270+
self->trace_flow_ids_.pop_front();
271+
}
272+
}
273+
});
254274
}
255275

256276
} // namespace flutter

shell/common/animator.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,19 +63,21 @@ class Animator final {
6363
/// secondary callback will still be executed at vsync.
6464
///
6565
/// This callback is used to provide the vsync signal needed by
66-
/// `SmoothPointerDataDispatcher`.
66+
/// `SmoothPointerDataDispatcher`, and for our own flow events.
6767
///
6868
/// @see `PointerDataDispatcher::ScheduleSecondaryVsyncCallback`.
69-
void ScheduleSecondaryVsyncCallback(const fml::closure& callback);
69+
void ScheduleSecondaryVsyncCallback(uintptr_t id,
70+
const fml::closure& callback);
7071

7172
void Start();
7273

7374
void Stop();
7475

7576
void SetDimensionChangePending();
7677

77-
// Enqueue |trace_flow_id| into |trace_flow_ids_|. The corresponding flow
78-
// will be ended during the next |BeginFrame|.
78+
// Enqueue |trace_flow_id| into |trace_flow_ids_|. The flow event will be
79+
// ended at either the next frame, or the next vsync interval with no active
80+
// active rendering.
7981
void EnqueueTraceFlowId(uint64_t trace_flow_id);
8082

8183
private:
@@ -91,6 +93,9 @@ class Animator final {
9193

9294
const char* FrameParity();
9395

96+
// Clear |trace_flow_ids_| if |frame_scheduled_| is false.
97+
void ScheduleMaybeClearTraceFlowIds();
98+
9499
Delegate& delegate_;
95100
TaskRunners task_runners_;
96101
std::shared_ptr<VsyncWaiter> waiter_;

shell/common/engine.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -515,8 +515,9 @@ void Engine::DoDispatchPacket(std::unique_ptr<PointerDataPacket> packet,
515515
}
516516
}
517517

518-
void Engine::ScheduleSecondaryVsyncCallback(const fml::closure& callback) {
519-
animator_->ScheduleSecondaryVsyncCallback(callback);
518+
void Engine::ScheduleSecondaryVsyncCallback(uintptr_t id,
519+
const fml::closure& callback) {
520+
animator_->ScheduleSecondaryVsyncCallback(id, callback);
520521
}
521522

522523
void Engine::HandleAssetPlatformMessage(fml::RefPtr<PlatformMessage> message) {

shell/common/engine.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -804,7 +804,8 @@ class Engine final : public RuntimeDelegate,
804804
uint64_t trace_flow_id) override;
805805

806806
// |PointerDataDispatcher::Delegate|
807-
void ScheduleSecondaryVsyncCallback(const fml::closure& callback) override;
807+
void ScheduleSecondaryVsyncCallback(uintptr_t id,
808+
const fml::closure& callback) override;
808809

809810
//----------------------------------------------------------------------------
810811
/// @brief Get the last Entrypoint that was used in the RunConfiguration

shell/common/pointer_data_dispatcher.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
#include "flutter/shell/common/pointer_data_dispatcher.h"
66

7+
#include "flutter/fml/trace_event.h"
8+
79
namespace flutter {
810

911
PointerDataDispatcher::~PointerDataDispatcher() = default;
@@ -16,12 +18,17 @@ SmoothPointerDataDispatcher::~SmoothPointerDataDispatcher() = default;
1618
void DefaultPointerDataDispatcher::DispatchPacket(
1719
std::unique_ptr<PointerDataPacket> packet,
1820
uint64_t trace_flow_id) {
21+
TRACE_EVENT0("flutter", "DefaultPointerDataDispatcher::DispatchPacket");
22+
TRACE_FLOW_STEP("flutter", "PointerEvent", trace_flow_id);
1923
delegate_.DoDispatchPacket(std::move(packet), trace_flow_id);
2024
}
2125

2226
void SmoothPointerDataDispatcher::DispatchPacket(
2327
std::unique_ptr<PointerDataPacket> packet,
2428
uint64_t trace_flow_id) {
29+
TRACE_EVENT0("flutter", "SmoothPointerDataDispatcher::DispatchPacket");
30+
TRACE_FLOW_STEP("flutter", "PointerEvent", trace_flow_id);
31+
2532
if (is_pointer_data_in_progress_) {
2633
if (pending_packet_ != nullptr) {
2734
DispatchPendingPacket();
@@ -39,6 +46,7 @@ void SmoothPointerDataDispatcher::DispatchPacket(
3946

4047
void SmoothPointerDataDispatcher::ScheduleSecondaryVsyncCallback() {
4148
delegate_.ScheduleSecondaryVsyncCallback(
49+
reinterpret_cast<uintptr_t>(this),
4250
[dispatcher = weak_factory_.GetWeakPtr()]() {
4351
if (dispatcher && dispatcher->is_pointer_data_in_progress_) {
4452
if (dispatcher->pending_packet_ != nullptr) {

shell/common/pointer_data_dispatcher.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,16 @@ class PointerDataDispatcher {
5353
/// by `Animator::RequestFrame`).
5454
///
5555
/// Like the callback in `AsyncWaitForVsync`, this callback is
56-
/// only scheduled to be called once, and it will be called in the
57-
/// UI thread. If there is no AsyncWaitForVsync callback
58-
/// (`Animator::RequestFrame` is not called), this secondary
59-
/// callback will still be executed at vsync.
56+
/// only scheduled to be called once per |id|, and it will be
57+
/// called in the UI thread. If there is no AsyncWaitForVsync
58+
/// callback (`Animator::RequestFrame` is not called), this
59+
/// secondary callback will still be executed at vsync.
6060
///
6161
/// This callback is used to provide the vsync signal needed by
62-
/// `SmoothPointerDataDispatcher`.
62+
/// `SmoothPointerDataDispatcher`, and for `Animator` input flow
63+
/// events.
6364
virtual void ScheduleSecondaryVsyncCallback(
65+
uintptr_t id,
6466
const fml::closure& callback) = 0;
6567
};
6668

shell/common/vsync_waiter.cc

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ void VsyncWaiter::AsyncWaitForVsync(const Callback& callback) {
5252
return;
5353
}
5454
callback_ = std::move(callback);
55-
if (secondary_callback_) {
55+
if (!secondary_callbacks_.empty()) {
5656
// Return directly as `AwaitVSync` is already called by
5757
// `ScheduleSecondaryCallback`.
5858
return;
@@ -61,7 +61,8 @@ void VsyncWaiter::AsyncWaitForVsync(const Callback& callback) {
6161
AwaitVSync();
6262
}
6363

64-
void VsyncWaiter::ScheduleSecondaryCallback(const fml::closure& callback) {
64+
void VsyncWaiter::ScheduleSecondaryCallback(uintptr_t id,
65+
const fml::closure& callback) {
6566
FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
6667

6768
if (!callback) {
@@ -72,13 +73,13 @@ void VsyncWaiter::ScheduleSecondaryCallback(const fml::closure& callback) {
7273

7374
{
7475
std::scoped_lock lock(callback_mutex_);
75-
if (secondary_callback_) {
76+
auto [_, inserted] = secondary_callbacks_.emplace(id, std::move(callback));
77+
if (!inserted) {
7678
// Multiple schedules must result in a single callback per frame interval.
7779
TRACE_EVENT_INSTANT0("flutter",
7880
"MultipleCallsToSecondaryVsyncInFrameInterval");
7981
return;
8082
}
81-
secondary_callback_ = std::move(callback);
8283
if (callback_) {
8384
// Return directly as `AwaitVSync` is already called by
8485
// `AsyncWaitForVsync`.
@@ -91,15 +92,18 @@ void VsyncWaiter::ScheduleSecondaryCallback(const fml::closure& callback) {
9192
void VsyncWaiter::FireCallback(fml::TimePoint frame_start_time,
9293
fml::TimePoint frame_target_time) {
9394
Callback callback;
94-
fml::closure secondary_callback;
95+
std::vector<fml::closure> secondary_callbacks;
9596

9697
{
9798
std::scoped_lock lock(callback_mutex_);
9899
callback = std::move(callback_);
99-
secondary_callback = std::move(secondary_callback_);
100+
for (auto& pair : secondary_callbacks_) {
101+
secondary_callbacks.push_back(std::move(pair.second));
102+
}
103+
secondary_callbacks_.clear();
100104
}
101105

102-
if (!callback && !secondary_callback) {
106+
if (!callback && secondary_callbacks.empty()) {
103107
// This means that the vsync waiter implementation fired a callback for a
104108
// request we did not make. This is a paranoid check but we still want to
105109
// make sure we catch misbehaving vsync implementations.
@@ -128,7 +132,7 @@ void VsyncWaiter::FireCallback(fml::TimePoint frame_start_time,
128132
frame_start_time);
129133
}
130134

131-
if (secondary_callback) {
135+
for (auto& secondary_callback : secondary_callbacks) {
132136
task_runners_.GetUITaskRunner()->PostTaskForTime(
133137
std::move(secondary_callback), frame_start_time);
134138
}

shell/common/vsync_waiter.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <functional>
99
#include <memory>
1010
#include <mutex>
11+
#include <unordered_map>
1112

1213
#include "flutter/common/task_runners.h"
1314
#include "flutter/fml/time/time_point.h"
@@ -25,10 +26,11 @@ class VsyncWaiter : public std::enable_shared_from_this<VsyncWaiter> {
2526

2627
void AsyncWaitForVsync(const Callback& callback);
2728

28-
/// Add a secondary callback for the next vsync.
29+
/// Add a secondary callback for key |id| for the next vsync.
2930
///
30-
/// See also |PointerDataDispatcher::ScheduleSecondaryVsyncCallback|.
31-
void ScheduleSecondaryCallback(const fml::closure& callback);
31+
/// See also |PointerDataDispatcher::ScheduleSecondaryVsyncCallback| and
32+
/// |Animator::ScheduleMaybeClearTraceFlowIds|.
33+
void ScheduleSecondaryCallback(uintptr_t id, const fml::closure& callback);
3234

3335
protected:
3436
// On some backends, the |FireCallback| needs to be made from a static C
@@ -52,9 +54,7 @@ class VsyncWaiter : public std::enable_shared_from_this<VsyncWaiter> {
5254
private:
5355
std::mutex callback_mutex_;
5456
Callback callback_;
55-
56-
std::mutex secondary_callback_mutex_;
57-
fml::closure secondary_callback_;
57+
std::unordered_map<uintptr_t, fml::closure> secondary_callbacks_;
5858

5959
FML_DISALLOW_COPY_AND_ASSIGN(VsyncWaiter);
6060
};

0 commit comments

Comments
 (0)