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

Commit fe0c92a

Browse files
committed
Additional changes
1 parent aca468a commit fe0c92a

14 files changed

+238
-168
lines changed

lib/ui/dart_ui.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ typedef CanvasPath Path;
9898
V(NativeStringAttribute::initSpellOutStringAttribute) \
9999
V(PlatformConfigurationNativeApi::DefaultRouteName) \
100100
V(PlatformConfigurationNativeApi::ScheduleFrame) \
101+
V(PlatformConfigurationNativeApi::ForceSyncFrame) \
101102
V(PlatformConfigurationNativeApi::Render) \
102103
V(PlatformConfigurationNativeApi::UpdateSemantics) \
103104
V(PlatformConfigurationNativeApi::SetNeedsReportTimings) \

lib/ui/platform_dispatcher.dart

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -801,11 +801,36 @@ class PlatformDispatcher {
801801
///
802802
/// * [SchedulerBinding], the Flutter framework class which manages the
803803
/// scheduling of frames.
804+
/// * [forceSyncFrame], a similar method that is used in rare cases that
805+
/// a frame must be rendered immediately.
804806
void scheduleFrame() => _scheduleFrame();
805807

806808
@Native<Void Function()>(symbol: 'PlatformConfigurationNativeApi::ScheduleFrame')
807809
external static void _scheduleFrame();
808810

811+
/// Immediately render a frame by invoking the [onBeginFrame] and
812+
/// [onDrawFrame] callbacks synchronously.
813+
///
814+
/// This method performs the same computation for a frame as [scheduleFrame]
815+
/// does, but instead of doing so at an appropriate opportunity, the render is
816+
/// completed synchronously within this call.
817+
///
818+
/// Prefer [scheduleFrame] to update the display in normal operation. The
819+
/// [forceSyncFrame] method is designed for situations that require a frame is
820+
/// rendered as soon as possible, even at the cost of rendering quality. An
821+
/// example of using this method is [SchedulerBinding.scheduleWarmUpFrame],
822+
/// which is called during application startup so that the first frame can be
823+
/// presented to the screen a few extra milliseconds earlier.
824+
///
825+
/// See also:
826+
///
827+
/// * [SchedulerBinding.scheduleWarmUpFrame], which uses this method.
828+
/// * [scheduleFrame].
829+
void forceSyncFrame() => _forceSyncFrame();
830+
831+
@Native<Void Function()>(symbol: 'PlatformConfigurationNativeApi::ForceSyncFrame')
832+
external static void _forceSyncFrame();
833+
809834
/// Additional accessibility features that may be enabled by the platform.
810835
AccessibilityFeatures get accessibilityFeatures => _configuration.accessibilityFeatures;
811836

lib/ui/window/platform_configuration.cc

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -453,9 +453,6 @@ void PlatformConfigurationNativeApi::Render(int64_t view_id,
453453
Scene* scene,
454454
double width,
455455
double height) {
456-
// TODO(dkwingsmt): Currently only supports a single window.
457-
// See https://github.com/flutter/flutter/issues/135530, item 2.
458-
FML_DCHECK(view_id == kFlutterImplicitViewId);
459456
UIDartState::ThrowIfUIOperationsProhibited();
460457
UIDartState::Current()->platform_configuration()->client()->Render(
461458
view_id, scene, width, height);
@@ -589,6 +586,11 @@ void PlatformConfigurationNativeApi::ScheduleFrame() {
589586
UIDartState::Current()->platform_configuration()->client()->ScheduleFrame();
590587
}
591588

589+
void PlatformConfigurationNativeApi::ForceSyncFrame() {
590+
UIDartState::ThrowIfUIOperationsProhibited();
591+
UIDartState::Current()->platform_configuration()->client()->ForceSyncFrame();
592+
}
593+
592594
void PlatformConfigurationNativeApi::UpdateSemantics(SemanticsUpdate* update) {
593595
UIDartState::ThrowIfUIOperationsProhibited();
594596
UIDartState::Current()->platform_configuration()->client()->UpdateSemantics(

lib/ui/window/platform_configuration.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ class PlatformConfigurationClient {
6565
///
6666
virtual void ScheduleFrame() = 0;
6767

68+
//--------------------------------------------------------------------------
69+
/// @brief
70+
///
71+
virtual void ForceSyncFrame() = 0;
72+
6873
//--------------------------------------------------------------------------
6974
/// @brief Updates the client's rendering on the GPU with the newly
7075
/// provided Scene.
@@ -560,6 +565,8 @@ class PlatformConfigurationNativeApi {
560565

561566
static void ScheduleFrame();
562567

568+
static void ForceSyncFrame();
569+
563570
static void Render(int64_t view_id,
564571
Scene* scene,
565572
double width,

lib/ui/window/platform_configuration_unittests.cc

Lines changed: 0 additions & 158 deletions
Original file line numberDiff line numberDiff line change
@@ -15,166 +15,8 @@
1515
#include "flutter/shell/common/shell_test.h"
1616
#include "flutter/shell/common/thread_host.h"
1717
#include "flutter/testing/testing.h"
18-
#include "gmock/gmock.h"
1918

2019
namespace flutter {
21-
22-
namespace {
23-
24-
static constexpr int64_t kImplicitViewId = 0;
25-
26-
static void PostSync(const fml::RefPtr<fml::TaskRunner>& task_runner,
27-
const fml::closure& task) {
28-
fml::AutoResetWaitableEvent latch;
29-
fml::TaskRunner::RunNowOrPostTask(task_runner, [&latch, &task] {
30-
task();
31-
latch.Signal();
32-
});
33-
latch.Wait();
34-
}
35-
36-
class MockRuntimeDelegate : public RuntimeDelegate {
37-
public:
38-
MOCK_METHOD(std::string, DefaultRouteName, (), (override));
39-
MOCK_METHOD(void, ScheduleFrame, (bool), (override));
40-
MOCK_METHOD(void,
41-
Render,
42-
(int64_t, std::unique_ptr<flutter::LayerTree>, float),
43-
(override));
44-
MOCK_METHOD(void,
45-
UpdateSemantics,
46-
(SemanticsNodeUpdates, CustomAccessibilityActionUpdates),
47-
(override));
48-
MOCK_METHOD(void,
49-
HandlePlatformMessage,
50-
(std::unique_ptr<PlatformMessage>),
51-
(override));
52-
MOCK_METHOD(FontCollection&, GetFontCollection, (), (override));
53-
MOCK_METHOD(std::shared_ptr<AssetManager>, GetAssetManager, (), (override));
54-
MOCK_METHOD(void, OnRootIsolateCreated, (), (override));
55-
MOCK_METHOD(void,
56-
UpdateIsolateDescription,
57-
(const std::string, int64_t),
58-
(override));
59-
MOCK_METHOD(void, SetNeedsReportTimings, (bool), (override));
60-
MOCK_METHOD(std::unique_ptr<std::vector<std::string>>,
61-
ComputePlatformResolvedLocale,
62-
(const std::vector<std::string>&),
63-
(override));
64-
MOCK_METHOD(void, RequestDartDeferredLibrary, (intptr_t), (override));
65-
MOCK_METHOD(std::weak_ptr<PlatformMessageHandler>,
66-
GetPlatformMessageHandler,
67-
(),
68-
(const, override));
69-
MOCK_METHOD(void, SendChannelUpdate, (std::string, bool), (override));
70-
MOCK_METHOD(double,
71-
GetScaledFontSize,
72-
(double font_size, int configuration_id),
73-
(const, override));
74-
};
75-
76-
class MockPlatformMessageHandler : public PlatformMessageHandler {
77-
public:
78-
MOCK_METHOD(void,
79-
HandlePlatformMessage,
80-
(std::unique_ptr<PlatformMessage> message),
81-
(override));
82-
MOCK_METHOD(bool,
83-
DoesHandlePlatformMessageOnPlatformThread,
84-
(),
85-
(const, override));
86-
MOCK_METHOD(void,
87-
InvokePlatformMessageResponseCallback,
88-
(int response_id, std::unique_ptr<fml::Mapping> mapping),
89-
(override));
90-
MOCK_METHOD(void,
91-
InvokePlatformMessageEmptyResponseCallback,
92-
(int response_id),
93-
(override));
94-
};
95-
96-
// A class that can launch a RuntimeController with the specified
97-
// RuntimeDelegate.
98-
//
99-
// To use this class, contruct this class with Create, call LaunchRootIsolate,
100-
// and use the controller with ControllerTaskSync().
101-
class RuntimeControllerContext {
102-
public:
103-
using ControllerCallback = std::function<void(RuntimeController&)>;
104-
105-
[[nodiscard]] static std::unique_ptr<RuntimeControllerContext> Create(
106-
Settings settings, //
107-
const TaskRunners& task_runners, //
108-
RuntimeDelegate& client) {
109-
auto [vm, isolate_snapshot] = Shell::InferVmInitDataFromSettings(settings);
110-
FML_CHECK(vm) << "Must be able to initialize the VM.";
111-
// Construct the class with `new` because `make_unique` has no access to the
112-
// private constructor.
113-
RuntimeControllerContext* raw_pointer = new RuntimeControllerContext(
114-
settings, task_runners, client, std::move(vm), isolate_snapshot);
115-
return std::unique_ptr<RuntimeControllerContext>(raw_pointer);
116-
}
117-
118-
~RuntimeControllerContext() {
119-
PostSync(task_runners_.GetUITaskRunner(),
120-
[&]() { runtime_controller_.reset(); });
121-
}
122-
123-
// Launch the root isolate. The post_launch callback will be executed in the
124-
// same UI task, which can be used to create initial views.
125-
void LaunchRootIsolate(RunConfiguration& configuration,
126-
ControllerCallback post_launch) {
127-
PostSync(task_runners_.GetUITaskRunner(), [&]() {
128-
bool launch_success = runtime_controller_->LaunchRootIsolate(
129-
settings_, //
130-
[]() {}, //
131-
configuration.GetEntrypoint(), //
132-
configuration.GetEntrypointLibrary(), //
133-
configuration.GetEntrypointArgs(), //
134-
configuration.TakeIsolateConfiguration()); //
135-
ASSERT_TRUE(launch_success);
136-
post_launch(*runtime_controller_);
137-
});
138-
}
139-
140-
// Run a task that operates the RuntimeController on the UI thread, and wait
141-
// for the task to end.
142-
void ControllerTaskSync(ControllerCallback task) {
143-
ASSERT_TRUE(runtime_controller_);
144-
ASSERT_TRUE(task);
145-
PostSync(task_runners_.GetUITaskRunner(),
146-
[&]() { task(*runtime_controller_); });
147-
}
148-
149-
private:
150-
RuntimeControllerContext(const Settings& settings,
151-
const TaskRunners& task_runners,
152-
RuntimeDelegate& client,
153-
DartVMRef vm,
154-
fml::RefPtr<const DartSnapshot> isolate_snapshot)
155-
: settings_(settings),
156-
task_runners_(task_runners),
157-
isolate_snapshot_(std::move(isolate_snapshot)),
158-
vm_(std::move(vm)),
159-
runtime_controller_(std::make_unique<RuntimeController>(
160-
client,
161-
&vm_,
162-
std::move(isolate_snapshot_),
163-
settings.idle_notification_callback, // idle notification callback
164-
flutter::PlatformData(), // platform data
165-
settings.isolate_create_callback, // isolate create callback
166-
settings.isolate_shutdown_callback, // isolate shutdown callback
167-
settings.persistent_isolate_data, // persistent isolate data
168-
UIDartState::Context{task_runners})) {}
169-
170-
Settings settings_;
171-
TaskRunners task_runners_;
172-
fml::RefPtr<const DartSnapshot> isolate_snapshot_;
173-
DartVMRef vm_;
174-
std::unique_ptr<RuntimeController> runtime_controller_;
175-
};
176-
} // namespace
177-
17820
namespace testing {
17921

18022
class PlatformConfigurationTest : public ShellTest {};

runtime/runtime_controller.cc

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ bool RuntimeController::SetAccessibilityFeatures(int32_t flags) {
226226

227227
bool RuntimeController::BeginFrame(fml::TimePoint frame_time,
228228
uint64_t frame_number) {
229+
MarkAsFrameBorder();
229230
if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
230231
platform_configuration->BeginFrame(frame_time, frame_number);
231232
return true;
@@ -340,6 +341,10 @@ void RuntimeController::ScheduleFrame() {
340341
client_.ScheduleFrame();
341342
}
342343

344+
void RuntimeController::ForceSyncFrame() {
345+
client_.ForceSyncFrame();
346+
}
347+
343348
// |PlatformConfigurationClient|
344349
void RuntimeController::Render(int64_t view_id,
345350
Scene* scene,
@@ -352,6 +357,21 @@ void RuntimeController::Render(int64_t view_id,
352357
}
353358
client_.Render(view_id, scene->takeLayerTree(width, height),
354359
view_metrics->device_pixel_ratio);
360+
rendered_views_during_frame_.insert(view_id);
361+
CheckIfAllViewsRendered();
362+
}
363+
364+
void RuntimeController::MarkAsFrameBorder() {
365+
rendered_views_during_frame_.clear();
366+
}
367+
368+
void RuntimeController::CheckIfAllViewsRendered() {
369+
if (rendered_views_during_frame_.size() != 0 &&
370+
rendered_views_during_frame_.size() ==
371+
platform_data_.viewport_metrics_for_views.size()) {
372+
client_.OnAllViewsRendered();
373+
MarkAsFrameBorder();
374+
}
355375
}
356376

357377
// |PlatformConfigurationClient|

runtime/runtime_controller.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,10 @@ class RuntimeController : public PlatformConfigurationClient {
633633
std::string variant_code;
634634
};
635635

636+
void MarkAsFrameBorder();
637+
638+
void CheckIfAllViewsRendered();
639+
636640
RuntimeDelegate& client_;
637641
DartVM* const vm_;
638642
fml::RefPtr<const DartSnapshot> isolate_snapshot_;
@@ -647,6 +651,17 @@ class RuntimeController : public PlatformConfigurationClient {
647651
UIDartState::Context context_;
648652
bool has_flushed_runtime_state_ = false;
649653

654+
// Tracks the views that have been called `Render` during a frame.
655+
//
656+
// If all registered views (see `AddView`) have been rendered, then the end of
657+
// frame will be called immediately, submitting the views to the pipeline.
658+
//
659+
// This is a transitional solution to keep the warm up frame rendered in a
660+
// multiview setup, before the Framework uses forceSyncFrame.
661+
// TODO(dkwingsmt): Use forceSyncFrame to render the warm up frame.
662+
// https://github.com/flutter/flutter/issues/142851.
663+
std::unordered_set<uint64_t> rendered_views_during_frame_;
664+
650665
PlatformConfiguration* GetPlatformConfigurationIfAvailable();
651666

652667
bool FlushRuntimeStateToIsolate();
@@ -657,6 +672,9 @@ class RuntimeController : public PlatformConfigurationClient {
657672
// |PlatformConfigurationClient|
658673
void ScheduleFrame() override;
659674

675+
// |PlatformConfigurationClient|
676+
void ForceSyncFrame() override;
677+
660678
// |PlatformConfigurationClient|
661679
void Render(int64_t view_id,
662680
Scene* scene,

runtime/runtime_delegate.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,14 @@ class RuntimeDelegate {
2525

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

28+
virtual void ForceSyncFrame() = 0;
29+
2830
virtual void Render(int64_t view_id,
2931
std::unique_ptr<flutter::LayerTree> layer_tree,
3032
float device_pixel_ratio) = 0;
3133

34+
virtual void OnAllViewsRendered() = 0;
35+
3236
virtual void UpdateSemantics(SemanticsNodeUpdates update,
3337
CustomAccessibilityActionUpdates actions) = 0;
3438

0 commit comments

Comments
 (0)