Home | History | Annotate | Download | only in bench
      1 // Copyright (c) 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 "base/at_exit.h"
      6 #include "base/bind.h"
      7 #include "base/command_line.h"
      8 #include "base/i18n/icu_util.h"
      9 #include "base/memory/scoped_ptr.h"
     10 #include "base/message_loop/message_loop.h"
     11 #include "base/strings/string_split.h"
     12 #include "base/time/time.h"
     13 #include "third_party/khronos/GLES2/gl2.h"
     14 #include "third_party/skia/include/core/SkXfermode.h"
     15 #include "ui/aura/client/default_capture_client.h"
     16 #include "ui/aura/env.h"
     17 #include "ui/aura/focus_manager.h"
     18 #include "ui/aura/root_window.h"
     19 #include "ui/aura/test/test_screen.h"
     20 #include "ui/aura/window.h"
     21 #include "ui/base/hit_test.h"
     22 #include "ui/base/resource/resource_bundle.h"
     23 #include "ui/base/ui_base_paths.h"
     24 #include "ui/compositor/compositor.h"
     25 #include "ui/compositor/compositor_observer.h"
     26 #include "ui/compositor/debug_utils.h"
     27 #include "ui/compositor/layer.h"
     28 #include "ui/gfx/canvas.h"
     29 #include "ui/gfx/rect.h"
     30 #include "ui/gfx/skia_util.h"
     31 #ifndef GL_GLEXT_PROTOTYPES
     32 #define GL_GLEXT_PROTOTYPES 1
     33 #endif
     34 #include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
     35 #include "third_party/khronos/GLES2/gl2ext.h"
     36 
     37 #if defined(USE_X11)
     38 #include "base/message_loop/message_pump_aurax11.h"
     39 #endif
     40 
     41 using base::TimeTicks;
     42 using ui::Compositor;
     43 using ui::Layer;
     44 using ui::LayerDelegate;
     45 using WebKit::WebGraphicsContext3D;
     46 
     47 namespace {
     48 
     49 class ColoredLayer : public Layer, public LayerDelegate {
     50  public:
     51   explicit ColoredLayer(SkColor color)
     52       : Layer(ui::LAYER_TEXTURED),
     53         color_(color),
     54         draw_(true) {
     55     set_delegate(this);
     56   }
     57 
     58   virtual ~ColoredLayer() {}
     59 
     60   // Overridden from LayerDelegate:
     61   virtual void OnPaintLayer(gfx::Canvas* canvas) OVERRIDE {
     62     if (draw_) {
     63       canvas->DrawColor(color_);
     64     }
     65   }
     66 
     67   virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE {
     68   }
     69 
     70   virtual base::Closure PrepareForLayerBoundsChange() OVERRIDE {
     71     return base::Closure();
     72   }
     73 
     74   void set_color(SkColor color) { color_ = color; }
     75   void set_draw(bool draw) { draw_ = draw; }
     76 
     77  private:
     78   SkColor color_;
     79   bool draw_;
     80 
     81   DISALLOW_COPY_AND_ASSIGN(ColoredLayer);
     82 };
     83 
     84 const int kFrames = 100;
     85 
     86 // Benchmark base class, hooks up drawing callback and displaying FPS.
     87 class BenchCompositorObserver : public ui::CompositorObserver {
     88  public:
     89   explicit BenchCompositorObserver(int max_frames)
     90       : start_time_(),
     91         frames_(0),
     92         max_frames_(max_frames) {
     93   }
     94 
     95   virtual void OnCompositingDidCommit(ui::Compositor* compositor) OVERRIDE {}
     96 
     97   virtual void OnCompositingStarted(Compositor* compositor,
     98                                     base::TimeTicks start_time) OVERRIDE {}
     99 
    100   virtual void OnCompositingEnded(Compositor* compositor) OVERRIDE {
    101     if (start_time_.is_null()) {
    102       start_time_ = TimeTicks::Now();
    103     } else {
    104       ++frames_;
    105       if (frames_ % kFrames == 0) {
    106         TimeTicks now = TimeTicks::Now();
    107         double ms = (now - start_time_).InMillisecondsF() / kFrames;
    108         LOG(INFO) << "FPS: " << 1000.f / ms << " (" << ms << " ms)";
    109         start_time_ = now;
    110       }
    111     }
    112     if (max_frames_ && frames_ == max_frames_) {
    113       base::MessageLoop::current()->Quit();
    114     } else {
    115       Draw();
    116     }
    117   }
    118 
    119   virtual void OnCompositingAborted(Compositor* compositor) OVERRIDE {}
    120 
    121   virtual void OnCompositingLockStateChanged(
    122       Compositor* compositor) OVERRIDE {}
    123 
    124   virtual void OnUpdateVSyncParameters(ui::Compositor* compositor,
    125                                        base::TimeTicks timebase,
    126                                        base::TimeDelta interval) OVERRIDE {
    127   }
    128 
    129   virtual void Draw() {}
    130 
    131   int frames() const { return frames_; }
    132 
    133  private:
    134   TimeTicks start_time_;
    135   int frames_;
    136   int max_frames_;
    137 
    138   DISALLOW_COPY_AND_ASSIGN(BenchCompositorObserver);
    139 };
    140 
    141 class WebGLTexture : public ui::Texture {
    142  public:
    143   WebGLTexture(WebGraphicsContext3D* context, const gfx::Size& size)
    144       : ui::Texture(false, size, 1.0f),
    145         context_(context),
    146         texture_id_(context_->createTexture()) {
    147     context_->bindTexture(GL_TEXTURE_2D, texture_id_);
    148     context_->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    149     context_->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    150     context_->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    151     context_->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    152     context_->texImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
    153                          size.width(), size.height(), 0,
    154                          GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    155   }
    156 
    157   virtual unsigned int PrepareTexture() OVERRIDE {
    158     return texture_id_;
    159   }
    160 
    161   virtual WebGraphicsContext3D* HostContext3D() OVERRIDE {
    162     return context_;
    163   }
    164 
    165  private:
    166   virtual ~WebGLTexture() {
    167     context_->deleteTexture(texture_id_);
    168   }
    169 
    170   WebGraphicsContext3D* context_;
    171   unsigned texture_id_;
    172 
    173   DISALLOW_COPY_AND_ASSIGN(WebGLTexture);
    174 };
    175 
    176 // A benchmark that adds a texture layer that is updated every frame.
    177 class WebGLBench : public BenchCompositorObserver {
    178  public:
    179   WebGLBench(Layer* parent, Compositor* compositor, int max_frames)
    180       : BenchCompositorObserver(max_frames),
    181         parent_(parent),
    182         webgl_(ui::LAYER_TEXTURED),
    183         compositor_(compositor),
    184         context_(),
    185         texture_(),
    186         fbo_(0),
    187         do_draw_(true) {
    188     CommandLine* command_line = CommandLine::ForCurrentProcess();
    189     do_draw_ = !command_line->HasSwitch("disable-draw");
    190 
    191     std::string webgl_size = command_line->GetSwitchValueASCII("webgl-size");
    192     int width = 0;
    193     int height = 0;
    194     if (!webgl_size.empty()) {
    195       std::vector<std::string> split_size;
    196       base::SplitString(webgl_size, 'x', &split_size);
    197       if (split_size.size() == 2) {
    198         width = atoi(split_size[0].c_str());
    199         height = atoi(split_size[1].c_str());
    200       }
    201     }
    202     if (!width || !height) {
    203       width = 800;
    204       height = 600;
    205     }
    206     gfx::Rect bounds(width, height);
    207     webgl_.SetBounds(bounds);
    208     parent_->Add(&webgl_);
    209 
    210     context_ = ui::ContextFactory::GetInstance()->CreateOffscreenContext();
    211     context_->makeContextCurrent();
    212     texture_ = new WebGLTexture(context_.get(), bounds.size());
    213     fbo_ = context_->createFramebuffer();
    214     compositor->AddObserver(this);
    215     webgl_.SetExternalTexture(texture_.get());
    216     context_->bindFramebuffer(GL_FRAMEBUFFER, fbo_);
    217     context_->framebufferTexture2D(
    218         GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
    219         GL_TEXTURE_2D, texture_->PrepareTexture(), 0);
    220     context_->clearColor(0.f, 1.f, 0.f, 1.f);
    221     context_->clear(GL_COLOR_BUFFER_BIT);
    222     context_->flush();
    223   }
    224 
    225   virtual ~WebGLBench() {
    226     context_->makeContextCurrent();
    227     context_->deleteFramebuffer(fbo_);
    228     webgl_.SetExternalTexture(NULL);
    229     texture_ = NULL;
    230     compositor_->RemoveObserver(this);
    231   }
    232 
    233   virtual void Draw() OVERRIDE {
    234     if (do_draw_) {
    235       context_->makeContextCurrent();
    236       context_->clearColor((frames() % kFrames)*1.0/kFrames, 1.f, 0.f, 1.f);
    237       context_->clear(GL_COLOR_BUFFER_BIT);
    238       context_->flush();
    239     }
    240     webgl_.SetExternalTexture(texture_.get());
    241     webgl_.SchedulePaint(gfx::Rect(webgl_.bounds().size()));
    242     compositor_->ScheduleDraw();
    243   }
    244 
    245  private:
    246   Layer* parent_;
    247   Layer webgl_;
    248   Compositor* compositor_;
    249   scoped_ptr<WebGraphicsContext3D> context_;
    250   scoped_refptr<WebGLTexture> texture_;
    251 
    252   // The FBO that is used to render to the texture.
    253   unsigned int fbo_;
    254 
    255   // Whether or not to draw to the texture every frame.
    256   bool do_draw_;
    257 
    258   DISALLOW_COPY_AND_ASSIGN(WebGLBench);
    259 };
    260 
    261 // A benchmark that paints (in software) all tiles every frame.
    262 class SoftwareScrollBench : public BenchCompositorObserver {
    263  public:
    264   SoftwareScrollBench(ColoredLayer* layer,
    265                       Compositor* compositor,
    266                       int max_frames)
    267       : BenchCompositorObserver(max_frames),
    268         layer_(layer),
    269         compositor_(compositor) {
    270     compositor->AddObserver(this);
    271     layer_->set_draw(
    272         !CommandLine::ForCurrentProcess()->HasSwitch("disable-draw"));
    273   }
    274 
    275   virtual ~SoftwareScrollBench() {
    276     compositor_->RemoveObserver(this);
    277   }
    278 
    279   virtual void Draw() OVERRIDE {
    280     layer_->set_color(
    281         SkColorSetARGBInline(255*(frames() % kFrames)/kFrames, 255, 0, 255));
    282     layer_->SchedulePaint(gfx::Rect(layer_->bounds().size()));
    283   }
    284 
    285  private:
    286   ColoredLayer* layer_;
    287   Compositor* compositor_;
    288 
    289   DISALLOW_COPY_AND_ASSIGN(SoftwareScrollBench);
    290 };
    291 
    292 }  // namespace
    293 
    294 int main(int argc, char** argv) {
    295   CommandLine::Init(argc, argv);
    296 
    297   base::AtExitManager exit_manager;
    298 
    299   ui::RegisterPathProvider();
    300   icu_util::Initialize();
    301   ResourceBundle::InitSharedInstanceWithLocale("en-US", NULL);
    302 
    303   base::MessageLoop message_loop(base::MessageLoop::TYPE_UI);
    304   aura::Env::GetInstance();
    305   scoped_ptr<aura::TestScreen> test_screen(
    306       aura::TestScreen::CreateFullscreen());
    307   gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, test_screen.get());
    308   scoped_ptr<aura::RootWindow> root_window(
    309       test_screen->CreateRootWindowForPrimaryDisplay());
    310   aura::client::SetCaptureClient(
    311       root_window.get(),
    312       new aura::client::DefaultCaptureClient(root_window.get()));
    313 
    314   scoped_ptr<aura::client::FocusClient> focus_client(new aura::FocusManager);
    315   aura::client::SetFocusClient(root_window.get(), focus_client.get());
    316 
    317   // add layers
    318   ColoredLayer background(SK_ColorRED);
    319   background.SetBounds(root_window->bounds());
    320   root_window->layer()->Add(&background);
    321 
    322   ColoredLayer window(SK_ColorBLUE);
    323   window.SetBounds(gfx::Rect(background.bounds().size()));
    324   background.Add(&window);
    325 
    326   Layer content_layer(ui::LAYER_NOT_DRAWN);
    327 
    328   CommandLine* command_line = CommandLine::ForCurrentProcess();
    329   bool force = command_line->HasSwitch("force-render-surface");
    330   content_layer.SetForceRenderSurface(force);
    331   gfx::Rect bounds(window.bounds().size());
    332   bounds.Inset(0, 30, 0, 0);
    333   content_layer.SetBounds(bounds);
    334   window.Add(&content_layer);
    335 
    336   ColoredLayer page_background(SK_ColorWHITE);
    337   page_background.SetBounds(gfx::Rect(content_layer.bounds().size()));
    338   content_layer.Add(&page_background);
    339 
    340   int frames = atoi(command_line->GetSwitchValueASCII("frames").c_str());
    341   scoped_ptr<BenchCompositorObserver> bench;
    342 
    343   if (command_line->HasSwitch("bench-software-scroll")) {
    344     bench.reset(new SoftwareScrollBench(&page_background,
    345                                         root_window->compositor(),
    346                                         frames));
    347   } else {
    348     bench.reset(new WebGLBench(&page_background,
    349                                root_window->compositor(),
    350                                frames));
    351   }
    352 
    353 #ifndef NDEBUG
    354   ui::PrintLayerHierarchy(root_window->layer(), gfx::Point(100, 100));
    355 #endif
    356 
    357   root_window->ShowRootWindow();
    358   base::MessageLoopForUI::current()->Run();
    359   focus_client.reset();
    360   root_window.reset();
    361 
    362   return 0;
    363 }
    364