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 next_frame_is_newly_committed_frame_(false),
37 TRACE_EVENT0("cc", "SingleThreadProxy::SingleThreadProxy");
38 DCHECK(Proxy::IsMainThread());
39 DCHECK(layer_tree_host
);
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.";
46 void SingleThreadProxy::Start() {
47 DebugScopedSetImplThread
impl(this);
48 layer_tree_host_impl_
= layer_tree_host_
->CreateLayerTreeHostImpl(this);
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_
);
58 void SingleThreadProxy::FinishAllRendering() {
59 TRACE_EVENT0("cc", "SingleThreadProxy::FinishAllRendering");
60 DCHECK(Proxy::IsMainThread());
62 DebugScopedSetImplThread
impl(this);
63 layer_tree_host_impl_
->FinishAllRendering();
67 bool SingleThreadProxy::IsStarted() const {
68 DCHECK(Proxy::IsMainThread());
69 return layer_tree_host_impl_
;
72 void SingleThreadProxy::SetLayerTreeHostClientReady() {
73 TRACE_EVENT0("cc", "SingleThreadProxy::SetLayerTreeHostClientReady");
74 // Scheduling is controlled by the embedder in the single thread case, so
78 void SingleThreadProxy::SetVisible(bool visible
) {
79 TRACE_EVENT0("cc", "SingleThreadProxy::SetVisible");
80 DebugScopedSetImplThread
impl(this);
81 layer_tree_host_impl_
->SetVisible(visible
);
83 // Changing visibility could change ShouldComposite().
84 UpdateBackgroundAnimateTicking();
87 void SingleThreadProxy::CreateAndInitializeOutputSurface() {
89 "cc", "SingleThreadProxy::CreateAndInitializeOutputSurface");
90 DCHECK(Proxy::IsMainThread());
91 DCHECK(layer_tree_host_
->output_surface_lost());
93 scoped_ptr
<OutputSurface
> output_surface
=
94 layer_tree_host_
->CreateOutputSurface();
96 renderer_capabilities_for_main_thread_
= RendererCapabilities();
98 bool success
= !!output_surface
;
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());
107 layer_tree_host_
->OnCreateAndInitializeOutputSurfaceAttempted(success
);
110 // Force another recreation attempt to happen by requesting another commit.
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_
;
121 void SingleThreadProxy::SetNeedsAnimate() {
122 TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsAnimate");
123 DCHECK(Proxy::IsMainThread());
124 client_
->ScheduleAnimation();
127 void SingleThreadProxy::SetNeedsUpdateLayers() {
128 TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsUpdateLayers");
129 DCHECK(Proxy::IsMainThread());
130 client_
->ScheduleComposite();
133 void SingleThreadProxy::DoCommit(scoped_ptr
<ResourceUpdateQueue
> queue
) {
134 TRACE_EVENT0("cc", "SingleThreadProxy::DoCommit");
135 DCHECK(Proxy::IsMainThread());
136 // Commit immediately.
138 DebugScopedSetMainThreadBlocked
main_thread_blocked(this);
139 DebugScopedSetImplThread
impl(this);
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
;
146 layer_tree_host_impl_
->BeginCommit();
148 if (PrioritizedResourceManager
* contents_texture_manager
=
149 layer_tree_host_
->contents_texture_manager()) {
150 contents_texture_manager
->PushTexturePrioritiesToBackings();
152 layer_tree_host_
->BeginCommitOnImplThread(layer_tree_host_impl_
.get());
154 scoped_ptr
<ResourceUpdateController
> update_controller
=
155 ResourceUpdateController::Create(
157 Proxy::MainThreadTaskRunner(),
159 layer_tree_host_impl_
->resource_provider());
160 update_controller
->Finalize();
162 if (layer_tree_host_impl_
->EvictedUIResourcesExist())
163 layer_tree_host_
->RecreateUIResources();
165 layer_tree_host_
->FinishCommitOnImplThread(layer_tree_host_impl_
.get());
167 layer_tree_host_impl_
->CommitComplete();
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
);
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();
184 layer_tree_host_
->CommitComplete();
185 next_frame_is_newly_committed_frame_
= true;
188 void SingleThreadProxy::SetNeedsCommit() {
189 DCHECK(Proxy::IsMainThread());
190 client_
->ScheduleComposite();
193 void SingleThreadProxy::SetNeedsRedraw(const gfx::Rect
& damage_rect
) {
194 TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsRedraw");
195 SetNeedsRedrawRectOnImplThread(damage_rect
);
196 client_
->ScheduleComposite();
199 void SingleThreadProxy::SetNextCommitWaitsForActivation() {
200 // There is no activation here other than commit. So do nothing.
203 void SingleThreadProxy::SetDeferCommits(bool defer_commits
) {
204 // Thread-only feature.
208 bool SingleThreadProxy::CommitRequested() const { return false; }
210 bool SingleThreadProxy::BeginMainFrameRequested() const { return false; }
212 size_t SingleThreadProxy::MaxPartialTextureUpdates() const {
213 return std::numeric_limits
<size_t>::max();
216 void SingleThreadProxy::Stop() {
217 TRACE_EVENT0("cc", "SingleThreadProxy::stop");
218 DCHECK(Proxy::IsMainThread());
220 DebugScopedSetMainThreadBlocked
main_thread_blocked(this);
221 DebugScopedSetImplThread
impl(this);
223 BlockingTaskRunner::CapturePostTasks blocked
;
224 layer_tree_host_
->DeleteContentsTexturesOnImplThread(
225 layer_tree_host_impl_
->resource_provider());
226 layer_tree_host_impl_
.reset();
228 layer_tree_host_
= NULL
;
231 void SingleThreadProxy::OnCanDrawStateChanged(bool can_draw
) {
233 "cc", "SingleThreadProxy::OnCanDrawStateChanged", "can_draw", can_draw
);
234 DCHECK(Proxy::IsImplThread());
235 UpdateBackgroundAnimateTicking();
238 void SingleThreadProxy::NotifyReadyToActivate() {
239 // Thread-only feature.
243 void SingleThreadProxy::SetNeedsRedrawOnImplThread() {
244 client_
->ScheduleComposite();
247 void SingleThreadProxy::SetNeedsAnimateOnImplThread() {
248 SetNeedsRedrawOnImplThread();
251 void SingleThreadProxy::SetNeedsManageTilesOnImplThread() {
252 // Thread-only/Impl-side-painting-only feature.
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
261 layer_tree_host_impl_
->SetViewportDamage(damage_rect
);
265 void SingleThreadProxy::DidInitializeVisibleTileOnImplThread() {
266 // Impl-side painting only.
270 void SingleThreadProxy::SetNeedsCommitOnImplThread() {
271 client_
->ScheduleComposite();
274 void SingleThreadProxy::PostAnimationEventsToMainThreadOnImplThread(
275 scoped_ptr
<AnimationEventsVector
> events
) {
277 "cc", "SingleThreadProxy::PostAnimationEventsToMainThreadOnImplThread");
278 DCHECK(Proxy::IsImplThread());
279 DebugScopedSetMainThread
main(this);
280 layer_tree_host_
->SetAnimationEvents(events
.Pass());
283 bool SingleThreadProxy::ReduceContentsTextureMemoryOnImplThread(
285 int priority_cutoff
) {
286 DCHECK(IsImplThread());
287 PrioritizedResourceManager
* contents_texture_manager
=
288 layer_tree_host_
->contents_texture_manager();
290 ResourceProvider
* resource_provider
=
291 layer_tree_host_impl_
->resource_provider();
293 if (!contents_texture_manager
|| !resource_provider
)
296 return contents_texture_manager
->ReduceMemoryOnImplThread(
297 limit_bytes
, priority_cutoff
, resource_provider
);
300 void SingleThreadProxy::SendManagedMemoryStats() {
301 DCHECK(Proxy::IsImplThread());
302 if (!layer_tree_host_impl_
)
304 PrioritizedResourceManager
* contents_texture_manager
=
305 layer_tree_host_
->contents_texture_manager();
306 if (!contents_texture_manager
)
309 layer_tree_host_impl_
->SendManagedMemoryStats(
310 contents_texture_manager
->MemoryVisibleBytes(),
311 contents_texture_manager
->MemoryVisibleAndNearbyBytes(),
312 contents_texture_manager
->MemoryUseBytes());
315 bool SingleThreadProxy::IsInsideDraw() { return inside_draw_
; }
317 void SingleThreadProxy::UpdateRendererCapabilitiesOnImplThread() {
318 DCHECK(IsImplThread());
319 renderer_capabilities_for_main_thread_
=
320 layer_tree_host_impl_
->GetRendererCapabilities().MainThreadCapabilities();
323 void SingleThreadProxy::DidLoseOutputSurfaceOnImplThread() {
324 TRACE_EVENT0("cc", "SingleThreadProxy::DidLoseOutputSurfaceOnImplThread");
325 // Cause a commit so we can notice the lost context.
326 SetNeedsCommitOnImplThread();
327 client_
->DidAbortSwapBuffers();
330 void SingleThreadProxy::DidSwapBuffersOnImplThread() {
331 client_
->DidPostSwapBuffers();
334 void SingleThreadProxy::DidSwapBuffersCompleteOnImplThread() {
335 TRACE_EVENT0("cc", "SingleThreadProxy::DidSwapBuffersCompleteOnImplThread");
336 client_
->DidCompleteSwapBuffers();
339 // Called by the legacy scheduling path (e.g. where render_widget does the
341 void SingleThreadProxy::CompositeImmediately(base::TimeTicks frame_begin_time
) {
342 TRACE_EVENT0("cc", "SingleThreadProxy::CompositeImmediately");
343 DCHECK(Proxy::IsMainThread());
344 DCHECK(!layer_tree_host_
->output_surface_lost());
346 layer_tree_host_
->AnimateLayers(frame_begin_time
);
348 if (PrioritizedResourceManager
* contents_texture_manager
=
349 layer_tree_host_
->contents_texture_manager()) {
350 contents_texture_manager
->UnlinkAndClearEvictedBackings();
351 contents_texture_manager
->SetMaxMemoryLimitBytes(
352 layer_tree_host_impl_
->memory_allocation_limit_bytes());
353 contents_texture_manager
->SetExternalPriorityCutoff(
354 layer_tree_host_impl_
->memory_allocation_priority_cutoff());
357 scoped_ptr
<ResourceUpdateQueue
> queue
=
358 make_scoped_ptr(new ResourceUpdateQueue
);
359 layer_tree_host_
->UpdateLayers(queue
.get());
360 layer_tree_host_
->WillCommit();
361 DoCommit(queue
.Pass());
362 layer_tree_host_
->DidBeginMainFrame();
364 LayerTreeHostImpl::FrameData frame
;
365 if (DoComposite(frame_begin_time
, &frame
)) {
367 DebugScopedSetMainThreadBlocked
main_thread_blocked(this);
368 DebugScopedSetImplThread
impl(this);
370 // This CapturePostTasks should be destroyed before
371 // DidCommitAndDrawFrame() is called since that goes out to the embedder,
372 // and we want the embedder to receive its callbacks before that.
373 // NOTE: This maintains consistent ordering with the ThreadProxy since
374 // the DidCommitAndDrawFrame() must be post-tasked from the impl thread
375 // there as the main thread is not blocked, so any posted tasks inside
376 // the swap buffers will execute first.
377 BlockingTaskRunner::CapturePostTasks blocked
;
379 layer_tree_host_impl_
->SwapBuffers(frame
);
385 scoped_ptr
<base::Value
> SingleThreadProxy::AsValue() const {
386 scoped_ptr
<base::DictionaryValue
> state(new base::DictionaryValue());
388 // The following line casts away const modifiers because it is just
389 // setting debug state. We still want the AsValue() function and its
390 // call chain to be const throughout.
391 DebugScopedSetImplThread
impl(const_cast<SingleThreadProxy
*>(this));
393 state
->Set("layer_tree_host_impl",
394 layer_tree_host_impl_
->AsValue().release());
396 return state
.PassAs
<base::Value
>();
399 void SingleThreadProxy::ForceSerializeOnSwapBuffers() {
401 DebugScopedSetImplThread
impl(this);
402 if (layer_tree_host_impl_
->renderer()) {
403 DCHECK(!layer_tree_host_
->output_surface_lost());
404 layer_tree_host_impl_
->renderer()->DoNoOp();
409 bool SingleThreadProxy::ShouldComposite() const {
410 DCHECK(Proxy::IsImplThread());
411 return layer_tree_host_impl_
->visible() &&
412 layer_tree_host_impl_
->CanDraw();
415 void SingleThreadProxy::UpdateBackgroundAnimateTicking() {
416 DCHECK(Proxy::IsImplThread());
417 layer_tree_host_impl_
->UpdateBackgroundAnimateTicking(
418 !ShouldComposite() && layer_tree_host_impl_
->active_tree()->root_layer());
421 bool SingleThreadProxy::DoComposite(
422 base::TimeTicks frame_begin_time
,
423 LayerTreeHostImpl::FrameData
* frame
) {
424 TRACE_EVENT0("cc", "SingleThreadProxy::DoComposite");
425 DCHECK(!layer_tree_host_
->output_surface_lost());
427 bool lost_output_surface
= false;
429 DebugScopedSetImplThread
impl(this);
430 base::AutoReset
<bool> mark_inside(&inside_draw_
, true);
432 // We guard PrepareToDraw() with CanDraw() because it always returns a valid
433 // frame, so can only be used when such a frame is possible. Since
434 // DrawLayers() depends on the result of PrepareToDraw(), it is guarded on
435 // CanDraw() as well.
436 if (!ShouldComposite()) {
437 UpdateBackgroundAnimateTicking();
441 layer_tree_host_impl_
->Animate(
442 layer_tree_host_impl_
->CurrentFrameTimeTicks());
443 UpdateBackgroundAnimateTicking();
445 if (!layer_tree_host_impl_
->IsContextLost()) {
446 layer_tree_host_impl_
->PrepareToDraw(frame
);
447 layer_tree_host_impl_
->DrawLayers(frame
, frame_begin_time
);
448 layer_tree_host_impl_
->DidDrawAllLayers(*frame
);
450 lost_output_surface
= layer_tree_host_impl_
->IsContextLost();
452 bool start_ready_animations
= true;
453 layer_tree_host_impl_
->UpdateAnimationState(start_ready_animations
);
455 layer_tree_host_impl_
->ResetCurrentFrameTimeForNextFrame();
458 if (lost_output_surface
) {
459 layer_tree_host_
->DidLoseOutputSurface();
466 void SingleThreadProxy::DidSwapFrame() {
467 if (next_frame_is_newly_committed_frame_
) {
468 next_frame_is_newly_committed_frame_
= false;
469 layer_tree_host_
->DidCommitAndDrawFrame();
473 bool SingleThreadProxy::CommitPendingForTesting() { return false; }