Skip to content

Commit 67fdd7e

Browse files
authored
Embedder API Support for display settings (flutter#21355)
Embedders can now notify shell during startup about the various displays and their corresponding settings. Adds a notion of Display update type which can later include chages to displays during runtime such as addition / removal / reconfiguration of displays. We also remove the responsibility of providing the refresh rate from `vsync_waiter` to `DisplayManager`. Rewires existing platform implementations of the said API to use `Shell::OnDisplayUpdate` to notify the display manager of the startup configuration. DisplayManager is also thread-safe to account for rasterizer and UI thread accesses.
1 parent aa8d5d4 commit 67fdd7e

27 files changed

+645
-136
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,9 @@ FILE: ../../../flutter/shell/common/animator_unittests.cc
599599
FILE: ../../../flutter/shell/common/canvas_spy.cc
600600
FILE: ../../../flutter/shell/common/canvas_spy.h
601601
FILE: ../../../flutter/shell/common/canvas_spy_unittests.cc
602+
FILE: ../../../flutter/shell/common/display.h
603+
FILE: ../../../flutter/shell/common/display_manager.cc
604+
FILE: ../../../flutter/shell/common/display_manager.h
602605
FILE: ../../../flutter/shell/common/engine.cc
603606
FILE: ../../../flutter/shell/common/engine.h
604607
FILE: ../../../flutter/shell/common/engine_unittests.cc

shell/common/BUILD.gn

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ source_set("common") {
6464
"animator.h",
6565
"canvas_spy.cc",
6666
"canvas_spy.h",
67+
"display.h",
68+
"display_manager.cc",
69+
"display_manager.h",
6770
"engine.cc",
6871
"engine.h",
6972
"isolate_configuration.cc",

shell/common/animator.cc

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,6 @@ Animator::Animator(Delegate& delegate,
5353

5454
Animator::~Animator() = default;
5555

56-
float Animator::GetDisplayRefreshRate() const {
57-
return waiter_->GetDisplayRefreshRate();
58-
}
59-
6056
void Animator::Stop() {
6157
paused_ = true;
6258
}

shell/common/animator.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,6 @@ class Animator final {
4747

4848
~Animator();
4949

50-
float GetDisplayRefreshRate() const;
51-
5250
void RequestFrame(bool regenerate_layer_tree = true);
5351

5452
void Render(std::unique_ptr<flutter::LayerTree> layer_tree);

shell/common/display.h

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#ifndef FLUTTER_SHELL_COMMON_DISPLAY_H_
6+
#define FLUTTER_SHELL_COMMON_DISPLAY_H_
7+
8+
#include <optional>
9+
10+
namespace flutter {
11+
12+
/// Unique ID per display that is stable until the Flutter application restarts.
13+
/// See also: `flutter::Display`
14+
typedef uint64_t DisplayId;
15+
16+
/// To be used when the display refresh rate is unknown.
17+
static constexpr double kUnknownDisplayRefreshRate = 0;
18+
19+
/// Display refers to a graphics hardware system consisting of a framebuffer,
20+
/// typically a monitor or a screen. This class holds the various display
21+
/// settings.
22+
class Display {
23+
public:
24+
//------------------------------------------------------------------------------
25+
/// @brief Construct a new Display object in case where the display id of the
26+
/// display is known. In cases where there is more than one display, every
27+
/// display is expected to have a display id.
28+
///
29+
Display(DisplayId display_id, double refresh_rate)
30+
: display_id_(display_id), refresh_rate_(refresh_rate) {}
31+
32+
//------------------------------------------------------------------------------
33+
/// @brief Construct a new Display object when there is only a single display.
34+
/// When there are multiple displays, every display must have a display id.
35+
///
36+
explicit Display(double refresh_rate)
37+
: display_id_({}), refresh_rate_(refresh_rate) {}
38+
39+
~Display() = default;
40+
41+
// Get the display's maximum refresh rate in the unit of frame per second.
42+
// Return `kUnknownDisplayRefreshRate` if the refresh rate is unknown.
43+
double GetRefreshRate() const { return refresh_rate_; }
44+
45+
/// Returns the `DisplayId` of the display.
46+
std::optional<DisplayId> GetDisplayId() const { return display_id_; }
47+
48+
private:
49+
std::optional<DisplayId> display_id_;
50+
double refresh_rate_;
51+
};
52+
53+
} // namespace flutter
54+
55+
#endif // FLUTTER_SHELL_COMMON_DISPLAY_H_

shell/common/display_manager.cc

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include "flutter/shell/common/display_manager.h"
6+
7+
#include "flutter/fml/logging.h"
8+
#include "flutter/fml/macros.h"
9+
10+
namespace flutter {
11+
12+
DisplayManager::DisplayManager() = default;
13+
14+
DisplayManager::~DisplayManager() = default;
15+
16+
double DisplayManager::GetMainDisplayRefreshRate() const {
17+
std::scoped_lock lock(displays_mutex_);
18+
if (displays_.empty()) {
19+
return kUnknownDisplayRefreshRate;
20+
} else {
21+
return displays_[0].GetRefreshRate();
22+
}
23+
}
24+
25+
void DisplayManager::HandleDisplayUpdates(DisplayUpdateType update_type,
26+
std::vector<Display> displays) {
27+
std::scoped_lock lock(displays_mutex_);
28+
CheckDisplayConfiguration(displays);
29+
switch (update_type) {
30+
case DisplayUpdateType::kStartup:
31+
FML_CHECK(displays_.empty());
32+
displays_ = displays;
33+
return;
34+
default:
35+
FML_CHECK(false) << "Unknown DisplayUpdateType.";
36+
}
37+
}
38+
39+
void DisplayManager::CheckDisplayConfiguration(
40+
std::vector<Display> displays) const {
41+
FML_CHECK(!displays.empty());
42+
if (displays.size() > 1) {
43+
for (auto& display : displays) {
44+
FML_CHECK(display.GetDisplayId().has_value());
45+
}
46+
}
47+
}
48+
49+
} // namespace flutter

shell/common/display_manager.h

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#ifndef FLUTTER_SHELL_COMMON_DISPLAY_MANAGER_H_
6+
#define FLUTTER_SHELL_COMMON_DISPLAY_MANAGER_H_
7+
8+
#include <mutex>
9+
#include <vector>
10+
11+
#include "flutter/shell/common/display.h"
12+
13+
namespace flutter {
14+
15+
/// The update type parameter that is passed to
16+
/// `DisplayManager::HandleDisplayUpdates`.
17+
enum class DisplayUpdateType {
18+
/// `flutter::Display`s that were active during start-up. A display is
19+
/// considered active if:
20+
/// 1. The frame buffer hardware is connected.
21+
/// 2. The display is drawable, e.g. it isn't being mirrored from another
22+
/// connected display or sleeping.
23+
kStartup
24+
};
25+
26+
/// Manages lifecycle of the connected displays. This class is thread-safe.
27+
class DisplayManager {
28+
public:
29+
DisplayManager();
30+
31+
~DisplayManager();
32+
33+
/// Returns the display refresh rate of the main display. In cases where there
34+
/// is only one display connected, it will return that. We do not yet support
35+
/// cases where there are multiple displays.
36+
///
37+
/// When there are no registered displays, it returns
38+
/// `kUnknownDisplayRefreshRate`.
39+
double GetMainDisplayRefreshRate() const;
40+
41+
/// Handles the display updates.
42+
void HandleDisplayUpdates(DisplayUpdateType update_type,
43+
std::vector<Display> displays);
44+
45+
private:
46+
/// Guards `displays_` vector.
47+
mutable std::mutex displays_mutex_;
48+
std::vector<Display> displays_;
49+
50+
/// Checks that the provided display configuration is valid. Currently this
51+
/// ensures that all the displays have an id in the case there are multiple
52+
/// displays. In case where there is a single display, it is valid for the
53+
/// display to not have an id.
54+
void CheckDisplayConfiguration(std::vector<Display> displays) const;
55+
};
56+
57+
} // namespace flutter
58+
59+
#endif // FLUTTER_SHELL_COMMON_DISPLAY_MANAGER_H_

shell/common/engine.cc

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,6 @@ Engine::Engine(Delegate& delegate,
9797

9898
Engine::~Engine() = default;
9999

100-
float Engine::GetDisplayRefreshRate() const {
101-
return animator_->GetDisplayRefreshRate();
102-
}
103-
104100
fml::WeakPtr<Engine> Engine::GetWeakPtr() const {
105101
return weak_factory_.GetWeakPtr();
106102
}

shell/common/engine.h

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "flutter/runtime/runtime_controller.h"
2525
#include "flutter/runtime/runtime_delegate.h"
2626
#include "flutter/shell/common/animator.h"
27+
#include "flutter/shell/common/display_manager.h"
2728
#include "flutter/shell/common/platform_view.h"
2829
#include "flutter/shell/common/pointer_data_dispatcher.h"
2930
#include "flutter/shell/common/rasterizer.h"
@@ -328,30 +329,6 @@ class Engine final : public RuntimeDelegate,
328329
///
329330
~Engine() override;
330331

331-
//----------------------------------------------------------------------------
332-
/// @brief Gets the refresh rate in frames per second of the vsync waiter
333-
/// used by the animator managed by this engine. This information
334-
/// is purely advisory and is not used by any component. It is
335-
/// only used by the tooling to visualize frame performance.
336-
///
337-
/// @attention The display refresh rate is useless for frame scheduling
338-
/// because it can vary and more accurate frame specific
339-
/// information is given to the engine by the vsync waiter
340-
/// already. However, this call is used by the tooling to ask very
341-
/// high level questions about display refresh rate. For example,
342-
/// "Is the display 60 or 120Hz?". This information is quite
343-
/// unreliable (not available immediately on launch on some
344-
/// platforms), variable and advisory. It must not be used by any
345-
/// component that claims to use it to perform accurate frame
346-
/// scheduling.
347-
///
348-
/// @return The display refresh rate in frames per second. This may change
349-
/// from frame to frame, throughout the lifecycle of the
350-
/// application, and, may not be available immediately upon
351-
/// application launch.
352-
///
353-
float GetDisplayRefreshRate() const;
354-
355332
//----------------------------------------------------------------------------
356333
/// @return The pointer to this instance of the engine. The engine may
357334
/// only be accessed safely on the UI task runner.

shell/common/rasterizer.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,9 @@ class Rasterizer final : public SnapshotDelegate {
6868
///
6969
virtual void OnFrameRasterized(const FrameTiming& frame_timing) = 0;
7070

71-
/// Time limit for a smooth frame. See `Engine::GetDisplayRefreshRate`.
71+
/// Time limit for a smooth frame.
72+
///
73+
/// See: `DisplayManager::GetMainDisplayRefreshRate`.
7274
virtual fml::Milliseconds GetFrameBudget() = 0;
7375

7476
/// Target time for the latest frame. See also `Shell::OnAnimatorBeginFrame`

shell/common/shell.cc

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,8 @@ Shell::Shell(DartVMRef vm, TaskRunners task_runners, Settings settings)
333333
FML_DCHECK(task_runners_.IsValid());
334334
FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
335335

336+
display_manager_ = std::make_unique<DisplayManager>();
337+
336338
// Generate a WeakPtrFactory for use with the raster thread. This does not
337339
// need to wait on a latch because it can only ever be used from the raster
338340
// thread from this class, so we have ordering guarantees.
@@ -574,14 +576,6 @@ bool Shell::Setup(std::unique_ptr<PlatformView> platform_view,
574576
PersistentCache::GetCacheForProcess()->Purge();
575577
}
576578

577-
// TODO(gw280): The WeakPtr here asserts that we are derefing it on the
578-
// same thread as it was created on. Shell is constructed on the platform
579-
// thread but we need to call into the Engine on the UI thread, so we need
580-
// to use getUnsafe() here to avoid failing the assertion.
581-
//
582-
// https://github.com/flutter/flutter/issues/42947
583-
display_refresh_rate_ = weak_engine_.getUnsafe()->GetDisplayRefreshRate();
584-
585579
return true;
586580
}
587581

@@ -1260,8 +1254,9 @@ void Shell::OnFrameRasterized(const FrameTiming& timing) {
12601254
}
12611255

12621256
fml::Milliseconds Shell::GetFrameBudget() {
1263-
if (display_refresh_rate_ > 0) {
1264-
return fml::RefreshRateToFrameBudget(display_refresh_rate_.load());
1257+
double display_refresh_rate = display_manager_->GetMainDisplayRefreshRate();
1258+
if (display_refresh_rate > 0) {
1259+
return fml::RefreshRateToFrameBudget(display_refresh_rate);
12651260
} else {
12661261
return fml::kDefaultFrameBudget;
12671262
}
@@ -1452,11 +1447,15 @@ bool Shell::OnServiceProtocolGetDisplayRefreshRate(
14521447
FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
14531448
response->SetObject();
14541449
response->AddMember("type", "DisplayRefreshRate", response->GetAllocator());
1455-
response->AddMember("fps", engine_->GetDisplayRefreshRate(),
1450+
response->AddMember("fps", display_manager_->GetMainDisplayRefreshRate(),
14561451
response->GetAllocator());
14571452
return true;
14581453
}
14591454

1455+
double Shell::GetMainDisplayRefreshRate() {
1456+
return display_manager_->GetMainDisplayRefreshRate();
1457+
}
1458+
14601459
bool Shell::OnServiceProtocolGetSkSLs(
14611460
const ServiceProtocol::Handler::ServiceProtocolMap& params,
14621461
rapidjson::Document* response) {
@@ -1618,4 +1617,9 @@ std::shared_ptr<fml::SyncSwitch> Shell::GetIsGpuDisabledSyncSwitch() const {
16181617
return is_gpu_disabled_sync_switch_;
16191618
}
16201619

1620+
void Shell::OnDisplayUpdates(DisplayUpdateType update_type,
1621+
std::vector<Display> displays) {
1622+
display_manager_->HandleDisplayUpdates(update_type, displays);
1623+
}
1624+
16211625
} // namespace flutter

shell/common/shell.h

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "flutter/runtime/dart_vm_lifecycle.h"
3131
#include "flutter/runtime/service_protocol.h"
3232
#include "flutter/shell/common/animator.h"
33+
#include "flutter/shell/common/display_manager.h"
3334
#include "flutter/shell/common/engine.h"
3435
#include "flutter/shell/common/platform_view.h"
3536
#include "flutter/shell/common/rasterizer.h"
@@ -369,6 +370,17 @@ class Shell final : public PlatformView::Delegate,
369370
///
370371
DartVM* GetDartVM();
371372

373+
//----------------------------------------------------------------------------
374+
/// @brief Notifies the display manager of the updates.
375+
///
376+
void OnDisplayUpdates(DisplayUpdateType update_type,
377+
std::vector<Display> displays);
378+
379+
//----------------------------------------------------------------------------
380+
/// @brief Queries the `DisplayManager` for the main display refresh rate.
381+
///
382+
double GetMainDisplayRefreshRate();
383+
372384
private:
373385
using ServiceProtocolHandler =
374386
std::function<bool(const ServiceProtocol::Handler::ServiceProtocolMap&,
@@ -418,12 +430,9 @@ class Shell final : public PlatformView::Delegate,
418430
// here for easier conversions to Dart objects.
419431
std::vector<int64_t> unreported_timings_;
420432

421-
// A cache of `Engine::GetDisplayRefreshRate` (only callable in the UI thread)
422-
// so we can access it from `Rasterizer` (in the raster thread).
423-
//
424-
// The atomic is for extra thread safety as this is written in the UI thread
425-
// and read from the raster thread.
426-
std::atomic<float> display_refresh_rate_ = 0.0f;
433+
/// Manages the displays. This class is thread safe, can be accessed from any
434+
/// of the threads.
435+
std::unique_ptr<DisplayManager> display_manager_;
427436

428437
// protects expected_frame_size_ which is set on platform thread and read on
429438
// raster thread

shell/common/vsync_waiter.cc

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,4 @@ void VsyncWaiter::FireCallback(fml::TimePoint frame_start_time,
134134
}
135135
}
136136

137-
float VsyncWaiter::GetDisplayRefreshRate() const {
138-
return kUnknownRefreshRateFPS;
139-
}
140-
141137
} // namespace flutter

shell/common/vsync_waiter.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,6 @@ class VsyncWaiter : public std::enable_shared_from_this<VsyncWaiter> {
3030
/// See also |PointerDataDispatcher::ScheduleSecondaryVsyncCallback|.
3131
void ScheduleSecondaryCallback(const fml::closure& callback);
3232

33-
static constexpr float kUnknownRefreshRateFPS = 0.0;
34-
35-
// Get the display's maximum refresh rate in the unit of frame per second.
36-
// Return kUnknownRefreshRateFPS if the refresh rate is unknown.
37-
virtual float GetDisplayRefreshRate() const;
38-
3933
protected:
4034
// On some backends, the |FireCallback| needs to be made from a static C
4135
// method.

0 commit comments

Comments
 (0)