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