compositor.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
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 34namespace { 35 36const double kDefaultRefreshRate = 60.0; 37const double kTestRefreshRate = 200.0; 38 39const int kCompositorLockTimeoutMs = 67; 40 41} // namespace 42 43namespace ui { 44 45CompositorLock::CompositorLock(Compositor* compositor) 46 : compositor_(compositor) { 47 compositor_->task_runner_->PostDelayedTask( 48 FROM_HERE, 49 base::Bind(&CompositorLock::CancelLock, AsWeakPtr()), 50 base::TimeDelta::FromMilliseconds(kCompositorLockTimeoutMs)); 51} 52 53CompositorLock::~CompositorLock() { 54 CancelLock(); 55} 56 57void CompositorLock::CancelLock() { 58 if (!compositor_) 59 return; 60 compositor_->UnlockCompositor(); 61 compositor_ = NULL; 62} 63 64} // namespace ui 65 66namespace { 67 68} // namespace 69 70namespace ui { 71 72Compositor::Compositor(gfx::AcceleratedWidget widget, 73 ui::ContextFactory* context_factory, 74 scoped_refptr<base::SingleThreadTaskRunner> task_runner) 75 : context_factory_(context_factory), 76 root_layer_(NULL), 77 widget_(widget), 78 compositor_thread_loop_(context_factory->GetCompositorMessageLoop()), 79 task_runner_(task_runner), 80 vsync_manager_(new CompositorVSyncManager()), 81 device_scale_factor_(0.0f), 82 last_started_frame_(0), 83 last_ended_frame_(0), 84 disable_schedule_composite_(false), 85 compositor_lock_(NULL), 86 defer_draw_scheduling_(false), 87 waiting_on_compositing_end_(false), 88 draw_on_compositing_end_(false), 89 swap_state_(SWAP_NONE), 90 layer_animator_collection_(this), 91 schedule_draw_factory_(this) { 92 root_web_layer_ = cc::Layer::Create(); 93 94 CommandLine* command_line = CommandLine::ForCurrentProcess(); 95 96 cc::LayerTreeSettings settings; 97 settings.refresh_rate = 98 context_factory_->DoesCreateTestContexts() 99 ? kTestRefreshRate 100 : kDefaultRefreshRate; 101 settings.main_frame_before_draw_enabled = false; 102 settings.main_frame_before_activation_enabled = false; 103 settings.throttle_frame_production = 104 !command_line->HasSwitch(switches::kDisableGpuVsync); 105#if !defined(OS_MACOSX) 106 settings.partial_swap_enabled = 107 !command_line->HasSwitch(cc::switches::kUIDisablePartialSwap); 108#endif 109#if defined(OS_CHROMEOS) 110 settings.per_tile_painting_enabled = true; 111#endif 112 113 // These flags should be mirrored by renderer versions in content/renderer/. 114 settings.initial_debug_state.show_debug_borders = 115 command_line->HasSwitch(cc::switches::kUIShowCompositedLayerBorders); 116 settings.initial_debug_state.show_fps_counter = 117 command_line->HasSwitch(cc::switches::kUIShowFPSCounter); 118 settings.initial_debug_state.show_layer_animation_bounds_rects = 119 command_line->HasSwitch(cc::switches::kUIShowLayerAnimationBounds); 120 settings.initial_debug_state.show_paint_rects = 121 command_line->HasSwitch(switches::kUIShowPaintRects); 122 settings.initial_debug_state.show_property_changed_rects = 123 command_line->HasSwitch(cc::switches::kUIShowPropertyChangedRects); 124 settings.initial_debug_state.show_surface_damage_rects = 125 command_line->HasSwitch(cc::switches::kUIShowSurfaceDamageRects); 126 settings.initial_debug_state.show_screen_space_rects = 127 command_line->HasSwitch(cc::switches::kUIShowScreenSpaceRects); 128 settings.initial_debug_state.show_replica_screen_space_rects = 129 command_line->HasSwitch(cc::switches::kUIShowReplicaScreenSpaceRects); 130 settings.initial_debug_state.show_occluding_rects = 131 command_line->HasSwitch(cc::switches::kUIShowOccludingRects); 132 settings.initial_debug_state.show_non_occluding_rects = 133 command_line->HasSwitch(cc::switches::kUIShowNonOccludingRects); 134 135 settings.initial_debug_state.SetRecordRenderingStats( 136 command_line->HasSwitch(cc::switches::kEnableGpuBenchmarking)); 137 138 settings.impl_side_painting = IsUIImplSidePaintingEnabled(); 139 settings.use_zero_copy = IsUIZeroCopyEnabled(); 140 141 base::TimeTicks before_create = base::TimeTicks::Now(); 142 if (compositor_thread_loop_) { 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 163Compositor::~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 179void Compositor::ScheduleDraw() { 180 if (compositor_thread_loop_) { 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 190void 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 203void Compositor::SetHostHasTransparentBackground( 204 bool host_has_transparent_background) { 205 host_->set_has_transparent_background(host_has_transparent_background); 206} 207 208void Compositor::Draw() { 209 DCHECK(!compositor_thread_loop_); 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 base::TimeTicks now = gfx::FrameTime::Now(); 230 Animate(now); 231 Layout(); 232 host_->Composite(now); 233 } 234 if (swap_state_ == SWAP_NONE) 235 NotifyEnd(); 236} 237 238void Compositor::ScheduleFullRedraw() { 239 host_->SetNeedsRedraw(); 240} 241 242void Compositor::ScheduleRedrawRect(const gfx::Rect& damage_rect) { 243 host_->SetNeedsRedrawRect(damage_rect); 244} 245 246void Compositor::FinishAllRendering() { 247 host_->FinishAllRendering(); 248} 249 250void Compositor::SetLatencyInfo(const ui::LatencyInfo& latency_info) { 251 scoped_ptr<cc::SwapPromise> swap_promise( 252 new cc::LatencyInfoSwapPromise(latency_info)); 253 host_->QueueSwapPromise(swap_promise.Pass()); 254} 255 256void Compositor::SetScaleAndSize(float scale, const gfx::Size& size_in_pixel) { 257 DCHECK_GT(scale, 0); 258 if (!size_in_pixel.IsEmpty()) { 259 size_ = size_in_pixel; 260 host_->SetViewportSize(size_in_pixel); 261 root_web_layer_->SetBounds(size_in_pixel); 262 } 263 if (device_scale_factor_ != scale) { 264 device_scale_factor_ = scale; 265 host_->SetDeviceScaleFactor(scale); 266 if (root_layer_) 267 root_layer_->OnDeviceScaleFactorChanged(scale); 268 } 269} 270 271void Compositor::SetBackgroundColor(SkColor color) { 272 host_->set_background_color(color); 273 ScheduleDraw(); 274} 275 276scoped_refptr<CompositorVSyncManager> Compositor::vsync_manager() const { 277 return vsync_manager_; 278} 279 280void Compositor::AddObserver(CompositorObserver* observer) { 281 observer_list_.AddObserver(observer); 282} 283 284void Compositor::RemoveObserver(CompositorObserver* observer) { 285 observer_list_.RemoveObserver(observer); 286} 287 288bool Compositor::HasObserver(CompositorObserver* observer) { 289 return observer_list_.HasObserver(observer); 290} 291 292void Compositor::AddAnimationObserver(CompositorAnimationObserver* observer) { 293 animation_observer_list_.AddObserver(observer); 294 host_->SetNeedsAnimate(); 295} 296 297void Compositor::RemoveAnimationObserver( 298 CompositorAnimationObserver* observer) { 299 animation_observer_list_.RemoveObserver(observer); 300} 301 302bool Compositor::HasAnimationObserver(CompositorAnimationObserver* observer) { 303 return animation_observer_list_.HasObserver(observer); 304} 305 306void Compositor::Animate(base::TimeTicks frame_begin_time) { 307 FOR_EACH_OBSERVER(CompositorAnimationObserver, 308 animation_observer_list_, 309 OnAnimationStep(frame_begin_time)); 310 if (animation_observer_list_.might_have_observers()) 311 host_->SetNeedsAnimate(); 312} 313 314void Compositor::Layout() { 315 // We're sending damage that will be addressed during this composite 316 // cycle, so we don't need to schedule another composite to address it. 317 disable_schedule_composite_ = true; 318 if (root_layer_) 319 root_layer_->SendDamagedRects(); 320 disable_schedule_composite_ = false; 321} 322 323scoped_ptr<cc::OutputSurface> Compositor::CreateOutputSurface(bool fallback) { 324 return context_factory_->CreateOutputSurface(this, fallback); 325} 326 327void Compositor::DidCommit() { 328 DCHECK(!IsLocked()); 329 FOR_EACH_OBSERVER(CompositorObserver, 330 observer_list_, 331 OnCompositingDidCommit(this)); 332} 333 334void Compositor::DidCommitAndDrawFrame() { 335 base::TimeTicks start_time = gfx::FrameTime::Now(); 336 FOR_EACH_OBSERVER(CompositorObserver, 337 observer_list_, 338 OnCompositingStarted(this, start_time)); 339} 340 341void Compositor::DidCompleteSwapBuffers() { 342 if (compositor_thread_loop_) { 343 NotifyEnd(); 344 } else { 345 DCHECK_EQ(swap_state_, SWAP_POSTED); 346 NotifyEnd(); 347 swap_state_ = SWAP_COMPLETED; 348 } 349} 350 351void Compositor::ScheduleComposite() { 352 if (!disable_schedule_composite_) 353 ScheduleDraw(); 354} 355 356void Compositor::ScheduleAnimation() { 357 ScheduleComposite(); 358} 359 360void Compositor::DidPostSwapBuffers() { 361 DCHECK(!compositor_thread_loop_); 362 DCHECK_EQ(swap_state_, SWAP_NONE); 363 swap_state_ = SWAP_POSTED; 364} 365 366void Compositor::DidAbortSwapBuffers() { 367 if (!compositor_thread_loop_) { 368 if (swap_state_ == SWAP_POSTED) { 369 NotifyEnd(); 370 swap_state_ = SWAP_COMPLETED; 371 } 372 } 373 374 FOR_EACH_OBSERVER(CompositorObserver, 375 observer_list_, 376 OnCompositingAborted(this)); 377} 378 379const cc::LayerTreeDebugState& Compositor::GetLayerTreeDebugState() const { 380 return host_->debug_state(); 381} 382 383void Compositor::SetLayerTreeDebugState( 384 const cc::LayerTreeDebugState& debug_state) { 385 host_->SetDebugState(debug_state); 386} 387 388scoped_refptr<CompositorLock> Compositor::GetCompositorLock() { 389 if (!compositor_lock_) { 390 compositor_lock_ = new CompositorLock(this); 391 if (compositor_thread_loop_) 392 host_->SetDeferCommits(true); 393 FOR_EACH_OBSERVER(CompositorObserver, 394 observer_list_, 395 OnCompositingLockStateChanged(this)); 396 } 397 return compositor_lock_; 398} 399 400void Compositor::UnlockCompositor() { 401 DCHECK(compositor_lock_); 402 compositor_lock_ = NULL; 403 if (compositor_thread_loop_) 404 host_->SetDeferCommits(false); 405 FOR_EACH_OBSERVER(CompositorObserver, 406 observer_list_, 407 OnCompositingLockStateChanged(this)); 408} 409 410void Compositor::CancelCompositorLock() { 411 if (compositor_lock_) 412 compositor_lock_->CancelLock(); 413} 414 415void Compositor::NotifyEnd() { 416 last_ended_frame_++; 417 TRACE_EVENT_ASYNC_END0("ui", "Compositor::Draw", last_ended_frame_); 418 waiting_on_compositing_end_ = false; 419 if (draw_on_compositing_end_) { 420 draw_on_compositing_end_ = false; 421 422 // Call ScheduleDraw() instead of Draw() in order to allow other 423 // CompositorObservers to be notified before starting another 424 // draw cycle. 425 ScheduleDraw(); 426 } 427 FOR_EACH_OBSERVER(CompositorObserver, 428 observer_list_, 429 OnCompositingEnded(this)); 430} 431 432} // namespace ui 433