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 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
1950e72
Impl engine
dkwingsmt Feb 12, 2024
f55dfdf
Web
dkwingsmt Feb 12, 2024
7f76c5f
Rename to RequestWarmUpFrame and add web time
dkwingsmt Feb 13, 2024
31a5ea3
Change to scheduleWarmUpFrame and EndWarmUpFrame
dkwingsmt Feb 13, 2024
590287d
Comment
dkwingsmt Feb 13, 2024
40b269b
Doc
dkwingsmt Feb 13, 2024
2d70a0f
Simplify web implementation
dkwingsmt Feb 14, 2024
4af9f06
Fix comment
dkwingsmt Feb 14, 2024
bfe5570
More doc
dkwingsmt Feb 14, 2024
21439c4
Fix doc
dkwingsmt Feb 14, 2024
1bd21db
More doc
dkwingsmt Feb 14, 2024
4f41658
Fix linter
dkwingsmt Feb 14, 2024
eeac064
Fix comment
dkwingsmt Feb 14, 2024
9c5bce4
Add test
dkwingsmt Feb 15, 2024
cdcf71a
Fix test
dkwingsmt Feb 15, 2024
7ab7d8e
Better test
dkwingsmt Feb 15, 2024
afbcfae
Merge remote-tracking branch 'origin/main' into force-sync-frame
dkwingsmt Feb 15, 2024
7381087
Simplify test and add platformdispatcher test
dkwingsmt Feb 15, 2024
05d3d2d
Better structure
dkwingsmt Feb 15, 2024
06957bb
Better name
dkwingsmt Feb 15, 2024
68953c0
Merge branch 'main' into force-sync-frame
dkwingsmt Feb 15, 2024
a9b7511
Merge branch 'main' into force-sync-frame
dkwingsmt Feb 20, 2024
8731e47
Add web platform dispatcher test
dkwingsmt Feb 20, 2024
cdeffd9
Merge branch 'main' into force-sync-frame
dkwingsmt Feb 20, 2024
5d9f48b
Web comments
dkwingsmt Feb 21, 2024
1589c59
Merge remote-tracking branch 'origin/main' into force-sync-frame
dkwingsmt Feb 21, 2024
556984f
Fix test
dkwingsmt Feb 21, 2024
2b6d3b2
Revert timer run change
dkwingsmt Feb 21, 2024
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
Prev Previous commit
Next Next commit
Change to scheduleWarmUpFrame and EndWarmUpFrame
  • Loading branch information
