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.
5 #include "cc/trees/single_thread_proxy.h"
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"
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>();
30 SingleThreadProxy::SingleThreadProxy(LayerTreeHost* layer_tree_host,
31 LayerTreeHostSingleThreadClient* client)
33 layer_tree_host_(layer_tree_host),
35 created_offscreen_context_provider_(false),
36 next_frame_is_newly_committed_frame_(false),
38 TRACE_EVENT0("cc", "SingleThreadProxy::SingleThreadProxy");
39 DCHECK(Proxy::IsMainThread());
40 DCHECK(layer_tree_host);
42 // Impl-side painting not supported without threaded compositing.
43 CHECK(!layer_tree_host->settings().impl_side_painting)
44 << "Threaded compositing must be enabled to use impl-side painting.";
47 void SingleThreadProxy::Start() {
48 DebugScopedSetImplThread impl(this);
49 layer_tree_host_impl_ = layer_tree_host_->CreateLayerTreeHostImpl(this);
52 SingleThreadProxy::~SingleThreadProxy() {
53 TRACE_EVENT0("cc", "SingleThreadProxy::~SingleThreadProxy");
54 DCHECK(Proxy::IsMainThread());
55 // Make sure Stop() got called or never Started.
56 DCHECK(!layer_tree_host_impl_);
59 bool SingleThreadProxy::CompositeAndReadback(void* pixels,
60 const gfx::Rect& rect) {
61 TRACE_EVENT0("cc", "SingleThreadProxy::CompositeAndReadback");
62 DCHECK(Proxy::IsMainThread());
64 gfx::Rect device_viewport_damage_rect = rect;
66 LayerTreeHostImpl::FrameData frame;
67 if (!CommitAndComposite(gfx::FrameTime::Now(),
68 device_viewport_damage_rect,
74 DebugScopedSetImplThread impl(this);
75 layer_tree_host_impl_->Readback(pixels, rect);
77 if (layer_tree_host_impl_->IsContextLost())
84 void SingleThreadProxy::FinishAllRendering() {
85 TRACE_EVENT0("cc", "SingleThreadProxy::FinishAllRendering");
86 DCHECK(Proxy::IsMainThread());
88 DebugScopedSetImplThread impl(this);
89 layer_tree_host_impl_->FinishAllRendering();
93 bool SingleThreadProxy::IsStarted() const {
94 DCHECK(Proxy::IsMainThread());
95 return layer_tree_host_impl_;
98 void SingleThreadProxy::SetLayerTreeHostClientReady() {
99 TRACE_EVENT0("cc", "SingleThreadProxy::SetLayerTreeHostClientReady");
100 // Scheduling is controlled by the embedder in the single thread case, so
104 void SingleThreadProxy::SetVisible(bool visible) {
105 TRACE_EVENT0("cc", "SingleThreadProxy::SetVisible");
106 DebugScopedSetImplThread impl(this);
107 layer_tree_host_impl_->SetVisible(visible);
109 // Changing visibility could change ShouldComposite().
110 UpdateBackgroundAnimateTicking();
113 void SingleThreadProxy::CreateAndInitializeOutputSurface() {
115 "cc", "SingleThreadProxy::CreateAndInitializeOutputSurface");
116 DCHECK(Proxy::IsMainThread());
118 scoped_ptr<OutputSurface> output_surface =
119 layer_tree_host_->CreateOutputSurface();
120 if (!output_surface) {
121 OnOutputSurfaceInitializeAttempted(false);
125 scoped_refptr<ContextProvider> offscreen_context_provider;
126 if (created_offscreen_context_provider_) {
127 offscreen_context_provider =
128 layer_tree_host_->client()->OffscreenContextProvider();
129 if (!offscreen_context_provider.get() ||
130 !offscreen_context_provider->BindToCurrentThread()) {
131 OnOutputSurfaceInitializeAttempted(false);
137 DebugScopedSetMainThreadBlocked main_thread_blocked(this);
138 DebugScopedSetImplThread impl(this);
139 layer_tree_host_->DeleteContentsTexturesOnImplThread(
140 layer_tree_host_impl_->resource_provider());
145 DebugScopedSetImplThread impl(this);
147 DCHECK(output_surface);
148 initialized = layer_tree_host_impl_->InitializeRenderer(
149 output_surface.Pass());
150 if (!initialized && offscreen_context_provider.get()) {
151 offscreen_context_provider->VerifyContexts();
152 offscreen_context_provider = NULL;
155 layer_tree_host_impl_->SetOffscreenContextProvider(
156 offscreen_context_provider);
159 OnOutputSurfaceInitializeAttempted(initialized);
162 void SingleThreadProxy::OnOutputSurfaceInitializeAttempted(bool success) {
163 LayerTreeHost::CreateResult result =
164 layer_tree_host_->OnCreateAndInitializeOutputSurfaceAttempted(success);
165 if (result == LayerTreeHost::CreateFailedButTryAgain) {
166 // Force another recreation attempt to happen by requesting another commit.
171 const RendererCapabilities& SingleThreadProxy::GetRendererCapabilities() const {
172 DCHECK(Proxy::IsMainThread());
173 DCHECK(!layer_tree_host_->output_surface_lost());
174 return renderer_capabilities_for_main_thread_;
177 void SingleThreadProxy::SetNeedsAnimate() {
178 TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsAnimate");
179 DCHECK(Proxy::IsMainThread());
180 client_->ScheduleAnimation();
183 void SingleThreadProxy::SetNeedsUpdateLayers() {
184 TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsUpdateLayers");
185 DCHECK(Proxy::IsMainThread());
186 client_->ScheduleComposite();
189 void SingleThreadProxy::DoCommit(scoped_ptr<ResourceUpdateQueue> queue) {
190 TRACE_EVENT0("cc", "SingleThreadProxy::DoCommit");
191 DCHECK(Proxy::IsMainThread());
192 // Commit immediately.
194 DebugScopedSetMainThreadBlocked main_thread_blocked(this);
195 DebugScopedSetImplThread impl(this);
197 // This CapturePostTasks should be destroyed before CommitComplete() is
198 // called since that goes out to the embedder, and we want the embedder
199 // to receive its callbacks before that.
200 BlockingTaskRunner::CapturePostTasks blocked;
202 layer_tree_host_impl_->BeginCommit();
204 if (PrioritizedResourceManager* contents_texture_manager =
205 layer_tree_host_->contents_texture_manager()) {
206 contents_texture_manager->PushTexturePrioritiesToBackings();
208 layer_tree_host_->BeginCommitOnImplThread(layer_tree_host_impl_.get());
210 scoped_ptr<ResourceUpdateController> update_controller =
211 ResourceUpdateController::Create(
213 Proxy::MainThreadTaskRunner(),
215 layer_tree_host_impl_->resource_provider());
216 update_controller->Finalize();
218 if (layer_tree_host_impl_->EvictedUIResourcesExist())
219 layer_tree_host_->RecreateUIResources();
221 layer_tree_host_->FinishCommitOnImplThread(layer_tree_host_impl_.get());
223 layer_tree_host_impl_->CommitComplete();
226 // In the single-threaded case, the scale and scroll deltas should never be
227 // touched on the impl layer tree.
228 scoped_ptr<ScrollAndScaleSet> scroll_info =
229 layer_tree_host_impl_->ProcessScrollDeltas();
230 DCHECK(!scroll_info->scrolls.size());
231 DCHECK_EQ(1.f, scroll_info->page_scale_delta);
234 RenderingStatsInstrumentation* stats_instrumentation =
235 layer_tree_host_->rendering_stats_instrumentation();
236 BenchmarkInstrumentation::IssueMainThreadRenderingStatsEvent(
237 stats_instrumentation->main_thread_rendering_stats());
238 stats_instrumentation->AccumulateAndClearMainThreadStats();
240 layer_tree_host_->CommitComplete();
241 next_frame_is_newly_committed_frame_ = true;
244 void SingleThreadProxy::SetNeedsCommit() {
245 DCHECK(Proxy::IsMainThread());
246 client_->ScheduleComposite();
249 void SingleThreadProxy::SetNeedsRedraw(const gfx::Rect& damage_rect) {
250 TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsRedraw");
251 SetNeedsRedrawRectOnImplThread(damage_rect);
252 client_->ScheduleComposite();
255 void SingleThreadProxy::SetNextCommitWaitsForActivation() {
256 // There is no activation here other than commit. So do nothing.
259 void SingleThreadProxy::SetDeferCommits(bool defer_commits) {
260 // Thread-only feature.
264 bool SingleThreadProxy::CommitRequested() const { return false; }
266 bool SingleThreadProxy::BeginMainFrameRequested() const { return false; }
268 size_t SingleThreadProxy::MaxPartialTextureUpdates() const {
269 return std::numeric_limits<size_t>::max();
272 void SingleThreadProxy::Stop() {
273 TRACE_EVENT0("cc", "SingleThreadProxy::stop");
274 DCHECK(Proxy::IsMainThread());
276 DebugScopedSetMainThreadBlocked main_thread_blocked(this);
277 DebugScopedSetImplThread impl(this);
279 layer_tree_host_->DeleteContentsTexturesOnImplThread(
280 layer_tree_host_impl_->resource_provider());
281 layer_tree_host_impl_.reset();
283 layer_tree_host_ = NULL;
286 void SingleThreadProxy::OnCanDrawStateChanged(bool can_draw) {
288 "cc", "SingleThreadProxy::OnCanDrawStateChanged", "can_draw", can_draw);
289 DCHECK(Proxy::IsImplThread());
290 UpdateBackgroundAnimateTicking();
293 void SingleThreadProxy::NotifyReadyToActivate() {
294 // Thread-only feature.
298 void SingleThreadProxy::SetNeedsRedrawOnImplThread() {
299 client_->ScheduleComposite();
302 void SingleThreadProxy::SetNeedsManageTilesOnImplThread() {
303 // Thread-only/Impl-side-painting-only feature.
307 void SingleThreadProxy::SetNeedsRedrawRectOnImplThread(
308 const gfx::Rect& damage_rect) {
309 // TODO(brianderson): Once we move render_widget scheduling into this class,
310 // we can treat redraw requests more efficiently than CommitAndRedraw
312 layer_tree_host_impl_->SetViewportDamage(damage_rect);
316 void SingleThreadProxy::DidInitializeVisibleTileOnImplThread() {
317 // Impl-side painting only.
321 void SingleThreadProxy::SetNeedsCommitOnImplThread() {
322 client_->ScheduleComposite();
325 void SingleThreadProxy::PostAnimationEventsToMainThreadOnImplThread(
326 scoped_ptr<AnimationEventsVector> events,
327 base::Time wall_clock_time) {
329 "cc", "SingleThreadProxy::PostAnimationEventsToMainThreadOnImplThread");
330 DCHECK(Proxy::IsImplThread());
331 DebugScopedSetMainThread main(this);
332 layer_tree_host_->SetAnimationEvents(events.Pass(), wall_clock_time);
335 bool SingleThreadProxy::ReduceContentsTextureMemoryOnImplThread(
337 int priority_cutoff) {
338 DCHECK(IsImplThread());
339 PrioritizedResourceManager* contents_texture_manager =
340 layer_tree_host_->contents_texture_manager();
342 ResourceProvider* resource_provider =
343 layer_tree_host_impl_->resource_provider();
345 if (!contents_texture_manager || !resource_provider)
348 return contents_texture_manager->ReduceMemoryOnImplThread(
349 limit_bytes, priority_cutoff, resource_provider);
352 void SingleThreadProxy::SendManagedMemoryStats() {
353 DCHECK(Proxy::IsImplThread());
354 if (!layer_tree_host_impl_)
356 PrioritizedResourceManager* contents_texture_manager =
357 layer_tree_host_->contents_texture_manager();
358 if (!contents_texture_manager)
361 layer_tree_host_impl_->SendManagedMemoryStats(
362 contents_texture_manager->MemoryVisibleBytes(),
363 contents_texture_manager->MemoryVisibleAndNearbyBytes(),
364 contents_texture_manager->MemoryUseBytes());
367 bool SingleThreadProxy::IsInsideDraw() { return inside_draw_; }
369 void SingleThreadProxy::UpdateRendererCapabilitiesOnImplThread() {
370 DCHECK(IsImplThread());
371 renderer_capabilities_for_main_thread_ =
372 layer_tree_host_impl_->GetRendererCapabilities().MainThreadCapabilities();
375 void SingleThreadProxy::DidLoseOutputSurfaceOnImplThread() {
376 TRACE_EVENT0("cc", "SingleThreadProxy::DidLoseOutputSurfaceOnImplThread");
377 // Cause a commit so we can notice the lost context.
378 SetNeedsCommitOnImplThread();
379 client_->DidAbortSwapBuffers();
382 void SingleThreadProxy::DidSwapBuffersOnImplThread() {
383 client_->DidPostSwapBuffers();
386 void SingleThreadProxy::OnSwapBuffersCompleteOnImplThread() {
387 TRACE_EVENT0("cc", "SingleThreadProxy::OnSwapBuffersCompleteOnImplThread");
388 client_->DidCompleteSwapBuffers();
391 // Called by the legacy scheduling path (e.g. where render_widget does the
393 void SingleThreadProxy::CompositeImmediately(base::TimeTicks frame_begin_time) {
394 TRACE_EVENT0("cc", "SingleThreadProxy::CompositeImmediately");
395 gfx::Rect device_viewport_damage_rect;
397 LayerTreeHostImpl::FrameData frame;
398 if (CommitAndComposite(frame_begin_time,
399 device_viewport_damage_rect,
400 false, // for_readback
403 DebugScopedSetMainThreadBlocked main_thread_blocked(this);
404 DebugScopedSetImplThread impl(this);
406 // This CapturePostTasks should be destroyed before
407 // DidCommitAndDrawFrame() is called since that goes out to the embedder,
408 // and we want the embedder to receive its callbacks before that.
409 // NOTE: This maintains consistent ordering with the ThreadProxy since
410 // the DidCommitAndDrawFrame() must be post-tasked from the impl thread
411 // there as the main thread is not blocked, so any posted tasks inside
412 // the swap buffers will execute first.
413 BlockingTaskRunner::CapturePostTasks blocked;
415 layer_tree_host_impl_->SwapBuffers(frame);
421 scoped_ptr<base::Value> SingleThreadProxy::AsValue() const {
422 scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue());
424 // The following line casts away const modifiers because it is just
425 // setting debug state. We still want the AsValue() function and its
426 // call chain to be const throughout.
427 DebugScopedSetImplThread impl(const_cast<SingleThreadProxy*>(this));
429 state->Set("layer_tree_host_impl",
430 layer_tree_host_impl_->AsValue().release());
432 return state.PassAs<base::Value>();
435 void SingleThreadProxy::ForceSerializeOnSwapBuffers() {
437 DebugScopedSetImplThread impl(this);
438 if (layer_tree_host_impl_->renderer()) {
439 DCHECK(!layer_tree_host_->output_surface_lost());
440 layer_tree_host_impl_->renderer()->DoNoOp();
445 bool SingleThreadProxy::CommitAndComposite(
446 base::TimeTicks frame_begin_time,
447 const gfx::Rect& device_viewport_damage_rect,
449 LayerTreeHostImpl::FrameData* frame) {
450 TRACE_EVENT0("cc", "SingleThreadProxy::CommitAndComposite");
451 DCHECK(Proxy::IsMainThread());
453 if (!layer_tree_host_->InitializeOutputSurfaceIfNeeded())
456 layer_tree_host_->AnimateLayers(frame_begin_time);
458 if (PrioritizedResourceManager* contents_texture_manager =
459 layer_tree_host_->contents_texture_manager()) {
460 contents_texture_manager->UnlinkAndClearEvictedBackings();
461 contents_texture_manager->SetMaxMemoryLimitBytes(
462 layer_tree_host_impl_->memory_allocation_limit_bytes());
463 contents_texture_manager->SetExternalPriorityCutoff(
464 layer_tree_host_impl_->memory_allocation_priority_cutoff());
467 scoped_ptr<ResourceUpdateQueue> queue =
468 make_scoped_ptr(new ResourceUpdateQueue);
469 layer_tree_host_->UpdateLayers(queue.get());
471 layer_tree_host_->WillCommit();
473 scoped_refptr<ContextProvider> offscreen_context_provider;
474 if (renderer_capabilities_for_main_thread_.using_offscreen_context3d &&
475 layer_tree_host_->needs_offscreen_context()) {
476 offscreen_context_provider =
477 layer_tree_host_->client()->OffscreenContextProvider();
478 if (offscreen_context_provider.get() &&
479 !offscreen_context_provider->BindToCurrentThread())
480 offscreen_context_provider = NULL;
482 if (offscreen_context_provider.get())
483 created_offscreen_context_provider_ = true;
486 DoCommit(queue.Pass());
487 bool result = DoComposite(offscreen_context_provider,
489 device_viewport_damage_rect,
492 layer_tree_host_->DidBeginMainFrame();
496 bool SingleThreadProxy::ShouldComposite() const {
497 DCHECK(Proxy::IsImplThread());
498 return layer_tree_host_impl_->visible() &&
499 layer_tree_host_impl_->CanDraw();
502 void SingleThreadProxy::UpdateBackgroundAnimateTicking() {
503 DCHECK(Proxy::IsImplThread());
504 layer_tree_host_impl_->UpdateBackgroundAnimateTicking(
505 !ShouldComposite() && layer_tree_host_impl_->active_tree()->root_layer());
508 bool SingleThreadProxy::DoComposite(
509 scoped_refptr<ContextProvider> offscreen_context_provider,
510 base::TimeTicks frame_begin_time,
511 const gfx::Rect& device_viewport_damage_rect,
513 LayerTreeHostImpl::FrameData* frame) {
514 TRACE_EVENT0("cc", "SingleThreadProxy::DoComposite");
515 DCHECK(!layer_tree_host_->output_surface_lost());
517 bool lost_output_surface = false;
519 DebugScopedSetImplThread impl(this);
520 base::AutoReset<bool> mark_inside(&inside_draw_, true);
522 layer_tree_host_impl_->SetOffscreenContextProvider(
523 offscreen_context_provider);
525 bool can_do_readback = layer_tree_host_impl_->renderer()->CanReadPixels();
527 // We guard PrepareToDraw() with CanDraw() because it always returns a valid
528 // frame, so can only be used when such a frame is possible. Since
529 // DrawLayers() depends on the result of PrepareToDraw(), it is guarded on
530 // CanDraw() as well.
531 if (!ShouldComposite() || (for_readback && !can_do_readback)) {
532 UpdateBackgroundAnimateTicking();
536 layer_tree_host_impl_->Animate(
537 layer_tree_host_impl_->CurrentFrameTimeTicks(),
538 layer_tree_host_impl_->CurrentFrameTime());
539 UpdateBackgroundAnimateTicking();
541 if (!layer_tree_host_impl_->IsContextLost()) {
542 layer_tree_host_impl_->PrepareToDraw(frame, device_viewport_damage_rect);
543 layer_tree_host_impl_->DrawLayers(frame, frame_begin_time);
544 layer_tree_host_impl_->DidDrawAllLayers(*frame);
546 lost_output_surface = layer_tree_host_impl_->IsContextLost();
548 bool start_ready_animations = true;
549 layer_tree_host_impl_->UpdateAnimationState(start_ready_animations);
551 layer_tree_host_impl_->ResetCurrentFrameTimeForNextFrame();
554 if (lost_output_surface) {
555 ContextProvider* offscreen_contexts =
556 layer_tree_host_impl_->offscreen_context_provider();
557 if (offscreen_contexts)
558 offscreen_contexts->VerifyContexts();
559 layer_tree_host_->DidLoseOutputSurface();
566 void SingleThreadProxy::DidSwapFrame() {
567 if (next_frame_is_newly_committed_frame_) {
568 next_frame_is_newly_committed_frame_ = false;
569 layer_tree_host_->DidCommitAndDrawFrame();
573 bool SingleThreadProxy::CommitPendingForTesting() { return false; }