Variable Refresh Rate Display (flutter/engine#30223)
This commit is contained in:
@@ -765,6 +765,10 @@ FILE: ../../../flutter/shell/common/switches.h
|
||||
FILE: ../../../flutter/shell/common/switches_unittests.cc
|
||||
FILE: ../../../flutter/shell/common/thread_host.cc
|
||||
FILE: ../../../flutter/shell/common/thread_host.h
|
||||
FILE: ../../../flutter/shell/common/variable_refresh_rate_display.cc
|
||||
FILE: ../../../flutter/shell/common/variable_refresh_rate_display.h
|
||||
FILE: ../../../flutter/shell/common/variable_refresh_rate_display_unittests.cc
|
||||
FILE: ../../../flutter/shell/common/variable_refresh_rate_reporter.h
|
||||
FILE: ../../../flutter/shell/common/vsync_waiter.cc
|
||||
FILE: ../../../flutter/shell/common/vsync_waiter.h
|
||||
FILE: ../../../flutter/shell/common/vsync_waiter_fallback.cc
|
||||
|
||||
@@ -96,6 +96,9 @@ source_set("common") {
|
||||
"switches.h",
|
||||
"thread_host.cc",
|
||||
"thread_host.h",
|
||||
"variable_refresh_rate_display.cc",
|
||||
"variable_refresh_rate_display.h",
|
||||
"variable_refresh_rate_reporter.h",
|
||||
"vsync_waiter.cc",
|
||||
"vsync_waiter.h",
|
||||
"vsync_waiter_fallback.cc",
|
||||
@@ -266,6 +269,7 @@ if (enable_unittests) {
|
||||
"shell_unittests.cc",
|
||||
"skp_shader_warmup_unittests.cc",
|
||||
"switches_unittests.cc",
|
||||
"variable_refresh_rate_display_unittests.cc",
|
||||
]
|
||||
|
||||
deps = [
|
||||
|
||||
@@ -206,6 +206,10 @@ void Animator::Render(std::unique_ptr<flutter::LayerTree> layer_tree) {
|
||||
std::move(frame_timings_recorder_));
|
||||
}
|
||||
|
||||
const VsyncWaiter& Animator::GetVsyncWaiter() const {
|
||||
return *waiter_.get();
|
||||
}
|
||||
|
||||
bool Animator::CanReuseLastLayerTree() {
|
||||
return !regenerate_layer_tree_;
|
||||
}
|
||||
|
||||
@@ -54,6 +54,8 @@ class Animator final {
|
||||
|
||||
void Render(std::unique_ptr<flutter::LayerTree> layer_tree);
|
||||
|
||||
const VsyncWaiter& GetVsyncWaiter() const;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/// @brief Schedule a secondary callback to be executed right after the
|
||||
/// main `VsyncWaiter::AsyncWaitForVsync` callback (which is added
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <optional>
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "flutter/shell/common/variable_refresh_rate_reporter.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
|
||||
@@ -600,4 +600,8 @@ void Engine::LoadDartDeferredLibraryError(intptr_t loading_unit_id,
|
||||
}
|
||||
}
|
||||
|
||||
const VsyncWaiter& Engine::GetVsyncWaiter() const {
|
||||
return animator_->GetVsyncWaiter();
|
||||
}
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
@@ -903,6 +903,8 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate {
|
||||
return runtime_controller_.get();
|
||||
}
|
||||
|
||||
const VsyncWaiter& GetVsyncWaiter() const;
|
||||
|
||||
private:
|
||||
// |RuntimeDelegate|
|
||||
std::string DefaultRouteName() override;
|
||||
|
||||
@@ -1872,4 +1872,8 @@ Shell::GetPlatformMessageHandler() const {
|
||||
return platform_message_handler_;
|
||||
}
|
||||
|
||||
const VsyncWaiter& Shell::GetVsyncWaiter() const {
|
||||
return engine_->GetVsyncWaiter();
|
||||
}
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
@@ -401,6 +401,8 @@ class Shell final : public PlatformView::Delegate,
|
||||
const std::shared_ptr<PlatformMessageHandler>& GetPlatformMessageHandler()
|
||||
const;
|
||||
|
||||
const VsyncWaiter& GetVsyncWaiter() const;
|
||||
|
||||
private:
|
||||
using ServiceProtocolHandler =
|
||||
std::function<bool(const ServiceProtocol::Handler::ServiceProtocolMap&,
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
// 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/variable_refresh_rate_display.h"
|
||||
#include "flutter/fml/logging.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
VariableRefreshRateDisplay::VariableRefreshRateDisplay(
|
||||
DisplayId display_id,
|
||||
const VariableRefreshRateReporter& refresh_rate_reporter)
|
||||
: Display(display_id, refresh_rate_reporter.GetRefreshRate()),
|
||||
refresh_rate_reporter_(refresh_rate_reporter) {}
|
||||
|
||||
VariableRefreshRateDisplay::VariableRefreshRateDisplay(
|
||||
const VariableRefreshRateReporter& refresh_rate_reporter)
|
||||
: Display(refresh_rate_reporter.GetRefreshRate()),
|
||||
refresh_rate_reporter_(refresh_rate_reporter) {}
|
||||
|
||||
double VariableRefreshRateDisplay::GetRefreshRate() const {
|
||||
return refresh_rate_reporter_.GetRefreshRate();
|
||||
}
|
||||
|
||||
} // namespace flutter
|
||||
@@ -0,0 +1,37 @@
|
||||
// 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_VARIABLE_REFRESH_RATE_DISPLAY_H_
|
||||
#define FLUTTER_SHELL_COMMON_VARIABLE_REFRESH_RATE_DISPLAY_H_
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "display.h"
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "variable_refresh_rate_reporter.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
/// A Display where the refresh rate can change over time.
|
||||
class VariableRefreshRateDisplay : public Display {
|
||||
public:
|
||||
explicit VariableRefreshRateDisplay(
|
||||
DisplayId display_id,
|
||||
const VariableRefreshRateReporter& refresh_rate_reporter);
|
||||
explicit VariableRefreshRateDisplay(
|
||||
const VariableRefreshRateReporter& refresh_rate_reporter);
|
||||
~VariableRefreshRateDisplay() = default;
|
||||
|
||||
// |Display|
|
||||
double GetRefreshRate() const override;
|
||||
|
||||
private:
|
||||
const VariableRefreshRateReporter& refresh_rate_reporter_;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(VariableRefreshRateDisplay);
|
||||
};
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
#endif // FLUTTER_SHELL_COMMON_VARIABLE_REFRESH_RATE_DISPLAY_H_
|
||||
@@ -0,0 +1,29 @@
|
||||
// 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 "variable_refresh_rate_display.h"
|
||||
#include "vsync_waiters_test.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace flutter {
|
||||
namespace testing {
|
||||
|
||||
TEST(VariableRefreshRateDisplayTest, ReportCorrectInitialRefreshRate) {
|
||||
auto refresh_rate_reporter = std::make_unique<TestRefreshRateReporter>(60);
|
||||
auto display =
|
||||
flutter::VariableRefreshRateDisplay(*refresh_rate_reporter.get());
|
||||
ASSERT_EQ(display.GetRefreshRate(), 60);
|
||||
}
|
||||
|
||||
TEST(VariableRefreshRateDisplayTest, ReportCorrectRefreshRateWhenUpdated) {
|
||||
auto refresh_rate_reporter = std::make_unique<TestRefreshRateReporter>(60);
|
||||
auto display =
|
||||
flutter::VariableRefreshRateDisplay(*refresh_rate_reporter.get());
|
||||
refresh_rate_reporter->UpdateRefreshRate(30);
|
||||
ASSERT_EQ(display.GetRefreshRate(), 30);
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace flutter
|
||||
@@ -0,0 +1,28 @@
|
||||
// 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_VARIABLE_REFRESH_RATE_REPORTER_H_
|
||||
#define FLUTTER_SHELL_COMMON_VARIABLE_REFRESH_RATE_REPORTER_H_
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace flutter {
|
||||
|
||||
/// Abstract class that reprents a platform specific mechanism to report current
|
||||
/// refresh rates.
|
||||
class VariableRefreshRateReporter {
|
||||
public:
|
||||
VariableRefreshRateReporter() = default;
|
||||
|
||||
virtual double GetRefreshRate() const = 0;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(VariableRefreshRateReporter);
|
||||
};
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
#endif // FLUTTER_SHELL_COMMON_VARIABLE_REFRESH_RATE_REPORTER_H_
|
||||
@@ -64,5 +64,16 @@ void ConstantFiringVsyncWaiter::AwaitVSync() {
|
||||
});
|
||||
}
|
||||
|
||||
TestRefreshRateReporter::TestRefreshRateReporter(double refresh_rate)
|
||||
: refresh_rate_(refresh_rate) {}
|
||||
|
||||
void TestRefreshRateReporter::UpdateRefreshRate(double refresh_rate) {
|
||||
refresh_rate_ = refresh_rate;
|
||||
}
|
||||
|
||||
double TestRefreshRateReporter::GetRefreshRate() const {
|
||||
return refresh_rate_;
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace flutter
|
||||
|
||||
@@ -56,6 +56,18 @@ class ConstantFiringVsyncWaiter : public VsyncWaiter {
|
||||
void AwaitVSync() override;
|
||||
};
|
||||
|
||||
class TestRefreshRateReporter final : public VariableRefreshRateReporter {
|
||||
public:
|
||||
explicit TestRefreshRateReporter(double refresh_rate);
|
||||
void UpdateRefreshRate(double refresh_rate);
|
||||
|
||||
// |RefreshRateReporter|
|
||||
double GetRefreshRate() const override;
|
||||
|
||||
private:
|
||||
double refresh_rate_;
|
||||
};
|
||||
|
||||
} // namespace testing
|
||||
} // namespace flutter
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "flutter/shell/common/shell.h"
|
||||
#include "flutter/shell/common/switches.h"
|
||||
#include "flutter/shell/common/thread_host.h"
|
||||
#include "flutter/shell/common/variable_refresh_rate_display.h"
|
||||
#import "flutter/shell/platform/darwin/common/command_line.h"
|
||||
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterBinaryMessengerRelay.h"
|
||||
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h"
|
||||
@@ -699,9 +700,10 @@ static void SetEntryPoint(flutter::Settings* settings, NSString* entrypoint, NSS
|
||||
}
|
||||
|
||||
- (void)initializeDisplays {
|
||||
double refresh_rate = [DisplayLinkManager displayRefreshRate];
|
||||
const flutter::VsyncWaiterIOS& vsync_waiter_ios =
|
||||
static_cast<const flutter::VsyncWaiterIOS&>(_shell->GetVsyncWaiter());
|
||||
std::vector<std::unique_ptr<flutter::Display>> displays;
|
||||
displays.push_back(std::make_unique<flutter::Display>(refresh_rate));
|
||||
displays.push_back(std::make_unique<flutter::VariableRefreshRateDisplay>(vsync_waiter_ios));
|
||||
_shell->OnDisplayUpdates(flutter::DisplayUpdateType::kStartup, std::move(displays));
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "flutter/fml/memory/weak_ptr.h"
|
||||
#include "flutter/fml/platform/darwin/scoped_nsobject.h"
|
||||
#include "flutter/shell/common/variable_refresh_rate_reporter.h"
|
||||
#include "flutter/shell/common/vsync_waiter.h"
|
||||
|
||||
@interface DisplayLinkManager : NSObject
|
||||
@@ -34,16 +35,21 @@
|
||||
|
||||
- (void)invalidate;
|
||||
|
||||
- (double)getRefreshRate;
|
||||
|
||||
@end
|
||||
|
||||
namespace flutter {
|
||||
|
||||
class VsyncWaiterIOS final : public VsyncWaiter {
|
||||
class VsyncWaiterIOS final : public VsyncWaiter, public VariableRefreshRateReporter {
|
||||
public:
|
||||
explicit VsyncWaiterIOS(flutter::TaskRunners task_runners);
|
||||
|
||||
~VsyncWaiterIOS() override;
|
||||
|
||||
// |VariableRefreshRateReporter|
|
||||
double GetRefreshRate() const override;
|
||||
|
||||
private:
|
||||
fml::scoped_nsobject<VSyncClient> client_;
|
||||
|
||||
|
||||
@@ -39,11 +39,17 @@ void VsyncWaiterIOS::AwaitVSync() {
|
||||
[client_.get() await];
|
||||
}
|
||||
|
||||
// |VariableRefreshRateReporter|
|
||||
double VsyncWaiterIOS::GetRefreshRate() const {
|
||||
return [client_.get() getRefreshRate];
|
||||
}
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
@implementation VSyncClient {
|
||||
flutter::VsyncWaiter::Callback callback_;
|
||||
fml::scoped_nsobject<CADisplayLink> display_link_;
|
||||
double current_refresh_rate_;
|
||||
}
|
||||
|
||||
- (instancetype)initWithTaskRunner:(fml::RefPtr<fml::TaskRunner>)task_runner
|
||||
@@ -51,6 +57,7 @@ void VsyncWaiterIOS::AwaitVSync() {
|
||||
self = [super init];
|
||||
|
||||
if (self) {
|
||||
current_refresh_rate_ = [DisplayLinkManager displayRefreshRate];
|
||||
callback_ = std::move(callback);
|
||||
display_link_ = fml::scoped_nsobject<CADisplayLink> {
|
||||
[[CADisplayLink displayLinkWithTarget:self selector:@selector(onDisplayLink:)] retain]
|
||||
@@ -87,6 +94,9 @@ void VsyncWaiterIOS::AwaitVSync() {
|
||||
|
||||
std::unique_ptr<flutter::FrameTimingsRecorder> recorder =
|
||||
std::make_unique<flutter::FrameTimingsRecorder>();
|
||||
|
||||
current_refresh_rate_ = round(1 / (frame_target_time - frame_start_time).ToSecondsF());
|
||||
|
||||
recorder->RecordVsync(frame_start_time, frame_target_time);
|
||||
display_link_.get().paused = YES;
|
||||
|
||||
@@ -103,6 +113,10 @@ void VsyncWaiterIOS::AwaitVSync() {
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (double)getRefreshRate {
|
||||
return current_refresh_rate_;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation DisplayLinkManager
|
||||
|
||||
Reference in New Issue
Block a user