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