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