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