Flutter Engine
 
Loading...
Searching...
No Matches
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
6
7#include <cstdint>
8#include <sstream>
9
15#include "third_party/skia/include/core/SkData.h"
16#include "third_party/skia/include/core/SkImage.h"
17#include "third_party/skia/include/core/SkSerialProcs.h"
18#include "third_party/skia/include/core/SkStream.h"
19#include "third_party/skia/include/core/SkSurface.h"
20#include "third_party/skia/include/core/SkTextBlob.h"
21#include "third_party/skia/include/encode/SkPngEncoder.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);
58 sk_sp<SkSurface> surface = SkSurfaces::Raster(image_info);
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 .impeller_enabled = false,
77 // clang-format on
78 };
79
80 // Specify font file to ensure the same font across different operation
81 // systems.
87 flutter::GetFontFile().c_str());
88 layer.set_paint_bounds(DlRect::MakeWH(1000, 400));
89 surface->getCanvas()->clear(SK_ColorTRANSPARENT);
90 layer.Paint(paint_context);
91
92 sk_sp<SkImage> snapshot = surface->makeImageSnapshot();
93 sk_sp<SkData> snapshot_data =
94 SkPngEncoder::Encode(nullptr, snapshot.get(), {});
95
96 sk_sp<SkData> golden_data =
97 SkData::MakeFromFileName(golden_file_path.c_str());
98 EXPECT_TRUE(golden_data != nullptr)
99 << "Golden file not found: " << golden_file_path << ".\n"
100 << "Please either set --golden-dir, or make sure that the unit test is "
101 << "run from the right directory (e.g., flutter/engine/src).";
102
103 // TODO(https://github.com/flutter/flutter/issues/53784): enable this on all
104 // platforms.
105#if !defined(FML_OS_LINUX)
106 GTEST_SKIP() << "Skipping golden tests on non-Linux OSes";
107#else
108 const bool golden_data_matches = golden_data->equals(snapshot_data.get());
109 if (!golden_data_matches) {
110 SkFILEWStream wstream(new_golden_file_path.c_str());
111 wstream.write(snapshot_data->data(), snapshot_data->size());
112 wstream.flush();
113
114 size_t b64_size = Base64::EncodedSize(snapshot_data->size());
115 sk_sp<SkData> b64_data = SkData::MakeUninitialized(b64_size + 1);
116 char* b64_char = static_cast<char*>(b64_data->writable_data());
117 Base64::Encode(snapshot_data->data(), snapshot_data->size(), b64_char);
118 b64_char[b64_size] = 0; // make it null terminated for printing
119
120 EXPECT_TRUE(golden_data_matches)
121 << "Golden file mismatch. Please check " << "the difference between "
122 << golden_file_path << " and " << new_golden_file_path
123 << ", and replace the former "
124 << "with the latter if the difference looks good.\nS\n"
125 << "See also the base64 encoded " << new_golden_file_path << ":\n"
126 << b64_char;
127 }
128#endif // FML_OS_LINUX
129}
130
131} // namespace
132
134
140 public:
141 void drawImage(const sk_sp<DlImage> image,
142 const DlPoint& point,
143 DlImageSampling sampling,
144 bool render_with_attributes) override {
145 // We no longer render performance overlays with temp images.
147 }
148
149 void drawVertices(const std::shared_ptr<DlVertices>& vertices,
150 DlBlendMode mode) override {
151 sizes_.push_back(vertices->GetBounds().GetSize());
152 }
153
154 void drawText(const std::shared_ptr<DlText>& text,
155 DlScalar x,
156 DlScalar y) override {
157 texts_.push_back(text);
158 text_positions_.push_back(DlPoint(x, y));
159 }
160
161 const std::vector<DlSize>& sizes() { return sizes_; }
162 const std::vector<std::shared_ptr<DlText>> texts() { return texts_; }
163 const std::vector<DlPoint> text_positions() { return text_positions_; }
164
165 private:
166 std::vector<DlSize> sizes_;
167 std::vector<std::shared_ptr<DlText>> texts_;
168 std::vector<DlPoint> text_positions_;
169};
170
171TEST_F(PerformanceOverlayLayerTest, PaintingEmptyLayerDoesNotDie) {
172 const uint64_t overlay_opts = kVisualizeRasterizerStatistics;
173 auto layer = std::make_shared<PerformanceOverlayLayer>(overlay_opts);
174
175 layer->Preroll(preroll_context());
176 EXPECT_EQ(layer->paint_bounds(), DlRect());
177 EXPECT_FALSE(layer->needs_painting(paint_context()));
178
179 layer->Paint(paint_context());
180}
181
183 const DlRect layer_bounds = DlRect::MakeLTRB(0.0f, 0.0f, 64.0f, 64.0f);
184 const uint64_t overlay_opts = 0;
185 auto layer = std::make_shared<PerformanceOverlayLayer>(overlay_opts);
186
187 // TODO(): Note calling code has to call set_paint_bounds right now. Make
188 // this a constructor parameter and move the set_paint_bounds into Preroll
189 layer->set_paint_bounds(layer_bounds);
190
191 layer->Preroll(preroll_context());
192 EXPECT_EQ(layer->paint_bounds(), layer_bounds);
193 EXPECT_TRUE(layer->needs_painting(paint_context()));
194
195 // Nothing is drawn if options are invalid (0).
196 layer->Paint(display_list_paint_context());
197
198 DisplayListBuilder expected_builder;
199 auto expected_dl = expected_builder.Build();
200
201 EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_dl));
202}
203
204TEST_F(PerformanceOverlayLayerTest, SimpleRasterizerStatistics) {
205 const DlRect layer_bounds = DlRect::MakeLTRB(0.0f, 0.0f, 64.0f, 64.0f);
206 const uint64_t overlay_opts = kDisplayRasterizerStatistics;
207 auto layer = std::make_shared<PerformanceOverlayLayer>(overlay_opts);
209
210 // TODO(): Note calling code has to call set_paint_bounds right now. Make
211 // this a constructor parameter and move the set_paint_bounds into Preroll
212 layer->set_paint_bounds(layer_bounds);
213
214 layer->Preroll(preroll_context());
215 EXPECT_EQ(layer->paint_bounds(), layer_bounds);
216 EXPECT_TRUE(layer->needs_painting(paint_context()));
217
218 layer->Paint(display_list_paint_context());
220 display_list_paint_context().raster_time, font, "Raster");
221 auto overlay_text_data = overlay_text->serialize(SkSerialProcs{});
222 // Historically SK_ColorGRAY (== 0xFF888888) was used here
223 DlPaint text_paint(DlColor(0xFF888888));
224 DlPoint text_position = DlPoint(16.0f, 22.0f);
226 display_list()->Dispatch(inspector);
227
228 ASSERT_EQ(inspector.sizes().size(), 0u);
229 ASSERT_EQ(inspector.texts().size(), 1u);
230 ASSERT_EQ(inspector.text_positions().size(), 1u);
231 auto text_data =
232 inspector.texts().front()->GetTextBlob()->serialize(SkSerialProcs{});
233 EXPECT_TRUE(text_data->equals(overlay_text_data.get()));
234 EXPECT_EQ(inspector.text_positions().front(), text_position);
235}
236
237TEST_F(PerformanceOverlayLayerTest, MarkAsDirtyWhenResized) {
238 // Regression test for https://github.com/flutter/flutter/issues/54188
239
240 // Create a PerformanceOverlayLayer.
241 const uint64_t overlay_opts = kVisualizeRasterizerStatistics;
242 auto layer = std::make_shared<PerformanceOverlayLayer>(overlay_opts);
243 layer->set_paint_bounds(DlRect::MakeLTRB(0.0f, 0.0f, 48.0f, 48.0f));
244 layer->Preroll(preroll_context());
245 layer->Paint(display_list_paint_context());
246 DlSize first_draw_size;
247 {
249 display_list()->Dispatch(inspector);
250 ASSERT_EQ(inspector.sizes().size(), 1u);
251 ASSERT_EQ(inspector.texts().size(), 0u);
252 ASSERT_EQ(inspector.text_positions().size(), 0u);
253 first_draw_size = inspector.sizes().front();
254 }
255
256 // Create a second PerformanceOverlayLayer with different bounds.
257 layer = std::make_shared<PerformanceOverlayLayer>(overlay_opts);
258 layer->set_paint_bounds(DlRect::MakeLTRB(0.0f, 0.0f, 64.0f, 64.0f));
259 layer->Preroll(preroll_context());
260 reset_display_list();
261 layer->Paint(display_list_paint_context());
262 {
264 display_list()->Dispatch(inspector);
265 ASSERT_EQ(inspector.sizes().size(), 1u);
266 ASSERT_EQ(inspector.texts().size(), 0u);
267 ASSERT_EQ(inspector.text_positions().size(), 0u);
268 EXPECT_NE(first_draw_size, inspector.sizes().front());
269 }
270}
271
272TEST(PerformanceOverlayLayerDefault, Gold) {
273 TestPerformanceOverlayLayerGold(60);
274}
275
276TEST(PerformanceOverlayLayer90fps, Gold) {
277 TestPerformanceOverlayLayerGold(90);
278}
279
280TEST(PerformanceOverlayLayer120fps, Gold) {
281 TestPerformanceOverlayLayerGold(120);
282}
283
284} // namespace testing
285} // namespace flutter
sk_sp< DisplayList > Build()
Definition dl_builder.cc:66
Internal API for rendering recorded display lists to backends.
static sk_sp< SkTextBlob > MakeStatisticsText(const Stopwatch &stopwatch, const SkFont &font, std::string_view label_prefix)
static SkFont MakeStatisticsFont(std::string_view font_path)
void drawImage(const sk_sp< DlImage > image, const DlPoint &point, DlImageSampling sampling, bool render_with_attributes) override
void drawVertices(const std::shared_ptr< DlVertices > &vertices, DlBlendMode mode) override
void drawText(const std::shared_ptr< DlText > &text, DlScalar x, DlScalar y) override
const std::vector< std::shared_ptr< DlText > > texts()
static constexpr TimeDelta FromMilliseconds(int64_t millis)
Definition time_delta.h:46
int32_t x
FlutterVulkanImage * image
VkSurfaceKHR surface
Definition main.cc:65
#define FML_UNREACHABLE()
Definition logging.h:128
std::u16string text
double y
TEST_F(DisplayListTest, Defaults)
LayerTestBase<::testing::Test > LayerTest
Definition layer_test.h:177
TEST(NativeAssetsManagerTest, NoAvailableAssets)
bool DisplayListsEQ_Verbose(const DisplayList *a, const DisplayList *b)
const int kVisualizeEngineStatistics
impeller::Scalar DlScalar
const std::string & GetFontFile()
const int kDisplayEngineStatistics
it will be possible to load the file into Perfetto s trace viewer use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all 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
const int kVisualizeRasterizerStatistics
const int kDisplayRasterizerStatistics
impeller::Point DlPoint
const std::string & GetGoldenDir()
Milliseconds RefreshRateToFrameBudget(T refresh_rate)
Definition time_delta.h:24
BlendMode
Definition color.h:58
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:91
static constexpr TRect MakeWH(Type width, Type height)
Definition rect.h:140
static constexpr TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition rect.h:129