[Android] Get the right frame_budget when device frame_rate is not 60 (flutter/engine#30924)
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
46
engine/src/flutter/flow/instrumentation_unittests.cc
Normal file
46
engine/src/flutter/flow/instrumentation_unittests.cc
Normal 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
|
||||
@@ -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.
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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_;
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
Reference in New Issue
Block a user