compositor.cc revision 010d83a9304c5a91596085d917d248abff47903a
1410ffb2bc5f072d58a73c14560345bcf77dec1ccJohn McCall// Copyright (c) 2012 The Chromium Authors. All rights reserved. 24de9fce48e42cc7ec1345c0fd21b3dbc5b9114c8Anders Carlsson// Use of this source code is governed by a BSD-style license that can be 3a17d7ccc2ed77e321855990e180f2a34ec304bfcAnders Carlsson// found in the LICENSE file. 4a17d7ccc2ed77e321855990e180f2a34ec304bfcAnders Carlsson 5a17d7ccc2ed77e321855990e180f2a34ec304bfcAnders Carlsson#include "ui/compositor/compositor.h" 6a17d7ccc2ed77e321855990e180f2a34ec304bfcAnders Carlsson 7a17d7ccc2ed77e321855990e180f2a34ec304bfcAnders Carlsson#include <algorithm> 80e4f40e1bbc4dce16bbb9870300a435419f1b3d5Daniel Dunbar#include <deque> 90e4f40e1bbc4dce16bbb9870300a435419f1b3d5Daniel Dunbar 100e4f40e1bbc4dce16bbb9870300a435419f1b3d5Daniel Dunbar#include "base/bind.h" 110e4f40e1bbc4dce16bbb9870300a435419f1b3d5Daniel Dunbar#include "base/command_line.h" 120e4f40e1bbc4dce16bbb9870300a435419f1b3d5Daniel Dunbar#include "base/debug/trace_event.h" 130e4f40e1bbc4dce16bbb9870300a435419f1b3d5Daniel Dunbar#include "base/memory/singleton.h" 140e4f40e1bbc4dce16bbb9870300a435419f1b3d5Daniel Dunbar#include "base/message_loop/message_loop.h" 15c1ea4b96adca4767991bb0a7b21052cef4db059cBill Wendling#include "base/metrics/histogram.h" 160e4f40e1bbc4dce16bbb9870300a435419f1b3d5Daniel Dunbar#include "base/run_loop.h" 170e4f40e1bbc4dce16bbb9870300a435419f1b3d5Daniel Dunbar#include "base/strings/string_util.h" 180e4f40e1bbc4dce16bbb9870300a435419f1b3d5Daniel Dunbar#include "base/sys_info.h" 190e4f40e1bbc4dce16bbb9870300a435419f1b3d5Daniel Dunbar#include "base/threading/thread.h" 20f1c97eb52e55d2d1340a0345ed91e345fddcb65dChris Lattner#include "base/threading/thread_restrictions.h" 21f1c97eb52e55d2d1340a0345ed91e345fddcb65dChris Lattner#include "cc/base/latency_info_swap_promise.h" 22f1c97eb52e55d2d1340a0345ed91e345fddcb65dChris Lattner#include "cc/base/switches.h" 23f1c97eb52e55d2d1340a0345ed91e345fddcb65dChris Lattner#include "cc/input/input_handler.h" 24f1c97eb52e55d2d1340a0345ed91e345fddcb65dChris Lattner#include "cc/layers/layer.h" 25dd2fb9c5ebc02f48a5b91a9c2a5f1e4562d02a0bMike Stump#include "cc/output/context_provider.h" 26dd2fb9c5ebc02f48a5b91a9c2a5f1e4562d02a0bMike Stump#include "cc/trees/layer_tree_host.h" 27dd2fb9c5ebc02f48a5b91a9c2a5f1e4562d02a0bMike Stump#include "third_party/skia/include/core/SkBitmap.h" 28dd2fb9c5ebc02f48a5b91a9c2a5f1e4562d02a0bMike Stump#include "ui/compositor/compositor_observer.h" 29f1c97eb52e55d2d1340a0345ed91e345fddcb65dChris Lattner#include "ui/compositor/compositor_switches.h" 30c71a4915ca216847599d03cab4ed1c5086b0eb43John McCall#include "ui/compositor/compositor_vsync_manager.h" 31c71a4915ca216847599d03cab4ed1c5086b0eb43John McCall#include "ui/compositor/dip_util.h" 32c71a4915ca216847599d03cab4ed1c5086b0eb43John McCall#include "ui/compositor/layer.h" 33c71a4915ca216847599d03cab4ed1c5086b0eb43John McCall#include "ui/gfx/frame_time.h" 34c71a4915ca216847599d03cab4ed1c5086b0eb43John McCall#include "ui/gl/gl_context.h" 35c71a4915ca216847599d03cab4ed1c5086b0eb43John McCall#include "ui/gl/gl_switches.h" 3646ec70e2e6541a067d33b2513505bec74582b53cJohn McCall 3746ec70e2e6541a067d33b2513505bec74582b53cJohn McCallnamespace { 3846ec70e2e6541a067d33b2513505bec74582b53cJohn McCall 3946ec70e2e6541a067d33b2513505bec74582b53cJohn McCallconst double kDefaultRefreshRate = 60.0; 4046ec70e2e6541a067d33b2513505bec74582b53cJohn McCallconst double kTestRefreshRate = 200.0; 4146ec70e2e6541a067d33b2513505bec74582b53cJohn McCall 4246ec70e2e6541a067d33b2513505bec74582b53cJohn McCallbool g_compositor_initialized = false; 436ea4841da1390b4f76d066f25333f11f6d8c5f40John McCallbase::Thread* g_compositor_thread = NULL; 446ea4841da1390b4f76d066f25333f11f6d8c5f40John McCall 456c803f7f46533c69e2f8a9a882af9ae3b7fffb6fJohn McCallui::ContextFactory* g_context_factory = NULL; 466c803f7f46533c69e2f8a9a882af9ae3b7fffb6fJohn McCall 476ea4841da1390b4f76d066f25333f11f6d8c5f40John McCallconst int kCompositorLockTimeoutMs = 67; 4893ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Lin 496ea4841da1390b4f76d066f25333f11f6d8c5f40John McCall} // namespace 506ea4841da1390b4f76d066f25333f11f6d8c5f40John McCall 516ea4841da1390b4f76d066f25333f11f6d8c5f40John McCallnamespace ui { 526c803f7f46533c69e2f8a9a882af9ae3b7fffb6fJohn McCall 536ea4841da1390b4f76d066f25333f11f6d8c5f40John McCall// static 546ea4841da1390b4f76d066f25333f11f6d8c5f40John McCallContextFactory* ContextFactory::GetInstance() { 556c803f7f46533c69e2f8a9a882af9ae3b7fffb6fJohn McCall DCHECK(g_context_factory); 566c803f7f46533c69e2f8a9a882af9ae3b7fffb6fJohn McCall return g_context_factory; 576c803f7f46533c69e2f8a9a882af9ae3b7fffb6fJohn McCall} 586c803f7f46533c69e2f8a9a882af9ae3b7fffb6fJohn McCall 596c803f7f46533c69e2f8a9a882af9ae3b7fffb6fJohn McCall// static 606c803f7f46533c69e2f8a9a882af9ae3b7fffb6fJohn McCallvoid ContextFactory::SetInstance(ContextFactory* instance) { 616c803f7f46533c69e2f8a9a882af9ae3b7fffb6fJohn McCall DCHECK_NE(!!g_context_factory, !!instance); 626c803f7f46533c69e2f8a9a882af9ae3b7fffb6fJohn McCall g_context_factory = instance; 6393ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Lin} 646c803f7f46533c69e2f8a9a882af9ae3b7fffb6fJohn McCall 656c803f7f46533c69e2f8a9a882af9ae3b7fffb6fJohn McCallCompositorLock::CompositorLock(Compositor* compositor) 666c803f7f46533c69e2f8a9a882af9ae3b7fffb6fJohn McCall : compositor_(compositor) { 676c803f7f46533c69e2f8a9a882af9ae3b7fffb6fJohn McCall base::MessageLoop::current()->PostDelayedTask( 686c803f7f46533c69e2f8a9a882af9ae3b7fffb6fJohn McCall FROM_HERE, 697523606638128e19d6993c356851fd3e88078201Fariborz Jahanian base::Bind(&CompositorLock::CancelLock, AsWeakPtr()), 707523606638128e19d6993c356851fd3e88078201Fariborz Jahanian base::TimeDelta::FromMilliseconds(kCompositorLockTimeoutMs)); 717523606638128e19d6993c356851fd3e88078201Fariborz Jahanian} 727523606638128e19d6993c356851fd3e88078201Fariborz Jahanian 737523606638128e19d6993c356851fd3e88078201Fariborz JahanianCompositorLock::~CompositorLock() { 747523606638128e19d6993c356851fd3e88078201Fariborz Jahanian CancelLock(); 757523606638128e19d6993c356851fd3e88078201Fariborz Jahanian} 767523606638128e19d6993c356851fd3e88078201Fariborz Jahanian 777523606638128e19d6993c356851fd3e88078201Fariborz Jahanianvoid CompositorLock::CancelLock() { 787523606638128e19d6993c356851fd3e88078201Fariborz Jahanian if (!compositor_) 797523606638128e19d6993c356851fd3e88078201Fariborz Jahanian return; 807523606638128e19d6993c356851fd3e88078201Fariborz Jahanian compositor_->UnlockCompositor(); 81 compositor_ = NULL; 82} 83 84} // namespace ui 85 86namespace { 87 88} // namespace 89 90namespace ui { 91 92Compositor::Compositor(gfx::AcceleratedWidget widget) 93 : root_layer_(NULL), 94 widget_(widget), 95 vsync_manager_(new CompositorVSyncManager()), 96 device_scale_factor_(0.0f), 97 last_started_frame_(0), 98 last_ended_frame_(0), 99 next_draw_is_resize_(false), 100 disable_schedule_composite_(false), 101 compositor_lock_(NULL), 102 defer_draw_scheduling_(false), 103 waiting_on_compositing_end_(false), 104 draw_on_compositing_end_(false), 105 swap_state_(SWAP_NONE), 106 schedule_draw_factory_(this) { 107 DCHECK(g_compositor_initialized) 108 << "Compositor::Initialize must be called before creating a Compositor."; 109 110 root_web_layer_ = cc::Layer::Create(); 111 root_web_layer_->SetAnchorPoint(gfx::PointF(0.f, 0.f)); 112 113 CommandLine* command_line = CommandLine::ForCurrentProcess(); 114 115 cc::LayerTreeSettings settings; 116 settings.refresh_rate = 117 ContextFactory::GetInstance()->DoesCreateTestContexts() 118 ? kTestRefreshRate 119 : kDefaultRefreshRate; 120 settings.main_frame_before_draw_enabled = false; 121 settings.main_frame_before_activation_enabled = false; 122 settings.throttle_frame_production = 123 !command_line->HasSwitch(switches::kDisableGpuVsync); 124 settings.partial_swap_enabled = 125 !command_line->HasSwitch(cc::switches::kUIDisablePartialSwap); 126#if defined(OS_CHROMEOS) 127 settings.per_tile_painting_enabled = true; 128#endif 129 130 // These flags should be mirrored by renderer versions in content/renderer/. 131 settings.initial_debug_state.show_debug_borders = 132 command_line->HasSwitch(cc::switches::kUIShowCompositedLayerBorders); 133 settings.initial_debug_state.show_fps_counter = 134 command_line->HasSwitch(cc::switches::kUIShowFPSCounter); 135 settings.initial_debug_state.show_layer_animation_bounds_rects = 136 command_line->HasSwitch(cc::switches::kUIShowLayerAnimationBounds); 137 settings.initial_debug_state.show_paint_rects = 138 command_line->HasSwitch(switches::kUIShowPaintRects); 139 settings.initial_debug_state.show_property_changed_rects = 140 command_line->HasSwitch(cc::switches::kUIShowPropertyChangedRects); 141 settings.initial_debug_state.show_surface_damage_rects = 142 command_line->HasSwitch(cc::switches::kUIShowSurfaceDamageRects); 143 settings.initial_debug_state.show_screen_space_rects = 144 command_line->HasSwitch(cc::switches::kUIShowScreenSpaceRects); 145 settings.initial_debug_state.show_replica_screen_space_rects = 146 command_line->HasSwitch(cc::switches::kUIShowReplicaScreenSpaceRects); 147 settings.initial_debug_state.show_occluding_rects = 148 command_line->HasSwitch(cc::switches::kUIShowOccludingRects); 149 settings.initial_debug_state.show_non_occluding_rects = 150 command_line->HasSwitch(cc::switches::kUIShowNonOccludingRects); 151 152 settings.initial_debug_state.SetRecordRenderingStats( 153 command_line->HasSwitch(cc::switches::kEnableGpuBenchmarking)); 154 155 settings.impl_side_painting = IsUIImplSidePaintingEnabled(); 156 settings.use_zero_copy = IsUIZeroCopyEnabled(); 157 158 base::TimeTicks before_create = base::TimeTicks::Now(); 159 if (!!g_compositor_thread) { 160 host_ = cc::LayerTreeHost::CreateThreaded( 161 this, 162 g_context_factory->GetSharedBitmapManager(), 163 settings, 164 g_compositor_thread->message_loop_proxy()); 165 } else { 166 host_ = cc::LayerTreeHost::CreateSingleThreaded( 167 this, this, g_context_factory->GetSharedBitmapManager(), settings); 168 } 169 UMA_HISTOGRAM_TIMES("GPU.CreateBrowserCompositor", 170 base::TimeTicks::Now() - before_create); 171 host_->SetRootLayer(root_web_layer_); 172 host_->SetLayerTreeHostClientReady(); 173} 174 175Compositor::~Compositor() { 176 TRACE_EVENT0("shutdown", "Compositor::destructor"); 177 178 DCHECK(g_compositor_initialized); 179 180 CancelCompositorLock(); 181 DCHECK(!compositor_lock_); 182 183 if (root_layer_) 184 root_layer_->SetCompositor(NULL); 185 186 // Stop all outstanding draws before telling the ContextFactory to tear 187 // down any contexts that the |host_| may rely upon. 188 host_.reset(); 189 190 ContextFactory::GetInstance()->RemoveCompositor(this); 191} 192 193// static 194void Compositor::Initialize() { 195#if defined(OS_CHROMEOS) 196 bool use_thread = !CommandLine::ForCurrentProcess()->HasSwitch( 197 switches::kUIDisableThreadedCompositing); 198#else 199 bool use_thread = false; 200#endif 201 if (use_thread) { 202 g_compositor_thread = new base::Thread("Browser Compositor"); 203 g_compositor_thread->Start(); 204 } 205 206 DCHECK(!g_compositor_initialized) << "Compositor initialized twice."; 207 g_compositor_initialized = true; 208} 209 210// static 211bool Compositor::WasInitializedWithThread() { 212 DCHECK(g_compositor_initialized); 213 return !!g_compositor_thread; 214} 215 216// static 217scoped_refptr<base::MessageLoopProxy> Compositor::GetCompositorMessageLoop() { 218 scoped_refptr<base::MessageLoopProxy> proxy; 219 if (g_compositor_thread) 220 proxy = g_compositor_thread->message_loop_proxy(); 221 return proxy; 222} 223 224// static 225void Compositor::Terminate() { 226 if (g_compositor_thread) { 227 g_compositor_thread->Stop(); 228 delete g_compositor_thread; 229 g_compositor_thread = NULL; 230 } 231 232 DCHECK(g_compositor_initialized) << "Compositor::Initialize() didn't happen."; 233 g_compositor_initialized = false; 234} 235 236void Compositor::ScheduleDraw() { 237 if (g_compositor_thread) { 238 host_->Composite(gfx::FrameTime::Now()); 239 } else if (!defer_draw_scheduling_) { 240 defer_draw_scheduling_ = true; 241 base::MessageLoop::current()->PostTask( 242 FROM_HERE, 243 base::Bind(&Compositor::Draw, schedule_draw_factory_.GetWeakPtr())); 244 } 245} 246 247void Compositor::SetRootLayer(Layer* root_layer) { 248 if (root_layer_ == root_layer) 249 return; 250 if (root_layer_) 251 root_layer_->SetCompositor(NULL); 252 root_layer_ = root_layer; 253 if (root_layer_ && !root_layer_->GetCompositor()) 254 root_layer_->SetCompositor(this); 255 root_web_layer_->RemoveAllChildren(); 256 if (root_layer_) 257 root_web_layer_->AddChild(root_layer_->cc_layer()); 258} 259 260void Compositor::SetHostHasTransparentBackground( 261 bool host_has_transparent_background) { 262 host_->set_has_transparent_background(host_has_transparent_background); 263} 264 265void Compositor::Draw() { 266 DCHECK(!g_compositor_thread); 267 268 defer_draw_scheduling_ = false; 269 if (waiting_on_compositing_end_) { 270 draw_on_compositing_end_ = true; 271 return; 272 } 273 waiting_on_compositing_end_ = true; 274 275 TRACE_EVENT_ASYNC_BEGIN0("ui", "Compositor::Draw", last_started_frame_ + 1); 276 277 if (!root_layer_) 278 return; 279 280 DCHECK_NE(swap_state_, SWAP_POSTED); 281 swap_state_ = SWAP_NONE; 282 283 last_started_frame_++; 284 if (!IsLocked()) { 285 // TODO(nduca): Temporary while compositor calls 286 // compositeImmediately() directly. 287 Layout(); 288 host_->Composite(gfx::FrameTime::Now()); 289 290#if defined(OS_WIN) 291 // While we resize, we are usually a few frames behind. By blocking 292 // the UI thread here we minize the area that is mis-painted, specially 293 // in the non-client area. See RenderWidgetHostViewAura::SetBounds for 294 // more details and bug 177115. 295 if (next_draw_is_resize_ && (last_ended_frame_ > 1)) { 296 next_draw_is_resize_ = false; 297 host_->FinishAllRendering(); 298 } 299#endif 300 301 } 302 if (swap_state_ == SWAP_NONE) 303 NotifyEnd(); 304} 305 306void Compositor::ScheduleFullRedraw() { 307 host_->SetNeedsRedraw(); 308} 309 310void Compositor::ScheduleRedrawRect(const gfx::Rect& damage_rect) { 311 host_->SetNeedsRedrawRect(damage_rect); 312} 313 314void Compositor::SetLatencyInfo(const ui::LatencyInfo& latency_info) { 315 scoped_ptr<cc::SwapPromise> swap_promise( 316 new cc::LatencyInfoSwapPromise(latency_info)); 317 host_->QueueSwapPromise(swap_promise.Pass()); 318} 319 320void Compositor::SetScaleAndSize(float scale, const gfx::Size& size_in_pixel) { 321 DCHECK_GT(scale, 0); 322 if (!size_in_pixel.IsEmpty()) { 323 size_ = size_in_pixel; 324 host_->SetViewportSize(size_in_pixel); 325 root_web_layer_->SetBounds(size_in_pixel); 326 327 next_draw_is_resize_ = true; 328 } 329 if (device_scale_factor_ != scale) { 330 device_scale_factor_ = scale; 331 if (root_layer_) 332 root_layer_->OnDeviceScaleFactorChanged(scale); 333 } 334} 335 336void Compositor::SetBackgroundColor(SkColor color) { 337 host_->set_background_color(color); 338 ScheduleDraw(); 339} 340 341scoped_refptr<CompositorVSyncManager> Compositor::vsync_manager() const { 342 return vsync_manager_; 343} 344 345void Compositor::AddObserver(CompositorObserver* observer) { 346 observer_list_.AddObserver(observer); 347} 348 349void Compositor::RemoveObserver(CompositorObserver* observer) { 350 observer_list_.RemoveObserver(observer); 351} 352 353bool Compositor::HasObserver(CompositorObserver* observer) { 354 return observer_list_.HasObserver(observer); 355} 356 357void Compositor::Layout() { 358 // We're sending damage that will be addressed during this composite 359 // cycle, so we don't need to schedule another composite to address it. 360 disable_schedule_composite_ = true; 361 if (root_layer_) 362 root_layer_->SendDamagedRects(); 363 disable_schedule_composite_ = false; 364} 365 366scoped_ptr<cc::OutputSurface> Compositor::CreateOutputSurface(bool fallback) { 367 return ContextFactory::GetInstance()->CreateOutputSurface(this, fallback); 368} 369 370void Compositor::DidCommit() { 371 DCHECK(!IsLocked()); 372 FOR_EACH_OBSERVER(CompositorObserver, 373 observer_list_, 374 OnCompositingDidCommit(this)); 375} 376 377void Compositor::DidCommitAndDrawFrame() { 378 base::TimeTicks start_time = gfx::FrameTime::Now(); 379 FOR_EACH_OBSERVER(CompositorObserver, 380 observer_list_, 381 OnCompositingStarted(this, start_time)); 382} 383 384void Compositor::DidCompleteSwapBuffers() { 385 if (g_compositor_thread) { 386 NotifyEnd(); 387 } else { 388 DCHECK_EQ(swap_state_, SWAP_POSTED); 389 NotifyEnd(); 390 swap_state_ = SWAP_COMPLETED; 391 } 392} 393 394void Compositor::ScheduleComposite() { 395 if (!disable_schedule_composite_) 396 ScheduleDraw(); 397} 398 399void Compositor::ScheduleAnimation() { 400 ScheduleComposite(); 401} 402 403void Compositor::DidPostSwapBuffers() { 404 DCHECK(!g_compositor_thread); 405 DCHECK_EQ(swap_state_, SWAP_NONE); 406 swap_state_ = SWAP_POSTED; 407} 408 409void Compositor::DidAbortSwapBuffers() { 410 if (!g_compositor_thread) { 411 if (swap_state_ == SWAP_POSTED) { 412 NotifyEnd(); 413 swap_state_ = SWAP_COMPLETED; 414 } 415 } 416 417 FOR_EACH_OBSERVER(CompositorObserver, 418 observer_list_, 419 OnCompositingAborted(this)); 420} 421 422const cc::LayerTreeDebugState& Compositor::GetLayerTreeDebugState() const { 423 return host_->debug_state(); 424} 425 426void Compositor::SetLayerTreeDebugState( 427 const cc::LayerTreeDebugState& debug_state) { 428 host_->SetDebugState(debug_state); 429} 430 431scoped_refptr<CompositorLock> Compositor::GetCompositorLock() { 432 if (!compositor_lock_) { 433 compositor_lock_ = new CompositorLock(this); 434 if (g_compositor_thread) 435 host_->SetDeferCommits(true); 436 FOR_EACH_OBSERVER(CompositorObserver, 437 observer_list_, 438 OnCompositingLockStateChanged(this)); 439 } 440 return compositor_lock_; 441} 442 443void Compositor::UnlockCompositor() { 444 DCHECK(compositor_lock_); 445 compositor_lock_ = NULL; 446 if (g_compositor_thread) 447 host_->SetDeferCommits(false); 448 FOR_EACH_OBSERVER(CompositorObserver, 449 observer_list_, 450 OnCompositingLockStateChanged(this)); 451} 452 453void Compositor::CancelCompositorLock() { 454 if (compositor_lock_) 455 compositor_lock_->CancelLock(); 456} 457 458void Compositor::NotifyEnd() { 459 last_ended_frame_++; 460 TRACE_EVENT_ASYNC_END0("ui", "Compositor::Draw", last_ended_frame_); 461 waiting_on_compositing_end_ = false; 462 if (draw_on_compositing_end_) { 463 draw_on_compositing_end_ = false; 464 465 // Call ScheduleDraw() instead of Draw() in order to allow other 466 // CompositorObservers to be notified before starting another 467 // draw cycle. 468 ScheduleDraw(); 469 } 470 FOR_EACH_OBSERVER(CompositorObserver, 471 observer_list_, 472 OnCompositingEnded(this)); 473} 474 475} // namespace ui 476