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