76b4413fc315d450318e67270b6cf7283b69d5fe
[platform/framework/web/crosswalk.git] / src / ui / compositor / compositor.cc
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/metrics/histogram.h"
16 #include "base/run_loop.h"
17 #include "base/strings/string_util.h"
18 #include "base/sys_info.h"
19 #include "base/threading/thread.h"
20 #include "base/threading/thread_restrictions.h"
21 #include "cc/base/latency_info_swap_promise.h"
22 #include "cc/base/switches.h"
23 #include "cc/input/input_handler.h"
24 #include "cc/layers/layer.h"
25 #include "cc/output/context_provider.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/compositor_vsync_manager.h"
31 #include "ui/compositor/dip_util.h"
32 #include "ui/compositor/layer.h"
33 #include "ui/gfx/frame_time.h"
34 #include "ui/gl/gl_context.h"
35 #include "ui/gl/gl_switches.h"
36
37 namespace {
38
39 const double kDefaultRefreshRate = 60.0;
40 const double kTestRefreshRate = 200.0;
41
42 enum SwapType {
43   DRAW_SWAP,
44 };
45
46 bool g_compositor_initialized = false;
47 base::Thread* g_compositor_thread = NULL;
48 cc::SharedBitmapManager* g_shared_bitmap_manager;
49
50 ui::ContextFactory* g_context_factory = NULL;
51
52 const int kCompositorLockTimeoutMs = 67;
53
54 class PendingSwap {
55  public:
56   PendingSwap(SwapType type, ui::PostedSwapQueue* posted_swaps);
57   ~PendingSwap();
58
59   SwapType type() const { return type_; }
60   bool posted() const { return posted_; }
61
62  private:
63   friend class ui::PostedSwapQueue;
64
65   SwapType type_;
66   bool posted_;
67   ui::PostedSwapQueue* posted_swaps_;
68
69   DISALLOW_COPY_AND_ASSIGN(PendingSwap);
70 };
71
72 }  // namespace
73
74 namespace ui {
75
76 // static
77 ContextFactory* ContextFactory::GetInstance() {
78   DCHECK(g_context_factory);
79   return g_context_factory;
80 }
81
82 // static
83 void ContextFactory::SetInstance(ContextFactory* instance) {
84   DCHECK_NE(!!g_context_factory, !!instance);
85   g_context_factory = instance;
86 }
87
88 Texture::Texture(bool flipped, const gfx::Size& size, float device_scale_factor)
89     : size_(size),
90       flipped_(flipped),
91       device_scale_factor_(device_scale_factor) {
92 }
93
94 Texture::~Texture() {
95 }
96
97 gpu::Mailbox Texture::Produce() {
98   return gpu::Mailbox();
99 }
100
101 CompositorLock::CompositorLock(Compositor* compositor)
102     : compositor_(compositor) {
103   base::MessageLoop::current()->PostDelayedTask(
104       FROM_HERE,
105       base::Bind(&CompositorLock::CancelLock, AsWeakPtr()),
106       base::TimeDelta::FromMilliseconds(kCompositorLockTimeoutMs));
107 }
108
109 CompositorLock::~CompositorLock() {
110   CancelLock();
111 }
112
113 void CompositorLock::CancelLock() {
114   if (!compositor_)
115     return;
116   compositor_->UnlockCompositor();
117   compositor_ = NULL;
118 }
119
120 class PostedSwapQueue {
121  public:
122   PostedSwapQueue() : pending_swap_(NULL) {
123   }
124
125   ~PostedSwapQueue() {
126     DCHECK(!pending_swap_);
127   }
128
129   SwapType NextPostedSwap() const {
130     return queue_.front();
131   }
132
133   bool AreSwapsPosted() const {
134     return !queue_.empty();
135   }
136
137   int NumSwapsPosted(SwapType type) const {
138     int count = 0;
139     for (std::deque<SwapType>::const_iterator it = queue_.begin();
140          it != queue_.end(); ++it) {
141       if (*it == type)
142         count++;
143     }
144     return count;
145   }
146
147   void PostSwap() {
148     DCHECK(pending_swap_);
149     queue_.push_back(pending_swap_->type());
150     pending_swap_->posted_ = true;
151   }
152
153   void EndSwap() {
154     queue_.pop_front();
155   }
156
157  private:
158   friend class ::PendingSwap;
159
160   PendingSwap* pending_swap_;
161   std::deque<SwapType> queue_;
162
163   DISALLOW_COPY_AND_ASSIGN(PostedSwapQueue);
164 };
165
166 }  // namespace ui
167
168 namespace {
169
170 PendingSwap::PendingSwap(SwapType type, ui::PostedSwapQueue* posted_swaps)
171     : type_(type), posted_(false), posted_swaps_(posted_swaps) {
172   // Only one pending swap in flight.
173   DCHECK_EQ(static_cast<PendingSwap*>(NULL), posted_swaps_->pending_swap_);
174   posted_swaps_->pending_swap_ = this;
175 }
176
177 PendingSwap::~PendingSwap() {
178   DCHECK_EQ(this, posted_swaps_->pending_swap_);
179   posted_swaps_->pending_swap_ = NULL;
180 }
181
182 }  // namespace
183
184 namespace ui {
185
186 Compositor::Compositor(gfx::AcceleratedWidget widget)
187     : root_layer_(NULL),
188       widget_(widget),
189       vsync_manager_(new CompositorVSyncManager()),
190       posted_swaps_(new PostedSwapQueue()),
191       device_scale_factor_(0.0f),
192       last_started_frame_(0),
193       last_ended_frame_(0),
194       next_draw_is_resize_(false),
195       disable_schedule_composite_(false),
196       compositor_lock_(NULL),
197       defer_draw_scheduling_(false),
198       waiting_on_compositing_end_(false),
199       draw_on_compositing_end_(false),
200       schedule_draw_factory_(this) {
201   DCHECK(g_compositor_initialized)
202       << "Compositor::Initialize must be called before creating a Compositor.";
203
204   root_web_layer_ = cc::Layer::Create();
205   root_web_layer_->SetAnchorPoint(gfx::PointF(0.f, 0.f));
206
207   CommandLine* command_line = CommandLine::ForCurrentProcess();
208
209   cc::LayerTreeSettings settings;
210   settings.refresh_rate =
211       ContextFactory::GetInstance()->DoesCreateTestContexts()
212       ? kTestRefreshRate
213       : kDefaultRefreshRate;
214   settings.main_frame_before_draw_enabled = false;
215   settings.main_frame_before_activation_enabled = false;
216   settings.partial_swap_enabled =
217       !command_line->HasSwitch(cc::switches::kUIDisablePartialSwap);
218 #if defined(OS_CHROMEOS)
219   settings.per_tile_painting_enabled = true;
220 #endif
221
222   // These flags should be mirrored by renderer versions in content/renderer/.
223   settings.initial_debug_state.show_debug_borders =
224       command_line->HasSwitch(cc::switches::kUIShowCompositedLayerBorders);
225   settings.initial_debug_state.show_fps_counter =
226       command_line->HasSwitch(cc::switches::kUIShowFPSCounter);
227   settings.initial_debug_state.show_layer_animation_bounds_rects =
228       command_line->HasSwitch(cc::switches::kUIShowLayerAnimationBounds);
229   settings.initial_debug_state.show_paint_rects =
230       command_line->HasSwitch(switches::kUIShowPaintRects);
231   settings.initial_debug_state.show_property_changed_rects =
232       command_line->HasSwitch(cc::switches::kUIShowPropertyChangedRects);
233   settings.initial_debug_state.show_surface_damage_rects =
234       command_line->HasSwitch(cc::switches::kUIShowSurfaceDamageRects);
235   settings.initial_debug_state.show_screen_space_rects =
236       command_line->HasSwitch(cc::switches::kUIShowScreenSpaceRects);
237   settings.initial_debug_state.show_replica_screen_space_rects =
238       command_line->HasSwitch(cc::switches::kUIShowReplicaScreenSpaceRects);
239   settings.initial_debug_state.show_occluding_rects =
240       command_line->HasSwitch(cc::switches::kUIShowOccludingRects);
241   settings.initial_debug_state.show_non_occluding_rects =
242       command_line->HasSwitch(cc::switches::kUIShowNonOccludingRects);
243
244   settings.initial_debug_state.SetRecordRenderingStats(
245       command_line->HasSwitch(cc::switches::kEnableGpuBenchmarking));
246
247   settings.impl_side_painting = IsUIImplSidePaintingEnabled();
248   settings.use_map_image = IsUIMapImageEnabled();
249
250   base::TimeTicks before_create = base::TimeTicks::Now();
251   if (!!g_compositor_thread) {
252     host_ = cc::LayerTreeHost::CreateThreaded(
253         this,
254         g_shared_bitmap_manager,
255         settings,
256         g_compositor_thread->message_loop_proxy());
257   } else {
258     host_ = cc::LayerTreeHost::CreateSingleThreaded(
259         this, this, g_shared_bitmap_manager, settings);
260   }
261   UMA_HISTOGRAM_TIMES("GPU.CreateBrowserCompositor",
262                       base::TimeTicks::Now() - before_create);
263   host_->SetRootLayer(root_web_layer_);
264   host_->SetLayerTreeHostClientReady();
265 }
266
267 Compositor::~Compositor() {
268   TRACE_EVENT0("shutdown", "Compositor::destructor");
269
270   DCHECK(g_compositor_initialized);
271
272   CancelCompositorLock();
273   DCHECK(!compositor_lock_);
274
275   if (root_layer_)
276     root_layer_->SetCompositor(NULL);
277
278   // Stop all outstanding draws before telling the ContextFactory to tear
279   // down any contexts that the |host_| may rely upon.
280   host_.reset();
281
282   ContextFactory::GetInstance()->RemoveCompositor(this);
283 }
284
285 // static
286 void Compositor::Initialize() {
287 #if defined(OS_CHROMEOS)
288   bool use_thread = !CommandLine::ForCurrentProcess()->HasSwitch(
289       switches::kUIDisableThreadedCompositing);
290 #else
291   bool use_thread = false;
292 #endif
293   if (use_thread) {
294     g_compositor_thread = new base::Thread("Browser Compositor");
295     g_compositor_thread->Start();
296   }
297
298   DCHECK(!g_compositor_initialized) << "Compositor initialized twice.";
299   g_compositor_initialized = true;
300 }
301
302 // static
303 bool Compositor::WasInitializedWithThread() {
304   DCHECK(g_compositor_initialized);
305   return !!g_compositor_thread;
306 }
307
308 // static
309 scoped_refptr<base::MessageLoopProxy> Compositor::GetCompositorMessageLoop() {
310   scoped_refptr<base::MessageLoopProxy> proxy;
311   if (g_compositor_thread)
312     proxy = g_compositor_thread->message_loop_proxy();
313   return proxy;
314 }
315
316 // static
317 void Compositor::Terminate() {
318   if (g_compositor_thread) {
319     g_compositor_thread->Stop();
320     delete g_compositor_thread;
321     g_compositor_thread = NULL;
322   }
323
324   DCHECK(g_compositor_initialized) << "Compositor::Initialize() didn't happen.";
325   g_compositor_initialized = false;
326 }
327
328 // static
329 void Compositor::SetSharedBitmapManager(cc::SharedBitmapManager* manager) {
330   g_shared_bitmap_manager = manager;
331 }
332
333 void Compositor::ScheduleDraw() {
334   if (g_compositor_thread) {
335     host_->Composite(gfx::FrameTime::Now());
336   } else if (!defer_draw_scheduling_) {
337     defer_draw_scheduling_ = true;
338     base::MessageLoop::current()->PostTask(
339         FROM_HERE,
340         base::Bind(&Compositor::Draw, schedule_draw_factory_.GetWeakPtr()));
341   }
342 }
343
344 void Compositor::SetRootLayer(Layer* root_layer) {
345   if (root_layer_ == root_layer)
346     return;
347   if (root_layer_)
348     root_layer_->SetCompositor(NULL);
349   root_layer_ = root_layer;
350   if (root_layer_ && !root_layer_->GetCompositor())
351     root_layer_->SetCompositor(this);
352   root_web_layer_->RemoveAllChildren();
353   if (root_layer_)
354     root_web_layer_->AddChild(root_layer_->cc_layer());
355 }
356
357 void Compositor::SetHostHasTransparentBackground(
358     bool host_has_transparent_background) {
359   host_->set_has_transparent_background(host_has_transparent_background);
360 }
361
362 void Compositor::Draw() {
363   DCHECK(!g_compositor_thread);
364
365   defer_draw_scheduling_ = false;
366   if (waiting_on_compositing_end_) {
367     draw_on_compositing_end_ = true;
368     return;
369   }
370   waiting_on_compositing_end_ = true;
371
372   TRACE_EVENT_ASYNC_BEGIN0("ui", "Compositor::Draw", last_started_frame_ + 1);
373
374   if (!root_layer_)
375     return;
376
377   last_started_frame_++;
378   PendingSwap pending_swap(DRAW_SWAP, posted_swaps_.get());
379   if (!IsLocked()) {
380     // TODO(nduca): Temporary while compositor calls
381     // compositeImmediately() directly.
382     Layout();
383     host_->Composite(gfx::FrameTime::Now());
384
385 #if defined(OS_WIN)
386     // While we resize, we are usually a few frames behind. By blocking
387     // the UI thread here we minize the area that is mis-painted, specially
388     // in the non-client area. See RenderWidgetHostViewAura::SetBounds for
389     // more details and bug 177115.
390     if (next_draw_is_resize_ && (last_ended_frame_ > 1)) {
391       next_draw_is_resize_ = false;
392       host_->FinishAllRendering();
393     }
394 #endif
395
396   }
397   if (!pending_swap.posted())
398     NotifyEnd();
399 }
400
401 void Compositor::ScheduleFullRedraw() {
402   host_->SetNeedsRedraw();
403 }
404
405 void Compositor::ScheduleRedrawRect(const gfx::Rect& damage_rect) {
406   host_->SetNeedsRedrawRect(damage_rect);
407 }
408
409 void Compositor::SetLatencyInfo(const ui::LatencyInfo& latency_info) {
410   scoped_ptr<cc::SwapPromise> swap_promise(
411       new cc::LatencyInfoSwapPromise(latency_info));
412   host_->QueueSwapPromise(swap_promise.Pass());
413 }
414
415 void Compositor::SetScaleAndSize(float scale, const gfx::Size& size_in_pixel) {
416   DCHECK_GT(scale, 0);
417   if (!size_in_pixel.IsEmpty()) {
418     size_ = size_in_pixel;
419     host_->SetViewportSize(size_in_pixel);
420     root_web_layer_->SetBounds(size_in_pixel);
421
422     next_draw_is_resize_ = true;
423   }
424   if (device_scale_factor_ != scale) {
425     device_scale_factor_ = scale;
426     if (root_layer_)
427       root_layer_->OnDeviceScaleFactorChanged(scale);
428   }
429 }
430
431 void Compositor::SetBackgroundColor(SkColor color) {
432   host_->set_background_color(color);
433   ScheduleDraw();
434 }
435
436 scoped_refptr<CompositorVSyncManager> Compositor::vsync_manager() const {
437   return vsync_manager_;
438 }
439
440 void Compositor::AddObserver(CompositorObserver* observer) {
441   observer_list_.AddObserver(observer);
442 }
443
444 void Compositor::RemoveObserver(CompositorObserver* observer) {
445   observer_list_.RemoveObserver(observer);
446 }
447
448 bool Compositor::HasObserver(CompositorObserver* observer) {
449   return observer_list_.HasObserver(observer);
450 }
451
452 void Compositor::Layout() {
453   // We're sending damage that will be addressed during this composite
454   // cycle, so we don't need to schedule another composite to address it.
455   disable_schedule_composite_ = true;
456   if (root_layer_)
457     root_layer_->SendDamagedRects();
458   disable_schedule_composite_ = false;
459 }
460
461 scoped_ptr<cc::OutputSurface> Compositor::CreateOutputSurface(bool fallback) {
462   return ContextFactory::GetInstance()->CreateOutputSurface(this, fallback);
463 }
464
465 void Compositor::DidCommit() {
466   DCHECK(!IsLocked());
467   FOR_EACH_OBSERVER(CompositorObserver,
468                     observer_list_,
469                     OnCompositingDidCommit(this));
470 }
471
472 void Compositor::DidCommitAndDrawFrame() {
473   base::TimeTicks start_time = gfx::FrameTime::Now();
474   FOR_EACH_OBSERVER(CompositorObserver,
475                     observer_list_,
476                     OnCompositingStarted(this, start_time));
477 }
478
479 void Compositor::DidCompleteSwapBuffers() {
480   if (g_compositor_thread) {
481     NotifyEnd();
482   } else {
483     DCHECK(posted_swaps_->AreSwapsPosted());
484     DCHECK_GE(1, posted_swaps_->NumSwapsPosted(DRAW_SWAP));
485     if (posted_swaps_->NextPostedSwap() == DRAW_SWAP)
486       NotifyEnd();
487     posted_swaps_->EndSwap();
488   }
489 }
490
491 scoped_refptr<cc::ContextProvider> Compositor::OffscreenContextProvider() {
492   return ContextFactory::GetInstance()->OffscreenCompositorContextProvider();
493 }
494
495 void Compositor::ScheduleComposite() {
496   if (!disable_schedule_composite_)
497     ScheduleDraw();
498 }
499
500 void Compositor::ScheduleAnimation() {
501   ScheduleComposite();
502 }
503
504 void Compositor::DidPostSwapBuffers() {
505   DCHECK(!g_compositor_thread);
506   posted_swaps_->PostSwap();
507 }
508
509 void Compositor::DidAbortSwapBuffers() {
510   if (!g_compositor_thread) {
511     DCHECK_GE(1, posted_swaps_->NumSwapsPosted(DRAW_SWAP));
512
513     // We've just lost the context, so unwind all posted_swaps.
514     while (posted_swaps_->AreSwapsPosted()) {
515       if (posted_swaps_->NextPostedSwap() == DRAW_SWAP)
516         NotifyEnd();
517       posted_swaps_->EndSwap();
518     }
519   }
520
521   FOR_EACH_OBSERVER(CompositorObserver,
522                     observer_list_,
523                     OnCompositingAborted(this));
524 }
525
526 const cc::LayerTreeDebugState& Compositor::GetLayerTreeDebugState() const {
527   return host_->debug_state();
528 }
529
530 void Compositor::SetLayerTreeDebugState(
531     const cc::LayerTreeDebugState& debug_state) {
532   host_->SetDebugState(debug_state);
533 }
534
535 scoped_refptr<CompositorLock> Compositor::GetCompositorLock() {
536   if (!compositor_lock_) {
537     compositor_lock_ = new CompositorLock(this);
538     if (g_compositor_thread)
539       host_->SetDeferCommits(true);
540     FOR_EACH_OBSERVER(CompositorObserver,
541                       observer_list_,
542                       OnCompositingLockStateChanged(this));
543   }
544   return compositor_lock_;
545 }
546
547 void Compositor::UnlockCompositor() {
548   DCHECK(compositor_lock_);
549   compositor_lock_ = NULL;
550   if (g_compositor_thread)
551     host_->SetDeferCommits(false);
552   FOR_EACH_OBSERVER(CompositorObserver,
553                     observer_list_,
554                     OnCompositingLockStateChanged(this));
555 }
556
557 void Compositor::CancelCompositorLock() {
558   if (compositor_lock_)
559     compositor_lock_->CancelLock();
560 }
561
562 void Compositor::NotifyEnd() {
563   last_ended_frame_++;
564   TRACE_EVENT_ASYNC_END0("ui", "Compositor::Draw", last_ended_frame_);
565   waiting_on_compositing_end_ = false;
566   if (draw_on_compositing_end_) {
567     draw_on_compositing_end_ = false;
568
569     // Call ScheduleDraw() instead of Draw() in order to allow other
570     // CompositorObservers to be notified before starting another
571     // draw cycle.
572     ScheduleDraw();
573   }
574   FOR_EACH_OBSERVER(CompositorObserver,
575                     observer_list_,
576                     OnCompositingEnded(this));
577 }
578
579 }  // namespace ui