single_thread_proxy.cc revision b2df76ea8fec9e32f6f3718986dba0d95315b29c
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) { 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) { 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 layer_tree_host_->contents_texture_manager()-> 189 PushTexturePrioritiesToBackings(); 190 layer_tree_host_->BeginCommitOnImplThread(layer_tree_host_impl_.get()); 191 192 scoped_ptr<ResourceUpdateController> update_controller = 193 ResourceUpdateController::Create( 194 NULL, 195 Proxy::MainThread(), 196 queue.Pass(), 197 layer_tree_host_impl_->resource_provider()); 198 update_controller->Finalize(); 199 200 layer_tree_host_->FinishCommitOnImplThread(layer_tree_host_impl_.get()); 201 202 layer_tree_host_impl_->CommitComplete(); 203 204#ifndef NDEBUG 205 // In the single-threaded case, the scroll deltas should never be 206 // touched on the impl layer tree. 207 scoped_ptr<ScrollAndScaleSet> scroll_info = 208 layer_tree_host_impl_->ProcessScrollDeltas(); 209 DCHECK(!scroll_info->scrolls.size()); 210#endif 211 212 base::TimeDelta duration = stats_instrumentation->EndRecording(start_time); 213 stats_instrumentation->AddCommit(duration); 214 } 215 layer_tree_host_->CommitComplete(); 216 next_frame_is_newly_committed_frame_ = true; 217} 218 219void SingleThreadProxy::SetNeedsCommit() { 220 DCHECK(Proxy::IsMainThread()); 221 layer_tree_host_->ScheduleComposite(); 222} 223 224void SingleThreadProxy::SetNeedsRedraw(gfx::Rect damage_rect) { 225 SetNeedsRedrawRectOnImplThread(damage_rect); 226} 227 228void SingleThreadProxy::OnHasPendingTreeStateChanged(bool have_pending_tree) { 229 // Thread-only feature. 230 NOTREACHED(); 231} 232 233void SingleThreadProxy::SetDeferCommits(bool defer_commits) { 234 // Thread-only feature. 235 NOTREACHED(); 236} 237 238bool SingleThreadProxy::CommitRequested() const { return false; } 239 240size_t SingleThreadProxy::MaxPartialTextureUpdates() const { 241 return std::numeric_limits<size_t>::max(); 242} 243 244void SingleThreadProxy::Stop() { 245 TRACE_EVENT0("cc", "SingleThreadProxy::stop"); 246 DCHECK(Proxy::IsMainThread()); 247 { 248 DebugScopedSetMainThreadBlocked mainThreadBlocked(this); 249 DebugScopedSetImplThread impl(this); 250 251 layer_tree_host_->DeleteContentsTexturesOnImplThread( 252 layer_tree_host_impl_->resource_provider()); 253 layer_tree_host_impl_.reset(); 254 } 255 layer_tree_host_ = NULL; 256} 257 258void SingleThreadProxy::OnCanDrawStateChanged(bool can_draw) { 259 DCHECK(Proxy::IsImplThread()); 260 layer_tree_host_impl_->UpdateBackgroundAnimateTicking(!ShouldComposite()); 261} 262 263void SingleThreadProxy::SetNeedsRedrawOnImplThread() { 264 layer_tree_host_->ScheduleComposite(); 265} 266 267void SingleThreadProxy::SetNeedsRedrawRectOnImplThread(gfx::Rect damage_rect) { 268 // FIXME: Once we move render_widget scheduling into this class, we can 269 // treat redraw requests more efficiently than CommitAndRedraw requests. 270 layer_tree_host_impl_->SetViewportDamage(damage_rect); 271 SetNeedsCommit(); 272} 273 274void SingleThreadProxy::DidInitializeVisibleTileOnImplThread() { 275 // Impl-side painting only. 276 NOTREACHED(); 277} 278 279void SingleThreadProxy::SetNeedsCommitOnImplThread() { 280 layer_tree_host_->ScheduleComposite(); 281} 282 283void SingleThreadProxy::SetNeedsManageTilesOnImplThread() { 284 layer_tree_host_->ScheduleComposite(); 285} 286 287void SingleThreadProxy::PostAnimationEventsToMainThreadOnImplThread( 288 scoped_ptr<AnimationEventsVector> events, 289 base::Time wall_clock_time) { 290 DCHECK(Proxy::IsImplThread()); 291 DebugScopedSetMainThread main(this); 292 layer_tree_host_->SetAnimationEvents(events.Pass(), wall_clock_time); 293} 294 295bool SingleThreadProxy::ReduceContentsTextureMemoryOnImplThread( 296 size_t limit_bytes, 297 int priority_cutoff) { 298 DCHECK(IsImplThread()); 299 if (!layer_tree_host_->contents_texture_manager()) 300 return false; 301 302 return layer_tree_host_->contents_texture_manager()->ReduceMemoryOnImplThread( 303 limit_bytes, priority_cutoff, layer_tree_host_impl_->resource_provider()); 304} 305 306void SingleThreadProxy::ReduceWastedContentsTextureMemoryOnImplThread() { 307 // Impl-side painting only. 308 NOTREACHED(); 309} 310 311void SingleThreadProxy::SendManagedMemoryStats() { 312 DCHECK(Proxy::IsImplThread()); 313 if (!layer_tree_host_impl_) 314 return; 315 if (!layer_tree_host_->contents_texture_manager()) 316 return; 317 318 PrioritizedResourceManager* contents_texture_manager = 319 layer_tree_host_->contents_texture_manager(); 320 layer_tree_host_impl_->SendManagedMemoryStats( 321 contents_texture_manager->MemoryVisibleBytes(), 322 contents_texture_manager->MemoryVisibleAndNearbyBytes(), 323 contents_texture_manager->MemoryUseBytes()); 324} 325 326bool SingleThreadProxy::IsInsideDraw() { return inside_draw_; } 327 328void SingleThreadProxy::DidLoseOutputSurfaceOnImplThread() { 329 // Cause a commit so we can notice the lost context. 330 SetNeedsCommitOnImplThread(); 331} 332 333// Called by the legacy scheduling path (e.g. where render_widget does the 334// scheduling) 335void SingleThreadProxy::CompositeImmediately(base::TimeTicks frame_begin_time) { 336 gfx::Rect device_viewport_damage_rect; 337 338 LayerTreeHostImpl::FrameData frame; 339 if (CommitAndComposite(frame_begin_time, 340 device_viewport_damage_rect, 341 false, // for_readback 342 &frame)) { 343 layer_tree_host_impl_->SwapBuffers(frame); 344 DidSwapFrame(); 345 } 346} 347 348scoped_ptr<base::Value> SingleThreadProxy::AsValue() const { 349 scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue()); 350 { 351 // The following line casts away const modifiers because it is just 352 // setting debug state. We still want the AsValue() function and its 353 // call chain to be const throughout. 354 DebugScopedSetImplThread impl(const_cast<SingleThreadProxy*>(this)); 355 356 state->Set("layer_tree_host_impl", 357 layer_tree_host_impl_->AsValue().release()); 358 } 359 return state.PassAs<base::Value>(); 360} 361 362void SingleThreadProxy::ForceSerializeOnSwapBuffers() { 363 { 364 DebugScopedSetImplThread impl(this); 365 if (layer_tree_host_impl_->renderer()) { 366 DCHECK(!layer_tree_host_->output_surface_lost()); 367 layer_tree_host_impl_->renderer()->DoNoOp(); 368 } 369 } 370} 371 372bool SingleThreadProxy::CommitAndComposite( 373 base::TimeTicks frame_begin_time, 374 gfx::Rect device_viewport_damage_rect, 375 bool for_readback, 376 LayerTreeHostImpl::FrameData* frame) { 377 DCHECK(Proxy::IsMainThread()); 378 379 if (!layer_tree_host_->InitializeOutputSurfaceIfNeeded()) 380 return false; 381 382 layer_tree_host_->AnimateLayers(frame_begin_time); 383 384 scoped_refptr<cc::ContextProvider> offscreen_context_provider; 385 if (renderer_capabilities_for_main_thread_.using_offscreen_context3d && 386 layer_tree_host_->needs_offscreen_context()) { 387 offscreen_context_provider = 388 layer_tree_host_->client()->OffscreenContextProviderForMainThread(); 389 if (offscreen_context_provider) 390 created_offscreen_context_provider_ = true; 391 } 392 393 layer_tree_host_->contents_texture_manager()->UnlinkAndClearEvictedBackings(); 394 395 scoped_ptr<ResourceUpdateQueue> queue = 396 make_scoped_ptr(new ResourceUpdateQueue); 397 layer_tree_host_->UpdateLayers( 398 queue.get(), layer_tree_host_impl_->memory_allocation_limit_bytes()); 399 400 layer_tree_host_->WillCommit(); 401 DoCommit(queue.Pass()); 402 bool result = DoComposite(offscreen_context_provider, 403 frame_begin_time, 404 device_viewport_damage_rect, 405 for_readback, 406 frame); 407 layer_tree_host_->DidBeginFrame(); 408 return result; 409} 410 411bool SingleThreadProxy::ShouldComposite() const { 412 DCHECK(Proxy::IsImplThread()); 413 return layer_tree_host_impl_->visible() && 414 layer_tree_host_impl_->CanDraw(); 415} 416 417bool SingleThreadProxy::DoComposite( 418 scoped_refptr<cc::ContextProvider> offscreen_context_provider, 419 base::TimeTicks frame_begin_time, 420 gfx::Rect device_viewport_damage_rect, 421 bool for_readback, 422 LayerTreeHostImpl::FrameData* frame) { 423 DCHECK(!layer_tree_host_->output_surface_lost()); 424 425 bool lost_output_surface = false; 426 { 427 DebugScopedSetImplThread impl(this); 428 base::AutoReset<bool> mark_inside(&inside_draw_, true); 429 430 layer_tree_host_impl_->resource_provider()-> 431 set_offscreen_context_provider(offscreen_context_provider); 432 433 bool can_do_readback = layer_tree_host_impl_->renderer()->CanReadPixels(); 434 435 // We guard PrepareToDraw() with CanDraw() because it always returns a valid 436 // frame, so can only be used when such a frame is possible. Since 437 // DrawLayers() depends on the result of PrepareToDraw(), it is guarded on 438 // CanDraw() as well. 439 if (!ShouldComposite() || (for_readback && !can_do_readback)) { 440 layer_tree_host_impl_->UpdateBackgroundAnimateTicking(true); 441 return false; 442 } 443 444 layer_tree_host_impl_->Animate( 445 layer_tree_host_impl_->CurrentFrameTimeTicks(), 446 layer_tree_host_impl_->CurrentFrameTime()); 447 layer_tree_host_impl_->UpdateBackgroundAnimateTicking(false); 448 449 layer_tree_host_impl_->PrepareToDraw(frame, device_viewport_damage_rect); 450 layer_tree_host_impl_->DrawLayers(frame, frame_begin_time); 451 layer_tree_host_impl_->DidDrawAllLayers(*frame); 452 lost_output_surface = layer_tree_host_impl_->IsContextLost(); 453 454 bool start_ready_animations = true; 455 layer_tree_host_impl_->UpdateAnimationState(start_ready_animations); 456 457 layer_tree_host_impl_->BeginNextFrame(); 458 } 459 460 if (lost_output_surface) { 461 cc::ContextProvider* offscreen_contexts = layer_tree_host_impl_-> 462 resource_provider()->offscreen_context_provider(); 463 if (offscreen_contexts) 464 offscreen_contexts->VerifyContexts(); 465 layer_tree_host_->DidLoseOutputSurface(); 466 return false; 467 } 468 469 return true; 470} 471 472void SingleThreadProxy::DidSwapFrame() { 473 if (next_frame_is_newly_committed_frame_) { 474 next_frame_is_newly_committed_frame_ = false; 475 layer_tree_host_->DidCommitAndDrawFrame(); 476 } 477} 478 479bool SingleThreadProxy::CommitPendingForTesting() { return false; } 480 481skia::RefPtr<SkPicture> SingleThreadProxy::CapturePicture() { 482 // Impl-side painting only. 483 NOTREACHED(); 484 return skia::RefPtr<SkPicture>(); 485} 486 487} // namespace cc 488