compositor.cc revision d0247b1b59f9c528cb6df88b4f2b9afaf80d181e
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/run_loop.h" 16#include "base/strings/string_util.h" 17#include "base/threading/thread.h" 18#include "base/threading/thread_restrictions.h" 19#include "cc/base/switches.h" 20#include "cc/debug/test_context_provider.h" 21#include "cc/debug/test_web_graphics_context_3d.h" 22#include "cc/input/input_handler.h" 23#include "cc/layers/layer.h" 24#include "cc/output/context_provider.h" 25#include "cc/output/output_surface.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/compositor/reflector.h" 33#include "ui/gl/gl_context.h" 34#include "ui/gl/gl_implementation.h" 35#include "ui/gl/gl_surface.h" 36#include "ui/gl/gl_switches.h" 37#include "webkit/common/gpu/context_provider_in_process.h" 38#include "webkit/common/gpu/grcontext_for_webgraphicscontext3d.h" 39#include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h" 40 41#if defined(OS_CHROMEOS) 42#include "base/chromeos/chromeos_version.h" 43#endif 44 45namespace { 46 47const double kDefaultRefreshRate = 60.0; 48const double kTestRefreshRate = 200.0; 49 50enum SwapType { 51 DRAW_SWAP, 52 READPIXELS_SWAP, 53}; 54 55bool g_compositor_initialized = false; 56base::Thread* g_compositor_thread = NULL; 57 58ui::ContextFactory* g_implicit_factory = NULL; 59ui::ContextFactory* g_context_factory = NULL; 60 61const int kCompositorLockTimeoutMs = 67; 62 63class PendingSwap { 64 public: 65 PendingSwap(SwapType type, ui::PostedSwapQueue* posted_swaps); 66 ~PendingSwap(); 67 68 SwapType type() const { return type_; } 69 bool posted() const { return posted_; } 70 71 private: 72 friend class ui::PostedSwapQueue; 73 74 SwapType type_; 75 bool posted_; 76 ui::PostedSwapQueue* posted_swaps_; 77 78 DISALLOW_COPY_AND_ASSIGN(PendingSwap); 79}; 80 81} // namespace 82 83namespace ui { 84 85// static 86ContextFactory* ContextFactory::GetInstance() { 87 DCHECK(g_context_factory); 88 return g_context_factory; 89} 90 91// static 92void ContextFactory::SetInstance(ContextFactory* instance) { 93 g_context_factory = instance; 94} 95 96DefaultContextFactory::DefaultContextFactory() { 97} 98 99DefaultContextFactory::~DefaultContextFactory() { 100} 101 102bool DefaultContextFactory::Initialize() { 103 if (!gfx::GLSurface::InitializeOneOff() || 104 gfx::GetGLImplementation() == gfx::kGLImplementationNone) { 105 LOG(ERROR) << "Could not load the GL bindings"; 106 return false; 107 } 108 return true; 109} 110 111scoped_ptr<cc::OutputSurface> DefaultContextFactory::CreateOutputSurface( 112 Compositor* compositor) { 113 WebKit::WebGraphicsContext3D::Attributes attrs; 114 attrs.depth = false; 115 attrs.stencil = false; 116 attrs.antialias = false; 117 attrs.shareResources = true; 118 119 using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl; 120 scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> context3d( 121 WebGraphicsContext3DInProcessCommandBufferImpl::CreateViewContext( 122 attrs, compositor->widget())); 123 CHECK(context3d); 124 125 using webkit::gpu::ContextProviderInProcess; 126 scoped_refptr<ContextProviderInProcess> context_provider = 127 ContextProviderInProcess::Create(context3d.Pass(), 128 "UICompositor"); 129 130 return make_scoped_ptr(new cc::OutputSurface(context_provider)); 131} 132 133scoped_refptr<Reflector> DefaultContextFactory::CreateReflector( 134 Compositor* mirroed_compositor, 135 Layer* mirroring_layer) { 136 return NULL; 137} 138 139void DefaultContextFactory::RemoveReflector( 140 scoped_refptr<Reflector> reflector) { 141} 142 143scoped_refptr<cc::ContextProvider> 144DefaultContextFactory::OffscreenContextProviderForMainThread() { 145 if (!offscreen_contexts_main_thread_.get() || 146 !offscreen_contexts_main_thread_->DestroyedOnMainThread()) { 147 offscreen_contexts_main_thread_ = 148 webkit::gpu::ContextProviderInProcess::CreateOffscreen(); 149 if (offscreen_contexts_main_thread_.get() && 150 !offscreen_contexts_main_thread_->BindToCurrentThread()) 151 offscreen_contexts_main_thread_ = NULL; 152 } 153 return offscreen_contexts_main_thread_; 154} 155 156scoped_refptr<cc::ContextProvider> 157DefaultContextFactory::OffscreenContextProviderForCompositorThread() { 158 if (!offscreen_contexts_compositor_thread_.get() || 159 !offscreen_contexts_compositor_thread_->DestroyedOnMainThread()) { 160 offscreen_contexts_compositor_thread_ = 161 webkit::gpu::ContextProviderInProcess::CreateOffscreen(); 162 } 163 return offscreen_contexts_compositor_thread_; 164} 165 166void DefaultContextFactory::RemoveCompositor(Compositor* compositor) { 167} 168 169bool DefaultContextFactory::DoesCreateTestContexts() { return false; } 170 171TestContextFactory::TestContextFactory() {} 172 173TestContextFactory::~TestContextFactory() {} 174 175scoped_ptr<cc::OutputSurface> TestContextFactory::CreateOutputSurface( 176 Compositor* compositor) { 177 return make_scoped_ptr( 178 new cc::OutputSurface(cc::TestContextProvider::Create())); 179} 180 181scoped_refptr<Reflector> TestContextFactory::CreateReflector( 182 Compositor* mirrored_compositor, 183 Layer* mirroring_layer) { 184 return new Reflector(); 185} 186 187void TestContextFactory::RemoveReflector(scoped_refptr<Reflector> reflector) { 188} 189 190scoped_refptr<cc::ContextProvider> 191TestContextFactory::OffscreenContextProviderForMainThread() { 192 if (!offscreen_contexts_main_thread_.get() || 193 offscreen_contexts_main_thread_->DestroyedOnMainThread()) { 194 offscreen_contexts_main_thread_ = cc::TestContextProvider::Create(); 195 CHECK(offscreen_contexts_main_thread_->BindToCurrentThread()); 196 } 197 return offscreen_contexts_main_thread_; 198} 199 200scoped_refptr<cc::ContextProvider> 201TestContextFactory::OffscreenContextProviderForCompositorThread() { 202 if (!offscreen_contexts_compositor_thread_.get() || 203 offscreen_contexts_compositor_thread_->DestroyedOnMainThread()) { 204 offscreen_contexts_compositor_thread_ = cc::TestContextProvider::Create(); 205 } 206 return offscreen_contexts_compositor_thread_; 207} 208 209void TestContextFactory::RemoveCompositor(Compositor* compositor) { 210} 211 212bool TestContextFactory::DoesCreateTestContexts() { return true; } 213 214Texture::Texture(bool flipped, const gfx::Size& size, float device_scale_factor) 215 : size_(size), 216 flipped_(flipped), 217 device_scale_factor_(device_scale_factor) { 218} 219 220Texture::~Texture() { 221} 222 223std::string Texture::Produce() { 224 return EmptyString(); 225} 226 227CompositorLock::CompositorLock(Compositor* compositor) 228 : compositor_(compositor) { 229 base::MessageLoop::current()->PostDelayedTask( 230 FROM_HERE, 231 base::Bind(&CompositorLock::CancelLock, AsWeakPtr()), 232 base::TimeDelta::FromMilliseconds(kCompositorLockTimeoutMs)); 233} 234 235CompositorLock::~CompositorLock() { 236 CancelLock(); 237} 238 239void CompositorLock::CancelLock() { 240 if (!compositor_) 241 return; 242 compositor_->UnlockCompositor(); 243 compositor_ = NULL; 244} 245 246// static 247void DrawWaiterForTest::Wait(Compositor* compositor) { 248 DrawWaiterForTest waiter; 249 waiter.wait_for_commit_ = false; 250 waiter.WaitImpl(compositor); 251} 252 253// static 254void DrawWaiterForTest::WaitForCommit(Compositor* compositor) { 255 DrawWaiterForTest waiter; 256 waiter.wait_for_commit_ = true; 257 waiter.WaitImpl(compositor); 258} 259 260DrawWaiterForTest::DrawWaiterForTest() { 261} 262 263DrawWaiterForTest::~DrawWaiterForTest() { 264} 265 266void DrawWaiterForTest::WaitImpl(Compositor* compositor) { 267 compositor->AddObserver(this); 268 wait_run_loop_.reset(new base::RunLoop()); 269 wait_run_loop_->Run(); 270 compositor->RemoveObserver(this); 271} 272 273void DrawWaiterForTest::OnCompositingDidCommit(Compositor* compositor) { 274 if (wait_for_commit_) 275 wait_run_loop_->Quit(); 276} 277 278void DrawWaiterForTest::OnCompositingStarted(Compositor* compositor, 279 base::TimeTicks start_time) { 280} 281 282void DrawWaiterForTest::OnCompositingEnded(Compositor* compositor) { 283 if (!wait_for_commit_) 284 wait_run_loop_->Quit(); 285} 286 287void DrawWaiterForTest::OnCompositingAborted(Compositor* compositor) { 288} 289 290void DrawWaiterForTest::OnCompositingLockStateChanged(Compositor* compositor) { 291} 292 293void DrawWaiterForTest::OnUpdateVSyncParameters(Compositor* compositor, 294 base::TimeTicks timebase, 295 base::TimeDelta interval) { 296} 297 298class PostedSwapQueue { 299 public: 300 PostedSwapQueue() : pending_swap_(NULL) { 301 } 302 303 ~PostedSwapQueue() { 304 DCHECK(!pending_swap_); 305 } 306 307 SwapType NextPostedSwap() const { 308 return queue_.front(); 309 } 310 311 bool AreSwapsPosted() const { 312 return !queue_.empty(); 313 } 314 315 int NumSwapsPosted(SwapType type) const { 316 int count = 0; 317 for (std::deque<SwapType>::const_iterator it = queue_.begin(); 318 it != queue_.end(); ++it) { 319 if (*it == type) 320 count++; 321 } 322 return count; 323 } 324 325 void PostSwap() { 326 DCHECK(pending_swap_); 327 queue_.push_back(pending_swap_->type()); 328 pending_swap_->posted_ = true; 329 } 330 331 void EndSwap() { 332 queue_.pop_front(); 333 } 334 335 private: 336 friend class ::PendingSwap; 337 338 PendingSwap* pending_swap_; 339 std::deque<SwapType> queue_; 340 341 DISALLOW_COPY_AND_ASSIGN(PostedSwapQueue); 342}; 343 344} // namespace ui 345 346namespace { 347 348PendingSwap::PendingSwap(SwapType type, ui::PostedSwapQueue* posted_swaps) 349 : type_(type), posted_(false), posted_swaps_(posted_swaps) { 350 // Only one pending swap in flight. 351 DCHECK_EQ(static_cast<PendingSwap*>(NULL), posted_swaps_->pending_swap_); 352 posted_swaps_->pending_swap_ = this; 353} 354 355PendingSwap::~PendingSwap() { 356 DCHECK_EQ(this, posted_swaps_->pending_swap_); 357 posted_swaps_->pending_swap_ = NULL; 358} 359 360} // namespace 361 362namespace ui { 363 364Compositor::Compositor(CompositorDelegate* delegate, 365 gfx::AcceleratedWidget widget) 366 : delegate_(delegate), 367 root_layer_(NULL), 368 widget_(widget), 369 posted_swaps_(new PostedSwapQueue()), 370 device_scale_factor_(0.0f), 371 last_started_frame_(0), 372 last_ended_frame_(0), 373 next_draw_is_resize_(false), 374 disable_schedule_composite_(false), 375 compositor_lock_(NULL) { 376 DCHECK(g_compositor_initialized) 377 << "Compositor::Initialize must be called before creating a Compositor."; 378 379 root_web_layer_ = cc::Layer::Create(); 380 root_web_layer_->SetAnchorPoint(gfx::PointF(0.f, 0.f)); 381 382 CommandLine* command_line = CommandLine::ForCurrentProcess(); 383 384 cc::LayerTreeSettings settings; 385 settings.refresh_rate = 386 ContextFactory::GetInstance()->DoesCreateTestContexts() 387 ? kTestRefreshRate 388 : kDefaultRefreshRate; 389 settings.partial_swap_enabled = 390 !command_line->HasSwitch(cc::switches::kUIDisablePartialSwap); 391 settings.per_tile_painting_enabled = 392 command_line->HasSwitch(cc::switches::kUIEnablePerTilePainting); 393 394 // These flags should be mirrored by renderer versions in content/renderer/. 395 settings.initial_debug_state.show_debug_borders = 396 command_line->HasSwitch(cc::switches::kUIShowCompositedLayerBorders); 397 settings.initial_debug_state.show_fps_counter = 398 command_line->HasSwitch(cc::switches::kUIShowFPSCounter); 399 settings.initial_debug_state.show_paint_rects = 400 command_line->HasSwitch(switches::kUIShowPaintRects); 401 settings.initial_debug_state.show_property_changed_rects = 402 command_line->HasSwitch(cc::switches::kUIShowPropertyChangedRects); 403 settings.initial_debug_state.show_surface_damage_rects = 404 command_line->HasSwitch(cc::switches::kUIShowSurfaceDamageRects); 405 settings.initial_debug_state.show_screen_space_rects = 406 command_line->HasSwitch(cc::switches::kUIShowScreenSpaceRects); 407 settings.initial_debug_state.show_replica_screen_space_rects = 408 command_line->HasSwitch(cc::switches::kUIShowReplicaScreenSpaceRects); 409 settings.initial_debug_state.show_occluding_rects = 410 command_line->HasSwitch(cc::switches::kUIShowOccludingRects); 411 settings.initial_debug_state.show_non_occluding_rects = 412 command_line->HasSwitch(cc::switches::kUIShowNonOccludingRects); 413 414 scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner = 415 g_compositor_thread ? g_compositor_thread->message_loop_proxy() : NULL; 416 417 host_ = cc::LayerTreeHost::Create(this, settings, compositor_task_runner); 418 host_->SetRootLayer(root_web_layer_); 419 host_->SetLayerTreeHostClientReady(); 420} 421 422Compositor::~Compositor() { 423 TRACE_EVENT0("shutdown", "Compositor::destructor"); 424 425 DCHECK(g_compositor_initialized); 426 427 CancelCompositorLock(); 428 DCHECK(!compositor_lock_); 429 430 // Don't call |CompositorDelegate::ScheduleDraw| from this point. 431 delegate_ = NULL; 432 if (root_layer_) 433 root_layer_->SetCompositor(NULL); 434 435 // Stop all outstanding draws before telling the ContextFactory to tear 436 // down any contexts that the |host_| may rely upon. 437 host_.reset(); 438 439 ContextFactory::GetInstance()->RemoveCompositor(this); 440} 441 442// static 443void Compositor::InitializeContextFactoryForTests(bool allow_test_contexts) { 444 // The factory may already have been initialized by the content layer, in 445 // which case, use that one. 446 if (g_context_factory) 447 return; 448 DCHECK(!g_implicit_factory) << 449 "ContextFactory for tests already initialized."; 450 451 bool use_test_contexts = true; 452 453 // Always use test contexts unless the disable command line flag is used. 454 CommandLine* command_line = CommandLine::ForCurrentProcess(); 455 if (command_line->HasSwitch(switches::kDisableTestCompositor)) 456 use_test_contexts = false; 457 458#if defined(OS_CHROMEOS) 459 // If the test is running on the chromeos envrionment (such as 460 // device or vm bots), always use real contexts. 461 if (base::chromeos::IsRunningOnChromeOS()) 462 use_test_contexts = false; 463#endif 464 465 if (!allow_test_contexts) 466 use_test_contexts = false; 467 468 if (use_test_contexts) { 469 g_implicit_factory = new ui::TestContextFactory; 470 } else { 471 DVLOG(1) << "Using DefaultContextFactory"; 472 scoped_ptr<ui::DefaultContextFactory> instance( 473 new ui::DefaultContextFactory()); 474 if (instance->Initialize()) 475 g_implicit_factory = instance.release(); 476 } 477 g_context_factory = g_implicit_factory; 478} 479 480// static 481void Compositor::Initialize() { 482#if defined(OS_CHROMEOS) 483 bool use_thread = !CommandLine::ForCurrentProcess()->HasSwitch( 484 switches::kUIDisableThreadedCompositing); 485#else 486 bool use_thread = 487 CommandLine::ForCurrentProcess()->HasSwitch( 488 switches::kUIEnableThreadedCompositing) && 489 !CommandLine::ForCurrentProcess()->HasSwitch( 490 switches::kUIDisableThreadedCompositing); 491#endif 492 if (use_thread) { 493 g_compositor_thread = new base::Thread("Browser Compositor"); 494#if defined(OS_POSIX) 495 // Workaround for crbug.com/293736 496 // On Posix, MessagePumpDefault uses system time, so delayed tasks (for 497 // compositor scheduling) work incorrectly across system time changes (e.g. 498 // tlsdate). So instead, use an IO loop, which uses libevent, that uses 499 // monotonic time (immune to these problems). 500 base::Thread::Options options; 501 options.message_loop_type = base::MessageLoop::TYPE_IO; 502 g_compositor_thread->StartWithOptions(options); 503#else 504 g_compositor_thread->Start(); 505#endif 506 } 507 508 DCHECK(!g_compositor_initialized) << "Compositor initialized twice."; 509 g_compositor_initialized = true; 510} 511 512// static 513bool Compositor::WasInitializedWithThread() { 514 return !!g_compositor_thread; 515} 516 517// static 518scoped_refptr<base::MessageLoopProxy> Compositor::GetCompositorMessageLoop() { 519 scoped_refptr<base::MessageLoopProxy> proxy; 520 if (g_compositor_thread) 521 proxy = g_compositor_thread->message_loop_proxy(); 522 return proxy; 523} 524 525// static 526void Compositor::Terminate() { 527 if (g_context_factory) { 528 if (g_implicit_factory) { 529 delete g_implicit_factory; 530 g_implicit_factory = NULL; 531 } 532 g_context_factory = NULL; 533 } 534 535 if (g_compositor_thread) { 536 DCHECK(!g_context_factory) 537 << "The ContextFactory should not outlive the compositor thread."; 538 g_compositor_thread->Stop(); 539 delete g_compositor_thread; 540 g_compositor_thread = NULL; 541 } 542 543 DCHECK(g_compositor_initialized) << "Compositor::Initialize() didn't happen."; 544 g_compositor_initialized = false; 545} 546 547void Compositor::ScheduleDraw() { 548 if (g_compositor_thread) 549 host_->Composite(base::TimeTicks::Now()); 550 else if (delegate_) 551 delegate_->ScheduleDraw(); 552} 553 554void Compositor::SetRootLayer(Layer* root_layer) { 555 if (root_layer_ == root_layer) 556 return; 557 if (root_layer_) 558 root_layer_->SetCompositor(NULL); 559 root_layer_ = root_layer; 560 if (root_layer_ && !root_layer_->GetCompositor()) 561 root_layer_->SetCompositor(this); 562 root_web_layer_->RemoveAllChildren(); 563 if (root_layer_) 564 root_web_layer_->AddChild(root_layer_->cc_layer()); 565} 566 567void Compositor::SetHostHasTransparentBackground( 568 bool host_has_transparent_background) { 569 host_->set_has_transparent_background(host_has_transparent_background); 570} 571 572void Compositor::Draw() { 573 DCHECK(!g_compositor_thread); 574 575 if (!root_layer_) 576 return; 577 578 last_started_frame_++; 579 PendingSwap pending_swap(DRAW_SWAP, posted_swaps_.get()); 580 if (!IsLocked()) { 581 // TODO(nduca): Temporary while compositor calls 582 // compositeImmediately() directly. 583 Layout(); 584 host_->Composite(base::TimeTicks::Now()); 585 586#if defined(OS_WIN) 587 // While we resize, we are usually a few frames behind. By blocking 588 // the UI thread here we minize the area that is mis-painted, specially 589 // in the non-client area. See RenderWidgetHostViewAura::SetBounds for 590 // more details and bug 177115. 591 if (next_draw_is_resize_ && (last_ended_frame_ > 1)) { 592 next_draw_is_resize_ = false; 593 host_->FinishAllRendering(); 594 } 595#endif 596 597 } 598 if (!pending_swap.posted()) 599 NotifyEnd(); 600} 601 602void Compositor::ScheduleFullRedraw() { 603 host_->SetNeedsRedraw(); 604} 605 606void Compositor::ScheduleRedrawRect(const gfx::Rect& damage_rect) { 607 host_->SetNeedsRedrawRect(damage_rect); 608} 609 610void Compositor::SetLatencyInfo(const ui::LatencyInfo& latency_info) { 611 host_->SetLatencyInfo(latency_info); 612} 613 614bool Compositor::ReadPixels(SkBitmap* bitmap, 615 const gfx::Rect& bounds_in_pixel) { 616 if (bounds_in_pixel.right() > size().width() || 617 bounds_in_pixel.bottom() > size().height()) 618 return false; 619 bitmap->setConfig(SkBitmap::kARGB_8888_Config, 620 bounds_in_pixel.width(), bounds_in_pixel.height()); 621 bitmap->allocPixels(); 622 SkAutoLockPixels lock_image(*bitmap); 623 unsigned char* pixels = static_cast<unsigned char*>(bitmap->getPixels()); 624 CancelCompositorLock(); 625 PendingSwap pending_swap(READPIXELS_SWAP, posted_swaps_.get()); 626 return host_->CompositeAndReadback(pixels, bounds_in_pixel); 627} 628 629void Compositor::SetScaleAndSize(float scale, const gfx::Size& size_in_pixel) { 630 DCHECK_GT(scale, 0); 631 if (!size_in_pixel.IsEmpty()) { 632 size_ = size_in_pixel; 633 host_->SetViewportSize(size_in_pixel); 634 root_web_layer_->SetBounds(size_in_pixel); 635 636 next_draw_is_resize_ = true; 637 } 638 if (device_scale_factor_ != scale) { 639 device_scale_factor_ = scale; 640 if (root_layer_) 641 root_layer_->OnDeviceScaleFactorChanged(scale); 642 } 643} 644 645void Compositor::SetBackgroundColor(SkColor color) { 646 host_->set_background_color(color); 647 ScheduleDraw(); 648} 649 650void Compositor::AddObserver(CompositorObserver* observer) { 651 observer_list_.AddObserver(observer); 652} 653 654void Compositor::RemoveObserver(CompositorObserver* observer) { 655 observer_list_.RemoveObserver(observer); 656} 657 658bool Compositor::HasObserver(CompositorObserver* observer) { 659 return observer_list_.HasObserver(observer); 660} 661 662void Compositor::OnSwapBuffersPosted() { 663 DCHECK(!g_compositor_thread); 664 posted_swaps_->PostSwap(); 665} 666 667void Compositor::OnSwapBuffersComplete() { 668 DCHECK(!g_compositor_thread); 669 DCHECK(posted_swaps_->AreSwapsPosted()); 670 DCHECK_GE(1, posted_swaps_->NumSwapsPosted(DRAW_SWAP)); 671 if (posted_swaps_->NextPostedSwap() == DRAW_SWAP) 672 NotifyEnd(); 673 posted_swaps_->EndSwap(); 674} 675 676void Compositor::OnSwapBuffersAborted() { 677 if (!g_compositor_thread) { 678 DCHECK_GE(1, posted_swaps_->NumSwapsPosted(DRAW_SWAP)); 679 680 // We've just lost the context, so unwind all posted_swaps. 681 while (posted_swaps_->AreSwapsPosted()) { 682 if (posted_swaps_->NextPostedSwap() == DRAW_SWAP) 683 NotifyEnd(); 684 posted_swaps_->EndSwap(); 685 } 686 } 687 688 FOR_EACH_OBSERVER(CompositorObserver, 689 observer_list_, 690 OnCompositingAborted(this)); 691} 692 693void Compositor::OnUpdateVSyncParameters(base::TimeTicks timebase, 694 base::TimeDelta interval) { 695 FOR_EACH_OBSERVER(CompositorObserver, 696 observer_list_, 697 OnUpdateVSyncParameters(this, timebase, interval)); 698} 699 700void Compositor::Layout() { 701 // We're sending damage that will be addressed during this composite 702 // cycle, so we don't need to schedule another composite to address it. 703 disable_schedule_composite_ = true; 704 if (root_layer_) 705 root_layer_->SendDamagedRects(); 706 disable_schedule_composite_ = false; 707} 708 709scoped_ptr<cc::OutputSurface> Compositor::CreateOutputSurface(bool fallback) { 710 return ContextFactory::GetInstance()->CreateOutputSurface(this); 711} 712 713void Compositor::DidCommit() { 714 DCHECK(!IsLocked()); 715 FOR_EACH_OBSERVER(CompositorObserver, 716 observer_list_, 717 OnCompositingDidCommit(this)); 718} 719 720void Compositor::DidCommitAndDrawFrame() { 721 base::TimeTicks start_time = base::TimeTicks::Now(); 722 FOR_EACH_OBSERVER(CompositorObserver, 723 observer_list_, 724 OnCompositingStarted(this, start_time)); 725} 726 727void Compositor::DidCompleteSwapBuffers() { 728 DCHECK(g_compositor_thread); 729 NotifyEnd(); 730} 731 732void Compositor::ScheduleComposite() { 733 if (!disable_schedule_composite_) 734 ScheduleDraw(); 735} 736 737scoped_refptr<cc::ContextProvider> 738Compositor::OffscreenContextProviderForMainThread() { 739 return ContextFactory::GetInstance()->OffscreenContextProviderForMainThread(); 740} 741 742scoped_refptr<cc::ContextProvider> 743Compositor::OffscreenContextProviderForCompositorThread() { 744 return ContextFactory::GetInstance()-> 745 OffscreenContextProviderForCompositorThread(); 746} 747 748const cc::LayerTreeDebugState& Compositor::GetLayerTreeDebugState() const { 749 return host_->debug_state(); 750} 751 752void Compositor::SetLayerTreeDebugState( 753 const cc::LayerTreeDebugState& debug_state) { 754 host_->SetDebugState(debug_state); 755} 756 757scoped_refptr<CompositorLock> Compositor::GetCompositorLock() { 758 if (!compositor_lock_) { 759 compositor_lock_ = new CompositorLock(this); 760 if (g_compositor_thread) 761 host_->SetDeferCommits(true); 762 FOR_EACH_OBSERVER(CompositorObserver, 763 observer_list_, 764 OnCompositingLockStateChanged(this)); 765 } 766 return compositor_lock_; 767} 768 769void Compositor::UnlockCompositor() { 770 DCHECK(compositor_lock_); 771 compositor_lock_ = NULL; 772 if (g_compositor_thread) 773 host_->SetDeferCommits(false); 774 FOR_EACH_OBSERVER(CompositorObserver, 775 observer_list_, 776 OnCompositingLockStateChanged(this)); 777} 778 779void Compositor::CancelCompositorLock() { 780 if (compositor_lock_) 781 compositor_lock_->CancelLock(); 782} 783 784void Compositor::NotifyEnd() { 785 last_ended_frame_++; 786 FOR_EACH_OBSERVER(CompositorObserver, 787 observer_list_, 788 OnCompositingEnded(this)); 789} 790 791} // namespace ui 792