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