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