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