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