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.
5 #include "ui/compositor/compositor.h"
10 #include "base/bind.h"
11 #include "base/command_line.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/metrics/histogram.h"
14 #include "base/profiler/scoped_tracker.h"
15 #include "base/strings/string_util.h"
16 #include "base/sys_info.h"
17 #include "base/trace_event/trace_event.h"
18 #include "cc/base/switches.h"
19 #include "cc/input/input_handler.h"
20 #include "cc/layers/layer.h"
21 #include "cc/output/begin_frame_args.h"
22 #include "cc/output/context_provider.h"
23 #include "cc/output/latency_info_swap_promise.h"
24 #include "cc/scheduler/begin_frame_source.h"
25 #include "cc/surfaces/surface_id_allocator.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/compositor/layer_animator_collection.h"
34 #include "ui/gfx/frame_time.h"
35 #include "ui/gl/gl_context.h"
36 #include "ui/gl/gl_switches.h"
40 const double kDefaultRefreshRate
= 60.0;
41 const double kTestRefreshRate
= 200.0;
47 CompositorLock::CompositorLock(Compositor
* compositor
)
48 : compositor_(compositor
) {
49 if (compositor_
->locks_will_time_out_
) {
50 compositor_
->task_runner_
->PostDelayedTask(
52 base::Bind(&CompositorLock::CancelLock
, AsWeakPtr()),
53 base::TimeDelta::FromMilliseconds(kCompositorLockTimeoutMs
));
57 CompositorLock::~CompositorLock() {
61 void CompositorLock::CancelLock() {
64 compositor_
->UnlockCompositor();
68 Compositor::Compositor(gfx::AcceleratedWidget widget
,
69 ui::ContextFactory
* context_factory
,
70 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner
)
71 : context_factory_(context_factory
),
74 surface_id_allocator_(context_factory
->CreateSurfaceIdAllocator()),
75 task_runner_(task_runner
),
76 vsync_manager_(new CompositorVSyncManager()),
77 device_scale_factor_(0.0f
),
78 last_started_frame_(0),
80 locks_will_time_out_(true),
81 compositor_lock_(NULL
),
82 layer_animator_collection_(this),
83 weak_ptr_factory_(this) {
84 root_web_layer_
= cc::Layer::Create();
86 base::CommandLine
* command_line
= base::CommandLine::ForCurrentProcess();
88 cc::LayerTreeSettings settings
;
89 // When impl-side painting is enabled, this will ensure PictureLayers always
90 // can have LCD text, to match the previous behaviour with ContentLayers,
91 // where LCD-not-allowed notifications were ignored.
92 settings
.layers_always_allowed_lcd_text
= true;
93 settings
.renderer_settings
.refresh_rate
=
94 context_factory_
->DoesCreateTestContexts() ? kTestRefreshRate
95 : kDefaultRefreshRate
;
96 settings
.main_frame_before_activation_enabled
= false;
97 settings
.throttle_frame_production
=
98 !command_line
->HasSwitch(switches::kDisableGpuVsync
);
99 settings
.renderer_settings
.partial_swap_enabled
=
100 !command_line
->HasSwitch(cc::switches::kUIDisablePartialSwap
);
101 #if defined(OS_CHROMEOS)
102 settings
.per_tile_painting_enabled
= true;
105 settings
.renderer_settings
.finish_rendering_on_resize
= true;
108 // These flags should be mirrored by renderer versions in content/renderer/.
109 settings
.initial_debug_state
.show_debug_borders
=
110 command_line
->HasSwitch(cc::switches::kUIShowCompositedLayerBorders
);
111 settings
.initial_debug_state
.show_fps_counter
=
112 command_line
->HasSwitch(cc::switches::kUIShowFPSCounter
);
113 settings
.initial_debug_state
.show_layer_animation_bounds_rects
=
114 command_line
->HasSwitch(cc::switches::kUIShowLayerAnimationBounds
);
115 settings
.initial_debug_state
.show_paint_rects
=
116 command_line
->HasSwitch(switches::kUIShowPaintRects
);
117 settings
.initial_debug_state
.show_property_changed_rects
=
118 command_line
->HasSwitch(cc::switches::kUIShowPropertyChangedRects
);
119 settings
.initial_debug_state
.show_surface_damage_rects
=
120 command_line
->HasSwitch(cc::switches::kUIShowSurfaceDamageRects
);
121 settings
.initial_debug_state
.show_screen_space_rects
=
122 command_line
->HasSwitch(cc::switches::kUIShowScreenSpaceRects
);
123 settings
.initial_debug_state
.show_replica_screen_space_rects
=
124 command_line
->HasSwitch(cc::switches::kUIShowReplicaScreenSpaceRects
);
126 settings
.initial_debug_state
.SetRecordRenderingStats(
127 command_line
->HasSwitch(cc::switches::kEnableGpuBenchmarking
));
129 settings
.impl_side_painting
= IsUIImplSidePaintingEnabled();
130 settings
.use_display_lists
= IsUISlimmingPaintEnabled();
131 settings
.use_zero_copy
= IsUIZeroCopyEnabled();
132 settings
.use_one_copy
= IsUIOneCopyEnabled();
133 settings
.use_image_texture_target
= context_factory_
->GetImageTextureTarget();
134 // Note: gathering of pixel refs is only needed when using multiple
136 settings
.gather_pixel_refs
= false;
138 settings
.use_compositor_animation_timelines
=
139 command_line
->HasSwitch(switches::kUIEnableCompositorAnimationTimelines
);
141 base::TimeTicks before_create
= base::TimeTicks::Now();
142 host_
= cc::LayerTreeHost::CreateSingleThreaded(
143 this, this, context_factory_
->GetSharedBitmapManager(),
144 context_factory_
->GetGpuMemoryBufferManager(),
145 context_factory_
->GetTaskGraphRunner(), settings
, task_runner_
, nullptr);
146 UMA_HISTOGRAM_TIMES("GPU.CreateBrowserCompositor",
147 base::TimeTicks::Now() - before_create
);
148 host_
->SetRootLayer(root_web_layer_
);
149 host_
->set_surface_id_namespace(surface_id_allocator_
->id_namespace());
150 host_
->SetLayerTreeHostClientReady();
153 Compositor::~Compositor() {
154 TRACE_EVENT0("shutdown", "Compositor::destructor");
156 CancelCompositorLock();
157 DCHECK(!compositor_lock_
);
159 FOR_EACH_OBSERVER(CompositorObserver
, observer_list_
,
160 OnCompositingShuttingDown(this));
162 DCHECK(begin_frame_observer_list_
.empty());
165 root_layer_
->SetCompositor(NULL
);
167 // Stop all outstanding draws before telling the ContextFactory to tear
168 // down any contexts that the |host_| may rely upon.
171 context_factory_
->RemoveCompositor(this);
174 void Compositor::SetOutputSurface(
175 scoped_ptr
<cc::OutputSurface
> output_surface
) {
176 host_
->SetOutputSurface(output_surface
.Pass());
179 void Compositor::ScheduleDraw() {
180 host_
->SetNeedsCommit();
183 void Compositor::SetRootLayer(Layer
* root_layer
) {
184 if (root_layer_
== root_layer
)
187 root_layer_
->SetCompositor(NULL
);
188 root_layer_
= root_layer
;
189 if (root_layer_
&& !root_layer_
->GetCompositor())
190 root_layer_
->SetCompositor(this);
191 root_web_layer_
->RemoveAllChildren();
193 root_web_layer_
->AddChild(root_layer_
->cc_layer());
196 void Compositor::SetHostHasTransparentBackground(
197 bool host_has_transparent_background
) {
198 host_
->set_has_transparent_background(host_has_transparent_background
);
201 void Compositor::ScheduleFullRedraw() {
202 // TODO(enne): Some callers (mac) call this function expecting that it
203 // will also commit. This should probably just redraw the screen
204 // from damage and not commit. ScheduleDraw/ScheduleRedraw need
206 host_
->SetNeedsRedraw();
207 host_
->SetNeedsCommit();
210 void Compositor::ScheduleRedrawRect(const gfx::Rect
& damage_rect
) {
211 // TODO(enne): Make this not commit. See ScheduleFullRedraw.
212 host_
->SetNeedsRedrawRect(damage_rect
);
213 host_
->SetNeedsCommit();
216 void Compositor::FinishAllRendering() {
217 host_
->FinishAllRendering();
220 void Compositor::DisableSwapUntilResize() {
221 host_
->FinishAllRendering();
222 context_factory_
->ResizeDisplay(this, gfx::Size());
225 void Compositor::SetLatencyInfo(const ui::LatencyInfo
& latency_info
) {
226 scoped_ptr
<cc::SwapPromise
> swap_promise(
227 new cc::LatencyInfoSwapPromise(latency_info
));
228 host_
->QueueSwapPromise(swap_promise
.Pass());
231 void Compositor::SetScaleAndSize(float scale
, const gfx::Size
& size_in_pixel
) {
233 if (!size_in_pixel
.IsEmpty()) {
234 size_
= size_in_pixel
;
235 host_
->SetViewportSize(size_in_pixel
);
236 root_web_layer_
->SetBounds(size_in_pixel
);
237 context_factory_
->ResizeDisplay(this, size_in_pixel
);
239 if (device_scale_factor_
!= scale
) {
240 device_scale_factor_
= scale
;
241 host_
->SetDeviceScaleFactor(scale
);
243 root_layer_
->OnDeviceScaleFactorChanged(scale
);
247 void Compositor::SetBackgroundColor(SkColor color
) {
248 host_
->set_background_color(color
);
252 void Compositor::SetVisible(bool visible
) {
253 host_
->SetVisible(visible
);
256 bool Compositor::IsVisible() {
257 return host_
->visible();
260 scoped_refptr
<CompositorVSyncManager
> Compositor::vsync_manager() const {
261 return vsync_manager_
;
264 void Compositor::AddObserver(CompositorObserver
* observer
) {
265 observer_list_
.AddObserver(observer
);
268 void Compositor::RemoveObserver(CompositorObserver
* observer
) {
269 observer_list_
.RemoveObserver(observer
);
272 bool Compositor::HasObserver(const CompositorObserver
* observer
) const {
273 return observer_list_
.HasObserver(observer
);
276 void Compositor::AddAnimationObserver(CompositorAnimationObserver
* observer
) {
277 animation_observer_list_
.AddObserver(observer
);
278 host_
->SetNeedsAnimate();
281 void Compositor::RemoveAnimationObserver(
282 CompositorAnimationObserver
* observer
) {
283 animation_observer_list_
.RemoveObserver(observer
);
286 bool Compositor::HasAnimationObserver(
287 const CompositorAnimationObserver
* observer
) const {
288 return animation_observer_list_
.HasObserver(observer
);
291 void Compositor::AddBeginFrameObserver(CompositorBeginFrameObserver
* observer
) {
292 DCHECK(std::find(begin_frame_observer_list_
.begin(),
293 begin_frame_observer_list_
.end(), observer
) ==
294 begin_frame_observer_list_
.end());
296 if (begin_frame_observer_list_
.empty())
297 host_
->SetChildrenNeedBeginFrames(true);
299 if (missed_begin_frame_args_
.IsValid())
300 observer
->OnSendBeginFrame(missed_begin_frame_args_
);
302 begin_frame_observer_list_
.push_back(observer
);
305 void Compositor::RemoveBeginFrameObserver(
306 CompositorBeginFrameObserver
* observer
) {
307 auto it
= std::find(begin_frame_observer_list_
.begin(),
308 begin_frame_observer_list_
.end(), observer
);
309 DCHECK(it
!= begin_frame_observer_list_
.end());
310 begin_frame_observer_list_
.erase(it
);
312 if (begin_frame_observer_list_
.empty()) {
313 host_
->SetChildrenNeedBeginFrames(false);
314 missed_begin_frame_args_
= cc::BeginFrameArgs();
318 void Compositor::BeginMainFrame(const cc::BeginFrameArgs
& args
) {
319 FOR_EACH_OBSERVER(CompositorAnimationObserver
,
320 animation_observer_list_
,
321 OnAnimationStep(args
.frame_time
));
322 if (animation_observer_list_
.might_have_observers())
323 host_
->SetNeedsAnimate();
326 void Compositor::BeginMainFrameNotExpectedSoon() {
329 static void SendDamagedRectsRecursive(ui::Layer
* layer
) {
330 layer
->SendDamagedRects();
331 for (auto* child
: layer
->children())
332 SendDamagedRectsRecursive(child
);
335 void Compositor::Layout() {
338 SendDamagedRectsRecursive(root_layer());
341 void Compositor::RequestNewOutputSurface() {
342 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/466870
344 tracked_objects::ScopedTracker
tracking_profile(
345 FROM_HERE_WITH_EXPLICIT_FUNCTION(
346 "466870 Compositor::RequestNewOutputSurface"));
348 context_factory_
->CreateOutputSurface(weak_ptr_factory_
.GetWeakPtr());
351 void Compositor::DidInitializeOutputSurface() {
354 void Compositor::DidFailToInitializeOutputSurface() {
355 // The OutputSurface should already be bound/initialized before being given to
360 void Compositor::DidCommit() {
362 FOR_EACH_OBSERVER(CompositorObserver
,
364 OnCompositingDidCommit(this));
367 void Compositor::DidCommitAndDrawFrame() {
370 void Compositor::DidCompleteSwapBuffers() {
371 FOR_EACH_OBSERVER(CompositorObserver
, observer_list_
,
372 OnCompositingEnded(this));
375 void Compositor::DidPostSwapBuffers() {
376 base::TimeTicks start_time
= gfx::FrameTime::Now();
377 FOR_EACH_OBSERVER(CompositorObserver
, observer_list_
,
378 OnCompositingStarted(this, start_time
));
381 void Compositor::DidAbortSwapBuffers() {
382 FOR_EACH_OBSERVER(CompositorObserver
,
384 OnCompositingAborted(this));
387 void Compositor::SendBeginFramesToChildren(const cc::BeginFrameArgs
& args
) {
388 for (auto observer
: begin_frame_observer_list_
)
389 observer
->OnSendBeginFrame(args
);
391 missed_begin_frame_args_
= args
;
392 missed_begin_frame_args_
.type
= cc::BeginFrameArgs::MISSED
;
395 const cc::LayerTreeDebugState
& Compositor::GetLayerTreeDebugState() const {
396 return host_
->debug_state();
399 void Compositor::SetLayerTreeDebugState(
400 const cc::LayerTreeDebugState
& debug_state
) {
401 host_
->SetDebugState(debug_state
);
404 const cc::RendererSettings
& Compositor::GetRendererSettings() const {
405 return host_
->settings().renderer_settings
;
408 scoped_refptr
<CompositorLock
> Compositor::GetCompositorLock() {
409 if (!compositor_lock_
) {
410 compositor_lock_
= new CompositorLock(this);
411 host_
->SetDeferCommits(true);
412 FOR_EACH_OBSERVER(CompositorObserver
,
414 OnCompositingLockStateChanged(this));
416 return compositor_lock_
;
419 void Compositor::UnlockCompositor() {
420 DCHECK(compositor_lock_
);
421 compositor_lock_
= NULL
;
422 host_
->SetDeferCommits(false);
423 FOR_EACH_OBSERVER(CompositorObserver
,
425 OnCompositingLockStateChanged(this));
428 void Compositor::CancelCompositorLock() {
429 if (compositor_lock_
)
430 compositor_lock_
->CancelLock();