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/flow/testing/mock_layer.h"
14 #include "flutter/fml/build_config.h"
15 #include "flutter/fml/macros.h"
16 #include "flutter/testing/mock_canvas.h"
17 #include "gtest/gtest.h"
18 #include "third_party/skia/include/core/SkData.h"
19 #include "third_party/skia/include/core/SkSerialProcs.h"
20 #include "third_party/skia/include/core/SkSurface.h"
21 #include "third_party/skia/include/core/SkTextBlob.h"
22 #include "third_party/skia/include/utils/SkBase64.h"
23 
24 namespace flutter {
25 namespace testing {
26 namespace {
27 
28 // To get the size of kMockedTimes in compile time.
29 template <class T, std::size_t N>
30 constexpr int size(const T (&array)[N]) noexcept {
31  return N;
32 }
33 
34 constexpr int kMockedTimes[] = {17, 1, 4, 24, 4, 25, 30, 4, 13, 34,
35  14, 0, 18, 9, 32, 36, 26, 23, 5, 8,
36  32, 18, 29, 16, 29, 18, 0, 36, 33, 10};
37 
38 static std::string GetGoldenFilePath(int refresh_rate, bool is_new) {
39  std::stringstream ss;
40  // This unit test should only be run on Linux (not even on Mac since it's a
41  // golden test). Hence we don't have to worry about the "/" vs. "\".
42  ss << flutter::GetGoldenDir() << "/"
43  << "performance_overlay_gold_" << refresh_rate << "fps"
44  << (is_new ? "_new" : "") << ".png";
45  return ss.str();
46 }
47 
48 static void TestPerformanceOverlayLayerGold(int refresh_rate) {
49  std::string golden_file_path = GetGoldenFilePath(refresh_rate, false);
50  std::string new_golden_file_path = GetGoldenFilePath(refresh_rate, true);
51 
52  flutter::Stopwatch mock_stopwatch(
53  fml::RefreshRateToFrameBudget(refresh_rate));
54  for (int i = 0; i < size(kMockedTimes); ++i) {
55  mock_stopwatch.SetLapTime(
56  fml::TimeDelta::FromMilliseconds(kMockedTimes[i]));
57  }
58 
59  const SkImageInfo image_info = SkImageInfo::MakeN32Premul(1000, 1000);
60  sk_sp<SkSurface> surface = SkSurface::MakeRaster(image_info);
61 
62  ASSERT_TRUE(surface != nullptr);
63 
64  flutter::TextureRegistry unused_texture_registry;
65  flutter::Layer::PaintContext paintContext = {
66  nullptr, surface->getCanvas(), nullptr, nullptr, mock_stopwatch,
67  mock_stopwatch, unused_texture_registry, nullptr, false};
68 
69  // Specify font file to ensure the same font across different operation
70  // systems.
76  flutter::GetFontFile().c_str());
77  layer.set_paint_bounds(SkRect::MakeWH(1000, 400));
78  surface->getCanvas()->clear(SK_ColorTRANSPARENT);
79  layer.Paint(paintContext);
80 
81  sk_sp<SkImage> snapshot = surface->makeImageSnapshot();
82  sk_sp<SkData> snapshot_data = snapshot->encodeToData();
83 
84  sk_sp<SkData> golden_data =
85  SkData::MakeFromFileName(golden_file_path.c_str());
86  EXPECT_TRUE(golden_data != nullptr)
87  << "Golden file not found: " << golden_file_path << ".\n"
88  << "Please either set --golden-dir, or make sure that the unit test is "
89  << "run from the right directory (e.g., flutter/engine/src).";
90 
91  // TODO(https://github.com/flutter/flutter/issues/53784): enable this on all
92  // platforms.
93 #if !defined(OS_LINUX)
94  GTEST_SKIP() << "Skipping golden tests on non-Linux OSes";
95 #endif // OS_LINUX
96  const bool golden_data_matches = golden_data->equals(snapshot_data.get());
97  if (!golden_data_matches) {
98  SkFILEWStream wstream(new_golden_file_path.c_str());
99  wstream.write(snapshot_data->data(), snapshot_data->size());
100  wstream.flush();
101 
102  size_t b64_size =
103  SkBase64::Encode(snapshot_data->data(), snapshot_data->size(), nullptr);
104  sk_sp<SkData> b64_data = SkData::MakeUninitialized(b64_size + 1);
105  char* b64_char = static_cast<char*>(b64_data->writable_data());
106  SkBase64::Encode(snapshot_data->data(), snapshot_data->size(), b64_char);
107  b64_char[b64_size] = 0; // make it null terminated for printing
108 
109  EXPECT_TRUE(golden_data_matches)
110  << "Golden file mismatch. Please check "
111  << "the difference between " << golden_file_path << " and "
112  << new_golden_file_path << ", and replace the former "
113  << "with the latter if the difference looks good.\nS\n"
114  << "See also the base64 encoded " << new_golden_file_path << ":\n"
115  << b64_char;
116  }
117 }
118 
119 } // namespace
120 
122 
123 TEST_F(PerformanceOverlayLayerTest, PaintingEmptyLayerDies) {
124  const uint64_t overlay_opts = kVisualizeRasterizerStatistics;
125  auto layer = std::make_shared<PerformanceOverlayLayer>(overlay_opts);
126 
127  layer->Preroll(preroll_context(), SkMatrix());
128  EXPECT_EQ(layer->paint_bounds(), SkRect::MakeEmpty());
129  EXPECT_FALSE(layer->needs_painting());
130 
131  // Crashes reading a nullptr.
132  EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()), "");
133 }
134 
136  const SkRect layer_bounds = SkRect::MakeLTRB(0.0f, 0.0f, 64.0f, 64.0f);
137  const uint64_t overlay_opts = 0;
138  auto layer = std::make_shared<PerformanceOverlayLayer>(overlay_opts);
139 
140  // TODO(): Note calling code has to call set_paint_bounds right now. Make
141  // this a constructor parameter and move the set_paint_bounds into Preroll
142  layer->set_paint_bounds(layer_bounds);
143 
144  layer->Preroll(preroll_context(), SkMatrix());
145  EXPECT_EQ(layer->paint_bounds(), layer_bounds);
146  EXPECT_TRUE(layer->needs_painting());
147 
148  // Nothing is drawn if options are invalid (0).
149  layer->Paint(paint_context());
150  EXPECT_EQ(mock_canvas().draw_calls(), std::vector<MockCanvas::DrawCall>());
151 }
152 
153 TEST_F(PerformanceOverlayLayerTest, SimpleRasterizerStatistics) {
154  const SkRect layer_bounds = SkRect::MakeLTRB(0.0f, 0.0f, 64.0f, 64.0f);
155  const uint64_t overlay_opts = kDisplayRasterizerStatistics;
156  auto layer = std::make_shared<PerformanceOverlayLayer>(overlay_opts);
157 
158  // TODO(): Note calling code has to call set_paint_bounds right now. Make
159  // this a constructor parameter and move the set_paint_bounds into Preroll
160  layer->set_paint_bounds(layer_bounds);
161 
162  layer->Preroll(preroll_context(), SkMatrix());
163  EXPECT_EQ(layer->paint_bounds(), layer_bounds);
164  EXPECT_TRUE(layer->needs_painting());
165 
166  layer->Paint(paint_context());
168  paint_context().raster_time, "Raster", "");
169  auto overlay_text_data = overlay_text->serialize(SkSerialProcs{});
170  SkPaint text_paint;
171  text_paint.setColor(SK_ColorGRAY);
172  SkPoint text_position = SkPoint::Make(16.0f, 22.0f);
173  EXPECT_EQ(mock_canvas().draw_calls(),
174  std::vector({MockCanvas::DrawCall{
175  0, MockCanvas::DrawTextData{overlay_text_data, text_paint,
176  text_position}}}));
177 }
178 
179 TEST(PerformanceOverlayLayerDefault, Gold) {
180  TestPerformanceOverlayLayerGold(60);
181 }
182 
183 TEST(PerformanceOverlayLayer90fps, Gold) {
184  TestPerformanceOverlayLayerGold(90);
185 }
186 
187 TEST(PerformanceOverlayLayer120fps, Gold) {
188  TestPerformanceOverlayLayerGold(120);
189 }
190 
191 } // namespace testing
192 } // namespace flutter
const int kDisplayRasterizerStatistics
constexpr std::size_t size(T(&array)[N])
Definition: size.h:13
const std::string & GetGoldenDir()
const int kVisualizeEngineStatistics
LayerTestBase<::testing::Test > LayerTest
Definition: layer_test.h:151
const std::string & GetFontFile()
Milliseconds RefreshRateToFrameBudget(T refresh_rate)
Definition: time_delta.h:24
TEST_F(BackdropFilterLayerTest, PaintingEmptyLayerDies)
const int kVisualizeRasterizerStatistics
const int kDisplayEngineStatistics
static constexpr TimeDelta FromMilliseconds(int64_t millis)
Definition: time_delta.h:46
static sk_sp< SkTextBlob > MakeStatisticsText(const Stopwatch &stopwatch, const std::string &label_prefix, const std::string &font_path)
TEST(EmbeddedViewParams, GetBoundingRectAfterMutationsWithNoMutations)