Skip to content

Commit

Permalink
Embedder API Support for display settings (flutter#21355)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
iskakaushik committed Sep 25, 2020
1 parent aa8d5d4 commit 67fdd7e
Show file tree
Hide file tree
Showing 27 changed files with 645 additions and 136 deletions.
3 changes: 3 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,9 @@ FILE: ../../../flutter/shell/common/animator_unittests.cc
FILE: ../../../flutter/shell/common/canvas_spy.cc
FILE: ../../../flutter/shell/common/canvas_spy.h
FILE: ../../../flutter/shell/common/canvas_spy_unittests.cc
FILE: ../../../flutter/shell/common/display.h
FILE: ../../../flutter/shell/common/display_manager.cc
FILE: ../../../flutter/shell/common/display_manager.h
FILE: ../../../flutter/shell/common/engine.cc
FILE: ../../../flutter/shell/common/engine.h
FILE: ../../../flutter/shell/common/engine_unittests.cc
Expand Down
3 changes: 3 additions & 0 deletions shell/common/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ source_set("common") {
"animator.h",
"canvas_spy.cc",
"canvas_spy.h",
"display.h",
"display_manager.cc",
"display_manager.h",
"engine.cc",
"engine.h",
"isolate_configuration.cc",
Expand Down
4 changes: 0 additions & 4 deletions shell/common/animator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,6 @@ Animator::Animator(Delegate& delegate,

Animator::~Animator() = default;

float Animator::GetDisplayRefreshRate() const {
return waiter_->GetDisplayRefreshRate();
}

void Animator::Stop() {
paused_ = true;
}
Expand Down
2 changes: 0 additions & 2 deletions shell/common/animator.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,6 @@ class Animator final {

~Animator();

float GetDisplayRefreshRate() const;

void RequestFrame(bool regenerate_layer_tree = true);

void Render(std::unique_ptr<flutter::LayerTree> layer_tree);
Expand Down
55 changes: 55 additions & 0 deletions shell/common/display.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef FLUTTER_SHELL_COMMON_DISPLAY_H_
#define FLUTTER_SHELL_COMMON_DISPLAY_H_

#include <optional>

namespace flutter {

/// Unique ID per display that is stable until the Flutter application restarts.
/// See also: `flutter::Display`
typedef uint64_t DisplayId;

/// To be used when the display refresh rate is unknown.
static constexpr double kUnknownDisplayRefreshRate = 0;

/// Display refers to a graphics hardware system consisting of a framebuffer,
/// typically a monitor or a screen. This class holds the various display
/// settings.
class Display {
public:
//------------------------------------------------------------------------------
/// @brief Construct a new Display object in case where the display id of the
/// display is known. In cases where there is more than one display, every
/// display is expected to have a display id.
///
Display(DisplayId display_id, double refresh_rate)
: display_id_(display_id), refresh_rate_(refresh_rate) {}

//------------------------------------------------------------------------------
/// @brief Construct a new Display object when there is only a single display.
/// When there are multiple displays, every display must have a display id.
///
explicit Display(double refresh_rate)
: display_id_({}), refresh_rate_(refresh_rate) {}

~Display() = default;

// Get the display's maximum refresh rate in the unit of frame per second.
// Return `kUnknownDisplayRefreshRate` if the refresh rate is unknown.
double GetRefreshRate() const { return refresh_rate_; }

/// Returns the `DisplayId` of the display.
std::optional<DisplayId> GetDisplayId() const { return display_id_; }

private:
std::optional<DisplayId> display_id_;
double refresh_rate_;
};

} // namespace flutter

#endif // FLUTTER_SHELL_COMMON_DISPLAY_H_
49 changes: 49 additions & 0 deletions shell/common/display_manager.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "flutter/shell/common/display_manager.h"

#include "flutter/fml/logging.h"
#include "flutter/fml/macros.h"

namespace flutter {

DisplayManager::DisplayManager() = default;

DisplayManager::~DisplayManager() = default;

double DisplayManager::GetMainDisplayRefreshRate() const {
std::scoped_lock lock(displays_mutex_);
if (displays_.empty()) {
return kUnknownDisplayRefreshRate;
} else {
return displays_[0].GetRefreshRate();
}
}

void DisplayManager::HandleDisplayUpdates(DisplayUpdateType update_type,
std::vector<Display> displays) {
std::scoped_lock lock(displays_mutex_);
CheckDisplayConfiguration(displays);
switch (update_type) {
case DisplayUpdateType::kStartup:
FML_CHECK(displays_.empty());
displays_ = displays;
return;
default:
FML_CHECK(false) << "Unknown DisplayUpdateType.";
}
}

void DisplayManager::CheckDisplayConfiguration(
std::vector<Display> displays) const {
FML_CHECK(!displays.empty());
if (displays.size() > 1) {
for (auto& display : displays) {
FML_CHECK(display.GetDisplayId().has_value());
}
}
}

} // namespace flutter
59 changes: 59 additions & 0 deletions shell/common/display_manager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef FLUTTER_SHELL_COMMON_DISPLAY_MANAGER_H_
#define FLUTTER_SHELL_COMMON_DISPLAY_MANAGER_H_

#include <mutex>
#include <vector>

#include "flutter/shell/common/display.h"

namespace flutter {

/// The update type parameter that is passed to
/// `DisplayManager::HandleDisplayUpdates`.
enum class DisplayUpdateType {
/// `flutter::Display`s that were active during start-up. A display is
/// considered active if:
/// 1. The frame buffer hardware is connected.
/// 2. The display is drawable, e.g. it isn't being mirrored from another
/// connected display or sleeping.
kStartup
};

/// Manages lifecycle of the connected displays. This class is thread-safe.
class DisplayManager {
public:
DisplayManager();

~DisplayManager();

/// Returns the display refresh rate of the main display. In cases where there
/// is only one display connected, it will return that. We do not yet support
/// cases where there are multiple displays.
///
/// When there are no registered displays, it returns
/// `kUnknownDisplayRefreshRate`.
double GetMainDisplayRefreshRate() const;

/// Handles the display updates.
void HandleDisplayUpdates(DisplayUpdateType update_type,
std::vector<Display> displays);

private:
/// Guards `displays_` vector.
mutable std::mutex displays_mutex_;
std::vector<Display> displays_;

/// Checks that the provided display configuration is valid. Currently this
/// ensures that all the displays have an id in the case there are multiple
/// displays. In case where there is a single display, it is valid for the
/// display to not have an id.
void CheckDisplayConfiguration(std::vector<Display> displays) const;
};

} // namespace flutter

#endif // FLUTTER_SHELL_COMMON_DISPLAY_MANAGER_H_
4 changes: 0 additions & 4 deletions shell/common/engine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,6 @@ Engine::Engine(Delegate& delegate,

Engine::~Engine() = default;

float Engine::GetDisplayRefreshRate() const {
return animator_->GetDisplayRefreshRate();
}

fml::WeakPtr<Engine> Engine::GetWeakPtr() const {
return weak_factory_.GetWeakPtr();
}
Expand Down
25 changes: 1 addition & 24 deletions shell/common/engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "flutter/runtime/runtime_controller.h"
#include "flutter/runtime/runtime_delegate.h"
#include "flutter/shell/common/animator.h"
#include "flutter/shell/common/display_manager.h"
#include "flutter/shell/common/platform_view.h"
#include "flutter/shell/common/pointer_data_dispatcher.h"
#include "flutter/shell/common/rasterizer.h"
Expand Down Expand Up @@ -328,30 +329,6 @@ class Engine final : public RuntimeDelegate,
///
~Engine() override;

//----------------------------------------------------------------------------
/// @brief Gets the refresh rate in frames per second of the vsync waiter
/// used by the animator managed by this engine. This information
/// is purely advisory and is not used by any component. It is
/// only used by the tooling to visualize frame performance.
///
/// @attention The display refresh rate is useless for frame scheduling
/// because it can vary and more accurate frame specific
/// information is given to the engine by the vsync waiter
/// already. However, this call is used by the tooling to ask very
/// high level questions about display refresh rate. For example,
/// "Is the display 60 or 120Hz?". This information is quite
/// unreliable (not available immediately on launch on some
/// platforms), variable and advisory. It must not be used by any
/// component that claims to use it to perform accurate frame
/// scheduling.
///
/// @return The display refresh rate in frames per second. This may change
/// from frame to frame, throughout the lifecycle of the
/// application, and, may not be available immediately upon
/// application launch.
///
float GetDisplayRefreshRate() const;

//----------------------------------------------------------------------------
/// @return The pointer to this instance of the engine. The engine may
/// only be accessed safely on the UI task runner.
Expand Down
4 changes: 3 additions & 1 deletion shell/common/rasterizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,9 @@ class Rasterizer final : public SnapshotDelegate {
///
virtual void OnFrameRasterized(const FrameTiming& frame_timing) = 0;

/// Time limit for a smooth frame. See `Engine::GetDisplayRefreshRate`.
/// Time limit for a smooth frame.
///
/// See: `DisplayManager::GetMainDisplayRefreshRate`.
virtual fml::Milliseconds GetFrameBudget() = 0;

/// Target time for the latest frame. See also `Shell::OnAnimatorBeginFrame`
Expand Down
26 changes: 15 additions & 11 deletions shell/common/shell.cc
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,8 @@ Shell::Shell(DartVMRef vm, TaskRunners task_runners, Settings settings)
FML_DCHECK(task_runners_.IsValid());
FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());

display_manager_ = std::make_unique<DisplayManager>();

// Generate a WeakPtrFactory for use with the raster thread. This does not
// need to wait on a latch because it can only ever be used from the raster
// thread from this class, so we have ordering guarantees.
Expand Down Expand Up @@ -574,14 +576,6 @@ bool Shell::Setup(std::unique_ptr<PlatformView> platform_view,
PersistentCache::GetCacheForProcess()->Purge();
}

// TODO(gw280): The WeakPtr here asserts that we are derefing it on the
// same thread as it was created on. Shell is constructed on the platform
// thread but we need to call into the Engine on the UI thread, so we need
// to use getUnsafe() here to avoid failing the assertion.
//
// https://github.com/flutter/flutter/issues/42947
display_refresh_rate_ = weak_engine_.getUnsafe()->GetDisplayRefreshRate();

return true;
}

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

fml::Milliseconds Shell::GetFrameBudget() {
if (display_refresh_rate_ > 0) {
return fml::RefreshRateToFrameBudget(display_refresh_rate_.load());
double display_refresh_rate = display_manager_->GetMainDisplayRefreshRate();
if (display_refresh_rate > 0) {
return fml::RefreshRateToFrameBudget(display_refresh_rate);
} else {
return fml::kDefaultFrameBudget;
}
Expand Down Expand Up @@ -1452,11 +1447,15 @@ bool Shell::OnServiceProtocolGetDisplayRefreshRate(
FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
response->SetObject();
response->AddMember("type", "DisplayRefreshRate", response->GetAllocator());
response->AddMember("fps", engine_->GetDisplayRefreshRate(),
response->AddMember("fps", display_manager_->GetMainDisplayRefreshRate(),
response->GetAllocator());
return true;
}

double Shell::GetMainDisplayRefreshRate() {
return display_manager_->GetMainDisplayRefreshRate();
}

bool Shell::OnServiceProtocolGetSkSLs(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document* response) {
Expand Down Expand Up @@ -1618,4 +1617,9 @@ std::shared_ptr<fml::SyncSwitch> Shell::GetIsGpuDisabledSyncSwitch() const {
return is_gpu_disabled_sync_switch_;
}

void Shell::OnDisplayUpdates(DisplayUpdateType update_type,
std::vector<Display> displays) {
display_manager_->HandleDisplayUpdates(update_type, displays);
}

} // namespace flutter
21 changes: 15 additions & 6 deletions shell/common/shell.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "flutter/runtime/dart_vm_lifecycle.h"
#include "flutter/runtime/service_protocol.h"
#include "flutter/shell/common/animator.h"
#include "flutter/shell/common/display_manager.h"
#include "flutter/shell/common/engine.h"
#include "flutter/shell/common/platform_view.h"
#include "flutter/shell/common/rasterizer.h"
Expand Down Expand Up @@ -369,6 +370,17 @@ class Shell final : public PlatformView::Delegate,
///
DartVM* GetDartVM();

//----------------------------------------------------------------------------
/// @brief Notifies the display manager of the updates.
///
void OnDisplayUpdates(DisplayUpdateType update_type,
std::vector<Display> displays);

//----------------------------------------------------------------------------
/// @brief Queries the `DisplayManager` for the main display refresh rate.
///
double GetMainDisplayRefreshRate();

private:
using ServiceProtocolHandler =
std::function<bool(const ServiceProtocol::Handler::ServiceProtocolMap&,
Expand Down Expand Up @@ -418,12 +430,9 @@ class Shell final : public PlatformView::Delegate,
// here for easier conversions to Dart objects.
std::vector<int64_t> unreported_timings_;

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

// protects expected_frame_size_ which is set on platform thread and read on
// raster thread
Expand Down
4 changes: 0 additions & 4 deletions shell/common/vsync_waiter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,4 @@ void VsyncWaiter::FireCallback(fml::TimePoint frame_start_time,
}
}

float VsyncWaiter::GetDisplayRefreshRate() const {
return kUnknownRefreshRateFPS;
}

} // namespace flutter
6 changes: 0 additions & 6 deletions shell/common/vsync_waiter.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,6 @@ class VsyncWaiter : public std::enable_shared_from_this<VsyncWaiter> {
/// See also |PointerDataDispatcher::ScheduleSecondaryVsyncCallback|.
void ScheduleSecondaryCallback(const fml::closure& callback);

static constexpr float kUnknownRefreshRateFPS = 0.0;

// Get the display's maximum refresh rate in the unit of frame per second.
// Return kUnknownRefreshRateFPS if the refresh rate is unknown.
virtual float GetDisplayRefreshRate() const;

protected:
// On some backends, the |FireCallback| needs to be made from a static C
// method.
Expand Down
Loading

0 comments on commit 67fdd7e

Please sign in to comment.