compositor.cc revision 03b57e008b61dfcb1fbad3aea950ae0e001748b0
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/message_loop/message_loop.h" 14#include "base/metrics/histogram.h" 15#include "base/strings/string_util.h" 16#include "base/sys_info.h" 17#include "cc/base/latency_info_swap_promise.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/trees/layer_tree_host.h" 24#include "third_party/skia/include/core/SkBitmap.h" 25#include "ui/compositor/compositor_observer.h" 26#include "ui/compositor/compositor_switches.h" 27#include "ui/compositor/compositor_vsync_manager.h" 28#include "ui/compositor/dip_util.h" 29#include "ui/compositor/layer.h" 30#include "ui/compositor/layer_animator_collection.h" 31#include "ui/gfx/frame_time.h" 32#include "ui/gl/gl_context.h" 33#include "ui/gl/gl_switches.h" 34 35namespace { 36 37const double kDefaultRefreshRate = 60.0; 38const double kTestRefreshRate = 200.0; 39 40const int kCompositorLockTimeoutMs = 67; 41 42} // namespace 43 44namespace ui { 45 46CompositorLock::CompositorLock(Compositor* compositor) 47 : compositor_(compositor) { 48 compositor_->task_runner_->PostDelayedTask( 49 FROM_HERE, 50 base::Bind(&CompositorLock::CancelLock, AsWeakPtr()), 51 base::TimeDelta::FromMilliseconds(kCompositorLockTimeoutMs)); 52} 53 54CompositorLock::~CompositorLock() { 55 CancelLock(); 56} 57 58void CompositorLock::CancelLock() { 59 if (!compositor_) 60 return; 61 compositor_->UnlockCompositor(); 62 compositor_ = NULL; 63} 64 65} // namespace ui 66 67namespace {} // namespace 68 69namespace ui { 70 71Compositor::Compositor(gfx::AcceleratedWidget widget, 72 ui::ContextFactory* context_factory, 73 scoped_refptr<base::SingleThreadTaskRunner> task_runner) 74 : context_factory_(context_factory), 75 root_layer_(NULL), 76 widget_(widget), 77 compositor_thread_loop_(context_factory->GetCompositorMessageLoop()), 78 task_runner_(task_runner), 79 vsync_manager_(new CompositorVSyncManager()), 80 device_scale_factor_(0.0f), 81 last_started_frame_(0), 82 last_ended_frame_(0), 83 disable_schedule_composite_(false), 84 compositor_lock_(NULL), 85 defer_draw_scheduling_(false), 86 waiting_on_compositing_end_(false), 87 draw_on_compositing_end_(false), 88 swap_state_(SWAP_NONE), 89 layer_animator_collection_(this), 90 schedule_draw_factory_(this) { 91 root_web_layer_ = cc::Layer::Create(); 92 93 CommandLine* command_line = CommandLine::ForCurrentProcess(); 94 95 cc::LayerTreeSettings settings; 96 settings.refresh_rate = 97 context_factory_->DoesCreateTestContexts() 98 ? kTestRefreshRate 99 : kDefaultRefreshRate; 100 settings.main_frame_before_draw_enabled = false; 101 settings.main_frame_before_activation_enabled = false; 102 settings.throttle_frame_production = 103 !command_line->HasSwitch(switches::kDisableGpuVsync); 104#if !defined(OS_MACOSX) 105 settings.partial_swap_enabled = 106 !command_line->HasSwitch(cc::switches::kUIDisablePartialSwap); 107#endif 108#if defined(OS_CHROMEOS) 109 settings.per_tile_painting_enabled = true; 110#endif 111 112 // These flags should be mirrored by renderer versions in content/renderer/. 113 settings.initial_debug_state.show_debug_borders = 114 command_line->HasSwitch(cc::switches::kUIShowCompositedLayerBorders); 115 settings.initial_debug_state.show_fps_counter = 116 command_line->HasSwitch(cc::switches::kUIShowFPSCounter); 117 settings.initial_debug_state.show_layer_animation_bounds_rects = 118 command_line->HasSwitch(cc::switches::kUIShowLayerAnimationBounds); 119 settings.initial_debug_state.show_paint_rects = 120 command_line->HasSwitch(switches::kUIShowPaintRects); 121 settings.initial_debug_state.show_property_changed_rects = 122 command_line->HasSwitch(cc::switches::kUIShowPropertyChangedRects); 123 settings.initial_debug_state.show_surface_damage_rects = 124 command_line->HasSwitch(cc::switches::kUIShowSurfaceDamageRects); 125 settings.initial_debug_state.show_screen_space_rects = 126 command_line->HasSwitch(cc::switches::kUIShowScreenSpaceRects); 127 settings.initial_debug_state.show_replica_screen_space_rects = 128 command_line->HasSwitch(cc::switches::kUIShowReplicaScreenSpaceRects); 129 settings.initial_debug_state.show_occluding_rects = 130 command_line->HasSwitch(cc::switches::kUIShowOccludingRects); 131 settings.initial_debug_state.show_non_occluding_rects = 132 command_line->HasSwitch(cc::switches::kUIShowNonOccludingRects); 133 134 settings.initial_debug_state.SetRecordRenderingStats( 135 command_line->HasSwitch(cc::switches::kEnableGpuBenchmarking)); 136 137 settings.impl_side_painting = IsUIImplSidePaintingEnabled(); 138 settings.use_zero_copy = IsUIZeroCopyEnabled(); 139 settings.single_thread_proxy_scheduler = false; 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 cc::BeginFrameArgs args = 230 cc::BeginFrameArgs::Create(gfx::FrameTime::Now(), 231 base::TimeTicks(), 232 cc::BeginFrameArgs::DefaultInterval()); 233 BeginMainFrame(args); 234 Layout(); 235 host_->Composite(args.frame_time); 236 } 237 if (swap_state_ == SWAP_NONE) 238 NotifyEnd(); 239} 240 241void Compositor::ScheduleFullRedraw() { 242 host_->SetNeedsRedraw(); 243} 244 245void Compositor::ScheduleRedrawRect(const gfx::Rect& damage_rect) { 246 host_->SetNeedsRedrawRect(damage_rect); 247} 248 249void Compositor::FinishAllRendering() { 250 host_->FinishAllRendering(); 251} 252 253void Compositor::SetLatencyInfo(const ui::LatencyInfo& latency_info) { 254 scoped_ptr<cc::SwapPromise> swap_promise( 255 new cc::LatencyInfoSwapPromise(latency_info)); 256 host_->QueueSwapPromise(swap_promise.Pass()); 257} 258 259void Compositor::SetScaleAndSize(float scale, const gfx::Size& size_in_pixel) { 260 DCHECK_GT(scale, 0); 261 if (!size_in_pixel.IsEmpty()) { 262 size_ = size_in_pixel; 263 host_->SetViewportSize(size_in_pixel); 264 root_web_layer_->SetBounds(size_in_pixel); 265 } 266 if (device_scale_factor_ != scale) { 267 device_scale_factor_ = scale; 268 host_->SetDeviceScaleFactor(scale); 269 if (root_layer_) 270 root_layer_->OnDeviceScaleFactorChanged(scale); 271 } 272} 273 274void Compositor::SetBackgroundColor(SkColor color) { 275 host_->set_background_color(color); 276 ScheduleDraw(); 277} 278 279scoped_refptr<CompositorVSyncManager> Compositor::vsync_manager() const { 280 return vsync_manager_; 281} 282 283void Compositor::AddObserver(CompositorObserver* observer) { 284#if defined(OS_MACOSX) 285 // Debugging instrumentation for crbug.com/401630. 286 // TODO(ccameron): remove this. 287 CHECK(observer); 288 if (!observer_list_.HasObserver(observer)) 289 observer->observing_count_ += 1; 290#endif 291 292 observer_list_.AddObserver(observer); 293} 294 295void Compositor::RemoveObserver(CompositorObserver* observer) { 296#if defined(OS_MACOSX) 297 // Debugging instrumentation for crbug.com/401630. 298 // TODO(ccameron): remove this. 299 if (observer_list_.HasObserver(observer)) 300 observer->observing_count_ -= 1; 301#endif 302 303 observer_list_.RemoveObserver(observer); 304} 305 306bool Compositor::HasObserver(CompositorObserver* observer) { 307 return observer_list_.HasObserver(observer); 308} 309 310void Compositor::AddAnimationObserver(CompositorAnimationObserver* observer) { 311 animation_observer_list_.AddObserver(observer); 312 host_->SetNeedsAnimate(); 313} 314 315void Compositor::RemoveAnimationObserver( 316 CompositorAnimationObserver* observer) { 317 animation_observer_list_.RemoveObserver(observer); 318} 319 320bool Compositor::HasAnimationObserver(CompositorAnimationObserver* observer) { 321 return animation_observer_list_.HasObserver(observer); 322} 323 324void Compositor::BeginMainFrame(const cc::BeginFrameArgs& args) { 325 FOR_EACH_OBSERVER(CompositorAnimationObserver, 326 animation_observer_list_, 327 OnAnimationStep(args.frame_time)); 328 if (animation_observer_list_.might_have_observers()) 329 host_->SetNeedsAnimate(); 330} 331 332void Compositor::Layout() { 333 // We're sending damage that will be addressed during this composite 334 // cycle, so we don't need to schedule another composite to address it. 335 disable_schedule_composite_ = true; 336 if (root_layer_) 337 root_layer_->SendDamagedRects(); 338 disable_schedule_composite_ = false; 339} 340 341scoped_ptr<cc::OutputSurface> Compositor::CreateOutputSurface(bool fallback) { 342 return context_factory_->CreateOutputSurface(this, fallback); 343} 344 345void Compositor::DidCommit() { 346 DCHECK(!IsLocked()); 347 FOR_EACH_OBSERVER(CompositorObserver, 348 observer_list_, 349 OnCompositingDidCommit(this)); 350} 351 352void Compositor::DidCommitAndDrawFrame() { 353 base::TimeTicks start_time = gfx::FrameTime::Now(); 354 FOR_EACH_OBSERVER(CompositorObserver, 355 observer_list_, 356 OnCompositingStarted(this, start_time)); 357} 358 359void Compositor::DidCompleteSwapBuffers() { 360 if (compositor_thread_loop_) { 361 NotifyEnd(); 362 } else { 363 DCHECK_EQ(swap_state_, SWAP_POSTED); 364 NotifyEnd(); 365 swap_state_ = SWAP_COMPLETED; 366 } 367} 368 369void Compositor::ScheduleComposite() { 370 if (!disable_schedule_composite_) 371 ScheduleDraw(); 372} 373 374void Compositor::ScheduleAnimation() { 375 ScheduleComposite(); 376} 377 378void Compositor::DidPostSwapBuffers() { 379 DCHECK(!compositor_thread_loop_); 380 DCHECK_EQ(swap_state_, SWAP_NONE); 381 swap_state_ = SWAP_POSTED; 382} 383 384void Compositor::DidAbortSwapBuffers() { 385 if (!compositor_thread_loop_) { 386 if (swap_state_ == SWAP_POSTED) { 387 NotifyEnd(); 388 swap_state_ = SWAP_COMPLETED; 389 } 390 } 391 392 FOR_EACH_OBSERVER(CompositorObserver, 393 observer_list_, 394 OnCompositingAborted(this)); 395} 396 397const cc::LayerTreeDebugState& Compositor::GetLayerTreeDebugState() const { 398 return host_->debug_state(); 399} 400 401void Compositor::SetLayerTreeDebugState( 402 const cc::LayerTreeDebugState& debug_state) { 403 host_->SetDebugState(debug_state); 404} 405 406scoped_refptr<CompositorLock> Compositor::GetCompositorLock() { 407 if (!compositor_lock_) { 408 compositor_lock_ = new CompositorLock(this); 409 if (compositor_thread_loop_) 410 host_->SetDeferCommits(true); 411 FOR_EACH_OBSERVER(CompositorObserver, 412 observer_list_, 413 OnCompositingLockStateChanged(this)); 414 } 415 return compositor_lock_; 416} 417 418void Compositor::UnlockCompositor() { 419 DCHECK(compositor_lock_); 420 compositor_lock_ = NULL; 421 if (compositor_thread_loop_) 422 host_->SetDeferCommits(false); 423 FOR_EACH_OBSERVER(CompositorObserver, 424 observer_list_, 425 OnCompositingLockStateChanged(this)); 426} 427 428void Compositor::CancelCompositorLock() { 429 if (compositor_lock_) 430 compositor_lock_->CancelLock(); 431} 432 433void Compositor::NotifyEnd() { 434 last_ended_frame_++; 435 TRACE_EVENT_ASYNC_END0("ui", "Compositor::Draw", last_ended_frame_); 436 waiting_on_compositing_end_ = false; 437 if (draw_on_compositing_end_) { 438 draw_on_compositing_end_ = false; 439 440 // Call ScheduleDraw() instead of Draw() in order to allow other 441 // CompositorObservers to be notified before starting another 442 // draw cycle. 443 ScheduleDraw(); 444 } 445 FOR_EACH_OBSERVER( 446 CompositorObserver, observer_list_, OnCompositingEnded(this)); 447} 448 449} // namespace ui 450