Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
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(team-engine): Note calling code has to call set_paint_bounds right
188 // now. Make this a constructor parameter and move the set_paint_bounds
189 // into Preroll
190 layer->set_paint_bounds(layer_bounds);
191
192 layer->Preroll(preroll_context());
193 EXPECT_EQ(layer->paint_bounds(), layer_bounds);
194 EXPECT_TRUE(layer->needs_painting(paint_context()));
195
196 // Nothing is drawn if options are invalid (0).
197 layer->Paint(display_list_paint_context());
198
199 DisplayListBuilder expected_builder;
200 auto expected_dl = expected_builder.Build();
201
202 EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_dl));
203}
204
205TEST_F(PerformanceOverlayLayerTest, SimpleRasterizerStatistics) {
206 const DlRect layer_bounds = DlRect::MakeLTRB(0.0f, 0.0f, 64.0f, 64.0f);
207 const uint64_t overlay_opts = kDisplayRasterizerStatistics;
208 auto layer = std::make_shared<PerformanceOverlayLayer>(overlay_opts);
210
211 // TODO(team-engine): Note calling code has to call set_paint_bounds right
212 // now. Make this a constructor parameter and move the set_paint_bounds
213 // into Preroll
214 layer->set_paint_bounds(layer_bounds);
215
216 layer->Preroll(preroll_context());
217 EXPECT_EQ(layer->paint_bounds(), layer_bounds);
218 EXPECT_TRUE(layer->needs_painting(paint_context()));
219
220 layer->Paint(display_list_paint_context());
222 display_list_paint_context().raster_time, font, "Raster");
223 auto overlay_text_data = overlay_text->serialize(SkSerialProcs{});
224 // Historically SK_ColorGRAY (== 0xFF888888) was used here
225 DlPaint text_paint(DlColor(0xFF888888));
226 DlPoint text_position = DlPoint(16.0f, 22.0f);
228 display_list()->Dispatch(inspector);
229
230 ASSERT_EQ(inspector.sizes().size(), 0u);
231 ASSERT_EQ(inspector.texts().size(), 1u);
232 ASSERT_EQ(inspector.text_positions().size(), 1u);
233 auto text_data =
234 inspector.texts().front()->GetTextBlob()->serialize(SkSerialProcs{});
235 EXPECT_TRUE(text_data->equals(overlay_text_data.get()));
236 EXPECT_EQ(inspector.text_positions().front(), text_position);
237}
238
239TEST_F(PerformanceOverlayLayerTest, MarkAsDirtyWhenResized) {
240 // Regression test for https://github.com/flutter/flutter/issues/54188
241
242 // Create a PerformanceOverlayLayer.
243 const uint64_t overlay_opts = kVisualizeRasterizerStatistics;
244 auto layer = std::make_shared<PerformanceOverlayLayer>(overlay_opts);
245 layer->set_paint_bounds(DlRect::MakeLTRB(0.0f, 0.0f, 48.0f, 48.0f));
246 layer->Preroll(preroll_context());
247 layer->Paint(display_list_paint_context());
248 DlSize first_draw_size;
249 {
251 display_list()->Dispatch(inspector);
252 ASSERT_EQ(inspector.sizes().size(), 1u);
253 ASSERT_EQ(inspector.texts().size(), 0u);
254 ASSERT_EQ(inspector.text_positions().size(), 0u);
255 first_draw_size = inspector.sizes().front();
256 }
257
258 // Create a second PerformanceOverlayLayer with different bounds.
259 layer = std::make_shared<PerformanceOverlayLayer>(overlay_opts);
260 layer->set_paint_bounds(DlRect::MakeLTRB(0.0f, 0.0f, 64.0f, 64.0f));
261 layer->Preroll(preroll_context());
262 reset_display_list();
263 layer->Paint(display_list_paint_context());
264 {
266 display_list()->Dispatch(inspector);
267 ASSERT_EQ(inspector.sizes().size(), 1u);
268 ASSERT_EQ(inspector.texts().size(), 0u);
269 ASSERT_EQ(inspector.text_positions().size(), 0u);
270 EXPECT_NE(first_draw_size, inspector.sizes().front());
271 }
272}
273
274TEST(PerformanceOverlayLayerDefault, Gold) {
275 TestPerformanceOverlayLayerGold(60);
276}
277
278TEST(PerformanceOverlayLayer90fps, Gold) {
279 TestPerformanceOverlayLayerGold(90);
280}
281
282TEST(PerformanceOverlayLayer120fps, Gold) {
283 TestPerformanceOverlayLayerGold(120);
284}
285
286} // namespace testing
287} // namespace flutter
sk_sp< DisplayList > Build()
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