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