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/memory/singleton.h" 14 #include "base/message_loop/message_loop.h" 15 #include "base/metrics/histogram.h" 16 #include "base/run_loop.h" 17 #include "base/strings/string_util.h" 18 #include "base/sys_info.h" 19 #include "base/threading/thread.h" 20 #include "base/threading/thread_restrictions.h" 21 #include "cc/base/latency_info_swap_promise.h" 22 #include "cc/base/switches.h" 23 #include "cc/input/input_handler.h" 24 #include "cc/layers/layer.h" 25 #include "cc/output/context_provider.h" 26 #include "cc/trees/layer_tree_host.h" 27 #include "third_party/skia/include/core/SkBitmap.h" 28 #include "ui/compositor/compositor_observer.h" 29 #include "ui/compositor/compositor_switches.h" 30 #include "ui/compositor/dip_util.h" 31 #include "ui/compositor/layer.h" 32 #include "ui/gfx/frame_time.h" 33 #include "ui/gl/gl_context.h" 34 #include "ui/gl/gl_switches.h" 35 36 namespace { 37 38 const double kDefaultRefreshRate = 60.0; 39 const double kTestRefreshRate = 200.0; 40 41 enum SwapType { 42 DRAW_SWAP, 43 READPIXELS_SWAP, 44 }; 45 46 bool g_compositor_initialized = false; 47 base::Thread* g_compositor_thread = NULL; 48 49 ui::ContextFactory* g_context_factory = NULL; 50 51 const int kCompositorLockTimeoutMs = 67; 52 53 class PendingSwap { 54 public: 55 PendingSwap(SwapType type, ui::PostedSwapQueue* posted_swaps); 56 ~PendingSwap(); 57 58 SwapType type() const { return type_; } 59 bool posted() const { return posted_; } 60 61 private: 62 friend class ui::PostedSwapQueue; 63 64 SwapType type_; 65 bool posted_; 66 ui::PostedSwapQueue* posted_swaps_; 67 68 DISALLOW_COPY_AND_ASSIGN(PendingSwap); 69 }; 70 71 } // namespace 72 73 namespace ui { 74 75 // static 76 ContextFactory* ContextFactory::GetInstance() { 77 DCHECK(g_context_factory); 78 return g_context_factory; 79 } 80 81 // static 82 void ContextFactory::SetInstance(ContextFactory* instance) { 83 g_context_factory = instance; 84 } 85 86 Texture::Texture(bool flipped, const gfx::Size& size, float device_scale_factor) 87 : size_(size), 88 flipped_(flipped), 89 device_scale_factor_(device_scale_factor) { 90 } 91 92 Texture::~Texture() { 93 } 94 95 std::string Texture::Produce() { 96 return std::string(); 97 } 98 99 CompositorLock::CompositorLock(Compositor* compositor) 100 : compositor_(compositor) { 101 base::MessageLoop::current()->PostDelayedTask( 102 FROM_HERE, 103 base::Bind(&CompositorLock::CancelLock, AsWeakPtr()), 104 base::TimeDelta::FromMilliseconds(kCompositorLockTimeoutMs)); 105 } 106 107 CompositorLock::~CompositorLock() { 108 CancelLock(); 109 } 110 111 void CompositorLock::CancelLock() { 112 if (!compositor_) 113 return; 114 compositor_->UnlockCompositor(); 115 compositor_ = NULL; 116 } 117 118 // static 119 void DrawWaiterForTest::Wait(Compositor* compositor) { 120 DrawWaiterForTest waiter; 121 waiter.wait_for_commit_ = false; 122 waiter.WaitImpl(compositor); 123 } 124 125 // static 126 void DrawWaiterForTest::WaitForCommit(Compositor* compositor) { 127 DrawWaiterForTest waiter; 128 waiter.wait_for_commit_ = true; 129 waiter.WaitImpl(compositor); 130 } 131 132 DrawWaiterForTest::DrawWaiterForTest() { 133 } 134 135 DrawWaiterForTest::~DrawWaiterForTest() { 136 } 137 138 void DrawWaiterForTest::WaitImpl(Compositor* compositor) { 139 compositor->AddObserver(this); 140 wait_run_loop_.reset(new base::RunLoop()); 141 wait_run_loop_->Run(); 142 compositor->RemoveObserver(this); 143 } 144 145 void DrawWaiterForTest::OnCompositingDidCommit(Compositor* compositor) { 146 if (wait_for_commit_) 147 wait_run_loop_->Quit(); 148 } 149 150 void DrawWaiterForTest::OnCompositingStarted(Compositor* compositor, 151 base::TimeTicks start_time) { 152 } 153 154 void DrawWaiterForTest::OnCompositingEnded(Compositor* compositor) { 155 if (!wait_for_commit_) 156 wait_run_loop_->Quit(); 157 } 158 159 void DrawWaiterForTest::OnCompositingAborted(Compositor* compositor) { 160 } 161 162 void DrawWaiterForTest::OnCompositingLockStateChanged(Compositor* compositor) { 163 } 164 165 void DrawWaiterForTest::OnUpdateVSyncParameters(Compositor* compositor, 166 base::TimeTicks timebase, 167 base::TimeDelta interval) { 168 } 169 170 class PostedSwapQueue { 171 public: 172 PostedSwapQueue() : pending_swap_(NULL) { 173 } 174 175 ~PostedSwapQueue() { 176 DCHECK(!pending_swap_); 177 } 178 179 SwapType NextPostedSwap() const { 180 return queue_.front(); 181 } 182 183 bool AreSwapsPosted() const { 184 return !queue_.empty(); 185 } 186 187 int NumSwapsPosted(SwapType type) const { 188 int count = 0; 189 for (std::deque<SwapType>::const_iterator it = queue_.begin(); 190 it != queue_.end(); ++it) { 191 if (*it == type) 192 count++; 193 } 194 return count; 195 } 196 197 void PostSwap() { 198 DCHECK(pending_swap_); 199 queue_.push_back(pending_swap_->type()); 200 pending_swap_->posted_ = true; 201 } 202 203 void EndSwap() { 204 queue_.pop_front(); 205 } 206 207 private: 208 friend class ::PendingSwap; 209 210 PendingSwap* pending_swap_; 211 std::deque<SwapType> queue_; 212 213 DISALLOW_COPY_AND_ASSIGN(PostedSwapQueue); 214 }; 215 216 } // namespace ui 217 218 namespace { 219 220 PendingSwap::PendingSwap(SwapType type, ui::PostedSwapQueue* posted_swaps) 221 : type_(type), posted_(false), posted_swaps_(posted_swaps) { 222 // Only one pending swap in flight. 223 DCHECK_EQ(static_cast<PendingSwap*>(NULL), posted_swaps_->pending_swap_); 224 posted_swaps_->pending_swap_ = this; 225 } 226 227 PendingSwap::~PendingSwap() { 228 DCHECK_EQ(this, posted_swaps_->pending_swap_); 229 posted_swaps_->pending_swap_ = NULL; 230 } 231 232 } // namespace 233 234 namespace ui { 235 236 Compositor::Compositor(gfx::AcceleratedWidget widget) 237 : root_layer_(NULL), 238 widget_(widget), 239 posted_swaps_(new PostedSwapQueue()), 240 device_scale_factor_(0.0f), 241 last_started_frame_(0), 242 last_ended_frame_(0), 243 next_draw_is_resize_(false), 244 disable_schedule_composite_(false), 245 compositor_lock_(NULL), 246 defer_draw_scheduling_(false), 247 waiting_on_compositing_end_(false), 248 draw_on_compositing_end_(false), 249 schedule_draw_factory_(this) { 250 DCHECK(g_compositor_initialized) 251 << "Compositor::Initialize must be called before creating a Compositor."; 252 253 root_web_layer_ = cc::Layer::Create(); 254 root_web_layer_->SetAnchorPoint(gfx::PointF(0.f, 0.f)); 255 256 CommandLine* command_line = CommandLine::ForCurrentProcess(); 257 258 cc::LayerTreeSettings settings; 259 settings.refresh_rate = 260 ContextFactory::GetInstance()->DoesCreateTestContexts() 261 ? kTestRefreshRate 262 : kDefaultRefreshRate; 263 settings.deadline_scheduling_enabled = 264 switches::IsUIDeadlineSchedulingEnabled(); 265 settings.partial_swap_enabled = 266 !command_line->HasSwitch(cc::switches::kUIDisablePartialSwap); 267 settings.per_tile_painting_enabled = 268 command_line->HasSwitch(cc::switches::kUIEnablePerTilePainting); 269 270 // These flags should be mirrored by renderer versions in content/renderer/. 271 settings.initial_debug_state.show_debug_borders = 272 command_line->HasSwitch(cc::switches::kUIShowCompositedLayerBorders); 273 settings.initial_debug_state.show_fps_counter = 274 command_line->HasSwitch(cc::switches::kUIShowFPSCounter); 275 settings.initial_debug_state.show_layer_animation_bounds_rects = 276 command_line->HasSwitch(cc::switches::kUIShowLayerAnimationBounds); 277 settings.initial_debug_state.show_paint_rects = 278 command_line->HasSwitch(switches::kUIShowPaintRects); 279 settings.initial_debug_state.show_property_changed_rects = 280 command_line->HasSwitch(cc::switches::kUIShowPropertyChangedRects); 281 settings.initial_debug_state.show_surface_damage_rects = 282 command_line->HasSwitch(cc::switches::kUIShowSurfaceDamageRects); 283 settings.initial_debug_state.show_screen_space_rects = 284 command_line->HasSwitch(cc::switches::kUIShowScreenSpaceRects); 285 settings.initial_debug_state.show_replica_screen_space_rects = 286 command_line->HasSwitch(cc::switches::kUIShowReplicaScreenSpaceRects); 287 settings.initial_debug_state.show_occluding_rects = 288 command_line->HasSwitch(cc::switches::kUIShowOccludingRects); 289 settings.initial_debug_state.show_non_occluding_rects = 290 command_line->HasSwitch(cc::switches::kUIShowNonOccludingRects); 291 292 base::TimeTicks before_create = base::TimeTicks::Now(); 293 if (!!g_compositor_thread) { 294 host_ = cc::LayerTreeHost::CreateThreaded( 295 this, NULL, settings, g_compositor_thread->message_loop_proxy()); 296 } else { 297 host_ = cc::LayerTreeHost::CreateSingleThreaded(this, this, NULL, settings); 298 } 299 UMA_HISTOGRAM_TIMES("GPU.CreateBrowserCompositor", 300 base::TimeTicks::Now() - before_create); 301 host_->SetRootLayer(root_web_layer_); 302 host_->SetLayerTreeHostClientReady(); 303 } 304 305 Compositor::~Compositor() { 306 TRACE_EVENT0("shutdown", "Compositor::destructor"); 307 308 DCHECK(g_compositor_initialized); 309 310 CancelCompositorLock(); 311 DCHECK(!compositor_lock_); 312 313 if (root_layer_) 314 root_layer_->SetCompositor(NULL); 315 316 // Stop all outstanding draws before telling the ContextFactory to tear 317 // down any contexts that the |host_| may rely upon. 318 host_.reset(); 319 320 ContextFactory::GetInstance()->RemoveCompositor(this); 321 } 322 323 // static 324 void Compositor::Initialize() { 325 #if defined(OS_CHROMEOS) 326 bool use_thread = !CommandLine::ForCurrentProcess()->HasSwitch( 327 switches::kUIDisableThreadedCompositing); 328 #else 329 bool use_thread = 330 CommandLine::ForCurrentProcess()->HasSwitch( 331 switches::kUIEnableThreadedCompositing) && 332 !CommandLine::ForCurrentProcess()->HasSwitch( 333 switches::kUIDisableThreadedCompositing); 334 #endif 335 if (use_thread) { 336 g_compositor_thread = new base::Thread("Browser Compositor"); 337 g_compositor_thread->Start(); 338 } 339 340 DCHECK(!g_compositor_initialized) << "Compositor initialized twice."; 341 g_compositor_initialized = true; 342 } 343 344 // static 345 bool Compositor::WasInitializedWithThread() { 346 DCHECK(g_compositor_initialized); 347 return !!g_compositor_thread; 348 } 349 350 // static 351 scoped_refptr<base::MessageLoopProxy> Compositor::GetCompositorMessageLoop() { 352 scoped_refptr<base::MessageLoopProxy> proxy; 353 if (g_compositor_thread) 354 proxy = g_compositor_thread->message_loop_proxy(); 355 return proxy; 356 } 357 358 // static 359 void Compositor::Terminate() { 360 if (g_compositor_thread) { 361 g_compositor_thread->Stop(); 362 delete g_compositor_thread; 363 g_compositor_thread = NULL; 364 } 365 366 DCHECK(g_compositor_initialized) << "Compositor::Initialize() didn't happen."; 367 g_compositor_initialized = false; 368 } 369 370 void Compositor::ScheduleDraw() { 371 if (g_compositor_thread) { 372 host_->Composite(gfx::FrameTime::Now()); 373 } else if (!defer_draw_scheduling_) { 374 defer_draw_scheduling_ = true; 375 base::MessageLoop::current()->PostTask( 376 FROM_HERE, 377 base::Bind(&Compositor::Draw, schedule_draw_factory_.GetWeakPtr())); 378 } 379 } 380 381 void Compositor::SetRootLayer(Layer* root_layer) { 382 if (root_layer_ == root_layer) 383 return; 384 if (root_layer_) 385 root_layer_->SetCompositor(NULL); 386 root_layer_ = root_layer; 387 if (root_layer_ && !root_layer_->GetCompositor()) 388 root_layer_->SetCompositor(this); 389 root_web_layer_->RemoveAllChildren(); 390 if (root_layer_) 391 root_web_layer_->AddChild(root_layer_->cc_layer()); 392 } 393 394 void Compositor::SetHostHasTransparentBackground( 395 bool host_has_transparent_background) { 396 host_->set_has_transparent_background(host_has_transparent_background); 397 } 398 399 void Compositor::Draw() { 400 DCHECK(!g_compositor_thread); 401 402 defer_draw_scheduling_ = false; 403 if (waiting_on_compositing_end_) { 404 draw_on_compositing_end_ = true; 405 return; 406 } 407 waiting_on_compositing_end_ = true; 408 409 TRACE_EVENT_ASYNC_BEGIN0("ui", "Compositor::Draw", last_started_frame_ + 1); 410 411 if (!root_layer_) 412 return; 413 414 last_started_frame_++; 415 PendingSwap pending_swap(DRAW_SWAP, posted_swaps_.get()); 416 if (!IsLocked()) { 417 // TODO(nduca): Temporary while compositor calls 418 // compositeImmediately() directly. 419 Layout(); 420 host_->Composite(gfx::FrameTime::Now()); 421 422 #if defined(OS_WIN) 423 // While we resize, we are usually a few frames behind. By blocking 424 // the UI thread here we minize the area that is mis-painted, specially 425 // in the non-client area. See RenderWidgetHostViewAura::SetBounds for 426 // more details and bug 177115. 427 if (next_draw_is_resize_ && (last_ended_frame_ > 1)) { 428 next_draw_is_resize_ = false; 429 host_->FinishAllRendering(); 430 } 431 #endif 432 433 } 434 if (!pending_swap.posted()) 435 NotifyEnd(); 436 } 437 438 void Compositor::ScheduleFullRedraw() { 439 host_->SetNeedsRedraw(); 440 } 441 442 void Compositor::ScheduleRedrawRect(const gfx::Rect& damage_rect) { 443 host_->SetNeedsRedrawRect(damage_rect); 444 } 445 446 void Compositor::SetLatencyInfo(const ui::LatencyInfo& latency_info) { 447 scoped_ptr<cc::SwapPromise> swap_promise( 448 new cc::LatencyInfoSwapPromise(latency_info)); 449 host_->QueueSwapPromise(swap_promise.Pass()); 450 } 451 452 bool Compositor::ReadPixels(SkBitmap* bitmap, 453 const gfx::Rect& bounds_in_pixel) { 454 if (bounds_in_pixel.right() > size().width() || 455 bounds_in_pixel.bottom() > size().height()) 456 return false; 457 bitmap->setConfig(SkBitmap::kARGB_8888_Config, 458 bounds_in_pixel.width(), bounds_in_pixel.height()); 459 bitmap->allocPixels(); 460 SkAutoLockPixels lock_image(*bitmap); 461 unsigned char* pixels = static_cast<unsigned char*>(bitmap->getPixels()); 462 CancelCompositorLock(); 463 PendingSwap pending_swap(READPIXELS_SWAP, posted_swaps_.get()); 464 return host_->CompositeAndReadback(pixels, bounds_in_pixel); 465 } 466 467 void Compositor::SetScaleAndSize(float scale, const gfx::Size& size_in_pixel) { 468 DCHECK_GT(scale, 0); 469 if (!size_in_pixel.IsEmpty()) { 470 size_ = size_in_pixel; 471 host_->SetViewportSize(size_in_pixel); 472 root_web_layer_->SetBounds(size_in_pixel); 473 474 next_draw_is_resize_ = true; 475 } 476 if (device_scale_factor_ != scale) { 477 device_scale_factor_ = scale; 478 if (root_layer_) 479 root_layer_->OnDeviceScaleFactorChanged(scale); 480 } 481 } 482 483 void Compositor::SetBackgroundColor(SkColor color) { 484 host_->set_background_color(color); 485 ScheduleDraw(); 486 } 487 488 void Compositor::AddObserver(CompositorObserver* observer) { 489 observer_list_.AddObserver(observer); 490 } 491 492 void Compositor::RemoveObserver(CompositorObserver* observer) { 493 observer_list_.RemoveObserver(observer); 494 } 495 496 bool Compositor::HasObserver(CompositorObserver* observer) { 497 return observer_list_.HasObserver(observer); 498 } 499 500 void Compositor::OnUpdateVSyncParameters(base::TimeTicks timebase, 501 base::TimeDelta interval) { 502 FOR_EACH_OBSERVER(CompositorObserver, 503 observer_list_, 504 OnUpdateVSyncParameters(this, timebase, interval)); 505 } 506 507 void Compositor::Layout() { 508 // We're sending damage that will be addressed during this composite 509 // cycle, so we don't need to schedule another composite to address it. 510 disable_schedule_composite_ = true; 511 if (root_layer_) 512 root_layer_->SendDamagedRects(); 513 disable_schedule_composite_ = false; 514 } 515 516 scoped_ptr<cc::OutputSurface> Compositor::CreateOutputSurface(bool fallback) { 517 return ContextFactory::GetInstance()->CreateOutputSurface(this, fallback); 518 } 519 520 void Compositor::DidCommit() { 521 DCHECK(!IsLocked()); 522 FOR_EACH_OBSERVER(CompositorObserver, 523 observer_list_, 524 OnCompositingDidCommit(this)); 525 } 526 527 void Compositor::DidCommitAndDrawFrame() { 528 base::TimeTicks start_time = gfx::FrameTime::Now(); 529 FOR_EACH_OBSERVER(CompositorObserver, 530 observer_list_, 531 OnCompositingStarted(this, start_time)); 532 } 533 534 void Compositor::DidCompleteSwapBuffers() { 535 if (g_compositor_thread) { 536 NotifyEnd(); 537 } else { 538 DCHECK(posted_swaps_->AreSwapsPosted()); 539 DCHECK_GE(1, posted_swaps_->NumSwapsPosted(DRAW_SWAP)); 540 if (posted_swaps_->NextPostedSwap() == DRAW_SWAP) 541 NotifyEnd(); 542 posted_swaps_->EndSwap(); 543 } 544 } 545 546 scoped_refptr<cc::ContextProvider> Compositor::OffscreenContextProvider() { 547 return ContextFactory::GetInstance()->OffscreenCompositorContextProvider(); 548 } 549 550 void Compositor::ScheduleComposite() { 551 if (!disable_schedule_composite_) 552 ScheduleDraw(); 553 } 554 555 void Compositor::ScheduleAnimation() { 556 ScheduleComposite(); 557 } 558 559 void Compositor::DidPostSwapBuffers() { 560 DCHECK(!g_compositor_thread); 561 posted_swaps_->PostSwap(); 562 } 563 564 void Compositor::DidAbortSwapBuffers() { 565 if (!g_compositor_thread) { 566 DCHECK_GE(1, posted_swaps_->NumSwapsPosted(DRAW_SWAP)); 567 568 // We've just lost the context, so unwind all posted_swaps. 569 while (posted_swaps_->AreSwapsPosted()) { 570 if (posted_swaps_->NextPostedSwap() == DRAW_SWAP) 571 NotifyEnd(); 572 posted_swaps_->EndSwap(); 573 } 574 } 575 576 FOR_EACH_OBSERVER(CompositorObserver, 577 observer_list_, 578 OnCompositingAborted(this)); 579 } 580 581 const cc::LayerTreeDebugState& Compositor::GetLayerTreeDebugState() const { 582 return host_->debug_state(); 583 } 584 585 void Compositor::SetLayerTreeDebugState( 586 const cc::LayerTreeDebugState& debug_state) { 587 host_->SetDebugState(debug_state); 588 } 589 590 scoped_refptr<CompositorLock> Compositor::GetCompositorLock() { 591 if (!compositor_lock_) { 592 compositor_lock_ = new CompositorLock(this); 593 if (g_compositor_thread) 594 host_->SetDeferCommits(true); 595 FOR_EACH_OBSERVER(CompositorObserver, 596 observer_list_, 597 OnCompositingLockStateChanged(this)); 598 } 599 return compositor_lock_; 600 } 601 602 void Compositor::UnlockCompositor() { 603 DCHECK(compositor_lock_); 604 compositor_lock_ = NULL; 605 if (g_compositor_thread) 606 host_->SetDeferCommits(false); 607 FOR_EACH_OBSERVER(CompositorObserver, 608 observer_list_, 609 OnCompositingLockStateChanged(this)); 610 } 611 612 void Compositor::CancelCompositorLock() { 613 if (compositor_lock_) 614 compositor_lock_->CancelLock(); 615 } 616 617 void Compositor::NotifyEnd() { 618 last_ended_frame_++; 619 TRACE_EVENT_ASYNC_END0("ui", "Compositor::Draw", last_ended_frame_); 620 waiting_on_compositing_end_ = false; 621 if (draw_on_compositing_end_) { 622 draw_on_compositing_end_ = false; 623 624 // Call ScheduleDraw() instead of Draw() in order to allow other 625 // CompositorObservers to be notified before starting another 626 // draw cycle. 627 ScheduleDraw(); 628 } 629 FOR_EACH_OBSERVER(CompositorObserver, 630 observer_list_, 631 OnCompositingEnded(this)); 632 } 633 634 } // namespace ui 635