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 #if defined(USE_X11)
      6 #include <X11/Xlib.h>
      7 #endif
      8 
      9 #include "base/at_exit.h"
     10 #include "base/bind.h"
     11 #include "base/command_line.h"
     12 #include "base/i18n/icu_util.h"
     13 #include "base/memory/scoped_ptr.h"
     14 #include "base/message_loop/message_loop.h"
     15 #include "base/strings/string_split.h"
     16 #include "base/time/time.h"
     17 #include "cc/output/context_provider.h"
     18 #include "gpu/command_buffer/client/gles2_interface.h"
     19 #include "third_party/khronos/GLES2/gl2.h"
     20 #include "third_party/skia/include/core/SkXfermode.h"
     21 #include "ui/aura/client/default_capture_client.h"
     22 #include "ui/aura/env.h"
     23 #include "ui/aura/test/test_focus_client.h"
     24 #include "ui/aura/test/test_screen.h"
     25 #include "ui/aura/window.h"
     26 #include "ui/aura/window_tree_host.h"
     27 #include "ui/base/hit_test.h"
     28 #include "ui/compositor/compositor.h"
     29 #include "ui/compositor/compositor_observer.h"
     30 #include "ui/compositor/debug_utils.h"
     31 #include "ui/compositor/layer.h"
     32 #include "ui/compositor/test/in_process_context_factory.h"
     33 #include "ui/gfx/canvas.h"
     34 #include "ui/gfx/rect.h"
     35 #include "ui/gfx/skia_util.h"
     36 #include "ui/gfx/x/x11_connection.h"
     37 #include "ui/gl/gl_surface.h"
     38 
     39 #ifndef GL_GLEXT_PROTOTYPES
     40 #define GL_GLEXT_PROTOTYPES 1
     41 #endif
     42 #include "third_party/khronos/GLES2/gl2ext.h"
     43 
     44 using base::TimeTicks;
     45 using ui::Compositor;
     46 using ui::Layer;
     47 using ui::LayerDelegate;
     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 Draw() {}
    127 
    128   int frames() const { return frames_; }
    129 
    130  private:
    131   TimeTicks start_time_;
    132   int frames_;
    133   int max_frames_;
    134 
    135   DISALLOW_COPY_AND_ASSIGN(BenchCompositorObserver);
    136 };
    137 
    138 void ReturnMailbox(scoped_refptr<cc::ContextProvider> context_provider,
    139                    GLuint texture,
    140                    GLuint sync_point,
    141                    bool is_lost) {
    142   gpu::gles2::GLES2Interface* gl = context_provider->ContextGL();
    143   gl->WaitSyncPointCHROMIUM(sync_point);
    144   gl->DeleteTextures(1, &texture);
    145   gl->ShallowFlushCHROMIUM();
    146 }
    147 
    148 // A benchmark that adds a texture layer that is updated every frame.
    149 class WebGLBench : public BenchCompositorObserver {
    150  public:
    151   WebGLBench(ui::ContextFactory* context_factory,
    152              Layer* parent,
    153              Compositor* compositor,
    154              int max_frames)
    155       : BenchCompositorObserver(max_frames),
    156         parent_(parent),
    157         webgl_(ui::LAYER_TEXTURED),
    158         compositor_(compositor),
    159         fbo_(0),
    160         do_draw_(true) {
    161     CommandLine* command_line = CommandLine::ForCurrentProcess();
    162     do_draw_ = !command_line->HasSwitch("disable-draw");
    163 
    164     std::string webgl_size = command_line->GetSwitchValueASCII("webgl-size");
    165     int width = 0;
    166     int height = 0;
    167     if (!webgl_size.empty()) {
    168       std::vector<std::string> split_size;
    169       base::SplitString(webgl_size, 'x', &split_size);
    170       if (split_size.size() == 2) {
    171         width = atoi(split_size[0].c_str());
    172         height = atoi(split_size[1].c_str());
    173       }
    174     }
    175     if (!width || !height) {
    176       width = 800;
    177       height = 600;
    178     }
    179     gfx::Rect bounds(width, height);
    180     webgl_.SetBounds(bounds);
    181     parent_->Add(&webgl_);
    182 
    183     context_provider_ = context_factory->SharedMainThreadContextProvider();
    184     gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
    185     GLuint texture = 0;
    186     gl->GenTextures(1, &texture);
    187     gl->BindTexture(GL_TEXTURE_2D, texture);
    188     gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    189     gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    190     gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    191     gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    192     gl->TexImage2D(GL_TEXTURE_2D,
    193                    0,
    194                    GL_RGBA,
    195                    width,
    196                    height,
    197                    0,
    198                    GL_RGBA,
    199                    GL_UNSIGNED_BYTE,
    200                    NULL);
    201     gpu::Mailbox mailbox;
    202     gl->GenMailboxCHROMIUM(mailbox.name);
    203     gl->ProduceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
    204 
    205     gl->GenFramebuffers(1, &fbo_);
    206     gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_);
    207     gl->FramebufferTexture2D(
    208         GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
    209     gl->ClearColor(0.f, 1.f, 0.f, 1.f);
    210     gl->Clear(GL_COLOR_BUFFER_BIT);
    211     gl->Flush();
    212 
    213     GLuint sync_point = gl->InsertSyncPointCHROMIUM();
    214     webgl_.SetTextureMailbox(
    215         cc::TextureMailbox(mailbox, GL_TEXTURE_2D, sync_point),
    216         cc::SingleReleaseCallback::Create(
    217             base::Bind(ReturnMailbox, context_provider_, texture)),
    218         bounds.size());
    219     compositor->AddObserver(this);
    220   }
    221 
    222   virtual ~WebGLBench() {
    223     webgl_.SetShowPaintedContent();
    224     gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
    225     gl->DeleteFramebuffers(1, &fbo_);
    226     compositor_->RemoveObserver(this);
    227   }
    228 
    229   virtual void Draw() OVERRIDE {
    230     if (do_draw_) {
    231       gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
    232       gl->ClearColor((frames() % kFrames)*1.0/kFrames, 1.f, 0.f, 1.f);
    233       gl->Clear(GL_COLOR_BUFFER_BIT);
    234       gl->Flush();
    235     }
    236     webgl_.SchedulePaint(gfx::Rect(webgl_.bounds().size()));
    237     compositor_->ScheduleDraw();
    238   }
    239 
    240  private:
    241   Layer* parent_;
    242   Layer webgl_;
    243   Compositor* compositor_;
    244   scoped_refptr<cc::ContextProvider> context_provider_;
    245 
    246   // The FBO that is used to render to the texture.
    247   unsigned int fbo_;
    248 
    249   // Whether or not to draw to the texture every frame.
    250   bool do_draw_;
    251 
    252   DISALLOW_COPY_AND_ASSIGN(WebGLBench);
    253 };
    254 
    255 // A benchmark that paints (in software) all tiles every frame.
    256 class SoftwareScrollBench : public BenchCompositorObserver {
    257  public:
    258   SoftwareScrollBench(ColoredLayer* layer,
    259                       Compositor* compositor,
    260                       int max_frames)
    261       : BenchCompositorObserver(max_frames),
    262         layer_(layer),
    263         compositor_(compositor) {
    264     compositor->AddObserver(this);
    265     layer_->set_draw(
    266         !CommandLine::ForCurrentProcess()->HasSwitch("disable-draw"));
    267   }
    268 
    269   virtual ~SoftwareScrollBench() {
    270     compositor_->RemoveObserver(this);
    271   }
    272 
    273   virtual void Draw() OVERRIDE {
    274     layer_->set_color(
    275         SkColorSetARGBInline(255*(frames() % kFrames)/kFrames, 255, 0, 255));
    276     layer_->SchedulePaint(gfx::Rect(layer_->bounds().size()));
    277   }
    278 
    279  private:
    280   ColoredLayer* layer_;
    281   Compositor* compositor_;
    282 
    283   DISALLOW_COPY_AND_ASSIGN(SoftwareScrollBench);
    284 };
    285 
    286 }  // namespace
    287 
    288 int main(int argc, char** argv) {
    289   CommandLine::Init(argc, argv);
    290 
    291   base::AtExitManager exit_manager;
    292 
    293 #if defined(USE_X11)
    294   // This demo uses InProcessContextFactory which uses X on a separate Gpu
    295   // thread.
    296   gfx::InitializeThreadedX11();
    297 #endif
    298 
    299   gfx::GLSurface::InitializeOneOff();
    300 
    301   // The ContextFactory must exist before any Compositors are created.
    302   scoped_ptr<ui::InProcessContextFactory> context_factory(
    303       new ui::InProcessContextFactory());
    304 
    305   base::i18n::InitializeICU();
    306 
    307   base::MessageLoopForUI message_loop;
    308   aura::Env::CreateInstance(true);
    309   aura::Env::GetInstance()->set_context_factory(context_factory.get());
    310   scoped_ptr<aura::TestScreen> test_screen(
    311       aura::TestScreen::CreateFullscreen());
    312   gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, test_screen.get());
    313   scoped_ptr<aura::WindowTreeHost> host(
    314       test_screen->CreateHostForPrimaryDisplay());
    315   aura::client::SetCaptureClient(
    316       host->window(),
    317       new aura::client::DefaultCaptureClient(host->window()));
    318 
    319   scoped_ptr<aura::client::FocusClient> focus_client(
    320       new aura::test::TestFocusClient);
    321   aura::client::SetFocusClient(host->window(), focus_client.get());
    322 
    323   // add layers
    324   ColoredLayer background(SK_ColorRED);
    325   background.SetBounds(host->window()->bounds());
    326   host->window()->layer()->Add(&background);
    327 
    328   ColoredLayer window(SK_ColorBLUE);
    329   window.SetBounds(gfx::Rect(background.bounds().size()));
    330   background.Add(&window);
    331 
    332   Layer content_layer(ui::LAYER_NOT_DRAWN);
    333 
    334   CommandLine* command_line = CommandLine::ForCurrentProcess();
    335   bool force = command_line->HasSwitch("force-render-surface");
    336   content_layer.SetForceRenderSurface(force);
    337   gfx::Rect bounds(window.bounds().size());
    338   bounds.Inset(0, 30, 0, 0);
    339   content_layer.SetBounds(bounds);
    340   window.Add(&content_layer);
    341 
    342   ColoredLayer page_background(SK_ColorWHITE);
    343   page_background.SetBounds(gfx::Rect(content_layer.bounds().size()));
    344   content_layer.Add(&page_background);
    345 
    346   int frames = atoi(command_line->GetSwitchValueASCII("frames").c_str());
    347   scoped_ptr<BenchCompositorObserver> bench;
    348 
    349   if (command_line->HasSwitch("bench-software-scroll")) {
    350     bench.reset(new SoftwareScrollBench(&page_background,
    351                                         host->compositor(),
    352                                         frames));
    353   } else {
    354     bench.reset(new WebGLBench(context_factory.get(),
    355                                &page_background,
    356                                host->compositor(),
    357                                frames));
    358   }
    359 
    360 #ifndef NDEBUG
    361   ui::PrintLayerHierarchy(host->window()->layer(), gfx::Point(100, 100));
    362 #endif
    363 
    364   host->Show();
    365   base::MessageLoopForUI::current()->Run();
    366   focus_client.reset();
    367   host.reset();
    368 
    369   return 0;
    370 }
    371