diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 31ba579d95761..4509c7d13bb7d 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -88,6 +88,7 @@ FILE: ../../../flutter/flow/layers/opacity_layer.cc FILE: ../../../flutter/flow/layers/opacity_layer.h FILE: ../../../flutter/flow/layers/performance_overlay_layer.cc FILE: ../../../flutter/flow/layers/performance_overlay_layer.h +FILE: ../../../flutter/flow/layers/performance_overlay_layer_unittests.cc FILE: ../../../flutter/flow/layers/physical_shape_layer.cc FILE: ../../../flutter/flow/layers/physical_shape_layer.h FILE: ../../../flutter/flow/layers/picture_layer.cc @@ -727,9 +728,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== ==================================================================================================== +LIBRARY: engine LIBRARY: txt ORIGIN: ../../../flutter/third_party/txt/LICENSE TYPE: LicenseType.apache +FILE: ../../../flutter/flow/flow_run_all_unittests.cc +FILE: ../../../flutter/flow/flow_test_utils.cc +FILE: ../../../flutter/flow/flow_test_utils.h FILE: ../../../flutter/third_party/txt/benchmarks/paint_record_benchmarks.cc FILE: ../../../flutter/third_party/txt/benchmarks/paragraph_benchmarks.cc FILE: ../../../flutter/third_party/txt/benchmarks/paragraph_builder_benchmarks.cc diff --git a/flow/BUILD.gn b/flow/BUILD.gn index 6b345aa87a35a..fbbf0e49db095 100644 --- a/flow/BUILD.gn +++ b/flow/BUILD.gn @@ -93,13 +93,18 @@ executable("flow_unittests") { testonly = true sources = [ + "flow_run_all_unittests.cc", + "flow_test_utils.h", + "flow_test_utils.cc", "matrix_decomposition_unittests.cc", "raster_cache_unittests.cc", + "layers/performance_overlay_layer_unittests.cc", ] deps = [ ":flow", - "$flutter_root/testing", + "$flutter_root/fml", + "//third_party/googletest:gtest", "//third_party/dart/runtime:libdart_jit", # for tracing "//third_party/skia", ] diff --git a/flow/flow_run_all_unittests.cc b/flow/flow_run_all_unittests.cc new file mode 100644 index 0000000000000..c1755e639b037 --- /dev/null +++ b/flow/flow_run_all_unittests.cc @@ -0,0 +1,32 @@ +/* + * Copyright 2017 Google, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "flutter/fml/command_line.h" +#include "flutter/fml/logging.h" +#include "gtest/gtest.h" + +#include "flow_test_utils.h" + +int main(int argc, char** argv) { + testing::InitGoogleTest(&argc, argv); + fml::CommandLine cmd = fml::CommandLineFromArgcArgv(argc, argv); + flow::SetGoldenDir( + cmd.GetOptionValueWithDefault("golden-dir", "flutter/testing/resources")); + flow::SetFontFile(cmd.GetOptionValueWithDefault( + "font-file", + "flutter/third_party/txt/third_party/fonts/Roboto-Regular.ttf")); + return RUN_ALL_TESTS(); +} diff --git a/flow/flow_test_utils.cc b/flow/flow_test_utils.cc new file mode 100644 index 0000000000000..0bf6d4c31d4d9 --- /dev/null +++ b/flow/flow_test_utils.cc @@ -0,0 +1,40 @@ +/* + * Copyright 2017 Google, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace flow { + +static std::string gGoldenDir; +static std::string gFontFile; + +const std::string& GetGoldenDir() { + return gGoldenDir; +} + +void SetGoldenDir(const std::string& dir) { + gGoldenDir = dir; +} + +const std::string& GetFontFile() { + return gFontFile; +} + +void SetFontFile(const std::string& file) { + gFontFile = file; +} + +} // namespace flow diff --git a/flow/flow_test_utils.h b/flow/flow_test_utils.h new file mode 100644 index 0000000000000..58da75b3f4dde --- /dev/null +++ b/flow/flow_test_utils.h @@ -0,0 +1,29 @@ +/* + * Copyright 2017 Google, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace flow { + +const std::string& GetGoldenDir(); + +void SetGoldenDir(const std::string& dir); + +const std::string& GetFontFile(); + +void SetFontFile(const std::string& dir); + +} // namespace flow diff --git a/flow/layers/performance_overlay_layer.cc b/flow/layers/performance_overlay_layer.cc index c80786e866e1b..e7f40058c3bfb 100644 --- a/flow/layers/performance_overlay_layer.cc +++ b/flow/layers/performance_overlay_layer.cc @@ -15,8 +15,12 @@ namespace { void DrawStatisticsText(SkCanvas& canvas, const std::string& string, int x, - int y) { + int y, + const std::string& font_path) { SkFont font; + if (font_path != "") { + font = SkFont(SkTypeface::MakeFromFile(font_path.c_str())); + } font.setSize(15); font.setLinearMetrics(false); SkPaint paint; @@ -33,7 +37,8 @@ void VisualizeStopWatch(SkCanvas& canvas, SkScalar height, bool show_graph, bool show_labels, - const std::string& label_prefix) { + const std::string& label_prefix, + const std::string& font_path) { const int label_x = 8; // distance from x const int label_y = -10; // distance from y+height @@ -51,14 +56,20 @@ void VisualizeStopWatch(SkCanvas& canvas, stream << label_prefix << " " << "max " << max_ms_per_frame << " ms/frame, " << "avg " << average_ms_per_frame << " ms/frame"; - DrawStatisticsText(canvas, stream.str(), x + label_x, y + height + label_y); + DrawStatisticsText(canvas, stream.str(), x + label_x, y + height + label_y, + font_path); } } } // namespace -PerformanceOverlayLayer::PerformanceOverlayLayer(uint64_t options) - : options_(options) {} +PerformanceOverlayLayer::PerformanceOverlayLayer(uint64_t options, + const char* font_path) + : options_(options) { + if (font_path != nullptr) { + font_path_ = font_path; + } +} void PerformanceOverlayLayer::Paint(PaintContext& context) const { const int padding = 8; @@ -73,15 +84,15 @@ void PerformanceOverlayLayer::Paint(PaintContext& context) const { SkScalar height = paint_bounds().height() / 2; SkAutoCanvasRestore save(context.leaf_nodes_canvas, true); - VisualizeStopWatch(*context.leaf_nodes_canvas, context.frame_time, x, y, - width, height - padding, - options_ & kVisualizeRasterizerStatistics, - options_ & kDisplayRasterizerStatistics, "GPU"); + VisualizeStopWatch( + *context.leaf_nodes_canvas, context.frame_time, x, y, width, + height - padding, options_ & kVisualizeRasterizerStatistics, + options_ & kDisplayRasterizerStatistics, "GPU", font_path_); VisualizeStopWatch(*context.leaf_nodes_canvas, context.engine_time, x, y + height, width, height - padding, options_ & kVisualizeEngineStatistics, - options_ & kDisplayEngineStatistics, "UI"); + options_ & kDisplayEngineStatistics, "UI", font_path_); } } // namespace flow diff --git a/flow/layers/performance_overlay_layer.h b/flow/layers/performance_overlay_layer.h index b5f20ecbd7a6b..a47b836c49f3a 100644 --- a/flow/layers/performance_overlay_layer.h +++ b/flow/layers/performance_overlay_layer.h @@ -5,6 +5,8 @@ #ifndef FLUTTER_FLOW_LAYERS_PERFORMANCE_OVERLAY_LAYER_H_ #define FLUTTER_FLOW_LAYERS_PERFORMANCE_OVERLAY_LAYER_H_ +#include + #include "flutter/flow/layers/layer.h" #include "flutter/fml/macros.h" @@ -17,12 +19,14 @@ const int kVisualizeEngineStatistics = 1 << 3; class PerformanceOverlayLayer : public Layer { public: - explicit PerformanceOverlayLayer(uint64_t options); + explicit PerformanceOverlayLayer(uint64_t options, + const char* font_path = nullptr); void Paint(PaintContext& context) const override; private: int options_; + std::string font_path_; FML_DISALLOW_COPY_AND_ASSIGN(PerformanceOverlayLayer); }; diff --git a/flow/layers/performance_overlay_layer_unittests.cc b/flow/layers/performance_overlay_layer_unittests.cc new file mode 100644 index 0000000000000..f64f53422fb37 --- /dev/null +++ b/flow/layers/performance_overlay_layer_unittests.cc @@ -0,0 +1,96 @@ +// 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/flow_test_utils.h" +#include "flutter/flow/layers/performance_overlay_layer.h" +#include "flutter/flow/raster_cache.h" + +#include "third_party/skia/include/core/SkSurface.h" +#include "third_party/skia/include/utils/SkBase64.h" + +#include "gtest/gtest.h" + +// To get the size of kMockedTimes in compile time. +template +constexpr int size(const T (&array)[N]) noexcept { + return N; +} + +constexpr int kMockedTimes[] = {17, 1, 4, 24, 4, 25, 30, 4, 13, 34, + 14, 0, 18, 9, 32, 36, 26, 23, 5, 8, + 32, 18, 29, 16, 29, 18, 0, 36, 33, 10}; + +// Relative to the flutter/src/engine/flutter directory +const char* kGoldenFileName = "performance_overlay_gold.png"; + +// Relative to the flutter/src/engine/flutter directory +const char* kNewGoldenFileName = "performance_overlay_gold_new.png"; + +TEST(PerformanceOverlayLayer, Gold) { + const std::string& golden_dir = flow::GetGoldenDir(); + // This unit test should only be run on Linux (not even on Mac since it's a + // golden test). Hence we don't have to worry about the "/" vs. "\". + std::string golden_file_path = golden_dir + "/" + kGoldenFileName; + std::string new_golden_file_path = golden_dir + "/" + kNewGoldenFileName; + + flow::Stopwatch mock_stopwatch; + for (int i = 0; i < size(kMockedTimes); ++i) { + mock_stopwatch.SetLapTime( + fml::TimeDelta::FromMilliseconds(kMockedTimes[i])); + } + + const SkImageInfo image_info = SkImageInfo::MakeN32Premul(1000, 1000); + sk_sp surface = SkSurface::MakeRaster(image_info); + + ASSERT_TRUE(surface != nullptr); + + flow::TextureRegistry unused_texture_registry; + + flow::Layer::PaintContext paintContext = { + nullptr, surface->getCanvas(), nullptr, mock_stopwatch, + mock_stopwatch, unused_texture_registry, nullptr, false}; + + // Specify font file to ensure the same font across different operation + // systems. + flow::PerformanceOverlayLayer layer(flow::kDisplayRasterizerStatistics | + flow::kVisualizeRasterizerStatistics | + flow::kDisplayEngineStatistics | + flow::kVisualizeEngineStatistics, + flow::GetFontFile().c_str()); + layer.set_paint_bounds(SkRect::MakeWH(1000, 400)); + surface->getCanvas()->clear(SK_ColorTRANSPARENT); + layer.Paint(paintContext); + + sk_sp snapshot = surface->makeImageSnapshot(); + sk_sp snapshot_data = snapshot->encodeToData(); + + sk_sp golden_data = + SkData::MakeFromFileName(golden_file_path.c_str()); + EXPECT_TRUE(golden_data != nullptr) + << "Golden file not found: " << golden_file_path << ".\n" + << "Please either set --golden-dir, or make sure that the unit test is " + << "run from the right directory (e.g., flutter/engine/src)."; + + const bool golden_data_matches = golden_data->equals(snapshot_data.get()); + if (!golden_data_matches) { + SkFILEWStream wstream(new_golden_file_path.c_str()); + wstream.write(snapshot_data->data(), snapshot_data->size()); + wstream.flush(); + + size_t b64_size = + SkBase64::Encode(snapshot_data->data(), snapshot_data->size(), nullptr); + char* b64_data = new char[b64_size]; + SkBase64::Encode(snapshot_data->data(), snapshot_data->size(), b64_data); + + EXPECT_TRUE(golden_data_matches) + << "Golden file mismatch. Please check " + << "the difference between " << kGoldenFileName << " and " + << kNewGoldenFileName << ", and replace the former " + << "with the latter if the difference looks good.\n\n" + << "See also the base64 encoded " << kNewGoldenFileName << ":\n" + << b64_data; + + delete[] b64_data; + } +} diff --git a/testing/resources/performance_overlay_gold.png b/testing/resources/performance_overlay_gold.png new file mode 100644 index 0000000000000..119551f705793 Binary files /dev/null and b/testing/resources/performance_overlay_gold.png differ