Flutter Engine
The Flutter Engine
performance_overlay_layer_unittests.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "flutter/flow/layers/performance_overlay_layer.h"
6
7#include <cstdint>
8#include <sstream>
9
10#include "flutter/flow/flow_test_utils.h"
11#include "flutter/flow/raster_cache.h"
12#include "flutter/flow/testing/layer_test.h"
13#include "flutter/shell/common/base64.h"
14#include "flutter/testing/mock_canvas.h"
22
23namespace flutter {
24namespace testing {
25namespace {
26
27// To get the size of kMockedTimes in compile time.
28template <class T, std::size_t N>
29constexpr int size(const T (&array)[N]) noexcept {
30 return N;
31}
32
33constexpr int kMockedTimes[] = {17, 1, 4, 24, 4, 25, 30, 4, 13, 34,
34 14, 0, 18, 9, 32, 36, 26, 23, 5, 8,
35 32, 18, 29, 16, 29, 18, 0, 36, 33, 10};
36
37static std::string GetGoldenFilePath(int refresh_rate, bool is_new) {
38 std::stringstream ss;
39 // This unit test should only be run on Linux (not even on Mac since it's a
40 // golden test). Hence we don't have to worry about the "/" vs. "\".
41 ss << flutter::GetGoldenDir() << "/" << "performance_overlay_gold_"
42 << refresh_rate << "fps" << (is_new ? "_new" : "") << ".png";
43 return ss.str();
44}
45
46static void TestPerformanceOverlayLayerGold(int refresh_rate) {
47 std::string golden_file_path = GetGoldenFilePath(refresh_rate, false);
48 std::string new_golden_file_path = GetGoldenFilePath(refresh_rate, true);
49
50 FixedRefreshRateStopwatch mock_stopwatch(
51 fml::RefreshRateToFrameBudget(refresh_rate));
52 for (int i = 0; i < size(kMockedTimes); ++i) {
53 mock_stopwatch.SetLapTime(
54 fml::TimeDelta::FromMilliseconds(kMockedTimes[i]));
55 }
56
57 const SkImageInfo image_info = SkImageInfo::MakeN32Premul(1000, 1000);
59 DlSkCanvasAdapter canvas(surface->getCanvas());
60
61 ASSERT_TRUE(surface != nullptr);
62
63 LayerStateStack state_stack;
64 state_stack.set_delegate(&canvas);
65
66 flutter::PaintContext paint_context = {
67 // clang-format off
68 .state_stack = state_stack,
69 .canvas = &canvas,
70 .gr_context = nullptr,
71 .view_embedder = nullptr,
72 .raster_time = mock_stopwatch,
73 .ui_time = mock_stopwatch,
74 .texture_registry = nullptr,
75 .raster_cache = nullptr,
76 // clang-format on
77 };
78
79 // Specify font file to ensure the same font across different operation
80 // systems.
86 flutter::GetFontFile().c_str());
87 layer.set_paint_bounds(SkRect::MakeWH(1000, 400));
88 surface->getCanvas()->clear(SK_ColorTRANSPARENT);
89 layer.Paint(paint_context);
90
91 sk_sp<SkImage> snapshot = surface->makeImageSnapshot();
92 sk_sp<SkData> snapshot_data =
93 SkPngEncoder::Encode(nullptr, snapshot.get(), {});
94
95 sk_sp<SkData> golden_data =
96 SkData::MakeFromFileName(golden_file_path.c_str());
97 EXPECT_TRUE(golden_data != nullptr)
98 << "Golden file not found: " << golden_file_path << ".\n"
99 << "Please either set --golden-dir, or make sure that the unit test is "
100 << "run from the right directory (e.g., flutter/engine/src).";
101
102 // TODO(https://github.com/flutter/flutter/issues/53784): enable this on all
103 // platforms.
104#if !defined(FML_OS_LINUX)
105 GTEST_SKIP() << "Skipping golden tests on non-Linux OSes";
106#else
107 const bool golden_data_matches = golden_data->equals(snapshot_data.get());
108 if (!golden_data_matches) {
109 SkFILEWStream wstream(new_golden_file_path.c_str());
110 wstream.write(snapshot_data->data(), snapshot_data->size());
111 wstream.flush();
112
113 size_t b64_size = Base64::EncodedSize(snapshot_data->size());
114 sk_sp<SkData> b64_data = SkData::MakeUninitialized(b64_size + 1);
115 char* b64_char = static_cast<char*>(b64_data->writable_data());
116 Base64::Encode(snapshot_data->data(), snapshot_data->size(), b64_char);
117 b64_char[b64_size] = 0; // make it null terminated for printing
118
119 EXPECT_TRUE(golden_data_matches)
120 << "Golden file mismatch. Please check " << "the difference between "
121 << golden_file_path << " and " << new_golden_file_path
122 << ", and replace the former "
123 << "with the latter if the difference looks good.\nS\n"
124 << "See also the base64 encoded " << new_golden_file_path << ":\n"
125 << b64_char;
126 }
127#endif // FML_OS_LINUX
128}
129
130} // namespace
131
133
134TEST_F(PerformanceOverlayLayerTest, PaintingEmptyLayerDies) {
135 const uint64_t overlay_opts = kVisualizeRasterizerStatistics;
136 auto layer = std::make_shared<PerformanceOverlayLayer>(overlay_opts);
137
138 layer->Preroll(preroll_context());
139 EXPECT_EQ(layer->paint_bounds(), SkRect::MakeEmpty());
140 EXPECT_FALSE(layer->needs_painting(paint_context()));
141
142 // Crashes reading a nullptr.
143 EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()), "");
144}
145
147 const SkRect layer_bounds = SkRect::MakeLTRB(0.0f, 0.0f, 64.0f, 64.0f);
148 const uint64_t overlay_opts = 0;
149 auto layer = std::make_shared<PerformanceOverlayLayer>(overlay_opts);
150
151 // TODO(): Note calling code has to call set_paint_bounds right now. Make
152 // this a constructor parameter and move the set_paint_bounds into Preroll
153 layer->set_paint_bounds(layer_bounds);
154
155 layer->Preroll(preroll_context());
156 EXPECT_EQ(layer->paint_bounds(), layer_bounds);
157 EXPECT_TRUE(layer->needs_painting(paint_context()));
158
159 // Nothing is drawn if options are invalid (0).
160 layer->Paint(paint_context());
161 EXPECT_EQ(mock_canvas().draw_calls(), std::vector<MockCanvas::DrawCall>());
162}
163
164TEST_F(PerformanceOverlayLayerTest, SimpleRasterizerStatistics) {
165 const SkRect layer_bounds = SkRect::MakeLTRB(0.0f, 0.0f, 64.0f, 64.0f);
166 const uint64_t overlay_opts = kDisplayRasterizerStatistics;
167 auto layer = std::make_shared<PerformanceOverlayLayer>(overlay_opts);
168
169 // TODO(): Note calling code has to call set_paint_bounds right now. Make
170 // this a constructor parameter and move the set_paint_bounds into Preroll
171 layer->set_paint_bounds(layer_bounds);
172
173 layer->Preroll(preroll_context());
174 EXPECT_EQ(layer->paint_bounds(), layer_bounds);
175 EXPECT_TRUE(layer->needs_painting(paint_context()));
176
177 layer->Paint(paint_context());
179 paint_context().raster_time, "Raster", "");
180 auto overlay_text_data = overlay_text->serialize(SkSerialProcs{});
181 // Historically SK_ColorGRAY (== 0xFF888888) was used here
182 DlPaint text_paint(DlColor(0xFF888888));
183 SkPoint text_position = SkPoint::Make(16.0f, 22.0f);
184
185 // TODO(https://github.com/flutter/flutter/issues/82202): Remove once the
186 // performance overlay can use Fuchsia's font manager instead of the empty
187 // default.
188#if defined(OS_FUCHSIA)
189 GTEST_SKIP() << "Expectation requires a valid default font manager";
190#endif // OS_FUCHSIA
191 EXPECT_EQ(mock_canvas().draw_calls(),
192 std::vector({MockCanvas::DrawCall{
193 0, MockCanvas::DrawTextData{overlay_text_data, text_paint,
194 text_position}}}));
195}
196
197TEST_F(PerformanceOverlayLayerTest, MarkAsDirtyWhenResized) {
198 // Regression test for https://github.com/flutter/flutter/issues/54188
199
200 // Create a PerformanceOverlayLayer.
201 const uint64_t overlay_opts = kVisualizeRasterizerStatistics;
202 auto layer = std::make_shared<PerformanceOverlayLayer>(overlay_opts);
203 layer->set_paint_bounds(SkRect::MakeLTRB(0.0f, 0.0f, 48.0f, 48.0f));
204 layer->Preroll(preroll_context());
205 layer->Paint(paint_context());
206 auto data = mock_canvas().draw_calls().front().data;
207 auto image_data = std::get<MockCanvas::DrawImageDataNoPaint>(data);
208 auto first_draw_width = image_data.image->width();
209
210 // Create a second PerformanceOverlayLayer with different bounds.
211 layer = std::make_shared<PerformanceOverlayLayer>(overlay_opts);
212 layer->set_paint_bounds(SkRect::MakeLTRB(0.0f, 0.0f, 64.0f, 64.0f));
213 layer->Preroll(preroll_context());
214 layer->Paint(paint_context());
215 data = mock_canvas().draw_calls().back().data;
216 image_data = std::get<MockCanvas::DrawImageDataNoPaint>(data);
217 auto refreshed_draw_width = image_data.image->width();
218
219 EXPECT_NE(first_draw_width, refreshed_draw_width);
220}
221
222TEST(PerformanceOverlayLayerDefault, Gold) {
223 TestPerformanceOverlayLayerGold(60);
224}
225
226TEST(PerformanceOverlayLayer90fps, Gold) {
227 TestPerformanceOverlayLayerGold(90);
228}
229
230TEST(PerformanceOverlayLayer120fps, Gold) {
231 TestPerformanceOverlayLayerGold(120);
232}
233
234} // namespace testing
235} // namespace flutter
constexpr SkColor SK_ColorTRANSPARENT
Definition: SkColor.h:99
#define N
Definition: beziers.cpp:19
static sk_sp< SkData > MakeUninitialized(size_t length)
Definition: SkData.cpp:116
bool equals(const SkData *other) const
Definition: SkData.cpp:43
const void * data() const
Definition: SkData.h:37
void * writable_data()
Definition: SkData.h:52
static sk_sp< SkData > MakeFromFileName(const char path[])
Definition: SkData.cpp:148
size_t size() const
Definition: SkData.h:30
static sk_sp< SkTextBlob > MakeStatisticsText(const Stopwatch &stopwatch, const std::string &label_prefix, const std::string &font_path)
static constexpr TimeDelta FromMilliseconds(int64_t millis)
Definition: time_delta.h:46
T * get() const
Definition: SkRefCnt.h:303
VkSurfaceKHR surface
Definition: main.cc:49
SK_API bool Encode(SkWStream *dst, const SkPixmap &src, const Options &options)
SK_API sk_sp< SkSurface > Raster(const SkImageInfo &imageInfo, size_t rowBytes, const SkSurfaceProps *surfaceProps)
TEST_F(DisplayListTest, Defaults)
LayerTestBase<::testing::Test > LayerTest
Definition: layer_test.h:210
TEST(DisplayListComplexity, EmptyDisplayList)
const int kVisualizeEngineStatistics
const std::string & GetFontFile()
const int kDisplayEngineStatistics
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition: switches.h:41
const int kVisualizeRasterizerStatistics
const int kDisplayRasterizerStatistics
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
const std::string & GetGoldenDir()
Milliseconds RefreshRateToFrameBudget(T refresh_rate)
Definition: time_delta.h:24
flutter::DlColor DlColor
#define T
Definition: precompiler.cc:65
Definition: DM.cpp:425
static SkImageInfo MakeN32Premul(int width, int height)
static constexpr SkPoint Make(float x, float y)
Definition: SkPoint_impl.h:173
static constexpr SkRect MakeEmpty()
Definition: SkRect.h:595
static constexpr SkRect MakeWH(float w, float h)
Definition: SkRect.h:609
static constexpr SkRect MakeLTRB(float l, float t, float r, float b)
Definition: SkRect.h:646
static size_t Encode(const void *src, size_t length, void *dst)
Definition: base64.cc:118
static size_t EncodedSize(size_t srcDataLength)
Definition: base64.h:33
LayerStateStack & state_stack
Definition: layer.h:101
#define EXPECT_TRUE(handle)
Definition: unit_test.h:678