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/single_thread_proxy.h" 6 7 #include "base/auto_reset.h" 8 #include "base/debug/trace_event.h" 9 #include "cc/debug/benchmark_instrumentation.h" 10 #include "cc/output/context_provider.h" 11 #include "cc/output/output_surface.h" 12 #include "cc/quads/draw_quad.h" 13 #include "cc/resources/prioritized_resource_manager.h" 14 #include "cc/resources/resource_update_controller.h" 15 #include "cc/trees/blocking_task_runner.h" 16 #include "cc/trees/layer_tree_host.h" 17 #include "cc/trees/layer_tree_host_single_thread_client.h" 18 #include "cc/trees/layer_tree_impl.h" 19 #include "ui/gfx/frame_time.h" 20 21 namespace cc { 22 23 scoped_ptr<Proxy> SingleThreadProxy::Create( 24 LayerTreeHost* layer_tree_host, 25 LayerTreeHostSingleThreadClient* client) { 26 return make_scoped_ptr( 27 new SingleThreadProxy(layer_tree_host, client)).PassAs<Proxy>(); 28 } 29 30 SingleThreadProxy::SingleThreadProxy(LayerTreeHost* layer_tree_host, 31 LayerTreeHostSingleThreadClient* client) 32 : Proxy(NULL), 33 layer_tree_host_(layer_tree_host), 34 client_(client), 35 created_offscreen_context_provider_(false), 36 next_frame_is_newly_committed_frame_(false), 37 inside_draw_(false) { 38 TRACE_EVENT0("cc", "SingleThreadProxy::SingleThreadProxy"); 39 DCHECK(Proxy::IsMainThread()); 40 DCHECK(layer_tree_host); 41 42 // Impl-side painting not supported without threaded compositing. 43 CHECK(!layer_tree_host->settings().impl_side_painting) 44 << "Threaded compositing must be enabled to use impl-side painting."; 45 } 46 47 void SingleThreadProxy::Start(scoped_ptr<OutputSurface> first_output_surface) { 48 DCHECK(first_output_surface); 49 DebugScopedSetImplThread impl(this); 50 layer_tree_host_impl_ = layer_tree_host_->CreateLayerTreeHostImpl(this); 51 first_output_surface_ = first_output_surface.Pass(); 52 } 53 54 SingleThreadProxy::~SingleThreadProxy() { 55 TRACE_EVENT0("cc", "SingleThreadProxy::~SingleThreadProxy"); 56 DCHECK(Proxy::IsMainThread()); 57 // Make sure Stop() got called or never Started. 58 DCHECK(!layer_tree_host_impl_); 59 } 60 61 bool SingleThreadProxy::CompositeAndReadback(void* pixels, gfx::Rect rect) { 62 TRACE_EVENT0("cc", "SingleThreadProxy::CompositeAndReadback"); 63 DCHECK(Proxy::IsMainThread()); 64 65 gfx::Rect device_viewport_damage_rect = rect; 66 67 LayerTreeHostImpl::FrameData frame; 68 if (!CommitAndComposite(gfx::FrameTime::Now(), 69 device_viewport_damage_rect, 70 true, // for_readback 71 &frame)) 72 return false; 73 74 { 75 DebugScopedSetImplThread impl(this); 76 layer_tree_host_impl_->Readback(pixels, rect); 77 78 if (layer_tree_host_impl_->IsContextLost()) 79 return false; 80 } 81 82 return true; 83 } 84 85 void SingleThreadProxy::FinishAllRendering() { 86 DCHECK(Proxy::IsMainThread()); 87 { 88 DebugScopedSetImplThread impl(this); 89 layer_tree_host_impl_->FinishAllRendering(); 90 } 91 } 92 93 bool SingleThreadProxy::IsStarted() const { 94 DCHECK(Proxy::IsMainThread()); 95 return layer_tree_host_impl_; 96 } 97 98 void SingleThreadProxy::SetLayerTreeHostClientReady() { 99 // Scheduling is controlled by the embedder in the single thread case, so 100 // nothing to do. 101 } 102 103 void SingleThreadProxy::SetVisible(bool visible) { 104 DebugScopedSetImplThread impl(this); 105 layer_tree_host_impl_->SetVisible(visible); 106 107 // Changing visibility could change ShouldComposite(). 108 UpdateBackgroundAnimateTicking(); 109 } 110 111 void SingleThreadProxy::CreateAndInitializeOutputSurface() { 112 TRACE_EVENT0( 113 "cc", "SingleThreadProxy::CreateAndInitializeOutputSurface"); 114 DCHECK(Proxy::IsMainThread()); 115 116 scoped_ptr<OutputSurface> output_surface = first_output_surface_.Pass(); 117 if (!output_surface) 118 output_surface = layer_tree_host_->CreateOutputSurface(); 119 if (!output_surface) { 120 OnOutputSurfaceInitializeAttempted(false); 121 return; 122 } 123 124 scoped_refptr<ContextProvider> offscreen_context_provider; 125 if (created_offscreen_context_provider_) { 126 offscreen_context_provider = 127 layer_tree_host_->client()->OffscreenContextProvider(); 128 if (!offscreen_context_provider.get() || 129 !offscreen_context_provider->BindToCurrentThread()) { 130 OnOutputSurfaceInitializeAttempted(false); 131 return; 132 } 133 } 134 135 { 136 DebugScopedSetMainThreadBlocked main_thread_blocked(this); 137 DebugScopedSetImplThread impl(this); 138 layer_tree_host_->DeleteContentsTexturesOnImplThread( 139 layer_tree_host_impl_->resource_provider()); 140 } 141 142 bool initialized; 143 { 144 DebugScopedSetImplThread impl(this); 145 146 DCHECK(output_surface); 147 initialized = layer_tree_host_impl_->InitializeRenderer( 148 output_surface.Pass()); 149 if (!initialized && offscreen_context_provider.get()) { 150 offscreen_context_provider->VerifyContexts(); 151 offscreen_context_provider = NULL; 152 } 153 154 layer_tree_host_impl_->SetOffscreenContextProvider( 155 offscreen_context_provider); 156 } 157 158 OnOutputSurfaceInitializeAttempted(initialized); 159 } 160 161 void SingleThreadProxy::OnOutputSurfaceInitializeAttempted(bool success) { 162 LayerTreeHost::CreateResult result = 163 layer_tree_host_->OnCreateAndInitializeOutputSurfaceAttempted(success); 164 if (result == LayerTreeHost::CreateFailedButTryAgain) { 165 // Force another recreation attempt to happen by requesting another commit. 166 SetNeedsCommit(); 167 } 168 } 169 170 const RendererCapabilities& SingleThreadProxy::GetRendererCapabilities() const { 171 DCHECK(Proxy::IsMainThread()); 172 DCHECK(!layer_tree_host_->output_surface_lost()); 173 return renderer_capabilities_for_main_thread_; 174 } 175 176 void SingleThreadProxy::SetNeedsAnimate() { 177 DCHECK(Proxy::IsMainThread()); 178 client_->ScheduleAnimation(); 179 } 180 181 void SingleThreadProxy::SetNeedsUpdateLayers() { 182 DCHECK(Proxy::IsMainThread()); 183 client_->ScheduleComposite(); 184 } 185 186 void SingleThreadProxy::DoCommit(scoped_ptr<ResourceUpdateQueue> queue) { 187 DCHECK(Proxy::IsMainThread()); 188 // Commit immediately. 189 { 190 DebugScopedSetMainThreadBlocked main_thread_blocked(this); 191 DebugScopedSetImplThread impl(this); 192 193 // This CapturePostTasks should be destroyed before CommitComplete() is 194 // called since that goes out to the embedder, and we want the embedder 195 // to receive its callbacks before that. 196 BlockingTaskRunner::CapturePostTasks blocked; 197 198 layer_tree_host_impl_->BeginCommit(); 199 200 if (PrioritizedResourceManager* contents_texture_manager = 201 layer_tree_host_->contents_texture_manager()) { 202 contents_texture_manager->PushTexturePrioritiesToBackings(); 203 } 204 layer_tree_host_->BeginCommitOnImplThread(layer_tree_host_impl_.get()); 205 206 scoped_ptr<ResourceUpdateController> update_controller = 207 ResourceUpdateController::Create( 208 NULL, 209 Proxy::MainThreadTaskRunner(), 210 queue.Pass(), 211 layer_tree_host_impl_->resource_provider()); 212 update_controller->Finalize(); 213 214 if (layer_tree_host_impl_->EvictedUIResourcesExist()) 215 layer_tree_host_->RecreateUIResources(); 216 217 layer_tree_host_->FinishCommitOnImplThread(layer_tree_host_impl_.get()); 218 219 layer_tree_host_impl_->CommitComplete(); 220 221 #ifndef NDEBUG 222 // In the single-threaded case, the scale and scroll deltas should never be 223 // touched on the impl layer tree. 224 scoped_ptr<ScrollAndScaleSet> scroll_info = 225 layer_tree_host_impl_->ProcessScrollDeltas(); 226 DCHECK(!scroll_info->scrolls.size()); 227 DCHECK_EQ(1.f, scroll_info->page_scale_delta); 228 #endif 229 230 RenderingStatsInstrumentation* stats_instrumentation = 231 layer_tree_host_->rendering_stats_instrumentation(); 232 BenchmarkInstrumentation::IssueMainThreadRenderingStatsEvent( 233 stats_instrumentation->main_thread_rendering_stats()); 234 stats_instrumentation->AccumulateAndClearMainThreadStats(); 235 } 236 layer_tree_host_->CommitComplete(); 237 next_frame_is_newly_committed_frame_ = true; 238 } 239 240 void SingleThreadProxy::SetNeedsCommit() { 241 DCHECK(Proxy::IsMainThread()); 242 client_->ScheduleComposite(); 243 } 244 245 void SingleThreadProxy::SetNeedsRedraw(gfx::Rect damage_rect) { 246 SetNeedsRedrawRectOnImplThread(damage_rect); 247 client_->ScheduleComposite(); 248 } 249 250 void SingleThreadProxy::SetNextCommitWaitsForActivation() { 251 // There is no activation here other than commit. So do nothing. 252 } 253 254 void SingleThreadProxy::SetDeferCommits(bool defer_commits) { 255 // Thread-only feature. 256 NOTREACHED(); 257 } 258 259 bool SingleThreadProxy::CommitRequested() const { return false; } 260 261 bool SingleThreadProxy::BeginMainFrameRequested() const { return false; } 262 263 size_t SingleThreadProxy::MaxPartialTextureUpdates() const { 264 return std::numeric_limits<size_t>::max(); 265 } 266 267 void SingleThreadProxy::Stop() { 268 TRACE_EVENT0("cc", "SingleThreadProxy::stop"); 269 DCHECK(Proxy::IsMainThread()); 270 { 271 DebugScopedSetMainThreadBlocked main_thread_blocked(this); 272 DebugScopedSetImplThread impl(this); 273 274 layer_tree_host_->DeleteContentsTexturesOnImplThread( 275 layer_tree_host_impl_->resource_provider()); 276 layer_tree_host_impl_.reset(); 277 } 278 layer_tree_host_ = NULL; 279 } 280 281 void SingleThreadProxy::OnCanDrawStateChanged(bool can_draw) { 282 DCHECK(Proxy::IsImplThread()); 283 UpdateBackgroundAnimateTicking(); 284 } 285 286 void SingleThreadProxy::NotifyReadyToActivate() { 287 // Thread-only feature. 288 NOTREACHED(); 289 } 290 291 void SingleThreadProxy::SetNeedsRedrawOnImplThread() { 292 client_->ScheduleComposite(); 293 } 294 295 void SingleThreadProxy::SetNeedsManageTilesOnImplThread() { 296 // Thread-only/Impl-side-painting-only feature. 297 NOTREACHED(); 298 } 299 300 void SingleThreadProxy::SetNeedsRedrawRectOnImplThread(gfx::Rect damage_rect) { 301 // TODO(brianderson): Once we move render_widget scheduling into this class, 302 // we can treat redraw requests more efficiently than CommitAndRedraw 303 // requests. 304 layer_tree_host_impl_->SetViewportDamage(damage_rect); 305 SetNeedsCommit(); 306 } 307 308 void SingleThreadProxy::DidInitializeVisibleTileOnImplThread() { 309 // Impl-side painting only. 310 NOTREACHED(); 311 } 312 313 void SingleThreadProxy::SetNeedsCommitOnImplThread() { 314 client_->ScheduleComposite(); 315 } 316 317 void SingleThreadProxy::PostAnimationEventsToMainThreadOnImplThread( 318 scoped_ptr<AnimationEventsVector> events, 319 base::Time wall_clock_time) { 320 DCHECK(Proxy::IsImplThread()); 321 DebugScopedSetMainThread main(this); 322 layer_tree_host_->SetAnimationEvents(events.Pass(), wall_clock_time); 323 } 324 325 bool SingleThreadProxy::ReduceContentsTextureMemoryOnImplThread( 326 size_t limit_bytes, 327 int priority_cutoff) { 328 DCHECK(IsImplThread()); 329 PrioritizedResourceManager* contents_texture_manager = 330 layer_tree_host_->contents_texture_manager(); 331 332 ResourceProvider* resource_provider = 333 layer_tree_host_impl_->resource_provider(); 334 335 if (!contents_texture_manager || !resource_provider) 336 return false; 337 338 return contents_texture_manager->ReduceMemoryOnImplThread( 339 limit_bytes, priority_cutoff, resource_provider); 340 } 341 342 void SingleThreadProxy::SendManagedMemoryStats() { 343 DCHECK(Proxy::IsImplThread()); 344 if (!layer_tree_host_impl_) 345 return; 346 PrioritizedResourceManager* contents_texture_manager = 347 layer_tree_host_->contents_texture_manager(); 348 if (!contents_texture_manager) 349 return; 350 351 layer_tree_host_impl_->SendManagedMemoryStats( 352 contents_texture_manager->MemoryVisibleBytes(), 353 contents_texture_manager->MemoryVisibleAndNearbyBytes(), 354 contents_texture_manager->MemoryUseBytes()); 355 } 356 357 bool SingleThreadProxy::IsInsideDraw() { return inside_draw_; } 358 359 void SingleThreadProxy::UpdateRendererCapabilitiesOnImplThread() { 360 DCHECK(IsImplThread()); 361 renderer_capabilities_for_main_thread_ = 362 layer_tree_host_impl_->GetRendererCapabilities().MainThreadCapabilities(); 363 } 364 365 void SingleThreadProxy::DidLoseOutputSurfaceOnImplThread() { 366 // Cause a commit so we can notice the lost context. 367 SetNeedsCommitOnImplThread(); 368 client_->DidAbortSwapBuffers(); 369 } 370 371 void SingleThreadProxy::DidSwapBuffersOnImplThread() { 372 client_->DidPostSwapBuffers(); 373 } 374 375 void SingleThreadProxy::OnSwapBuffersCompleteOnImplThread() { 376 client_->DidCompleteSwapBuffers(); 377 } 378 379 // Called by the legacy scheduling path (e.g. where render_widget does the 380 // scheduling) 381 void SingleThreadProxy::CompositeImmediately(base::TimeTicks frame_begin_time) { 382 gfx::Rect device_viewport_damage_rect; 383 384 LayerTreeHostImpl::FrameData frame; 385 if (CommitAndComposite(frame_begin_time, 386 device_viewport_damage_rect, 387 false, // for_readback 388 &frame)) { 389 { 390 DebugScopedSetMainThreadBlocked main_thread_blocked(this); 391 DebugScopedSetImplThread impl(this); 392 393 // This CapturePostTasks should be destroyed before 394 // DidCommitAndDrawFrame() is called since that goes out to the embedder, 395 // and we want the embedder to receive its callbacks before that. 396 // NOTE: This maintains consistent ordering with the ThreadProxy since 397 // the DidCommitAndDrawFrame() must be post-tasked from the impl thread 398 // there as the main thread is not blocked, so any posted tasks inside 399 // the swap buffers will execute first. 400 BlockingTaskRunner::CapturePostTasks blocked; 401 402 layer_tree_host_impl_->SwapBuffers(frame); 403 } 404 DidSwapFrame(); 405 } 406 } 407 408 scoped_ptr<base::Value> SingleThreadProxy::AsValue() const { 409 scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue()); 410 { 411 // The following line casts away const modifiers because it is just 412 // setting debug state. We still want the AsValue() function and its 413 // call chain to be const throughout. 414 DebugScopedSetImplThread impl(const_cast<SingleThreadProxy*>(this)); 415 416 state->Set("layer_tree_host_impl", 417 layer_tree_host_impl_->AsValue().release()); 418 } 419 return state.PassAs<base::Value>(); 420 } 421 422 void SingleThreadProxy::ForceSerializeOnSwapBuffers() { 423 { 424 DebugScopedSetImplThread impl(this); 425 if (layer_tree_host_impl_->renderer()) { 426 DCHECK(!layer_tree_host_->output_surface_lost()); 427 layer_tree_host_impl_->renderer()->DoNoOp(); 428 } 429 } 430 } 431 432 bool SingleThreadProxy::CommitAndComposite( 433 base::TimeTicks frame_begin_time, 434 gfx::Rect device_viewport_damage_rect, 435 bool for_readback, 436 LayerTreeHostImpl::FrameData* frame) { 437 DCHECK(Proxy::IsMainThread()); 438 439 if (!layer_tree_host_->InitializeOutputSurfaceIfNeeded()) 440 return false; 441 442 layer_tree_host_->AnimateLayers(frame_begin_time); 443 444 if (PrioritizedResourceManager* contents_texture_manager = 445 layer_tree_host_->contents_texture_manager()) { 446 contents_texture_manager->UnlinkAndClearEvictedBackings(); 447 contents_texture_manager->SetMaxMemoryLimitBytes( 448 layer_tree_host_impl_->memory_allocation_limit_bytes()); 449 contents_texture_manager->SetExternalPriorityCutoff( 450 layer_tree_host_impl_->memory_allocation_priority_cutoff()); 451 } 452 453 scoped_ptr<ResourceUpdateQueue> queue = 454 make_scoped_ptr(new ResourceUpdateQueue); 455 layer_tree_host_->UpdateLayers(queue.get()); 456 457 layer_tree_host_->WillCommit(); 458 459 scoped_refptr<ContextProvider> offscreen_context_provider; 460 if (renderer_capabilities_for_main_thread_.using_offscreen_context3d && 461 layer_tree_host_->needs_offscreen_context()) { 462 offscreen_context_provider = 463 layer_tree_host_->client()->OffscreenContextProvider(); 464 if (offscreen_context_provider.get() && 465 !offscreen_context_provider->BindToCurrentThread()) 466 offscreen_context_provider = NULL; 467 468 if (offscreen_context_provider.get()) 469 created_offscreen_context_provider_ = true; 470 } 471 472 DoCommit(queue.Pass()); 473 bool result = DoComposite(offscreen_context_provider, 474 frame_begin_time, 475 device_viewport_damage_rect, 476 for_readback, 477 frame); 478 layer_tree_host_->DidBeginMainFrame(); 479 return result; 480 } 481 482 bool SingleThreadProxy::ShouldComposite() const { 483 DCHECK(Proxy::IsImplThread()); 484 return layer_tree_host_impl_->visible() && 485 layer_tree_host_impl_->CanDraw(); 486 } 487 488 void SingleThreadProxy::UpdateBackgroundAnimateTicking() { 489 DCHECK(Proxy::IsImplThread()); 490 layer_tree_host_impl_->UpdateBackgroundAnimateTicking( 491 !ShouldComposite() && layer_tree_host_impl_->active_tree()->root_layer()); 492 } 493 494 bool SingleThreadProxy::DoComposite( 495 scoped_refptr<ContextProvider> offscreen_context_provider, 496 base::TimeTicks frame_begin_time, 497 gfx::Rect device_viewport_damage_rect, 498 bool for_readback, 499 LayerTreeHostImpl::FrameData* frame) { 500 DCHECK(!layer_tree_host_->output_surface_lost()); 501 502 bool lost_output_surface = false; 503 { 504 DebugScopedSetImplThread impl(this); 505 base::AutoReset<bool> mark_inside(&inside_draw_, true); 506 507 layer_tree_host_impl_->SetOffscreenContextProvider( 508 offscreen_context_provider); 509 510 bool can_do_readback = layer_tree_host_impl_->renderer()->CanReadPixels(); 511 512 // We guard PrepareToDraw() with CanDraw() because it always returns a valid 513 // frame, so can only be used when such a frame is possible. Since 514 // DrawLayers() depends on the result of PrepareToDraw(), it is guarded on 515 // CanDraw() as well. 516 if (!ShouldComposite() || (for_readback && !can_do_readback)) { 517 UpdateBackgroundAnimateTicking(); 518 return false; 519 } 520 521 layer_tree_host_impl_->Animate( 522 layer_tree_host_impl_->CurrentFrameTimeTicks(), 523 layer_tree_host_impl_->CurrentFrameTime()); 524 UpdateBackgroundAnimateTicking(); 525 526 if (!layer_tree_host_impl_->IsContextLost()) { 527 layer_tree_host_impl_->PrepareToDraw(frame, device_viewport_damage_rect); 528 layer_tree_host_impl_->DrawLayers(frame, frame_begin_time); 529 layer_tree_host_impl_->DidDrawAllLayers(*frame); 530 } 531 lost_output_surface = layer_tree_host_impl_->IsContextLost(); 532 533 bool start_ready_animations = true; 534 layer_tree_host_impl_->UpdateAnimationState(start_ready_animations); 535 536 layer_tree_host_impl_->ResetCurrentFrameTimeForNextFrame(); 537 } 538 539 if (lost_output_surface) { 540 ContextProvider* offscreen_contexts = 541 layer_tree_host_impl_->offscreen_context_provider(); 542 if (offscreen_contexts) 543 offscreen_contexts->VerifyContexts(); 544 layer_tree_host_->DidLoseOutputSurface(); 545 return false; 546 } 547 548 return true; 549 } 550 551 void SingleThreadProxy::DidSwapFrame() { 552 if (next_frame_is_newly_committed_frame_) { 553 next_frame_is_newly_committed_frame_ = false; 554 layer_tree_host_->DidCommitAndDrawFrame(); 555 } 556 } 557 558 bool SingleThreadProxy::CommitPendingForTesting() { return false; } 559 560 } // namespace cc 561