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: 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 layer_tree_host()->SetNextCommitForcesRedraw(); 60 } 61 } 62 63 virtual void BeginCommitOnThread(LayerTreeHostImpl* host_impl) OVERRIDE { 64 if (measure_commit_cost_) 65 commit_timer_.Start(); 66 } 67 68 virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE { 69 if (measure_commit_cost_ && draw_timer_.IsWarmedUp()) { 70 commit_timer_.NextLap(); 71 } 72 } 73 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 88 virtual void CleanUpAndEndTest(LayerTreeHostImpl* host_impl) { EndTest(); } 89 90 virtual bool CleanUpStarted() { return false; } 91 92 virtual void BuildTree() {} 93 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: 119 LayerTreeHostPerfTestJsonReader() 120 : LayerTreeHostPerfTest() { 121 } 122 123 void SetTestName(const std::string& name) { 124 test_name_ = name; 125 } 126 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 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. 148 TEST_F(LayerTreeHostPerfTestJsonReader, TenTenSingleThread) { 149 SetTestName("10_10_single_thread"); 150 ReadTestFile("10_10_layer_tree"); 151 RunTest(false, false, false); 152 } 153 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. 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 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: 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 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. 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 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: 220 ScrollingLayerTreePerfTest() 221 : LayerTreeHostPerfTestJsonReader() { 222 } 223 224 virtual void BuildTree() OVERRIDE { 225 LayerTreeHostPerfTestJsonReader::BuildTree(); 226 scrollable_ = layer_tree_host()->root_layer()->children()[1]; 227 ASSERT_TRUE(scrollable_.get()); 228 } 229 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 239 TEST_F(ScrollingLayerTreePerfTest, LongScrollablePageSingleThread) { 240 SetTestName("long_scrollable_page"); 241 ReadTestFile("long_scrollable_page"); 242 RunTest(false, false, false); 243 } 244 245 TEST_F(ScrollingLayerTreePerfTest, LongScrollablePageThreadedImplSide) { 246 SetTestName("long_scrollable_page_threaded_impl_side"); 247 ReadTestFile("long_scrollable_page"); 248 RunTestWithImplSidePainting(); 249 } 250 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: 257 BrowserCompositorInvalidateLayerTreePerfTest() 258 : LayerTreeHostPerfTestJsonReader(), 259 next_sync_point_(1), 260 clean_up_started_(false) {} 261 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 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 289 virtual void DidCommit() OVERRIDE { 290 if (CleanUpStarted()) 291 return; 292 layer_tree_host()->SetNeedsCommit(); 293 } 294 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 304 void CleanUpAndEndTestOnMainThread() { 305 tab_contents_->SetTextureMailbox(TextureMailbox(), 306 scoped_ptr<SingleReleaseCallback>()); 307 EndTest(); 308 } 309 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 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. 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