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.
5 #include "cc/trees/layer_tree_host.h"
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"
30 static const int kTimeLimitMillis = 2000;
31 static const int kWarmupRuns = 5;
32 static const int kTimeCheckInterval = 10;
34 class LayerTreeHostPerfTest : public LayerTreeTest {
36 LayerTreeHostPerfTest()
37 : draw_timer_(kWarmupRuns,
38 base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
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);
47 virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
48 settings->throttle_frame_production = false;
51 virtual void BeginTest() OVERRIDE {
53 PostSetNeedsCommitToMainThread();
56 virtual void Animate(base::TimeTicks monotonic_time) OVERRIDE {
57 if (animation_driven_drawing_ && !TestEnded())
58 layer_tree_host()->SetNeedsAnimate();
61 virtual void BeginCommitOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
62 if (measure_commit_cost_)
63 commit_timer_.Start();
66 virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
67 if (measure_commit_cost_ && draw_timer_.IsWarmedUp()) {
68 commit_timer_.NextLap();
72 virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE {
76 draw_timer_.NextLap();
77 if (draw_timer_.HasTimeLimitExpired()) {
81 if (!animation_driven_drawing_)
82 impl->SetNeedsRedraw();
83 if (full_damage_each_frame_)
84 impl->SetFullRootLayerDamage();
87 virtual void BuildTree() {}
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);
104 LapTimer draw_timer_;
105 LapTimer commit_timer_;
107 std::string test_name_;
108 FakeContentLayerClient fake_content_layer_client_;
109 bool full_damage_each_frame_;
110 bool animation_driven_drawing_;
112 bool measure_commit_cost_;
116 class LayerTreeHostPerfTestJsonReader : public LayerTreeHostPerfTest {
118 LayerTreeHostPerfTestJsonReader()
119 : LayerTreeHostPerfTest() {
122 void SetTestName(const std::string& name) {
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_));
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);
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);
153 TEST_F(LayerTreeHostPerfTestJsonReader, TenTenThreadedImplSide) {
154 SetTestName("10_10_threaded_impl_side");
155 ReadTestFile("10_10_layer_tree");
156 RunTestWithImplSidePainting();
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);
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();
176 // Invalidates a leaf layer in the tree on the main thread after every commit.
177 class LayerTreeHostPerfTestLeafInvalidates
178 : public LayerTreeHostPerfTestJsonReader {
180 virtual void BuildTree() OVERRIDE {
181 LayerTreeHostPerfTestJsonReader::BuildTree();
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]) {}
189 virtual void DidCommitAndDrawFrame() OVERRIDE {
193 static bool flip = true;
194 layer_to_invalidate_->SetOpacity(flip ? 1.f : 0.5f);
199 Layer* layer_to_invalidate_;
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);
210 TEST_F(LayerTreeHostPerfTestLeafInvalidates, TenTenThreadedImplSide) {
211 SetTestName("10_10_threaded_impl_side_leaf_invalidates");
212 ReadTestFile("10_10_layer_tree");
213 RunTestWithImplSidePainting();
216 // Simulates main-thread scrolling on each frame.
217 class ScrollingLayerTreePerfTest : public LayerTreeHostPerfTestJsonReader {
219 ScrollingLayerTreePerfTest()
220 : LayerTreeHostPerfTestJsonReader() {
223 virtual void BuildTree() OVERRIDE {
224 LayerTreeHostPerfTestJsonReader::BuildTree();
225 scrollable_ = layer_tree_host()->root_layer()->children()[1];
226 ASSERT_TRUE(scrollable_.get());
229 virtual void Layout() OVERRIDE {
230 static const gfx::Vector2d delta = gfx::Vector2d(0, 10);
231 scrollable_->SetScrollOffset(scrollable_->scroll_offset() + delta);
235 scoped_refptr<Layer> scrollable_;
238 TEST_F(ScrollingLayerTreePerfTest, LongScrollablePageSingleThread) {
239 SetTestName("long_scrollable_page");
240 ReadTestFile("long_scrollable_page");
241 RunTest(false, false, false);
244 TEST_F(ScrollingLayerTreePerfTest, LongScrollablePageThreadedImplSide) {
245 SetTestName("long_scrollable_page_threaded_impl_side");
246 ReadTestFile("long_scrollable_page");
247 RunTestWithImplSidePainting();
250 static void EmptyReleaseCallback(unsigned sync_point, bool lost_resource) {}
252 // Simulates main-thread scrolling on each frame.
253 class BrowserCompositorInvalidateLayerTreePerfTest
254 : public LayerTreeHostPerfTestJsonReader {
256 BrowserCompositorInvalidateLayerTreePerfTest()
257 : next_sync_point_(1) {
260 virtual void BuildTree() OVERRIDE {
261 LayerTreeHostPerfTestJsonReader::BuildTree();
263 static_cast<TextureLayer*>(
264 layer_tree_host()->root_layer()->children()[0]->
267 children()[0].get());
268 ASSERT_TRUE(tab_contents_.get());
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_);
282 tab_contents_->SetTextureMailbox(mailbox, callback.Pass());
286 scoped_refptr<TextureLayer> tab_contents_;
287 unsigned next_sync_point_;
290 TEST_F(BrowserCompositorInvalidateLayerTreePerfTest, DenseBrowserUI) {
291 SetTestName("dense_layer_tree");
292 ReadTestFile("dense_layer_tree");
293 RunTestWithImplSidePainting();
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();
305 class PageScaleImplSidePaintingPerfTest
306 : public LayerTreeHostPerfTestJsonReader {
308 PageScaleImplSidePaintingPerfTest()
309 : max_scale_(16.f), min_scale_(1.f / max_scale_) {}
311 virtual void SetupTree() OVERRIDE {
312 layer_tree_host()->SetPageScaleFactorAndLimits(1.f, min_scale_, max_scale_);
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_);
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;
329 gfx::Point anchor(200, 200);
331 float seconds = (monotonic_time - start_time_).InSecondsF();
333 // Every half second, zoom from min scale to max scale.
334 float interval = 0.5f;
336 // Start time in the middle of the interval when zoom = 1.
337 seconds += interval / 2.f;
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;
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;
352 float desired_delta =
353 total_scale / host_impl->active_tree()->total_page_scale_factor();
354 host_impl->PinchGestureUpdate(desired_delta, anchor);
360 base::TimeTicks start_time_;
363 TEST_F(PageScaleImplSidePaintingPerfTest, HeavyPage) {
364 measure_commit_cost_ = true;
365 SetTestName("heavy_page_page_scale");
366 ReadTestFile("heavy_layer_tree");
367 RunTestWithImplSidePainting();