compositor.cc revision 5e3f23d412006dc4db4e659864679f29341e113f
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/strings/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.wait_for_commit_ = false; 363 waiter.WaitImpl(compositor); 364} 365 366// static 367void DrawWaiterForTest::WaitForCommit(Compositor* compositor) { 368 DrawWaiterForTest waiter; 369 waiter.wait_for_commit_ = true; 370 waiter.WaitImpl(compositor); 371} 372 373DrawWaiterForTest::DrawWaiterForTest() { 374} 375 376DrawWaiterForTest::~DrawWaiterForTest() { 377} 378 379void DrawWaiterForTest::WaitImpl(Compositor* compositor) { 380 compositor->AddObserver(this); 381 wait_run_loop_.reset(new base::RunLoop()); 382 wait_run_loop_->Run(); 383 compositor->RemoveObserver(this); 384} 385 386void DrawWaiterForTest::OnCompositingDidCommit(Compositor* compositor) { 387 if (wait_for_commit_) 388 wait_run_loop_->Quit(); 389} 390 391void DrawWaiterForTest::OnCompositingStarted(Compositor* compositor, 392 base::TimeTicks start_time) { 393} 394 395void DrawWaiterForTest::OnCompositingEnded(Compositor* compositor) { 396 if (!wait_for_commit_) 397 wait_run_loop_->Quit(); 398} 399 400void DrawWaiterForTest::OnCompositingAborted(Compositor* compositor) { 401} 402 403void DrawWaiterForTest::OnCompositingLockStateChanged(Compositor* compositor) { 404} 405 406void DrawWaiterForTest::OnUpdateVSyncParameters(Compositor* compositor, 407 base::TimeTicks timebase, 408 base::TimeDelta interval) { 409} 410 411class PostedSwapQueue { 412 public: 413 PostedSwapQueue() : pending_swap_(NULL) { 414 } 415 416 ~PostedSwapQueue() { 417 DCHECK(!pending_swap_); 418 } 419 420 SwapType NextPostedSwap() const { 421 return queue_.front(); 422 } 423 424 bool AreSwapsPosted() const { 425 return !queue_.empty(); 426 } 427 428 int NumSwapsPosted(SwapType type) const { 429 int count = 0; 430 for (std::deque<SwapType>::const_iterator it = queue_.begin(); 431 it != queue_.end(); ++it) { 432 if (*it == type) 433 count++; 434 } 435 return count; 436 } 437 438 void PostSwap() { 439 DCHECK(pending_swap_); 440 queue_.push_back(pending_swap_->type()); 441 pending_swap_->posted_ = true; 442 } 443 444 void EndSwap() { 445 queue_.pop_front(); 446 } 447 448 private: 449 friend class ::PendingSwap; 450 451 PendingSwap* pending_swap_; 452 std::deque<SwapType> queue_; 453 454 DISALLOW_COPY_AND_ASSIGN(PostedSwapQueue); 455}; 456 457} // namespace ui 458 459namespace { 460 461PendingSwap::PendingSwap(SwapType type, ui::PostedSwapQueue* posted_swaps) 462 : type_(type), posted_(false), posted_swaps_(posted_swaps) { 463 // Only one pending swap in flight. 464 DCHECK_EQ(static_cast<PendingSwap*>(NULL), posted_swaps_->pending_swap_); 465 posted_swaps_->pending_swap_ = this; 466} 467 468PendingSwap::~PendingSwap() { 469 DCHECK_EQ(this, posted_swaps_->pending_swap_); 470 posted_swaps_->pending_swap_ = NULL; 471} 472 473} // namespace 474 475namespace ui { 476 477Compositor::Compositor(CompositorDelegate* delegate, 478 gfx::AcceleratedWidget widget) 479 : delegate_(delegate), 480 root_layer_(NULL), 481 widget_(widget), 482 posted_swaps_(new PostedSwapQueue()), 483 device_scale_factor_(0.0f), 484 last_started_frame_(0), 485 last_ended_frame_(0), 486 next_draw_is_resize_(false), 487 disable_schedule_composite_(false), 488 compositor_lock_(NULL) { 489 root_web_layer_ = cc::Layer::Create(); 490 root_web_layer_->SetAnchorPoint(gfx::PointF(0.f, 0.f)); 491 // TODO(piman): remove after crbug.com/235302 is fixed. 492 root_web_layer_->SetMasksToBounds(true); 493 494 CommandLine* command_line = CommandLine::ForCurrentProcess(); 495 496 cc::LayerTreeSettings settings; 497 settings.refresh_rate = 498 g_test_compositor_enabled ? kTestRefreshRate : kDefaultRefreshRate; 499 settings.partial_swap_enabled = 500 !command_line->HasSwitch(cc::switches::kUIDisablePartialSwap); 501 settings.per_tile_painting_enabled = 502 command_line->HasSwitch(cc::switches::kUIEnablePerTilePainting); 503 504 // These flags should be mirrored by renderer versions in content/renderer/. 505 settings.initial_debug_state.show_debug_borders = 506 command_line->HasSwitch(cc::switches::kUIShowCompositedLayerBorders); 507 settings.initial_debug_state.show_fps_counter = 508 command_line->HasSwitch(cc::switches::kUIShowFPSCounter); 509 settings.initial_debug_state.show_paint_rects = 510 command_line->HasSwitch(switches::kUIShowPaintRects); 511 settings.initial_debug_state.show_platform_layer_tree = 512 command_line->HasSwitch(cc::switches::kUIShowCompositedLayerTree); 513 settings.initial_debug_state.show_property_changed_rects = 514 command_line->HasSwitch(cc::switches::kUIShowPropertyChangedRects); 515 settings.initial_debug_state.show_surface_damage_rects = 516 command_line->HasSwitch(cc::switches::kUIShowSurfaceDamageRects); 517 settings.initial_debug_state.show_screen_space_rects = 518 command_line->HasSwitch(cc::switches::kUIShowScreenSpaceRects); 519 settings.initial_debug_state.show_replica_screen_space_rects = 520 command_line->HasSwitch(cc::switches::kUIShowReplicaScreenSpaceRects); 521 settings.initial_debug_state.show_occluding_rects = 522 command_line->HasSwitch(cc::switches::kUIShowOccludingRects); 523 settings.initial_debug_state.show_non_occluding_rects = 524 command_line->HasSwitch(cc::switches::kUIShowNonOccludingRects); 525 526 scoped_ptr<cc::Thread> thread; 527 if (g_compositor_thread) { 528 thread = cc::ThreadImpl::CreateForDifferentThread( 529 g_compositor_thread->message_loop_proxy()); 530 } 531 532 host_ = cc::LayerTreeHost::Create(this, settings, thread.Pass()); 533 host_->SetRootLayer(root_web_layer_); 534 host_->SetLayerTreeHostClientReady(); 535} 536 537Compositor::~Compositor() { 538 CancelCompositorLock(); 539 DCHECK(!compositor_lock_); 540 541 // Don't call |CompositorDelegate::ScheduleDraw| from this point. 542 delegate_ = NULL; 543 if (root_layer_) 544 root_layer_->SetCompositor(NULL); 545 546 // Stop all outstanding draws before telling the ContextFactory to tear 547 // down any contexts that the |host_| may rely upon. 548 host_.reset(); 549 550 ContextFactory::GetInstance()->RemoveCompositor(this); 551} 552 553// static 554void Compositor::Initialize() { 555#if defined(OS_CHROMEOS) 556 bool use_thread = !CommandLine::ForCurrentProcess()->HasSwitch( 557 switches::kUIDisableThreadedCompositing); 558#else 559 bool use_thread = 560 CommandLine::ForCurrentProcess()->HasSwitch( 561 switches::kUIEnableThreadedCompositing) && 562 !CommandLine::ForCurrentProcess()->HasSwitch( 563 switches::kUIDisableThreadedCompositing); 564#endif 565 if (use_thread) { 566 g_compositor_thread = new base::Thread("Browser Compositor"); 567 g_compositor_thread->Start(); 568 } 569} 570 571// static 572bool Compositor::WasInitializedWithThread() { 573 return !!g_compositor_thread; 574} 575 576// static 577scoped_refptr<base::MessageLoopProxy> Compositor::GetCompositorMessageLoop() { 578 scoped_refptr<base::MessageLoopProxy> proxy; 579 if (g_compositor_thread) 580 proxy = g_compositor_thread->message_loop_proxy(); 581 return proxy; 582} 583 584// static 585void Compositor::Terminate() { 586 if (g_compositor_thread) { 587 g_compositor_thread->Stop(); 588 delete g_compositor_thread; 589 g_compositor_thread = NULL; 590 } 591} 592 593void Compositor::ScheduleDraw() { 594 if (g_compositor_thread) 595 host_->Composite(base::TimeTicks::Now()); 596 else if (delegate_) 597 delegate_->ScheduleDraw(); 598} 599 600void Compositor::SetRootLayer(Layer* root_layer) { 601 if (root_layer_ == root_layer) 602 return; 603 if (root_layer_) 604 root_layer_->SetCompositor(NULL); 605 root_layer_ = root_layer; 606 if (root_layer_ && !root_layer_->GetCompositor()) 607 root_layer_->SetCompositor(this); 608 root_web_layer_->RemoveAllChildren(); 609 if (root_layer_) 610 root_web_layer_->AddChild(root_layer_->cc_layer()); 611} 612 613void Compositor::SetHostHasTransparentBackground( 614 bool host_has_transparent_background) { 615 host_->set_has_transparent_background(host_has_transparent_background); 616} 617 618void Compositor::Draw() { 619 DCHECK(!g_compositor_thread); 620 621 if (!root_layer_) 622 return; 623 624 last_started_frame_++; 625 PendingSwap pending_swap(DRAW_SWAP, posted_swaps_.get()); 626 if (!IsLocked()) { 627 // TODO(nduca): Temporary while compositor calls 628 // compositeImmediately() directly. 629 Layout(); 630 host_->Composite(base::TimeTicks::Now()); 631 632#if defined(OS_WIN) 633 // While we resize, we are usually a few frames behind. By blocking 634 // the UI thread here we minize the area that is mis-painted, specially 635 // in the non-client area. See RenderWidgetHostViewAura::SetBounds for 636 // more details and bug 177115. 637 if (next_draw_is_resize_ && (last_ended_frame_ > 1)) { 638 next_draw_is_resize_ = false; 639 host_->FinishAllRendering(); 640 } 641#endif 642 643 } 644 if (!pending_swap.posted()) 645 NotifyEnd(); 646} 647 648void Compositor::ScheduleFullRedraw() { 649 host_->SetNeedsRedraw(); 650} 651 652void Compositor::ScheduleRedrawRect(const gfx::Rect& damage_rect) { 653 host_->SetNeedsRedrawRect(damage_rect); 654} 655 656void Compositor::SetLatencyInfo(const ui::LatencyInfo& latency_info) { 657 host_->SetLatencyInfo(latency_info); 658} 659 660bool Compositor::ReadPixels(SkBitmap* bitmap, 661 const gfx::Rect& bounds_in_pixel) { 662 if (bounds_in_pixel.right() > size().width() || 663 bounds_in_pixel.bottom() > size().height()) 664 return false; 665 bitmap->setConfig(SkBitmap::kARGB_8888_Config, 666 bounds_in_pixel.width(), bounds_in_pixel.height()); 667 bitmap->allocPixels(); 668 SkAutoLockPixels lock_image(*bitmap); 669 unsigned char* pixels = static_cast<unsigned char*>(bitmap->getPixels()); 670 CancelCompositorLock(); 671 PendingSwap pending_swap(READPIXELS_SWAP, posted_swaps_.get()); 672 return host_->CompositeAndReadback(pixels, bounds_in_pixel); 673} 674 675void Compositor::SetScaleAndSize(float scale, const gfx::Size& size_in_pixel) { 676 DCHECK_GT(scale, 0); 677 if (!size_in_pixel.IsEmpty()) { 678 size_ = size_in_pixel; 679 host_->SetViewportSize(size_in_pixel); 680 root_web_layer_->SetBounds(size_in_pixel); 681 682 next_draw_is_resize_ = true; 683 } 684 if (device_scale_factor_ != scale) { 685 device_scale_factor_ = scale; 686 if (root_layer_) 687 root_layer_->OnDeviceScaleFactorChanged(scale); 688 } 689} 690 691void Compositor::SetBackgroundColor(SkColor color) { 692 host_->set_background_color(color); 693 ScheduleDraw(); 694} 695 696void Compositor::AddObserver(CompositorObserver* observer) { 697 observer_list_.AddObserver(observer); 698} 699 700void Compositor::RemoveObserver(CompositorObserver* observer) { 701 observer_list_.RemoveObserver(observer); 702} 703 704bool Compositor::HasObserver(CompositorObserver* observer) { 705 return observer_list_.HasObserver(observer); 706} 707 708void Compositor::OnSwapBuffersPosted() { 709 DCHECK(!g_compositor_thread); 710 posted_swaps_->PostSwap(); 711} 712 713void Compositor::OnSwapBuffersComplete() { 714 DCHECK(!g_compositor_thread); 715 DCHECK(posted_swaps_->AreSwapsPosted()); 716 DCHECK_GE(1, posted_swaps_->NumSwapsPosted(DRAW_SWAP)); 717 if (posted_swaps_->NextPostedSwap() == DRAW_SWAP) 718 NotifyEnd(); 719 posted_swaps_->EndSwap(); 720} 721 722void Compositor::OnSwapBuffersAborted() { 723 if (!g_compositor_thread) { 724 DCHECK_GE(1, posted_swaps_->NumSwapsPosted(DRAW_SWAP)); 725 726 // We've just lost the context, so unwind all posted_swaps. 727 while (posted_swaps_->AreSwapsPosted()) { 728 if (posted_swaps_->NextPostedSwap() == DRAW_SWAP) 729 NotifyEnd(); 730 posted_swaps_->EndSwap(); 731 } 732 } 733 734 FOR_EACH_OBSERVER(CompositorObserver, 735 observer_list_, 736 OnCompositingAborted(this)); 737} 738 739void Compositor::OnUpdateVSyncParameters(base::TimeTicks timebase, 740 base::TimeDelta interval) { 741 FOR_EACH_OBSERVER(CompositorObserver, 742 observer_list_, 743 OnUpdateVSyncParameters(this, timebase, interval)); 744} 745 746void Compositor::Layout() { 747 // We're sending damage that will be addressed during this composite 748 // cycle, so we don't need to schedule another composite to address it. 749 disable_schedule_composite_ = true; 750 if (root_layer_) 751 root_layer_->SendDamagedRects(); 752 disable_schedule_composite_ = false; 753} 754 755scoped_ptr<cc::OutputSurface> Compositor::CreateOutputSurface() { 756 return make_scoped_ptr( 757 ContextFactory::GetInstance()->CreateOutputSurface(this)); 758} 759 760void Compositor::DidCommit() { 761 DCHECK(!IsLocked()); 762 FOR_EACH_OBSERVER(CompositorObserver, 763 observer_list_, 764 OnCompositingDidCommit(this)); 765} 766 767void Compositor::DidCommitAndDrawFrame() { 768 base::TimeTicks start_time = base::TimeTicks::Now(); 769 FOR_EACH_OBSERVER(CompositorObserver, 770 observer_list_, 771 OnCompositingStarted(this, start_time)); 772} 773 774void Compositor::DidCompleteSwapBuffers() { 775 DCHECK(g_compositor_thread); 776 NotifyEnd(); 777} 778 779void Compositor::ScheduleComposite() { 780 if (!disable_schedule_composite_) 781 ScheduleDraw(); 782} 783 784scoped_refptr<cc::ContextProvider> 785Compositor::OffscreenContextProviderForMainThread() { 786 return ContextFactory::GetInstance()->OffscreenContextProviderForMainThread(); 787} 788 789scoped_refptr<cc::ContextProvider> 790Compositor::OffscreenContextProviderForCompositorThread() { 791 return ContextFactory::GetInstance()-> 792 OffscreenContextProviderForCompositorThread(); 793} 794 795const cc::LayerTreeDebugState& Compositor::GetLayerTreeDebugState() const { 796 return host_->debug_state(); 797} 798 799void Compositor::SetLayerTreeDebugState( 800 const cc::LayerTreeDebugState& debug_state) { 801 host_->SetDebugState(debug_state); 802} 803 804scoped_refptr<CompositorLock> Compositor::GetCompositorLock() { 805 if (!compositor_lock_) { 806 compositor_lock_ = new CompositorLock(this); 807 if (g_compositor_thread) 808 host_->SetDeferCommits(true); 809 FOR_EACH_OBSERVER(CompositorObserver, 810 observer_list_, 811 OnCompositingLockStateChanged(this)); 812 } 813 return compositor_lock_; 814} 815 816void Compositor::UnlockCompositor() { 817 DCHECK(compositor_lock_); 818 compositor_lock_ = NULL; 819 if (g_compositor_thread) 820 host_->SetDeferCommits(false); 821 FOR_EACH_OBSERVER(CompositorObserver, 822 observer_list_, 823 OnCompositingLockStateChanged(this)); 824} 825 826void Compositor::CancelCompositorLock() { 827 if (compositor_lock_) 828 compositor_lock_->CancelLock(); 829} 830 831void Compositor::NotifyEnd() { 832 last_ended_frame_++; 833 FOR_EACH_OBSERVER(CompositorObserver, 834 observer_list_, 835 OnCompositingEnded(this)); 836} 837 838COMPOSITOR_EXPORT void SetupTestCompositor() { 839 if (!CommandLine::ForCurrentProcess()->HasSwitch( 840 switches::kDisableTestCompositor)) { 841 g_test_compositor_enabled = true; 842 } 843#if defined(OS_CHROMEOS) 844 // If the test is running on the chromeos envrionment (such as 845 // device or vm bots), use the real compositor. 846 if (base::chromeos::IsRunningOnChromeOS()) 847 g_test_compositor_enabled = false; 848#endif 849 ResetImplicitFactory(); 850} 851 852COMPOSITOR_EXPORT void DisableTestCompositor() { 853 ResetImplicitFactory(); 854 g_test_compositor_enabled = false; 855} 856 857COMPOSITOR_EXPORT bool IsTestCompositorEnabled() { 858 return g_test_compositor_enabled; 859} 860 861} // namespace ui 862