Home | History | Annotate | Download | only in debug
      1 // Copyright 2014 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/debug/invalidation_benchmark.h"
      6 
      7 #include <algorithm>
      8 #include <limits>
      9 
     10 #include "base/basictypes.h"
     11 #include "base/rand_util.h"
     12 #include "base/values.h"
     13 #include "cc/layers/layer.h"
     14 #include "cc/layers/picture_layer.h"
     15 #include "cc/trees/layer_tree_host.h"
     16 #include "cc/trees/layer_tree_host_common.h"
     17 #include "ui/gfx/rect.h"
     18 
     19 namespace cc {
     20 
     21 namespace {
     22 
     23 const char* kDefaultInvalidationMode = "viewport";
     24 
     25 }  // namespace
     26 
     27 InvalidationBenchmark::InvalidationBenchmark(
     28     scoped_ptr<base::Value> value,
     29     const MicroBenchmark::DoneCallback& callback)
     30     : MicroBenchmark(callback), seed_(0) {
     31   base::DictionaryValue* settings = NULL;
     32   value->GetAsDictionary(&settings);
     33   if (!settings)
     34     return;
     35 
     36   std::string mode_string = kDefaultInvalidationMode;
     37 
     38   if (settings->HasKey("mode"))
     39     settings->GetString("mode", &mode_string);
     40 
     41   if (mode_string == "fixed_size") {
     42     mode_ = FIXED_SIZE;
     43     CHECK(settings->HasKey("width"))
     44         << "Must provide a width for fixed_size mode.";
     45     CHECK(settings->HasKey("height"))
     46         << "Must provide a height for fixed_size mode.";
     47     settings->GetInteger("width", &width_);
     48     settings->GetInteger("height", &height_);
     49   } else if (mode_string == "layer") {
     50     mode_ = LAYER;
     51   } else if (mode_string == "random") {
     52     mode_ = RANDOM;
     53   } else if (mode_string == "viewport") {
     54     mode_ = VIEWPORT;
     55   } else {
     56     CHECK(false) << "Invalid mode: " << mode_string
     57                  << ". One of {fixed_size, layer, viewport, random} expected.";
     58   }
     59 }
     60 
     61 InvalidationBenchmark::~InvalidationBenchmark() {
     62 }
     63 
     64 void InvalidationBenchmark::DidUpdateLayers(LayerTreeHost* host) {
     65   LayerTreeHostCommon::CallFunctionForSubtree(
     66       host->root_layer(),
     67       base::Bind(&InvalidationBenchmark::Run, base::Unretained(this)));
     68 }
     69 
     70 void InvalidationBenchmark::Run(Layer* layer) {
     71   layer->RunMicroBenchmark(this);
     72 }
     73 
     74 void InvalidationBenchmark::RunOnLayer(PictureLayer* layer) {
     75   switch (mode_) {
     76     case FIXED_SIZE: {
     77       // Invalidation with a random position and fixed size.
     78       gfx::Rect visible_content_rect = layer->visible_content_rect();
     79       int x = LCGRandom() * (visible_content_rect.width() - width_);
     80       int y = LCGRandom() * (visible_content_rect.height() - height_);
     81       gfx::Rect invalidation_rect(x, y, width_, height_);
     82       layer->SetNeedsDisplayRect(invalidation_rect);
     83       break;
     84     }
     85     case LAYER: {
     86       // Invalidate entire layer.
     87       layer->SetNeedsDisplay();
     88       break;
     89     }
     90     case RANDOM: {
     91       // Random invalidation inside the viewport.
     92       gfx::Rect visible_content_rect = layer->visible_content_rect();
     93       int x_min = LCGRandom() * visible_content_rect.width();
     94       int x_max = LCGRandom() * visible_content_rect.width();
     95       int y_min = LCGRandom() * visible_content_rect.height();
     96       int y_max = LCGRandom() * visible_content_rect.height();
     97       if (x_min > x_max)
     98         std::swap(x_min, x_max);
     99       if (y_min > y_max)
    100         std::swap(y_min, y_max);
    101       gfx::Rect invalidation_rect(x_min, y_min, x_max - x_min, y_max - y_min);
    102       layer->SetNeedsDisplayRect(invalidation_rect);
    103       break;
    104     }
    105     case VIEWPORT: {
    106       // Invalidate entire viewport.
    107       layer->SetNeedsDisplayRect(layer->visible_content_rect());
    108       break;
    109     }
    110   }
    111 }
    112 
    113 bool InvalidationBenchmark::ProcessMessage(scoped_ptr<base::Value> value) {
    114   base::DictionaryValue* message = NULL;
    115   value->GetAsDictionary(&message);
    116   if (!message)
    117     return false;
    118 
    119   bool notify_done;
    120   if (message->HasKey("notify_done")) {
    121     message->GetBoolean("notify_done", &notify_done);
    122     if (notify_done)
    123       NotifyDone(scoped_ptr<base::Value>(base::Value::CreateNullValue()));
    124     return true;
    125   }
    126   return false;
    127 }
    128 
    129 // A simple linear congruential generator. The random numbers don't need to be
    130 // high quality, but they need to be identical in each run. Therefore, we use a
    131 // LCG and keep the state locally in the benchmark.
    132 float InvalidationBenchmark::LCGRandom() {
    133   const uint32 a = 1664525;
    134   const uint32 c = 1013904223;
    135   seed_ = a * seed_ + c;
    136   return static_cast<float>(seed_) / std::numeric_limits<uint32>::max();
    137 }
    138 
    139 }  // namespace cc
    140