[Android] Get the right frame_budget when device frame_rate is not 60 (flutter/engine#30924)

This commit is contained in:
eggfly
2022-01-28 05:35:10 +08:00
committed by GitHub
parent 59d6b58cc8
commit 1d4b9857fc
16 changed files with 143 additions and 40 deletions

View File

@@ -78,6 +78,7 @@ FILE: ../../../flutter/flow/frame_timings_recorder_unittests.cc
FILE: ../../../flutter/flow/gl_context_switch_unittests.cc
FILE: ../../../flutter/flow/instrumentation.cc
FILE: ../../../flutter/flow/instrumentation.h
FILE: ../../../flutter/flow/instrumentation_unittests.cc
FILE: ../../../flutter/flow/layers/backdrop_filter_layer.cc
FILE: ../../../flutter/flow/layers/backdrop_filter_layer.h
FILE: ../../../flutter/flow/layers/backdrop_filter_layer_unittests.cc

View File

@@ -135,6 +135,7 @@ if (enable_unittests) {
"flow_test_utils.h",
"frame_timings_recorder_unittests.cc",
"gl_context_switch_unittests.cc",
"instrumentation_unittests.cc",
"layers/backdrop_filter_layer_unittests.cc",
"layers/checkerboard_layertree_unittests.cc",
"layers/clip_path_layer_unittests.cc",

View File

@@ -43,8 +43,12 @@ std::optional<SkRect> FrameDamage::ComputeClipRect(
}
}
CompositorContext::CompositorContext(fml::Milliseconds frame_budget)
: raster_time_(frame_budget), ui_time_(frame_budget) {}
CompositorContext::CompositorContext()
: raster_time_(fixed_refresh_rate_updater_),
ui_time_(fixed_refresh_rate_updater_) {}
CompositorContext::CompositorContext(Stopwatch::RefreshRateUpdater& updater)
: raster_time_(updater), ui_time_(updater) {}
CompositorContext::~CompositorContext() = default;

View File

@@ -138,8 +138,9 @@ class CompositorContext {
FML_DISALLOW_COPY_AND_ASSIGN(ScopedFrame);
};
explicit CompositorContext(
fml::Milliseconds frame_budget = fml::kDefaultFrameBudget);
CompositorContext();
explicit CompositorContext(Stopwatch::RefreshRateUpdater& updater);
virtual ~CompositorContext();
@@ -173,6 +174,9 @@ class CompositorContext {
Stopwatch raster_time_;
Stopwatch ui_time_;
/// Only used by default constructor of `CompositorContext`.
FixedRefreshRateUpdater fixed_refresh_rate_updater_;
void BeginFrame(ScopedFrame& frame, bool enable_instrumentation);
void EndFrame(ScopedFrame& frame, bool enable_instrumentation);

View File

@@ -15,17 +15,26 @@ namespace flutter {
static const size_t kMaxSamples = 120;
static const size_t kMaxFrameMarkers = 8;
Stopwatch::Stopwatch(fml::Milliseconds frame_budget)
: start_(fml::TimePoint::Now()), current_sample_(0) {
Stopwatch::Stopwatch(const RefreshRateUpdater& updater)
: refresh_rate_updater_(updater),
start_(fml::TimePoint::Now()),
current_sample_(0) {
const fml::TimeDelta delta = fml::TimeDelta::Zero();
laps_.resize(kMaxSamples, delta);
cache_dirty_ = true;
prev_drawn_sample_index_ = 0;
frame_budget_ = frame_budget;
}
Stopwatch::~Stopwatch() = default;
FixedRefreshRateStopwatch::FixedRefreshRateStopwatch(
fml::Milliseconds frame_budget)
: Stopwatch(fixed_delegate_), fixed_delegate_(frame_budget) {}
FixedRefreshRateUpdater::FixedRefreshRateUpdater(
fml::Milliseconds fixed_frame_budget)
: fixed_frame_budget_(fixed_frame_budget) {}
void Stopwatch::Start() {
start_ = fml::TimePoint::Now();
current_sample_ = (current_sample_ + 1) % kMaxSamples;
@@ -45,7 +54,7 @@ const fml::TimeDelta& Stopwatch::LastLap() const {
}
double Stopwatch::UnitFrameInterval(double raster_time_ms) const {
return raster_time_ms / frame_budget_.count();
return raster_time_ms / GetFrameBudget().count();
}
double Stopwatch::UnitHeight(double raster_time_ms,
@@ -101,7 +110,7 @@ void Stopwatch::InitVisualizeSurface(const SkRect& rect) const {
// Scale the graph to show frame times up to those that are 3 times the frame
// time.
const double one_frame_ms = frame_budget_.count();
const double one_frame_ms = GetFrameBudget().count();
const double max_interval = one_frame_ms * 3.0;
const double max_unit_interval = UnitFrameInterval(max_interval);
@@ -151,7 +160,7 @@ void Stopwatch::Visualize(SkCanvas* canvas, const SkRect& rect) const {
// Scale the graph to show frame times up to those that are 3 times the frame
// time.
const double one_frame_ms = frame_budget_.count();
const double one_frame_ms = GetFrameBudget().count();
const double max_interval = one_frame_ms * 3.0;
const double max_unit_interval = UnitFrameInterval(max_interval);
@@ -228,6 +237,10 @@ void Stopwatch::Visualize(SkCanvas* canvas, const SkRect& rect) const {
visualize_cache_surface_->draw(canvas, rect.x(), rect.y());
}
fml::Milliseconds Stopwatch::GetFrameBudget() const {
return refresh_rate_updater_.GetFrameBudget();
}
CounterValues::CounterValues() : current_sample_(kMaxSamples - 1) {
values_.resize(kMaxSamples, 0);
}
@@ -300,10 +313,6 @@ void CounterValues::Visualize(SkCanvas* canvas, const SkRect& rect) const {
canvas->drawRect(marker_rect, paint);
}
int64_t CounterValues::GetCurrentValue() const {
return values_[current_sample_];
}
int64_t CounterValues::GetMaxValue() const {
auto max = std::numeric_limits<int64_t>::min();
for (size_t i = 0; i < kMaxSamples; ++i) {
@@ -320,4 +329,8 @@ int64_t CounterValues::GetMinValue() const {
return min;
}
fml::Milliseconds FixedRefreshRateUpdater::GetFrameBudget() const {
return fixed_frame_budget_;
}
} // namespace flutter

View File

@@ -16,14 +16,22 @@ namespace flutter {
class Stopwatch {
public:
explicit Stopwatch(fml::Milliseconds frame_budget = fml::kDefaultFrameBudget);
/// The refresh rate interface for `Stopwatch`.
class RefreshRateUpdater {
public:
/// Time limit for a smooth frame.
/// See: `DisplayManager::GetMainDisplayRefreshRate`.
virtual fml::Milliseconds GetFrameBudget() const = 0;
};
/// The constructor with a updater parameter, it will update frame_budget
/// everytime when `GetFrameBudget()` is called.
explicit Stopwatch(const RefreshRateUpdater& updater);
~Stopwatch();
const fml::TimeDelta& LastLap() const;
fml::TimeDelta CurrentLap() const { return fml::TimePoint::Now() - start_; }
fml::TimeDelta MaxDelta() const;
fml::TimeDelta AverageDelta() const;
@@ -38,16 +46,18 @@ class Stopwatch {
void SetLapTime(const fml::TimeDelta& delta);
/// All places which want to get frame_budget should call this function.
fml::Milliseconds GetFrameBudget() const;
private:
inline double UnitFrameInterval(double time_ms) const;
inline double UnitHeight(double time_ms, double max_height) const;
const RefreshRateUpdater& refresh_rate_updater_;
fml::TimePoint start_;
std::vector<fml::TimeDelta> laps_;
size_t current_sample_;
fml::Milliseconds frame_budget_;
// Mutable data cache for performance optimization of the graphs. Prevents
// expensive redrawing of old data.
mutable bool cache_dirty_;
@@ -57,6 +67,28 @@ class Stopwatch {
FML_DISALLOW_COPY_AND_ASSIGN(Stopwatch);
};
/// Used for fixed refresh rate query cases.
class FixedRefreshRateUpdater : public Stopwatch::RefreshRateUpdater {
fml::Milliseconds GetFrameBudget() const override;
public:
explicit FixedRefreshRateUpdater(
fml::Milliseconds fixed_frame_budget = fml::kDefaultFrameBudget);
private:
fml::Milliseconds fixed_frame_budget_;
};
/// Used for fixed refresh rate cases.
class FixedRefreshRateStopwatch : public Stopwatch {
public:
explicit FixedRefreshRateStopwatch(
fml::Milliseconds fixed_frame_budget = fml::kDefaultFrameBudget);
private:
FixedRefreshRateUpdater fixed_delegate_;
};
class Counter {
public:
Counter() : count_(0) {}
@@ -83,8 +115,6 @@ class CounterValues {
void Visualize(SkCanvas* canvas, const SkRect& rect) const;
int64_t GetCurrentValue() const;
int64_t GetMaxValue() const;
int64_t GetMinValue() const;

View File

@@ -0,0 +1,46 @@
// 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/flow/instrumentation.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
using testing::Return;
namespace flutter {
namespace testing {
class MockRefreshRateUpdater : public Stopwatch::RefreshRateUpdater {
public:
MOCK_CONST_METHOD0(GetFrameBudget, fml::Milliseconds());
};
TEST(Instrumentation, GetDefaultFrameBudgetTest) {
fml::Milliseconds frame_budget_60fps = fml::RefreshRateToFrameBudget(60);
// The default constructor sets the frame_budget to 16.6667 (60 fps).
FixedRefreshRateStopwatch stopwatch;
fml::Milliseconds actual_frame_budget = stopwatch.GetFrameBudget();
EXPECT_EQ(frame_budget_60fps, actual_frame_budget);
}
TEST(Instrumentation, GetOneShotFrameBudgetTest) {
fml::Milliseconds frame_budget_90fps = fml::RefreshRateToFrameBudget(90);
FixedRefreshRateStopwatch stopwatch(frame_budget_90fps);
fml::Milliseconds actual_frame_budget = stopwatch.GetFrameBudget();
EXPECT_EQ(frame_budget_90fps, actual_frame_budget);
}
TEST(Instrumentation, GetFrameBudgetFromUpdaterTest) {
MockRefreshRateUpdater updater;
fml::Milliseconds frame_budget_90fps = fml::RefreshRateToFrameBudget(90);
EXPECT_CALL(updater, GetFrameBudget())
.Times(1)
.WillOnce(Return(frame_budget_90fps));
Stopwatch stopwatch(updater);
fml::Milliseconds actual_frame_budget = stopwatch.GetFrameBudget();
EXPECT_EQ(frame_budget_90fps, actual_frame_budget);
}
} // namespace testing
} // namespace flutter

View File

@@ -102,7 +102,7 @@ sk_sp<SkPicture> LayerTree::Flatten(const SkRect& bounds) {
}
MutatorsStack unused_stack;
const Stopwatch unused_stopwatch;
const FixedRefreshRateStopwatch unused_stopwatch;
TextureRegistry unused_texture_registry;
SkMatrix root_surface_transformation;
// No root surface transformation. So assume identity.

View File

@@ -19,7 +19,6 @@ class LayerTreeTest : public CanvasTest {
public:
LayerTreeTest()
: layer_tree_(SkISize::Make(64, 64), 1.0f),
compositor_context_(fml::kDefaultFrameBudget),
root_transform_(SkMatrix::Translate(1.0f, 1.0f)),
scoped_frame_(compositor_context_.AcquireFrame(nullptr,
&mock_canvas(),

View File

@@ -10,11 +10,7 @@
#include "flutter/flow/flow_test_utils.h"
#include "flutter/flow/raster_cache.h"
#include "flutter/flow/testing/layer_test.h"
#include "flutter/flow/testing/mock_layer.h"
#include "flutter/fml/build_config.h"
#include "flutter/fml/macros.h"
#include "flutter/testing/mock_canvas.h"
#include "gtest/gtest.h"
#include "third_party/skia/include/core/SkData.h"
#include "third_party/skia/include/core/SkSerialProcs.h"
#include "third_party/skia/include/core/SkSurface.h"
@@ -49,7 +45,7 @@ static void TestPerformanceOverlayLayerGold(int refresh_rate) {
std::string golden_file_path = GetGoldenFilePath(refresh_rate, false);
std::string new_golden_file_path = GetGoldenFilePath(refresh_rate, true);
flutter::Stopwatch mock_stopwatch(
FixedRefreshRateStopwatch mock_stopwatch(
fml::RefreshRateToFrameBudget(refresh_rate));
for (int i = 0; i < size(kMockedTimes); ++i) {
mock_stopwatch.SetLapTime(

View File

@@ -136,8 +136,8 @@ class LayerTestBase : public CanvasTestBase<BaseT> {
paint_context_.raster_cache = raster_cache_.get();
}
Stopwatch raster_time_;
Stopwatch ui_time_;
FixedRefreshRateStopwatch raster_time_;
FixedRefreshRateStopwatch ui_time_;
MutatorsStack mutators_stack_;
TextureRegistry texture_registry_;

View File

@@ -66,8 +66,8 @@ void MockRasterCache::AddMockPicture(int width, int height) {
}
PrerollContextHolder GetSamplePrerollContextHolder() {
Stopwatch raster_time;
Stopwatch ui_time;
FixedRefreshRateStopwatch raster_time;
FixedRefreshRateStopwatch ui_time;
MutatorsStack mutators_stack;
TextureRegistry texture_registry;
sk_sp<SkColorSpace> srgb = SkColorSpace::MakeSRGB();

View File

@@ -74,8 +74,8 @@ class MockRasterCache : public RasterCache {
MockCanvas mock_canvas_;
SkColorSpace* color_space_ = mock_canvas_.imageInfo().colorSpace();
MutatorsStack mutators_stack_;
Stopwatch raster_time_;
Stopwatch ui_time_;
FixedRefreshRateStopwatch raster_time_;
FixedRefreshRateStopwatch ui_time_;
TextureRegistry texture_registry_;
PrerollContext preroll_context_ = {
nullptr, /* raster_cache */

View File

@@ -14,7 +14,6 @@
#include "flutter/fml/time/time_point.h"
#include "flutter/shell/common/serialization_callbacks.h"
#include "fml/make_copyable.h"
#include "third_party/skia/include/core/SkEncodedImageFormat.h"
#include "third_party/skia/include/core/SkImageEncoder.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"
#include "third_party/skia/include/core/SkSerialProcs.h"
@@ -30,8 +29,7 @@ static constexpr std::chrono::milliseconds kSkiaCleanupExpiration(15000);
Rasterizer::Rasterizer(Delegate& delegate)
: delegate_(delegate),
compositor_context_(std::make_unique<flutter::CompositorContext>(
delegate.GetFrameBudget())),
compositor_context_(std::make_unique<flutter::CompositorContext>(*this)),
user_override_resource_cache_bytes_(false),
weak_factory_(this) {
FML_DCHECK(compositor_context_);
@@ -381,6 +379,10 @@ sk_sp<SkImage> Rasterizer::ConvertToRasterImage(sk_sp<SkImage> image) {
});
}
fml::Milliseconds Rasterizer::GetFrameBudget() const {
return delegate_.GetFrameBudget();
};
RasterStatus Rasterizer::DoDraw(
std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder,
std::unique_ptr<flutter::LayerTree> layer_tree) {

View File

@@ -42,7 +42,8 @@ namespace flutter {
/// and the on-screen render surface. The compositor context has all the GPU
/// state necessary to render frames to the render surface.
///
class Rasterizer final : public SnapshotDelegate {
class Rasterizer final : public SnapshotDelegate,
public Stopwatch::RefreshRateUpdater {
public:
//----------------------------------------------------------------------------
/// @brief Used to forward events from the rasterizer to interested
@@ -460,6 +461,12 @@ class Rasterizer final : public SnapshotDelegate {
// |SnapshotDelegate|
sk_sp<SkImage> ConvertToRasterImage(sk_sp<SkImage> image) override;
// |Stopwatch::Delegate|
/// Time limit for a smooth frame.
///
/// See: `DisplayManager::GetMainDisplayRefreshRate`.
fml::Milliseconds GetFrameBudget() const override;
sk_sp<SkData> ScreenshotLayerTreeAsImage(
flutter::LayerTree* tree,
flutter::CompositorContext& compositor_context,

View File

@@ -2248,8 +2248,8 @@ TEST_F(ShellTest, OnServiceProtocolEstimateRasterCacheMemoryWorks) {
auto* compositor_context = shell->GetRasterizer()->compositor_context();
auto& raster_cache = compositor_context->raster_cache();
Stopwatch raster_time;
Stopwatch ui_time;
FixedRefreshRateStopwatch raster_time;
FixedRefreshRateStopwatch ui_time;
MutatorsStack mutators_stack;
TextureRegistry texture_registry;
PrerollContext preroll_context = {