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

Commit 54dccde

Browse files
authored
Reland 5: Multiview pipeline (#51186)
This relands #50931. The crash that caused the 4th revert has been fixed by flutter/flutter#144212. [There has been discussion](#51019) on why the benchmark in previous attempts show significant drop in build time. This PR addresses it using option a as described in [this comment](#51186 (comment)). This PR also addresses flutter/flutter#144584 with option 1. A test is added. [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
1 parent 03ebd64 commit 54dccde

25 files changed

+1165
-415
lines changed

ci/licenses_golden/excluded_files

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@
252252
../../../flutter/shell/common/base64_unittests.cc
253253
../../../flutter/shell/common/context_options_unittests.cc
254254
../../../flutter/shell/common/dl_op_spy_unittests.cc
255+
../../../flutter/shell/common/engine_animator_unittests.cc
255256
../../../flutter/shell/common/engine_unittests.cc
256257
../../../flutter/shell/common/fixtures
257258
../../../flutter/shell/common/input_events_unittests.cc

flow/frame_timings.cc

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,31 @@
1313

1414
namespace flutter {
1515

16+
namespace {
17+
18+
const char* StateToString(FrameTimingsRecorder::State state) {
19+
#ifndef NDEBUG
20+
switch (state) {
21+
case FrameTimingsRecorder::State::kUninitialized:
22+
return "kUninitialized";
23+
case FrameTimingsRecorder::State::kVsync:
24+
return "kVsync";
25+
case FrameTimingsRecorder::State::kBuildStart:
26+
return "kBuildStart";
27+
case FrameTimingsRecorder::State::kBuildEnd:
28+
return "kBuildEnd";
29+
case FrameTimingsRecorder::State::kRasterStart:
30+
return "kRasterStart";
31+
case FrameTimingsRecorder::State::kRasterEnd:
32+
return "kRasterEnd";
33+
};
34+
FML_UNREACHABLE();
35+
#endif
36+
return "";
37+
}
38+
39+
} // namespace
40+
1641
std::atomic<uint64_t> FrameTimingsRecorder::frame_number_gen_ = {1};
1742

1843
FrameTimingsRecorder::FrameTimingsRecorder()
@@ -255,7 +280,8 @@ const char* FrameTimingsRecorder::GetFrameNumberTraceArg() const {
255280
}
256281

257282
void FrameTimingsRecorder::AssertInState(State state) const {
258-
FML_DCHECK(state_ == state);
283+
FML_DCHECK(state_ == state) << "Expected state " << StateToString(state)
284+
<< ", actual state " << StateToString(state_);
259285
}
260286

261287
} // 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 release builds, this call is a no-op.
124127
void AssertInState(State state) const;
125128

126129
private:

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/platform_configuration.cc

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -453,12 +453,9 @@ 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(
461-
scene, width, height);
458+
view_id, scene, width, height);
462459
}
463460

