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