Home | History | Annotate | Download | only in compositor
      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 "ui/compositor/compositor.h"
      6 
      7 #include <algorithm>
      8 #include <deque>
      9 
     10 #include "base/bind.h"
     11 #include "base/command_line.h"
     12 #include "base/debug/trace_event.h"
     13 #include "base/message_loop/message_loop.h"
     14 #include "base/metrics/histogram.h"
     15 #include "base/strings/string_util.h"
     16 #include "base/sys_info.h"
     17 #include "cc/base/latency_info_swap_promise.h"
     18 #include "cc/base/switches.h"
     19 #include "cc/input/input_handler.h"
     20 #include "cc/layers/layer.h"
     21 #include "cc/output/context_provider.h"
     22 #include "cc/trees/layer_tree_host.h"
     23 #include "third_party/skia/include/core/SkBitmap.h"
     24 #include "ui/compositor/compositor_observer.h"
     25 #include "ui/compositor/compositor_switches.h"
     26 #include "ui/compositor/compositor_vsync_manager.h"
     27 #include "ui/compositor/dip_util.h"
     28 #include "ui/compositor/layer.h"
     29 #include "ui/compositor/layer_animator_collection.h"
     30 #include "ui/gfx/frame_time.h"
     31 #include "ui/gl/gl_context.h"
     32 #include "ui/gl/gl_switches.h"
     33 
     34 namespace {
     35 
     36 const double kDefaultRefreshRate = 60.0;
     37 const double kTestRefreshRate = 200.0;
     38 
     39 const int kCompositorLockTimeoutMs = 67;
     40 
     41 }  // namespace
     42 
     43 namespace ui {
     44 
     45 CompositorLock::CompositorLock(Compositor* compositor)
     46     : compositor_(compositor) {
     47   base::MessageLoop::current()->PostDelayedTask(
     48       FROM_HERE,
     49       base::Bind(&CompositorLock::CancelLock, AsWeakPtr()),
     50       base::TimeDelta::FromMilliseconds(kCompositorLockTimeoutMs));
     51 }
     52 
     53 CompositorLock::~CompositorLock() {
     54   CancelLock();
     55 }
     56 
     57 void CompositorLock::CancelLock() {
     58   if (!compositor_)
     59     return;
     60   compositor_->UnlockCompositor();
     61   compositor_ = NULL;
     62 }
     63 
     64 }  // namespace ui
     65 
     66 namespace {
     67 
     68 }  // namespace
     69 
     70 namespace ui {
     71 
     72 Compositor::Compositor(gfx::AcceleratedWidget widget,
     73                        ui::ContextFactory* context_factory)
     74     : context_factory_(context_factory),
     75       root_layer_(NULL),
     76       widget_(widget),
     77       compositor_thread_loop_(context_factory->GetCompositorMessageLoop()),
     78       vsync_manager_(new CompositorVSyncManager()),
     79       device_scale_factor_(0.0f),
     80       last_started_frame_(0),
     81       last_ended_frame_(0),
     82       disable_schedule_composite_(false),
     83       compositor_lock_(NULL),
     84       defer_draw_scheduling_(false),
     85       waiting_on_compositing_end_(false),
     86       draw_on_compositing_end_(false),
     87       swap_state_(SWAP_NONE),
     88       layer_animator_collection_(this),
     89       schedule_draw_factory_(this) {
     90   root_web_layer_ = cc::Layer::Create();
     91 
     92   CommandLine* command_line = CommandLine::ForCurrentProcess();
     93 
     94   cc::LayerTreeSettings settings;
     95   settings.refresh_rate =
     96       context_factory_->DoesCreateTestContexts()
     97       ? kTestRefreshRate
     98       : kDefaultRefreshRate;
     99   settings.main_frame_before_draw_enabled = false;
    100   settings.main_frame_before_activation_enabled = false;
    101   settings.throttle_frame_production =
    102       !command_line->HasSwitch(switches::kDisableGpuVsync);
    103 #if !defined(OS_MACOSX)
    104   settings.partial_swap_enabled =
    105       !command_line->HasSwitch(cc::switches::kUIDisablePartialSwap);
    106 #endif
    107 #if defined(OS_CHROMEOS)
    108   settings.per_tile_painting_enabled = true;
    109 #endif
    110 
    111   // These flags should be mirrored by renderer versions in content/renderer/.
    112   settings.initial_debug_state.show_debug_borders =
    113       command_line->HasSwitch(cc::switches::kUIShowCompositedLayerBorders);
    114   settings.initial_debug_state.show_fps_counter =
    115       command_line->HasSwitch(cc::switches::kUIShowFPSCounter);
    116   settings.initial_debug_state.show_layer_animation_bounds_rects =
    117       command_line->HasSwitch(cc::switches::kUIShowLayerAnimationBounds);
    118   settings.initial_debug_state.show_paint_rects =
    119       command_line->HasSwitch(switches::kUIShowPaintRects);
    120   settings.initial_debug_state.show_property_changed_rects =
    121       command_line->HasSwitch(cc::switches::kUIShowPropertyChangedRects);
    122   settings.initial_debug_state.show_surface_damage_rects =
    123       command_line->HasSwitch(cc::switches::kUIShowSurfaceDamageRects);
    124   settings.initial_debug_state.show_screen_space_rects =
    125       command_line->HasSwitch(cc::switches::kUIShowScreenSpaceRects);
    126   settings.initial_debug_state.show_replica_screen_space_rects =
    127       command_line->HasSwitch(cc::switches::kUIShowReplicaScreenSpaceRects);
    128   settings.initial_debug_state.show_occluding_rects =
    129       command_line->HasSwitch(cc::switches::kUIShowOccludingRects);
    130   settings.initial_debug_state.show_non_occluding_rects =
    131       command_line->HasSwitch(cc::switches::kUIShowNonOccludingRects);
    132 
    133   settings.initial_debug_state.SetRecordRenderingStats(
    134       command_line->HasSwitch(cc::switches::kEnableGpuBenchmarking));
    135 
    136   settings.impl_side_painting = IsUIImplSidePaintingEnabled();
    137   settings.use_zero_copy = IsUIZeroCopyEnabled();
    138 
    139   base::TimeTicks before_create = base::TimeTicks::Now();
    140   if (compositor_thread_loop_) {
    141     host_ = cc::LayerTreeHost::CreateThreaded(
    142         this,
    143         context_factory_->GetSharedBitmapManager(),
    144         settings,
    145         compositor_thread_loop_);
    146   } else {
    147     host_ = cc::LayerTreeHost::CreateSingleThreaded(
    148         this, this, context_factory_->GetSharedBitmapManager(), settings);
    149   }
    150   UMA_HISTOGRAM_TIMES("GPU.CreateBrowserCompositor",
    151                       base::TimeTicks::Now() - before_create);
    152   host_->SetRootLayer(root_web_layer_);
    153   host_->SetLayerTreeHostClientReady();
    154 }
    155 
    156 Compositor::~Compositor() {
    157   TRACE_EVENT0("shutdown", "Compositor::destructor");
    158 
    159   CancelCompositorLock();
    160   DCHECK(!compositor_lock_);
    161 
    162   if (root_layer_)
    163     root_layer_->SetCompositor(NULL);
    164 
    165   // Stop all outstanding draws before telling the ContextFactory to tear
    166   // down any contexts that the |host_| may rely upon.
    167   host_.reset();
    168 
    169   context_factory_->RemoveCompositor(this);
    170 }
    171 
    172 void Compositor::ScheduleDraw() {
    173   if (compositor_thread_loop_) {
    174     host_->SetNeedsCommit();
    175   } else if (!defer_draw_scheduling_) {
    176     defer_draw_scheduling_ = true;
    177     base::MessageLoop::current()->PostTask(
    178         FROM_HERE,
    179         base::Bind(&Compositor::Draw, schedule_draw_factory_.GetWeakPtr()));
    180   }
    181 }
    182 
    183 void Compositor::SetRootLayer(Layer* root_layer) {
    184   if (root_layer_ == root_layer)
    185     return;
    186   if (root_layer_)
    187     root_layer_->SetCompositor(NULL);
    188   root_layer_ = root_layer;
    189   if (root_layer_ && !root_layer_->GetCompositor())
    190     root_layer_->SetCompositor(this);
    191   root_web_layer_->RemoveAllChildren();
    192   if (root_layer_)
    193     root_web_layer_->AddChild(root_layer_->cc_layer());
    194 }
    195 
    196 void Compositor::SetHostHasTransparentBackground(
    197     bool host_has_transparent_background) {
    198   host_->set_has_transparent_background(host_has_transparent_background);
    199 }
    200 
    201 void Compositor::Draw() {
    202   DCHECK(!compositor_thread_loop_);
    203 
    204   defer_draw_scheduling_ = false;
    205   if (waiting_on_compositing_end_) {
    206     draw_on_compositing_end_ = true;
    207     return;
    208   }
    209   waiting_on_compositing_end_ = true;
    210 
    211   TRACE_EVENT_ASYNC_BEGIN0("ui", "Compositor::Draw", last_started_frame_ + 1);
    212 
    213   if (!root_layer_)
    214     return;
    215 
    216   DCHECK_NE(swap_state_, SWAP_POSTED);
    217   swap_state_ = SWAP_NONE;
    218 
    219   last_started_frame_++;
    220   if (!IsLocked()) {
    221     // TODO(nduca): Temporary while compositor calls
    222     // compositeImmediately() directly.
    223     base::TimeTicks now = gfx::FrameTime::Now();
    224     Animate(now);
    225     Layout();
    226     host_->Composite(now);
    227   }
    228   if (swap_state_ == SWAP_NONE)
    229     NotifyEnd();
    230 }
    231 
    232 void Compositor::ScheduleFullRedraw() {
    233   host_->SetNeedsRedraw();
    234 }
    235 
    236 void Compositor::ScheduleRedrawRect(const gfx::Rect& damage_rect) {
    237   host_->SetNeedsRedrawRect(damage_rect);
    238 }
    239 
    240 void Compositor::FinishAllRendering() {
    241   host_->FinishAllRendering();
    242 }
    243 
    244 void Compositor::SetLatencyInfo(const ui::LatencyInfo& latency_info) {
    245   scoped_ptr<cc::SwapPromise> swap_promise(
    246       new cc::LatencyInfoSwapPromise(latency_info));
    247   host_->QueueSwapPromise(swap_promise.Pass());
    248 }
    249 
    250 void Compositor::SetScaleAndSize(float scale, const gfx::Size& size_in_pixel) {
    251   DCHECK_GT(scale, 0);
    252   if (!size_in_pixel.IsEmpty()) {
    253     size_ = size_in_pixel;
    254     host_->SetViewportSize(size_in_pixel);
    255     root_web_layer_->SetBounds(size_in_pixel);
    256   }
    257   if (device_scale_factor_ != scale) {
    258     device_scale_factor_ = scale;
    259     host_->SetDeviceScaleFactor(scale);
    260     if (root_layer_)
    261       root_layer_->OnDeviceScaleFactorChanged(scale);
    262   }
    263 }
    264 
    265 void Compositor::SetBackgroundColor(SkColor color) {
    266   host_->set_background_color(color);
    267   ScheduleDraw();
    268 }
    269 
    270 scoped_refptr<CompositorVSyncManager> Compositor::vsync_manager() const {
    271   return vsync_manager_;
    272 }
    273 
    274 void Compositor::AddObserver(CompositorObserver* observer) {
    275   observer_list_.AddObserver(observer);
    276 }
    277 
    278 void Compositor::RemoveObserver(CompositorObserver* observer) {
    279   observer_list_.RemoveObserver(observer);
    280 }
    281 
    282 bool Compositor::HasObserver(CompositorObserver* observer) {
    283   return observer_list_.HasObserver(observer);
    284 }
    285 
    286 void Compositor::Animate(base::TimeTicks frame_begin_time) {
    287   layer_animator_collection_.Progress(frame_begin_time);
    288   if (layer_animator_collection_.HasActiveAnimators())
    289     host_->SetNeedsAnimate();
    290 }
    291 
    292 void Compositor::Layout() {
    293   // We're sending damage that will be addressed during this composite
    294   // cycle, so we don't need to schedule another composite to address it.
    295   disable_schedule_composite_ = true;
    296   if (root_layer_)
    297     root_layer_->SendDamagedRects();
    298   disable_schedule_composite_ = false;
    299 }
    300 
    301 scoped_ptr<cc::OutputSurface> Compositor::CreateOutputSurface(bool fallback) {
    302   return context_factory_->CreateOutputSurface(this, fallback);
    303 }
    304 
    305 void Compositor::DidCommit() {
    306   DCHECK(!IsLocked());
    307   FOR_EACH_OBSERVER(CompositorObserver,
    308                     observer_list_,
    309                     OnCompositingDidCommit(this));
    310 }
    311 
    312 void Compositor::DidCommitAndDrawFrame() {
    313   base::TimeTicks start_time = gfx::FrameTime::Now();
    314   FOR_EACH_OBSERVER(CompositorObserver,
    315                     observer_list_,
    316                     OnCompositingStarted(this, start_time));
    317 }
    318 
    319 void Compositor::DidCompleteSwapBuffers() {
    320   if (compositor_thread_loop_) {
    321     NotifyEnd();
    322   } else {
    323     DCHECK_EQ(swap_state_, SWAP_POSTED);
    324     NotifyEnd();
    325     swap_state_ = SWAP_COMPLETED;
    326   }
    327 }
    328 
    329 void Compositor::ScheduleComposite() {
    330   if (!disable_schedule_composite_)
    331     ScheduleDraw();
    332 }
    333 
    334 void Compositor::ScheduleAnimation() {
    335   ScheduleComposite();
    336 }
    337 
    338 void Compositor::DidPostSwapBuffers() {
    339   DCHECK(!compositor_thread_loop_);
    340   DCHECK_EQ(swap_state_, SWAP_NONE);
    341   swap_state_ = SWAP_POSTED;
    342 }
    343 
    344 void Compositor::DidAbortSwapBuffers() {
    345   if (!compositor_thread_loop_) {
    346     if (swap_state_ == SWAP_POSTED) {
    347       NotifyEnd();
    348       swap_state_ = SWAP_COMPLETED;
    349     }
    350   }
    351 
    352   FOR_EACH_OBSERVER(CompositorObserver,
    353                     observer_list_,
    354                     OnCompositingAborted(this));
    355 }
    356 
    357 void Compositor::ScheduleAnimationForLayerCollection() {
    358   host_->SetNeedsAnimate();
    359 }
    360 
    361 const cc::LayerTreeDebugState& Compositor::GetLayerTreeDebugState() const {
    362   return host_->debug_state();
    363 }
    364 
    365 void Compositor::SetLayerTreeDebugState(
    366     const cc::LayerTreeDebugState& debug_state) {
    367   host_->SetDebugState(debug_state);
    368 }
    369 
    370 scoped_refptr<CompositorLock> Compositor::GetCompositorLock() {
    371   if (!compositor_lock_) {
    372     compositor_lock_ = new CompositorLock(this);
    373     if (compositor_thread_loop_)
    374       host_->SetDeferCommits(true);
    375     FOR_EACH_OBSERVER(CompositorObserver,
    376                       observer_list_,
    377                       OnCompositingLockStateChanged(this));
    378   }
    379   return compositor_lock_;
    380 }
    381 
    382 void Compositor::UnlockCompositor() {
    383   DCHECK(compositor_lock_);
    384   compositor_lock_ = NULL;
    385   if (compositor_thread_loop_)
    386     host_->SetDeferCommits(false);
    387   FOR_EACH_OBSERVER(CompositorObserver,
    388                     observer_list_,
    389                     OnCompositingLockStateChanged(this));
    390 }
    391 
    392 void Compositor::CancelCompositorLock() {
    393   if (compositor_lock_)
    394     compositor_lock_->CancelLock();
    395 }
    396 
    397 void Compositor::NotifyEnd() {
    398   last_ended_frame_++;
    399   TRACE_EVENT_ASYNC_END0("ui", "Compositor::Draw", last_ended_frame_);
    400   waiting_on_compositing_end_ = false;
    401   if (draw_on_compositing_end_) {
    402     draw_on_compositing_end_ = false;
    403 
    404     // Call ScheduleDraw() instead of Draw() in order to allow other
    405     // CompositorObservers to be notified before starting another
    406     // draw cycle.
    407     ScheduleDraw();
    408   }
    409   FOR_EACH_OBSERVER(CompositorObserver,
    410                     observer_list_,
    411                     OnCompositingEnded(this));
    412 }
    413 
    414 }  // namespace ui
    415