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