Home | History | Annotate | Download | only in trees
      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