compositor.cc revision 010d83a9304c5a91596085d917d248abff47903a
1410ffb2bc5f072d58a73c14560345bcf77dec1ccJohn McCall// Copyright (c) 2012 The Chromium Authors. All rights reserved.
24de9fce48e42cc7ec1345c0fd21b3dbc5b9114c8Anders Carlsson// Use of this source code is governed by a BSD-style license that can be
3a17d7ccc2ed77e321855990e180f2a34ec304bfcAnders Carlsson// found in the LICENSE file.
4a17d7ccc2ed77e321855990e180f2a34ec304bfcAnders Carlsson
5a17d7ccc2ed77e321855990e180f2a34ec304bfcAnders Carlsson#include "ui/compositor/compositor.h"
6a17d7ccc2ed77e321855990e180f2a34ec304bfcAnders Carlsson
7a17d7ccc2ed77e321855990e180f2a34ec304bfcAnders Carlsson#include <algorithm>
80e4f40e1bbc4dce16bbb9870300a435419f1b3d5Daniel Dunbar#include <deque>
90e4f40e1bbc4dce16bbb9870300a435419f1b3d5Daniel Dunbar
100e4f40e1bbc4dce16bbb9870300a435419f1b3d5Daniel Dunbar#include "base/bind.h"
110e4f40e1bbc4dce16bbb9870300a435419f1b3d5Daniel Dunbar#include "base/command_line.h"
120e4f40e1bbc4dce16bbb9870300a435419f1b3d5Daniel Dunbar#include "base/debug/trace_event.h"
130e4f40e1bbc4dce16bbb9870300a435419f1b3d5Daniel Dunbar#include "base/memory/singleton.h"
140e4f40e1bbc4dce16bbb9870300a435419f1b3d5Daniel Dunbar#include "base/message_loop/message_loop.h"
15c1ea4b96adca4767991bb0a7b21052cef4db059cBill Wendling#include "base/metrics/histogram.h"
160e4f40e1bbc4dce16bbb9870300a435419f1b3d5Daniel Dunbar#include "base/run_loop.h"
170e4f40e1bbc4dce16bbb9870300a435419f1b3d5Daniel Dunbar#include "base/strings/string_util.h"
180e4f40e1bbc4dce16bbb9870300a435419f1b3d5Daniel Dunbar#include "base/sys_info.h"
190e4f40e1bbc4dce16bbb9870300a435419f1b3d5Daniel Dunbar#include "base/threading/thread.h"
20f1c97eb52e55d2d1340a0345ed91e345fddcb65dChris Lattner#include "base/threading/thread_restrictions.h"
21f1c97eb52e55d2d1340a0345ed91e345fddcb65dChris Lattner#include "cc/base/latency_info_swap_promise.h"
22f1c97eb52e55d2d1340a0345ed91e345fddcb65dChris Lattner#include "cc/base/switches.h"
23f1c97eb52e55d2d1340a0345ed91e345fddcb65dChris Lattner#include "cc/input/input_handler.h"
24f1c97eb52e55d2d1340a0345ed91e345fddcb65dChris Lattner#include "cc/layers/layer.h"
25dd2fb9c5ebc02f48a5b91a9c2a5f1e4562d02a0bMike Stump#include "cc/output/context_provider.h"
26dd2fb9c5ebc02f48a5b91a9c2a5f1e4562d02a0bMike Stump#include "cc/trees/layer_tree_host.h"
27dd2fb9c5ebc02f48a5b91a9c2a5f1e4562d02a0bMike Stump#include "third_party/skia/include/core/SkBitmap.h"
28dd2fb9c5ebc02f48a5b91a9c2a5f1e4562d02a0bMike Stump#include "ui/compositor/compositor_observer.h"
29f1c97eb52e55d2d1340a0345ed91e345fddcb65dChris Lattner#include "ui/compositor/compositor_switches.h"
30c71a4915ca216847599d03cab4ed1c5086b0eb43John McCall#include "ui/compositor/compositor_vsync_manager.h"
31c71a4915ca216847599d03cab4ed1c5086b0eb43John McCall#include "ui/compositor/dip_util.h"
32c71a4915ca216847599d03cab4ed1c5086b0eb43John McCall#include "ui/compositor/layer.h"
33c71a4915ca216847599d03cab4ed1c5086b0eb43John McCall#include "ui/gfx/frame_time.h"
34c71a4915ca216847599d03cab4ed1c5086b0eb43John McCall#include "ui/gl/gl_context.h"
35c71a4915ca216847599d03cab4ed1c5086b0eb43John McCall#include "ui/gl/gl_switches.h"
3646ec70e2e6541a067d33b2513505bec74582b53cJohn McCall
3746ec70e2e6541a067d33b2513505bec74582b53cJohn McCallnamespace {
3846ec70e2e6541a067d33b2513505bec74582b53cJohn McCall
3946ec70e2e6541a067d33b2513505bec74582b53cJohn McCallconst double kDefaultRefreshRate = 60.0;
4046ec70e2e6541a067d33b2513505bec74582b53cJohn McCallconst double kTestRefreshRate = 200.0;
4146ec70e2e6541a067d33b2513505bec74582b53cJohn McCall
4246ec70e2e6541a067d33b2513505bec74582b53cJohn McCallbool g_compositor_initialized = false;
436ea4841da1390b4f76d066f25333f11f6d8c5f40John McCallbase::Thread* g_compositor_thread = NULL;
446ea4841da1390b4f76d066f25333f11f6d8c5f40John McCall
456c803f7f46533c69e2f8a9a882af9ae3b7fffb6fJohn McCallui::ContextFactory* g_context_factory = NULL;
466c803f7f46533c69e2f8a9a882af9ae3b7fffb6fJohn McCall
476ea4841da1390b4f76d066f25333f11f6d8c5f40John McCallconst int kCompositorLockTimeoutMs = 67;
4893ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Lin
496ea4841da1390b4f76d066f25333f11f6d8c5f40John McCall}  // namespace
506ea4841da1390b4f76d066f25333f11f6d8c5f40John McCall
516ea4841da1390b4f76d066f25333f11f6d8c5f40John McCallnamespace ui {
526c803f7f46533c69e2f8a9a882af9ae3b7fffb6fJohn McCall
536ea4841da1390b4f76d066f25333f11f6d8c5f40John McCall// static
546ea4841da1390b4f76d066f25333f11f6d8c5f40John McCallContextFactory* ContextFactory::GetInstance() {
556c803f7f46533c69e2f8a9a882af9ae3b7fffb6fJohn McCall  DCHECK(g_context_factory);
566c803f7f46533c69e2f8a9a882af9ae3b7fffb6fJohn McCall  return g_context_factory;
576c803f7f46533c69e2f8a9a882af9ae3b7fffb6fJohn McCall}
586c803f7f46533c69e2f8a9a882af9ae3b7fffb6fJohn McCall
596c803f7f46533c69e2f8a9a882af9ae3b7fffb6fJohn McCall// static
606c803f7f46533c69e2f8a9a882af9ae3b7fffb6fJohn McCallvoid ContextFactory::SetInstance(ContextFactory* instance) {
616c803f7f46533c69e2f8a9a882af9ae3b7fffb6fJohn McCall  DCHECK_NE(!!g_context_factory, !!instance);
626c803f7f46533c69e2f8a9a882af9ae3b7fffb6fJohn McCall  g_context_factory = instance;
6393ab6bf534fb6c26563c00f28a8fc5581bb71dfdStephen Lin}
646c803f7f46533c69e2f8a9a882af9ae3b7fffb6fJohn McCall
656c803f7f46533c69e2f8a9a882af9ae3b7fffb6fJohn McCallCompositorLock::CompositorLock(Compositor* compositor)
666c803f7f46533c69e2f8a9a882af9ae3b7fffb6fJohn McCall    : compositor_(compositor) {
676c803f7f46533c69e2f8a9a882af9ae3b7fffb6fJohn McCall  base::MessageLoop::current()->PostDelayedTask(
686c803f7f46533c69e2f8a9a882af9ae3b7fffb6fJohn McCall      FROM_HERE,
697523606638128e19d6993c356851fd3e88078201Fariborz Jahanian      base::Bind(&CompositorLock::CancelLock, AsWeakPtr()),
707523606638128e19d6993c356851fd3e88078201Fariborz Jahanian      base::TimeDelta::FromMilliseconds(kCompositorLockTimeoutMs));
717523606638128e19d6993c356851fd3e88078201Fariborz Jahanian}
727523606638128e19d6993c356851fd3e88078201Fariborz Jahanian
737523606638128e19d6993c356851fd3e88078201Fariborz JahanianCompositorLock::~CompositorLock() {
747523606638128e19d6993c356851fd3e88078201Fariborz Jahanian  CancelLock();
757523606638128e19d6993c356851fd3e88078201Fariborz Jahanian}
767523606638128e19d6993c356851fd3e88078201Fariborz Jahanian
777523606638128e19d6993c356851fd3e88078201Fariborz Jahanianvoid CompositorLock::CancelLock() {
787523606638128e19d6993c356851fd3e88078201Fariborz Jahanian  if (!compositor_)
797523606638128e19d6993c356851fd3e88078201Fariborz Jahanian    return;
807523606638128e19d6993c356851fd3e88078201Fariborz Jahanian  compositor_->UnlockCompositor();
81  compositor_ = NULL;
82}
83
84}  // namespace ui
85
86namespace {
87
88}  // namespace
89
90namespace ui {
91
92Compositor::Compositor(gfx::AcceleratedWidget widget)
93    : root_layer_(NULL),
94      widget_(widget),
95      vsync_manager_(new CompositorVSyncManager()),
96      device_scale_factor_(0.0f),
97      last_started_frame_(0),
98      last_ended_frame_(0),
99      next_draw_is_resize_(false),
100      disable_schedule_composite_(false),
101      compositor_lock_(NULL),
102      defer_draw_scheduling_(false),
103      waiting_on_compositing_end_(false),
104      draw_on_compositing_end_(false),
105      swap_state_(SWAP_NONE),
106      schedule_draw_factory_(this) {
107  DCHECK(g_compositor_initialized)
108      << "Compositor::Initialize must be called before creating a Compositor.";
109
110  root_web_layer_ = cc::Layer::Create();
111  root_web_layer_->SetAnchorPoint(gfx::PointF(0.f, 0.f));
112
113  CommandLine* command_line = CommandLine::ForCurrentProcess();
114
115  cc::LayerTreeSettings settings;
116  settings.refresh_rate =
117      ContextFactory::GetInstance()->DoesCreateTestContexts()
118      ? kTestRefreshRate
119      : kDefaultRefreshRate;
120  settings.main_frame_before_draw_enabled = false;
121  settings.main_frame_before_activation_enabled = false;
122  settings.throttle_frame_production =
123      !command_line->HasSwitch(switches::kDisableGpuVsync);
124  settings.partial_swap_enabled =
125      !command_line->HasSwitch(cc::switches::kUIDisablePartialSwap);
126#if defined(OS_CHROMEOS)
127  settings.per_tile_painting_enabled = true;
128#endif
129
130  // These flags should be mirrored by renderer versions in content/renderer/.
131  settings.initial_debug_state.show_debug_borders =
132      command_line->HasSwitch(cc::switches::kUIShowCompositedLayerBorders);
133  settings.initial_debug_state.show_fps_counter =
134      command_line->HasSwitch(cc::switches::kUIShowFPSCounter);
135  settings.initial_debug_state.show_layer_animation_bounds_rects =
136      command_line->HasSwitch(cc::switches::kUIShowLayerAnimationBounds);
137  settings.initial_debug_state.show_paint_rects =
138      command_line->HasSwitch(switches::kUIShowPaintRects);
139  settings.initial_debug_state.show_property_changed_rects =
140      command_line->HasSwitch(cc::switches::kUIShowPropertyChangedRects);
141  settings.initial_debug_state.show_surface_damage_rects =
142      command_line->HasSwitch(cc::switches::kUIShowSurfaceDamageRects);
143  settings.initial_debug_state.show_screen_space_rects =
144      command_line->HasSwitch(cc::switches::kUIShowScreenSpaceRects);
145  settings.initial_debug_state.show_replica_screen_space_rects =
146      command_line->HasSwitch(cc::switches::kUIShowReplicaScreenSpaceRects);
147  settings.initial_debug_state.show_occluding_rects =
148      command_line->HasSwitch(cc::switches::kUIShowOccludingRects);
149  settings.initial_debug_state.show_non_occluding_rects =
150      command_line->HasSwitch(cc::switches::kUIShowNonOccludingRects);
151
152  settings.initial_debug_state.SetRecordRenderingStats(
153      command_line->HasSwitch(cc::switches::kEnableGpuBenchmarking));
154
155  settings.impl_side_painting = IsUIImplSidePaintingEnabled();
156  settings.use_zero_copy = IsUIZeroCopyEnabled();
157
158  base::TimeTicks before_create = base::TimeTicks::Now();
159  if (!!g_compositor_thread) {
160    host_ = cc::LayerTreeHost::CreateThreaded(
161        this,
162        g_context_factory->GetSharedBitmapManager(),
163        settings,
164        g_compositor_thread->message_loop_proxy());
165  } else {
166    host_ = cc::LayerTreeHost::CreateSingleThreaded(
167        this, this, g_context_factory->GetSharedBitmapManager(), settings);
168  }
169  UMA_HISTOGRAM_TIMES("GPU.CreateBrowserCompositor",
170                      base::TimeTicks::Now() - before_create);
171  host_->SetRootLayer(root_web_layer_);
172  host_->SetLayerTreeHostClientReady();
173}
174
175Compositor::~Compositor() {
176  TRACE_EVENT0("shutdown", "Compositor::destructor");
177
178  DCHECK(g_compositor_initialized);
179
180  CancelCompositorLock();
181  DCHECK(!compositor_lock_);
182
183  if (root_layer_)
184    root_layer_->SetCompositor(NULL);
185
186  // Stop all outstanding draws before telling the ContextFactory to tear
187  // down any contexts that the |host_| may rely upon.
188  host_.reset();
189
190  ContextFactory::GetInstance()->RemoveCompositor(this);
191}
192
193// static
194void Compositor::Initialize() {
195#if defined(OS_CHROMEOS)
196  bool use_thread = !CommandLine::ForCurrentProcess()->HasSwitch(
197      switches::kUIDisableThreadedCompositing);
198#else
199  bool use_thread = false;
200#endif
201  if (use_thread) {
202    g_compositor_thread = new base::Thread("Browser Compositor");
203    g_compositor_thread->Start();
204  }
205
206  DCHECK(!g_compositor_initialized) << "Compositor initialized twice.";
207  g_compositor_initialized = true;
208}
209
210// static
211bool Compositor::WasInitializedWithThread() {
212  DCHECK(g_compositor_initialized);
213  return !!g_compositor_thread;
214}
215
216// static
217scoped_refptr<base::MessageLoopProxy> Compositor::GetCompositorMessageLoop() {
218  scoped_refptr<base::MessageLoopProxy> proxy;
219  if (g_compositor_thread)
220    proxy = g_compositor_thread->message_loop_proxy();
221  return proxy;
222}
223
224// static
225void Compositor::Terminate() {
226  if (g_compositor_thread) {
227    g_compositor_thread->Stop();
228    delete g_compositor_thread;
229    g_compositor_thread = NULL;
230  }
231
232  DCHECK(g_compositor_initialized) << "Compositor::Initialize() didn't happen.";
233  g_compositor_initialized = false;
234}
235
236void Compositor::ScheduleDraw() {
237  if (g_compositor_thread) {
238    host_->Composite(gfx::FrameTime::Now());
239  } else if (!defer_draw_scheduling_) {
240    defer_draw_scheduling_ = true;
241    base::MessageLoop::current()->PostTask(
242        FROM_HERE,
243        base::Bind(&Compositor::Draw, schedule_draw_factory_.GetWeakPtr()));
244  }
245}
246
247void Compositor::SetRootLayer(Layer* root_layer) {
248  if (root_layer_ == root_layer)
249    return;
250  if (root_layer_)
251    root_layer_->SetCompositor(NULL);
252  root_layer_ = root_layer;
253  if (root_layer_ && !root_layer_->GetCompositor())
254    root_layer_->SetCompositor(this);
255  root_web_layer_->RemoveAllChildren();
256  if (root_layer_)
257    root_web_layer_->AddChild(root_layer_->cc_layer());
258}
259
260void Compositor::SetHostHasTransparentBackground(
261    bool host_has_transparent_background) {
262  host_->set_has_transparent_background(host_has_transparent_background);
263}
264
265void Compositor::Draw() {
266  DCHECK(!g_compositor_thread);
267
268  defer_draw_scheduling_ = false;
269  if (waiting_on_compositing_end_) {
270    draw_on_compositing_end_ = true;
271    return;
272  }
273  waiting_on_compositing_end_ = true;
274
275  TRACE_EVENT_ASYNC_BEGIN0("ui", "Compositor::Draw", last_started_frame_ + 1);
276
277  if (!root_layer_)
278    return;
279
280  DCHECK_NE(swap_state_, SWAP_POSTED);
281  swap_state_ = SWAP_NONE;
282
283  last_started_frame_++;
284  if (!IsLocked()) {
285    // TODO(nduca): Temporary while compositor calls
286    // compositeImmediately() directly.
287    Layout();
288    host_->Composite(gfx::FrameTime::Now());
289
290#if defined(OS_WIN)
291    // While we resize, we are usually a few frames behind. By blocking
292    // the UI thread here we minize the area that is mis-painted, specially
293    // in the non-client area. See RenderWidgetHostViewAura::SetBounds for
294    // more details and bug 177115.
295    if (next_draw_is_resize_ && (last_ended_frame_ > 1)) {
296      next_draw_is_resize_ = false;
297      host_->FinishAllRendering();
298    }
299#endif
300
301  }
302  if (swap_state_ == SWAP_NONE)
303    NotifyEnd();
304}
305
306void Compositor::ScheduleFullRedraw() {
307  host_->SetNeedsRedraw();
308}
309
310void Compositor::ScheduleRedrawRect(const gfx::Rect& damage_rect) {
311  host_->SetNeedsRedrawRect(damage_rect);
312}
313
314void Compositor::SetLatencyInfo(const ui::LatencyInfo& latency_info) {
315  scoped_ptr<cc::SwapPromise> swap_promise(
316      new cc::LatencyInfoSwapPromise(latency_info));
317  host_->QueueSwapPromise(swap_promise.Pass());
318}
319
320void Compositor::SetScaleAndSize(float scale, const gfx::Size& size_in_pixel) {
321  DCHECK_GT(scale, 0);
322  if (!size_in_pixel.IsEmpty()) {
323    size_ = size_in_pixel;
324    host_->SetViewportSize(size_in_pixel);
325    root_web_layer_->SetBounds(size_in_pixel);
326
327    next_draw_is_resize_ = true;
328  }
329  if (device_scale_factor_ != scale) {
330    device_scale_factor_ = scale;
331    if (root_layer_)
332      root_layer_->OnDeviceScaleFactorChanged(scale);
333  }
334}
335
336void Compositor::SetBackgroundColor(SkColor color) {
337  host_->set_background_color(color);
338  ScheduleDraw();
339}
340
341scoped_refptr<CompositorVSyncManager> Compositor::vsync_manager() const {
342  return vsync_manager_;
343}
344
345void Compositor::AddObserver(CompositorObserver* observer) {
346  observer_list_.AddObserver(observer);
347}
348
349void Compositor::RemoveObserver(CompositorObserver* observer) {
350  observer_list_.RemoveObserver(observer);
351}
352
353bool Compositor::HasObserver(CompositorObserver* observer) {
354  return observer_list_.HasObserver(observer);
355}
356
357void Compositor::Layout() {
358  // We're sending damage that will be addressed during this composite
359  // cycle, so we don't need to schedule another composite to address it.
360  disable_schedule_composite_ = true;
361  if (root_layer_)
362    root_layer_->SendDamagedRects();
363  disable_schedule_composite_ = false;
364}
365
366scoped_ptr<cc::OutputSurface> Compositor::CreateOutputSurface(bool fallback) {
367  return ContextFactory::GetInstance()->CreateOutputSurface(this, fallback);
368}
369
370void Compositor::DidCommit() {
371  DCHECK(!IsLocked());
372  FOR_EACH_OBSERVER(CompositorObserver,
373                    observer_list_,
374                    OnCompositingDidCommit(this));
375}
376
377void Compositor::DidCommitAndDrawFrame() {
378  base::TimeTicks start_time = gfx::FrameTime::Now();
379  FOR_EACH_OBSERVER(CompositorObserver,
380                    observer_list_,
381                    OnCompositingStarted(this, start_time));
382}
383
384void Compositor::DidCompleteSwapBuffers() {
385  if (g_compositor_thread) {
386    NotifyEnd();
387  } else {
388    DCHECK_EQ(swap_state_, SWAP_POSTED);
389    NotifyEnd();
390    swap_state_ = SWAP_COMPLETED;
391  }
392}
393
394void Compositor::ScheduleComposite() {
395  if (!disable_schedule_composite_)
396    ScheduleDraw();
397}
398
399void Compositor::ScheduleAnimation() {
400  ScheduleComposite();
401}
402
403void Compositor::DidPostSwapBuffers() {
404  DCHECK(!g_compositor_thread);
405  DCHECK_EQ(swap_state_, SWAP_NONE);
406  swap_state_ = SWAP_POSTED;
407}
408
409void Compositor::DidAbortSwapBuffers() {
410  if (!g_compositor_thread) {
411    if (swap_state_ == SWAP_POSTED) {
412      NotifyEnd();
413      swap_state_ = SWAP_COMPLETED;
414    }
415  }
416
417  FOR_EACH_OBSERVER(CompositorObserver,
418                    observer_list_,
419                    OnCompositingAborted(this));
420}
421
422const cc::LayerTreeDebugState& Compositor::GetLayerTreeDebugState() const {
423  return host_->debug_state();
424}
425
426void Compositor::SetLayerTreeDebugState(
427    const cc::LayerTreeDebugState& debug_state) {
428  host_->SetDebugState(debug_state);
429}
430
431scoped_refptr<CompositorLock> Compositor::GetCompositorLock() {
432  if (!compositor_lock_) {
433    compositor_lock_ = new CompositorLock(this);
434    if (g_compositor_thread)
435      host_->SetDeferCommits(true);
436    FOR_EACH_OBSERVER(CompositorObserver,
437                      observer_list_,
438                      OnCompositingLockStateChanged(this));
439  }
440  return compositor_lock_;
441}
442
443void Compositor::UnlockCompositor() {
444  DCHECK(compositor_lock_);
445  compositor_lock_ = NULL;
446  if (g_compositor_thread)
447    host_->SetDeferCommits(false);
448  FOR_EACH_OBSERVER(CompositorObserver,
449                    observer_list_,
450                    OnCompositingLockStateChanged(this));
451}
452
453void Compositor::CancelCompositorLock() {
454  if (compositor_lock_)
455    compositor_lock_->CancelLock();
456}
457
458void Compositor::NotifyEnd() {
459  last_ended_frame_++;
460  TRACE_EVENT_ASYNC_END0("ui", "Compositor::Draw", last_ended_frame_);
461  waiting_on_compositing_end_ = false;
462  if (draw_on_compositing_end_) {
463    draw_on_compositing_end_ = false;
464
465    // Call ScheduleDraw() instead of Draw() in order to allow other
466    // CompositorObservers to be notified before starting another
467    // draw cycle.
468    ScheduleDraw();
469  }
470  FOR_EACH_OBSERVER(CompositorObserver,
471                    observer_list_,
472                    OnCompositingEnded(this));
473}
474
475}  // namespace ui
476