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/files/file_path.h" 10 #include "base/files/file_util.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/single_release_callback.h" 20 #include "cc/resources/texture_mailbox.h" 21 #include "cc/test/fake_content_layer_client.h" 22 #include "cc/test/layer_tree_json_parser.h" 23 #include "cc/test/layer_tree_test.h" 24 #include "cc/test/paths.h" 25 #include "cc/trees/layer_tree_impl.h" 26 #include "testing/perf/perf_test.h" 27 28 namespace cc { 29 namespace { 30 31 static const int kTimeLimitMillis = 2000; 32 static const int kWarmupRuns = 5; 33 static const int kTimeCheckInterval = 10; 34 35 class LayerTreeHostPerfTest : public LayerTreeTest { 36 public: 37 LayerTreeHostPerfTest() 38 : draw_timer_(kWarmupRuns, 39 base::TimeDelta::FromMilliseconds(kTimeLimitMillis), 40 kTimeCheckInterval), 41 commit_timer_(0, base::TimeDelta(), 1), 42 full_damage_each_frame_(false), 43 begin_frame_driven_drawing_(false), 44 measure_commit_cost_(false) { 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 BeginMainFrame(const BeginFrameArgs& args) OVERRIDE { 57 if (begin_frame_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 (!begin_frame_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 begin_frame_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].get()) { 188 } 189 } 190 191 virtual void DidCommitAndDrawFrame() OVERRIDE { 192 if (TestEnded()) 193 return; 194 195 layer_to_invalidate_->SetOpacity( 196 layer_to_invalidate_->opacity() != 1.f ? 1.f : 0.5f); 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 if (TestEnded()) 232 return; 233 static const gfx::Vector2d delta = gfx::Vector2d(0, 10); 234 scrollable_->SetScrollOffset(scrollable_->scroll_offset() + delta); 235 } 236 237 private: 238 scoped_refptr<Layer> scrollable_; 239 }; 240 241 TEST_F(ScrollingLayerTreePerfTest, LongScrollablePageSingleThread) { 242 SetTestName("long_scrollable_page"); 243 ReadTestFile("long_scrollable_page"); 244 RunTest(false, false, false); 245 } 246 247 TEST_F(ScrollingLayerTreePerfTest, LongScrollablePageThreadedImplSide) { 248 SetTestName("long_scrollable_page_threaded_impl_side"); 249 ReadTestFile("long_scrollable_page"); 250 RunTestWithImplSidePainting(); 251 } 252 253 static void EmptyReleaseCallback(uint32 sync_point, bool lost_resource) {} 254 255 // Simulates main-thread scrolling on each frame. 256 class BrowserCompositorInvalidateLayerTreePerfTest 257 : public LayerTreeHostPerfTestJsonReader { 258 public: 259 BrowserCompositorInvalidateLayerTreePerfTest() 260 : LayerTreeHostPerfTestJsonReader(), 261 next_sync_point_(1), 262 clean_up_started_(false) {} 263 264 virtual void BuildTree() OVERRIDE { 265 LayerTreeHostPerfTestJsonReader::BuildTree(); 266 tab_contents_ = 267 static_cast<TextureLayer*>( 268 layer_tree_host()->root_layer()->children()[0]-> 269 children()[0]-> 270 children()[0]-> 271 children()[0].get()); 272 ASSERT_TRUE(tab_contents_.get()); 273 } 274 275 virtual void WillCommit() OVERRIDE { 276 if (CleanUpStarted()) 277 return; 278 gpu::Mailbox gpu_mailbox; 279 std::ostringstream name_stream; 280 name_stream << "name" << next_sync_point_; 281 gpu_mailbox.SetName( 282 reinterpret_cast<const int8*>(name_stream.str().c_str())); 283 scoped_ptr<SingleReleaseCallback> callback = SingleReleaseCallback::Create( 284 base::Bind(&EmptyReleaseCallback)); 285 TextureMailbox mailbox(gpu_mailbox, GL_TEXTURE_2D, next_sync_point_); 286 next_sync_point_++; 287 288 tab_contents_->SetTextureMailbox(mailbox, callback.Pass()); 289 } 290 291 virtual void DidCommit() OVERRIDE { 292 if (CleanUpStarted()) 293 return; 294 layer_tree_host()->SetNeedsCommit(); 295 } 296 297 virtual void CleanUpAndEndTest(LayerTreeHostImpl* host_impl) OVERRIDE { 298 clean_up_started_ = true; 299 MainThreadTaskRunner()->PostTask( 300 FROM_HERE, 301 base::Bind(&BrowserCompositorInvalidateLayerTreePerfTest:: 302 CleanUpAndEndTestOnMainThread, 303 base::Unretained(this))); 304 } 305 306 void CleanUpAndEndTestOnMainThread() { 307 tab_contents_->SetTextureMailbox(TextureMailbox(), 308 scoped_ptr<SingleReleaseCallback>()); 309 EndTest(); 310 } 311 312 virtual bool CleanUpStarted() OVERRIDE { return clean_up_started_; } 313 314 private: 315 scoped_refptr<TextureLayer> tab_contents_; 316 unsigned next_sync_point_; 317 bool clean_up_started_; 318 }; 319 320 TEST_F(BrowserCompositorInvalidateLayerTreePerfTest, DenseBrowserUI) { 321 measure_commit_cost_ = true; 322 SetTestName("dense_layer_tree"); 323 ReadTestFile("dense_layer_tree"); 324 RunTestWithImplSidePainting(); 325 } 326 327 // Simulates a page with several large, transformed and animated layers. 328 TEST_F(LayerTreeHostPerfTestJsonReader, HeavyPageThreadedImplSide) { 329 begin_frame_driven_drawing_ = true; 330 measure_commit_cost_ = true; 331 SetTestName("heavy_page"); 332 ReadTestFile("heavy_layer_tree"); 333 RunTestWithImplSidePainting(); 334 } 335 336 } // namespace 337 } // namespace cc 338