- add sources.
[platform/framework/web/crosswalk.git] / src / cc / trees / layer_tree_host_perftest.cc
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/layers/content_layer.h"
15 #include "cc/layers/nine_patch_layer.h"
16 #include "cc/layers/solid_color_layer.h"
17 #include "cc/layers/texture_layer.h"
18 #include "cc/resources/texture_mailbox.h"
19 #include "cc/test/fake_content_layer_client.h"
20 #include "cc/test/lap_timer.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:
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
47   virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
48     settings->throttle_frame_production = false;
49   }
50
51   virtual void BeginTest() OVERRIDE {
52     BuildTree();
53     PostSetNeedsCommitToMainThread();
54   }
55
56   virtual void Animate(base::TimeTicks monotonic_time) OVERRIDE {
57     if (animation_driven_drawing_ && !TestEnded())
58       layer_tree_host()->SetNeedsAnimate();
59   }
60
61   virtual void BeginCommitOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
62     if (measure_commit_cost_)
63       commit_timer_.Start();
64   }
65
66   virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
67     if (measure_commit_cost_ && draw_timer_.IsWarmedUp()) {
68       commit_timer_.NextLap();
69     }
70   }
71
72   virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE {
73     if (TestEnded()) {
74       return;
75     }
76     draw_timer_.NextLap();
77     if (draw_timer_.HasTimeLimitExpired()) {
78       EndTest();
79       return;
80     }
81     if (!animation_driven_drawing_)
82       impl->SetNeedsRedraw();
83     if (full_damage_each_frame_)
84       impl->SetFullRootLayerDamage();
85   }
86
87   virtual void BuildTree() {}
88
89   virtual void AfterTest() OVERRIDE {
90     CHECK(!test_name_.empty()) << "Must SetTestName() before AfterTest().";
91     perf_test::PrintResult("layer_tree_host_frame_count", "", test_name_,
92                            draw_timer_.NumLaps(), "frame_count", true);
93     perf_test::PrintResult("layer_tree_host_frame_time", "", test_name_,
94                            1000 * draw_timer_.MsPerLap(), "us", true);
95     if (measure_commit_cost_) {
96       perf_test::PrintResult("layer_tree_host_commit_count", "", test_name_,
97                              commit_timer_.NumLaps(), "commit_count", true);
98       perf_test::PrintResult("layer_tree_host_commit_time", "", test_name_,
99                              1000 * commit_timer_.MsPerLap(), "us", true);
100     }
101   }
102
103  protected:
104   LapTimer draw_timer_;
105   LapTimer commit_timer_;
106
107   std::string test_name_;
108   FakeContentLayerClient fake_content_layer_client_;
109   bool full_damage_each_frame_;
110   bool animation_driven_drawing_;
111
112   bool measure_commit_cost_;
113 };
114
115
116 class LayerTreeHostPerfTestJsonReader : public LayerTreeHostPerfTest {
117  public:
118   LayerTreeHostPerfTestJsonReader()
119       : LayerTreeHostPerfTest() {
120   }
121
122   void SetTestName(const std::string& name) {
123     test_name_ = name;
124   }
125
126   void ReadTestFile(const std::string& name) {
127     base::FilePath test_data_dir;
128     ASSERT_TRUE(PathService::Get(cc::DIR_TEST_DATA, &test_data_dir));
129     base::FilePath json_file = test_data_dir.AppendASCII(name + ".json");
130     ASSERT_TRUE(base::ReadFileToString(json_file, &json_));
131   }
132
133   virtual void BuildTree() OVERRIDE {
134     gfx::Size viewport = gfx::Size(720, 1038);
135     layer_tree_host()->SetViewportSize(viewport);
136     scoped_refptr<Layer> root = ParseTreeFromJson(json_,
137                                                   &fake_content_layer_client_);
138     ASSERT_TRUE(root.get());
139     layer_tree_host()->SetRootLayer(root);
140   }
141
142  private:
143   std::string json_;
144 };
145
146 // Simulates a tab switcher scene with two stacks of 10 tabs each.
147 TEST_F(LayerTreeHostPerfTestJsonReader, TenTenSingleThread) {
148   SetTestName("10_10_single_thread");
149   ReadTestFile("10_10_layer_tree");
150   RunTest(false, false, false);
151 }
152
153 TEST_F(LayerTreeHostPerfTestJsonReader, TenTenThreadedImplSide) {
154   SetTestName("10_10_threaded_impl_side");
155   ReadTestFile("10_10_layer_tree");
156   RunTestWithImplSidePainting();
157 }
158
159 // Simulates a tab switcher scene with two stacks of 10 tabs each.
160 TEST_F(LayerTreeHostPerfTestJsonReader,
161        TenTenSingleThread_FullDamageEachFrame) {
162   full_damage_each_frame_ = true;
163   SetTestName("10_10_single_thread_full_damage_each_frame");
164   ReadTestFile("10_10_layer_tree");
165   RunTest(false, false, false);
166 }
167
168 TEST_F(LayerTreeHostPerfTestJsonReader,
169        TenTenThreadedImplSide_FullDamageEachFrame) {
170   full_damage_each_frame_ = true;
171   SetTestName("10_10_threaded_impl_side_full_damage_each_frame");
172   ReadTestFile("10_10_layer_tree");
173   RunTestWithImplSidePainting();
174 }
175
176 // Invalidates a leaf layer in the tree on the main thread after every commit.
177 class LayerTreeHostPerfTestLeafInvalidates
178     : public LayerTreeHostPerfTestJsonReader {
179  public:
180   virtual void BuildTree() OVERRIDE {
181     LayerTreeHostPerfTestJsonReader::BuildTree();
182
183     // Find a leaf layer.
184     for (layer_to_invalidate_ = layer_tree_host()->root_layer();
185          layer_to_invalidate_->children().size();
186          layer_to_invalidate_ = layer_to_invalidate_->children()[0]) {}
187   }
188
189   virtual void DidCommitAndDrawFrame() OVERRIDE {
190     if (TestEnded())
191       return;
192
193     static bool flip = true;
194     layer_to_invalidate_->SetOpacity(flip ? 1.f : 0.5f);
195     flip = !flip;
196   }
197
198  protected:
199   Layer* layer_to_invalidate_;
200 };
201
202 // Simulates a tab switcher scene with two stacks of 10 tabs each. Invalidate a
203 // property on a leaf layer in the tree every commit.
204 TEST_F(LayerTreeHostPerfTestLeafInvalidates, TenTenSingleThread) {
205   SetTestName("10_10_single_thread_leaf_invalidates");
206   ReadTestFile("10_10_layer_tree");
207   RunTest(false, false, false);
208 }
209
210 TEST_F(LayerTreeHostPerfTestLeafInvalidates, TenTenThreadedImplSide) {
211   SetTestName("10_10_threaded_impl_side_leaf_invalidates");
212   ReadTestFile("10_10_layer_tree");
213   RunTestWithImplSidePainting();
214 }
215
216 // Simulates main-thread scrolling on each frame.
217 class ScrollingLayerTreePerfTest : public LayerTreeHostPerfTestJsonReader {
218  public:
219   ScrollingLayerTreePerfTest()
220       : LayerTreeHostPerfTestJsonReader() {
221   }
222
223   virtual void BuildTree() OVERRIDE {
224     LayerTreeHostPerfTestJsonReader::BuildTree();
225     scrollable_ = layer_tree_host()->root_layer()->children()[1];
226     ASSERT_TRUE(scrollable_.get());
227   }
228
229   virtual void Layout() OVERRIDE {
230     static const gfx::Vector2d delta = gfx::Vector2d(0, 10);
231     scrollable_->SetScrollOffset(scrollable_->scroll_offset() + delta);
232   }
233
234  private:
235   scoped_refptr<Layer> scrollable_;
236 };
237
238 TEST_F(ScrollingLayerTreePerfTest, LongScrollablePageSingleThread) {
239   SetTestName("long_scrollable_page");
240   ReadTestFile("long_scrollable_page");
241   RunTest(false, false, false);
242 }
243
244 TEST_F(ScrollingLayerTreePerfTest, LongScrollablePageThreadedImplSide) {
245   SetTestName("long_scrollable_page_threaded_impl_side");
246   ReadTestFile("long_scrollable_page");
247   RunTestWithImplSidePainting();
248 }
249
250 static void EmptyReleaseCallback(unsigned sync_point, bool lost_resource) {}
251
252 // Simulates main-thread scrolling on each frame.
253 class BrowserCompositorInvalidateLayerTreePerfTest
254     : public LayerTreeHostPerfTestJsonReader {
255  public:
256   BrowserCompositorInvalidateLayerTreePerfTest()
257       : next_sync_point_(1) {
258   }
259
260   virtual void BuildTree() OVERRIDE {
261     LayerTreeHostPerfTestJsonReader::BuildTree();
262     tab_contents_ =
263         static_cast<TextureLayer*>(
264             layer_tree_host()->root_layer()->children()[0]->
265                                              children()[0]->
266                                              children()[0]->
267                                              children()[0].get());
268     ASSERT_TRUE(tab_contents_.get());
269   }
270
271   virtual void Layout() OVERRIDE {
272     gpu::Mailbox gpu_mailbox;
273     std::ostringstream name_stream;
274     name_stream << "name" << next_sync_point_;
275     const char* name = name_stream.str().c_str();
276     memcpy(gpu_mailbox.name, name, strlen(name) + 1);
277     scoped_ptr<SingleReleaseCallback> callback = SingleReleaseCallback::Create(
278         base::Bind(&EmptyReleaseCallback));
279     TextureMailbox mailbox(gpu_mailbox, next_sync_point_);
280     next_sync_point_++;
281
282     tab_contents_->SetTextureMailbox(mailbox, callback.Pass());
283   }
284
285  private:
286   scoped_refptr<TextureLayer> tab_contents_;
287   unsigned next_sync_point_;
288 };
289
290 TEST_F(BrowserCompositorInvalidateLayerTreePerfTest, DenseBrowserUI) {
291   SetTestName("dense_layer_tree");
292   ReadTestFile("dense_layer_tree");
293   RunTestWithImplSidePainting();
294 }
295
296 // Simulates a page with several large, transformed and animated layers.
297 TEST_F(LayerTreeHostPerfTestJsonReader, HeavyPageThreadedImplSide) {
298   animation_driven_drawing_ = true;
299   measure_commit_cost_ = true;
300   SetTestName("heavy_page");
301   ReadTestFile("heavy_layer_tree");
302   RunTestWithImplSidePainting();
303 }
304
305 class PageScaleImplSidePaintingPerfTest
306     : public LayerTreeHostPerfTestJsonReader {
307  public:
308   PageScaleImplSidePaintingPerfTest()
309       : max_scale_(16.f), min_scale_(1.f / max_scale_) {}
310
311   virtual void SetupTree() OVERRIDE {
312     layer_tree_host()->SetPageScaleFactorAndLimits(1.f, min_scale_, max_scale_);
313   }
314
315   virtual void ApplyScrollAndScale(gfx::Vector2d scroll_delta,
316                                    float scale_delta) OVERRIDE {
317     float page_scale_factor = layer_tree_host()->page_scale_factor();
318     page_scale_factor *= scale_delta;
319     layer_tree_host()->SetPageScaleFactorAndLimits(
320         page_scale_factor, min_scale_, max_scale_);
321   }
322
323   virtual void AnimateLayers(LayerTreeHostImpl* host_impl,
324                              base::TimeTicks monotonic_time) OVERRIDE {
325     if (!host_impl->pinch_gesture_active()) {
326       host_impl->PinchGestureBegin();
327       start_time_ = monotonic_time;
328     }
329     gfx::Point anchor(200, 200);
330
331     float seconds = (monotonic_time - start_time_).InSecondsF();
332
333     // Every half second, zoom from min scale to max scale.
334     float interval = 0.5f;
335
336     // Start time in the middle of the interval when zoom = 1.
337     seconds += interval / 2.f;
338
339     // Stack two ranges together to go up from min to max and down from
340     // max to min in the next so as not to have a zoom discrepancy.
341     float time_in_two_intervals = fmod(seconds, 2.f * interval) / interval;
342
343     // Map everything to go from min to max between 0 and 1.
344     float time_in_one_interval =
345         time_in_two_intervals > 1.f ? 2.f - time_in_two_intervals
346                                     : time_in_two_intervals;
347     // Normalize time to -1..1.
348     float normalized = 2.f * time_in_one_interval - 1.f;
349     float scale_factor = std::abs(normalized) * (max_scale_ - 1.f) + 1.f;
350     float total_scale = normalized < 0.f ? 1.f / scale_factor : scale_factor;
351
352     float desired_delta =
353         total_scale / host_impl->active_tree()->total_page_scale_factor();
354     host_impl->PinchGestureUpdate(desired_delta, anchor);
355   }
356
357  private:
358   float max_scale_;
359   float min_scale_;
360   base::TimeTicks start_time_;
361 };
362
363 TEST_F(PageScaleImplSidePaintingPerfTest, HeavyPage) {
364   measure_commit_cost_ = true;
365   SetTestName("heavy_page_page_scale");
366   ReadTestFile("heavy_layer_tree");
367   RunTestWithImplSidePainting();
368 }
369
370 }  // namespace
371 }  // namespace cc