1 // Copyright 2016 The Chromium 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 <stddef.h>
6 
7 #include <memory>
8 #include <sstream>
9 
10 #include "base/containers/circular_deque.h"
11 #include "base/files/file_path.h"
12 #include "base/files/file_util.h"
13 #include "base/path_service.h"
14 #include "base/strings/string_piece.h"
15 #include "base/threading/thread.h"
16 #include "base/time/time.h"
17 #include "base/timer/lap_timer.h"
18 #include "cc/layers/layer.h"
19 #include "cc/test/fake_content_layer_client.h"
20 #include "cc/test/fake_layer_tree_host_client.h"
21 #include "cc/test/layer_tree_json_parser.h"
22 #include "cc/test/layer_tree_test.h"
23 #include "cc/trees/layer_tree_impl.h"
24 #include "cc/trees/transform_node.h"
25 #include "components/viz/service/display/bsp_tree.h"
26 #include "components/viz/service/display/draw_polygon.h"
27 #include "components/viz/test/paths.h"
28 #include "testing/perf/perf_result_reporter.h"
29 
30 namespace viz {
31 namespace {
32 
33 static const int kTimeLimitMillis = 2000;
34 static const int kWarmupRuns = 5;
35 static const int kTimeCheckInterval = 10;
36 
37 const char kMetricPrefixBspTree[] = "BspTree.";
38 const char kMetricCalcDrawPropsTimeUs[] = "calc_draw_props_time";
39 
SetUpBspTreeReporter(const std::string & story)40 perf_test::PerfResultReporter SetUpBspTreeReporter(const std::string& story) {
41   perf_test::PerfResultReporter reporter(kMetricPrefixBspTree, story);
42   reporter.RegisterImportantMetric(kMetricCalcDrawPropsTimeUs, "us");
43   return reporter;
44 }
45 
46 class BspTreePerfTest : public cc::LayerTreeTest {
47  public:
BspTreePerfTest()48   BspTreePerfTest()
49       : timer_(kWarmupRuns,
50                base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
51                kTimeCheckInterval) {}
52 
SetupTree()53   void SetupTree() override {
54     gfx::Size viewport = gfx::Size(720, 1038);
55     layer_tree_host()->SetViewportRectAndScale(gfx::Rect(viewport), 1.f,
56                                                LocalSurfaceId());
57     scoped_refptr<cc::Layer> root =
58         ParseTreeFromJson(json_, &content_layer_client_);
59     ASSERT_TRUE(root.get());
60     layer_tree_host()->SetRootLayer(root);
61     content_layer_client_.set_bounds(viewport);
62   }
63 
SetStory(const std::string & story)64   void SetStory(const std::string& story) { story_ = story; }
65 
SetNumberOfDuplicates(int num_duplicates)66   void SetNumberOfDuplicates(int num_duplicates) {
67     num_duplicates_ = num_duplicates;
68   }
69 
ReadTestFile(const std::string & name)70   void ReadTestFile(const std::string& name) {
71     base::FilePath test_data_dir;
72     ASSERT_TRUE(base::PathService::Get(Paths::DIR_TEST_DATA, &test_data_dir));
73     base::FilePath json_file = test_data_dir.AppendASCII(name + ".json");
74     ASSERT_TRUE(base::ReadFileToString(json_file, &json_));
75   }
76 
BeginTest()77   void BeginTest() override { PostSetNeedsCommitToMainThread(); }
78 
DrawLayersOnThread(cc::LayerTreeHostImpl * host_impl)79   void DrawLayersOnThread(cc::LayerTreeHostImpl* host_impl) override {
80     cc::LayerTreeImpl* active_tree = host_impl->active_tree();
81     // First build the tree and then we'll start running tests on layersorter
82     // itself
83     host_impl->active_tree()->UpdateDrawProperties();
84 
85     cc::LayerImplList base_list;
86     BuildLayerImplList(active_tree->root_layer(), &base_list);
87 
88     int polygon_counter = 0;
89     std::vector<std::unique_ptr<DrawPolygon>> polygon_list;
90     for (auto it = base_list.begin(); it != base_list.end(); ++it) {
91       DrawPolygon* draw_polygon = new DrawPolygon(
92           nullptr, gfx::RectF(gfx::SizeF((*it)->bounds())),
93           (*it)->draw_properties().target_space_transform, polygon_counter++);
94       polygon_list.push_back(std::unique_ptr<DrawPolygon>(draw_polygon));
95     }
96 
97     timer_.Reset();
98     do {
99       base::circular_deque<std::unique_ptr<DrawPolygon>> test_list;
100       for (int i = 0; i < num_duplicates_; i++) {
101         for (size_t i = 0; i < polygon_list.size(); i++) {
102           test_list.push_back(polygon_list[i]->CreateCopy());
103         }
104       }
105       BspTree bsp_tree(&test_list);
106       timer_.NextLap();
107     } while (!timer_.HasTimeLimitExpired());
108 
109     EndTest();
110   }
111 
BuildLayerImplList(cc::LayerImpl * layer,cc::LayerImplList * list)112   void BuildLayerImplList(cc::LayerImpl* layer, cc::LayerImplList* list) {
113     for (auto* layer_impl : *layer->layer_tree_impl()) {
114       if (layer_impl->Is3dSorted() && !layer_impl->bounds().IsEmpty()) {
115         list->push_back(layer_impl);
116       }
117     }
118   }
119 
AfterTest()120   void AfterTest() override {
121     CHECK(!story_.empty()) << "Must SetStory() before TearDown().";
122     auto reporter = SetUpBspTreeReporter(story_);
123     reporter.AddResult(kMetricCalcDrawPropsTimeUs,
124                        timer_.TimePerLap().InMicrosecondsF());
125   }
126 
127  private:
128   cc::FakeContentLayerClient content_layer_client_;
129   base::LapTimer timer_;
130   std::string story_;
131   std::string json_;
132   cc::LayerImplList base_list_;
133   int num_duplicates_ = 1;
134 };
135 
TEST_F(BspTreePerfTest,LayerSorterCubes)136 TEST_F(BspTreePerfTest, LayerSorterCubes) {
137   SetStory("layer_sort_cubes");
138   ReadTestFile("layer_sort_cubes");
139   RunTest(cc::CompositorMode::SINGLE_THREADED);
140 }
141 
TEST_F(BspTreePerfTest,LayerSorterRubik)142 TEST_F(BspTreePerfTest, LayerSorterRubik) {
143   SetStory("layer_sort_rubik");
144   ReadTestFile("layer_sort_rubik");
145   RunTest(cc::CompositorMode::SINGLE_THREADED);
146 }
147 
TEST_F(BspTreePerfTest,BspTreeCubes)148 TEST_F(BspTreePerfTest, BspTreeCubes) {
149   SetStory("bsp_tree_cubes");
150   SetNumberOfDuplicates(1);
151   ReadTestFile("layer_sort_cubes");
152   RunTest(cc::CompositorMode::SINGLE_THREADED);
153 }
154 
TEST_F(BspTreePerfTest,BspTreeRubik)155 TEST_F(BspTreePerfTest, BspTreeRubik) {
156   SetStory("bsp_tree_rubik");
157   SetNumberOfDuplicates(1);
158   ReadTestFile("layer_sort_rubik");
159   RunTest(cc::CompositorMode::SINGLE_THREADED);
160 }
161 
TEST_F(BspTreePerfTest,BspTreeCubes_2)162 TEST_F(BspTreePerfTest, BspTreeCubes_2) {
163   SetStory("bsp_tree_cubes_2");
164   SetNumberOfDuplicates(2);
165   ReadTestFile("layer_sort_cubes");
166   RunTest(cc::CompositorMode::SINGLE_THREADED);
167 }
168 
TEST_F(BspTreePerfTest,BspTreeCubes_4)169 TEST_F(BspTreePerfTest, BspTreeCubes_4) {
170   SetStory("bsp_tree_cubes_4");
171   SetNumberOfDuplicates(4);
172   ReadTestFile("layer_sort_cubes");
173   RunTest(cc::CompositorMode::SINGLE_THREADED);
174 }
175 
176 }  // namespace
177 }  // namespace viz
178