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 21namespace cc { 22 23scoped_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 30SingleThreadProxy::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 46void SingleThreadProxy::Start() { 47 DebugScopedSetImplThread impl(this); 48 layer_tree_host_impl_ = layer_tree_host_->CreateLayerTreeHostImpl(this); 49} 50 51SingleThreadProxy::~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 58void 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 67bool SingleThreadProxy::IsStarted() const { 68 DCHECK(Proxy::IsMainThread()); 69 return layer_tree_host_impl_; 70} 71 72void 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 78void 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 87void 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 115const 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 121void SingleThreadProxy::SetNeedsAnimate() { 122 TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsAnimate"); 123 DCHECK(Proxy::IsMainThread()); 124 client_->ScheduleAnimation(); 125} 126 127void SingleThreadProxy::SetNeedsUpdateLayers() { 128 TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsUpdateLayers"); 129 DCHECK(Proxy::IsMainThread()); 130 client_->ScheduleComposite(); 131} 132 133void 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 188void SingleThreadProxy::SetNeedsCommit() { 189 DCHECK(Proxy::IsMainThread()); 190 client_->ScheduleComposite(); 191} 192 193void SingleThreadProxy::SetNeedsRedraw(const gfx::Rect& damage_rect) { 194 TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsRedraw"); 195 SetNeedsRedrawRectOnImplThread(damage_rect); 196 client_->ScheduleComposite(); 197} 198 199void SingleThreadProxy::SetNextCommitWaitsForActivation() { 200 // There is no activation here other than commit. So do nothing. 201} 202 203void SingleThreadProxy::SetDeferCommits(bool defer_commits) { 204 // Thread-only feature. 205 NOTREACHED(); 206} 207 208bool SingleThreadProxy::CommitRequested() const { return false; } 209 210bool SingleThreadProxy::BeginMainFrameRequested() const { return false; } 211 212size_t SingleThreadProxy::MaxPartialTextureUpdates() const { 213 return std::numeric_limits<size_t>::max(); 214} 215 216void 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 231void SingleThreadProxy::OnCanDrawStateChanged(bool can_draw) { 232 TRACE_EVENT1( 233 "cc", "SingleThreadProxy::OnCanDrawStateChanged", "can_draw", can_draw); 234 DCHECK(Proxy::IsImplThread()); 235 UpdateBackgroundAnimateTicking(); 236} 237 238void SingleThreadProxy::NotifyReadyToActivate() { 239 // Thread-only feature. 240 NOTREACHED(); 241} 242 243void SingleThreadProxy::SetNeedsRedrawOnImplThread() { 244 client_->ScheduleComposite(); 245} 246 247void SingleThreadProxy::SetNeedsAnimateOnImplThread() { 248 SetNeedsRedrawOnImplThread(); 249} 250 251void SingleThreadProxy::SetNeedsManageTilesOnImplThread() { 252 // Thread-only/Impl-side-painting-only feature. 253 NOTREACHED(); 254} 255 256void 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 265void SingleThreadProxy::DidInitializeVisibleTileOnImplThread() { 266 // Impl-side painting only. 267 NOTREACHED(); 268} 269 270void SingleThreadProxy::SetNeedsCommitOnImplThread() { 271 client_->ScheduleComposite(); 272} 273 274void 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 283bool 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 300bool SingleThreadProxy::IsInsideDraw() { return inside_draw_; } 301 302void SingleThreadProxy::UpdateRendererCapabilitiesOnImplThread() { 303 DCHECK(IsImplThread()); 304 renderer_capabilities_for_main_thread_ = 305 layer_tree_host_impl_->GetRendererCapabilities().MainThreadCapabilities(); 306} 307 308void 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 315void SingleThreadProxy::DidSwapBuffersOnImplThread() { 316 client_->DidPostSwapBuffers(); 317} 318 319void 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) 326void 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 370scoped_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 384void 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 394bool SingleThreadProxy::ShouldComposite() const { 395 DCHECK(Proxy::IsImplThread()); 396 return layer_tree_host_impl_->visible() && 397 layer_tree_host_impl_->CanDraw(); 398} 399 400void SingleThreadProxy::UpdateBackgroundAnimateTicking() { 401 DCHECK(Proxy::IsImplThread()); 402 layer_tree_host_impl_->UpdateBackgroundAnimateTicking( 403 !ShouldComposite() && layer_tree_host_impl_->active_tree()->root_layer()); 404} 405 406bool 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 451void 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 458bool SingleThreadProxy::CommitPendingForTesting() { return false; } 459 460} // namespace cc 461