dkwingsmt committed Feb 13, 2024
commit 31a5ea333a0d775672b5e2a1a75c2ae4bf17ce4c
2 changes: 1 addition & 1 deletion lib/ui/dart_ui.cc
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ typedef CanvasPath Path;
V(NativeStringAttribute::initSpellOutStringAttribute) \
V(PlatformConfigurationNativeApi::DefaultRouteName) \
V(PlatformConfigurationNativeApi::ScheduleFrame) \
V(PlatformConfigurationNativeApi::RequestWarmUpFrame) \
V(PlatformConfigurationNativeApi::EndWarmUpFrame) \
V(PlatformConfigurationNativeApi::Render) \
V(PlatformConfigurationNativeApi::UpdateSemantics) \
V(PlatformConfigurationNativeApi::SetNeedsReportTimings) \
Expand Down
16 changes: 11 additions & 5 deletions lib/ui/platform_dispatcher.dart
Original file line number Diff line number Diff line change
Expand Up @@ -801,7 +801,7 @@ class PlatformDispatcher {
///
/// * [SchedulerBinding], the Flutter framework class which manages the
/// scheduling of frames.
/// * [requestWarmUpFrame], a similar method that is used in rare cases that
/// * [scheduleWarmUpFrame], a similar method that is used in rare cases that
/// a frame must be rendered immediately.
void scheduleFrame() => _scheduleFrame();

Expand All @@ -816,7 +816,7 @@ class PlatformDispatcher {
/// completed synchronously within this call.
///
/// Prefer [scheduleFrame] to update the display in normal operation. The
/// [requestWarmUpFrame] method is designed for situations that require a frame is
/// [scheduleWarmUpFrame] method is designed for situations that require a frame is
/// rendered as soon as possible, even at the cost of rendering quality. An
/// example of using this method is [SchedulerBinding.scheduleWarmUpFrame],
/// which is called during application startup so that the first frame can be
Expand All @@ -826,10 +826,16 @@ class PlatformDispatcher {
///
/// * [SchedulerBinding.scheduleWarmUpFrame], which uses this method.
/// * [scheduleFrame].
void requestWarmUpFrame() => _requestWarmUpFrame();
void scheduleWarmUpFrame(VoidCallback beginFrameCallback, VoidCallback drawFrameCallback) {
Timer.run(beginFrameCallback);
Timer.run(() {
drawFrameCallback();
_endWarmUpFrame();
});
}

@Native<Void Function()>(symbol: 'PlatformConfigurationNativeApi::RequestWarmUpFrame')
external static void _requestWarmUpFrame();
@Native<Void Function()>(symbol: 'PlatformConfigurationNativeApi::EndWarmUpFrame')
external static void _endWarmUpFrame();

/// Additional accessibility features that may be enabled by the platform.
AccessibilityFeatures get accessibilityFeatures => _configuration.accessibilityFeatures;
Expand Down
7 changes: 2 additions & 5 deletions lib/ui/window/platform_configuration.cc
Original file line number Diff line number Diff line change
Expand Up @@ -589,12 +589,9 @@ void PlatformConfigurationNativeApi::ScheduleFrame() {
UIDartState::Current()->platform_configuration()->client()->ScheduleFrame();
}

void PlatformConfigurationNativeApi::RequestWarmUpFrame() {
void PlatformConfigurationNativeApi::EndWarmUpFrame() {
UIDartState::ThrowIfUIOperationsProhibited();
UIDartState::Current()
->platform_configuration()
->client()
->RequestWarmUpFrame();
UIDartState::Current()->platform_configuration()->client()->EndWarmUpFrame();
}

void PlatformConfigurationNativeApi::UpdateSemantics(SemanticsUpdate* update) {
Expand Down
4 changes: 2 additions & 2 deletions lib/ui/window/platform_configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ class PlatformConfigurationClient {
//--------------------------------------------------------------------------
/// @brief
///
virtual void RequestWarmUpFrame() = 0;
virtual void EndWarmUpFrame() = 0;

//--------------------------------------------------------------------------
/// @brief Updates the client's rendering on the GPU with the newly
Expand Down Expand Up @@ -562,7 +562,7 @@ class PlatformConfigurationNativeApi {

static void ScheduleFrame();

static void RequestWarmUpFrame();
static void EndWarmUpFrame();

static void Render(int64_t view_id,
Scene* scene,
Expand Down
2 changes: 1 addition & 1 deletion lib/web_ui/lib/platform_dispatcher.dart
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ abstract class PlatformDispatcher {

void scheduleFrame();

void requestWarmUpFrame();
void scheduleWarmUpFrame(VoidCallback beginFrameCallback, VoidCallback drawFrameCallback);

Future<void> render(Scene scene, [FlutterView view]);

Expand Down
54 changes: 26 additions & 28 deletions lib/web_ui/lib/src/engine/initialization.dart
Original file line number Diff line number Diff line change
Expand Up @@ -102,30 +102,6 @@ void debugResetEngineInitializationState() {
_initializationState = DebugEngineInitializationState.uninitialized;
}

void renderFrame(int timeMicroseconds) {
frameTimingsOnVsync();

// In Flutter terminology "building a frame" consists of "beginning
// frame" and "drawing frame".
//
// We do not call `frameTimingsOnBuildFinish` from here because
// part of the rasterization process, particularly in the HTML
// renderer, takes place in the `SceneBuilder.build()`.
frameTimingsOnBuildStart();
if (EnginePlatformDispatcher.instance.onBeginFrame != null) {
EnginePlatformDispatcher.instance.invokeOnBeginFrame(
Duration(microseconds: timeMicroseconds));
}

if (EnginePlatformDispatcher.instance.onDrawFrame != null) {
// TODO(yjbanov): technically Flutter flushes microtasks between
// onBeginFrame and onDrawFrame. We don't, which hasn't
// been an issue yet, but eventually we'll have to
// implement it properly.
EnginePlatformDispatcher.instance.invokeOnDrawFrame();
}
}

/// Initializes non-UI engine services.
///
/// Does not put any UI onto the page. It is therefore safe to call this
Expand Down Expand Up @@ -182,6 +158,8 @@ Future<void> initializeEngineServices({
if (!waitingForAnimation) {
waitingForAnimation = true;
domWindow.requestAnimationFrame((JSNumber highResTime) {
frameTimingsOnVsync();

// Reset immediately, because `frameHandler` can schedule more frames.
waitingForAnimation = false;

Expand All @@ -192,13 +170,33 @@ Future<void> initializeEngineServices({
// microsecond precision, and only then convert to `int`.
final int highResTimeMicroseconds =
(1000 * highResTime.toDartDouble).toInt();
renderFrame(highResTimeMicroseconds);

// In Flutter terminology "building a frame" consists of "beginning
// frame" and "drawing frame".
//
// We do not call `frameTimingsOnBuildFinish` from here because
// part of the rasterization process, particularly in the HTML
// renderer, takes place in the `SceneBuilder.build()`.
frameTimingsOnBuildStart();
if (EnginePlatformDispatcher.instance.onBeginFrame != null) {
EnginePlatformDispatcher.instance.invokeOnBeginFrame(
Duration(microseconds: highResTimeMicroseconds));
}

if (EnginePlatformDispatcher.instance.onDrawFrame != null) {
// TODO(yjbanov): technically Flutter flushes microtasks between
// onBeginFrame and onDrawFrame. We don't, which hasn't
// been an issue yet, but eventually we'll have to
// implement it properly.
EnginePlatformDispatcher.instance.invokeOnDrawFrame();
}
});
}
};
requestWarmUpFrameCallback = () {
final int timeMicroseconds = (1000 * domWindow.performance.now()).toInt();
renderFrame(timeMicroseconds);

scheduleWarmUpFrameCallback = (ui.VoidCallback beginFrameCallback, ui.VoidCallback drawFrameCallback) {
Timer.run(beginFrameCallback);
Timer.run(drawFrameCallback);
};

assetManager ??= ui_web.AssetManager(assetBase: configuration.assetBase);
Expand Down
14 changes: 9 additions & 5 deletions lib/web_ui/lib/src/engine/platform_dispatcher.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,16 @@ import '../engine.dart';
/// This may be overridden in tests, for example, to pump fake frames.
ui.VoidCallback? scheduleFrameCallback;

/// Signature of the function to schedule a warm up frame with the specified
/// frame callbacks.
typedef ScheduleWarmUpFrameCallback = void Function(ui.VoidCallback beginFrameCallback, ui.VoidCallback drawFrameCallback);

/// Requests that the framework tries to render a frame immediately.
///
/// Since this will probably call [PlatformWindow.render] outside of an
/// animation frame, the render will not be actually presented, but just to warm
/// up the framework.
ui.VoidCallback? requestWarmUpFrameCallback;
ScheduleWarmUpFrameCallback? scheduleWarmUpFrameCallback;

/// Signature of functions added as a listener to high contrast changes
typedef HighContrastListener = void Function(bool enabled);
Expand Down Expand Up @@ -779,11 +783,11 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher {
}

@override
void requestWarmUpFrame() {
if (requestWarmUpFrameCallback == null) {
throw Exception('requestWarmUpFrameCallback must be initialized first.');
void scheduleWarmUpFrame(ui.VoidCallback beginFrameCallback, ui.VoidCallback drawFrameCallback) {
if (scheduleWarmUpFrameCallback == null) {
throw Exception('scheduleWarmUpFrameCallback must be initialized first.');
}
requestWarmUpFrameCallback!();
scheduleWarmUpFrameCallback!(beginFrameCallback, drawFrameCallback);
}

/// Updates the application's rendering on the GPU with the newly provided
Expand Down
4 changes: 2 additions & 2 deletions runtime/runtime_controller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -341,8 +341,8 @@ void RuntimeController::ScheduleFrame() {
}

// |PlatformConfigurationClient|
void RuntimeController::RequestWarmUpFrame() {
client_.RequestWarmUpFrame();
void RuntimeController::EndWarmUpFrame() {
client_.EndWarmUpFrame();
}

// |PlatformConfigurationClient|
Expand Down
2 changes: 1 addition & 1 deletion runtime/runtime_controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -658,7 +658,7 @@ class RuntimeController : public PlatformConfigurationClient {
void ScheduleFrame() override;

// |PlatformConfigurationClient|
void RequestWarmUpFrame() override;
void EndWarmUpFrame() override;

// |PlatformConfigurationClient|
void Render(Scene* scene, double width, double height) override;
Expand Down
2 changes: 1 addition & 1 deletion runtime/runtime_delegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class RuntimeDelegate {

virtual void ScheduleFrame(bool regenerate_layer_trees = true) = 0;

virtual void RequestWarmUpFrame() = 0;
virtual void EndWarmUpFrame() = 0;

virtual void Render(std::unique_ptr<flutter::LayerTree> layer_tree,
float device_pixel_ratio) = 0;
Expand Down
16 changes: 4 additions & 12 deletions shell/common/animator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -264,18 +264,10 @@ void Animator::AwaitVSync() {
}
}

void Animator::RequestWarmUpFrame() {
TRACE_EVENT_ASYNC_BEGIN0("flutter", "Forced Frame Request Pending",
frame_request_number_);
regenerate_layer_trees_ = true;

const fml::TimePoint frame_start_time = fml::TimePoint::Now();
const fml::TimePoint frame_target_time = frame_start_time;

std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder =
std::make_unique<FrameTimingsRecorder>();
frame_timings_recorder->RecordVsync(frame_start_time, frame_target_time);
BeginFrame(std::move(frame_timings_recorder));
void Animator::EndWarmUpFrame() {
// Do nothing. The warm up frame does not need any additional work to end the
// frame for now. This will change once the pipeline supports multi-view.
// https://github.com/flutter/flutter/issues/142851
}

void Animator::ScheduleSecondaryVsyncCallback(uintptr_t id,
Expand Down
2 changes: 1 addition & 1 deletion shell/common/animator.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class Animator final {

void RequestFrame(bool regenerate_layer_trees = true);

void RequestWarmUpFrame();
void EndWarmUpFrame();

//--------------------------------------------------------------------------
/// @brief Tells the Animator that this frame needs to render another view.
Expand Down
4 changes: 2 additions & 2 deletions shell/common/engine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -462,8 +462,8 @@ void Engine::ScheduleFrame(bool regenerate_layer_trees) {
animator_->RequestFrame(regenerate_layer_trees);
}

void Engine::RequestWarmUpFrame() {
animator_->RequestWarmUpFrame();
void Engine::EndWarmUpFrame() {
animator_->EndWarmUpFrame();
}

void Engine::Render(std::unique_ptr<flutter::LayerTree> layer_tree,
Expand Down
2 changes: 1 addition & 1 deletion shell/common/engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -838,7 +838,7 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate {
void ScheduleFrame() { ScheduleFrame(true); }

// |RuntimeDelegate|
void RequestWarmUpFrame() override;
void EndWarmUpFrame() override;

// |RuntimeDelegate|
FontCollection& GetFontCollection() override;
Expand Down
2 changes: 1 addition & 1 deletion shell/common/engine_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class MockRuntimeDelegate : public RuntimeDelegate {
public:
MOCK_METHOD(std::string, DefaultRouteName, (), (override));
MOCK_METHOD(void, ScheduleFrame, (bool), (override));
MOCK_METHOD(void, RequestWarmUpFrame, (), (override));
MOCK_METHOD(void, EndWarmUpFrame, (), (override));
MOCK_METHOD(void,
Render,
(std::unique_ptr<flutter::LayerTree>, float),
Expand Down