| OLD | NEW |
| (Empty) |
| 1 // Copyright 2011 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 "cc/trees/thread_proxy.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 #include <string> | |
| 9 | |
| 10 #include "base/auto_reset.h" | |
| 11 #include "base/bind.h" | |
| 12 #include "base/trace_event/trace_event.h" | |
| 13 #include "base/trace_event/trace_event_argument.h" | |
| 14 #include "base/trace_event/trace_event_synthetic_delay.h" | |
| 15 #include "cc/debug/benchmark_instrumentation.h" | |
| 16 #include "cc/debug/devtools_instrumentation.h" | |
| 17 #include "cc/input/input_handler.h" | |
| 18 #include "cc/output/context_provider.h" | |
| 19 #include "cc/output/output_surface.h" | |
| 20 #include "cc/output/swap_promise.h" | |
| 21 #include "cc/quads/draw_quad.h" | |
| 22 #include "cc/resources/prioritized_resource_manager.h" | |
| 23 #include "cc/scheduler/commit_earlyout_reason.h" | |
| 24 #include "cc/scheduler/delay_based_time_source.h" | |
| 25 #include "cc/scheduler/scheduler.h" | |
| 26 #include "cc/trees/blocking_task_runner.h" | |
| 27 #include "cc/trees/layer_tree_host.h" | |
| 28 #include "cc/trees/layer_tree_impl.h" | |
| 29 #include "cc/trees/scoped_abort_remaining_swap_promises.h" | |
| 30 #include "gpu/command_buffer/client/gles2_interface.h" | |
| 31 #include "ui/gfx/frame_time.h" | |
| 32 | |
| 33 namespace cc { | |
| 34 | |
| 35 namespace { | |
| 36 | |
| 37 // Measured in seconds. | |
| 38 const double kSmoothnessTakesPriorityExpirationDelay = 0.25; | |
| 39 | |
| 40 unsigned int nextBeginFrameId = 0; | |
| 41 | |
| 42 } // namespace | |
| 43 | |
| 44 struct ThreadProxy::SchedulerStateRequest { | |
| 45 CompletionEvent completion; | |
| 46 scoped_ptr<base::Value> state; | |
| 47 }; | |
| 48 | |
| 49 scoped_ptr<Proxy> ThreadProxy::Create( | |
| 50 LayerTreeHost* layer_tree_host, | |
| 51 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, | |
| 52 scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner, | |
| 53 scoped_ptr<BeginFrameSource> external_begin_frame_source) { | |
| 54 return make_scoped_ptr(new ThreadProxy(layer_tree_host, | |
| 55 main_task_runner, | |
| 56 impl_task_runner, | |
| 57 external_begin_frame_source.Pass())); | |
| 58 } | |
| 59 | |
| 60 ThreadProxy::ThreadProxy( | |
| 61 LayerTreeHost* layer_tree_host, | |
| 62 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, | |
| 63 scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner, | |
| 64 scoped_ptr<BeginFrameSource> external_begin_frame_source) | |
| 65 : Proxy(main_task_runner, impl_task_runner), | |
| 66 main_thread_only_vars_unsafe_(this, layer_tree_host->id()), | |
| 67 main_thread_or_blocked_vars_unsafe_(layer_tree_host), | |
| 68 compositor_thread_vars_unsafe_( | |
| 69 this, | |
| 70 layer_tree_host->id(), | |
| 71 layer_tree_host->rendering_stats_instrumentation(), | |
| 72 external_begin_frame_source.Pass()) { | |
| 73 TRACE_EVENT0("cc", "ThreadProxy::ThreadProxy"); | |
| 74 DCHECK(IsMainThread()); | |
| 75 DCHECK(this->layer_tree_host()); | |
| 76 } | |
| 77 | |
| 78 ThreadProxy::MainThreadOnly::MainThreadOnly(ThreadProxy* proxy, | |
| 79 int layer_tree_host_id) | |
| 80 : layer_tree_host_id(layer_tree_host_id), | |
| 81 animate_requested(false), | |
| 82 commit_requested(false), | |
| 83 commit_request_sent_to_impl_thread(false), | |
| 84 started(false), | |
| 85 prepare_tiles_pending(false), | |
| 86 can_cancel_commit(true), | |
| 87 defer_commits(false), | |
| 88 weak_factory(proxy) { | |
| 89 } | |
| 90 | |
| 91 ThreadProxy::MainThreadOnly::~MainThreadOnly() {} | |
| 92 | |
| 93 ThreadProxy::MainThreadOrBlockedMainThread::MainThreadOrBlockedMainThread( | |
| 94 LayerTreeHost* host) | |
| 95 : layer_tree_host(host), | |
| 96 commit_waits_for_activation(false), | |
| 97 main_thread_inside_commit(false) {} | |
| 98 | |
| 99 ThreadProxy::MainThreadOrBlockedMainThread::~MainThreadOrBlockedMainThread() {} | |
| 100 | |
| 101 PrioritizedResourceManager* | |
| 102 ThreadProxy::MainThreadOrBlockedMainThread::contents_texture_manager() { | |
| 103 return layer_tree_host->contents_texture_manager(); | |
| 104 } | |
| 105 | |
| 106 ThreadProxy::CompositorThreadOnly::CompositorThreadOnly( | |
| 107 ThreadProxy* proxy, | |
| 108 int layer_tree_host_id, | |
| 109 RenderingStatsInstrumentation* rendering_stats_instrumentation, | |
| 110 scoped_ptr<BeginFrameSource> external_begin_frame_source) | |
| 111 : layer_tree_host_id(layer_tree_host_id), | |
| 112 contents_texture_manager(NULL), | |
| 113 commit_completion_event(NULL), | |
| 114 completion_event_for_commit_held_on_tree_activation(NULL), | |
| 115 next_frame_is_newly_committed_frame(false), | |
| 116 inside_draw(false), | |
| 117 input_throttled_until_commit(false), | |
| 118 smoothness_priority_expiration_notifier( | |
| 119 proxy->ImplThreadTaskRunner(), | |
| 120 base::Bind(&ThreadProxy::RenewTreePriority, base::Unretained(proxy)), | |
| 121 base::TimeDelta::FromMilliseconds( | |
| 122 kSmoothnessTakesPriorityExpirationDelay * 1000)), | |
| 123 timing_history(rendering_stats_instrumentation), | |
| 124 external_begin_frame_source(external_begin_frame_source.Pass()), | |
| 125 weak_factory(proxy) { | |
| 126 } | |
| 127 | |
| 128 ThreadProxy::CompositorThreadOnly::~CompositorThreadOnly() {} | |
| 129 | |
| 130 ThreadProxy::~ThreadProxy() { | |
| 131 TRACE_EVENT0("cc", "ThreadProxy::~ThreadProxy"); | |
| 132 DCHECK(IsMainThread()); | |
| 133 DCHECK(!main().started); | |
| 134 } | |
| 135 | |
| 136 void ThreadProxy::FinishAllRendering() { | |
| 137 DCHECK(Proxy::IsMainThread()); | |
| 138 DCHECK(!main().defer_commits); | |
| 139 | |
| 140 // Make sure all GL drawing is finished on the impl thread. | |
| 141 DebugScopedSetMainThreadBlocked main_thread_blocked(this); | |
| 142 CompletionEvent completion; | |
| 143 Proxy::ImplThreadTaskRunner()->PostTask( | |
| 144 FROM_HERE, | |
| 145 base::Bind(&ThreadProxy::FinishAllRenderingOnImplThread, | |
| 146 impl_thread_weak_ptr_, | |
| 147 &completion)); | |
| 148 completion.Wait(); | |
| 149 } | |
| 150 | |
| 151 bool ThreadProxy::IsStarted() const { | |
| 152 DCHECK(Proxy::IsMainThread()); | |
| 153 return main().started; | |
| 154 } | |
| 155 | |
| 156 bool ThreadProxy::CommitToActiveTree() const { | |
| 157 // With ThreadProxy and impl-side painting, we use a pending tree and activate | |
| 158 // it once it's ready to draw. | |
| 159 return !impl().layer_tree_host_impl->settings().impl_side_painting; | |
| 160 } | |
| 161 | |
| 162 void ThreadProxy::SetLayerTreeHostClientReady() { | |
| 163 TRACE_EVENT0("cc", "ThreadProxy::SetLayerTreeHostClientReady"); | |
| 164 Proxy::ImplThreadTaskRunner()->PostTask( | |
| 165 FROM_HERE, | |
| 166 base::Bind(&ThreadProxy::SetLayerTreeHostClientReadyOnImplThread, | |
| 167 impl_thread_weak_ptr_)); | |
| 168 } | |
| 169 | |
| 170 void ThreadProxy::SetLayerTreeHostClientReadyOnImplThread() { | |
| 171 TRACE_EVENT0("cc", "ThreadProxy::SetLayerTreeHostClientReadyOnImplThread"); | |
| 172 impl().scheduler->SetCanStart(); | |
| 173 } | |
| 174 | |
| 175 void ThreadProxy::SetVisible(bool visible) { | |
| 176 TRACE_EVENT1("cc", "ThreadProxy::SetVisible", "visible", visible); | |
| 177 DebugScopedSetMainThreadBlocked main_thread_blocked(this); | |
| 178 | |
| 179 CompletionEvent completion; | |
| 180 Proxy::ImplThreadTaskRunner()->PostTask( | |
| 181 FROM_HERE, | |
| 182 base::Bind(&ThreadProxy::SetVisibleOnImplThread, | |
| 183 impl_thread_weak_ptr_, | |
| 184 &completion, | |
| 185 visible)); | |
| 186 completion.Wait(); | |
| 187 } | |
| 188 | |
| 189 void ThreadProxy::SetVisibleOnImplThread(CompletionEvent* completion, | |
| 190 bool visible) { | |
| 191 TRACE_EVENT1("cc", "ThreadProxy::SetVisibleOnImplThread", "visible", visible); | |
| 192 impl().layer_tree_host_impl->SetVisible(visible); | |
| 193 impl().scheduler->SetVisible(visible); | |
| 194 completion->Signal(); | |
| 195 } | |
| 196 | |
| 197 void ThreadProxy::SetThrottleFrameProduction(bool throttle) { | |
| 198 TRACE_EVENT1("cc", "ThreadProxy::SetThrottleFrameProduction", "throttle", | |
| 199 throttle); | |
| 200 Proxy::ImplThreadTaskRunner()->PostTask( | |
| 201 FROM_HERE, | |
| 202 base::Bind(&ThreadProxy::SetThrottleFrameProductionOnImplThread, | |
| 203 impl_thread_weak_ptr_, throttle)); | |
| 204 } | |
| 205 | |
| 206 void ThreadProxy::SetThrottleFrameProductionOnImplThread(bool throttle) { | |
| 207 TRACE_EVENT1("cc", "ThreadProxy::SetThrottleFrameProductionOnImplThread", | |
| 208 "throttle", throttle); | |
| 209 impl().scheduler->SetThrottleFrameProduction(throttle); | |
| 210 } | |
| 211 | |
| 212 void ThreadProxy::DidLoseOutputSurface() { | |
| 213 TRACE_EVENT0("cc", "ThreadProxy::DidLoseOutputSurface"); | |
| 214 DCHECK(IsMainThread()); | |
| 215 layer_tree_host()->DidLoseOutputSurface(); | |
| 216 | |
| 217 { | |
| 218 DebugScopedSetMainThreadBlocked main_thread_blocked(this); | |
| 219 | |
| 220 // Return lost resources to their owners immediately. | |
| 221 BlockingTaskRunner::CapturePostTasks blocked( | |
| 222 blocking_main_thread_task_runner()); | |
| 223 | |
| 224 CompletionEvent completion; | |
| 225 Proxy::ImplThreadTaskRunner()->PostTask( | |
| 226 FROM_HERE, | |
| 227 base::Bind(&ThreadProxy::DeleteContentsTexturesOnImplThread, | |
| 228 impl_thread_weak_ptr_, | |
| 229 &completion)); | |
| 230 completion.Wait(); | |
| 231 } | |
| 232 } | |
| 233 | |
| 234 void ThreadProxy::RequestNewOutputSurface() { | |
| 235 DCHECK(IsMainThread()); | |
| 236 layer_tree_host()->RequestNewOutputSurface(); | |
| 237 } | |
| 238 | |
| 239 void ThreadProxy::SetOutputSurface(scoped_ptr<OutputSurface> output_surface) { | |
| 240 Proxy::ImplThreadTaskRunner()->PostTask( | |
| 241 FROM_HERE, | |
| 242 base::Bind(&ThreadProxy::InitializeOutputSurfaceOnImplThread, | |
| 243 impl_thread_weak_ptr_, base::Passed(&output_surface))); | |
| 244 } | |
| 245 | |
| 246 void ThreadProxy::DidInitializeOutputSurface( | |
| 247 bool success, | |
| 248 const RendererCapabilities& capabilities) { | |
| 249 TRACE_EVENT0("cc", "ThreadProxy::DidInitializeOutputSurface"); | |
| 250 DCHECK(IsMainThread()); | |
| 251 | |
| 252 if (!success) { | |
| 253 layer_tree_host()->DidFailToInitializeOutputSurface(); | |
| 254 return; | |
| 255 } | |
| 256 main().renderer_capabilities_main_thread_copy = capabilities; | |
| 257 layer_tree_host()->DidInitializeOutputSurface(); | |
| 258 } | |
| 259 | |
| 260 void ThreadProxy::SetRendererCapabilitiesMainThreadCopy( | |
| 261 const RendererCapabilities& capabilities) { | |
| 262 main().renderer_capabilities_main_thread_copy = capabilities; | |
| 263 } | |
| 264 | |
| 265 void ThreadProxy::SendCommitRequestToImplThreadIfNeeded() { | |
| 266 DCHECK(IsMainThread()); | |
| 267 if (main().commit_request_sent_to_impl_thread) | |
| 268 return; | |
| 269 main().commit_request_sent_to_impl_thread = true; | |
| 270 Proxy::ImplThreadTaskRunner()->PostTask( | |
| 271 FROM_HERE, | |
| 272 base::Bind(&ThreadProxy::SetNeedsCommitOnImplThread, | |
| 273 impl_thread_weak_ptr_)); | |
| 274 } | |
| 275 | |
| 276 void ThreadProxy::DidCompletePageScaleAnimation() { | |
| 277 DCHECK(IsMainThread()); | |
| 278 layer_tree_host()->DidCompletePageScaleAnimation(); | |
| 279 } | |
| 280 | |
| 281 const RendererCapabilities& ThreadProxy::GetRendererCapabilities() const { | |
| 282 DCHECK(IsMainThread()); | |
| 283 DCHECK(!layer_tree_host()->output_surface_lost()); | |
| 284 return main().renderer_capabilities_main_thread_copy; | |
| 285 } | |
| 286 | |
| 287 void ThreadProxy::SetNeedsAnimate() { | |
| 288 DCHECK(IsMainThread()); | |
| 289 if (main().animate_requested) | |
| 290 return; | |
| 291 | |
| 292 TRACE_EVENT0("cc", "ThreadProxy::SetNeedsAnimate"); | |
| 293 main().animate_requested = true; | |
| 294 SendCommitRequestToImplThreadIfNeeded(); | |
| 295 } | |
| 296 | |
| 297 void ThreadProxy::SetNeedsUpdateLayers() { | |
| 298 DCHECK(IsMainThread()); | |
| 299 | |
| 300 if (main().commit_request_sent_to_impl_thread) | |
| 301 return; | |
| 302 TRACE_EVENT0("cc", "ThreadProxy::SetNeedsUpdateLayers"); | |
| 303 | |
| 304 SendCommitRequestToImplThreadIfNeeded(); | |
| 305 } | |
| 306 | |
| 307 void ThreadProxy::SetNeedsCommit() { | |
| 308 DCHECK(IsMainThread()); | |
| 309 // Unconditionally set here to handle SetNeedsCommit calls during a commit. | |
| 310 main().can_cancel_commit = false; | |
| 311 | |
| 312 if (main().commit_requested) | |
| 313 return; | |
| 314 TRACE_EVENT0("cc", "ThreadProxy::SetNeedsCommit"); | |
| 315 main().commit_requested = true; | |
| 316 | |
| 317 SendCommitRequestToImplThreadIfNeeded(); | |
| 318 } | |
| 319 | |
| 320 void ThreadProxy::UpdateRendererCapabilitiesOnImplThread() { | |
| 321 DCHECK(IsImplThread()); | |
| 322 Proxy::MainThreadTaskRunner()->PostTask( | |
| 323 FROM_HERE, | |
| 324 base::Bind(&ThreadProxy::SetRendererCapabilitiesMainThreadCopy, | |
| 325 main_thread_weak_ptr_, | |
| 326 impl() | |
| 327 .layer_tree_host_impl->GetRendererCapabilities() | |
| 328 .MainThreadCapabilities())); | |
| 329 } | |
| 330 | |
| 331 void ThreadProxy::DidLoseOutputSurfaceOnImplThread() { | |
| 332 TRACE_EVENT0("cc", "ThreadProxy::DidLoseOutputSurfaceOnImplThread"); | |
| 333 DCHECK(IsImplThread()); | |
| 334 Proxy::MainThreadTaskRunner()->PostTask( | |
| 335 FROM_HERE, | |
| 336 base::Bind(&ThreadProxy::DidLoseOutputSurface, main_thread_weak_ptr_)); | |
| 337 impl().scheduler->DidLoseOutputSurface(); | |
| 338 } | |
| 339 | |
| 340 void ThreadProxy::CommitVSyncParameters(base::TimeTicks timebase, | |
| 341 base::TimeDelta interval) { | |
| 342 impl().scheduler->CommitVSyncParameters(timebase, interval); | |
| 343 } | |
| 344 | |
| 345 void ThreadProxy::SetEstimatedParentDrawTime(base::TimeDelta draw_time) { | |
| 346 impl().scheduler->SetEstimatedParentDrawTime(draw_time); | |
| 347 } | |
| 348 | |
| 349 void ThreadProxy::SetMaxSwapsPendingOnImplThread(int max) { | |
| 350 impl().scheduler->SetMaxSwapsPending(max); | |
| 351 } | |
| 352 | |
| 353 void ThreadProxy::DidSwapBuffersOnImplThread() { | |
| 354 impl().scheduler->DidSwapBuffers(); | |
| 355 } | |
| 356 | |
| 357 void ThreadProxy::DidSwapBuffersCompleteOnImplThread() { | |
| 358 TRACE_EVENT0("cc,benchmark", | |
| 359 "ThreadProxy::DidSwapBuffersCompleteOnImplThread"); | |
| 360 DCHECK(IsImplThread()); | |
| 361 impl().scheduler->DidSwapBuffersComplete(); | |
| 362 Proxy::MainThreadTaskRunner()->PostTask( | |
| 363 FROM_HERE, | |
| 364 base::Bind(&ThreadProxy::DidCompleteSwapBuffers, main_thread_weak_ptr_)); | |
| 365 } | |
| 366 | |
| 367 void ThreadProxy::WillBeginImplFrame(const BeginFrameArgs& args) { | |
| 368 impl().layer_tree_host_impl->WillBeginImplFrame(args); | |
| 369 } | |
| 370 | |
| 371 void ThreadProxy::OnCanDrawStateChanged(bool can_draw) { | |
| 372 TRACE_EVENT1( | |
| 373 "cc", "ThreadProxy::OnCanDrawStateChanged", "can_draw", can_draw); | |
| 374 DCHECK(IsImplThread()); | |
| 375 impl().scheduler->SetCanDraw(can_draw); | |
| 376 } | |
| 377 | |
| 378 void ThreadProxy::NotifyReadyToActivate() { | |
| 379 TRACE_EVENT0("cc", "ThreadProxy::NotifyReadyToActivate"); | |
| 380 impl().scheduler->NotifyReadyToActivate(); | |
| 381 } | |
| 382 | |
| 383 void ThreadProxy::NotifyReadyToDraw() { | |
| 384 TRACE_EVENT0("cc", "ThreadProxy::NotifyReadyToDraw"); | |
| 385 impl().scheduler->NotifyReadyToDraw(); | |
| 386 } | |
| 387 | |
| 388 void ThreadProxy::SetNeedsCommitOnImplThread() { | |
| 389 TRACE_EVENT0("cc", "ThreadProxy::SetNeedsCommitOnImplThread"); | |
| 390 DCHECK(IsImplThread()); | |
| 391 impl().scheduler->SetNeedsCommit(); | |
| 392 } | |
| 393 | |
| 394 void ThreadProxy::PostAnimationEventsToMainThreadOnImplThread( | |
| 395 scoped_ptr<AnimationEventsVector> events) { | |
| 396 TRACE_EVENT0("cc", | |
| 397 "ThreadProxy::PostAnimationEventsToMainThreadOnImplThread"); | |
| 398 DCHECK(IsImplThread()); | |
| 399 Proxy::MainThreadTaskRunner()->PostTask( | |
| 400 FROM_HERE, | |
| 401 base::Bind(&ThreadProxy::SetAnimationEvents, | |
| 402 main_thread_weak_ptr_, | |
| 403 base::Passed(&events))); | |
| 404 } | |
| 405 | |
| 406 bool ThreadProxy::ReduceContentsTextureMemoryOnImplThread(size_t limit_bytes, | |
| 407 int priority_cutoff) { | |
| 408 DCHECK(IsImplThread()); | |
| 409 | |
| 410 if (!impl().contents_texture_manager) | |
| 411 return false; | |
| 412 if (!impl().layer_tree_host_impl->resource_provider()) | |
| 413 return false; | |
| 414 | |
| 415 bool reduce_result = | |
| 416 impl().contents_texture_manager->ReduceMemoryOnImplThread( | |
| 417 limit_bytes, | |
| 418 priority_cutoff, | |
| 419 impl().layer_tree_host_impl->resource_provider()); | |
| 420 if (!reduce_result) | |
| 421 return false; | |
| 422 | |
| 423 // The texture upload queue may reference textures that were just purged, | |
| 424 // clear them from the queue. | |
| 425 if (impl().current_resource_update_controller) { | |
| 426 impl() | |
| 427 .current_resource_update_controller->DiscardUploadsToEvictedResources(); | |
| 428 } | |
| 429 return true; | |
| 430 } | |
| 431 | |
| 432 bool ThreadProxy::IsInsideDraw() { return impl().inside_draw; } | |
| 433 | |
| 434 void ThreadProxy::SetNeedsRedraw(const gfx::Rect& damage_rect) { | |
| 435 TRACE_EVENT0("cc", "ThreadProxy::SetNeedsRedraw"); | |
| 436 DCHECK(IsMainThread()); | |
| 437 Proxy::ImplThreadTaskRunner()->PostTask( | |
| 438 FROM_HERE, | |
| 439 base::Bind(&ThreadProxy::SetNeedsRedrawRectOnImplThread, | |
| 440 impl_thread_weak_ptr_, | |
| 441 damage_rect)); | |
| 442 } | |
| 443 | |
| 444 void ThreadProxy::SetNextCommitWaitsForActivation() { | |
| 445 DCHECK(IsMainThread()); | |
| 446 DCHECK(!blocked_main().main_thread_inside_commit); | |
| 447 blocked_main().commit_waits_for_activation = true; | |
| 448 } | |
| 449 | |
| 450 void ThreadProxy::SetDeferCommits(bool defer_commits) { | |
| 451 DCHECK(IsMainThread()); | |
| 452 if (main().defer_commits == defer_commits) | |
| 453 return; | |
| 454 | |
| 455 main().defer_commits = defer_commits; | |
| 456 if (main().defer_commits) | |
| 457 TRACE_EVENT_ASYNC_BEGIN0("cc", "ThreadProxy::SetDeferCommits", this); | |
| 458 else | |
| 459 TRACE_EVENT_ASYNC_END0("cc", "ThreadProxy::SetDeferCommits", this); | |
| 460 | |
| 461 Proxy::ImplThreadTaskRunner()->PostTask( | |
| 462 FROM_HERE, | |
| 463 base::Bind(&ThreadProxy::SetDeferCommitsOnImplThread, | |
| 464 impl_thread_weak_ptr_, | |
| 465 defer_commits)); | |
| 466 } | |
| 467 | |
| 468 void ThreadProxy::SetDeferCommitsOnImplThread(bool defer_commits) const { | |
| 469 DCHECK(IsImplThread()); | |
| 470 impl().scheduler->SetDeferCommits(defer_commits); | |
| 471 } | |
| 472 | |
| 473 bool ThreadProxy::CommitRequested() const { | |
| 474 DCHECK(IsMainThread()); | |
| 475 return main().commit_requested; | |
| 476 } | |
| 477 | |
| 478 bool ThreadProxy::BeginMainFrameRequested() const { | |
| 479 DCHECK(IsMainThread()); | |
| 480 return main().commit_request_sent_to_impl_thread; | |
| 481 } | |
| 482 | |
| 483 void ThreadProxy::SetNeedsRedrawOnImplThread() { | |
| 484 TRACE_EVENT0("cc", "ThreadProxy::SetNeedsRedrawOnImplThread"); | |
| 485 DCHECK(IsImplThread()); | |
| 486 impl().scheduler->SetNeedsRedraw(); | |
| 487 } | |
| 488 | |
| 489 void ThreadProxy::SetNeedsAnimateOnImplThread() { | |
| 490 TRACE_EVENT0("cc", "ThreadProxy::SetNeedsAnimateOnImplThread"); | |
| 491 DCHECK(IsImplThread()); | |
| 492 impl().scheduler->SetNeedsAnimate(); | |
| 493 } | |
| 494 | |
| 495 void ThreadProxy::SetNeedsPrepareTilesOnImplThread() { | |
| 496 DCHECK(IsImplThread()); | |
| 497 impl().scheduler->SetNeedsPrepareTiles(); | |
| 498 } | |
| 499 | |
| 500 void ThreadProxy::SetNeedsRedrawRectOnImplThread(const gfx::Rect& damage_rect) { | |
| 501 DCHECK(IsImplThread()); | |
| 502 impl().layer_tree_host_impl->SetViewportDamage(damage_rect); | |
| 503 SetNeedsRedrawOnImplThread(); | |
| 504 } | |
| 505 | |
| 506 void ThreadProxy::MainThreadHasStoppedFlinging() { | |
| 507 DCHECK(IsMainThread()); | |
| 508 Proxy::ImplThreadTaskRunner()->PostTask( | |
| 509 FROM_HERE, | |
| 510 base::Bind(&ThreadProxy::MainThreadHasStoppedFlingingOnImplThread, | |
| 511 impl_thread_weak_ptr_)); | |
| 512 } | |
| 513 | |
| 514 void ThreadProxy::MainThreadHasStoppedFlingingOnImplThread() { | |
| 515 DCHECK(IsImplThread()); | |
| 516 impl().layer_tree_host_impl->MainThreadHasStoppedFlinging(); | |
| 517 } | |
| 518 | |
| 519 void ThreadProxy::NotifyInputThrottledUntilCommit() { | |
| 520 DCHECK(IsMainThread()); | |
| 521 Proxy::ImplThreadTaskRunner()->PostTask( | |
| 522 FROM_HERE, | |
| 523 base::Bind(&ThreadProxy::SetInputThrottledUntilCommitOnImplThread, | |
| 524 impl_thread_weak_ptr_, | |
| 525 true)); | |
| 526 } | |
| 527 | |
| 528 void ThreadProxy::SetInputThrottledUntilCommitOnImplThread(bool is_throttled) { | |
| 529 DCHECK(IsImplThread()); | |
| 530 if (is_throttled == impl().input_throttled_until_commit) | |
| 531 return; | |
| 532 impl().input_throttled_until_commit = is_throttled; | |
| 533 RenewTreePriority(); | |
| 534 } | |
| 535 | |
| 536 LayerTreeHost* ThreadProxy::layer_tree_host() { | |
| 537 return blocked_main().layer_tree_host; | |
| 538 } | |
| 539 | |
| 540 const LayerTreeHost* ThreadProxy::layer_tree_host() const { | |
| 541 return blocked_main().layer_tree_host; | |
| 542 } | |
| 543 | |
| 544 ThreadProxy::MainThreadOnly& ThreadProxy::main() { | |
| 545 DCHECK(IsMainThread()); | |
| 546 return main_thread_only_vars_unsafe_; | |
| 547 } | |
| 548 const ThreadProxy::MainThreadOnly& ThreadProxy::main() const { | |
| 549 DCHECK(IsMainThread()); | |
| 550 return main_thread_only_vars_unsafe_; | |
| 551 } | |
| 552 | |
| 553 ThreadProxy::MainThreadOrBlockedMainThread& ThreadProxy::blocked_main() { | |
| 554 DCHECK(IsMainThread() || IsMainThreadBlocked()); | |
| 555 return main_thread_or_blocked_vars_unsafe_; | |
| 556 } | |
| 557 | |
| 558 const ThreadProxy::MainThreadOrBlockedMainThread& ThreadProxy::blocked_main() | |
| 559 const { | |
| 560 DCHECK(IsMainThread() || IsMainThreadBlocked()); | |
| 561 return main_thread_or_blocked_vars_unsafe_; | |
| 562 } | |
| 563 | |
| 564 ThreadProxy::CompositorThreadOnly& ThreadProxy::impl() { | |
| 565 DCHECK(IsImplThread()); | |
| 566 return compositor_thread_vars_unsafe_; | |
| 567 } | |
| 568 | |
| 569 const ThreadProxy::CompositorThreadOnly& ThreadProxy::impl() const { | |
| 570 DCHECK(IsImplThread()); | |
| 571 return compositor_thread_vars_unsafe_; | |
| 572 } | |
| 573 | |
| 574 void ThreadProxy::Start() { | |
| 575 DCHECK(IsMainThread()); | |
| 576 DCHECK(Proxy::HasImplThread()); | |
| 577 | |
| 578 // Create LayerTreeHostImpl. | |
| 579 DebugScopedSetMainThreadBlocked main_thread_blocked(this); | |
| 580 CompletionEvent completion; | |
| 581 Proxy::ImplThreadTaskRunner()->PostTask( | |
| 582 FROM_HERE, | |
| 583 base::Bind(&ThreadProxy::InitializeImplOnImplThread, | |
| 584 base::Unretained(this), | |
| 585 &completion)); | |
| 586 completion.Wait(); | |
| 587 | |
| 588 main_thread_weak_ptr_ = main().weak_factory.GetWeakPtr(); | |
| 589 | |
| 590 main().started = true; | |
| 591 } | |
| 592 | |
| 593 void ThreadProxy::Stop() { | |
| 594 TRACE_EVENT0("cc", "ThreadProxy::Stop"); | |
| 595 DCHECK(IsMainThread()); | |
| 596 DCHECK(main().started); | |
| 597 | |
| 598 // Synchronously finishes pending GL operations and deletes the impl. | |
| 599 // The two steps are done as separate post tasks, so that tasks posted | |
| 600 // by the GL implementation due to the Finish can be executed by the | |
| 601 // renderer before shutting it down. | |
| 602 { | |
| 603 DebugScopedSetMainThreadBlocked main_thread_blocked(this); | |
| 604 | |
| 605 CompletionEvent completion; | |
| 606 Proxy::ImplThreadTaskRunner()->PostTask( | |
| 607 FROM_HERE, | |
| 608 base::Bind(&ThreadProxy::FinishGLOnImplThread, | |
| 609 impl_thread_weak_ptr_, | |
| 610 &completion)); | |
| 611 completion.Wait(); | |
| 612 } | |
| 613 { | |
| 614 DebugScopedSetMainThreadBlocked main_thread_blocked(this); | |
| 615 | |
| 616 CompletionEvent completion; | |
| 617 Proxy::ImplThreadTaskRunner()->PostTask( | |
| 618 FROM_HERE, | |
| 619 base::Bind(&ThreadProxy::LayerTreeHostClosedOnImplThread, | |
| 620 impl_thread_weak_ptr_, | |
| 621 &completion)); | |
| 622 completion.Wait(); | |
| 623 } | |
| 624 | |
| 625 main().weak_factory.InvalidateWeakPtrs(); | |
| 626 blocked_main().layer_tree_host = NULL; | |
| 627 main().started = false; | |
| 628 } | |
| 629 | |
| 630 void ThreadProxy::ForceSerializeOnSwapBuffers() { | |
| 631 DebugScopedSetMainThreadBlocked main_thread_blocked(this); | |
| 632 CompletionEvent completion; | |
| 633 Proxy::ImplThreadTaskRunner()->PostTask( | |
| 634 FROM_HERE, | |
| 635 base::Bind(&ThreadProxy::ForceSerializeOnSwapBuffersOnImplThread, | |
| 636 impl_thread_weak_ptr_, | |
| 637 &completion)); | |
| 638 completion.Wait(); | |
| 639 } | |
| 640 | |
| 641 void ThreadProxy::ForceSerializeOnSwapBuffersOnImplThread( | |
| 642 CompletionEvent* completion) { | |
| 643 if (impl().layer_tree_host_impl->renderer()) | |
| 644 impl().layer_tree_host_impl->renderer()->DoNoOp(); | |
| 645 completion->Signal(); | |
| 646 } | |
| 647 | |
| 648 bool ThreadProxy::SupportsImplScrolling() const { | |
| 649 return true; | |
| 650 } | |
| 651 | |
| 652 void ThreadProxy::SetDebugState(const LayerTreeDebugState& debug_state) { | |
| 653 Proxy::ImplThreadTaskRunner()->PostTask( | |
| 654 FROM_HERE, | |
| 655 base::Bind(&ThreadProxy::SetDebugStateOnImplThread, | |
| 656 impl_thread_weak_ptr_, | |
| 657 debug_state)); | |
| 658 } | |
| 659 | |
| 660 void ThreadProxy::SetDebugStateOnImplThread( | |
| 661 const LayerTreeDebugState& debug_state) { | |
| 662 DCHECK(IsImplThread()); | |
| 663 impl().scheduler->SetContinuousPainting(debug_state.continuous_painting); | |
| 664 } | |
| 665 | |
| 666 void ThreadProxy::FinishAllRenderingOnImplThread(CompletionEvent* completion) { | |
| 667 TRACE_EVENT0("cc", "ThreadProxy::FinishAllRenderingOnImplThread"); | |
| 668 DCHECK(IsImplThread()); | |
| 669 impl().layer_tree_host_impl->FinishAllRendering(); | |
| 670 completion->Signal(); | |
| 671 } | |
| 672 | |
| 673 void ThreadProxy::ScheduledActionSendBeginMainFrame() { | |
| 674 unsigned int begin_frame_id = nextBeginFrameId++; | |
| 675 benchmark_instrumentation::ScopedBeginFrameTask begin_frame_task( | |
| 676 benchmark_instrumentation::kSendBeginFrame, begin_frame_id); | |
| 677 scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state( | |
| 678 new BeginMainFrameAndCommitState); | |
| 679 begin_main_frame_state->begin_frame_id = begin_frame_id; | |
| 680 begin_main_frame_state->begin_frame_args = | |
| 681 impl().layer_tree_host_impl->CurrentBeginFrameArgs(); | |
| 682 begin_main_frame_state->scroll_info = | |
| 683 impl().layer_tree_host_impl->ProcessScrollDeltas(); | |
| 684 | |
| 685 if (!impl().layer_tree_host_impl->settings().impl_side_painting) { | |
| 686 DCHECK_GT(impl().layer_tree_host_impl->memory_allocation_limit_bytes(), 0u); | |
| 687 } | |
| 688 begin_main_frame_state->memory_allocation_limit_bytes = | |
| 689 impl().layer_tree_host_impl->memory_allocation_limit_bytes(); | |
| 690 begin_main_frame_state->memory_allocation_priority_cutoff = | |
| 691 impl().layer_tree_host_impl->memory_allocation_priority_cutoff(); | |
| 692 begin_main_frame_state->evicted_ui_resources = | |
| 693 impl().layer_tree_host_impl->EvictedUIResourcesExist(); | |
| 694 Proxy::MainThreadTaskRunner()->PostTask( | |
| 695 FROM_HERE, | |
| 696 base::Bind(&ThreadProxy::BeginMainFrame, | |
| 697 main_thread_weak_ptr_, | |
| 698 base::Passed(&begin_main_frame_state))); | |
| 699 devtools_instrumentation::DidRequestMainThreadFrame( | |
| 700 impl().layer_tree_host_id); | |
| 701 impl().timing_history.DidBeginMainFrame(); | |
| 702 } | |
| 703 | |
| 704 void ThreadProxy::SendBeginMainFrameNotExpectedSoon() { | |
| 705 Proxy::MainThreadTaskRunner()->PostTask( | |
| 706 FROM_HERE, base::Bind(&ThreadProxy::BeginMainFrameNotExpectedSoon, | |
| 707 main_thread_weak_ptr_)); | |
| 708 } | |
| 709 | |
| 710 void ThreadProxy::BeginMainFrame( | |
| 711 scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state) { | |
| 712 benchmark_instrumentation::ScopedBeginFrameTask begin_frame_task( | |
| 713 benchmark_instrumentation::kDoBeginFrame, | |
| 714 begin_main_frame_state->begin_frame_id); | |
| 715 TRACE_EVENT_SYNTHETIC_DELAY_BEGIN("cc.BeginMainFrame"); | |
| 716 DCHECK(IsMainThread()); | |
| 717 | |
| 718 if (main().defer_commits) { | |
| 719 TRACE_EVENT_INSTANT0("cc", "EarlyOut_DeferCommit", | |
| 720 TRACE_EVENT_SCOPE_THREAD); | |
| 721 Proxy::ImplThreadTaskRunner()->PostTask( | |
| 722 FROM_HERE, base::Bind(&ThreadProxy::BeginMainFrameAbortedOnImplThread, | |
| 723 impl_thread_weak_ptr_, | |
| 724 CommitEarlyOutReason::ABORTED_DEFERRED_COMMIT)); | |
| 725 return; | |
| 726 } | |
| 727 | |
| 728 // If the commit finishes, LayerTreeHost will transfer its swap promises to | |
| 729 // LayerTreeImpl. The destructor of ScopedSwapPromiseChecker aborts the | |
| 730 // remaining swap promises. | |
| 731 ScopedAbortRemainingSwapPromises swap_promise_checker(layer_tree_host()); | |
| 732 | |
| 733 main().commit_requested = false; | |
| 734 main().commit_request_sent_to_impl_thread = false; | |
| 735 main().animate_requested = false; | |
| 736 | |
| 737 if (!layer_tree_host()->visible()) { | |
| 738 TRACE_EVENT_INSTANT0("cc", "EarlyOut_NotVisible", TRACE_EVENT_SCOPE_THREAD); | |
| 739 Proxy::ImplThreadTaskRunner()->PostTask( | |
| 740 FROM_HERE, base::Bind(&ThreadProxy::BeginMainFrameAbortedOnImplThread, | |
| 741 impl_thread_weak_ptr_, | |
| 742 CommitEarlyOutReason::ABORTED_NOT_VISIBLE)); | |
| 743 return; | |
| 744 } | |
| 745 | |
| 746 if (layer_tree_host()->output_surface_lost()) { | |
| 747 TRACE_EVENT_INSTANT0( | |
| 748 "cc", "EarlyOut_OutputSurfaceLost", TRACE_EVENT_SCOPE_THREAD); | |
| 749 Proxy::ImplThreadTaskRunner()->PostTask( | |
| 750 FROM_HERE, | |
| 751 base::Bind(&ThreadProxy::BeginMainFrameAbortedOnImplThread, | |
| 752 impl_thread_weak_ptr_, | |
| 753 CommitEarlyOutReason::ABORTED_OUTPUT_SURFACE_LOST)); | |
| 754 return; | |
| 755 } | |
| 756 | |
| 757 // Do not notify the impl thread of commit requests that occur during | |
| 758 // the apply/animate/layout part of the BeginMainFrameAndCommit process since | |
| 759 // those commit requests will get painted immediately. Once we have done | |
| 760 // the paint, main().commit_requested will be set to false to allow new commit | |
| 761 // requests to be scheduled. | |
| 762 // On the other hand, the animate_requested flag should remain cleared | |
| 763 // here so that any animation requests generated by the apply or animate | |
| 764 // callbacks will trigger another frame. | |
| 765 main().commit_requested = true; | |
| 766 main().commit_request_sent_to_impl_thread = true; | |
| 767 | |
| 768 layer_tree_host()->ApplyScrollAndScale( | |
| 769 begin_main_frame_state->scroll_info.get()); | |
| 770 | |
| 771 layer_tree_host()->WillBeginMainFrame(); | |
| 772 | |
| 773 layer_tree_host()->BeginMainFrame(begin_main_frame_state->begin_frame_args); | |
| 774 layer_tree_host()->AnimateLayers( | |
| 775 begin_main_frame_state->begin_frame_args.frame_time); | |
| 776 | |
| 777 // Unlink any backings that the impl thread has evicted, so that we know to | |
| 778 // re-paint them in UpdateLayers. | |
| 779 if (blocked_main().contents_texture_manager()) { | |
| 780 blocked_main().contents_texture_manager()->UnlinkAndClearEvictedBackings(); | |
| 781 | |
| 782 blocked_main().contents_texture_manager()->SetMaxMemoryLimitBytes( | |
| 783 begin_main_frame_state->memory_allocation_limit_bytes); | |
| 784 blocked_main().contents_texture_manager()->SetExternalPriorityCutoff( | |
| 785 begin_main_frame_state->memory_allocation_priority_cutoff); | |
| 786 } | |
| 787 | |
| 788 // Recreate all UI resources if there were evicted UI resources when the impl | |
| 789 // thread initiated the commit. | |
| 790 if (begin_main_frame_state->evicted_ui_resources) | |
| 791 layer_tree_host()->RecreateUIResources(); | |
| 792 | |
| 793 layer_tree_host()->Layout(); | |
| 794 TRACE_EVENT_SYNTHETIC_DELAY_END("cc.BeginMainFrame"); | |
| 795 | |
| 796 // Clear the commit flag after updating animations and layout here --- objects | |
| 797 // that only layout when painted will trigger another SetNeedsCommit inside | |
| 798 // UpdateLayers. | |
| 799 main().commit_requested = false; | |
| 800 main().commit_request_sent_to_impl_thread = false; | |
| 801 bool can_cancel_this_commit = | |
| 802 main().can_cancel_commit && !begin_main_frame_state->evicted_ui_resources; | |
| 803 main().can_cancel_commit = true; | |
| 804 | |
| 805 scoped_ptr<ResourceUpdateQueue> queue = | |
| 806 make_scoped_ptr(new ResourceUpdateQueue); | |
| 807 | |
| 808 bool updated = layer_tree_host()->UpdateLayers(queue.get()); | |
| 809 | |
| 810 layer_tree_host()->WillCommit(); | |
| 811 devtools_instrumentation::ScopedCommitTrace commit_task( | |
| 812 layer_tree_host()->id()); | |
| 813 | |
| 814 // Before calling animate, we set main().animate_requested to false. If it is | |
| 815 // true now, it means SetNeedAnimate was called again, but during a state when | |
| 816 // main().commit_request_sent_to_impl_thread = true. We need to force that | |
| 817 // call to happen again now so that the commit request is sent to the impl | |
| 818 // thread. | |
| 819 if (main().animate_requested) { | |
| 820 // Forces SetNeedsAnimate to consider posting a commit task. | |
| 821 main().animate_requested = false; | |
| 822 SetNeedsAnimate(); | |
| 823 } | |
| 824 | |
| 825 if (!updated && can_cancel_this_commit) { | |
| 826 TRACE_EVENT_INSTANT0("cc", "EarlyOut_NoUpdates", TRACE_EVENT_SCOPE_THREAD); | |
| 827 Proxy::ImplThreadTaskRunner()->PostTask( | |
| 828 FROM_HERE, base::Bind(&ThreadProxy::BeginMainFrameAbortedOnImplThread, | |
| 829 impl_thread_weak_ptr_, | |
| 830 CommitEarlyOutReason::FINISHED_NO_UPDATES)); | |
| 831 | |
| 832 // Although the commit is internally aborted, this is because it has been | |
| 833 // detected to be a no-op. From the perspective of an embedder, this commit | |
| 834 // went through, and input should no longer be throttled, etc. | |
| 835 layer_tree_host()->CommitComplete(); | |
| 836 layer_tree_host()->DidBeginMainFrame(); | |
| 837 layer_tree_host()->BreakSwapPromises(SwapPromise::COMMIT_NO_UPDATE); | |
| 838 return; | |
| 839 } | |
| 840 | |
| 841 // Notify the impl thread that the main thread is ready to commit. This will | |
| 842 // begin the commit process, which is blocking from the main thread's | |
| 843 // point of view, but asynchronously performed on the impl thread, | |
| 844 // coordinated by the Scheduler. | |
| 845 { | |
| 846 TRACE_EVENT0("cc", "ThreadProxy::BeginMainFrame::commit"); | |
| 847 | |
| 848 DebugScopedSetMainThreadBlocked main_thread_blocked(this); | |
| 849 | |
| 850 // This CapturePostTasks should be destroyed before CommitComplete() is | |
| 851 // called since that goes out to the embedder, and we want the embedder | |
| 852 // to receive its callbacks before that. | |
| 853 BlockingTaskRunner::CapturePostTasks blocked( | |
| 854 blocking_main_thread_task_runner()); | |
| 855 | |
| 856 CompletionEvent completion; | |
| 857 Proxy::ImplThreadTaskRunner()->PostTask( | |
| 858 FROM_HERE, | |
| 859 base::Bind(&ThreadProxy::StartCommitOnImplThread, | |
| 860 impl_thread_weak_ptr_, | |
| 861 &completion, | |
| 862 queue.release())); | |
| 863 completion.Wait(); | |
| 864 } | |
| 865 | |
| 866 layer_tree_host()->CommitComplete(); | |
| 867 layer_tree_host()->DidBeginMainFrame(); | |
| 868 } | |
| 869 | |
| 870 void ThreadProxy::BeginMainFrameNotExpectedSoon() { | |
| 871 TRACE_EVENT0("cc", "ThreadProxy::BeginMainFrameNotExpectedSoon"); | |
| 872 DCHECK(IsMainThread()); | |
| 873 layer_tree_host()->BeginMainFrameNotExpectedSoon(); | |
| 874 } | |
| 875 | |
| 876 void ThreadProxy::StartCommitOnImplThread(CompletionEvent* completion, | |
| 877 ResourceUpdateQueue* raw_queue) { | |
| 878 TRACE_EVENT0("cc", "ThreadProxy::StartCommitOnImplThread"); | |
| 879 DCHECK(!impl().commit_completion_event); | |
| 880 DCHECK(IsImplThread() && IsMainThreadBlocked()); | |
| 881 DCHECK(impl().scheduler); | |
| 882 DCHECK(impl().scheduler->CommitPending()); | |
| 883 | |
| 884 if (!impl().layer_tree_host_impl) { | |
| 885 TRACE_EVENT_INSTANT0( | |
| 886 "cc", "EarlyOut_NoLayerTree", TRACE_EVENT_SCOPE_THREAD); | |
| 887 completion->Signal(); | |
| 888 return; | |
| 889 } | |
| 890 | |
| 891 // Ideally, we should inform to impl thread when BeginMainFrame is started. | |
| 892 // But, we can avoid a PostTask in here. | |
| 893 impl().scheduler->NotifyBeginMainFrameStarted(); | |
| 894 | |
| 895 scoped_ptr<ResourceUpdateQueue> queue(raw_queue); | |
| 896 | |
| 897 if (impl().contents_texture_manager) { | |
| 898 DCHECK_EQ(impl().contents_texture_manager, | |
| 899 blocked_main().contents_texture_manager()); | |
| 900 } else { | |
| 901 // Cache this pointer that was created on the main thread side to avoid a | |
| 902 // data race between creating it and using it on the compositor thread. | |
| 903 impl().contents_texture_manager = blocked_main().contents_texture_manager(); | |
| 904 } | |
| 905 | |
| 906 if (impl().contents_texture_manager) { | |
| 907 if (impl().contents_texture_manager->LinkedEvictedBackingsExist()) { | |
| 908 // Clear any uploads we were making to textures linked to evicted | |
| 909 // resources | |
| 910 queue->ClearUploadsToEvictedResources(); | |
| 911 // Some textures in the layer tree are invalid. Kick off another commit | |
| 912 // to fill them again. | |
| 913 SetNeedsCommitOnImplThread(); | |
| 914 } | |
| 915 | |
| 916 impl().contents_texture_manager->PushTexturePrioritiesToBackings(); | |
| 917 } | |
| 918 | |
| 919 impl().commit_completion_event = completion; | |
| 920 impl().current_resource_update_controller = ResourceUpdateController::Create( | |
| 921 this, | |
| 922 Proxy::ImplThreadTaskRunner(), | |
| 923 queue.Pass(), | |
| 924 impl().layer_tree_host_impl->resource_provider()); | |
| 925 impl().current_resource_update_controller->PerformMoreUpdates( | |
| 926 impl().scheduler->AnticipatedDrawTime()); | |
| 927 } | |
| 928 | |
| 929 void ThreadProxy::BeginMainFrameAbortedOnImplThread( | |
| 930 CommitEarlyOutReason reason) { | |
| 931 TRACE_EVENT1("cc", "ThreadProxy::BeginMainFrameAbortedOnImplThread", "reason", | |
| 932 CommitEarlyOutReasonToString(reason)); | |
| 933 DCHECK(IsImplThread()); | |
| 934 DCHECK(impl().scheduler); | |
| 935 DCHECK(impl().scheduler->CommitPending()); | |
| 936 DCHECK(!impl().layer_tree_host_impl->pending_tree()); | |
| 937 | |
| 938 if (CommitEarlyOutHandledCommit(reason)) | |
| 939 SetInputThrottledUntilCommitOnImplThread(false); | |
| 940 impl().layer_tree_host_impl->BeginMainFrameAborted(reason); | |
| 941 impl().scheduler->BeginMainFrameAborted(reason); | |
| 942 } | |
| 943 | |
| 944 void ThreadProxy::ScheduledActionAnimate() { | |
| 945 TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionAnimate"); | |
| 946 DCHECK(IsImplThread()); | |
| 947 | |
| 948 // Don't animate if there is no root layer. | |
| 949 // TODO(mithro): Both Animate and UpdateAnimationState already have a | |
| 950 // "!active_tree_->root_layer()" check? | |
| 951 if (!impl().layer_tree_host_impl->active_tree()->root_layer()) { | |
| 952 return; | |
| 953 } | |
| 954 | |
| 955 impl().animation_time = | |
| 956 impl().layer_tree_host_impl->CurrentBeginFrameArgs().frame_time; | |
| 957 impl().layer_tree_host_impl->Animate(impl().animation_time); | |
| 958 | |
| 959 // If animations are not visible, update the state now as | |
| 960 // ScheduledActionDrawAndSwapIfPossible will never be called. | |
| 961 if (!impl().layer_tree_host_impl->AnimationsAreVisible()) { | |
| 962 impl().layer_tree_host_impl->UpdateAnimationState(true); | |
| 963 } | |
| 964 } | |
| 965 | |
| 966 void ThreadProxy::ScheduledActionCommit() { | |
| 967 TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionCommit"); | |
| 968 DCHECK(IsImplThread()); | |
| 969 DCHECK(IsMainThreadBlocked()); | |
| 970 DCHECK(impl().commit_completion_event); | |
| 971 DCHECK(impl().current_resource_update_controller); | |
| 972 | |
| 973 // Complete all remaining texture updates. | |
| 974 impl().current_resource_update_controller->Finalize(); | |
| 975 impl().current_resource_update_controller = nullptr; | |
| 976 | |
| 977 blocked_main().main_thread_inside_commit = true; | |
| 978 impl().layer_tree_host_impl->BeginCommit(); | |
| 979 layer_tree_host()->BeginCommitOnImplThread(impl().layer_tree_host_impl.get()); | |
| 980 layer_tree_host()->FinishCommitOnImplThread( | |
| 981 impl().layer_tree_host_impl.get()); | |
| 982 blocked_main().main_thread_inside_commit = false; | |
| 983 | |
| 984 bool hold_commit = layer_tree_host()->settings().impl_side_painting && | |
| 985 blocked_main().commit_waits_for_activation; | |
| 986 blocked_main().commit_waits_for_activation = false; | |
| 987 | |
| 988 if (hold_commit) { | |
| 989 // For some layer types in impl-side painting, the commit is held until | |
| 990 // the sync tree is activated. It's also possible that the | |
| 991 // sync tree has already activated if there was no work to be done. | |
| 992 TRACE_EVENT_INSTANT0("cc", "HoldCommit", TRACE_EVENT_SCOPE_THREAD); | |
| 993 impl().completion_event_for_commit_held_on_tree_activation = | |
| 994 impl().commit_completion_event; | |
| 995 impl().commit_completion_event = NULL; | |
| 996 } else { | |
| 997 impl().commit_completion_event->Signal(); | |
| 998 impl().commit_completion_event = NULL; | |
| 999 } | |
| 1000 | |
| 1001 // Delay this step until afer the main thread has been released as it's | |
| 1002 // often a good bit of work to update the tree and prepare the new frame. | |
| 1003 impl().layer_tree_host_impl->CommitComplete(); | |
| 1004 | |
| 1005 SetInputThrottledUntilCommitOnImplThread(false); | |
| 1006 | |
| 1007 impl().next_frame_is_newly_committed_frame = true; | |
| 1008 | |
| 1009 impl().timing_history.DidCommit(); | |
| 1010 } | |
| 1011 | |
| 1012 void ThreadProxy::ScheduledActionActivateSyncTree() { | |
| 1013 TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionActivateSyncTree"); | |
| 1014 DCHECK(IsImplThread()); | |
| 1015 impl().layer_tree_host_impl->ActivateSyncTree(); | |
| 1016 } | |
| 1017 | |
| 1018 void ThreadProxy::ScheduledActionBeginOutputSurfaceCreation() { | |
| 1019 TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionBeginOutputSurfaceCreation"); | |
| 1020 DCHECK(IsImplThread()); | |
| 1021 Proxy::MainThreadTaskRunner()->PostTask( | |
| 1022 FROM_HERE, | |
| 1023 base::Bind(&ThreadProxy::RequestNewOutputSurface, main_thread_weak_ptr_)); | |
| 1024 } | |
| 1025 | |
| 1026 DrawResult ThreadProxy::DrawSwapInternal(bool forced_draw) { | |
| 1027 TRACE_EVENT_SYNTHETIC_DELAY("cc.DrawAndSwap"); | |
| 1028 DrawResult result; | |
| 1029 | |
| 1030 DCHECK(IsImplThread()); | |
| 1031 DCHECK(impl().layer_tree_host_impl.get()); | |
| 1032 | |
| 1033 impl().timing_history.DidStartDrawing(); | |
| 1034 base::AutoReset<bool> mark_inside(&impl().inside_draw, true); | |
| 1035 | |
| 1036 if (impl().layer_tree_host_impl->pending_tree()) { | |
| 1037 bool update_lcd_text = false; | |
| 1038 impl().layer_tree_host_impl->pending_tree()->UpdateDrawProperties( | |
| 1039 update_lcd_text); | |
| 1040 } | |
| 1041 | |
| 1042 // This method is called on a forced draw, regardless of whether we are able | |
| 1043 // to produce a frame, as the calling site on main thread is blocked until its | |
| 1044 // request completes, and we signal completion here. If CanDraw() is false, we | |
| 1045 // will indicate success=false to the caller, but we must still signal | |
| 1046 // completion to avoid deadlock. | |
| 1047 | |
| 1048 // We guard PrepareToDraw() with CanDraw() because it always returns a valid | |
| 1049 // frame, so can only be used when such a frame is possible. Since | |
| 1050 // DrawLayers() depends on the result of PrepareToDraw(), it is guarded on | |
| 1051 // CanDraw() as well. | |
| 1052 | |
| 1053 LayerTreeHostImpl::FrameData frame; | |
| 1054 bool draw_frame = false; | |
| 1055 | |
| 1056 if (impl().layer_tree_host_impl->CanDraw()) { | |
| 1057 result = impl().layer_tree_host_impl->PrepareToDraw(&frame); | |
| 1058 draw_frame = forced_draw || result == DRAW_SUCCESS; | |
| 1059 } else { | |
| 1060 result = DRAW_ABORTED_CANT_DRAW; | |
| 1061 } | |
| 1062 | |
| 1063 if (draw_frame) { | |
| 1064 impl().layer_tree_host_impl->DrawLayers( | |
| 1065 &frame, impl().scheduler->LastBeginImplFrameTime()); | |
| 1066 result = DRAW_SUCCESS; | |
| 1067 } else { | |
| 1068 DCHECK_NE(DRAW_SUCCESS, result); | |
| 1069 } | |
| 1070 impl().layer_tree_host_impl->DidDrawAllLayers(frame); | |
| 1071 | |
| 1072 bool start_ready_animations = draw_frame; | |
| 1073 impl().layer_tree_host_impl->UpdateAnimationState(start_ready_animations); | |
| 1074 | |
| 1075 if (draw_frame) | |
| 1076 impl().layer_tree_host_impl->SwapBuffers(frame); | |
| 1077 | |
| 1078 // Tell the main thread that the the newly-commited frame was drawn. | |
| 1079 if (impl().next_frame_is_newly_committed_frame) { | |
| 1080 impl().next_frame_is_newly_committed_frame = false; | |
| 1081 Proxy::MainThreadTaskRunner()->PostTask( | |
| 1082 FROM_HERE, | |
| 1083 base::Bind(&ThreadProxy::DidCommitAndDrawFrame, main_thread_weak_ptr_)); | |
| 1084 } | |
| 1085 | |
| 1086 if (result == DRAW_SUCCESS) | |
| 1087 impl().timing_history.DidFinishDrawing(); | |
| 1088 | |
| 1089 DCHECK_NE(INVALID_RESULT, result); | |
| 1090 return result; | |
| 1091 } | |
| 1092 | |
| 1093 void ThreadProxy::ScheduledActionPrepareTiles() { | |
| 1094 TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionPrepareTiles"); | |
| 1095 DCHECK(impl().layer_tree_host_impl->settings().impl_side_painting); | |
| 1096 impl().layer_tree_host_impl->PrepareTiles(); | |
| 1097 } | |
| 1098 | |
| 1099 DrawResult ThreadProxy::ScheduledActionDrawAndSwapIfPossible() { | |
| 1100 TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionDrawAndSwap"); | |
| 1101 | |
| 1102 // SchedulerStateMachine::DidDrawIfPossibleCompleted isn't set up to | |
| 1103 // handle DRAW_ABORTED_CANT_DRAW. Moreover, the scheduler should | |
| 1104 // never generate this call when it can't draw. | |
| 1105 DCHECK(impl().layer_tree_host_impl->CanDraw()); | |
| 1106 | |
| 1107 bool forced_draw = false; | |
| 1108 return DrawSwapInternal(forced_draw); | |
| 1109 } | |
| 1110 | |
| 1111 DrawResult ThreadProxy::ScheduledActionDrawAndSwapForced() { | |
| 1112 TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionDrawAndSwapForced"); | |
| 1113 bool forced_draw = true; | |
| 1114 return DrawSwapInternal(forced_draw); | |
| 1115 } | |
| 1116 | |
| 1117 void ThreadProxy::DidAnticipatedDrawTimeChange(base::TimeTicks time) { | |
| 1118 if (impl().current_resource_update_controller) | |
| 1119 impl().current_resource_update_controller->PerformMoreUpdates(time); | |
| 1120 } | |
| 1121 | |
| 1122 base::TimeDelta ThreadProxy::DrawDurationEstimate() { | |
| 1123 return impl().timing_history.DrawDurationEstimate(); | |
| 1124 } | |
| 1125 | |
| 1126 base::TimeDelta ThreadProxy::BeginMainFrameToCommitDurationEstimate() { | |
| 1127 return impl().timing_history.BeginMainFrameToCommitDurationEstimate(); | |
| 1128 } | |
| 1129 | |
| 1130 base::TimeDelta ThreadProxy::CommitToActivateDurationEstimate() { | |
| 1131 return impl().timing_history.CommitToActivateDurationEstimate(); | |
| 1132 } | |
| 1133 | |
| 1134 void ThreadProxy::DidBeginImplFrameDeadline() { | |
| 1135 impl().layer_tree_host_impl->ResetCurrentBeginFrameArgsForNextFrame(); | |
| 1136 } | |
| 1137 | |
| 1138 void ThreadProxy::SendBeginFramesToChildren(const BeginFrameArgs& args) { | |
| 1139 NOTREACHED() << "Only used by SingleThreadProxy"; | |
| 1140 } | |
| 1141 | |
| 1142 void ThreadProxy::ReadyToFinalizeTextureUpdates() { | |
| 1143 DCHECK(IsImplThread()); | |
| 1144 impl().scheduler->NotifyReadyToCommit(); | |
| 1145 } | |
| 1146 | |
| 1147 void ThreadProxy::DidCommitAndDrawFrame() { | |
| 1148 DCHECK(IsMainThread()); | |
| 1149 layer_tree_host()->DidCommitAndDrawFrame(); | |
| 1150 } | |
| 1151 | |
| 1152 void ThreadProxy::DidCompleteSwapBuffers() { | |
| 1153 DCHECK(IsMainThread()); | |
| 1154 layer_tree_host()->DidCompleteSwapBuffers(); | |
| 1155 } | |
| 1156 | |
| 1157 void ThreadProxy::SetAnimationEvents(scoped_ptr<AnimationEventsVector> events) { | |
| 1158 TRACE_EVENT0("cc", "ThreadProxy::SetAnimationEvents"); | |
| 1159 DCHECK(IsMainThread()); | |
| 1160 layer_tree_host()->SetAnimationEvents(events.Pass()); | |
| 1161 } | |
| 1162 | |
| 1163 void ThreadProxy::InitializeImplOnImplThread(CompletionEvent* completion) { | |
| 1164 TRACE_EVENT0("cc", "ThreadProxy::InitializeImplOnImplThread"); | |
| 1165 DCHECK(IsImplThread()); | |
| 1166 impl().layer_tree_host_impl = | |
| 1167 layer_tree_host()->CreateLayerTreeHostImpl(this); | |
| 1168 SchedulerSettings scheduler_settings( | |
| 1169 layer_tree_host()->settings().ToSchedulerSettings()); | |
| 1170 impl().scheduler = Scheduler::Create( | |
| 1171 this, | |
| 1172 scheduler_settings, | |
| 1173 impl().layer_tree_host_id, | |
| 1174 ImplThreadTaskRunner(), | |
| 1175 impl().external_begin_frame_source.Pass()); | |
| 1176 impl().scheduler->SetVisible(impl().layer_tree_host_impl->visible()); | |
| 1177 impl_thread_weak_ptr_ = impl().weak_factory.GetWeakPtr(); | |
| 1178 completion->Signal(); | |
| 1179 } | |
| 1180 | |
| 1181 void ThreadProxy::DeleteContentsTexturesOnImplThread( | |
| 1182 CompletionEvent* completion) { | |
| 1183 TRACE_EVENT0("cc", "ThreadProxy::DeleteContentsTexturesOnImplThread"); | |
| 1184 DCHECK(IsImplThread()); | |
| 1185 DCHECK(IsMainThreadBlocked()); | |
| 1186 layer_tree_host()->DeleteContentsTexturesOnImplThread( | |
| 1187 impl().layer_tree_host_impl->resource_provider()); | |
| 1188 completion->Signal(); | |
| 1189 } | |
| 1190 | |
| 1191 void ThreadProxy::InitializeOutputSurfaceOnImplThread( | |
| 1192 scoped_ptr<OutputSurface> output_surface) { | |
| 1193 TRACE_EVENT0("cc", "ThreadProxy::InitializeOutputSurfaceOnImplThread"); | |
| 1194 DCHECK(IsImplThread()); | |
| 1195 | |
| 1196 LayerTreeHostImpl* host_impl = impl().layer_tree_host_impl.get(); | |
| 1197 bool success = host_impl->InitializeRenderer(output_surface.Pass()); | |
| 1198 RendererCapabilities capabilities; | |
| 1199 if (success) { | |
| 1200 capabilities = | |
| 1201 host_impl->GetRendererCapabilities().MainThreadCapabilities(); | |
| 1202 } | |
| 1203 | |
| 1204 Proxy::MainThreadTaskRunner()->PostTask( | |
| 1205 FROM_HERE, | |
| 1206 base::Bind(&ThreadProxy::DidInitializeOutputSurface, | |
| 1207 main_thread_weak_ptr_, | |
| 1208 success, | |
| 1209 capabilities)); | |
| 1210 | |
| 1211 if (success) | |
| 1212 impl().scheduler->DidCreateAndInitializeOutputSurface(); | |
| 1213 } | |
| 1214 | |
| 1215 void ThreadProxy::FinishGLOnImplThread(CompletionEvent* completion) { | |
| 1216 TRACE_EVENT0("cc", "ThreadProxy::FinishGLOnImplThread"); | |
| 1217 DCHECK(IsImplThread()); | |
| 1218 if (impl().layer_tree_host_impl->output_surface()) { | |
| 1219 ContextProvider* context_provider = | |
| 1220 impl().layer_tree_host_impl->output_surface()->context_provider(); | |
| 1221 if (context_provider) | |
| 1222 context_provider->ContextGL()->Finish(); | |
| 1223 } | |
| 1224 completion->Signal(); | |
| 1225 } | |
| 1226 | |
| 1227 void ThreadProxy::LayerTreeHostClosedOnImplThread(CompletionEvent* completion) { | |
| 1228 TRACE_EVENT0("cc", "ThreadProxy::LayerTreeHostClosedOnImplThread"); | |
| 1229 DCHECK(IsImplThread()); | |
| 1230 DCHECK(IsMainThreadBlocked()); | |
| 1231 layer_tree_host()->DeleteContentsTexturesOnImplThread( | |
| 1232 impl().layer_tree_host_impl->resource_provider()); | |
| 1233 impl().current_resource_update_controller = nullptr; | |
| 1234 impl().scheduler = nullptr; | |
| 1235 impl().layer_tree_host_impl = nullptr; | |
| 1236 impl().weak_factory.InvalidateWeakPtrs(); | |
| 1237 // We need to explicitly shutdown the notifier to destroy any weakptrs it is | |
| 1238 // holding while still on the compositor thread. This also ensures any | |
| 1239 // callbacks holding a ThreadProxy pointer are cancelled. | |
| 1240 impl().smoothness_priority_expiration_notifier.Shutdown(); | |
| 1241 impl().contents_texture_manager = NULL; | |
| 1242 completion->Signal(); | |
| 1243 } | |
| 1244 | |
| 1245 size_t ThreadProxy::MaxPartialTextureUpdates() const { | |
| 1246 return ResourceUpdateController::MaxPartialTextureUpdates(); | |
| 1247 } | |
| 1248 | |
| 1249 ThreadProxy::BeginMainFrameAndCommitState::BeginMainFrameAndCommitState() | |
| 1250 : memory_allocation_limit_bytes(0), | |
| 1251 memory_allocation_priority_cutoff(0), | |
| 1252 evicted_ui_resources(false) {} | |
| 1253 | |
| 1254 ThreadProxy::BeginMainFrameAndCommitState::~BeginMainFrameAndCommitState() {} | |
| 1255 | |
| 1256 bool ThreadProxy::MainFrameWillHappenForTesting() { | |
| 1257 DCHECK(IsMainThread()); | |
| 1258 CompletionEvent completion; | |
| 1259 bool main_frame_will_happen = false; | |
| 1260 { | |
| 1261 DebugScopedSetMainThreadBlocked main_thread_blocked(this); | |
| 1262 Proxy::ImplThreadTaskRunner()->PostTask( | |
| 1263 FROM_HERE, | |
| 1264 base::Bind(&ThreadProxy::MainFrameWillHappenOnImplThreadForTesting, | |
| 1265 impl_thread_weak_ptr_, | |
| 1266 &completion, | |
| 1267 &main_frame_will_happen)); | |
| 1268 completion.Wait(); | |
| 1269 } | |
| 1270 return main_frame_will_happen; | |
| 1271 } | |
| 1272 | |
| 1273 void ThreadProxy::SetChildrenNeedBeginFrames(bool children_need_begin_frames) { | |
| 1274 NOTREACHED() << "Only used by SingleThreadProxy"; | |
| 1275 } | |
| 1276 | |
| 1277 void ThreadProxy::MainFrameWillHappenOnImplThreadForTesting( | |
| 1278 CompletionEvent* completion, | |
| 1279 bool* main_frame_will_happen) { | |
| 1280 DCHECK(IsImplThread()); | |
| 1281 if (impl().layer_tree_host_impl->output_surface()) { | |
| 1282 *main_frame_will_happen = impl().scheduler->MainFrameForTestingWillHappen(); | |
| 1283 } else { | |
| 1284 *main_frame_will_happen = false; | |
| 1285 } | |
| 1286 completion->Signal(); | |
| 1287 } | |
| 1288 | |
| 1289 void ThreadProxy::RenewTreePriority() { | |
| 1290 DCHECK(IsImplThread()); | |
| 1291 bool smoothness_takes_priority = | |
| 1292 impl().layer_tree_host_impl->pinch_gesture_active() || | |
| 1293 impl().layer_tree_host_impl->page_scale_animation_active() || | |
| 1294 impl().layer_tree_host_impl->IsActivelyScrolling(); | |
| 1295 | |
| 1296 // Schedule expiration if smoothness currently takes priority. | |
| 1297 if (smoothness_takes_priority) | |
| 1298 impl().smoothness_priority_expiration_notifier.Schedule(); | |
| 1299 | |
| 1300 // We use the same priority for both trees by default. | |
| 1301 TreePriority priority = SAME_PRIORITY_FOR_BOTH_TREES; | |
| 1302 | |
| 1303 // Smoothness takes priority if we have an expiration for it scheduled. | |
| 1304 if (impl().smoothness_priority_expiration_notifier.HasPendingNotification()) | |
| 1305 priority = SMOOTHNESS_TAKES_PRIORITY; | |
| 1306 | |
| 1307 // New content always takes priority when the active tree has | |
| 1308 // evicted resources or there is an invalid viewport size. | |
| 1309 if (impl().layer_tree_host_impl->active_tree()->ContentsTexturesPurged() || | |
| 1310 impl().layer_tree_host_impl->active_tree()->ViewportSizeInvalid() || | |
| 1311 impl().layer_tree_host_impl->EvictedUIResourcesExist() || | |
| 1312 impl().input_throttled_until_commit) { | |
| 1313 // Once we enter NEW_CONTENTS_TAKES_PRIORITY mode, visible tiles on active | |
| 1314 // tree might be freed. We need to set RequiresHighResToDraw to ensure that | |
| 1315 // high res tiles will be required to activate pending tree. | |
| 1316 impl().layer_tree_host_impl->SetRequiresHighResToDraw(); | |
| 1317 priority = NEW_CONTENT_TAKES_PRIORITY; | |
| 1318 } | |
| 1319 | |
| 1320 impl().layer_tree_host_impl->SetTreePriority(priority); | |
| 1321 | |
| 1322 // Only put the scheduler in impl latency prioritization mode if we don't | |
| 1323 // have a scroll listener. This gives the scroll listener a better chance of | |
| 1324 // handling scroll updates within the same frame. The tree itself is still | |
| 1325 // kept in prefer smoothness mode to allow checkerboarding. | |
| 1326 impl().scheduler->SetImplLatencyTakesPriority( | |
| 1327 priority == SMOOTHNESS_TAKES_PRIORITY && | |
| 1328 !impl().layer_tree_host_impl->scroll_affects_scroll_handler()); | |
| 1329 | |
| 1330 // Notify the the client of this compositor via the output surface. | |
| 1331 // TODO(epenner): Route this to compositor-thread instead of output-surface | |
| 1332 // after GTFO refactor of compositor-thread (http://crbug/170828). | |
| 1333 if (impl().layer_tree_host_impl->output_surface()) { | |
| 1334 impl() | |
| 1335 .layer_tree_host_impl->output_surface() | |
| 1336 ->UpdateSmoothnessTakesPriority(priority == SMOOTHNESS_TAKES_PRIORITY); | |
| 1337 } | |
| 1338 } | |
| 1339 | |
| 1340 void ThreadProxy::PostDelayedAnimationTaskOnImplThread( | |
| 1341 const base::Closure& task, | |
| 1342 base::TimeDelta delay) { | |
| 1343 Proxy::ImplThreadTaskRunner()->PostDelayedTask(FROM_HERE, task, delay); | |
| 1344 } | |
| 1345 | |
| 1346 void ThreadProxy::DidActivateSyncTree() { | |
| 1347 TRACE_EVENT0("cc", "ThreadProxy::DidActivateSyncTreeOnImplThread"); | |
| 1348 DCHECK(IsImplThread()); | |
| 1349 | |
| 1350 if (impl().completion_event_for_commit_held_on_tree_activation) { | |
| 1351 TRACE_EVENT_INSTANT0( | |
| 1352 "cc", "ReleaseCommitbyActivation", TRACE_EVENT_SCOPE_THREAD); | |
| 1353 DCHECK(impl().layer_tree_host_impl->settings().impl_side_painting); | |
| 1354 impl().completion_event_for_commit_held_on_tree_activation->Signal(); | |
| 1355 impl().completion_event_for_commit_held_on_tree_activation = NULL; | |
| 1356 } | |
| 1357 | |
| 1358 impl().timing_history.DidActivateSyncTree(); | |
| 1359 } | |
| 1360 | |
| 1361 void ThreadProxy::DidPrepareTiles() { | |
| 1362 DCHECK(IsImplThread()); | |
| 1363 impl().scheduler->DidPrepareTiles(); | |
| 1364 } | |
| 1365 | |
| 1366 void ThreadProxy::DidCompletePageScaleAnimationOnImplThread() { | |
| 1367 DCHECK(IsImplThread()); | |
| 1368 Proxy::MainThreadTaskRunner()->PostTask( | |
| 1369 FROM_HERE, base::Bind(&ThreadProxy::DidCompletePageScaleAnimation, | |
| 1370 main_thread_weak_ptr_)); | |
| 1371 } | |
| 1372 | |
| 1373 } // namespace cc | |
| OLD | NEW |