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