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