compositor.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
1f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// Use of this source code is governed by a BSD-style license that can be
3f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// found in the LICENSE file.
4f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
5f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "ui/compositor/compositor.h"
6f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
7f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include <algorithm>
8f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include <deque>
9f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
10f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "base/bind.h"
11f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "base/command_line.h"
12f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "base/debug/trace_event.h"
13f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "base/message_loop/message_loop.h"
14f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "base/metrics/histogram.h"
15f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "base/strings/string_util.h"
16f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "base/sys_info.h"
17f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "cc/base/latency_info_swap_promise.h"
18f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "cc/base/switches.h"
19f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "cc/input/input_handler.h"
20f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "cc/layers/layer.h"
21f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "cc/output/context_provider.h"
22f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "cc/trees/layer_tree_host.h"
23f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "third_party/skia/include/core/SkBitmap.h"
24f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "ui/compositor/compositor_observer.h"
25f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "ui/compositor/compositor_switches.h"
26f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "ui/compositor/compositor_vsync_manager.h"
27f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "ui/compositor/dip_util.h"
28f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "ui/compositor/layer.h"
29f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "ui/compositor/layer_animator_collection.h"
30f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "ui/gfx/frame_time.h"
31f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "ui/gl/gl_context.h"
32f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "ui/gl/gl_switches.h"
33f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
34f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgnamespace {
35f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
36f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgconst double kDefaultRefreshRate = 60.0;
37f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgconst double kTestRefreshRate = 200.0;
38f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
39f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgconst int kCompositorLockTimeoutMs = 67;
40f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
41f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}  // namespace
42f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
43f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgnamespace ui {
44f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
45f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgCompositorLock::CompositorLock(Compositor* compositor)
46f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    : compositor_(compositor) {
47f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  compositor_->task_runner_->PostDelayedTask(
48f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      FROM_HERE,
49f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      base::Bind(&CompositorLock::CancelLock, AsWeakPtr()),
50f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      base::TimeDelta::FromMilliseconds(kCompositorLockTimeoutMs));
51f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
52f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
53f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgCompositorLock::~CompositorLock() {
54f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  CancelLock();
55f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
56f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
57f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid CompositorLock::CancelLock() {
58f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  if (!compositor_)
59f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    return;
60f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  compositor_->UnlockCompositor();
61f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  compositor_ = NULL;
62f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
63f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
64f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}  // namespace ui
65f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
66f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgnamespace {
67f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
68f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}  // namespace
69f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
70f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgnamespace ui {
71f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
72f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgCompositor::Compositor(gfx::AcceleratedWidget widget,
73f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                       ui::ContextFactory* context_factory,
74f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                       scoped_refptr<base::SingleThreadTaskRunner> task_runner)
75f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    : context_factory_(context_factory),
76f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      root_layer_(NULL),
77f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      widget_(widget),
78f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      compositor_thread_loop_(context_factory->GetCompositorMessageLoop()),
79f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      task_runner_(task_runner),
80f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      vsync_manager_(new CompositorVSyncManager()),
81f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      device_scale_factor_(0.0f),
82f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      last_started_frame_(0),
83f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      last_ended_frame_(0),
84f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      disable_schedule_composite_(false),
85f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      compositor_lock_(NULL),
86f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      defer_draw_scheduling_(false),
87f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      waiting_on_compositing_end_(false),
88f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      draw_on_compositing_end_(false),
89f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      swap_state_(SWAP_NONE),
90f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      layer_animator_collection_(this),
91f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      schedule_draw_factory_(this) {
92f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  root_web_layer_ = cc::Layer::Create();
93f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
94f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  CommandLine* command_line = CommandLine::ForCurrentProcess();
95f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
96f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  cc::LayerTreeSettings settings;
97f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  settings.refresh_rate =
98f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      context_factory_->DoesCreateTestContexts()
99      ? kTestRefreshRate
100      : kDefaultRefreshRate;
101  settings.main_frame_before_draw_enabled = false;
102  settings.main_frame_before_activation_enabled = false;
103  settings.throttle_frame_production =
104      !command_line->HasSwitch(switches::kDisableGpuVsync);
105#if !defined(OS_MACOSX)
106  settings.partial_swap_enabled =
107      !command_line->HasSwitch(cc::switches::kUIDisablePartialSwap);
108#endif
109#if defined(OS_CHROMEOS)
110  settings.per_tile_painting_enabled = true;
111#endif
112
113  // These flags should be mirrored by renderer versions in content/renderer/.
114  settings.initial_debug_state.show_debug_borders =
115      command_line->HasSwitch(cc::switches::kUIShowCompositedLayerBorders);
116  settings.initial_debug_state.show_fps_counter =
117      command_line->HasSwitch(cc::switches::kUIShowFPSCounter);
118  settings.initial_debug_state.show_layer_animation_bounds_rects =
119      command_line->HasSwitch(cc::switches::kUIShowLayerAnimationBounds);
120  settings.initial_debug_state.show_paint_rects =
121      command_line->HasSwitch(switches::kUIShowPaintRects);
122  settings.initial_debug_state.show_property_changed_rects =
123      command_line->HasSwitch(cc::switches::kUIShowPropertyChangedRects);
124  settings.initial_debug_state.show_surface_damage_rects =
125      command_line->HasSwitch(cc::switches::kUIShowSurfaceDamageRects);
126  settings.initial_debug_state.show_screen_space_rects =
127      command_line->HasSwitch(cc::switches::kUIShowScreenSpaceRects);
128  settings.initial_debug_state.show_replica_screen_space_rects =
129      command_line->HasSwitch(cc::switches::kUIShowReplicaScreenSpaceRects);
130  settings.initial_debug_state.show_occluding_rects =
131      command_line->HasSwitch(cc::switches::kUIShowOccludingRects);
132  settings.initial_debug_state.show_non_occluding_rects =
133      command_line->HasSwitch(cc::switches::kUIShowNonOccludingRects);
134
135  settings.initial_debug_state.SetRecordRenderingStats(
136      command_line->HasSwitch(cc::switches::kEnableGpuBenchmarking));
137
138  settings.impl_side_painting = IsUIImplSidePaintingEnabled();
139  settings.use_zero_copy = IsUIZeroCopyEnabled();
140
141  base::TimeTicks before_create = base::TimeTicks::Now();
142  if (compositor_thread_loop_) {
143    host_ = cc::LayerTreeHost::CreateThreaded(
144        this,
145        context_factory_->GetSharedBitmapManager(),
146        settings,
147        task_runner_,
148        compositor_thread_loop_);
149  } else {
150    host_ = cc::LayerTreeHost::CreateSingleThreaded(
151        this,
152        this,
153        context_factory_->GetSharedBitmapManager(),
154        settings,
155        task_runner_);
156  }
157  UMA_HISTOGRAM_TIMES("GPU.CreateBrowserCompositor",
158                      base::TimeTicks::Now() - before_create);
159  host_->SetRootLayer(root_web_layer_);
160  host_->SetLayerTreeHostClientReady();
161}
162
163Compositor::~Compositor() {
164  TRACE_EVENT0("shutdown", "Compositor::destructor");
165
166  CancelCompositorLock();
167  DCHECK(!compositor_lock_);
168
169  if (root_layer_)
170    root_layer_->SetCompositor(NULL);
171
172  // Stop all outstanding draws before telling the ContextFactory to tear
173  // down any contexts that the |host_| may rely upon.
174  host_.reset();
175
176  context_factory_->RemoveCompositor(this);
177}
178
179void Compositor::ScheduleDraw() {
180  if (compositor_thread_loop_) {
181    host_->SetNeedsCommit();
182  } else if (!defer_draw_scheduling_) {
183    defer_draw_scheduling_ = true;
184    task_runner_->PostTask(
185        FROM_HERE,
186        base::Bind(&Compositor::Draw, schedule_draw_factory_.GetWeakPtr()));
187  }
188}
189
190void Compositor::SetRootLayer(Layer* root_layer) {
191  if (root_layer_ == root_layer)
192    return;
193  if (root_layer_)
194    root_layer_->SetCompositor(NULL);
195  root_layer_ = root_layer;
196  if (root_layer_ && !root_layer_->GetCompositor())
197    root_layer_->SetCompositor(this);
198  root_web_layer_->RemoveAllChildren();
199  if (root_layer_)
200    root_web_layer_->AddChild(root_layer_->cc_layer());
201}
202
203void Compositor::SetHostHasTransparentBackground(
204    bool host_has_transparent_background) {
205  host_->set_has_transparent_background(host_has_transparent_background);
206}
207
208void Compositor::Draw() {
209  DCHECK(!compositor_thread_loop_);
210
211  defer_draw_scheduling_ = false;
212  if (waiting_on_compositing_end_) {
213    draw_on_compositing_end_ = true;
214    return;
215  }
216  if (!root_layer_)
217    return;
218
219  TRACE_EVENT_ASYNC_BEGIN0("ui", "Compositor::Draw", last_started_frame_ + 1);
220
221  DCHECK_NE(swap_state_, SWAP_POSTED);
222  swap_state_ = SWAP_NONE;
223
224  waiting_on_compositing_end_ = true;
225  last_started_frame_++;
226  if (!IsLocked()) {
227    // TODO(nduca): Temporary while compositor calls
228    // compositeImmediately() directly.
229    base::TimeTicks now = gfx::FrameTime::Now();
230    Animate(now);
231    Layout();
232    host_->Composite(now);
233  }
234  if (swap_state_ == SWAP_NONE)
235    NotifyEnd();
236}
237
238void Compositor::ScheduleFullRedraw() {
239  host_->SetNeedsRedraw();
240}
241
242void Compositor::ScheduleRedrawRect(const gfx::Rect& damage_rect) {
243  host_->SetNeedsRedrawRect(damage_rect);
244}
245
246void Compositor::FinishAllRendering() {
247  host_->FinishAllRendering();
248}
249
250void Compositor::SetLatencyInfo(const ui::LatencyInfo& latency_info) {
251  scoped_ptr<cc::SwapPromise> swap_promise(
252      new cc::LatencyInfoSwapPromise(latency_info));
253  host_->QueueSwapPromise(swap_promise.Pass());
254}
255
256void Compositor::SetScaleAndSize(float scale, const gfx::Size& size_in_pixel) {
257  DCHECK_GT(scale, 0);
258  if (!size_in_pixel.IsEmpty()) {
259    size_ = size_in_pixel;
260    host_->SetViewportSize(size_in_pixel);
261    root_web_layer_->SetBounds(size_in_pixel);
262  }
263  if (device_scale_factor_ != scale) {
264    device_scale_factor_ = scale;
265    host_->SetDeviceScaleFactor(scale);
266    if (root_layer_)
267      root_layer_->OnDeviceScaleFactorChanged(scale);
268  }
269}
270
271void Compositor::SetBackgroundColor(SkColor color) {
272  host_->set_background_color(color);
273  ScheduleDraw();
274}
275
276scoped_refptr<CompositorVSyncManager> Compositor::vsync_manager() const {
277  return vsync_manager_;
278}
279
280void Compositor::AddObserver(CompositorObserver* observer) {
281  observer_list_.AddObserver(observer);
282}
283
284void Compositor::RemoveObserver(CompositorObserver* observer) {
285  observer_list_.RemoveObserver(observer);
286}
287
288bool Compositor::HasObserver(CompositorObserver* observer) {
289  return observer_list_.HasObserver(observer);
290}
291
292void Compositor::AddAnimationObserver(CompositorAnimationObserver* observer) {
293  animation_observer_list_.AddObserver(observer);
294  host_->SetNeedsAnimate();
295}
296
297void Compositor::RemoveAnimationObserver(
298    CompositorAnimationObserver* observer) {
299  animation_observer_list_.RemoveObserver(observer);
300}
301
302bool Compositor::HasAnimationObserver(CompositorAnimationObserver* observer) {
303  return animation_observer_list_.HasObserver(observer);
304}
305
306void Compositor::Animate(base::TimeTicks frame_begin_time) {
307  FOR_EACH_OBSERVER(CompositorAnimationObserver,
308                    animation_observer_list_,
309                    OnAnimationStep(frame_begin_time));
310  if (animation_observer_list_.might_have_observers())
311    host_->SetNeedsAnimate();
312}
313
314void Compositor::Layout() {
315  // We're sending damage that will be addressed during this composite
316  // cycle, so we don't need to schedule another composite to address it.
317  disable_schedule_composite_ = true;
318  if (root_layer_)
319    root_layer_->SendDamagedRects();
320  disable_schedule_composite_ = false;
321}
322
323scoped_ptr<cc::OutputSurface> Compositor::CreateOutputSurface(bool fallback) {
324  return context_factory_->CreateOutputSurface(this, fallback);
325}
326
327void Compositor::DidCommit() {
328  DCHECK(!IsLocked());
329  FOR_EACH_OBSERVER(CompositorObserver,
330                    observer_list_,
331                    OnCompositingDidCommit(this));
332}
333
334void Compositor::DidCommitAndDrawFrame() {
335  base::TimeTicks start_time = gfx::FrameTime::Now();
336  FOR_EACH_OBSERVER(CompositorObserver,
337                    observer_list_,
338                    OnCompositingStarted(this, start_time));
339}
340
341void Compositor::DidCompleteSwapBuffers() {
342  if (compositor_thread_loop_) {
343    NotifyEnd();
344  } else {
345    DCHECK_EQ(swap_state_, SWAP_POSTED);
346    NotifyEnd();
347    swap_state_ = SWAP_COMPLETED;
348  }
349}
350
351void Compositor::ScheduleComposite() {
352  if (!disable_schedule_composite_)
353    ScheduleDraw();
354}
355
356void Compositor::ScheduleAnimation() {
357  ScheduleComposite();
358}
359
360void Compositor::DidPostSwapBuffers() {
361  DCHECK(!compositor_thread_loop_);
362  DCHECK_EQ(swap_state_, SWAP_NONE);
363  swap_state_ = SWAP_POSTED;
364}
365
366void Compositor::DidAbortSwapBuffers() {
367  if (!compositor_thread_loop_) {
368    if (swap_state_ == SWAP_POSTED) {
369      NotifyEnd();
370      swap_state_ = SWAP_COMPLETED;
371    }
372  }
373
374  FOR_EACH_OBSERVER(CompositorObserver,
375                    observer_list_,
376                    OnCompositingAborted(this));
377}
378
379const cc::LayerTreeDebugState& Compositor::GetLayerTreeDebugState() const {
380  return host_->debug_state();
381}
382
383void Compositor::SetLayerTreeDebugState(
384    const cc::LayerTreeDebugState& debug_state) {
385  host_->SetDebugState(debug_state);
386}
387
388scoped_refptr<CompositorLock> Compositor::GetCompositorLock() {
389  if (!compositor_lock_) {
390    compositor_lock_ = new CompositorLock(this);
391    if (compositor_thread_loop_)
392      host_->SetDeferCommits(true);
393    FOR_EACH_OBSERVER(CompositorObserver,
394                      observer_list_,
395                      OnCompositingLockStateChanged(this));
396  }
397  return compositor_lock_;
398}
399
400void Compositor::UnlockCompositor() {
401  DCHECK(compositor_lock_);
402  compositor_lock_ = NULL;
403  if (compositor_thread_loop_)
404    host_->SetDeferCommits(false);
405  FOR_EACH_OBSERVER(CompositorObserver,
406                    observer_list_,
407                    OnCompositingLockStateChanged(this));
408}
409
410void Compositor::CancelCompositorLock() {
411  if (compositor_lock_)
412    compositor_lock_->CancelLock();
413}
414
415void Compositor::NotifyEnd() {
416  last_ended_frame_++;
417  TRACE_EVENT_ASYNC_END0("ui", "Compositor::Draw", last_ended_frame_);
418  waiting_on_compositing_end_ = false;
419  if (draw_on_compositing_end_) {
420    draw_on_compositing_end_ = false;
421
422    // Call ScheduleDraw() instead of Draw() in order to allow other
423    // CompositorObservers to be notified before starting another
424    // draw cycle.
425    ScheduleDraw();
426  }
427  FOR_EACH_OBSERVER(CompositorObserver,
428                    observer_list_,
429                    OnCompositingEnded(this));
430}
431
432}  // namespace ui
433