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