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