Variable Refresh Rate Display (flutter/engine#30223)

This commit is contained in:
Chris Yang
2022-01-11 10:55:10 -08:00
committed by GitHub
parent 06addee8ac
commit a50ebf3955
18 changed files with 194 additions and 3 deletions

View File

@@ -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

View File

@@ -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 = [

View File

@@ -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_;
}

View File

@@ -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

View File

@@ -8,6 +8,7 @@
#include <optional>
#include "flutter/fml/macros.h"
#include "flutter/shell/common/variable_refresh_rate_reporter.h"
namespace flutter {

View File

@@ -600,4 +600,8 @@ void Engine::LoadDartDeferredLibraryError(intptr_t loading_unit_id,
}
}
const VsyncWaiter& Engine::GetVsyncWaiter() const {
return animator_->GetVsyncWaiter();
}
} // namespace flutter

View File

@@ -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;

View File

@@ -1872,4 +1872,8 @@ Shell::GetPlatformMessageHandler() const {
return platform_message_handler_;
}
const VsyncWaiter& Shell::GetVsyncWaiter() const {
return engine_->GetVsyncWaiter();
}
} // namespace flutter

View File

@@ -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&,

View File

@@ -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

View File

@@ -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_

View File

@@ -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

View File

@@ -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_

View File

@@ -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

View File

@@ -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

View File

@@ -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));
}

View File

@@ -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_;

View File

@@ -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