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 DCHECK(Proxy::IsMainThread());
87 DebugScopedSetImplThread
impl(this);
88 layer_tree_host_impl_
->FinishAllRendering();
92 bool SingleThreadProxy::IsStarted() const {
93 DCHECK(Proxy::IsMainThread());
94 return layer_tree_host_impl_
;
97 void SingleThreadProxy::SetLayerTreeHostClientReady() {
98 // Scheduling is controlled by the embedder in the single thread case, so
102 void SingleThreadProxy::SetVisible(bool visible
) {
103 DebugScopedSetImplThread
impl(this);
104 layer_tree_host_impl_
->SetVisible(visible
);
106 // Changing visibility could change ShouldComposite().
107 UpdateBackgroundAnimateTicking();
110 void SingleThreadProxy::CreateAndInitializeOutputSurface() {
112 "cc", "SingleThreadProxy::CreateAndInitializeOutputSurface");
113 DCHECK(Proxy::IsMainThread());
115 scoped_ptr
<OutputSurface
> output_surface
=
116 layer_tree_host_
->CreateOutputSurface();
117 if (!output_surface
) {
118 OnOutputSurfaceInitializeAttempted(false);
122 scoped_refptr
<ContextProvider
> offscreen_context_provider
;
123 if (created_offscreen_context_provider_
) {
124 offscreen_context_provider
=
125 layer_tree_host_
->client()->OffscreenContextProvider();
126 if (!offscreen_context_provider
.get() ||
127 !offscreen_context_provider
->BindToCurrentThread()) {
128 OnOutputSurfaceInitializeAttempted(false);
134 DebugScopedSetMainThreadBlocked
main_thread_blocked(this);
135 DebugScopedSetImplThread
impl(this);
136 layer_tree_host_
->DeleteContentsTexturesOnImplThread(
137 layer_tree_host_impl_
->resource_provider());
142 DebugScopedSetImplThread
impl(this);
144 DCHECK(output_surface
);
145 initialized
= layer_tree_host_impl_
->InitializeRenderer(
146 output_surface
.Pass());
148 renderer_capabilities_for_main_thread_
=
149 layer_tree_host_impl_
->GetRendererCapabilities()
150 .MainThreadCapabilities();
151 } else if (offscreen_context_provider
.get()) {
152 offscreen_context_provider
->VerifyContexts();
153 offscreen_context_provider
= NULL
;
156 layer_tree_host_impl_
->SetOffscreenContextProvider(
157 offscreen_context_provider
);
160 OnOutputSurfaceInitializeAttempted(initialized
);
163 void SingleThreadProxy::OnOutputSurfaceInitializeAttempted(bool success
) {
164 LayerTreeHost::CreateResult result
=
165 layer_tree_host_
->OnCreateAndInitializeOutputSurfaceAttempted(success
);
166 if (result
== LayerTreeHost::CreateFailedButTryAgain
) {
167 // Force another recreation attempt to happen by requesting another commit.
172 const RendererCapabilities
& SingleThreadProxy::GetRendererCapabilities() const {
173 DCHECK(Proxy::IsMainThread());
174 DCHECK(!layer_tree_host_
->output_surface_lost());
175 return renderer_capabilities_for_main_thread_
;
178 void SingleThreadProxy::SetNeedsAnimate() {
179 DCHECK(Proxy::IsMainThread());
180 client_
->ScheduleAnimation();
183 void SingleThreadProxy::SetNeedsUpdateLayers() {
184 DCHECK(Proxy::IsMainThread());
185 client_
->ScheduleComposite();
188 void SingleThreadProxy::DoCommit(scoped_ptr
<ResourceUpdateQueue
> queue
) {
189 DCHECK(Proxy::IsMainThread());
190 // Commit immediately.
192 DebugScopedSetMainThreadBlocked
main_thread_blocked(this);
193 DebugScopedSetImplThread
impl(this);
195 // This CapturePostTasks should be destroyed before CommitComplete() is
196 // called since that goes out to the embedder, and we want the embedder
197 // to receive its callbacks before that.
198 BlockingTaskRunner::CapturePostTasks blocked
;
200 layer_tree_host_impl_
->BeginCommit();
202 if (PrioritizedResourceManager
* contents_texture_manager
=
203 layer_tree_host_
->contents_texture_manager()) {
204 contents_texture_manager
->PushTexturePrioritiesToBackings();
206 layer_tree_host_
->BeginCommitOnImplThread(layer_tree_host_impl_
.get());
208 scoped_ptr
<ResourceUpdateController
> update_controller
=
209 ResourceUpdateController::Create(
211 Proxy::MainThreadTaskRunner(),
213 layer_tree_host_impl_
->resource_provider());
214 update_controller
->Finalize();
216 if (layer_tree_host_impl_
->EvictedUIResourcesExist())
217 layer_tree_host_
->RecreateUIResources();
219 layer_tree_host_
->FinishCommitOnImplThread(layer_tree_host_impl_
.get());
221 layer_tree_host_impl_
->CommitComplete();
224 // In the single-threaded case, the scale and scroll deltas should never be
225 // touched on the impl layer tree.
226 scoped_ptr
<ScrollAndScaleSet
> scroll_info
=
227 layer_tree_host_impl_
->ProcessScrollDeltas();
228 DCHECK(!scroll_info
->scrolls
.size());
229 DCHECK_EQ(1.f
, scroll_info
->page_scale_delta
);
232 RenderingStatsInstrumentation
* stats_instrumentation
=
233 layer_tree_host_
->rendering_stats_instrumentation();
234 BenchmarkInstrumentation::IssueMainThreadRenderingStatsEvent(
235 stats_instrumentation
->main_thread_rendering_stats());
236 stats_instrumentation
->AccumulateAndClearMainThreadStats();
238 layer_tree_host_
->CommitComplete();
239 next_frame_is_newly_committed_frame_
= true;
242 void SingleThreadProxy::SetNeedsCommit() {
243 DCHECK(Proxy::IsMainThread());
244 client_
->ScheduleComposite();
247 void SingleThreadProxy::SetNeedsRedraw(const gfx::Rect
& damage_rect
) {
248 SetNeedsRedrawRectOnImplThread(damage_rect
);
249 client_
->ScheduleComposite();
252 void SingleThreadProxy::SetNextCommitWaitsForActivation() {
253 // There is no activation here other than commit. So do nothing.
256 void SingleThreadProxy::SetDeferCommits(bool defer_commits
) {
257 // Thread-only feature.
261 bool SingleThreadProxy::CommitRequested() const { return false; }
263 bool SingleThreadProxy::BeginMainFrameRequested() const { return false; }
265 size_t SingleThreadProxy::MaxPartialTextureUpdates() const {
266 return std::numeric_limits
<size_t>::max();
269 void SingleThreadProxy::Stop() {
270 TRACE_EVENT0("cc", "SingleThreadProxy::stop");
271 DCHECK(Proxy::IsMainThread());
273 DebugScopedSetMainThreadBlocked
main_thread_blocked(this);
274 DebugScopedSetImplThread
impl(this);
276 layer_tree_host_
->DeleteContentsTexturesOnImplThread(
277 layer_tree_host_impl_
->resource_provider());
278 layer_tree_host_impl_
.reset();
280 layer_tree_host_
= NULL
;
283 void SingleThreadProxy::OnCanDrawStateChanged(bool can_draw
) {
284 DCHECK(Proxy::IsImplThread());
285 UpdateBackgroundAnimateTicking();
288 void SingleThreadProxy::NotifyReadyToActivate() {
289 // Thread-only feature.
293 void SingleThreadProxy::SetNeedsRedrawOnImplThread() {
294 client_
->ScheduleComposite();
297 void SingleThreadProxy::SetNeedsManageTilesOnImplThread() {
298 // Thread-only/Impl-side-painting-only feature.
302 void SingleThreadProxy::SetNeedsRedrawRectOnImplThread(
303 const gfx::Rect
& damage_rect
) {
304 // TODO(brianderson): Once we move render_widget scheduling into this class,
305 // we can treat redraw requests more efficiently than CommitAndRedraw
307 layer_tree_host_impl_
->SetViewportDamage(damage_rect
);
311 void SingleThreadProxy::DidInitializeVisibleTileOnImplThread() {
312 // Impl-side painting only.
316 void SingleThreadProxy::SetNeedsCommitOnImplThread() {
317 client_
->ScheduleComposite();
320 void SingleThreadProxy::PostAnimationEventsToMainThreadOnImplThread(
321 scoped_ptr
<AnimationEventsVector
> events
,
322 base::Time wall_clock_time
) {
323 DCHECK(Proxy::IsImplThread());
324 DebugScopedSetMainThread
main(this);
325 layer_tree_host_
->SetAnimationEvents(events
.Pass(), wall_clock_time
);
328 bool SingleThreadProxy::ReduceContentsTextureMemoryOnImplThread(
330 int priority_cutoff
) {
331 DCHECK(IsImplThread());
332 PrioritizedResourceManager
* contents_texture_manager
=
333 layer_tree_host_
->contents_texture_manager();
335 ResourceProvider
* resource_provider
=
336 layer_tree_host_impl_
->resource_provider();
338 if (!contents_texture_manager
|| !resource_provider
)
341 return contents_texture_manager
->ReduceMemoryOnImplThread(
342 limit_bytes
, priority_cutoff
, resource_provider
);
345 void SingleThreadProxy::SendManagedMemoryStats() {
346 DCHECK(Proxy::IsImplThread());
347 if (!layer_tree_host_impl_
)
349 PrioritizedResourceManager
* contents_texture_manager
=
350 layer_tree_host_
->contents_texture_manager();
351 if (!contents_texture_manager
)
354 layer_tree_host_impl_
->SendManagedMemoryStats(
355 contents_texture_manager
->MemoryVisibleBytes(),
356 contents_texture_manager
->MemoryVisibleAndNearbyBytes(),
357 contents_texture_manager
->MemoryUseBytes());
360 bool SingleThreadProxy::IsInsideDraw() { return inside_draw_
; }
362 void SingleThreadProxy::DidLoseOutputSurfaceOnImplThread() {
363 // Cause a commit so we can notice the lost context.
364 SetNeedsCommitOnImplThread();
365 client_
->DidAbortSwapBuffers();
368 void SingleThreadProxy::DidSwapBuffersOnImplThread() {
369 client_
->DidPostSwapBuffers();
372 void SingleThreadProxy::OnSwapBuffersCompleteOnImplThread() {
373 client_
->DidCompleteSwapBuffers();
376 // Called by the legacy scheduling path (e.g. where render_widget does the
378 void SingleThreadProxy::CompositeImmediately(base::TimeTicks frame_begin_time
) {
379 gfx::Rect device_viewport_damage_rect
;
381 LayerTreeHostImpl::FrameData frame
;
382 if (CommitAndComposite(frame_begin_time
,
383 device_viewport_damage_rect
,
384 false, // for_readback
387 DebugScopedSetMainThreadBlocked
main_thread_blocked(this);
388 DebugScopedSetImplThread
impl(this);
390 // This CapturePostTasks should be destroyed before
391 // DidCommitAndDrawFrame() is called since that goes out to the embedder,
392 // and we want the embedder to receive its callbacks before that.
393 // NOTE: This maintains consistent ordering with the ThreadProxy since
394 // the DidCommitAndDrawFrame() must be post-tasked from the impl thread
395 // there as the main thread is not blocked, so any posted tasks inside
396 // the swap buffers will execute first.
397 BlockingTaskRunner::CapturePostTasks blocked
;
399 layer_tree_host_impl_
->SwapBuffers(frame
);
405 scoped_ptr
<base::Value
> SingleThreadProxy::AsValue() const {
406 scoped_ptr
<base::DictionaryValue
> state(new base::DictionaryValue());
408 // The following line casts away const modifiers because it is just
409 // setting debug state. We still want the AsValue() function and its
410 // call chain to be const throughout.
411 DebugScopedSetImplThread
impl(const_cast<SingleThreadProxy
*>(this));
413 state
->Set("layer_tree_host_impl",
414 layer_tree_host_impl_
->AsValue().release());
416 return state
.PassAs
<base::Value
>();
419 void SingleThreadProxy::ForceSerializeOnSwapBuffers() {
421 DebugScopedSetImplThread
impl(this);
422 if (layer_tree_host_impl_
->renderer()) {
423 DCHECK(!layer_tree_host_
->output_surface_lost());
424 layer_tree_host_impl_
->renderer()->DoNoOp();
429 bool SingleThreadProxy::CommitAndComposite(
430 base::TimeTicks frame_begin_time
,
431 const gfx::Rect
& device_viewport_damage_rect
,
433 LayerTreeHostImpl::FrameData
* frame
) {
434 DCHECK(Proxy::IsMainThread());
436 if (!layer_tree_host_
->InitializeOutputSurfaceIfNeeded())
439 layer_tree_host_
->AnimateLayers(frame_begin_time
);
441 if (PrioritizedResourceManager
* contents_texture_manager
=
442 layer_tree_host_
->contents_texture_manager()) {
443 contents_texture_manager
->UnlinkAndClearEvictedBackings();
444 contents_texture_manager
->SetMaxMemoryLimitBytes(
445 layer_tree_host_impl_
->memory_allocation_limit_bytes());
446 contents_texture_manager
->SetExternalPriorityCutoff(
447 layer_tree_host_impl_
->memory_allocation_priority_cutoff());
450 scoped_ptr
<ResourceUpdateQueue
> queue
=
451 make_scoped_ptr(new ResourceUpdateQueue
);
452 layer_tree_host_
->UpdateLayers(queue
.get());
454 layer_tree_host_
->WillCommit();
456 scoped_refptr
<ContextProvider
> offscreen_context_provider
;
457 if (renderer_capabilities_for_main_thread_
.using_offscreen_context3d
&&
458 layer_tree_host_
->needs_offscreen_context()) {
459 offscreen_context_provider
=
460 layer_tree_host_
->client()->OffscreenContextProvider();
461 if (offscreen_context_provider
.get() &&
462 !offscreen_context_provider
->BindToCurrentThread())
463 offscreen_context_provider
= NULL
;
465 if (offscreen_context_provider
.get())
466 created_offscreen_context_provider_
= true;
469 DoCommit(queue
.Pass());
470 bool result
= DoComposite(offscreen_context_provider
,
472 device_viewport_damage_rect
,
475 layer_tree_host_
->DidBeginMainFrame();
479 bool SingleThreadProxy::ShouldComposite() const {
480 DCHECK(Proxy::IsImplThread());
481 return layer_tree_host_impl_
->visible() &&
482 layer_tree_host_impl_
->CanDraw();
485 void SingleThreadProxy::UpdateBackgroundAnimateTicking() {
486 DCHECK(Proxy::IsImplThread());
487 layer_tree_host_impl_
->UpdateBackgroundAnimateTicking(
488 !ShouldComposite() && layer_tree_host_impl_
->active_tree()->root_layer());
491 bool SingleThreadProxy::DoComposite(
492 scoped_refptr
<ContextProvider
> offscreen_context_provider
,
493 base::TimeTicks frame_begin_time
,
494 const gfx::Rect
& device_viewport_damage_rect
,
496 LayerTreeHostImpl::FrameData
* frame
) {
497 DCHECK(!layer_tree_host_
->output_surface_lost());
499 bool lost_output_surface
= false;
501 DebugScopedSetImplThread
impl(this);
502 base::AutoReset
<bool> mark_inside(&inside_draw_
, true);
504 layer_tree_host_impl_
->SetOffscreenContextProvider(
505 offscreen_context_provider
);
507 bool can_do_readback
= layer_tree_host_impl_
->renderer()->CanReadPixels();
509 // We guard PrepareToDraw() with CanDraw() because it always returns a valid
510 // frame, so can only be used when such a frame is possible. Since
511 // DrawLayers() depends on the result of PrepareToDraw(), it is guarded on
512 // CanDraw() as well.
513 if (!ShouldComposite() || (for_readback
&& !can_do_readback
)) {
514 UpdateBackgroundAnimateTicking();
518 layer_tree_host_impl_
->Animate(
519 layer_tree_host_impl_
->CurrentFrameTimeTicks(),
520 layer_tree_host_impl_
->CurrentFrameTime());
521 UpdateBackgroundAnimateTicking();
523 if (!layer_tree_host_impl_
->IsContextLost()) {
524 layer_tree_host_impl_
->PrepareToDraw(frame
, device_viewport_damage_rect
);
525 layer_tree_host_impl_
->DrawLayers(frame
, frame_begin_time
);
526 layer_tree_host_impl_
->DidDrawAllLayers(*frame
);
528 lost_output_surface
= layer_tree_host_impl_
->IsContextLost();
530 bool start_ready_animations
= true;
531 layer_tree_host_impl_
->UpdateAnimationState(start_ready_animations
);
533 layer_tree_host_impl_
->ResetCurrentFrameTimeForNextFrame();
536 if (lost_output_surface
) {
537 ContextProvider
* offscreen_contexts
=
538 layer_tree_host_impl_
->offscreen_context_provider();
539 if (offscreen_contexts
)
540 offscreen_contexts
->VerifyContexts();
541 layer_tree_host_
->DidLoseOutputSurface();
548 void SingleThreadProxy::DidSwapFrame() {
549 if (next_frame_is_newly_committed_frame_
) {
550 next_frame_is_newly_committed_frame_
= false;
551 layer_tree_host_
->DidCommitAndDrawFrame();
555 bool SingleThreadProxy::CommitPendingForTesting() { return false; }