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/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