mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Surface frame number identifier through window (flutter/engine#26785)
This commit is contained in:
parent
4ae3981290
commit
ccae44ffd0
@ -317,6 +317,11 @@ void hooksTests() {
|
||||
}
|
||||
}
|
||||
|
||||
void expectNotEquals(Object? value, Object? expected) {
|
||||
if (value == expected) {
|
||||
throw 'Expected $value to not be $expected.';
|
||||
}
|
||||
}
|
||||
|
||||
test('onMetricsChanged preserves callback zone', () {
|
||||
late Zone originalZone;
|
||||
@ -479,7 +484,7 @@ void hooksTests() {
|
||||
};
|
||||
});
|
||||
|
||||
_callHook('_beginFrame', 1, 1234);
|
||||
_callHook('_beginFrame', 2, 1234, 1);
|
||||
expectIdentical(runZone, innerZone);
|
||||
expectEquals(start, const Duration(microseconds: 1234));
|
||||
});
|
||||
@ -625,6 +630,25 @@ void hooksTests() {
|
||||
expectEquals(platformBrightness, Brightness.dark);
|
||||
});
|
||||
|
||||
test('onFrameDataChanged preserves callback zone', () {
|
||||
late Zone innerZone;
|
||||
late Zone runZone;
|
||||
late int frameNumber;
|
||||
|
||||
runZoned(() {
|
||||
innerZone = Zone.current;
|
||||
window.onFrameDataChanged = () {
|
||||
runZone = Zone.current;
|
||||
frameNumber = window.frameData.frameNumber;
|
||||
};
|
||||
});
|
||||
|
||||
_callHook('_beginFrame', 2, 0, 2);
|
||||
expectNotEquals(runZone, null);
|
||||
expectIdentical(runZone, innerZone);
|
||||
expectEquals(frameNumber, 2);
|
||||
});
|
||||
|
||||
_finish();
|
||||
}
|
||||
|
||||
|
||||
@ -110,8 +110,9 @@ void _dispatchSemanticsAction(int id, int action, ByteData? args) {
|
||||
|
||||
@pragma('vm:entry-point')
|
||||
// ignore: unused_element
|
||||
void _beginFrame(int microseconds) {
|
||||
void _beginFrame(int microseconds, int frameNumber) {
|
||||
PlatformDispatcher.instance._beginFrame(microseconds);
|
||||
PlatformDispatcher.instance._updateFrameData(frameNumber);
|
||||
}
|
||||
|
||||
@pragma('vm:entry-point')
|
||||
|
||||
@ -877,6 +877,29 @@ class PlatformDispatcher {
|
||||
_onSemanticsActionZone = Zone.current;
|
||||
}
|
||||
|
||||
// Called from the engine via hooks.dart.
|
||||
void _updateFrameData(int frameNumber) {
|
||||
final FrameData previous = _frameData;
|
||||
if (previous.frameNumber == frameNumber) {
|
||||
return;
|
||||
}
|
||||
_frameData = FrameData._(frameNumber: frameNumber);
|
||||
_invoke(onFrameDataChanged, _onFrameDataChangedZone);
|
||||
}
|
||||
|
||||
/// The [FrameData] object for the current frame.
|
||||
FrameData get frameData => _frameData;
|
||||
FrameData _frameData = const FrameData._();
|
||||
|
||||
/// A callback that is invoked when the window updates the [FrameData].
|
||||
VoidCallback? get onFrameDataChanged => _onFrameDataChanged;
|
||||
VoidCallback? _onFrameDataChanged;
|
||||
Zone _onFrameDataChangedZone = Zone.root;
|
||||
set onFrameDataChanged(VoidCallback? callback) {
|
||||
_onFrameDataChanged = callback;
|
||||
_onFrameDataChangedZone = Zone.current;
|
||||
}
|
||||
|
||||
// Called from the engine, via hooks.dart
|
||||
void _dispatchSemanticsAction(int id, int action, ByteData? args) {
|
||||
_invoke3<int, SemanticsAction, ByteData?>(
|
||||
|
||||
@ -633,6 +633,15 @@ class SingletonFlutterWindow extends FlutterWindow {
|
||||
platformDispatcher.onSemanticsEnabledChanged = callback;
|
||||
}
|
||||
|
||||
/// The [FrameData] object for the current frame.
|
||||
FrameData get frameData => platformDispatcher.frameData;
|
||||
|
||||
/// A callback that is invoked when the window updates the [FrameData].
|
||||
VoidCallback? get onFrameDataChanged => platformDispatcher.onFrameDataChanged;
|
||||
set onFrameDataChanged(VoidCallback? callback) {
|
||||
platformDispatcher.onFrameDataChanged = callback;
|
||||
}
|
||||
|
||||
/// A callback that is invoked whenever the user requests an action to be
|
||||
/// performed.
|
||||
///
|
||||
@ -849,3 +858,16 @@ enum Brightness {
|
||||
/// belonging to the application, including top level application windows like
|
||||
/// this one.
|
||||
final SingletonFlutterWindow window = SingletonFlutterWindow._(0, PlatformDispatcher.instance);
|
||||
|
||||
/// Additional data available on each flutter frame.
|
||||
class FrameData {
|
||||
const FrameData._({this.frameNumber = -1});
|
||||
|
||||
/// The number of the current frame.
|
||||
///
|
||||
/// This number monotonically increases, but doesn't necessarily
|
||||
/// start at a particular value.
|
||||
///
|
||||
/// If not provided, defaults to -1.
|
||||
final int frameNumber;
|
||||
}
|
||||
|
||||
@ -366,7 +366,8 @@ uint64_t PlatformConfiguration::RegisterKeyDataResponse(
|
||||
return response_id;
|
||||
}
|
||||
|
||||
void PlatformConfiguration::BeginFrame(fml::TimePoint frameTime) {
|
||||
void PlatformConfiguration::BeginFrame(fml::TimePoint frameTime,
|
||||
uint64_t frame_number) {
|
||||
std::shared_ptr<tonic::DartState> dart_state =
|
||||
begin_frame_.dart_state().lock();
|
||||
if (!dart_state) {
|
||||
@ -379,6 +380,7 @@ void PlatformConfiguration::BeginFrame(fml::TimePoint frameTime) {
|
||||
tonic::LogIfError(
|
||||
tonic::DartInvoke(begin_frame_.Get(), {
|
||||
Dart_NewInteger(microseconds),
|
||||
Dart_NewInteger(frame_number),
|
||||
}));
|
||||
|
||||
UIDartState::Current()->FlushMicrotasksNow();
|
||||
|
||||
@ -364,7 +364,12 @@ class PlatformConfiguration final {
|
||||
/// began. May be used by animation interpolators,
|
||||
/// physics simulations, etc..
|
||||
///
|
||||
void BeginFrame(fml::TimePoint frame_time);
|
||||
/// @param[in] frame_number The frame number recorded by the animator. Used
|
||||
/// by the framework to associate frame specific
|
||||
/// debug information with frame timings and timeline
|
||||
/// events.
|
||||
///
|
||||
void BeginFrame(fml::TimePoint frame_time, uint64_t frame_number);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief Dart code cannot fully measure the time it takes for a
|
||||
|
||||
@ -941,6 +941,8 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ui.FrameData get frameData => const ui.FrameData.webOnly();
|
||||
}
|
||||
|
||||
bool _handleWebTestEnd2EndMessage(MethodCodec codec, ByteData? data) {
|
||||
|
||||
@ -98,6 +98,11 @@ abstract class PlatformDispatcher {
|
||||
set onSemanticsAction(SemanticsActionCallback? callback);
|
||||
|
||||
String get defaultRouteName;
|
||||
|
||||
FrameData get frameData;
|
||||
|
||||
VoidCallback? get onFrameDataChanged => null;
|
||||
set onFrameDataChanged(VoidCallback? callback) {}
|
||||
}
|
||||
|
||||
class PlatformConfiguration {
|
||||
|
||||
@ -102,6 +102,11 @@ abstract class SingletonFlutterWindow extends FlutterWindow {
|
||||
platformDispatcher.onSemanticsAction = callback;
|
||||
}
|
||||
|
||||
FrameData get frameData => const FrameData._();
|
||||
|
||||
VoidCallback? get onFrameDataChanged => null;
|
||||
set onFrameDataChanged(VoidCallback? callback) {}
|
||||
|
||||
AccessibilityFeatures get accessibilityFeatures => platformDispatcher.accessibilityFeatures;
|
||||
|
||||
VoidCallback? get onAccessibilityFeaturesChanged =>
|
||||
@ -241,3 +246,11 @@ class IsolateNameServer {
|
||||
}
|
||||
|
||||
SingletonFlutterWindow get window => engine.window;
|
||||
|
||||
class FrameData {
|
||||
const FrameData._({this.frameNumber = -1});
|
||||
|
||||
const FrameData.webOnly() : frameNumber = -1;
|
||||
|
||||
final int frameNumber;
|
||||
}
|
||||
|
||||
@ -177,9 +177,10 @@ bool RuntimeController::SetAccessibilityFeatures(int32_t flags) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RuntimeController::BeginFrame(fml::TimePoint frame_time) {
|
||||
bool RuntimeController::BeginFrame(fml::TimePoint frame_time,
|
||||
uint64_t frame_number) {
|
||||
if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
|
||||
platform_configuration->BeginFrame(frame_time);
|
||||
platform_configuration->BeginFrame(frame_time, frame_number);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -244,7 +244,7 @@ class RuntimeController : public PlatformConfigurationClient {
|
||||
/// @return If notification to begin frame rendering was delivered to the
|
||||
/// running isolate.
|
||||
///
|
||||
bool BeginFrame(fml::TimePoint frame_time);
|
||||
bool BeginFrame(fml::TimePoint frame_time, uint64_t frame_number);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief Dart code cannot fully measure the time it takes for a
|
||||
|
||||
@ -149,7 +149,8 @@ void Animator::BeginFrame(
|
||||
{
|
||||
TRACE_EVENT2("flutter", "Framework Workload", "mode", "basic", "frame",
|
||||
FrameParity());
|
||||
delegate_.OnAnimatorBeginFrame(frame_target_time);
|
||||
uint64_t frame_number = frame_timings_recorder_->GetFrameNumber();
|
||||
delegate_.OnAnimatorBeginFrame(frame_target_time, frame_number);
|
||||
}
|
||||
|
||||
if (!frame_scheduled_) {
|
||||
|
||||
@ -31,7 +31,8 @@ class Animator final {
|
||||
public:
|
||||
class Delegate {
|
||||
public:
|
||||
virtual void OnAnimatorBeginFrame(fml::TimePoint frame_target_time) = 0;
|
||||
virtual void OnAnimatorBeginFrame(fml::TimePoint frame_target_time,
|
||||
uint64_t frame_number) = 0;
|
||||
|
||||
virtual void OnAnimatorNotifyIdle(int64_t deadline) = 0;
|
||||
|
||||
|
||||
@ -220,9 +220,9 @@ Engine::RunStatus Engine::Run(RunConfiguration configuration) {
|
||||
return Engine::RunStatus::Success;
|
||||
}
|
||||
|
||||
void Engine::BeginFrame(fml::TimePoint frame_time) {
|
||||
void Engine::BeginFrame(fml::TimePoint frame_time, uint64_t frame_number) {
|
||||
TRACE_EVENT0("flutter", "Engine::BeginFrame");
|
||||
runtime_controller_->BeginFrame(frame_time);
|
||||
runtime_controller_->BeginFrame(frame_time, frame_number);
|
||||
}
|
||||
|
||||
void Engine::ReportTimings(std::vector<int64_t> timings) {
|
||||
|
||||
@ -500,7 +500,11 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate {
|
||||
/// began. May be used by animation interpolators,
|
||||
/// physics simulations, etc..
|
||||
///
|
||||
void BeginFrame(fml::TimePoint frame_time);
|
||||
/// @param[in] frame_number The frame number recorded by the animator. Used
|
||||
/// by the framework to associate frame specific
|
||||
/// debug information with frame timings and timeline
|
||||
/// events.
|
||||
void BeginFrame(fml::TimePoint frame_time, uint64_t frame_number);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief Notifies the engine that the UI task runner is not expected to
|
||||
|
||||
@ -1101,7 +1101,8 @@ void Shell::OnPlatformViewSetNextFrameCallback(const fml::closure& closure) {
|
||||
}
|
||||
|
||||
// |Animator::Delegate|
|
||||
void Shell::OnAnimatorBeginFrame(fml::TimePoint frame_target_time) {
|
||||
void Shell::OnAnimatorBeginFrame(fml::TimePoint frame_target_time,
|
||||
uint64_t frame_number) {
|
||||
FML_DCHECK(is_setup_);
|
||||
FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
|
||||
|
||||
@ -1111,7 +1112,7 @@ void Shell::OnAnimatorBeginFrame(fml::TimePoint frame_target_time) {
|
||||
latest_frame_target_time_.emplace(frame_target_time);
|
||||
}
|
||||
if (engine_) {
|
||||
engine_->BeginFrame(frame_target_time);
|
||||
engine_->BeginFrame(frame_target_time, frame_number);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -532,7 +532,8 @@ class Shell final : public PlatformView::Delegate,
|
||||
AssetResolver::AssetResolverType type) override;
|
||||
|
||||
// |Animator::Delegate|
|
||||
void OnAnimatorBeginFrame(fml::TimePoint frame_target_time) override;
|
||||
void OnAnimatorBeginFrame(fml::TimePoint frame_target_time,
|
||||
uint64_t frame_number) override;
|
||||
|
||||
// |Animator::Delegate|
|
||||
void OnAnimatorNotifyIdle(int64_t deadline) override;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user