compositor.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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/gpu/grcontext_for_webgraphicscontext3d.h"
36#include "webkit/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<cc::ContextProvider>
214DefaultContextFactory::OffscreenContextProviderForMainThread() {
215  if (!offscreen_contexts_main_thread_ ||
216      !offscreen_contexts_main_thread_->DestroyedOnMainThread()) {
217    offscreen_contexts_main_thread_ =
218        ContextProviderFromContextFactory::Create(this);
219    if (offscreen_contexts_main_thread_ &&
220        !offscreen_contexts_main_thread_->BindToCurrentThread())
221      offscreen_contexts_main_thread_ = NULL;
222  }
223  return offscreen_contexts_main_thread_;
224}
225
226scoped_refptr<cc::ContextProvider>
227DefaultContextFactory::OffscreenContextProviderForCompositorThread() {
228  if (!offscreen_contexts_compositor_thread_ ||
229      !offscreen_contexts_compositor_thread_->DestroyedOnMainThread()) {
230    offscreen_contexts_compositor_thread_ =
231        ContextProviderFromContextFactory::Create(this);
232  }
233  return offscreen_contexts_compositor_thread_;
234}
235
236void DefaultContextFactory::RemoveCompositor(Compositor* compositor) {
237}
238
239WebKit::WebGraphicsContext3D* DefaultContextFactory::CreateContextCommon(
240    Compositor* compositor,
241    bool offscreen) {
242  DCHECK(offscreen || compositor);
243  WebKit::WebGraphicsContext3D::Attributes attrs;
244  attrs.depth = false;
245  attrs.stencil = false;
246  attrs.antialias = false;
247  attrs.shareResources = true;
248  using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl;
249  WebKit::WebGraphicsContext3D* context =
250      offscreen ?
251      WebGraphicsContext3DInProcessCommandBufferImpl::CreateOffscreenContext(
252          attrs) :
253      WebGraphicsContext3DInProcessCommandBufferImpl::CreateViewContext(
254          attrs, compositor->widget());
255  if (!context)
256    return NULL;
257
258  CommandLine* command_line = CommandLine::ForCurrentProcess();
259  if (!offscreen) {
260    context->makeContextCurrent();
261    gfx::GLContext* gl_context = gfx::GLContext::GetCurrent();
262    bool vsync = !command_line->HasSwitch(switches::kDisableGpuVsync);
263    gl_context->SetSwapInterval(vsync ? 1 : 0);
264    gl_context->ReleaseCurrent(NULL);
265  }
266  return context;
267}
268
269TestContextFactory::TestContextFactory() {}
270
271TestContextFactory::~TestContextFactory() {}
272
273cc::OutputSurface* TestContextFactory::CreateOutputSurface(
274    Compositor* compositor) {
275  return new cc::OutputSurface(make_scoped_ptr(CreateOffscreenContext()));
276}
277
278WebKit::WebGraphicsContext3D* TestContextFactory::CreateOffscreenContext() {
279  ui::TestWebGraphicsContext3D* context = new ui::TestWebGraphicsContext3D;
280  context->Initialize();
281  return context;
282}
283
284scoped_refptr<cc::ContextProvider>
285TestContextFactory::OffscreenContextProviderForMainThread() {
286  if (!offscreen_contexts_main_thread_ ||
287      offscreen_contexts_main_thread_->DestroyedOnMainThread()) {
288    offscreen_contexts_main_thread_ =
289        ContextProviderFromContextFactory::Create(this);
290    CHECK(offscreen_contexts_main_thread_->BindToCurrentThread());
291  }
292  return offscreen_contexts_main_thread_;
293}
294
295scoped_refptr<cc::ContextProvider>
296TestContextFactory::OffscreenContextProviderForCompositorThread() {
297  if (!offscreen_contexts_compositor_thread_ ||
298      offscreen_contexts_compositor_thread_->DestroyedOnMainThread()) {
299    offscreen_contexts_compositor_thread_ =
300        ContextProviderFromContextFactory::Create(this);
301  }
302  return offscreen_contexts_compositor_thread_;
303}
304
305void TestContextFactory::RemoveCompositor(Compositor* compositor) {
306}
307
308Texture::Texture(bool flipped, const gfx::Size& size, float device_scale_factor)
309    : size_(size),
310      flipped_(flipped),
311      device_scale_factor_(device_scale_factor) {
312}
313
314Texture::~Texture() {
315}
316
317std::string Texture::Produce() {
318  return EmptyString();
319}
320
321CompositorLock::CompositorLock(Compositor* compositor)
322    : compositor_(compositor) {
323  base::MessageLoop::current()->PostDelayedTask(
324      FROM_HERE,
325      base::Bind(&CompositorLock::CancelLock, AsWeakPtr()),
326      base::TimeDelta::FromMilliseconds(kCompositorLockTimeoutMs));
327}
328
329CompositorLock::~CompositorLock() {
330  CancelLock();
331}
332
333void CompositorLock::CancelLock() {
334  if (!compositor_)
335    return;
336  compositor_->UnlockCompositor();
337  compositor_ = NULL;
338}
339
340// static
341void DrawWaiterForTest::Wait(Compositor* compositor) {
342  DrawWaiterForTest waiter;
343  waiter.WaitImpl(compositor);
344}
345
346DrawWaiterForTest::DrawWaiterForTest() {
347}
348
349DrawWaiterForTest::~DrawWaiterForTest() {
350}
351
352void DrawWaiterForTest::WaitImpl(Compositor* compositor) {
353  compositor->AddObserver(this);
354  wait_run_loop_.reset(new base::RunLoop());
355  wait_run_loop_->Run();
356  compositor->RemoveObserver(this);
357}
358
359void DrawWaiterForTest::OnCompositingDidCommit(Compositor* compositor) {
360}
361
362void DrawWaiterForTest::OnCompositingStarted(Compositor* compositor,
363                                             base::TimeTicks start_time) {
364}
365
366void DrawWaiterForTest::OnCompositingEnded(Compositor* compositor) {
367  wait_run_loop_->Quit();
368}
369
370void DrawWaiterForTest::OnCompositingAborted(Compositor* compositor) {
371}
372
373void DrawWaiterForTest::OnCompositingLockStateChanged(Compositor* compositor) {
374}
375
376void DrawWaiterForTest::OnUpdateVSyncParameters(Compositor* compositor,
377                                                base::TimeTicks timebase,
378                                                base::TimeDelta interval) {
379}
380
381class PostedSwapQueue {
382 public:
383  PostedSwapQueue() : pending_swap_(NULL) {
384  }
385
386  ~PostedSwapQueue() {
387    DCHECK(!pending_swap_);
388  }
389
390  SwapType NextPostedSwap() const {
391    return queue_.front();
392  }
393
394  bool AreSwapsPosted() const {
395    return !queue_.empty();
396  }
397
398  int NumSwapsPosted(SwapType type) const {
399    int count = 0;
400    for (std::deque<SwapType>::const_iterator it = queue_.begin();
401         it != queue_.end(); ++it) {
402      if (*it == type)
403        count++;
404    }
405    return count;
406  }
407
408  void PostSwap() {
409    DCHECK(pending_swap_);
410    queue_.push_back(pending_swap_->type());
411    pending_swap_->posted_ = true;
412  }
413
414  void EndSwap() {
415    queue_.pop_front();
416  }
417
418 private:
419  friend class ::PendingSwap;
420
421  PendingSwap* pending_swap_;
422  std::deque<SwapType> queue_;
423
424  DISALLOW_COPY_AND_ASSIGN(PostedSwapQueue);
425};
426
427}  // namespace ui
428
429namespace {
430
431PendingSwap::PendingSwap(SwapType type, ui::PostedSwapQueue* posted_swaps)
432    : type_(type), posted_(false), posted_swaps_(posted_swaps) {
433  // Only one pending swap in flight.
434  DCHECK_EQ(static_cast<PendingSwap*>(NULL), posted_swaps_->pending_swap_);
435  posted_swaps_->pending_swap_ = this;
436}
437
438PendingSwap::~PendingSwap() {
439  DCHECK_EQ(this, posted_swaps_->pending_swap_);
440  posted_swaps_->pending_swap_ = NULL;
441}
442
443}  // namespace
444
445namespace ui {
446
447Compositor::Compositor(CompositorDelegate* delegate,
448                       gfx::AcceleratedWidget widget)
449    : delegate_(delegate),
450      root_layer_(NULL),
451      widget_(widget),
452      posted_swaps_(new PostedSwapQueue()),
453      device_scale_factor_(0.0f),
454      last_started_frame_(0),
455      last_ended_frame_(0),
456      next_draw_is_resize_(false),
457      disable_schedule_composite_(false),
458      compositor_lock_(NULL) {
459  root_web_layer_ = cc::Layer::Create();
460  root_web_layer_->SetAnchorPoint(gfx::PointF(0.f, 0.f));
461  // TODO(piman): remove after crbug.com/235302 is fixed.
462  root_web_layer_->SetMasksToBounds(true);
463
464  CommandLine* command_line = CommandLine::ForCurrentProcess();
465
466  cc::LayerTreeSettings settings;
467  settings.refresh_rate =
468      g_test_compositor_enabled ? kTestRefreshRate : kDefaultRefreshRate;
469  settings.partial_swap_enabled =
470      !command_line->HasSwitch(cc::switches::kUIDisablePartialSwap);
471  settings.per_tile_painting_enabled =
472      command_line->HasSwitch(cc::switches::kUIEnablePerTilePainting);
473
474  // These flags should be mirrored by renderer versions in content/renderer/.
475  settings.initial_debug_state.show_debug_borders =
476      command_line->HasSwitch(cc::switches::kUIShowCompositedLayerBorders);
477  settings.initial_debug_state.show_fps_counter =
478      command_line->HasSwitch(cc::switches::kUIShowFPSCounter);
479  settings.initial_debug_state.show_paint_rects =
480      command_line->HasSwitch(switches::kUIShowPaintRects);
481  settings.initial_debug_state.show_platform_layer_tree =
482      command_line->HasSwitch(cc::switches::kUIShowCompositedLayerTree);
483  settings.initial_debug_state.show_property_changed_rects =
484      command_line->HasSwitch(cc::switches::kUIShowPropertyChangedRects);
485  settings.initial_debug_state.show_surface_damage_rects =
486      command_line->HasSwitch(cc::switches::kUIShowSurfaceDamageRects);
487  settings.initial_debug_state.show_screen_space_rects =
488      command_line->HasSwitch(cc::switches::kUIShowScreenSpaceRects);
489  settings.initial_debug_state.show_replica_screen_space_rects =
490      command_line->HasSwitch(cc::switches::kUIShowReplicaScreenSpaceRects);
491  settings.initial_debug_state.show_occluding_rects =
492      command_line->HasSwitch(cc::switches::kUIShowOccludingRects);
493  settings.initial_debug_state.show_non_occluding_rects =
494      command_line->HasSwitch(cc::switches::kUIShowNonOccludingRects);
495
496  scoped_ptr<cc::Thread> thread;
497  if (g_compositor_thread) {
498    thread = cc::ThreadImpl::CreateForDifferentThread(
499        g_compositor_thread->message_loop_proxy());
500  }
501
502  host_ = cc::LayerTreeHost::Create(this, settings, thread.Pass());
503  host_->SetRootLayer(root_web_layer_);
504  host_->SetSurfaceReady();
505}
506
507Compositor::~Compositor() {
508  CancelCompositorLock();
509  DCHECK(!compositor_lock_);
510
511  // Don't call |CompositorDelegate::ScheduleDraw| from this point.
512  delegate_ = NULL;
513  if (root_layer_)
514    root_layer_->SetCompositor(NULL);
515
516  // Stop all outstanding draws before telling the ContextFactory to tear
517  // down any contexts that the |host_| may rely upon.
518  host_.reset();
519
520  ContextFactory::GetInstance()->RemoveCompositor(this);
521}
522
523// static
524void Compositor::Initialize() {
525#if defined(OS_CHROMEOS)
526  bool use_thread = !CommandLine::ForCurrentProcess()->HasSwitch(
527      switches::kUIDisableThreadedCompositing);
528#else
529  bool use_thread =
530      CommandLine::ForCurrentProcess()->HasSwitch(
531          switches::kUIEnableThreadedCompositing) &&
532      !CommandLine::ForCurrentProcess()->HasSwitch(
533          switches::kUIDisableThreadedCompositing);
534#endif
535  if (use_thread) {
536    g_compositor_thread = new base::Thread("Browser Compositor");
537    g_compositor_thread->Start();
538  }
539}
540
541// static
542bool Compositor::WasInitializedWithThread() {
543  return !!g_compositor_thread;
544}
545
546// static
547void Compositor::Terminate() {
548  if (g_compositor_thread) {
549    g_compositor_thread->Stop();
550    delete g_compositor_thread;
551    g_compositor_thread = NULL;
552  }
553}
554
555void Compositor::ScheduleDraw() {
556  if (g_compositor_thread)
557    host_->Composite(base::TimeTicks::Now());
558  else if (delegate_)
559    delegate_->ScheduleDraw();
560}
561
562void Compositor::SetRootLayer(Layer* root_layer) {
563  if (root_layer_ == root_layer)
564    return;
565  if (root_layer_)
566    root_layer_->SetCompositor(NULL);
567  root_layer_ = root_layer;
568  if (root_layer_ && !root_layer_->GetCompositor())
569    root_layer_->SetCompositor(this);
570  root_web_layer_->RemoveAllChildren();
571  if (root_layer_)
572    root_web_layer_->AddChild(root_layer_->cc_layer());
573}
574
575void Compositor::SetHostHasTransparentBackground(
576    bool host_has_transparent_background) {
577  host_->set_has_transparent_background(host_has_transparent_background);
578}
579
580void Compositor::Draw() {
581  DCHECK(!g_compositor_thread);
582
583  if (!root_layer_)
584    return;
585
586  last_started_frame_++;
587  PendingSwap pending_swap(DRAW_SWAP, posted_swaps_.get());
588  if (!IsLocked()) {
589    // TODO(nduca): Temporary while compositor calls
590    // compositeImmediately() directly.
591    Layout();
592    host_->Composite(base::TimeTicks::Now());
593
594#if defined(OS_WIN)
595    // While we resize, we are usually a few frames behind. By blocking
596    // the UI thread here we minize the area that is mis-painted, specially
597    // in the non-client area. See RenderWidgetHostViewAura::SetBounds for
598    // more details and bug 177115.
599    if (next_draw_is_resize_ && (last_ended_frame_ > 1)) {
600      next_draw_is_resize_ = false;
601      host_->FinishAllRendering();
602    }
603#endif
604
605  }
606  if (!pending_swap.posted())
607    NotifyEnd();
608}
609
610void Compositor::ScheduleFullRedraw() {
611  host_->SetNeedsRedraw();
612}
613
614void Compositor::ScheduleRedrawRect(const gfx::Rect& damage_rect) {
615  host_->SetNeedsRedrawRect(damage_rect);
616}
617
618bool Compositor::ReadPixels(SkBitmap* bitmap,
619                            const gfx::Rect& bounds_in_pixel) {
620  if (bounds_in_pixel.right() > size().width() ||
621      bounds_in_pixel.bottom() > size().height())
622    return false;
623  bitmap->setConfig(SkBitmap::kARGB_8888_Config,
624                    bounds_in_pixel.width(), bounds_in_pixel.height());
625  bitmap->allocPixels();
626  SkAutoLockPixels lock_image(*bitmap);
627  unsigned char* pixels = static_cast<unsigned char*>(bitmap->getPixels());
628  CancelCompositorLock();
629  PendingSwap pending_swap(READPIXELS_SWAP, posted_swaps_.get());
630  return host_->CompositeAndReadback(pixels, bounds_in_pixel);
631}
632
633void Compositor::SetScaleAndSize(float scale, const gfx::Size& size_in_pixel) {
634  DCHECK_GT(scale, 0);
635  if (!size_in_pixel.IsEmpty()) {
636    size_ = size_in_pixel;
637    host_->SetViewportSize(size_in_pixel);
638    root_web_layer_->SetBounds(size_in_pixel);
639
640    next_draw_is_resize_ = true;
641  }
642  if (device_scale_factor_ != scale) {
643    device_scale_factor_ = scale;
644    if (root_layer_)
645      root_layer_->OnDeviceScaleFactorChanged(scale);
646  }
647}
648
649void Compositor::SetBackgroundColor(SkColor color) {
650  host_->set_background_color(color);
651  ScheduleDraw();
652}
653
654void Compositor::AddObserver(CompositorObserver* observer) {
655  observer_list_.AddObserver(observer);
656}
657
658void Compositor::RemoveObserver(CompositorObserver* observer) {
659  observer_list_.RemoveObserver(observer);
660}
661
662bool Compositor::HasObserver(CompositorObserver* observer) {
663  return observer_list_.HasObserver(observer);
664}
665
666void Compositor::OnSwapBuffersPosted() {
667  DCHECK(!g_compositor_thread);
668  posted_swaps_->PostSwap();
669}
670
671void Compositor::OnSwapBuffersComplete() {
672  DCHECK(!g_compositor_thread);
673  DCHECK(posted_swaps_->AreSwapsPosted());
674  DCHECK_GE(1, posted_swaps_->NumSwapsPosted(DRAW_SWAP));
675  if (posted_swaps_->NextPostedSwap() == DRAW_SWAP)
676    NotifyEnd();
677  posted_swaps_->EndSwap();
678}
679
680void Compositor::OnSwapBuffersAborted() {
681  if (!g_compositor_thread) {
682    DCHECK_GE(1, posted_swaps_->NumSwapsPosted(DRAW_SWAP));
683
684    // We've just lost the context, so unwind all posted_swaps.
685    while (posted_swaps_->AreSwapsPosted()) {
686      if (posted_swaps_->NextPostedSwap() == DRAW_SWAP)
687        NotifyEnd();
688      posted_swaps_->EndSwap();
689    }
690  }
691
692  FOR_EACH_OBSERVER(CompositorObserver,
693                    observer_list_,
694                    OnCompositingAborted(this));
695}
696
697void Compositor::OnUpdateVSyncParameters(base::TimeTicks timebase,
698                                         base::TimeDelta interval) {
699  FOR_EACH_OBSERVER(CompositorObserver,
700                    observer_list_,
701                    OnUpdateVSyncParameters(this, timebase, interval));
702}
703
704void Compositor::Layout() {
705  // We're sending damage that will be addressed during this composite
706  // cycle, so we don't need to schedule another composite to address it.
707  disable_schedule_composite_ = true;
708  if (root_layer_)
709    root_layer_->SendDamagedRects();
710  disable_schedule_composite_ = false;
711}
712
713scoped_ptr<cc::OutputSurface> Compositor::CreateOutputSurface() {
714  return make_scoped_ptr(
715      ContextFactory::GetInstance()->CreateOutputSurface(this));
716}
717
718scoped_ptr<cc::InputHandlerClient> Compositor::CreateInputHandlerClient() {
719  return scoped_ptr<cc::InputHandlerClient>();
720}
721
722void Compositor::DidCommit() {
723  DCHECK(!IsLocked());
724  FOR_EACH_OBSERVER(CompositorObserver,
725                    observer_list_,
726                    OnCompositingDidCommit(this));
727}
728
729void Compositor::DidCommitAndDrawFrame() {
730  base::TimeTicks start_time = base::TimeTicks::Now();
731  FOR_EACH_OBSERVER(CompositorObserver,
732                    observer_list_,
733                    OnCompositingStarted(this, start_time));
734  // If we're threaded without a swap complete callback, we have to
735  // call DidCompleteSwapBuffersManually.
736  if (g_compositor_thread &&
737      !host_->GetRendererCapabilities().using_swap_complete_callback)
738    DidCompleteSwapBuffers();
739}
740
741void Compositor::DidCompleteSwapBuffers() {
742  DCHECK(g_compositor_thread);
743  NotifyEnd();
744}
745
746void Compositor::ScheduleComposite() {
747  if (!disable_schedule_composite_)
748    ScheduleDraw();
749}
750
751scoped_refptr<cc::ContextProvider>
752Compositor::OffscreenContextProviderForMainThread() {
753  return ContextFactory::GetInstance()->OffscreenContextProviderForMainThread();
754}
755
756scoped_refptr<cc::ContextProvider>
757Compositor::OffscreenContextProviderForCompositorThread() {
758  return ContextFactory::GetInstance()->
759      OffscreenContextProviderForCompositorThread();
760}
761
762const cc::LayerTreeDebugState& Compositor::GetLayerTreeDebugState() const {
763  return host_->debug_state();
764}
765
766void Compositor::SetLayerTreeDebugState(
767    const cc::LayerTreeDebugState& debug_state) {
768  host_->SetDebugState(debug_state);
769}
770
771scoped_refptr<CompositorLock> Compositor::GetCompositorLock() {
772  if (!compositor_lock_) {
773    compositor_lock_ = new CompositorLock(this);
774    if (g_compositor_thread)
775      host_->SetDeferCommits(true);
776    FOR_EACH_OBSERVER(CompositorObserver,
777                      observer_list_,
778                      OnCompositingLockStateChanged(this));
779  }
780  return compositor_lock_;
781}
782
783void Compositor::UnlockCompositor() {
784  DCHECK(compositor_lock_);
785  compositor_lock_ = NULL;
786  if (g_compositor_thread)
787    host_->SetDeferCommits(false);
788  FOR_EACH_OBSERVER(CompositorObserver,
789                    observer_list_,
790                    OnCompositingLockStateChanged(this));
791}
792
793void Compositor::CancelCompositorLock() {
794  if (compositor_lock_)
795    compositor_lock_->CancelLock();
796}
797
798void Compositor::NotifyEnd() {
799  last_ended_frame_++;
800  FOR_EACH_OBSERVER(CompositorObserver,
801                    observer_list_,
802                    OnCompositingEnded(this));
803}
804
805COMPOSITOR_EXPORT void SetupTestCompositor() {
806  if (!CommandLine::ForCurrentProcess()->HasSwitch(
807      switches::kDisableTestCompositor)) {
808    g_test_compositor_enabled = true;
809  }
810#if defined(OS_CHROMEOS)
811  // If the test is running on the chromeos envrionment (such as
812  // device or vm bots), use the real compositor.
813  if (base::chromeos::IsRunningOnChromeOS())
814    g_test_compositor_enabled = false;
815#endif
816  ResetImplicitFactory();
817}
818
819COMPOSITOR_EXPORT void DisableTestCompositor() {
820  ResetImplicitFactory();
821  g_test_compositor_enabled = false;
822}
823
824COMPOSITOR_EXPORT bool IsTestCompositorEnabled() {
825  return g_test_compositor_enabled;
826}
827
828}  // namespace ui
829