| OLD | NEW |
| (Empty) |
| 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 void InitializeSettings(LayerTreeSettings* settings) override { | |
| 48 settings->throttle_frame_production = false; | |
| 49 } | |
| 50 | |
| 51 void BeginTest() override { | |
| 52 BuildTree(); | |
| 53 PostSetNeedsCommitToMainThread(); | |
| 54 } | |
| 55 | |
| 56 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 void BeginCommitOnThread(LayerTreeHostImpl* host_impl) override { | |
| 64 if (measure_commit_cost_) | |
| 65 commit_timer_.Start(); | |
| 66 } | |
| 67 | |
| 68 void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { | |
| 69 if (measure_commit_cost_ && draw_timer_.IsWarmedUp()) { | |
| 70 commit_timer_.NextLap(); | |
| 71 } | |
| 72 } | |
| 73 | |
| 74 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 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 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 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 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 void BuildTree() override { | |
| 225 LayerTreeHostPerfTestJsonReader::BuildTree(); | |
| 226 scrollable_ = layer_tree_host()->root_layer()->children()[1]; | |
| 227 ASSERT_TRUE(scrollable_.get()); | |
| 228 } | |
| 229 | |
| 230 void Layout() override { | |
| 231 if (TestEnded()) | |
| 232 return; | |
| 233 static const gfx::Vector2d delta = gfx::Vector2d(0, 10); | |
| 234 scrollable_->SetScrollOffset( | |
| 235 gfx::ScrollOffsetWithDelta(scrollable_->scroll_offset(), delta)); | |
| 236 } | |
| 237 | |
| 238 private: | |
| 239 scoped_refptr<Layer> scrollable_; | |
| 240 }; | |
| 241 | |
| 242 TEST_F(ScrollingLayerTreePerfTest, LongScrollablePageSingleThread) { | |
| 243 SetTestName("long_scrollable_page"); | |
| 244 ReadTestFile("long_scrollable_page"); | |
| 245 // TODO(vollick): Remove verify_property_trees setting after | |
| 246 // crbug.com/444219 is fixed. | |
| 247 bool old_verify_property_trees = verify_property_trees(); | |
| 248 set_verify_property_trees(false); | |
| 249 RunTest(false, false, false); | |
| 250 set_verify_property_trees(old_verify_property_trees); | |
| 251 } | |
| 252 | |
| 253 TEST_F(ScrollingLayerTreePerfTest, LongScrollablePageThreadedImplSide) { | |
| 254 SetTestName("long_scrollable_page_threaded_impl_side"); | |
| 255 ReadTestFile("long_scrollable_page"); | |
| 256 // TODO(vollick): Remove verify_property_trees setting after | |
| 257 // crbug.com/444219 is fixed. | |
| 258 bool old_verify_property_trees = verify_property_trees(); | |
| 259 set_verify_property_trees(false); | |
| 260 RunTestWithImplSidePainting(); | |
| 261 set_verify_property_trees(old_verify_property_trees); | |
| 262 } | |
| 263 | |
| 264 static void EmptyReleaseCallback(uint32 sync_point, bool lost_resource) {} | |
| 265 | |
| 266 // Simulates main-thread scrolling on each frame. | |
| 267 class BrowserCompositorInvalidateLayerTreePerfTest | |
| 268 : public LayerTreeHostPerfTestJsonReader { | |
| 269 public: | |
| 270 BrowserCompositorInvalidateLayerTreePerfTest() | |
| 271 : LayerTreeHostPerfTestJsonReader(), | |
| 272 next_sync_point_(1), | |
| 273 clean_up_started_(false) {} | |
| 274 | |
| 275 void BuildTree() override { | |
| 276 LayerTreeHostPerfTestJsonReader::BuildTree(); | |
| 277 tab_contents_ = | |
| 278 static_cast<TextureLayer*>( | |
| 279 layer_tree_host()->root_layer()->children()[0]-> | |
| 280 children()[0]-> | |
| 281 children()[0]-> | |
| 282 children()[0].get()); | |
| 283 ASSERT_TRUE(tab_contents_.get()); | |
| 284 } | |
| 285 | |
| 286 void WillCommit() override { | |
| 287 if (CleanUpStarted()) | |
| 288 return; | |
| 289 gpu::Mailbox gpu_mailbox; | |
| 290 std::ostringstream name_stream; | |
| 291 name_stream << "name" << next_sync_point_; | |
| 292 gpu_mailbox.SetName( | |
| 293 reinterpret_cast<const int8*>(name_stream.str().c_str())); | |
| 294 scoped_ptr<SingleReleaseCallback> callback = SingleReleaseCallback::Create( | |
| 295 base::Bind(&EmptyReleaseCallback)); | |
| 296 TextureMailbox mailbox(gpu_mailbox, GL_TEXTURE_2D, next_sync_point_); | |
| 297 next_sync_point_++; | |
| 298 | |
| 299 tab_contents_->SetTextureMailbox(mailbox, callback.Pass()); | |
| 300 } | |
| 301 | |
| 302 void DidCommit() override { | |
| 303 if (CleanUpStarted()) | |
| 304 return; | |
| 305 layer_tree_host()->SetNeedsCommit(); | |
| 306 } | |
| 307 | |
| 308 void CleanUpAndEndTest(LayerTreeHostImpl* host_impl) override { | |
| 309 clean_up_started_ = true; | |
| 310 MainThreadTaskRunner()->PostTask( | |
| 311 FROM_HERE, | |
| 312 base::Bind(&BrowserCompositorInvalidateLayerTreePerfTest:: | |
| 313 CleanUpAndEndTestOnMainThread, | |
| 314 base::Unretained(this))); | |
| 315 } | |
| 316 | |
| 317 void CleanUpAndEndTestOnMainThread() { | |
| 318 tab_contents_->SetTextureMailbox(TextureMailbox(), nullptr); | |
| 319 EndTest(); | |
| 320 } | |
| 321 | |
| 322 bool CleanUpStarted() override { return clean_up_started_; } | |
| 323 | |
| 324 private: | |
| 325 scoped_refptr<TextureLayer> tab_contents_; | |
| 326 unsigned next_sync_point_; | |
| 327 bool clean_up_started_; | |
| 328 }; | |
| 329 | |
| 330 TEST_F(BrowserCompositorInvalidateLayerTreePerfTest, DenseBrowserUI) { | |
| 331 measure_commit_cost_ = true; | |
| 332 SetTestName("dense_layer_tree"); | |
| 333 ReadTestFile("dense_layer_tree"); | |
| 334 RunTestWithImplSidePainting(); | |
| 335 } | |
| 336 | |
| 337 // Simulates a page with several large, transformed and animated layers. | |
| 338 TEST_F(LayerTreeHostPerfTestJsonReader, HeavyPageThreadedImplSide) { | |
| 339 begin_frame_driven_drawing_ = true; | |
| 340 measure_commit_cost_ = true; | |
| 341 SetTestName("heavy_page"); | |
| 342 ReadTestFile("heavy_layer_tree"); | |
| 343 RunTestWithImplSidePainting(); | |
| 344 } | |
| 345 | |
| 346 } // namespace | |
| 347 } // namespace cc | |
| OLD | NEW |