464461
void PlatformConfigurationNativeApi::SetNeedsReportTimings(bool value) {

lib/ui/window/platform_configuration.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,10 @@ class PlatformConfigurationClient {
7777
/// @brief Updates the client's rendering on the GPU with the newly
7878
/// provided Scene.
7979
///
80-
virtual void Render(Scene* scene, double width, double height) = 0;
80+
virtual void Render(int64_t view_id,
81+
Scene* scene,
82+
double width,
83+
double height) = 0;
8184

8285
//--------------------------------------------------------------------------
8386
/// @brief Receives an updated semantics tree from the Framework.

runtime/dart_isolate_unittests.cc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -707,7 +707,10 @@ class FakePlatformConfigurationClient : public PlatformConfigurationClient {
707707
std::string DefaultRouteName() override { return ""; }
708708
void ScheduleFrame() override {}
709709
void EndWarmUpFrame() override {}
710-
void Render(Scene* scene, double width, double height) override {}
710+
void Render(int64_t view_id,
711+
Scene* scene,
712+
double width,
713+
double height) override {}
711714
void UpdateSemantics(SemanticsUpdate* update) override {}
712715
void HandlePlatformMessage(
713716
std::unique_ptr<PlatformMessage> message) override {}

runtime/runtime_controller.cc

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ RuntimeController::RuntimeController(
4747

4848
std::unique_ptr<RuntimeController> RuntimeController::Spawn(
4949
RuntimeDelegate& p_client,
50-
std::string advisory_script_uri,
51-
std::string advisory_script_entrypoint,
50+
const std::string& advisory_script_uri,
51+
const std::string& advisory_script_entrypoint,
5252
const std::function<void(int64_t)>& p_idle_notification_callback,
5353
const fml::closure& p_isolate_create_callback,
5454
const fml::closure& p_isolate_shutdown_callback,
@@ -57,13 +57,18 @@ std::unique_ptr<RuntimeController> RuntimeController::Spawn(
5757
fml::WeakPtr<ImageDecoder> image_decoder,
5858
fml::WeakPtr<ImageGeneratorRegistry> image_generator_registry,
5959
fml::TaskRunnerAffineWeakPtr<SnapshotDelegate> snapshot_delegate) const {
60-
UIDartState::Context spawned_context{
61-
context_.task_runners, std::move(snapshot_delegate),
62-
std::move(io_manager), context_.unref_queue,
63-
std::move(image_decoder), std::move(image_generator_registry),
64-
std::move(advisory_script_uri), std::move(advisory_script_entrypoint),
65-
context_.volatile_path_tracker, context_.concurrent_task_runner,
66-
context_.enable_impeller, context_.runtime_stage_backend};
60+
UIDartState::Context spawned_context{context_.task_runners,
61+
std::move(snapshot_delegate),
62+
std::move(io_manager),
63+
context_.unref_queue,
64+
std::move(image_decoder),
65+
std::move(image_generator_registry),
66+
advisory_script_uri,
67+
advisory_script_entrypoint,
68+
context_.volatile_path_tracker,
69+
context_.concurrent_task_runner,
70+
context_.enable_impeller,
71+
context_.runtime_stage_backend};
6772
auto result =
6873
std::make_unique<RuntimeController>(p_client, //
6974
vm_, //
@@ -226,6 +231,7 @@ bool RuntimeController::SetAccessibilityFeatures(int32_t flags) {
226231

227232
bool RuntimeController::BeginFrame(fml::TimePoint frame_time,
228233
uint64_t frame_number) {
234+
MarkAsFrameBorder();
229235
if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
230236
platform_configuration->BeginFrame(frame_time, frame_number);
231237
return true;
@@ -340,22 +346,37 @@ void RuntimeController::ScheduleFrame() {
340346
client_.ScheduleFrame();
341347
}
342348

343-
// |PlatformConfigurationClient|
344349
void RuntimeController::EndWarmUpFrame() {
345-
client_.EndWarmUpFrame();
350+
client_.OnAllViewsRendered();
346351
}
347352

348353
// |PlatformConfigurationClient|
349-
void RuntimeController::Render(Scene* scene, double width, double height) {
350-
// TODO(dkwingsmt): Currently only supports a single window.
351-
int64_t view_id = kFlutterImplicitViewId;
354+
void RuntimeController::Render(int64_t view_id,
355+
Scene* scene,
356+
double width,
357+
double height) {
352358
const ViewportMetrics* view_metrics =
353359
UIDartState::Current()->platform_configuration()->GetMetrics(view_id);
354360
if (view_metrics == nullptr) {
355361
return;
356362
}
357-
client_.Render(scene->takeLayerTree(width, height),
363+
client_.Render(view_id, scene->takeLayerTree(width, height),
358364
view_metrics->device_pixel_ratio);
365+
rendered_views_during_frame_.insert(view_id);
366+
CheckIfAllViewsRendered();
367+
}
368+
369+
void RuntimeController::MarkAsFrameBorder() {
370+
rendered_views_during_frame_.clear();
371+
}
372+
373+
void RuntimeController::CheckIfAllViewsRendered() {
374+
if (rendered_views_during_frame_.size() != 0 &&
375+
rendered_views_during_frame_.size() ==
376+
platform_data_.viewport_metrics_for_views.size()) {
377+
client_.OnAllViewsRendered();
378+
MarkAsFrameBorder();
379+
}
359380
}
360381

361382
// |PlatformConfigurationClient|

runtime/runtime_controller.h

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,8 @@ class RuntimeController : public PlatformConfigurationClient {
104104
///
105105
std::unique_ptr<RuntimeController> Spawn(
106106
RuntimeDelegate& p_client,
107-
std::string advisory_script_uri,
108-
std::string advisory_script_entrypoint,
107+
const std::string& advisory_script_uri,
108+
const std::string& advisory_script_entrypoint,
109109
const std::function<void(int64_t)>& idle_notification_callback,
110110
const fml::closure& isolate_create_callback,
111111
const fml::closure& isolate_shutdown_callback,
@@ -660,6 +660,26 @@ class RuntimeController : public PlatformConfigurationClient {
660660
std::shared_ptr<PlatformIsolateManager>(new PlatformIsolateManager());
661661
bool has_flushed_runtime_state_ = false;
662662

663+
// Tracks the views that have been called `Render` during a frame.
664+
//
665+
// If all views that have been registered by `AddView` have been called
666+
// `Render`, then the runtime controller notifies the client of the end of
667+
// frame immediately, allowing the client to submit the views to the pipeline
668+
// a bit earlier than having to wait for the end of `BeginFrame`. See also
669+
// `Animator::OnAllViewsRendered`.
670+
//
671+
// This mechanism fixes https://github.com/flutter/flutter/issues/144584 with
672+
// option 2 and
673+
// https://github.com/flutter/engine/pull/51186#issuecomment-1977820525 with
674+
// option a in most cases, except if there are multiple views and only part of
675+
// them are rendered.
676+
// TODO(dkwingsmt): Fix these problems for all cases.
677+
std::unordered_set<uint64_t> rendered_views_during_frame_;
678+
679+
void MarkAsFrameBorder();
680+
681+
void CheckIfAllViewsRendered();
682+
663683
PlatformConfiguration* GetPlatformConfigurationIfAvailable();
664684

665685
bool FlushRuntimeStateToIsolate();
@@ -674,7 +694,10 @@ class RuntimeController : public PlatformConfigurationClient {
674694
void EndWarmUpFrame() override;
675695

676696
// |PlatformConfigurationClient|
677-
void Render(Scene* scene, double width, double height) override;
697+
void Render(int64_t view_id,
698+
Scene* scene,
699+
double width,
700+
double height) override;
678701

679702
// |PlatformConfigurationClient|
680703
void UpdateSemantics(SemanticsUpdate* update) override;

runtime/runtime_delegate.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,10 @@ class RuntimeDelegate {
2525

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

28-
virtual void EndWarmUpFrame() = 0;
28+
virtual void OnAllViewsRendered() = 0;
2929

30-
virtual void Render(std::unique_ptr<flutter::LayerTree> layer_tree,
30+
virtual void Render(int64_t view_id,
31+
std::unique_ptr<flutter::LayerTree> layer_tree,
3132
float device_pixel_ratio) = 0;
3233

3334
virtual void UpdateSemantics(SemanticsNodeUpdates update,

shell/common/BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,7 @@ if (enable_unittests) {
310310
"base64_unittests.cc",
311311
"context_options_unittests.cc",
312312
"dl_op_spy_unittests.cc",
313+
"engine_animator_unittests.cc",
313314
"engine_unittests.cc",
314315
"input_events_unittests.cc",
315316
"persistent_cache_unittests.cc",

0 commit comments

Comments
 (0)