Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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_;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice use of std::optional.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks!

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) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the displays list changes while you're iterating over it, the iterator will be invalidated. Assuming that's a distinct possibility, since accesses are protected by a lock elsewhere.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, acquiring lock before this call as well.

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 @@ -1250,8 +1244,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 @@ -1442,11 +1437,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 @@ -1608,4 +1607,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();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make const.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


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