• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 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 "cc/trees/layer_tree_host.h"
6 
7 #include <sstream>
8 
9 #include "base/file_util.h"
10 #include "base/files/file_path.h"
11 #include "base/path_service.h"
12 #include "base/strings/string_piece.h"
13 #include "base/time/time.h"
14 #include "cc/debug/lap_timer.h"
15 #include "cc/layers/content_layer.h"
16 #include "cc/layers/nine_patch_layer.h"
17 #include "cc/layers/solid_color_layer.h"
18 #include "cc/layers/texture_layer.h"
19 #include "cc/resources/texture_mailbox.h"
20 #include "cc/test/fake_content_layer_client.h"
21 #include "cc/test/layer_tree_json_parser.h"
22 #include "cc/test/layer_tree_test.h"
23 #include "cc/test/paths.h"
24 #include "cc/trees/layer_tree_impl.h"
25 #include "testing/perf/perf_test.h"
26 
27 namespace cc {
28 namespace {
29 
30 static const int kTimeLimitMillis = 2000;
31 static const int kWarmupRuns = 5;
32 static const int kTimeCheckInterval = 10;
33 
34 class LayerTreeHostPerfTest : public LayerTreeTest {
35  public:
LayerTreeHostPerfTest()36   LayerTreeHostPerfTest()
37       : draw_timer_(kWarmupRuns,
38                     base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
39                     kTimeCheckInterval),
40         commit_timer_(0, base::TimeDelta(), 1),
41         full_damage_each_frame_(false),
42         animation_driven_drawing_(false),
43         measure_commit_cost_(false) {
44     fake_content_layer_client_.set_paint_all_opaque(true);
45   }
46 
InitializeSettings(LayerTreeSettings * settings)47   virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
48     settings->throttle_frame_production = false;
49   }
50 
BeginTest()51   virtual void BeginTest() OVERRIDE {
52     BuildTree();
53     PostSetNeedsCommitToMainThread();
54   }
55 
Animate(base::TimeTicks monotonic_time)56   virtual void Animate(base::TimeTicks monotonic_time) OVERRIDE {
57     if (animation_driven_drawing_ && !TestEnded()) {
58       layer_tree_host()->SetNeedsAnimate();
59       layer_tree_host()->SetNextCommitForcesRedraw();
60     }
61   }
62 
BeginCommitOnThread(LayerTreeHostImpl * host_impl)63   virtual void BeginCommitOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
64     if (measure_commit_cost_)
65       commit_timer_.Start();
66   }
67 
CommitCompleteOnThread(LayerTreeHostImpl * host_impl)68   virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
69     if (measure_commit_cost_ && draw_timer_.IsWarmedUp()) {
70       commit_timer_.NextLap();
71     }
72   }
73 
DrawLayersOnThread(LayerTreeHostImpl * impl)74   virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE {
75     if (TestEnded() || CleanUpStarted())
76       return;
77     draw_timer_.NextLap();
78     if (draw_timer_.HasTimeLimitExpired()) {
79       CleanUpAndEndTest(impl);
80       return;
81     }
82     if (!animation_driven_drawing_)
83       impl->SetNeedsRedraw();
84     if (full_damage_each_frame_)
85       impl->SetFullRootLayerDamage();
86   }
87 
CleanUpAndEndTest(LayerTreeHostImpl * host_impl)88   virtual void CleanUpAndEndTest(LayerTreeHostImpl* host_impl) { EndTest(); }
89 
CleanUpStarted()90   virtual bool CleanUpStarted() { return false; }
91 
BuildTree()92   virtual void BuildTree() {}
93 
AfterTest()94   virtual void AfterTest() OVERRIDE {
95     CHECK(!test_name_.empty()) << "Must SetTestName() before AfterTest().";
96     perf_test::PrintResult("layer_tree_host_frame_time", "", test_name_,
97                            1000 * draw_timer_.MsPerLap(), "us", true);
98     if (measure_commit_cost_) {
99       perf_test::PrintResult("layer_tree_host_commit_time", "", test_name_,
100                              1000 * commit_timer_.MsPerLap(), "us", true);
101     }
102   }
103 
104  protected:
105   LapTimer draw_timer_;
106   LapTimer commit_timer_;
107 
108   std::string test_name_;
109   FakeContentLayerClient fake_content_layer_client_;
110   bool full_damage_each_frame_;
111   bool animation_driven_drawing_;
112 
113   bool measure_commit_cost_;
114 };
115 
116 
117 class LayerTreeHostPerfTestJsonReader : public LayerTreeHostPerfTest {
118  public:
LayerTreeHostPerfTestJsonReader()119   LayerTreeHostPerfTestJsonReader()
120       : LayerTreeHostPerfTest() {
121   }
122 
SetTestName(const std::string & name)123   void SetTestName(const std::string& name) {
124     test_name_ = name;
125   }
126 
ReadTestFile(const std::string & name)127   void ReadTestFile(const std::string& name) {
128     base::FilePath test_data_dir;
129     ASSERT_TRUE(PathService::Get(CCPaths::DIR_TEST_DATA, &test_data_dir));
130     base::FilePath json_file = test_data_dir.AppendASCII(name + ".json");
131     ASSERT_TRUE(base::ReadFileToString(json_file, &json_));
132   }
133 
BuildTree()134   virtual void BuildTree() OVERRIDE {
135     gfx::Size viewport = gfx::Size(720, 1038);
136     layer_tree_host()->SetViewportSize(viewport);
137     scoped_refptr<Layer> root = ParseTreeFromJson(json_,
138                                                   &fake_content_layer_client_);
139     ASSERT_TRUE(root.get());
140     layer_tree_host()->SetRootLayer(root);
141   }
142 
143  private:
144   std::string json_;
145 };
146 
147 // Simulates a tab switcher scene with two stacks of 10 tabs each.
TEST_F(LayerTreeHostPerfTestJsonReader,TenTenSingleThread)148 TEST_F(LayerTreeHostPerfTestJsonReader, TenTenSingleThread) {
149   SetTestName("10_10_single_thread");
150   ReadTestFile("10_10_layer_tree");
151   RunTest(false, false, false);
152 }
153 
TEST_F(LayerTreeHostPerfTestJsonReader,TenTenThreadedImplSide)154 TEST_F(LayerTreeHostPerfTestJsonReader, TenTenThreadedImplSide) {
155   SetTestName("10_10_threaded_impl_side");
156   ReadTestFile("10_10_layer_tree");
157   RunTestWithImplSidePainting();
158 }
159 
160 // Simulates a tab switcher scene with two stacks of 10 tabs each.
TEST_F(LayerTreeHostPerfTestJsonReader,TenTenSingleThread_FullDamageEachFrame)161 TEST_F(LayerTreeHostPerfTestJsonReader,
162        TenTenSingleThread_FullDamageEachFrame) {
163   full_damage_each_frame_ = true;
164   SetTestName("10_10_single_thread_full_damage_each_frame");
165   ReadTestFile("10_10_layer_tree");
166   RunTest(false, false, false);
167 }
168 
TEST_F(LayerTreeHostPerfTestJsonReader,TenTenThreadedImplSide_FullDamageEachFrame)169 TEST_F(LayerTreeHostPerfTestJsonReader,
170        TenTenThreadedImplSide_FullDamageEachFrame) {
171   full_damage_each_frame_ = true;
172   SetTestName("10_10_threaded_impl_side_full_damage_each_frame");
173   ReadTestFile("10_10_layer_tree");
174   RunTestWithImplSidePainting();
175 }
176 
177 // Invalidates a leaf layer in the tree on the main thread after every commit.
178 class LayerTreeHostPerfTestLeafInvalidates
179     : public LayerTreeHostPerfTestJsonReader {
180  public:
BuildTree()181   virtual void BuildTree() OVERRIDE {
182     LayerTreeHostPerfTestJsonReader::BuildTree();
183 
184     // Find a leaf layer.
185     for (layer_to_invalidate_ = layer_tree_host()->root_layer();
186          layer_to_invalidate_->children().size();
187          layer_to_invalidate_ = layer_to_invalidate_->children()[0]) {}
188   }
189 
DidCommitAndDrawFrame()190   virtual void DidCommitAndDrawFrame() OVERRIDE {
191     if (TestEnded())
192       return;
193 
194     static bool flip = true;
195     layer_to_invalidate_->SetOpacity(flip ? 1.f : 0.5f);
196     flip = !flip;
197   }
198 
199  protected:
200   Layer* layer_to_invalidate_;
201 };
202 
203 // Simulates a tab switcher scene with two stacks of 10 tabs each. Invalidate a
204 // property on a leaf layer in the tree every commit.
TEST_F(LayerTreeHostPerfTestLeafInvalidates,TenTenSingleThread)205 TEST_F(LayerTreeHostPerfTestLeafInvalidates, TenTenSingleThread) {
206   SetTestName("10_10_single_thread_leaf_invalidates");
207   ReadTestFile("10_10_layer_tree");
208   RunTest(false, false, false);
209 }
210 
TEST_F(LayerTreeHostPerfTestLeafInvalidates,TenTenThreadedImplSide)211 TEST_F(LayerTreeHostPerfTestLeafInvalidates, TenTenThreadedImplSide) {
212   SetTestName("10_10_threaded_impl_side_leaf_invalidates");
213   ReadTestFile("10_10_layer_tree");
214   RunTestWithImplSidePainting();
215 }
216 
217 // Simulates main-thread scrolling on each frame.
218 class ScrollingLayerTreePerfTest : public LayerTreeHostPerfTestJsonReader {
219  public:
ScrollingLayerTreePerfTest()220   ScrollingLayerTreePerfTest()
221       : LayerTreeHostPerfTestJsonReader() {
222   }
223 
BuildTree()224   virtual void BuildTree() OVERRIDE {
225     LayerTreeHostPerfTestJsonReader::BuildTree();
226     scrollable_ = layer_tree_host()->root_layer()->children()[1];
227     ASSERT_TRUE(scrollable_.get());
228   }
229 
Layout()230   virtual void Layout() OVERRIDE {
231     static const gfx::Vector2d delta = gfx::Vector2d(0, 10);
232     scrollable_->SetScrollOffset(scrollable_->scroll_offset() + delta);
233   }
234 
235  private:
236   scoped_refptr<Layer> scrollable_;
237 };
238 
TEST_F(ScrollingLayerTreePerfTest,LongScrollablePageSingleThread)239 TEST_F(ScrollingLayerTreePerfTest, LongScrollablePageSingleThread) {
240   SetTestName("long_scrollable_page");
241   ReadTestFile("long_scrollable_page");
242   RunTest(false, false, false);
243 }
244 
TEST_F(ScrollingLayerTreePerfTest,LongScrollablePageThreadedImplSide)245 TEST_F(ScrollingLayerTreePerfTest, LongScrollablePageThreadedImplSide) {
246   SetTestName("long_scrollable_page_threaded_impl_side");
247   ReadTestFile("long_scrollable_page");
248   RunTestWithImplSidePainting();
249 }
250 
EmptyReleaseCallback(uint32 sync_point,bool lost_resource)251 static void EmptyReleaseCallback(uint32 sync_point, bool lost_resource) {}
252 
253 // Simulates main-thread scrolling on each frame.
254 class BrowserCompositorInvalidateLayerTreePerfTest
255     : public LayerTreeHostPerfTestJsonReader {
256  public:
BrowserCompositorInvalidateLayerTreePerfTest()257   BrowserCompositorInvalidateLayerTreePerfTest()
258       : LayerTreeHostPerfTestJsonReader(),
259         next_sync_point_(1),
260         clean_up_started_(false) {}
261 
BuildTree()262   virtual void BuildTree() OVERRIDE {
263     LayerTreeHostPerfTestJsonReader::BuildTree();
264     tab_contents_ =
265         static_cast<TextureLayer*>(
266             layer_tree_host()->root_layer()->children()[0]->
267                                              children()[0]->
268                                              children()[0]->
269                                              children()[0].get());
270     ASSERT_TRUE(tab_contents_.get());
271   }
272 
WillCommit()273   virtual void WillCommit() OVERRIDE {
274     if (CleanUpStarted())
275       return;
276     gpu::Mailbox gpu_mailbox;
277     std::ostringstream name_stream;
278     name_stream << "name" << next_sync_point_;
279     gpu_mailbox.SetName(
280         reinterpret_cast<const int8*>(name_stream.str().c_str()));
281     scoped_ptr<SingleReleaseCallback> callback = SingleReleaseCallback::Create(
282         base::Bind(&EmptyReleaseCallback));
283     TextureMailbox mailbox(gpu_mailbox, GL_TEXTURE_2D, next_sync_point_);
284     next_sync_point_++;
285 
286     tab_contents_->SetTextureMailbox(mailbox, callback.Pass());
287   }
288 
DidCommit()289   virtual void DidCommit() OVERRIDE {
290     if (CleanUpStarted())
291       return;
292     layer_tree_host()->SetNeedsCommit();
293   }
294 
CleanUpAndEndTest(LayerTreeHostImpl * host_impl)295   virtual void CleanUpAndEndTest(LayerTreeHostImpl* host_impl) OVERRIDE {
296     clean_up_started_ = true;
297     MainThreadTaskRunner()->PostTask(
298         FROM_HERE,
299         base::Bind(&BrowserCompositorInvalidateLayerTreePerfTest::
300                         CleanUpAndEndTestOnMainThread,
301                    base::Unretained(this)));
302   }
303 
CleanUpAndEndTestOnMainThread()304   void CleanUpAndEndTestOnMainThread() {
305     tab_contents_->SetTextureMailbox(TextureMailbox(),
306                                      scoped_ptr<SingleReleaseCallback>());
307     EndTest();
308   }
309 
CleanUpStarted()310   virtual bool CleanUpStarted() OVERRIDE { return clean_up_started_; }
311 
312  private:
313   scoped_refptr<TextureLayer> tab_contents_;
314   unsigned next_sync_point_;
315   bool clean_up_started_;
316 };
317 
TEST_F(BrowserCompositorInvalidateLayerTreePerfTest,DenseBrowserUI)318 TEST_F(BrowserCompositorInvalidateLayerTreePerfTest, DenseBrowserUI) {
319   measure_commit_cost_ = true;
320   SetTestName("dense_layer_tree");
321   ReadTestFile("dense_layer_tree");
322   RunTestWithImplSidePainting();
323 }
324 
325 // Simulates a page with several large, transformed and animated layers.
TEST_F(LayerTreeHostPerfTestJsonReader,HeavyPageThreadedImplSide)326 TEST_F(LayerTreeHostPerfTestJsonReader, HeavyPageThreadedImplSide) {
327   animation_driven_drawing_ = true;
328   measure_commit_cost_ = true;
329   SetTestName("heavy_page");
330   ReadTestFile("heavy_layer_tree");
331   RunTestWithImplSidePainting();
332 }
333 
334 }  // namespace
335 }  // namespace cc
336