compositor.cc revision ca12bfac764ba476d6cd062bf1dde12cc64c3f40
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ui/compositor/compositor.h"
6
7#include <algorithm>
8#include <deque>
9
10#include "base/bind.h"
11#include "base/command_line.h"
12#include "base/memory/singleton.h"
13#include "base/message_loop/message_loop.h"
14#include "base/run_loop.h"
15#include "base/strings/string_util.h"
16#include "base/threading/thread.h"
17#include "base/threading/thread_restrictions.h"
18#include "cc/base/switches.h"
19#include "cc/input/input_handler.h"
20#include "cc/layers/layer.h"
21#include "cc/output/context_provider.h"
22#include "cc/output/output_surface.h"
23#include "cc/trees/layer_tree_host.h"
24#include "third_party/skia/include/core/SkBitmap.h"
25#include "ui/compositor/compositor_observer.h"
26#include "ui/compositor/compositor_switches.h"
27#include "ui/compositor/dip_util.h"
28#include "ui/compositor/layer.h"
29#include "ui/compositor/test_web_graphics_context_3d.h"
30#include "ui/gl/gl_context.h"
31#include "ui/gl/gl_implementation.h"
32#include "ui/gl/gl_surface.h"
33#include "ui/gl/gl_switches.h"
34#include "webkit/common/gpu/grcontext_for_webgraphicscontext3d.h"
35#include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h"
36
37#if defined(OS_CHROMEOS)
38#include "base/chromeos/chromeos_version.h"
39#endif
40
41namespace {
42
43const double kDefaultRefreshRate = 60.0;
44const double kTestRefreshRate = 200.0;
45
46enum SwapType {
47  DRAW_SWAP,
48  READPIXELS_SWAP,
49};
50
51base::Thread* g_compositor_thread = NULL;
52
53bool g_test_compositor_enabled = false;
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
78void SetupImplicitFactory() {
79  // We leak the implicit factory so that we don't race with the tear down of
80  // the gl_bindings.
81  DCHECK(!g_context_factory);
82  DCHECK(!g_implicit_factory);
83  if (g_test_compositor_enabled) {
84    g_implicit_factory = new ui::TestContextFactory;
85  } else {
86    DVLOG(1) << "Using DefaultContextFactory";
87    scoped_ptr<ui::DefaultContextFactory> instance(
88        new ui::DefaultContextFactory());
89    if (instance->Initialize())
90      g_implicit_factory = instance.release();
91  }
92  g_context_factory = g_implicit_factory;
93}
94
95void ResetImplicitFactory() {
96  if (!g_implicit_factory || g_context_factory != g_implicit_factory)
97    return;
98  delete g_implicit_factory;
99  g_implicit_factory = NULL;
100  g_context_factory = NULL;
101}
102
103}  // namespace
104
105namespace ui {
106
107// static
108ContextFactory* ContextFactory::GetInstance() {
109  if (!g_context_factory)
110    SetupImplicitFactory();
111  return g_context_factory;
112}
113
114// static
115void ContextFactory::SetInstance(ContextFactory* instance) {
116  g_context_factory = instance;
117}
118
119class ContextProviderFromContextFactory : public cc::ContextProvider {
120 public:
121  static scoped_refptr<ContextProviderFromContextFactory> Create(
122      ContextFactory* factory) {
123    scoped_refptr<ContextProviderFromContextFactory> provider =
124        new ContextProviderFromContextFactory(factory);
125    if (!provider->InitializeOnMainThread())
126      return NULL;
127    return provider;
128  }
129
130  virtual bool BindToCurrentThread() OVERRIDE {
131    DCHECK(context3d_);
132
133    return context3d_->makeContextCurrent();
134  }
135
136  virtual WebKit::WebGraphicsContext3D* Context3d() OVERRIDE {
137    DCHECK(context3d_);
138
139    return context3d_.get();
140  }
141
142  virtual class GrContext* GrContext() OVERRIDE {
143    DCHECK(context3d_);
144
145    if (!gr_context_) {
146      gr_context_.reset(
147          new webkit::gpu::GrContextForWebGraphicsContext3D(context3d_.get()));
148    }
149    return gr_context_->get();
150  }
151
152  virtual void VerifyContexts() OVERRIDE {
153    DCHECK(context3d_);
154
155    if (context3d_->isContextLost()) {
156      base::AutoLock lock(destroyed_lock_);
157      destroyed_ = true;
158    }
159  }
160
161  virtual bool DestroyedOnMainThread() OVERRIDE {
162    base::AutoLock lock(destroyed_lock_);
163    return destroyed_;
164  }
165
166 protected:
167  explicit ContextProviderFromContextFactory(ContextFactory* factory)
168      : factory_(factory),
169        destroyed_(false) {}
170  virtual ~ContextProviderFromContextFactory() {}
171
172  bool InitializeOnMainThread() {
173    if (context3d_)
174      return true;
175    context3d_ = factory_->CreateOffscreenContext();
176    return !!context3d_;
177  }
178
179 private:
180  ContextFactory* factory_;
181  base::Lock destroyed_lock_;
182  bool destroyed_;
183  scoped_ptr<WebKit::WebGraphicsContext3D> context3d_;
184  scoped_ptr<webkit::gpu::GrContextForWebGraphicsContext3D> gr_context_;
185};
186
187DefaultContextFactory::DefaultContextFactory() {
188}
189
190DefaultContextFactory::~DefaultContextFactory() {
191}
192
193bool DefaultContextFactory::Initialize() {
194  if (!gfx::GLSurface::InitializeOneOff() ||
195      gfx::GetGLImplementation() == gfx::kGLImplementationNone) {
196    LOG(ERROR) << "Could not load the GL bindings";
197    return false;
198  }
199  return true;
200}
201
202cc::OutputSurface* DefaultContextFactory::CreateOutputSurface(
203    Compositor* compositor) {
204  return new cc::OutputSurface(CreateContextCommon(compositor, false).Pass());
205}
206
207scoped_ptr<WebKit::WebGraphicsContext3D>
208DefaultContextFactory::CreateOffscreenContext() {
209  return CreateContextCommon(NULL, true);
210}
211
212scoped_refptr<Reflector> DefaultContextFactory::CreateReflector(
213    Compositor* mirroed_compositor,
214    Layer* mirroring_layer) {
215  return NULL;
216}
217
218void DefaultContextFactory::RemoveReflector(
219    scoped_refptr<Reflector> reflector) {
220}
221
222scoped_refptr<cc::ContextProvider>
223DefaultContextFactory::OffscreenContextProviderForMainThread() {
224  if (!offscreen_contexts_main_thread_.get() ||
225      !offscreen_contexts_main_thread_->DestroyedOnMainThread()) {
226    offscreen_contexts_main_thread_ =
227        ContextProviderFromContextFactory::Create(this);
228    if (offscreen_contexts_main_thread_.get() &&
229        !offscreen_contexts_main_thread_->BindToCurrentThread())
230      offscreen_contexts_main_thread_ = NULL;
231  }
232  return offscreen_contexts_main_thread_;
233}
234
235scoped_refptr<cc::ContextProvider>
236DefaultContextFactory::OffscreenContextProviderForCompositorThread() {
237  if (!offscreen_contexts_compositor_thread_.get() ||
238      !offscreen_contexts_compositor_thread_->DestroyedOnMainThread()) {
239    offscreen_contexts_compositor_thread_ =
240        ContextProviderFromContextFactory::Create(this);
241  }
242  return offscreen_contexts_compositor_thread_;
243}
244
245void DefaultContextFactory::RemoveCompositor(Compositor* compositor) {
246}
247
248scoped_ptr<WebKit::WebGraphicsContext3D>
249DefaultContextFactory::CreateContextCommon(Compositor* compositor,
250                                           bool offscreen) {
251  DCHECK(offscreen || compositor);
252  WebKit::WebGraphicsContext3D::Attributes attrs;
253  attrs.depth = false;
254  attrs.stencil = false;
255  attrs.antialias = false;
256  attrs.shareResources = true;
257  using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl;
258  if (offscreen) {
259    return WebGraphicsContext3DInProcessCommandBufferImpl::
260        CreateOffscreenContext(attrs);
261  }
262  return WebGraphicsContext3DInProcessCommandBufferImpl::CreateViewContext(
263      attrs, compositor->widget());
264}
265
266TestContextFactory::TestContextFactory() {}
267
268TestContextFactory::~TestContextFactory() {}
269
270cc::OutputSurface* TestContextFactory::CreateOutputSurface(
271    Compositor* compositor) {
272  return new cc::OutputSurface(CreateOffscreenContext());
273}
274
275scoped_ptr<WebKit::WebGraphicsContext3D>
276TestContextFactory::CreateOffscreenContext() {
277  scoped_ptr<ui::TestWebGraphicsContext3D> context(
278      new ui::TestWebGraphicsContext3D);
279  context->Initialize();
280  return context.PassAs<WebKit::WebGraphicsContext3D>();
281}
282
283scoped_refptr<Reflector> TestContextFactory::CreateReflector(
284    Compositor* mirrored_compositor,
285    Layer* mirroring_layer) {
286  return new Reflector();
287}
288
289void TestContextFactory::RemoveReflector(scoped_refptr<Reflector> reflector) {
290}
291
292scoped_refptr<cc::ContextProvider>
293TestContextFactory::OffscreenContextProviderForMainThread() {
294  if (!offscreen_contexts_main_thread_.get() ||
295      offscreen_contexts_main_thread_->DestroyedOnMainThread()) {
296    offscreen_contexts_main_thread_ =
297        ContextProviderFromContextFactory::Create(this);
298    CHECK(offscreen_contexts_main_thread_->BindToCurrentThread());
299  }
300  return offscreen_contexts_main_thread_;
301}
302
303scoped_refptr<cc::ContextProvider>
304TestContextFactory::OffscreenContextProviderForCompositorThread() {
305  if (!offscreen_contexts_compositor_thread_.get() ||
306      offscreen_contexts_compositor_thread_->DestroyedOnMainThread()) {
307    offscreen_contexts_compositor_thread_ =
308        ContextProviderFromContextFactory::Create(this);
309  }
310  return offscreen_contexts_compositor_thread_;
311}
312
313void TestContextFactory::RemoveCompositor(Compositor* compositor) {
314}
315
316Texture::Texture(bool flipped, const gfx::Size& size, float device_scale_factor)
317    : size_(size),
318      flipped_(flipped),
319      device_scale_factor_(device_scale_factor) {
320}
321
322Texture::~Texture() {
323}
324
325std::string Texture::Produce() {
326  return EmptyString();
327}
328
329CompositorLock::CompositorLock(Compositor* compositor)
330    : compositor_(compositor) {
331  base::MessageLoop::current()->PostDelayedTask(
332      FROM_HERE,
333      base::Bind(&CompositorLock::CancelLock, AsWeakPtr()),
334      base::TimeDelta::FromMilliseconds(kCompositorLockTimeoutMs));
335}
336
337CompositorLock::~CompositorLock() {
338  CancelLock();
339}
340
341void CompositorLock::CancelLock() {
342  if (!compositor_)
343    return;
344  compositor_->UnlockCompositor();
345  compositor_ = NULL;
346}
347
348// static
349void DrawWaiterForTest::Wait(Compositor* compositor) {
350  DrawWaiterForTest waiter;
351  waiter.wait_for_commit_ = false;
352  waiter.WaitImpl(compositor);
353}
354
355// static
356void DrawWaiterForTest::WaitForCommit(Compositor* compositor) {
357  DrawWaiterForTest waiter;
358  waiter.wait_for_commit_ = true;
359  waiter.WaitImpl(compositor);
360}
361
362DrawWaiterForTest::DrawWaiterForTest() {
363}
364
365DrawWaiterForTest::~DrawWaiterForTest() {
366}
367
368void DrawWaiterForTest::WaitImpl(Compositor* compositor) {
369  compositor->AddObserver(this);
370  wait_run_loop_.reset(new base::RunLoop());
371  wait_run_loop_->Run();
372  compositor->RemoveObserver(this);
373}
374
375void DrawWaiterForTest::OnCompositingDidCommit(Compositor* compositor) {
376  if (wait_for_commit_)
377    wait_run_loop_->Quit();
378}
379
380void DrawWaiterForTest::OnCompositingStarted(Compositor* compositor,
381                                             base::TimeTicks start_time) {
382}
383
384void DrawWaiterForTest::OnCompositingEnded(Compositor* compositor) {
385  if (!wait_for_commit_)
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_property_changed_rects =
501      command_line->HasSwitch(cc::switches::kUIShowPropertyChangedRects);
502  settings.initial_debug_state.show_surface_damage_rects =
503      command_line->HasSwitch(cc::switches::kUIShowSurfaceDamageRects);
504  settings.initial_debug_state.show_screen_space_rects =
505      command_line->HasSwitch(cc::switches::kUIShowScreenSpaceRects);
506  settings.initial_debug_state.show_replica_screen_space_rects =
507      command_line->HasSwitch(cc::switches::kUIShowReplicaScreenSpaceRects);
508  settings.initial_debug_state.show_occluding_rects =
509      command_line->HasSwitch(cc::switches::kUIShowOccludingRects);
510  settings.initial_debug_state.show_non_occluding_rects =
511      command_line->HasSwitch(cc::switches::kUIShowNonOccludingRects);
512
513  scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner =
514      g_compositor_thread ? g_compositor_thread->message_loop_proxy() : NULL;
515
516  host_ = cc::LayerTreeHost::Create(this, settings, compositor_task_runner);
517  host_->SetRootLayer(root_web_layer_);
518  host_->SetLayerTreeHostClientReady();
519}
520
521Compositor::~Compositor() {
522  CancelCompositorLock();
523  DCHECK(!compositor_lock_);
524
525  // Don't call |CompositorDelegate::ScheduleDraw| from this point.
526  delegate_ = NULL;
527  if (root_layer_)
528    root_layer_->SetCompositor(NULL);
529
530  // Stop all outstanding draws before telling the ContextFactory to tear
531  // down any contexts that the |host_| may rely upon.
532  host_.reset();
533
534  ContextFactory::GetInstance()->RemoveCompositor(this);
535}
536
537// static
538void Compositor::Initialize() {
539#if defined(OS_CHROMEOS)
540  bool use_thread = !CommandLine::ForCurrentProcess()->HasSwitch(
541      switches::kUIDisableThreadedCompositing);
542#else
543  bool use_thread =
544      CommandLine::ForCurrentProcess()->HasSwitch(
545          switches::kUIEnableThreadedCompositing) &&
546      !CommandLine::ForCurrentProcess()->HasSwitch(
547          switches::kUIDisableThreadedCompositing);
548#endif
549  if (use_thread) {
550    g_compositor_thread = new base::Thread("Browser Compositor");
551    g_compositor_thread->Start();
552  }
553}
554
555// static
556bool Compositor::WasInitializedWithThread() {
557  return !!g_compositor_thread;
558}
559
560// static
561scoped_refptr<base::MessageLoopProxy> Compositor::GetCompositorMessageLoop() {
562  scoped_refptr<base::MessageLoopProxy> proxy;
563  if (g_compositor_thread)
564    proxy = g_compositor_thread->message_loop_proxy();
565  return proxy;
566}
567
568// static
569void Compositor::Terminate() {
570  if (g_compositor_thread) {
571    g_compositor_thread->Stop();
572    delete g_compositor_thread;
573    g_compositor_thread = NULL;
574  }
575}
576
577void Compositor::ScheduleDraw() {
578  if (g_compositor_thread)
579    host_->Composite(base::TimeTicks::Now());
580  else if (delegate_)
581    delegate_->ScheduleDraw();
582}
583
584void Compositor::SetRootLayer(Layer* root_layer) {
585  if (root_layer_ == root_layer)
586    return;
587  if (root_layer_)
588    root_layer_->SetCompositor(NULL);
589  root_layer_ = root_layer;
590  if (root_layer_ && !root_layer_->GetCompositor())
591    root_layer_->SetCompositor(this);
592  root_web_layer_->RemoveAllChildren();
593  if (root_layer_)
594    root_web_layer_->AddChild(root_layer_->cc_layer());
595}
596
597void Compositor::SetHostHasTransparentBackground(
598    bool host_has_transparent_background) {
599  host_->set_has_transparent_background(host_has_transparent_background);
600}
601
602void Compositor::Draw() {
603  DCHECK(!g_compositor_thread);
604
605  if (!root_layer_)
606    return;
607
608  last_started_frame_++;
609  PendingSwap pending_swap(DRAW_SWAP, posted_swaps_.get());
610  if (!IsLocked()) {
611    // TODO(nduca): Temporary while compositor calls
612    // compositeImmediately() directly.
613    Layout();
614    host_->Composite(base::TimeTicks::Now());
615
616#if defined(OS_WIN)
617    // While we resize, we are usually a few frames behind. By blocking
618    // the UI thread here we minize the area that is mis-painted, specially
619    // in the non-client area. See RenderWidgetHostViewAura::SetBounds for
620    // more details and bug 177115.
621    if (next_draw_is_resize_ && (last_ended_frame_ > 1)) {
622      next_draw_is_resize_ = false;
623      host_->FinishAllRendering();
624    }
625#endif
626
627  }
628  if (!pending_swap.posted())
629    NotifyEnd();
630}
631
632void Compositor::ScheduleFullRedraw() {
633  host_->SetNeedsRedraw();
634}
635
636void Compositor::ScheduleRedrawRect(const gfx::Rect& damage_rect) {
637  host_->SetNeedsRedrawRect(damage_rect);
638}
639
640void Compositor::SetLatencyInfo(const ui::LatencyInfo& latency_info) {
641  host_->SetLatencyInfo(latency_info);
642}
643
644bool Compositor::ReadPixels(SkBitmap* bitmap,
645                            const gfx::Rect& bounds_in_pixel) {
646  if (bounds_in_pixel.right() > size().width() ||
647      bounds_in_pixel.bottom() > size().height())
648    return false;
649  bitmap->setConfig(SkBitmap::kARGB_8888_Config,
650                    bounds_in_pixel.width(), bounds_in_pixel.height());
651  bitmap->allocPixels();
652  SkAutoLockPixels lock_image(*bitmap);
653  unsigned char* pixels = static_cast<unsigned char*>(bitmap->getPixels());
654  CancelCompositorLock();
655  PendingSwap pending_swap(READPIXELS_SWAP, posted_swaps_.get());
656  return host_->CompositeAndReadback(pixels, bounds_in_pixel);
657}
658
659void Compositor::SetScaleAndSize(float scale, const gfx::Size& size_in_pixel) {
660  DCHECK_GT(scale, 0);
661  if (!size_in_pixel.IsEmpty()) {
662    size_ = size_in_pixel;
663    host_->SetViewportSize(size_in_pixel);
664    root_web_layer_->SetBounds(size_in_pixel);
665
666    next_draw_is_resize_ = true;
667  }
668  if (device_scale_factor_ != scale) {
669    device_scale_factor_ = scale;
670    if (root_layer_)
671      root_layer_->OnDeviceScaleFactorChanged(scale);
672  }
673}
674
675void Compositor::SetBackgroundColor(SkColor color) {
676  host_->set_background_color(color);
677  ScheduleDraw();
678}
679
680void Compositor::AddObserver(CompositorObserver* observer) {
681  observer_list_.AddObserver(observer);
682}
683
684void Compositor::RemoveObserver(CompositorObserver* observer) {
685  observer_list_.RemoveObserver(observer);
686}
687
688bool Compositor::HasObserver(CompositorObserver* observer) {
689  return observer_list_.HasObserver(observer);
690}
691
692void Compositor::OnSwapBuffersPosted() {
693  DCHECK(!g_compositor_thread);
694  posted_swaps_->PostSwap();
695}
696
697void Compositor::OnSwapBuffersComplete() {
698  DCHECK(!g_compositor_thread);
699  DCHECK(posted_swaps_->AreSwapsPosted());
700  DCHECK_GE(1, posted_swaps_->NumSwapsPosted(DRAW_SWAP));
701  if (posted_swaps_->NextPostedSwap() == DRAW_SWAP)
702    NotifyEnd();
703  posted_swaps_->EndSwap();
704}
705
706void Compositor::OnSwapBuffersAborted() {
707  if (!g_compositor_thread) {
708    DCHECK_GE(1, posted_swaps_->NumSwapsPosted(DRAW_SWAP));
709
710    // We've just lost the context, so unwind all posted_swaps.
711    while (posted_swaps_->AreSwapsPosted()) {
712      if (posted_swaps_->NextPostedSwap() == DRAW_SWAP)
713        NotifyEnd();
714      posted_swaps_->EndSwap();
715    }
716  }
717
718  FOR_EACH_OBSERVER(CompositorObserver,
719                    observer_list_,
720                    OnCompositingAborted(this));
721}
722
723void Compositor::OnUpdateVSyncParameters(base::TimeTicks timebase,
724                                         base::TimeDelta interval) {
725  FOR_EACH_OBSERVER(CompositorObserver,
726                    observer_list_,
727                    OnUpdateVSyncParameters(this, timebase, interval));
728}
729
730void Compositor::Layout() {
731  // We're sending damage that will be addressed during this composite
732  // cycle, so we don't need to schedule another composite to address it.
733  disable_schedule_composite_ = true;
734  if (root_layer_)
735    root_layer_->SendDamagedRects();
736  disable_schedule_composite_ = false;
737}
738
739scoped_ptr<cc::OutputSurface> Compositor::CreateOutputSurface() {
740  return make_scoped_ptr(
741      ContextFactory::GetInstance()->CreateOutputSurface(this));
742}
743
744void Compositor::DidCommit() {
745  DCHECK(!IsLocked());
746  FOR_EACH_OBSERVER(CompositorObserver,
747                    observer_list_,
748                    OnCompositingDidCommit(this));
749}
750
751void Compositor::DidCommitAndDrawFrame() {
752  base::TimeTicks start_time = base::TimeTicks::Now();
753  FOR_EACH_OBSERVER(CompositorObserver,
754                    observer_list_,
755                    OnCompositingStarted(this, start_time));
756}
757
758void Compositor::DidCompleteSwapBuffers() {
759  DCHECK(g_compositor_thread);
760  NotifyEnd();
761}
762
763void Compositor::ScheduleComposite() {
764  if (!disable_schedule_composite_)
765    ScheduleDraw();
766}
767
768scoped_refptr<cc::ContextProvider>
769Compositor::OffscreenContextProviderForMainThread() {
770  return ContextFactory::GetInstance()->OffscreenContextProviderForMainThread();
771}
772
773scoped_refptr<cc::ContextProvider>
774Compositor::OffscreenContextProviderForCompositorThread() {
775  return ContextFactory::GetInstance()->
776      OffscreenContextProviderForCompositorThread();
777}
778
779const cc::LayerTreeDebugState& Compositor::GetLayerTreeDebugState() const {
780  return host_->debug_state();
781}
782
783void Compositor::SetLayerTreeDebugState(
784    const cc::LayerTreeDebugState& debug_state) {
785  host_->SetDebugState(debug_state);
786}
787
788scoped_refptr<CompositorLock> Compositor::GetCompositorLock() {
789  if (!compositor_lock_) {
790    compositor_lock_ = new CompositorLock(this);
791    if (g_compositor_thread)
792      host_->SetDeferCommits(true);
793    FOR_EACH_OBSERVER(CompositorObserver,
794                      observer_list_,
795                      OnCompositingLockStateChanged(this));
796  }
797  return compositor_lock_;
798}
799
800void Compositor::UnlockCompositor() {
801  DCHECK(compositor_lock_);
802  compositor_lock_ = NULL;
803  if (g_compositor_thread)
804    host_->SetDeferCommits(false);
805  FOR_EACH_OBSERVER(CompositorObserver,
806                    observer_list_,
807                    OnCompositingLockStateChanged(this));
808}
809
810void Compositor::CancelCompositorLock() {
811  if (compositor_lock_)
812    compositor_lock_->CancelLock();
813}
814
815void Compositor::NotifyEnd() {
816  last_ended_frame_++;
817  FOR_EACH_OBSERVER(CompositorObserver,
818                    observer_list_,
819                    OnCompositingEnded(this));
820}
821
822COMPOSITOR_EXPORT void SetupTestCompositor() {
823  if (!CommandLine::ForCurrentProcess()->HasSwitch(
824      switches::kDisableTestCompositor)) {
825    g_test_compositor_enabled = true;
826  }
827#if defined(OS_CHROMEOS)
828  // If the test is running on the chromeos envrionment (such as
829  // device or vm bots), use the real compositor.
830  if (base::chromeos::IsRunningOnChromeOS())
831    g_test_compositor_enabled = false;
832#endif
833  ResetImplicitFactory();
834}
835
836COMPOSITOR_EXPORT void DisableTestCompositor() {
837  ResetImplicitFactory();
838  g_test_compositor_enabled = false;
839}
840
841COMPOSITOR_EXPORT bool IsTestCompositorEnabled() {
842  return g_test_compositor_enabled;
843}
844
845}  // namespace ui
846