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