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

Commit 9023d23

Browse files
authored
Reland: Multiview pipeline (#47234)
This PR relands #44473. The previous PR was immediately reverted after merging because we found that the PR could cause illegal renders to be skipped on debug builds but crash the app on release builds. This PR makes the `Animator::Render` skip illegal renders as well. This should not be the final shape of this feature, and thus a TODO is added. [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
1 parent abeab89 commit 9023d23

28 files changed

+742
-193
lines changed

flow/frame_timings.cc

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,8 +254,30 @@ const char* FrameTimingsRecorder::GetFrameNumberTraceArg() const {
254254
return frame_number_trace_arg_val_.c_str();
255255
}
256256

257+
static const char* StateToString(FrameTimingsRecorder::State state) {
258+
#ifndef NDEBUG
259+
switch (state) {
260+
case FrameTimingsRecorder::State::kUninitialized:
261+
return "kUninitialized";
262+
case FrameTimingsRecorder::State::kVsync:
263+
return "kVsync";
264+
case FrameTimingsRecorder::State::kBuildStart:
265+
return "kBuildStart";
266+
case FrameTimingsRecorder::State::kBuildEnd:
267+
return "kBuildEnd";
268+
case FrameTimingsRecorder::State::kRasterStart:
269+
return "kRasterStart";
270+
case FrameTimingsRecorder::State::kRasterEnd:
271+
return "kRasterEnd";
272+
};
273+
FML_UNREACHABLE();
274+
#endif
275+
return "";
276+
}
277+
257278
void FrameTimingsRecorder::AssertInState(State state) const {
258-
FML_DCHECK(state_ == state);
279+
FML_DCHECK(state_ == state) << "Expected state " << StateToString(state)
280+
<< ", actual state " << StateToString(state_);
259281
}
260282

261283
} // namespace flutter

