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