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