flow/frame_timings.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class FrameTimingsRecorder {
3131
public:
3232
/// Various states that the recorder can be in. When created the recorder is
3333
/// in an unitialized state and transtions in sequential order of the states.
34+
// After adding an item to this enum, modify StateToString accordingly.
3435
enum class State : uint32_t {
3536
kUninitialized,
3637
kVsync,
@@ -121,6 +122,8 @@ class FrameTimingsRecorder {
121122
///
122123
/// Instead of adding a `GetState` method and asserting on the result, this
123124
/// method prevents other logic from relying on the state.
125+
///
126+
/// In opt builds, this call is a no-op.
124127
void AssertInState(State state) const;
125128

126129
private:

impeller/entity/contents/filters/gaussian_blur_filter_contents.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ namespace impeller {
2626
DirectionalGaussianBlurFilterContents::DirectionalGaussianBlurFilterContents() =
2727
default;
2828

29-
DirectionalGaussianBlurFilterContents::
30-
~DirectionalGaussianBlurFilterContents() = default;
29+
DirectionalGaussianBlurFilterContents::~
30+
DirectionalGaussianBlurFilterContents() = default;
3131

3232
void DirectionalGaussianBlurFilterContents::SetSigma(Sigma sigma) {
3333
blur_sigma_ = sigma;

lib/ui/dart_ui.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ typedef CanvasPath Path;
9898
V(NativeStringAttribute::initSpellOutStringAttribute, 3) \
9999
V(PlatformConfigurationNativeApi::DefaultRouteName, 0) \
100100
V(PlatformConfigurationNativeApi::ScheduleFrame, 0) \
101-
V(PlatformConfigurationNativeApi::Render, 1) \
101+
V(PlatformConfigurationNativeApi::Render, 2) \
102102
V(PlatformConfigurationNativeApi::UpdateSemantics, 1) \
103103
V(PlatformConfigurationNativeApi::SetNeedsReportTimings, 1) \
104104
V(PlatformConfigurationNativeApi::SetIsolateDebugName, 1) \

lib/ui/painting/image_dispose_unittests.cc

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#define FML_USED_ON_EMBEDDER
66

77
#include "flutter/common/task_runners.h"
8+
#include "flutter/fml/synchronization/count_down_latch.h"
89
#include "flutter/fml/synchronization/waitable_event.h"
910
#include "flutter/lib/ui/painting/canvas.h"
1011
#include "flutter/lib/ui/painting/image.h"
@@ -57,6 +58,10 @@ TEST_F(ImageDisposeTest, ImageReleasedAfterFrameAndDisposePictureAndLayer) {
5758
};
5859

5960
Settings settings = CreateSettingsForFixture();
61+
fml::CountDownLatch frame_latch{2};
62+
settings.frame_rasterized_callback = [&frame_latch](const FrameTiming& t) {
63+
frame_latch.CountDown();
64+
};
6065
auto task_runner = CreateNewThread();
6166
TaskRunners task_runners("test", // label
6267
GetCurrentTaskRunner(), // platform
@@ -83,12 +88,15 @@ TEST_F(ImageDisposeTest, ImageReleasedAfterFrameAndDisposePictureAndLayer) {
8388
shell->RunEngine(std::move(configuration), [&](auto result) {
8489
ASSERT_EQ(result, Engine::RunStatus::Success);
8590
});
86-
8791
message_latch_.Wait();
8892

8993
ASSERT_TRUE(current_display_list_);
9094
ASSERT_TRUE(current_image_);
9195

96+
// Wait for 2 frames to be rasterized. The 2nd frame releases resources of the
97+
// 1st frame.
98+
frame_latch.Wait();
99+
92100
// Force a drain the SkiaUnrefQueue. The engine does this normally as frames
93101
// pump, but we force it here to make the test more deterministic.
94102
message_latch_.Reset();

lib/ui/window.dart

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -356,18 +356,20 @@ class FlutterView {
356356
void render(Scene scene) {
357357
// Duplicated calls or calls outside of onBeginFrame/onDrawFrame (indicated
358358
// by _debugRenderedViews being null) are ignored. See _debugRenderedViews.
359+
// TODO(dkwingsmt): We should change this skip into an assertion.
360+
// https://github.com/flutter/flutter/issues/137073
359361
bool validRender = true;
360362
assert(() {
361363
validRender = platformDispatcher._debugRenderedViews?.add(this) ?? false;
362364
return true;
363365
}());
364366
if (validRender) {
365-
_render(scene as _NativeScene);
367+
_render(viewId, scene as _NativeScene);
366368
}
367369
}
368370

369-
@Native<Void Function(Pointer<Void>)>(symbol: 'PlatformConfigurationNativeApi::Render')
370-
external static void _render(_NativeScene scene);
371+
@Native<Void Function(Int64, Pointer<Void>)>(symbol: 'PlatformConfigurationNativeApi::Render')
372+
external static void _render(int viewId, _NativeScene scene);
371373

372374
/// Change the retained semantics data about this [FlutterView].
373375
///

lib/ui/window/platform_configuration.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -449,9 +449,10 @@ void PlatformConfiguration::CompletePlatformMessageResponse(
449449
response->Complete(std::make_unique<fml::DataMapping>(std::move(data)));
450450
}
451451

452-
void PlatformConfigurationNativeApi::Render(Scene* scene) {
452+
void PlatformConfigurationNativeApi::Render(int64_t view_id, Scene* scene) {
453453
UIDartState::ThrowIfUIOperationsProhibited();
454-
UIDartState::Current()->platform_configuration()->client()->Render(scene);
454+
UIDartState::Current()->platform_configuration()->client()->Render(view_id,
455+
scene);
455456
}
456457

457458
void PlatformConfigurationNativeApi::SetNeedsReportTimings(bool value) {

lib/ui/window/platform_configuration.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ class PlatformConfigurationClient {
6969
/// @brief Updates the client's rendering on the GPU with the newly
7070
/// provided Scene.
7171
///
72-
virtual void Render(Scene* scene) = 0;
72+
virtual void Render(int64_t view_id, Scene* scene) = 0;
7373

7474
//--------------------------------------------------------------------------
7575
/// @brief Receives an updated semantics tree from the Framework.
@@ -557,7 +557,7 @@ class PlatformConfigurationNativeApi {
557557

558558
static void ScheduleFrame();
559559

560-
static void Render(Scene* scene);
560+
static void Render(int64_t view_id, Scene* scene);
561561

562562
static void UpdateSemantics(SemanticsUpdate* update);
563563

lib/ui/window/platform_configuration_unittests.cc

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,166 @@
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"
1819

1920
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+
20178
namespace testing {
21179

22180
class PlatformConfigurationTest : public ShellTest {};

runtime/dart_vm.cc

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -219,22 +219,22 @@ static std::vector<const char*> ProfilingFlags(bool enable_profiling) {
219219
// flags.
220220
if (enable_profiling) {
221221
return {
222-
// This is the default. But just be explicit.
223-
"--profiler",
224-
// This instructs the profiler to walk C++ frames, and to include
225-
// them in the profile.
226-
"--profile-vm",
222+
// This is the default. But just be explicit.
223+
"--profiler",
224+
// This instructs the profiler to walk C++ frames, and to include
225+
// them in the profile.
226+
"--profile-vm",
227227
#if FML_OS_IOS && FML_ARCH_CPU_ARM_FAMILY && FML_ARCH_CPU_ARMEL
228-
// Set the profiler interrupt period to 500Hz instead of the
229-
// default 1000Hz on 32-bit iOS devices to reduce average and worst
230-
// case frame build times.
231-
//
232-
// Note: profile_period is time in microseconds between sampling
233-
// events, not frequency. Frequency is calculated 1/period (or
234-
// 1,000,000 / 2,000 -> 500Hz in this case).
235-
"--profile_period=2000",
228+
// Set the profiler interrupt period to 500Hz instead of the
229+
// default 1000Hz on 32-bit iOS devices to reduce average and worst
230+
// case frame build times.
231+
//
232+
// Note: profile_period is time in microseconds between sampling
233+
// events, not frequency. Frequency is calculated 1/period (or
234+
// 1,000,000 / 2,000 -> 500Hz in this case).
235+
"--profile_period=2000",
236236
#else
237-
"--profile_period=1000",
237+
"--profile_period=1000",
238238
#endif // FML_OS_IOS && FML_ARCH_CPU_ARM_FAMILY && FML_ARCH_CPU_ARMEL
239239
};
240240
} else {

0 commit comments

Comments
 (0)